2
For general Scribus (>=1.3.2) copyright and licensing information please refer
3
to the COPYING file provided with the program. Following this notice may exist
4
a copyright and/or license notice that predates the release of Scribus 1.3.2
5
for which a new license (GPL+exception) is in place.
7
/***************************************************************************
8
pageitem_latexframe.cpp - description
10
begin : Mon May 28 2007
11
copyright : (C) 2007 by Hermann Kraus
12
email : hermann@physiklaborant.de
13
***************************************************************************/
15
/***************************************************************************
17
* This program is free software; you can redistribute it and/or modify *
18
* it under the terms of the GNU General Public License as published by *
19
* the Free Software Foundation; either version 2 of the License, or *
20
* (at your option) any later version. *
22
***************************************************************************/
24
#include "pageitem_latexframe.h"
27
#include <QTemporaryFile>
29
#include "prefsmanager.h"
30
#include "scpainter.h"
31
#include "scraction.h"
33
#include "scribusdoc.h"
34
#include "undomanager.h"
35
#include "undostate.h"
36
#include "latexeditor.h"
37
#include "latexhelpers.h"
40
PageItem_LatexFrame::PageItem_LatexFrame(ScribusDoc *pa, double x, double y, double w, double h, double w2, QString fill, QString outline)
41
: PageItem_ImageFrame(pa, x, y, w, h, w2, fill, outline)
43
setUPixmap(Um::ILatexFrame);
44
AnName = tr("Render") + QString::number(m_Doc->TotalItems);
54
if (PrefsManager::instance()->latexConfigs().count() > 0)
55
setConfigFile(PrefsManager::instance()->latexConfigs()[0]);
57
latex = new QProcess();
58
connect(latex, SIGNAL(finished(int, QProcess::ExitStatus)),
59
this, SLOT(updateImage(int, QProcess::ExitStatus)));
60
connect(latex, SIGNAL(error(QProcess::ProcessError)),
61
this, SLOT(latexError(QProcess::ProcessError)));
62
latex->setProcessChannelMode(QProcess::MergedChannels);
64
QTemporaryFile *tempfile = new QTemporaryFile(QDir::tempPath() + "/scribus_temp_render_XXXXXX");
66
tempFileBase = getLongPathName(tempfile->fileName());
67
tempfile->setAutoRemove(false);
70
Q_ASSERT(!tempFileBase.isEmpty());
75
PageItem_LatexFrame::~PageItem_LatexFrame()
77
if (internalEditor) delete internalEditor;
80
if (latex->state() != QProcess::NotRunning) {
83
latex->waitForFinished(500);
84
if (latex->state() != QProcess::NotRunning) {
86
latex->waitForFinished(500);
93
void PageItem_LatexFrame::clearContents()
95
PageItem_ImageFrame::clearContents();
102
void PageItem_LatexFrame::deleteImageFile()
104
QFileInfo fi(tempFileBase);
105
QDir dir = fi.absoluteDir();
108
filter << fi.fileName() + "*";
109
Q_ASSERT(!fi.fileName().isEmpty());
110
Q_ASSERT(!fi.fileName().contains("/"));
111
Q_ASSERT(!fi.fileName().contains("\\"));
113
files = dir.entryList(filter);
114
foreach (QString file, files) {
115
Q_ASSERT(file.startsWith("scribus_temp"));
121
void PageItem_LatexFrame::DrawObj_Item(ScPainter *p, QRectF e, double sc)
124
if (!imgValid && !err)
126
//Draw indicator that latex is running
127
p->setBrush(Qt::white);
128
p->setPen(Qt::green, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
129
p->drawLine(FPoint(0, 0), FPoint(Width, Height));
130
p->drawText(QRectF(0.0, 0.0, Width, Height), tr("Rendering..."));
134
//Draw error indicator
135
p->setBrush(Qt::white);
136
p->setPen(Qt::blue, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
137
p->drawLine(FPoint(0, 0), FPoint(Width, Height));
138
p->drawLine(FPoint(0, Height), FPoint(Width, 0));
139
p->drawText(QRectF(0.0, 0.0, Width, Height), tr("Render Error"));
143
//Just pass it to ImageFrame
144
PageItem_ImageFrame::DrawObj_Item(p, e, sc);
148
void PageItem_LatexFrame::updateImage(int exitCode, QProcess::ExitStatus exitStatus)
150
appStdout = latex->readAllStandardOutput();
153
emit latexFinished();
154
emit stateChanged(latex->state());
156
static bool firstWarning = true;
159
if (firstWarning && !killed)
161
QMessageBox::critical(0, tr("Error"), "<qt>" +
162
tr("Running the external application failed!")
164
firstWarning = false;
166
qCritical() << "RENDER FRAME: updateImage():" << tr("Running the external application failed!");
168
update(); //Show error marker
177
//Save state and restore afterwards
178
bool do_update = PictureIsAvailable;
179
double scaleX = 72.0, scaleY = 72.0, offX = 0.0, offY = 0.0;
181
scaleX = LocalScX * pixm.imgInfo.xres;
182
scaleY = LocalScY * pixm.imgInfo.yres;
183
offX = LocalX / pixm.imgInfo.xres;
184
offY = LocalY / pixm.imgInfo.yres;
186
PageItem_ImageFrame::loadImage(imageFile, true, realDpi());
187
if (PrefsManager::instance()->latexForceDpi())
189
pixm.imgInfo.xres = pixm.imgInfo.yres = realDpi();
194
//Restoring parameters
195
LocalScX = scaleX / pixm.imgInfo.xres; //Account for dpi changes!
196
LocalScY = scaleY / pixm.imgInfo.yres;
197
LocalX = offX * pixm.imgInfo.xres;
198
LocalY = offY * pixm.imgInfo.yres;
202
//Setting sane defaults
204
LocalScX = 72.0/pixm.imgInfo.xres;
205
LocalScY = 72.0/pixm.imgInfo.yres;
207
emit imageOffsetScale(LocalScX, LocalScY, LocalX, LocalY );
213
void PageItem_LatexFrame::runApplication()
219
static bool firstWarningTmpfile = true;
220
static bool firstWarningLatexMissing = true;
224
qCritical() << "RENDER FRAME:" << tr("No configuration defined to run the application!");
228
QFile tempfile(tempFileBase);
229
if (!tempfile.open(QIODevice::Truncate|QIODevice::WriteOnly)) {
231
update(); //Show error marker
232
if (firstWarningTmpfile)
234
QMessageBox::critical(0, tr("Error"), "<qt>" +
235
tr("Could not create a temporary file to run the application!")
237
firstWarningTmpfile = false;
239
qCritical() << "RENDER FRAME:" << tr("Could not create a temporary file to run the application!");
240
//Don't know how to continue as it's impossible to create tempfile
245
firstWarningTmpfile = true;
248
QString full_command = config->executable();
250
if (full_command.isEmpty()) {
252
update(); //Show error marker
253
if (firstWarningLatexMissing)
255
QMessageBox::critical(0, tr("Error"),
256
"<qt>" + tr("The config file didn't specify a executable path!") +
258
firstWarningLatexMissing = false;
260
qCritical() << "RENDER FRAME:" << tr("The config file didn't specify a executable path!");
265
firstWarningLatexMissing = true;
268
full_command.replace("%dpi", QString::number(realDpi()));
269
if (full_command.contains("%file")) {
270
full_command.replace("%file", QString("\"%1\"").arg(QDir::toNativeSeparators(tempFileBase)));
272
full_command = full_command + QString(" \"%1\"").arg(QDir::toNativeSeparators(tempFileBase));
274
full_command.replace("%dir", QString("\"%1\"").arg(QDir::toNativeSeparators(QDir::tempPath())));
275
latex->setWorkingDirectory(QDir::tempPath());
277
double lDpi = realDpi()/72.0;
278
full_command.replace("$scribus_height_px$", QString::number(qRound(Height*lDpi)));
279
full_command.replace("$scribus_width_px$", QString::number(qRound(Width*lDpi)));
280
QMapIterator<QString, QString> i(editorProperties);
284
full_command.replace("$scribus_"+i.key()+"$", i.value());
287
imageFile = tempFileBase + config->imageExtension();
289
writeFileContents(&tempfile);
292
latex->start(full_command);
293
emit stateChanged(QProcess::Starting);
296
void PageItem_LatexFrame::runEditor()
298
if (!internalEditor) {
299
internalEditor = new LatexEditor(this);
300
internalEditor->startEditor();
301
} else if (internalEditor->isVisible()) {
302
internalEditor->activateWindow();
303
internalEditor->raise();
305
internalEditor->startEditor();
309
void PageItem_LatexFrame::rerunApplication(bool updateDisplay)
311
if (latex->state() != QProcess::NotRunning) {
314
latex->waitForFinished(500);
315
if (latex->state() != QProcess::NotRunning) {
316
//Still not terminated?
318
latex->waitForFinished(500);
322
if (updateDisplay) this->update();
326
void PageItem_LatexFrame::writeFileContents(QFile *tempfile)
328
QString tmp(formulaText);
329
double scaleX, scaleY, realW, realH, offsetX, offsetY;
330
double lDpi = realDpi()/72.0;
331
scaleX = LocalScX*lDpi;
332
scaleY = LocalScY*lDpi;
333
offsetX = LocalX*LocalScX;
334
offsetY = LocalY*LocalScY;
335
realW = Width/scaleX - LocalX/lDpi;
336
realH = Height/scaleY - LocalY/lDpi;
337
if (!tmp.contains("$scribus_noprepost$") && m_usePreamble) {
338
tmp = config->preamble() + tmp + config->postamble();
340
tmp.replace(QString("$scribus_width$"), QString::number(Width));
341
tmp.replace(QString("$scribus_width_px$"), QString::number(qRound(Width*lDpi)));
342
tmp.replace(QString("$scribus_width_inch$"), QString::number(Width/72.0));
343
tmp.replace(QString("$scribus_height$"), QString::number(Height));
344
tmp.replace(QString("$scribus_height_px$"), QString::number(qRound(Height*lDpi)));
345
tmp.replace(QString("$scribus_height_inch$"), QString::number(Height/72.0));
346
tmp.replace(QString("$scribus_realwidth$"), QString::number(realW));
347
tmp.replace(QString("$scribus_realwidth_px$"), QString::number(qRound(realW*lDpi)));
348
tmp.replace(QString("$scribus_realheight$"), QString::number(realH));
349
tmp.replace(QString("$scribus_realheight_px$"), QString::number(qRound(realH*lDpi)));
350
tmp.replace(QString("$scribus_offsetX$"), QString::number(offsetX));
351
tmp.replace(QString("$scribus_offsetX_px$"), QString::number(qRound(offsetX*lDpi)));
352
tmp.replace(QString("$scribus_offsetY$"), QString::number(offsetY));
353
tmp.replace(QString("$scribus_offsetY$"), QString::number(qRound(offsetY*lDpi)));
354
tmp.replace(QString("$scribus_scaleX$"), QString::number(scaleX));
355
tmp.replace(QString("$scribus_scaleY$"), QString::number(scaleY));
356
tmp.replace(QString("$scribus_dpi$"), QString::number(realDpi()));
357
tmp.replace(QString("$scribus_file$"), tempFileBase);
358
tmp.replace(QString("$scribus_dir$"), QDir::tempPath());
359
QMapIterator<QString, QString> i(editorProperties);
360
while (i.hasNext()) {
362
tmp.replace("$scribus_"+i.key()+"$", i.value());
364
tempfile->write(tmp.toUtf8());
367
bool PageItem_LatexFrame::setFormula(QString formula, bool undoable)
369
if (formula == formulaText) {
375
if (UndoManager::undoEnabled() && undoable)
377
SimpleState *ss = new SimpleState(Um::ChangeFormula, "", Um::IChangeFormula);
378
ss->set("CHANGE_FORMULA", "change_formula");
379
ss->set("OLD_FORMULA", formulaText);
380
ss->set("NEW_FORMULA", formula);
381
undoManager->action(this, ss);
382
} else if (!undoable) {
383
emit formulaAutoUpdate(formulaText, formula);
385
formulaText = formula;
389
void PageItem_LatexFrame::latexError(QProcess::ProcessError error)
392
update(); //Show error marker
393
static bool firstWarning = true;
397
//Don't show errors caused by killing processes
402
if (latex->error() == QProcess::FailedToStart) {
403
QMessageBox::critical(0, tr("Error"), "<qt>" +
404
tr("The application \"%1\" failed to start!").
405
arg(config->executable())
408
QMessageBox::critical(0, tr("Error"), "<qt>" +
409
tr("The application \"%1\" crashed!").arg(config->executable())
412
firstWarning = false;
414
qCritical() << "RENDER FRAME: latexError():" <<
415
tr("Running the application \"%1\" failed!").arg(config->executable()) << latex->error();
419
QString PageItem_LatexFrame::application() const
421
return config ? config->executable() : tr("No application defined");
424
QString PageItem_LatexFrame::configFile() const
426
return configFilename;
429
int PageItem_LatexFrame::realDpi() const
434
return PrefsManager::instance()->latexResolution();
438
void PageItem_LatexFrame::setDpi(int newDpi)
443
void PageItem_LatexFrame::setConfigFile(QString newConfig, bool relative)
447
QStringList configs = PrefsManager::instance()->latexConfigs();
448
foreach (QString config, configs) {
450
if (newConfig == fi.fileName()) {
457
if (configFilename == newConfig) return;
459
bool unchanged = formulaText.isEmpty();
460
if (config && (formulaText == config->emptyFrameText())) {
464
configFilename = newConfig;
465
config = LatexConfigCache::instance()->parser(configFilename);
467
//Initialize with default values
469
QMapIterator<QString, QString> i(config->properties);
470
while (i.hasNext()) {
473
if (!editorProperties.contains(key)) {
474
editorProperties[key] = i.value();
479
if (PrefsManager::instance()->latexStartWithEmptyFrames()) {
482
newFormula = config->emptyFrameText();
484
emit formulaAutoUpdate(formulaText, newFormula);
485
formulaText = newFormula;
488
emit applicationChanged();
491
void PageItem_LatexFrame::killProcess()
497
void PageItem_LatexFrame::restore(UndoState *state, bool isUndo)
499
SimpleState *ss = dynamic_cast<SimpleState*>(state);
501
PageItem_ImageFrame::restore(state, isUndo);
504
if (ss->contains("CHANGE_FORMULA")) {
506
setFormula(ss->get("OLD_FORMULA"), false);
508
setFormula(ss->get("NEW_FORMULA"), false);
511
PageItem_ImageFrame::restore(state, isUndo);
516
void PageItem_LatexFrame::setUsePreamble(bool useP)
518
m_usePreamble = useP;
521
void PageItem_LatexFrame::layout()
523
if (!invalid) return;
526
if (Width == lastWidth && Height == lastHeight) return;
530
rerunApplication(false);
533
void PageItem_LatexFrame::applicableActions(QStringList & actionList)
535
actionList << "itemImageIsVisible";
536
actionList << "itemPreviewFull";
537
actionList << "itemPreviewLow";
538
actionList << "itemPreviewNormal";
539
actionList << "itemUpdateImage";
540
actionList << "editEditRenderSource";
541
if (PictureIsAvailable)
544
actionList << "itemAdjustFrameToImage";*/
545
actionList << "editClearContents";
546
actionList << "editCopyContents";
548
if (doc()->scMW()->contentsBuffer.sourceType==PageItem::LatexFrame)
550
actionList << "editPasteContents";
551
actionList << "editPasteContentsAbs";
555
QString PageItem_LatexFrame::infoDescription()
558
htmlText.append("<h2>"+tr("Render Frame") + "</h2><table>");
559
htmlText.append("<tr><th align=\"right\">" + tr("Application") + ": </th><td>" + application());
560
htmlText.append("</td></tr><tr><th align=\"right\">" + tr("DPI") + ": </th><td>" +
561
QString::number(realDpi()));
562
htmlText.append("</td></tr><tr><th align=\"right\">" + tr("State") + ": </th><td>");
563
if (latex->state() == QProcess::NotRunning) {
565
htmlText.append(tr("Error"));
567
htmlText.append(tr("Finished"));
570
htmlText.append(tr("Running"));
572
htmlText.append("</td></tr></table><hr>");
573
htmlText.append(PageItem::infoDescription());