Warning, file /education/cantor/src/lib/expression.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     SPDX-License-Identifier: GPL-2.0-or-later
0003     SPDX-FileCopyrightText: 2009 Alexander Rieder <alexanderrieder@gmail.com>
0004 */
0005 
0006 #include "expression.h"
0007 #include "latexrenderer.h"
0008 using namespace Cantor;
0009 
0010 #include <config-cantorlib.h>
0011 
0012 #include "session.h"
0013 #include "result.h"
0014 #include "textresult.h"
0015 #include "imageresult.h"
0016 #include "latexresult.h"
0017 #include "settings.h"
0018 
0019 #include <QDebug>
0020 #include <QFileInfo>
0021 #include <QString>
0022 #include <QFileSystemWatcher>
0023 
0024 #include <KProcess>
0025 #include <KZip>
0026 
0027 class Cantor::ExpressionPrivate
0028 {
0029 public:
0030     ExpressionPrivate() : id(-1) {}
0031 
0032     int id{-1};
0033     QString command;
0034     QString error;
0035     QList<QString> information;
0036     QVector<Result*> results;
0037     Expression::Status status{Expression::Done};
0038     Session* session{nullptr};
0039     Expression::FinishingBehavior finishingBehavior{Expression::DoNotDelete};
0040     bool internal{false};
0041     bool helpRequest{false};
0042     QFileSystemWatcher* fileWatcher{nullptr};
0043 };
0044 
0045 static const QString tex=QLatin1String("\\documentclass[12pt,fleqn]{article}          \n "\
0046                          "\\usepackage{latexsym,amsfonts,amssymb,ulem}  \n "\
0047                          "\\usepackage[dvips]{graphicx}                 \n "\
0048                          "\\setlength\\textwidth{5in}                   \n "\
0049                          "\\setlength{\\parindent}{0pt}                 \n "\
0050                          "%1                                            \n "\
0051                          "\\pagestyle{empty}                            \n "\
0052                          "\\begin{document}                             \n "\
0053                          "%2                                            \n "\
0054                          "\\end{document}\n");
0055 
0056 
0057 Expression::Expression( Session* session, bool internal ) : QObject( session ),
0058                                              d(new ExpressionPrivate)
0059 {
0060     d->session=session;
0061     d->internal = internal;
0062     if (!internal && session)
0063         d->id=session->nextExpressionId();
0064     else
0065         d->id = -1;
0066 }
0067 
0068 Expression::Expression( Session* session, bool internal, int id ) : QObject( session ), d(new ExpressionPrivate)
0069 {
0070     d->session = session;
0071     d->internal = internal;
0072     d->id = id;
0073 }
0074 
0075 Expression::~Expression()
0076 {
0077     qDeleteAll(d->results);
0078     if (d->fileWatcher)
0079         delete d->fileWatcher;
0080 
0081     delete d;
0082 }
0083 
0084 void Expression::setCommand(const QString& command)
0085 {
0086     d->command=command;
0087 }
0088 
0089 QString Expression::command()
0090 {
0091     return d->command;
0092 }
0093 
0094 QString Expression::internalCommand()
0095 {
0096     return d->command;
0097 }
0098 
0099 void Expression::setErrorMessage(const QString& error)
0100 {
0101     d->error=error;
0102 }
0103 
0104 QString Expression::errorMessage()
0105 {
0106     return d->error;
0107 }
0108 
0109 void Expression::setResult(Result* result)
0110 {
0111     clearResults();
0112     addResult(result);
0113 }
0114 
0115 void Expression::addResult(Result* result)
0116 {
0117     if(result!=nullptr)
0118     {
0119         qDebug()<<"setting result to a type "<<result->type()<<" result";
0120         #ifdef WITH_EPS
0121         //If it's text, and latex typesetting is enabled, render it
0122         if ( session() &&
0123              session()->isTypesettingEnabled()&&
0124              result->type()==TextResult::Type &&
0125              static_cast<TextResult*>(result)->format()==TextResult::LatexFormat &&
0126              !result->toHtml().trimmed().isEmpty() &&
0127              finishingBehavior()!=DeleteOnFinish &&
0128              !isInternal()
0129             )
0130         {
0131             renderResultAsLatex(result);
0132             return;
0133         }
0134         #endif
0135     }
0136 
0137     d->results << result;
0138     emit gotResult();
0139 }
0140 
0141 void Expression::clearResults()
0142 {
0143     qDeleteAll(d->results);
0144     d->results.clear();
0145     emit resultsCleared();
0146 }
0147 
0148 void Expression::removeResult(Result* result)
0149 {
0150     int index = d->results.indexOf(result);
0151     d->results.remove(index);
0152     delete result;
0153     emit resultRemoved(index);
0154 }
0155 
0156 void Expression::replaceResult(int index, Result* result)
0157 {
0158     if (result)
0159     {
0160         //insert the new result
0161         d->results.insert(index, result);
0162 
0163         //delete the previous result
0164         Result* oldResult = d->results.at(index+1);
0165         d->results.remove(index+1);
0166         delete oldResult;
0167 
0168         //notify about the replacement
0169         emit resultReplaced(index);
0170     }
0171 }
0172 
0173 Result* Expression::result()
0174 {
0175     if (!d->results.isEmpty())
0176         return d->results.first();
0177     else
0178         return nullptr;
0179 }
0180 
0181 const QVector<Result*>& Expression::results() const
0182 {
0183     return d->results;
0184 }
0185 
0186 void Expression::setStatus(Expression::Status status)
0187 {
0188     d->status=status;
0189     emit statusChanged(status);
0190 
0191     bool isFinished = status == Expression::Done || status == Expression::Error || status == Expression::Interrupted;
0192     if (isFinished)
0193     {
0194         emit expressionFinished(status);
0195         if(d->finishingBehavior==Expression::DeleteOnFinish)
0196             deleteLater();
0197     }
0198 }
0199 
0200 Expression::Status Expression::status()
0201 {
0202     return d->status;
0203 }
0204 
0205 Session* Expression::session()
0206 {
0207     return d->session;
0208 }
0209 void Expression::renderResultAsLatex(Result* result)
0210 {
0211     LatexRenderer* renderer=new LatexRenderer(this);
0212     renderer->setLatexCode(result->data().toString().trimmed());
0213     renderer->addHeader(additionalLatexHeaders());
0214 
0215     connect(renderer, &LatexRenderer::done, [=] { latexRendered(renderer, result); });
0216     connect(renderer, &LatexRenderer::error, [=] { latexRendered(renderer, result); });
0217 
0218     renderer->render();
0219 }
0220 
0221 void Expression::latexRendered(LatexRenderer* renderer, Result* result)
0222 {
0223     qDebug()<<"rendered a result to "<<renderer->imagePath();
0224     //replace the textresult with the rendered latex image result
0225     //ImageResult* latex=new ImageResult( d->latexFilename );
0226     if(renderer->renderingSuccessful())
0227     {
0228         if (result->type() == TextResult::Type)
0229         {
0230             TextResult* r = static_cast<TextResult*>(result);
0231             LatexResult* latex=new LatexResult(r->data().toString().trimmed(), QUrl::fromLocalFile(renderer->imagePath()), r->plain());
0232             addResult( latex );
0233         }
0234         else if (result->type() == LatexResult::Type)
0235         {
0236             LatexResult* previousLatexResult = static_cast<LatexResult*>(result);
0237             LatexResult* latex=new LatexResult(previousLatexResult->data().toString().trimmed(), QUrl::fromLocalFile(renderer->imagePath()), previousLatexResult->plain());
0238             addResult( latex );
0239         }
0240     }else
0241     {
0242         //if rendering with latex was not successful, just use the plain text version
0243         //if available
0244         TextResult* r=dynamic_cast<TextResult*>(result);
0245         if (r)
0246             addResult(new TextResult(r->plain()));
0247         qDebug()<<"error rendering latex: "<<renderer->errorMessage();
0248     }
0249 
0250     delete result;
0251 
0252     renderer->deleteLater();
0253 }
0254 
0255 void Expression::addInformation(const QString& information)
0256 {
0257     d->information.append(information);
0258 }
0259 
0260 QString Expression::additionalLatexHeaders()
0261 {
0262     return QString();
0263 }
0264 
0265 QFileSystemWatcher* Expression::fileWatcher() {
0266     if (!d->fileWatcher)
0267         d->fileWatcher = new QFileSystemWatcher();
0268 
0269     return d->fileWatcher;
0270 }
0271 
0272 int Expression::id()
0273 {
0274     return d->id;
0275 }
0276 
0277 void Expression::setId(int id)
0278 {
0279     d->id=id;
0280     emit idChanged();
0281 }
0282 
0283 void Expression::setFinishingBehavior(Expression::FinishingBehavior behavior)
0284 {
0285     d->finishingBehavior=behavior;
0286 }
0287 
0288 Expression::FinishingBehavior Expression::finishingBehavior()
0289 {
0290     return d->finishingBehavior;
0291 }
0292 
0293 bool Expression::isInternal() const
0294 {
0295     return d->internal;
0296 }
0297 
0298 void Expression::setIsHelpRequest(bool value)
0299 {
0300     d->helpRequest = value;
0301 }
0302 
0303 bool Expression::isHelpRequest() const
0304 {
0305     return d->helpRequest;
0306 }