diff --git a/src/lib/expression.cpp b/src/lib/expression.cpp index ae6bdf34..e8800599 100644 --- a/src/lib/expression.cpp +++ b/src/lib/expression.cpp @@ -1,280 +1,280 @@ /* 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 */ #include "expression.h" +#include "latexrenderer.h" using namespace Cantor; #include #include "session.h" #include "result.h" #include "textresult.h" #include "imageresult.h" #include "latexresult.h" #include "settings.h" -#include "latexrenderer.h" #include #include #include #include #include class Cantor::ExpressionPrivate { public: ExpressionPrivate() : result(nullptr), status(Expression::Done), session(nullptr), finishingBehavior(Expression::DoNotDelete), isInternal(false) { } int id; QString command; QString error; QList information; Result* result; Expression::Status status; Session* session; Expression::FinishingBehavior finishingBehavior; bool isInternal; }; static const QString tex=QLatin1String("\\documentclass[12pt,fleqn]{article} \n "\ "\\usepackage{latexsym,amsfonts,amssymb,ulem} \n "\ "\\usepackage[dvips]{graphicx} \n "\ "\\setlength\\textwidth{5in} \n "\ "\\setlength{\\parindent}{0pt} \n "\ "%1 \n "\ "\\pagestyle{empty} \n "\ "\\begin{document} \n "\ "%2 \n "\ "\\end{document}\n"); Expression::Expression( Session* session ) : QObject( session ), d(new ExpressionPrivate) { d->session=session; d->id=session->nextExpressionId(); } Expression::~Expression() { delete d->result; delete d; } void Expression::setCommand(const QString& command) { d->command=command; } QString Expression::command() { return d->command; } void Expression::setErrorMessage(const QString& error) { d->error=error; } QString Expression::errorMessage() { return d->error; } void Expression::setResult(Result* result) { - - if(d->result) - delete d->result; - - d->result=result; - if(result!=nullptr) { qDebug()<<"settting result to a type "<type()<<" result"; #ifdef WITH_EPS //If it's text, and latex typesetting is enabled, render it if ( session()->isTypesettingEnabled()&& result->type()==TextResult::Type && dynamic_cast(result)->format()==TextResult::LatexFormat && !result->toHtml().trimmed().isEmpty() && finishingBehavior()!=DeleteOnFinish && !isInternal() ) { - renderResultAsLatex(); + renderResultAsLatex(result); + return; } #endif } + if(d->result) + delete d->result; + + d->result=result; + emit gotResult(); } Result* Expression::result() { return d->result; } void Expression::clearResult() { if(d->result) delete d->result; d->result=nullptr; } void Expression::setStatus(Expression::Status status) { d->status=status; emit statusChanged(status); if(status==Expression::Done&&d->finishingBehavior==Expression::DeleteOnFinish) deleteLater(); } Expression::Status Expression::status() { return d->status; } Session* Expression::session() { return d->session; } -void Expression::renderResultAsLatex() +void Expression::renderResultAsLatex(Result* result) { qDebug()<<"rendering as latex"; qDebug()<<"checking if it really is a formula that can be typeset"; LatexRenderer* renderer=new LatexRenderer(this); - renderer->setLatexCode(result()->data().toString().trimmed()); + renderer->setLatexCode(result->data().toString().trimmed()); renderer->addHeader(additionalLatexHeaders()); - connect(renderer, &LatexRenderer::done, this, &Expression::latexRendered); - connect(renderer, &LatexRenderer::error, this, &Expression::latexRendered); + connect(renderer, &LatexRenderer::done, [=] { latexRendered(renderer, result); }); + connect(renderer, &LatexRenderer::error, [=] { latexRendered(renderer, result); }); renderer->render(); } -void Expression::latexRendered() +void Expression::latexRendered(LatexRenderer* renderer, Result* result) { - LatexRenderer* renderer=qobject_cast(sender()); - qDebug()<<"rendered a result to "<imagePath(); //replace the textresult with the rendered latex image result //ImageResult* latex=new ImageResult( d->latexFilename ); - if(renderer->renderingSuccessful()&&result()) + if(renderer->renderingSuccessful()) { - if (result()->type() == TextResult::Type) + if (result->type() == TextResult::Type) { - TextResult* r=dynamic_cast(result()); + TextResult* r=dynamic_cast(result); LatexResult* latex=new LatexResult(r->data().toString().trimmed(), QUrl::fromLocalFile(renderer->imagePath()), r->plain()); setResult( latex ); } - else if (result()->type() == LatexResult::Type) + else if (result->type() == LatexResult::Type) { - LatexResult* previousLatexResult=dynamic_cast(result()); + LatexResult* previousLatexResult=dynamic_cast(result); LatexResult* latex=new LatexResult(previousLatexResult->data().toString().trimmed(), QUrl::fromLocalFile(renderer->imagePath()), previousLatexResult->plain()); setResult( latex ); } }else { //if rendering with latex was not successful, just use the plain text version //if available - TextResult* r=dynamic_cast(result()); + TextResult* r=dynamic_cast(result); setResult(new TextResult(r->plain())); qDebug()<<"error rendering latex: "<errorMessage(); } + delete result; + renderer->deleteLater(); } //saving code QDomElement Expression::toXml(QDomDocument& doc) { QDomElement expr=doc.createElement( QLatin1String("Expression") ); QDomElement cmd=doc.createElement( QLatin1String("Command") ); QDomText cmdText=doc.createTextNode( command() ); cmd.appendChild( cmdText ); expr.appendChild( cmd ); if ( result() ) { qDebug()<<"result: "<toXml( doc ); expr.appendChild( resXml ); } return expr; } void Expression::saveAdditionalData(KZip* archive) { //just pass this call to the result if(result()) result()->saveAdditionalData(archive); } void Expression::addInformation(const QString& information) { d->information.append(information); } QString Expression::additionalLatexHeaders() { return QString(); } int Expression::id() { return d->id; } void Expression::setId(int id) { d->id=id; emit idChanged(); } void Expression::setFinishingBehavior(Expression::FinishingBehavior behavior) { d->finishingBehavior=behavior; } Expression::FinishingBehavior Expression::finishingBehavior() { return d->finishingBehavior; } void Expression::setInternal(bool internal) { d->isInternal=internal; } bool Expression::isInternal() { return d->isInternal; } diff --git a/src/lib/expression.h b/src/lib/expression.h index 066b7275..8b3ff475 100644 --- a/src/lib/expression.h +++ b/src/lib/expression.h @@ -1,257 +1,257 @@ /* 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 */ #ifndef _EXPRESSION_H #define _EXPRESSION_H #include #include #include "cantor_export.h" class KZip; /** * Namespace collecting all Classes of the Cantor Libraries */ namespace Cantor { class Session; class Result; +class LatexRenderer; class ExpressionPrivate; /** * An Expression object is used, to store the information needed when running a command of a Session * Evaluation of Expression is an asynchroneous process in most cases, so most of the members * of this class are not useful directly after its construction. Therefore there are signals * indicating, when the Expression goes through the different stages of the Running process. * An Expression is never constructed directly, but by using Session::evaluateExpression() * * @author Alexander Rieder */ class CANTOR_EXPORT Expression : public QObject { Q_OBJECT public: enum Status{ Computing, ///< The Expression is still being computed Done, ///< The Running of the Expression is finished successfully Error, ///< An Error occurred when running the Expression Interrupted ///< The Expression was interrupted by the user while running }; /** * Enum indicating how this Expression behaves on finishing */ enum FinishingBehavior { DoNotDelete, ///< This Expression will not be deleted. This is the normal behaviour DeleteOnFinish /** < The Object will delete itself when finished. This is used for fire-and-forget commands. All output/results will be dropped */ }; /** * Expression constructor. Should only be called from Session::evaulateExpression * @param session the session, this Expression belongs to */ Expression( Session* session ); /** * destructor */ ~Expression() override; /** * Evaluate the Expression. before this is called, you should set the Command first * This method can be implemented asynchroneous, thus the Evaluation doesn't need to happen in the method, * It can also only be scheduled for evaluating. * @see setCommand() */ virtual void evaluate() = 0; /** * Interrupt the running of the Expression. * This should set the state to Interrupted. */ virtual void interrupt() = 0; /** * Returns the unique id of the Expression * @return the unique id of the Expression */ int id(); /** * set the id of the Expression. It should be unique * @param id the new Id */ void setId(int id); /** * set the finishing behaviour * @param behavior the new Finishing Behaviour */ void setFinishingBehavior(FinishingBehavior behavior); /** * get the Expressions finishing behaviour * @return the current finishing behaviour */ FinishingBehavior finishingBehavior(); /** * Sets the command, represented by this Expression * @param cmd the command */ void setCommand( const QString& cmd ); /** * Returns the command, represented by this Expression * @return the command, represented by this Expression */ QString command(); /** * Adds some additional information/input to this expression. * this is needed, when the Expression has emitted the needsAdditionalInformation signal, * and the user has answered the question. This is used for e.g. if maxima asks whether * n+1 is zero or not when running the command "integrate(x^n,x)" * This method is part of the InteractiveMode feature */ virtual void addInformation(const QString& information); /** * Sets the error message * @param cmd the error message * @see errorMessage() */ void setErrorMessage( const QString& cmd); /** * returns the Error message, if an error occurred during * the evaluation of the expression. * @return the error message */ QString errorMessage(); /** * The result of this Expression. It can have different types, represented by various * subclasses of Result, like text, image, etc. * The result will be null, until the computation is completed. * When the result changes, the gotResult() signal is emitted. * The Result object is owned by the Expression, and will get deleted, as * soon as the Expression dies, or newer results appear. * @return the result of the Expression, 0 if it isn't yet set */ Result* result(); /** * Deletes the result of this expression. * */ void clearResult(); /** * Returns the status of this Expression * @return the status of this Expression */ Status status(); /** * Returns the Session, this Expression belongs to */ Session* session(); /** * returns an xml representation of this expression * used for saving the worksheet * @param doc DomDocument used for storing the information * @return QDomElemt containing the representation of this Expression */ QDomElement toXml(QDomDocument& doc); /** * saves all the data, that can't be saved in xml * in an extra file in the archive. for Example * images of plots * @param archive a Zip archive, the data should be stored in */ void saveAdditionalData(KZip* archive); /** * returns whether or not this expression is internal, or * comes from the user */ bool isInternal(); /** * mark this expression as an internal expression, * so for example latex will not be run on it */ void setInternal(bool internal); Q_SIGNALS: /** * the Id of this Expression changed */ void idChanged(); /** * A Result of the Expression has arrived */ void gotResult(); /** * the status of the Expression has changed. * @param status the new status */ void statusChanged(Cantor::Expression::Status status); /** * the Expression needs more information for the evaluation * @see addInformation() * @param question question, the user needs to answer */ void needsAdditionalInformation(const QString& question); //These are protected, because only subclasses will handle results/status changes protected: /** * Set the result of the Expression. * this will cause gotResult() to be emitted * The old result will be deleted, and the Expression * takes over ownership of the result object, taking * care of deleting it. * @param result the new result */ void setResult(Result* result); /** * Set the status * statusChanged will be emitted * @param status the new status */ void setStatus(Status status); protected: //returns a string of latex commands, that is inserted into the header. //used for example if special packages are needed virtual QString additionalLatexHeaders(); private: - void renderResultAsLatex(); - private Q_SLOTS: - void latexRendered(); + void renderResultAsLatex(Result* result); + void latexRendered(LatexRenderer* renderer, Result* result); private: ExpressionPrivate* d; }; } #endif /* _EXPRESSION_H */