File indexing completed on 2024-04-28 03:40:43

0001 /*************************************************************************************
0002  *  Copyright (C) 2008 by Aleix Pol <aleixpol@kde.org>                               *
0003  *                                                                                   *
0004  *  This program is free software; you can redistribute it and/or                    *
0005  *  modify it under the terms of the GNU General Public License                      *
0006  *  as published by the Free Software Foundation; either version 2                   *
0007  *  of the License, or (at your option) any later version.                           *
0008  *                                                                                   *
0009  *  This program is distributed in the hope that it will be useful,                  *
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of                   *
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                    *
0012  *  GNU General Public License for more details.                                     *
0013  *                                                                                   *
0014  *  You should have received a copy of the GNU General Public License                *
0015  *  along with this program; if not, write to the Free Software                      *
0016  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA   *
0017  *************************************************************************************/
0018 
0019 #include "htmlexpressionwriter.h"
0020 #include "value.h"
0021 #include "operator.h"
0022 #include "container.h"
0023 #include "vector.h"
0024 #include <QStringList>
0025 #include <QCoreApplication>
0026 
0027 #include "list.h"
0028 #include "variable.h"
0029 #include "stringexpressionwriter.h"
0030 #include "apply.h"
0031 #include "analitzautils.h"
0032 #include "matrix.h"
0033 
0034 using namespace Analitza;
0035 
0036 const double HtmlExpressionWriter::MIN_PRINTABLE_VALUE = 0.0000000000001; // since the precision we choose for 'G' is 12
0037 
0038 //we use the one in string*
0039 QMap<Operator::OperatorType, QString> initOperators();
0040 
0041 template <class T>
0042 QStringList HtmlExpressionWriter::allValues(T it, const T& itEnd, AbstractExpressionVisitor* writer)
0043 {
0044     QStringList elements;
0045     for(; it!=itEnd; ++it)
0046         elements += (*it)->accept(writer).toString();
0047     
0048     return elements;
0049 }
0050 
0051 
0052 static const QMap<Operator::OperatorType, QString> s_operators=initOperators();
0053 
0054 QString oper(const QString& op) { return QCoreApplication::translate("html representation of an operator", "<span class='op'>%1</span>").arg(op); }
0055 QString oper(const QChar& op) { return QCoreApplication::translate("html representation of an operator", "<span class='op'>%1</span>").arg(op); }
0056 QString keyword(const QString& op) { return QCoreApplication::translate("html representation of an operator", "<span class='keyword'>%1</span>").arg(op); }
0057 
0058 HtmlExpressionWriter::HtmlExpressionWriter(const Object* o)
0059 {
0060     if(o)
0061         m_result=o->accept(this);
0062 }
0063 
0064 QVariant HtmlExpressionWriter::visit(const Vector* vec)
0065 {
0066     return QString(keyword(QStringLiteral("vector "))+oper(QStringLiteral("{ "))+allValues<Vector::const_iterator>(vec->constBegin(), vec->constEnd(), this).join(QString(oper(QStringLiteral(", "))))+oper(QStringLiteral(" }")));
0067 }
0068 
0069 QVariant HtmlExpressionWriter::visit(const Matrix* m)
0070 {
0071     return QString(keyword(QStringLiteral("matrix "))+oper(QStringLiteral("{ "))+allValues(m->constBegin(), m->constEnd(), this).join(QString(oper(QStringLiteral(", "))))+oper(QStringLiteral(" }")));
0072 }
0073 
0074 QVariant HtmlExpressionWriter::visit(const MatrixRow* mr)
0075 {
0076     return QString(keyword(QStringLiteral("matrixrow "))+oper(QStringLiteral("{ "))+allValues(mr->constBegin(), mr->constEnd(), this).join(QString(oper(QStringLiteral(", "))))+oper(QStringLiteral(" }")));
0077 }
0078 
0079 QVariant HtmlExpressionWriter::visit(const List* vec)
0080 {
0081     if(!vec->isEmpty() && vec->at(0)->type()==Object::value && static_cast<Cn*>(vec->at(0))->format()==Cn::Char) {
0082         return QVariant::fromValue<QString>(QStringLiteral("<span class='string'>&quot;") + AnalitzaUtils::listToString(vec) + QStringLiteral("&quot;</span>"));
0083     } else
0084         return QVariant::fromValue<QString>(keyword(QStringLiteral("list "))+oper(QStringLiteral("{ "))+allValues<List::const_iterator>(vec->constBegin(), vec->constEnd(), this).join(QString(oper(QStringLiteral(", "))))+oper(QStringLiteral(" }")));
0085 }
0086 
0087 QVariant HtmlExpressionWriter::visit(const Cn* var)
0088 {
0089     QString innerhtml;
0090     if(var->isBoolean())
0091         innerhtml = var->isTrue() ? QStringLiteral("true") : QStringLiteral("false");
0092     else if(var->isCharacter())
0093         innerhtml = QString(var->character());
0094     else if(var->isComplex()) {
0095         QString realpart;
0096         QString imagpart;
0097         bool realiszero = false;
0098         const auto complex = var->complexValue();
0099         if (qAbs(complex.real()) > MIN_PRINTABLE_VALUE)
0100             realpart = QString::number(complex.real(), 'g', 12);
0101         else
0102             realiszero = true;
0103 
0104         if (!qFuzzyCompare(qAbs(complex.imag()), 1)) {
0105             if (qAbs(complex.imag()) > MIN_PRINTABLE_VALUE) {
0106                 if (!realiszero && complex.imag()>0.)
0107                     realpart += QLatin1Char('+');
0108                 imagpart = QString::number(complex.imag(), 'g', 12);
0109                 imagpart += QStringLiteral("*i");
0110             }
0111         } else {
0112             if (!realiszero)
0113                 realpart += QLatin1Char('+');
0114             if (qFuzzyCompare(complex.imag(), 1))
0115                 imagpart = QStringLiteral("i");
0116             else
0117                 imagpart = QStringLiteral("-i");
0118         }
0119         
0120         innerhtml = realpart+imagpart;
0121     }
0122     else
0123         innerhtml = QString::number(var->value(), 'g', 12);
0124     
0125     return QVariant::fromValue<QString>(QStringLiteral("<span class='num'>")+innerhtml+"</span>");
0126 }
0127 
0128 QVariant HtmlExpressionWriter::visit(const Analitza::Ci* var)
0129 {
0130     return var->toHtml();
0131 }
0132 
0133 QVariant HtmlExpressionWriter::visit(const Analitza::Operator* o)
0134 {
0135     return QVariant::fromValue<QString>(QStringLiteral("<span class='func'>") + o->toString() + QStringLiteral("</span>"));
0136 }
0137 
0138 QVariant HtmlExpressionWriter::visit ( const Analitza::Apply* a )
0139 {
0140     Operator op=a->firstOperator();
0141     QStringList ret;
0142     QString toret;
0143     QString bounds;
0144     
0145     if(a->ulimit() || a->dlimit()) {
0146         bounds += oper('=');
0147         if(a->dlimit())
0148             bounds += a->dlimit()->accept(this).toString();
0149         bounds += oper(QStringLiteral(".."));
0150         if(a->ulimit())
0151             bounds += a->ulimit()->accept(this).toString();
0152     }
0153     else if(a->domain())
0154         bounds += oper('@')+a->domain()->accept(this).toString();
0155     
0156     int i = 0;
0157     foreach(Object* o, a->m_params) {
0158         Object::ObjectType type=o->type();
0159         switch(type) {
0160             case Object::oper:
0161                 Q_ASSERT(false);
0162                 break;
0163             case Object::variable:
0164                 ret << static_cast<const Ci*>(o)->accept(this).toString();
0165                 break;
0166             case Object::apply: {
0167                 Apply *c = (Apply*) o;
0168                 QString s = c->accept(this).toString();
0169                 if(s_operators.contains(op.operatorType())) {
0170                     Operator child_op = c->firstOperator();
0171                     
0172                     if(child_op.operatorType() && 
0173                             StringExpressionWriter::weight(&op, c->countValues(), -1)>StringExpressionWriter::weight(&child_op, c->countValues(), i))
0174                         s=oper('(')+s+oper(')');
0175                 }
0176                 ret << s;
0177             }    break;
0178             default:
0179                 ret << o->accept(this).toString();
0180                 break;
0181         }
0182         ++i;
0183     }
0184     
0185     bool func=op.operatorType()==Operator::function;
0186     if(func) {
0187         QString n = ret.takeFirst();
0188         if(a->m_params.first()->type()!=Object::variable)
0189             n=oper('(')+n+oper(')');
0190         
0191         toret += n+oper('(') + ret.join(oper(QStringLiteral(", "))) + oper(')');
0192     } else if(op.operatorType()==Operator::selector) {
0193         if(a->m_params.last()->isApply()) {
0194             const Apply* a1=static_cast<const Apply*>(a->m_params.last());
0195             if(s_operators.contains(a1->firstOperator().operatorType()))
0196                 ret.last()=oper('(')+ret.last()+oper(')');
0197         }
0198         
0199         toret += ret.last() + oper('[') + ret.first() + oper(']');
0200     } else if(ret.count()>1 && s_operators.contains(op.operatorType())) {
0201         toret += ret.join(oper(s_operators.value(op.operatorType())));
0202     } else if(ret.count()==1 && op.operatorType()==Operator::minus)
0203         toret += oper('-')+ret[0];
0204     else {
0205         QString bounding;
0206         QStringList bvars;
0207         foreach(const Ci* bvar, a->bvarCi())
0208             bvars += bvar->accept(this).toString();
0209         
0210         if(!bounds.isEmpty() || !bvars.isEmpty()) {
0211             if(bvars.count()!=1) bounding +=oper('(');
0212             bounding += bvars.join(oper(QStringLiteral(", ")));
0213             if(bvars.count()!=1) bounding +=oper(')');
0214             
0215             bounding = ':'+bounding +bounds;
0216         }
0217         
0218         toret += op.accept(this).toString()+oper('(')+ret.join(oper(QStringLiteral(", ")))+bounding+oper(')');
0219     }
0220     
0221     return toret;
0222 }
0223 
0224 QVariant HtmlExpressionWriter::visit(const Container* var)
0225 {
0226     QStringList ret = allValues(var->constBegin(), var->constEnd(), this);
0227     
0228     
0229     QString toret;
0230     switch(var->containerType()) {
0231         case Container::declare:
0232             toret += ret.join(oper(QStringLiteral(":=")));
0233             break;
0234         case Container::lambda: {
0235             QString last=ret.takeLast();
0236             QStringList bvars;
0237             foreach(const Ci* bvar, var->bvarCi())
0238                 bvars += bvar->accept(this).toString();
0239             
0240             if(bvars.count()!=1) toret +=oper('(');
0241             toret += bvars.join(QStringLiteral(", "));
0242             if(bvars.count()!=1) toret +=oper(')');
0243             toret += oper(QStringLiteral("->")) + last;
0244         }    break;
0245         case Container::math:
0246             toret += ret.join(oper(QStringLiteral("; ")));
0247             break;
0248         case Container::uplimit: //x->(n1..n2) is put at the same time
0249         case Container::downlimit:
0250             break;
0251         case Container::bvar:
0252             if(ret.count()>1) toret += oper('(');
0253             toret += ret.join(QStringLiteral(", "));
0254             if(ret.count()>1) toret += oper(')');
0255             break;
0256         case Container::piece:
0257             toret += ret[1]+oper(QStringLiteral(" ? "))+ret[0];
0258             break;
0259         case Container::otherwise:
0260             toret += oper(QStringLiteral("? "))+ret[0];
0261             break;
0262         default:
0263             toret += var->tagName()+oper(QStringLiteral(" { "))+ret.join(oper(QStringLiteral(", ")))+oper(QStringLiteral(" }"));
0264             break;
0265     }
0266     return toret;
0267 }
0268 
0269 QVariant HtmlExpressionWriter::visit(const CustomObject*)
0270 {
0271     return QStringLiteral("Custom Object");
0272 }
0273 
0274 QVariant HtmlExpressionWriter::visit(const None* )
0275 {
0276     return QString();
0277 }