diff --git a/src/latexentry.cpp b/src/latexentry.cpp index 35ea0a90..cebe196f 100644 --- a/src/latexentry.cpp +++ b/src/latexentry.cpp @@ -1,551 +1,563 @@ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. --- Copyright (C) 2009 Alexander Rieder Copyright (C) 2012 Martin Kuettler */ #include "latexentry.h" #include "worksheetentry.h" #include "worksheet.h" #include "lib/renderer.h" #include "lib/jupyterutils.h" #include "lib/defaulthighlighter.h" #include "lib/latexrenderer.h" #include "config-cantor.h" #include #include #include #include #include #include #include #include #include #include LatexEntry::LatexEntry(Worksheet* worksheet) : WorksheetEntry(worksheet), m_textItem(new WorksheetTextItem(this, Qt::TextEditorInteraction)) { m_textItem->installEventFilter(this); connect(m_textItem, &WorksheetTextItem::moveToPrevious, this, &LatexEntry::moveToPreviousEntry); connect(m_textItem, &WorksheetTextItem::moveToNext, this, &LatexEntry::moveToNextEntry); connect(m_textItem, SIGNAL(execute()), this, SLOT(evaluate())); } void LatexEntry::populateMenu(QMenu* menu, QPointF pos) { bool imageSelected = false; QTextCursor cursor = m_textItem->textCursor(); const QChar repl = QChar::ObjectReplacementCharacter; if (cursor.hasSelection()) { QString selection = m_textItem->textCursor().selectedText(); imageSelected = selection.contains(repl); } else { // we need to try both the current cursor and the one after the that cursor = m_textItem->cursorForPosition(pos); for (int i = 2; i; --i) { int p = cursor.position(); if (m_textItem->document()->characterAt(p-1) == repl && cursor.charFormat().hasProperty(Cantor::Renderer::CantorFormula)) { m_textItem->setTextCursor(cursor); imageSelected = true; break; } cursor.movePosition(QTextCursor::NextCharacter); } } if (imageSelected) { menu->addAction(i18n("Show LaTeX code"), this, SLOT(resolveImagesAtCursor())); menu->addSeparator(); } WorksheetEntry::populateMenu(menu, pos); } int LatexEntry::type() const { return Type; } bool LatexEntry::isEmpty() { return m_textItem->document()->isEmpty(); } bool LatexEntry::acceptRichText() { return false; } bool LatexEntry::focusEntry(int pos, qreal xCoord) { if (aboutToBeRemoved()) return false; m_textItem->setFocusAt(pos, xCoord); return true; } void LatexEntry::setContent(const QString& content) { m_latex = content; m_textItem->setPlainText(m_latex); } void LatexEntry::setContent(const QDomElement& content, const KZip& file) { m_latex = content.text(); qDebug() << m_latex; m_textItem->document()->clear(); QTextCursor cursor = m_textItem->textCursor(); cursor.movePosition(QTextCursor::Start); QString imagePath; bool useLatexCode = true; if(content.hasAttribute(QLatin1String("filename"))) { const KArchiveEntry* imageEntry=file.directory()->entry(content.attribute(QLatin1String("filename"))); if (imageEntry&&imageEntry->isFile()) { const KArchiveFile* imageFile=static_cast(imageEntry); const QString& dir=QStandardPaths::writableLocation(QStandardPaths::TempLocation); imageFile->copyTo(dir); imagePath = dir + QDir::separator() + imageFile->name(); #ifdef LIBSPECTRE_FOUND QString uuid = Cantor::LatexRenderer::genUuid(); m_renderedFormat = worksheet()->renderer()->render(m_textItem->document(), Cantor::Renderer::EPS, QUrl::fromLocalFile(imagePath), uuid); qDebug()<<"rendering successful? " << !m_renderedFormat.name().isEmpty(); m_renderedFormat.setProperty(Cantor::Renderer::CantorFormula, Cantor::Renderer::LatexFormula); m_renderedFormat.setProperty(Cantor::Renderer::ImagePath, imagePath); m_renderedFormat.setProperty(Cantor::Renderer::Code, m_latex); cursor.insertText(QString(QChar::ObjectReplacementCharacter), m_renderedFormat); useLatexCode = false; m_textItem->denyEditing(); #endif } } if (useLatexCode && content.hasAttribute(QLatin1String("image"))) { const QByteArray& ba = QByteArray::fromBase64(content.attribute(QLatin1String("image")).toLatin1()); QImage image; if (image.loadFromData(ba)) { // Create unique internal url for this loaded image QUrl internal; internal.setScheme(QLatin1String("internal")); internal.setPath(QUuid::createUuid().toString()); m_textItem->document()->addResource(QTextDocument::ImageResource, internal, QVariant(image)); m_renderedFormat.setName(internal.url()); m_renderedFormat.setWidth(image.width()); m_renderedFormat.setHeight(image.height()); m_renderedFormat.setProperty(Cantor::Renderer::CantorFormula, Cantor::Renderer::LatexFormula); if (!imagePath.isEmpty()) m_renderedFormat.setProperty(Cantor::Renderer::ImagePath, imagePath); m_renderedFormat.setProperty(Cantor::Renderer::Code, m_latex); cursor.insertText(QString(QChar::ObjectReplacementCharacter), m_renderedFormat); useLatexCode = false; m_textItem->denyEditing(); } } if (useLatexCode) cursor.insertText(m_latex); } void LatexEntry::setContentFromJupyter(const QJsonObject& cell) { if (!Cantor::JupyterUtils::isCodeCell(cell)) return; m_textItem->document()->clear(); QTextCursor cursor = m_textItem->textCursor(); cursor.movePosition(QTextCursor::Start); bool useLatexCode = true; QString source = Cantor::JupyterUtils::getSource(cell); m_latex = source.remove(QLatin1String("%%latex\n")); QJsonArray outputs = cell.value(Cantor::JupyterUtils::outputsKey).toArray(); if (outputs.size() == 1 && Cantor::JupyterUtils::isJupyterDisplayOutput(outputs[0])) { const QJsonObject data = outputs[0].toObject().value(Cantor::JupyterUtils::dataKey).toObject(); const QImage& image = Cantor::JupyterUtils::loadImage(data, Cantor::JupyterUtils::pngMime); if (!image.isNull()) { QUrl internal; internal.setScheme(QLatin1String("internal")); internal.setPath(QUuid::createUuid().toString()); m_textItem->document()->addResource(QTextDocument::ImageResource, internal, QVariant(image)); m_renderedFormat.setName(internal.url()); m_renderedFormat.setWidth(image.width()); m_renderedFormat.setHeight(image.height()); m_renderedFormat.setProperty(Cantor::Renderer::CantorFormula, Cantor::Renderer::LatexFormula); m_renderedFormat.setProperty(Cantor::Renderer::Code, m_latex); cursor.insertText(QString(QChar::ObjectReplacementCharacter), m_renderedFormat); useLatexCode = false; m_textItem->denyEditing(); } } if (useLatexCode) { cursor.insertText(m_latex); m_latex.clear(); // We don't render image, so clear latex code cache } } QJsonValue LatexEntry::toJupyterJson() { QJsonObject entry; entry.insert(Cantor::JupyterUtils::cellTypeKey, QLatin1String("code")); entry.insert(Cantor::JupyterUtils::executionCountKey, QJsonValue()); QJsonObject metadata, cantorMetadata; cantorMetadata.insert(QLatin1String("latex_entry"), true); metadata.insert(Cantor::JupyterUtils::cantorMetadataKey, cantorMetadata); entry.insert(Cantor::JupyterUtils::metadataKey, metadata); QJsonArray outputs; QTextCursor cursor = m_textItem->document()->find(QString(QChar::ObjectReplacementCharacter)); if (!cursor.isNull()) { QTextImageFormat format=cursor.charFormat().toImageFormat(); QUrl internal; internal.setUrl(format.name()); const QImage& image = m_textItem->document()->resource(QTextDocument::ImageResource, internal).value(); if (!image.isNull()) { QByteArray ba; QBuffer buffer(&ba); buffer.open(QIODevice::WriteOnly); image.save(&buffer, "PNG"); // Add image result with latex rendered image to this Jupyter code cell QJsonObject imageResult; imageResult.insert(Cantor::JupyterUtils::outputTypeKey, QLatin1String("display_data")); QJsonObject data; data.insert(Cantor::JupyterUtils::pngMime, Cantor::JupyterUtils::toJupyterMultiline(QString::fromLatin1(ba.toBase64()))); imageResult.insert(QLatin1String("data"), data); imageResult.insert(Cantor::JupyterUtils::metadataKey, QJsonObject()); outputs.append(imageResult); } } entry.insert(Cantor::JupyterUtils::outputsKey, outputs); const QString& latex = latexCode(); Cantor::JupyterUtils::setSource(entry, QLatin1String("%%latex\n") + latex); return entry; } QDomElement LatexEntry::toXml(QDomDocument& doc, KZip* archive) { QDomElement el = doc.createElement(QLatin1String("Latex")); el.appendChild( doc.createTextNode( latexCode() )); QTextCursor cursor = m_textItem->document()->find(QString(QChar::ObjectReplacementCharacter)); if (!cursor.isNull()) { QTextImageFormat format=cursor.charFormat().toImageFormat(); QString fileName = format.property(Cantor::Renderer::ImagePath).toString(); // Check, if eps file exists, and if not true, rerender latex code bool isEpsFileExists = QFile::exists(fileName); #ifdef LIBSPECTRE_FOUND if (!isEpsFileExists && renderLatexCode()) { cursor = m_textItem->document()->find(QString(QChar::ObjectReplacementCharacter)); format=cursor.charFormat().toImageFormat(); fileName = format.property(Cantor::Renderer::ImagePath).toString(); isEpsFileExists = QFile::exists(fileName); } #endif if (isEpsFileExists && archive) { const QUrl& url=QUrl::fromLocalFile(fileName); archive->addLocalFile(url.toLocalFile(), url.fileName()); el.setAttribute(QLatin1String("filename"), url.fileName()); } // Save also rendered QImage, if exist. QUrl internal; internal.setUrl(format.name()); const QImage& image = m_textItem->document()->resource(QTextDocument::ImageResource, internal).value(); if (!image.isNull()) { QByteArray ba; QBuffer buffer(&ba); buffer.open(QIODevice::WriteOnly); image.save(&buffer, "PNG"); el.setAttribute(QLatin1String("image"), QString::fromLatin1(ba.toBase64())); } } return el; } QString LatexEntry::toPlain(const QString& commandSep, const QString& commentStartingSeq, const QString& commentEndingSeq) { Q_UNUSED(commandSep); if (commentStartingSeq.isEmpty()) return QString(); QString text = latexCode(); if (!commentEndingSeq.isEmpty()) return commentStartingSeq + text + commentEndingSeq + QLatin1String("\n"); return commentStartingSeq + text.replace(QLatin1String("\n"), QLatin1String("\n") + commentStartingSeq) + QLatin1String("\n"); } void LatexEntry::interruptEvaluation() { } bool LatexEntry::evaluate(EvaluationOption evalOp) { bool success = false; if (isOneImageOnly()) { success = true; } else { if (m_latex == latexCode()) { - QTextCursor cursor = m_textItem->textCursor(); - cursor.movePosition(QTextCursor::Start); - cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); - cursor.insertText(QString(QChar::ObjectReplacementCharacter), m_renderedFormat); - m_textItem->denyEditing(); + bool renderWasSuccessful = !m_renderedFormat.name().isEmpty(); + if (renderWasSuccessful) + { + QTextCursor cursor = m_textItem->textCursor(); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); + cursor.insertText(QString(QChar::ObjectReplacementCharacter), m_renderedFormat); + m_textItem->denyEditing(); + } + else + { + success = renderLatexCode(); + } } else { m_latex = latexCode(); success = renderLatexCode(); } } qDebug()<<"rendering successful? "<document()->find(QString(QChar::ObjectReplacementCharacter)); while (!cursor.isNull()) { qDebug()<<"found a formula... rendering the eps..."; QTextImageFormat format=cursor.charFormat().toImageFormat(); const QUrl& url=QUrl::fromLocalFile(format.property(Cantor::Renderer::ImagePath).toString()); QSizeF s = worksheet()->renderer()->renderToResource(m_textItem->document(), Cantor::Renderer::EPS, url, QUrl(format.name())); qDebug()<<"rendering successful? "<< s.isValid(); cursor.movePosition(QTextCursor::NextCharacter); cursor = m_textItem->document()->find(QString(QChar::ObjectReplacementCharacter), cursor); } } bool LatexEntry::eventFilter(QObject* object, QEvent* event) { if(object == m_textItem && event->type() == QEvent::GraphicsSceneMouseDoubleClick) { // One image if we have rendered entry if (isOneImageOnly()) { QTextCursor cursor = m_textItem->textCursor(); if (!cursor.hasSelection()) cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor); cursor.insertText(m_textItem->resolveImages(cursor)); m_textItem->allowEditing(); return true; } } return false; } QString LatexEntry::latexCode() { QTextCursor cursor = m_textItem->textCursor(); cursor.movePosition(QTextCursor::Start); cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); QString code = m_textItem->resolveImages(cursor); code.replace(QChar::ParagraphSeparator, QLatin1Char('\n')); //Replace the U+2029 paragraph break by a Normal Newline code.replace(QChar::LineSeparator, QLatin1Char('\n')); //Replace the line break by a Normal Newline return code; } bool LatexEntry::isOneImageOnly() { QTextCursor cursor = m_textItem->textCursor(); cursor.movePosition(QTextCursor::Start); cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); return (cursor.selectionEnd() == 1 && cursor.selectedText() == QString(QChar::ObjectReplacementCharacter)); } int LatexEntry::searchText(const QString& text, const QString& pattern, QTextDocument::FindFlags qt_flags) { Qt::CaseSensitivity caseSensitivity; if (qt_flags & QTextDocument::FindCaseSensitively) caseSensitivity = Qt::CaseSensitive; else caseSensitivity = Qt::CaseInsensitive; int position; if (qt_flags & QTextDocument::FindBackward) position = text.lastIndexOf(pattern, -1, caseSensitivity); else position = text.indexOf(pattern, 0, caseSensitivity); return position; } WorksheetCursor LatexEntry::search(const QString& pattern, unsigned flags, QTextDocument::FindFlags qt_flags, const WorksheetCursor& pos) { if (!(flags & WorksheetEntry::SearchLaTeX)) return WorksheetCursor(); if (pos.isValid() && (pos.entry() != this || pos.textItem() != m_textItem)) return WorksheetCursor(); QTextCursor textCursor = m_textItem->search(pattern, qt_flags, pos); int position = 0; QString latex; const QString repl = QString(QChar::ObjectReplacementCharacter); QTextCursor latexCursor = m_textItem->search(repl, qt_flags, pos); while (!latexCursor.isNull()) { latex = m_textItem->resolveImages(latexCursor); position = searchText(latex, pattern, qt_flags); if (position >= 0) { break; } WorksheetCursor c(this, m_textItem, latexCursor); latexCursor = m_textItem->search(repl, qt_flags, c); } if (latexCursor.isNull()) { if (textCursor.isNull()) return WorksheetCursor(); else return WorksheetCursor(this, m_textItem, textCursor); } else { if (textCursor.isNull() || latexCursor < textCursor) { int start = latexCursor.selectionStart(); latexCursor.insertText(latex); QTextCursor c = m_textItem->textCursor(); c.setPosition(start + position); c.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, pattern.length()); return WorksheetCursor(this, m_textItem, c); } else { return WorksheetCursor(this, m_textItem, textCursor); } } } void LatexEntry::layOutForWidth(qreal w, bool force) { if (size().width() == w && !force) return; m_textItem->setGeometry(0, 0, w); setSize(QSizeF(m_textItem->width(), m_textItem->height() + VerticalMargin)); } bool LatexEntry::wantToEvaluate() { return !isOneImageOnly(); } bool LatexEntry::renderLatexCode() { bool success = false; QString latex = latexCode(); + m_renderedFormat = QTextImageFormat(); // clear rendered image Cantor::LatexRenderer* renderer = new Cantor::LatexRenderer(this); renderer->setLatexCode(latex); renderer->setEquationOnly(false); renderer->setMethod(Cantor::LatexRenderer::LatexMethod); renderer->renderBlocking(); if (renderer->renderingSuccessful()) { Cantor::Renderer* epsRend = worksheet()->renderer(); m_renderedFormat = epsRend->render(m_textItem->document(), renderer); success = !m_renderedFormat.name().isEmpty(); } + else + qWarning() << "Fail to render LatexEntry with error " << renderer->errorMessage(); if(success) { QTextCursor cursor = m_textItem->textCursor(); cursor.movePosition(QTextCursor::Start); cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); cursor.insertText(QString(QChar::ObjectReplacementCharacter), m_renderedFormat); m_textItem->denyEditing(); } + delete renderer; return success; } bool LatexEntry::isConvertableToLatexEntry(const QJsonObject& cell) { if (!Cantor::JupyterUtils::isCodeCell(cell)) return false; const QString& source = Cantor::JupyterUtils::getSource(cell); return source.startsWith(QLatin1String("%%latex\n")); } void LatexEntry::resolveImagesAtCursor() { QTextCursor cursor = m_textItem->textCursor(); if (!cursor.hasSelection()) cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor); cursor.insertText(m_textItem->resolveImages(cursor)); } diff --git a/src/lib/latexrenderer.cpp b/src/lib/latexrenderer.cpp index 63ac4a35..648f4cda 100644 --- a/src/lib/latexrenderer.cpp +++ b/src/lib/latexrenderer.cpp @@ -1,297 +1,328 @@ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. --- Copyright (C) 2011 Alexander Rieder */ #include "latexrenderer.h" using namespace Cantor; #include #include #include #include #include #include #include #include #include #include #include "settings.h" class Cantor::LatexRendererPrivate { public: QString latexCode; QString header; LatexRenderer::Method method; bool isEquationOnly; LatexRenderer::EquationType equationType; QString errorMessage; bool success; QString latexFilename; QString epsFilename; QString uuid; QTemporaryFile* texFile; }; static const QLatin1String tex("\\documentclass[fleqn]{article}"\ "\\usepackage{latexsym,amsfonts,amssymb,ulem}"\ "\\usepackage{amsmath}"\ "\\usepackage[dvips]{graphicx}"\ "\\usepackage[utf8]{inputenc}"\ "\\usepackage{xcolor}"\ "\\setlength\\textwidth{5in}"\ "\\setlength{\\parindent}{0pt}"\ "%1"\ "\\pagecolor[rgb]{%2,%3,%4}"\ "\\pagestyle{empty}"\ "\\begin{document}"\ "\\color[rgb]{%5,%6,%7}"\ "\\fontsize{%8}{%8}\\selectfont\n"\ "%9\n"\ "\\end{document}"); static const QLatin1String eqnHeader("\\begin{eqnarray*}%1\\end{eqnarray*}"); static const QLatin1String inlineEqnHeader("$%1$"); LatexRenderer::LatexRenderer(QObject* parent) : QObject(parent), d(new LatexRendererPrivate) { d->method=LatexMethod; d->isEquationOnly=false; d->equationType=InlineEquation; d->success=false; d->texFile=nullptr; } LatexRenderer::~LatexRenderer() { delete d; } QString LatexRenderer::latexCode() const { return d->latexCode; } void LatexRenderer::setLatexCode(const QString& src) { d->latexCode=src; } QString LatexRenderer::header() const { return d->header; } void LatexRenderer::addHeader(const QString& header) { d->header.append(header); } void LatexRenderer::setHeader(const QString& header) { d->header=header; } LatexRenderer::Method LatexRenderer::method() const { return d->method; } void LatexRenderer::setMethod(LatexRenderer::Method method) { d->method=method; } void LatexRenderer::setEquationType(LatexRenderer::EquationType type) { d->equationType=type; } LatexRenderer::EquationType LatexRenderer::equationType() const { return d->equationType; } void LatexRenderer::setErrorMessage(const QString& msg) { d->errorMessage=msg; } QString LatexRenderer::errorMessage() const { return d->errorMessage; } bool LatexRenderer::renderingSuccessful() const { return d->success; } void LatexRenderer::setEquationOnly(bool isEquationOnly) { d->isEquationOnly=isEquationOnly; } bool LatexRenderer::isEquationOnly() const { return d->isEquationOnly; } QString LatexRenderer::imagePath() const { return d->epsFilename; } QString Cantor::LatexRenderer::uuid() const { return d->uuid; } -void LatexRenderer::render() +bool LatexRenderer::render() { switch(d->method) { - case LatexRenderer::LatexMethod: renderWithLatex(); break; - case LatexRenderer::MmlMethod: renderWithMml(); break; + case LatexRenderer::LatexMethod: + return renderWithLatex(); + + case LatexRenderer::MmlMethod: + return renderWithMml(); + + default: + return false; }; } void LatexRenderer::renderBlocking() { QEventLoop event; connect(this, &LatexRenderer::done, &event, &QEventLoop::quit); connect(this, &LatexRenderer::error, &event, &QEventLoop::quit); - render(); - event.exec(); + bool success = render(); + // We can't emit error before running event loop, so exit by passing false as an error indicator + if (success) + event.exec(); + else + return; } -void LatexRenderer::renderWithLatex() +bool LatexRenderer::renderWithLatex() { qDebug()<<"rendering using latex method"; QString dir=QStandardPaths::writableLocation(QStandardPaths::TempLocation); if (d->texFile) delete d->texFile; d->texFile=new QTemporaryFile(dir + QDir::separator() + QLatin1String("cantor_tex-XXXXXX.tex")); d->texFile->open(); KColorScheme scheme(QPalette::Active); const QColor &backgroundColor=scheme.background().color(); const QColor &foregroundColor=scheme.foreground().color(); QString expressionTex=tex; expressionTex=expressionTex.arg(d->header) .arg(backgroundColor.redF()).arg(backgroundColor.greenF()).arg(backgroundColor.blueF()) .arg(foregroundColor.redF()).arg(foregroundColor.greenF()).arg(foregroundColor.blueF()); int fontPointSize = QApplication::font().pointSize(); expressionTex=expressionTex.arg(fontPointSize); if(isEquationOnly()) { switch(equationType()) { case FullEquation: expressionTex=expressionTex.arg(eqnHeader); break; case InlineEquation: expressionTex=expressionTex.arg(inlineEqnHeader); break; } } expressionTex=expressionTex.arg(d->latexCode); // qDebug()<<"full tex:\n"<texFile->write(expressionTex.toUtf8()); d->texFile->flush(); QString fileName = d->texFile->fileName(); qDebug()<<"fileName: "<latexFilename=fileName; QProcess *p=new QProcess( this ); p->setWorkingDirectory(dir); d->uuid = genUuid(); - p->setProgram(Settings::self()->latexCommand()); - p->setArguments({QStringLiteral("-jobname=cantor_") + d->uuid, QStringLiteral("-halt-on-error"), fileName}); + qDebug() << Settings::self()->latexCommand(); + QFileInfo info(Settings::self()->latexCommand()); + if (info.exists() && info.isExecutable()) + { + p->setProgram(Settings::self()->latexCommand()); + p->setArguments({QStringLiteral("-jobname=cantor_") + d->uuid, QStringLiteral("-halt-on-error"), fileName}); - connect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(convertToPs()) ); - p->start(); + connect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(convertToPs()) ); + p->start(); + return true; + } + else + { + setErrorMessage(QStringLiteral("failed to find latex executable")); + return false; + } } void LatexRenderer::convertToPs() { const QString& dir=QStandardPaths::writableLocation(QStandardPaths::TempLocation); QString dviFile = dir + QDir::separator() + QStringLiteral("cantor_") + d->uuid + QStringLiteral(".dvi"); d->epsFilename = dir + QDir::separator() + QLatin1String("cantor_")+d->uuid+QLatin1String(".eps"); QProcess *p=new QProcess( this ); qDebug()<<"converting to eps: "<dvipsCommand()<<"-E"<<"-o"<epsFilename<setProgram(Settings::self()->dvipsCommand()); - p->setArguments({QStringLiteral("-E"), QStringLiteral("-q"), QStringLiteral("-o"), d->epsFilename, dviFile}); + QFileInfo info(Settings::self()->dvipsCommand()); + if (info.exists() && info.isExecutable()) + { + p->setProgram(Settings::self()->dvipsCommand()); + p->setArguments({QStringLiteral("-E"), QStringLiteral("-q"), QStringLiteral("-o"), d->epsFilename, dviFile}); - connect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(convertingDone()) ); - p->start(); + connect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(convertingDone()) ); + p->start(); + } + else + { + setErrorMessage(QStringLiteral("failed to find dvips executable")); + emit error(); + } } void LatexRenderer::convertingDone() { QFileInfo info(d->epsFilename); qDebug() <<"remove temporary files for " << d->latexFilename; QString pathWithoutExtension = info.path() + QDir::separator() + info.completeBaseName(); QFile::remove(pathWithoutExtension + QLatin1String(".log")); QFile::remove(pathWithoutExtension + QLatin1String(".aux")); QFile::remove(pathWithoutExtension + QLatin1String(".dvi")); if(info.exists()) { delete d->texFile; d->texFile = nullptr; d->success=true; emit done(); } else { d->success=false; setErrorMessage(QStringLiteral("failed to create the latex preview image")); emit error(); } } -void LatexRenderer::renderWithMml() +bool LatexRenderer::renderWithMml() { - qDebug()<<"WARNING: MML rendering not implemented yet!"; - emit done(); + qWarning()<<"WARNING: MML rendering not implemented yet!"; + emit error(); + return false; } QString LatexRenderer::genUuid() { QString uuid = QUuid::createUuid().toString(); uuid.remove(0, 1); uuid.chop(1); uuid.replace(QLatin1Char('-'), QLatin1Char('_')); return uuid; } diff --git a/src/lib/latexrenderer.h b/src/lib/latexrenderer.h index 3c7483c3..2dca186f 100644 --- a/src/lib/latexrenderer.h +++ b/src/lib/latexrenderer.h @@ -1,81 +1,81 @@ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. --- Copyright (C) 2011 Alexander Rieder */ #ifndef _LATEXRENDERER_H #define _LATEXRENDERER_H #include #include "cantor_export.h" namespace Cantor{ class LatexRendererPrivate; class CANTOR_EXPORT LatexRenderer : public QObject { Q_OBJECT public: enum Method{ LatexMethod = 0, MmlMethod = 1}; enum EquationType{ InlineEquation = 0, FullEquation = 1}; explicit LatexRenderer( QObject* parent = nullptr); ~LatexRenderer() override; QString latexCode() const; void setLatexCode(const QString& src); QString header() const; void addHeader(const QString& header); void setHeader(const QString& header); Method method() const; void setMethod( Method method); void setEquationOnly(bool isEquationOnly); bool isEquationOnly() const; void setEquationType(EquationType type); EquationType equationType() const; QString errorMessage() const; bool renderingSuccessful() const; QString imagePath() const; QString uuid() const; static QString genUuid(); Q_SIGNALS: void done(); void error(); public Q_SLOTS: - void render(); + bool render(); void renderBlocking(); private: void setErrorMessage(const QString& msg); private Q_SLOTS: - void renderWithLatex(); - void renderWithMml(); + bool renderWithLatex(); + bool renderWithMml(); void convertToPs(); void convertingDone(); private: LatexRendererPrivate* d; }; } #endif /* _LATEXRENDERER_H */