File indexing completed on 2024-04-28 11:20:48

0001 /*
0002     SPDX-License-Identifier: GPL-2.0-or-later
0003     SPDX-FileCopyrightText: 2009 Alexander Rieder <alexanderrieder@gmail.com>
0004     SPDX-FileCopyrightText: 2022 Alexander Semke <alexander.semke@web.de>
0005 */
0006 
0007 #include "textresult.h"
0008 using namespace Cantor;
0009 
0010 #include <QFile>
0011 #include <QTextStream>
0012 #include <QJsonArray>
0013 #include <QJsonObject>
0014 
0015 QString rtrim(const QString& s)
0016 {
0017     QString result = s;
0018     while (result.count() > 0 && result[result.count()-1].isSpace() )
0019         result = result.left(result.count() -1 );
0020 
0021     return result;
0022 }
0023 
0024 class Cantor::TextResultPrivate
0025 {
0026 public:
0027     QString data;
0028     QString plain;
0029     TextResult::Format format{TextResult::PlainTextFormat};
0030     bool isStderr{false};
0031     bool isWarning{false};
0032 };
0033 
0034 TextResult::TextResult(const QString& data) : d(new TextResultPrivate)
0035 {
0036     d->data = rtrim(data);
0037     d->plain = d->data;
0038 }
0039 
0040 TextResult::TextResult(const QString& data, const QString& plain) : d(new TextResultPrivate)
0041 {
0042     d->data = rtrim(data);
0043     d->plain = rtrim(plain);
0044 }
0045 
0046 TextResult::~TextResult()
0047 {
0048     delete d;
0049 }
0050 
0051 void TextResult::setIsWarning(bool value)
0052 {
0053     d->isWarning = value;
0054 }
0055 
0056 bool TextResult::isWarning() const
0057 {
0058     return d->isWarning;
0059 }
0060 
0061 QString TextResult::toHtml()
0062 {
0063     QString s = d->data.toHtmlEscaped();
0064     s.replace(QLatin1Char('\n'), QLatin1String("<br/>\n"));
0065     s.replace(QLatin1Char(' '), QLatin1String("&nbsp;"));
0066     return s;
0067 }
0068 
0069 QVariant TextResult::data()
0070 {
0071     return QVariant(d->data);
0072 }
0073 
0074 QString TextResult::plain()
0075 {
0076     return d->plain;
0077 }
0078 
0079 int TextResult::type()
0080 {
0081     return TextResult::Type;
0082 }
0083 
0084 QString TextResult::mimeType()
0085 {
0086     switch(format())
0087     {
0088         case TextResult::PlainTextFormat:
0089             return QStringLiteral("text/plain");
0090         case TextResult::LatexFormat:
0091             return QStringLiteral("text/x-tex");
0092         default:
0093             return QString();
0094     }
0095 }
0096 
0097 TextResult::Format TextResult::format()
0098 {
0099     return d->format;
0100 }
0101 
0102 void TextResult::setFormat(TextResult::Format f)
0103 {
0104     d->format = f;
0105 }
0106 
0107 QDomElement TextResult::toXml(QDomDocument& doc)
0108 {
0109     QDomElement e = doc.createElement(QStringLiteral("Result"));
0110     e.setAttribute(QStringLiteral("type"), QStringLiteral("text"));
0111     e.setAttribute(QStringLiteral("stderr"), d->isStderr);
0112 
0113     if (d->format == LatexFormat)
0114         e.setAttribute(QStringLiteral("format"), QStringLiteral("latex"));
0115 
0116     QDomText txt = doc.createTextNode(data().toString());
0117     e.appendChild(txt);
0118 
0119     return e;
0120 }
0121 
0122 QJsonValue Cantor::TextResult::toJupyterJson()
0123 {
0124     QJsonObject root;
0125 
0126     switch (d->format)
0127     {
0128         case PlainTextFormat:
0129         {
0130             if (executionIndex() != -1)
0131             {
0132                 root.insert(QLatin1String("output_type"), QLatin1String("execute_result"));
0133                 root.insert(QLatin1String("execution_count"), executionIndex());
0134 
0135                 QJsonObject data;
0136                 data.insert(QLatin1String("text/plain"), jupyterText(d->data));
0137                 root.insert(QLatin1String("data"), data);
0138 
0139                 root.insert(QLatin1String("metadata"), jupyterMetadata());
0140             }
0141             else
0142             {
0143                 root.insert(QLatin1String("output_type"), QLatin1String("stream"));
0144                 if (d->isStderr)
0145                     root.insert(QLatin1String("name"), QLatin1String("stderr"));
0146                 else
0147                     root.insert(QLatin1String("name"), QLatin1String("stdout"));
0148 
0149                 // Jupyter don't support a few text result (it merges them into one text),
0150                 // so add additional \n to end
0151                 // See https://github.com/jupyter/notebook/issues/4699
0152                 root.insert(QLatin1String("text"), jupyterText(d->data, true));
0153             }
0154             break;
0155         }
0156 
0157         case LatexFormat:
0158         {
0159             if (executionIndex() != -1)
0160             {
0161                 root.insert(QLatin1String("output_type"), QLatin1String("execute_result"));
0162                 root.insert(QLatin1String("execution_count"), executionIndex());
0163             }
0164             else
0165                 root.insert(QLatin1String("output_type"), QLatin1String("display_data"));
0166 
0167             QJsonObject data;
0168             data.insert(QLatin1String("text/latex"), jupyterText(d->data));
0169             data.insert(QLatin1String("text/plain"), jupyterText(d->plain));
0170             root.insert(QLatin1String("data"), data);
0171 
0172             root.insert(QLatin1String("metadata"), jupyterMetadata());
0173             break;
0174         }
0175     }
0176 
0177     return root;
0178 }
0179 
0180 void TextResult::save(const QString& filename)
0181 {
0182     QFile file(filename);
0183 
0184     if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
0185         return;
0186 
0187     QTextStream stream(&file);
0188 
0189     stream<<d->data;
0190 
0191     file.close();
0192 }
0193 
0194 QJsonArray TextResult::jupyterText(const QString& text, bool addEndNewLine)
0195 {
0196     QJsonArray array;
0197 
0198     const QStringList& lines = text.split(QLatin1Char('\n'));
0199     for (int i = 0; i < lines.size(); i++)
0200     {
0201         QString line = lines[i];
0202         if (i != lines.size() - 1 || addEndNewLine)
0203             line.append(QLatin1Char('\n'));
0204         array.append(line);
0205     }
0206 
0207     return array;
0208 }
0209 
0210 bool Cantor::TextResult::isStderr() const
0211 {
0212     return d->isStderr;
0213 }
0214 
0215 void Cantor::TextResult::setStdErr(bool value)
0216 {
0217     d->isStderr = value;
0218 }