diff --git a/src/backends/maxima/maximaexpression.h b/src/backends/maxima/maximaexpression.h index b33b792d..5b96c31f 100644 --- a/src/backends/maxima/maximaexpression.h +++ b/src/backends/maxima/maximaexpression.h @@ -1,72 +1,69 @@ /* 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-2012 Alexander Rieder */ #ifndef _MAXIMAEXPRESSION_H #define _MAXIMAEXPRESSION_H #include "expression.h" #include #include class QTemporaryFile; class MaximaExpression : public Cantor::Expression { Q_OBJECT public: explicit MaximaExpression(Cantor::Session*, bool internal = false); ~MaximaExpression() override; void evaluate() override; void interrupt() override; - //returns the command that should be send to - //the Maxima process, it's different from the - //command() for example to allow plot embedding - QString internalCommand(); + QString internalCommand() override; //Forces the status of this Expression to done void forceDone(); //reads from @param out until a prompt indicates that a new expression has started bool parseOutput(QString&); void parseError(const QString&); void addInformation(const QString&) override; private Q_SLOTS: void imageChanged(); private: void parseResult(const QString&); QTemporaryFile *m_tempFile; QFileSystemWatcher m_fileWatch; bool m_isHelpRequest; bool m_isHelpRequestAdditional; bool m_isPlot; Cantor::Result* m_plotResult; int m_plotResultIndex; QString m_errorBuffer; bool m_gotErrorContent; }; #endif /* _MAXIMAEXPRESSION_H */ diff --git a/src/lib/expression.cpp b/src/lib/expression.cpp index fe3ab9d8..2cfc5494 100644 --- a/src/lib/expression.cpp +++ b/src/lib/expression.cpp @@ -1,294 +1,299 @@ /* 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 #include #include #include #include #include class Cantor::ExpressionPrivate { public: ExpressionPrivate() : id(-1), status(Expression::Done), session(nullptr), finishingBehavior(Expression::DoNotDelete), internal(false), fileWatcher(nullptr) { } int id; QString command; QString error; QList information; QVector results; Expression::Status status; Session* session; Expression::FinishingBehavior finishingBehavior; bool internal; QFileSystemWatcher* fileWatcher; }; 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, bool internal ) : QObject( session ), d(new ExpressionPrivate) { d->session=session; d->internal = internal; if (!internal && session) d->id=session->nextExpressionId(); else d->id = -1; } Expression::Expression( Session* session, bool internal, int id ) : QObject( session ), d(new ExpressionPrivate) { d->session = session; d->internal = internal; d->id = id; } Expression::~Expression() { qDeleteAll(d->results); if (d->fileWatcher) delete d->fileWatcher; delete d; } void Expression::setCommand(const QString& command) { d->command=command; } QString Expression::command() { return d->command; } +QString Expression::internalCommand() +{ + return d->command; +} + void Expression::setErrorMessage(const QString& error) { d->error=error; } QString Expression::errorMessage() { return d->error; } void Expression::setResult(Result* result) { clearResults(); addResult(result); } void Expression::addResult(Result* result) { if(result!=nullptr) { qDebug()<<"setting result to a type "<type()<<" result"; #ifdef WITH_EPS //If it's text, and latex typesetting is enabled, render it if ( session() && session()->isTypesettingEnabled()&& result->type()==TextResult::Type && dynamic_cast(result)->format()==TextResult::LatexFormat && !result->toHtml().trimmed().isEmpty() && finishingBehavior()!=DeleteOnFinish && !isInternal() ) { renderResultAsLatex(result); return; } #endif } d->results << result; emit gotResult(); } void Expression::clearResults() { qDeleteAll(d->results); d->results.clear(); emit resultsCleared(); } void Expression::removeResult(Result* result) { int index = d->results.indexOf(result); d->results.remove(index); delete result; emit resultRemoved(index); } void Expression::replaceResult(int index, Result* result) { if (result) { d->results.insert(index, result); emit resultReplaced(index); } } Result* Expression::result() { if (!d->results.isEmpty()) return d->results.first(); else return nullptr; } const QVector& Expression::results() const { return d->results; } 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(Result* result) { LatexRenderer* renderer=new LatexRenderer(this); renderer->setLatexCode(result->data().toString().trimmed()); renderer->addHeader(additionalLatexHeaders()); connect(renderer, &LatexRenderer::done, [=] { latexRendered(renderer, result); }); connect(renderer, &LatexRenderer::error, [=] { latexRendered(renderer, result); }); renderer->render(); } void Expression::latexRendered(LatexRenderer* renderer, Result* result) { qDebug()<<"rendered a result to "<imagePath(); //replace the textresult with the rendered latex image result //ImageResult* latex=new ImageResult( d->latexFilename ); if(renderer->renderingSuccessful()) { if (result->type() == TextResult::Type) { TextResult* r=dynamic_cast(result); LatexResult* latex=new LatexResult(r->data().toString().trimmed(), QUrl::fromLocalFile(renderer->imagePath()), r->plain()); addResult( latex ); } else if (result->type() == LatexResult::Type) { LatexResult* previousLatexResult=dynamic_cast(result); LatexResult* latex=new LatexResult(previousLatexResult->data().toString().trimmed(), QUrl::fromLocalFile(renderer->imagePath()), previousLatexResult->plain()); addResult( latex ); } }else { //if rendering with latex was not successful, just use the plain text version //if available TextResult* r=dynamic_cast(result); addResult(new TextResult(r->plain())); qDebug()<<"error rendering latex: "<errorMessage(); } delete result; renderer->deleteLater(); } void Expression::addInformation(const QString& information) { d->information.append(information); } QString Expression::additionalLatexHeaders() { return QString(); } QFileSystemWatcher* Expression::fileWatcher() { if (!d->fileWatcher) d->fileWatcher = new QFileSystemWatcher(); return d->fileWatcher; } 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; } bool Expression::isInternal() { return d->internal; } diff --git a/src/lib/expression.h b/src/lib/expression.h index f806e79e..15130e81 100644 --- a/src/lib/expression.h +++ b/src/lib/expression.h @@ -1,278 +1,285 @@ /* 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 QFileSystemWatcher; 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 asynchronous 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 Queued ///< The Expression is in expression queue, waited for Computing }; /** * 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::evaluateExpression * @param session the session, this Expression belongs to * @param internal \c true if this expression is internal expression */ explicit Expression( Session* session, bool internal = false); /** * destructor */ ~Expression() override; /** * Evaluate the Expression. before this is called, you should set the Command first * This method can be implemented asynchronous, 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 * or -1 for internal expressions * @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(); + /** + * Returns the command, adapted for using by appropriate Backend + * The return value can be equal or not to @command() + * Backend should use this function, instead of @command() + */ + virtual QString internalCommand(); + /** * 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(); /*! * in case the expression has multiple outputs/results, those can be obtained with this functions. * Everything else said for \sa result() applies here too. * @return the vector with results, or an empty vector if nor results are available yet. */ const QVector& results() const; /** * Deletes the result of this expression. * */ void removeResult(Result* result); /** * Deletes the all results of this expression. * */ void clearResults(); /** * Returns the status of this Expression * @return the status of this Expression */ Status status(); /** * Set the status * statusChanged will be emitted * @param status the new status */ void setStatus(Status status); /** * Returns the Session, this Expression belongs to */ Session* session(); /** * returns whether or not this expression is internal, or * comes from the user */ bool isInternal(); Q_SIGNALS: /** * the Id of this Expression changed */ void idChanged(); /** * A Result of the Expression has arrived */ void gotResult(); /** * emitted when the results of the expression were deleted. * @see clearResults() */ void resultsCleared(); /** * emitted when the results of the expression were deleted. * @see clearResult(Result* result) */ void resultRemoved(int index); /** * emitted when the result at the position @c index was replaced by a new result. */ void resultReplaced(int index); /** * 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: // Protected constructor, useful for derived classes with own id setting strategy Expression(Session* session, bool internal, int id); /** * 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); void addResult(Result*); void replaceResult(int index, Result* result); //returns a string of latex commands, that is inserted into the header. //used for example if special packages are needed virtual QString additionalLatexHeaders(); QFileSystemWatcher* fileWatcher(); private: void renderResultAsLatex(Result* result); void latexRendered(LatexRenderer* renderer, Result* result); private: ExpressionPrivate* d; }; } #endif /* _EXPRESSION_H */