1 /*************************************************************************************
2  *  Copyright (C) 2007-2008 by Aleix Pol <aleixpol@kde.org>                          *
3  *                                                                                   *
4  *  This program is free software; you can redistribute it and/or                    *
5  *  modify it under the terms of the GNU General Public License                      *
6  *  as published by the Free Software Foundation; either version 2                   *
7  *  of the License, or (at your option) any later version.                           *
8  *                                                                                   *
9  *  This program is distributed in the hope that it will be useful,                  *
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of                   *
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                    *
12  *  GNU General Public License for more details.                                     *
13  *                                                                                   *
14  *  You should have received a copy of the GNU General Public License                *
15  *  along with this program; if not, write to the Free Software                      *
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA   *
17  *************************************************************************************/
18 
19 #include "operatorsmodel.h"
20 #include <analitza/operator.h>
21 #include <analitza/variables.h>
22 #include <QFont>
23 #include <QCoreApplication>
24 
25 using Analitza::Operator;
26 
OperatorsModel(QObject * parent)27 OperatorsModel::OperatorsModel(QObject *parent) : QAbstractTableModel(parent), m_vars(nullptr)
28 {
29 }
30 
roleNames() const31 QHash<int, QByteArray> OperatorsModel::roleNames() const
32 {
33     auto ret = QAbstractTableModel::roleNames();
34     ret.insert(IsVariableRole, "isVariable");
35     ret.insert(DescriptionRole, "description");
36     return ret;
37 }
38 
data(const QModelIndex & index,int role) const39 QVariant OperatorsModel::data(const QModelIndex & index, int role) const
40 {
41     QVariant ret;
42     if(role==Qt::DisplayRole) {
43         if(index.row()<Analitza::Operator::nOfOps-2) {
44             Analitza::Operator oper((Analitza::Operator::OperatorType) (index.row()+1));
45 
46             switch(index.column()) {
47                 case 0:
48                     ret=oper.toString();
49                     break;
50                 case 1:
51                     ret=description(oper);
52                     break;
53                 case 2:
54                     ret=sample(oper);
55                     break;
56                 case 3:
57                     ret=example(oper);
58                     break;
59             }
60         } else if(m_vars) {
61             int var=index.row()-Analitza::Operator::nOfOps+2;
62             QString key=m_vars->keys()[var];
63             switch(index.column()) {
64                 case 0:
65                     ret=key;
66                     break;
67                 case 1:
68                     ret=m_vars->value(key)->toString();
69                     break;
70             }
71         }
72     } else if(role==Qt::FontRole && index.column()==1) {
73         QFont f;
74         f.setItalic(true);
75         ret=f;
76     } else if(role==DescriptionRole && index.column()==0) {
77         Analitza::Operator oper((Analitza::Operator::OperatorType) (index.row()+1));
78         switch(index.column()) {
79             case 0:
80                 ret=description(oper);
81                 break;
82         }
83     } else if(role==IsVariableRole && index.column()==0) {
84         ret=index.row()<Analitza::Operator::nOfOps-2;
85     }
86     return ret;
87 }
88 
headerData(int section,Qt::Orientation orientation,int role) const89 QVariant OperatorsModel::headerData(int section, Qt::Orientation orientation, int role) const
90 {
91     QVariant ret;
92     if(role==Qt::DisplayRole && orientation==Qt::Horizontal) {
93         switch(section) {
94             case 0:
95                 ret=QCoreApplication::translate("@title:column", "Name");
96                 break;
97             case 1:
98                 ret=QCoreApplication::translate("@title:column", "Description");
99                 break;
100             case 2:
101                 ret=QCoreApplication::translate("@title:column", "Parameters");
102                 break;
103             case 3:
104                 ret=QCoreApplication::translate("@title:column", "Example");
105                 break;
106         }
107     }
108     return ret;
109 }
110 
rowCount(const QModelIndex &) const111 int OperatorsModel::rowCount(const QModelIndex &) const
112 {
113     int count=Analitza::Operator::nOfOps;
114     if(m_vars)
115         count+=m_vars->count();
116     return count-2;
117 }
118 
columnCount(const QModelIndex &) const119 int OperatorsModel::columnCount(const QModelIndex &) const
120 {
121     return 4;
122 }
123 
updateInformation()124 void OperatorsModel::updateInformation()
125 {
126     beginResetModel();
127     endResetModel();
128 }
129 
sample(const Analitza::Operator & oper)130 QString OperatorsModel::sample(const Analitza::Operator& oper)
131 {
132     QString funcname=oper.toString();
133     QString bounds;
134     if(oper.isBounded()) {
135         bounds=QCoreApplication::translate("Syntax for function bounding", " : var");
136         if(oper.operatorType()==Operator::sum || oper.operatorType()==Operator::product)
137             bounds += QCoreApplication::translate("Syntax for function bounding values", "=from..to");
138     }
139 
140     QString sample = QCoreApplication::tr("%1(").arg(funcname);
141 
142     if(oper.nparams()<0) {
143         return QCoreApplication::tr("%1... parameters, ...%2)").arg(sample, bounds);
144     } else {
145         for(int i=0; i<oper.nparams(); ++i) {
146             sample += QCoreApplication::tr("par%1").arg(i+1);
147             if(i<oper.nparams()-1)
148                 sample += QLatin1String(", ");
149         }
150         return sample+bounds+')';
151     }
152 }
153 
description(const Analitza::Operator & o)154 QString OperatorsModel::description(const Analitza::Operator& o)
155 {
156     QString s;
157     switch(o.operatorType()) {
158         case Operator::plus:
159             s = QCoreApplication::tr("Addition");
160             break;
161         case Operator::times:
162             s = QCoreApplication::tr("Multiplication");
163             break;
164         case Operator::divide:
165             s = QCoreApplication::tr("Division");
166             break;
167         case Operator::minus:
168             s = QCoreApplication::tr("Subtraction. Will remove all values from the first one.");
169             break;
170         case Operator::power:
171             s = QCoreApplication::tr("Power");
172             break;
173         case Operator::rem:
174             s = QCoreApplication::tr("Remainder");
175             break;
176         case Operator::quotient:
177             s = QCoreApplication::tr("Quotient");
178             break;
179         case Operator::factorof:
180             s = QCoreApplication::tr("The factor of");
181             break;
182         case Operator::factorial:
183             s = QCoreApplication::tr("Factorial. factorial(n)=n!");
184             break;
185         case Operator::sin:
186             s = QCoreApplication::tr("Function to calculate the sine of a given angle");
187             break;
188         case Operator::cos:
189             s = QCoreApplication::tr("Function to calculate the cosine of a given angle");
190             break;
191         case Operator::tan:
192             s = QCoreApplication::tr("Function to calculate the tangent of a given angle");
193             break;
194         case Operator::sec:
195             s = QCoreApplication::tr("Secant");
196             break;
197         case Operator::csc:
198             s = QCoreApplication::tr("Cosecant");
199             break;
200         case Operator::cot:
201             s = QCoreApplication::tr("Cotangent");
202             break;
203         case Operator::sinh:
204             s = QCoreApplication::tr("Hyperbolic sine");
205             break;
206         case Operator::cosh:
207             s = QCoreApplication::tr("Hyperbolic cosine");
208             break;
209         case Operator::tanh:
210             s = QCoreApplication::tr("Hyperbolic tangent");
211             break;
212         case Operator::sech:
213             s = QCoreApplication::tr("Hyperbolic secant");
214             break;
215         case Operator::csch:
216             s = QCoreApplication::tr("Hyperbolic cosecant");
217             break;
218         case Operator::coth:
219             s = QCoreApplication::tr("Hyperbolic cotangent");
220             break;
221         case Operator::arcsin:
222             s = QCoreApplication::tr("Arc sine");
223             break;
224         case Operator::arccos:
225             s = QCoreApplication::tr("Arc cosine");
226             break;
227         case Operator::arctan:
228             s = QCoreApplication::tr("Arc tangent");
229             break;
230         case Operator::arccot:
231             s = QCoreApplication::tr("Arc cotangent");
232             break;
233 //         case Operator::arccoth:
234 //             s = QCoreApplication::tr("Hyperbolic arc cotangent");
235 //             break;
236         case Operator::arctanh:
237             s = QCoreApplication::tr("Hyperbolic arc tangent");
238             break;
239         case Operator::sum:
240             s = QCoreApplication::tr("Summatory");
241             break;
242         case Operator::product:
243             s = QCoreApplication::tr("Productory");
244             break;
245         case Operator::forall:
246             s = QCoreApplication::tr("For all");
247             break;
248         case Operator::exists:
249             s = QCoreApplication::tr("Exists");
250             break;
251         case Operator::diff:
252             s = QCoreApplication::tr("Differentiation");
253             break;
254         case Operator::arcsinh:
255             s = QCoreApplication::tr("Hyperbolic arc sine");
256             break;
257         case Operator::arccosh:
258             s = QCoreApplication::tr("Hyperbolic arc cosine");
259             break;
260         case Operator::arccsc:
261             s = QCoreApplication::tr("Arc cosecant");
262             break;
263         case Operator::arccsch:
264             s = QCoreApplication::tr("Hyperbolic arc cosecant");
265             break;
266         case Operator::arcsec:
267             s = QCoreApplication::tr("Arc secant");
268             break;
269         case Operator::arcsech:
270             s = QCoreApplication::tr("Hyperbolic arc secant");
271             break;
272         case Operator::exp:
273             s = QCoreApplication::tr("Exponent (e^x)");
274             break;
275         case Operator::ln:
276             s = QCoreApplication::tr("Base-e logarithm");
277             break;
278         case Operator::log:
279             s = QCoreApplication::tr("Base-10 logarithm");
280             break;
281         case Operator::abs:
282             s = QCoreApplication::tr("Absolute value. abs(n)=|n|");
283             break;
284         case Operator::conjugate:
285             s = QCoreApplication::tr("Conjugate");
286             break;
287         case Operator::arg:
288             s = QCoreApplication::tr("Arg");
289             break;
290         case Operator::real:
291             s = QCoreApplication::tr("Real");
292             break;
293         case Operator::imaginary:
294             s = QCoreApplication::tr("Imaginary");
295             break;
296         case Operator::floor:
297             s = QCoreApplication::tr("Floor value. floor(n)=⌊n⌋");
298             break;
299         case Operator::ceiling:
300             s = QCoreApplication::tr("Ceil value. ceil(n)=⌈n⌉");
301             break;
302         case Operator::min:
303             s = QCoreApplication::tr("Minimum");
304             break;
305         case Operator::max:
306             s = QCoreApplication::tr("Maximum");
307             break;
308         case Operator::gt:
309             s = QCoreApplication::tr("Greater than. gt(a,b)=a>b");
310             break;
311         case Operator::lt:
312             s = QCoreApplication::tr("Less than. lt(a,b)=a<b");
313             break;
314         case Operator::eq:
315             s = QCoreApplication::tr("Equal. eq(a,b) = a=b");
316             break;
317         case Operator::approx:
318             s = QCoreApplication::tr("Approximation. approx(a)=a±n");
319             break;
320         case Operator::neq:
321             s = QCoreApplication::tr("Not equal. neq(a,b)=a≠b");
322             break;
323         case Operator::geq:
324             s = QCoreApplication::tr("Greater or equal. geq(a,b)=a≥b");
325             break;
326         case Operator::leq:
327             s = QCoreApplication::tr("Less or equal. leq(a,b)=a≤b");
328             break;
329         case Operator::_and:
330             s = QCoreApplication::tr("Boolean and");
331             break;
332         case Operator::_not:
333             s = QCoreApplication::tr("Boolean not");
334             break;
335         case Operator::_or:
336             s = QCoreApplication::tr("Boolean or");
337             break;
338         case Operator::_xor:
339             s = QCoreApplication::tr("Boolean xor");
340             break;
341         case Operator::implies:
342             s = QCoreApplication::tr("Boolean implication");
343             break;
344         case Operator::gcd:
345             s = QCoreApplication::tr("Greatest common divisor");
346             break;
347         case Operator::lcm:
348             s = QCoreApplication::tr("Least common multiple");
349             break;
350         case Operator::root:
351             s = QCoreApplication::tr("Root");
352             break;
353         case Operator::card:
354             s = QCoreApplication::tr("Cardinal");
355             break;
356         case Operator::scalarproduct:
357             s = QCoreApplication::tr("Scalar product");
358             break;
359         case Operator::selector:
360             s = QCoreApplication::tr("Select the par1-th element of par2 list or vector");
361             break;
362         case Operator::_union:
363             s = QCoreApplication::tr("Joins several items of the same type");
364             break;
365         case Operator::map:
366             s = QCoreApplication::tr("Applies a function to every element in a list");
367             break;
368         case Operator::filter:
369             s = QCoreApplication::tr("Removes all elements that don't fit a condition");
370             break;
371         case Operator::transpose:
372             s = QCoreApplication::tr("Transpose");
373             break;
374         case Operator::function:
375         case Operator::nOfOps:
376         case Operator::none:
377             break;
378     }
379     return s;
380 }
381 
example(const Analitza::Operator & o)382 QString OperatorsModel::example(const Analitza::Operator& o)
383 {
384     QString s;
385 
386     switch(o.operatorType()) {
387         case Operator::plus:
388             s=QStringLiteral("x+2");
389             break;
390         case Operator::times:
391             s=QStringLiteral("x*2");
392             break;
393         case Operator::divide:
394             s=QStringLiteral("x/2");
395             break;
396         case Operator::minus:
397             s=QStringLiteral("x-2");
398             break;
399         case Operator::power:
400             s=QStringLiteral("x^2");
401             break;
402         case Operator::rem:
403             s=QStringLiteral("rem(x, 5)");
404             break;
405         case Operator::quotient:
406             s=QStringLiteral("quotient(x, 2)");
407             break;
408         case Operator::factorof:
409             s=QStringLiteral("factorof(x, 3)");
410             break;
411         case Operator::min:
412             s=QStringLiteral("min(x, 4)");
413             break;
414         case Operator::max:
415             s=QStringLiteral("max(x, 4)");
416             break;
417         case Operator::gt:
418             s=QStringLiteral("piecewise { x>4 ? 1, ? 0 }");
419             break;
420         case Operator::lt:
421             s=QStringLiteral("piecewise { x<4 ? 1, ? 0 }");
422             break;
423         case Operator::eq:
424             s=QStringLiteral("piecewise { x=4 ? 1, ? 0 }");
425             break;
426         case Operator::approx:
427             s=QStringLiteral("piecewise { approx(x, 4) ? 1, ? 0 }");
428             break;
429         case Operator::neq:
430             s=QStringLiteral("piecewise { x!=4 ? 1, ? 0 }");
431             break;
432         case Operator::geq:
433             s=QStringLiteral("piecewise { x>=4 ? 1, ? 0 }");
434             break;
435         case Operator::leq:
436             s=QStringLiteral("piecewise { x<=4 ? 1, ? 0 }");
437             break;
438         case Operator::_and:
439             s=QStringLiteral("piecewise { and(x>-2, x<2) ? 1, ? 0 }");
440             break;
441         case Operator::_or:
442             s=QStringLiteral("piecewise { or(x>2, x>-2) ? 1, ? 0 }");
443             break;
444         case Operator::_xor:
445             s=QStringLiteral("piecewise { xor(x>0, x<3) ? 1, ? 0 }");
446             break;
447         case Operator::implies:
448             s=QStringLiteral("piecewise { implies(x<0, x<3) ? 1, ? 0 }");
449             break;
450         case Operator::forall:
451             s=QStringLiteral("piecewise { forall(t:t@list { true, false, false }) ? 1, ? 0 }");
452             break;
453         case Operator::exists:
454             s=QStringLiteral("piecewise { exists(t:t@list { true, false, false }) ? 1, ? 0 }");
455             break;
456         case Operator::_not:
457             s=QStringLiteral("piecewise { not(x>0) ? 1, ? 0 }");
458             break;
459         case Operator::gcd:
460             s=QStringLiteral("gcd(x, 3)");
461             break;
462         case Operator::lcm:
463             s=QStringLiteral("lcm(x, 4)");
464             break;
465         case Operator::root:
466             s=QStringLiteral("root(x, 2)");
467             break;
468         case Operator::selector:
469             s=QStringLiteral("scalarproduct(vector { 0, x }, vector { x, 0 })[1]");
470             break;
471         case Operator::sum:
472             s=QStringLiteral("x*sum(t*t:t=0..3)");
473             break;
474         case Operator::product:
475             s=QStringLiteral("product(t+t:t=1..3)");
476             break;
477         case Operator::card:
478             s=QStringLiteral("card(vector { x, 1, 2 })");
479             break;
480         case Operator::scalarproduct:
481             s=QStringLiteral("scalarproduct(vector { 0, x }, vector { x, 0 })[1]");
482             break;
483         case Operator::diff:
484             s=QStringLiteral("(diff(x^2:x))(x)");
485             break;
486         case Operator::_union:
487             s=QStringLiteral("union(list { 1, 2, 3 }, list { 4, 5, 6 })[rem(floor(x), 5)+3]");
488             break;
489         case Operator::map:
490             s=QStringLiteral("map(x->x+x, list { 1, 2, 3, 4, 5, 6 })[rem(floor(x), 5)+3]");
491             break;
492         case Operator::filter:
493             s=QStringLiteral("filter(u->rem(u, 2)=0, list { 2, 4, 3, 4, 8, 6 })[rem(floor(x), 5)+3]");
494             break;
495         case Operator::transpose:
496             s = QStringLiteral("transpose(matrix { matrixrow { 1, 2, 3, 4, 5, 6 } })[rem(floor(x), 5)+3][1]");
497             break;
498         case Operator::real:
499             s = QStringLiteral("real(x*i)");
500             break;
501         case Operator::conjugate:
502             s = QStringLiteral("conjugate(x*i)");
503             break;
504         case Operator::arg:
505             s = QStringLiteral("arg(x*i)");
506             break;
507         case Operator::imaginary:
508             s = QStringLiteral("imaginary(x*i)");
509             break;
510         case Operator::factorial:
511         case Operator::arcsech:
512         case Operator::arcsec:
513         case Operator::arccsch:
514         case Operator::arccsc:
515 //         case Operator::arccoth:
516         case Operator::sin:
517         case Operator::cos:
518         case Operator::tan:
519         case Operator::sec:
520         case Operator::csc:
521         case Operator::cot:
522         case Operator::sinh:
523         case Operator::cosh:
524         case Operator::tanh:
525         case Operator::sech:
526         case Operator::csch:
527         case Operator::coth:
528         case Operator::arcsin:
529         case Operator::arccos:
530         case Operator::arctan:
531         case Operator::arccot:
532         case Operator::arcsinh:
533         case Operator::arccosh:
534 //         case Operator::arccsc:
535 //         case Operator::arccsch:
536 //         case Operator::arcsec:
537 //         case Operator::arcsech:
538         case Operator::arctanh:
539         case Operator::exp:
540         case Operator::ln:
541         case Operator::log:
542         case Operator::abs:
543         case Operator::floor:
544         case Operator::ceiling:
545             s=QStringLiteral("%1(x)").arg(o.toString());
546             break;
547         case Operator::nOfOps:
548         case Operator::none:
549         case Operator::function:
550             break;
551     }
552     return "x->"+s;
553 }
554 
indexForOperatorName(const QString & id) const555 QModelIndex OperatorsModel::indexForOperatorName(const QString& id) const
556 {
557     Operator::OperatorType opt=Analitza::Operator::toOperatorType(id);
558     if(opt==Operator::none)
559         return QModelIndex();
560     else
561         return index(opt-1, 0);
562 }
563 
parameterHelp(const QModelIndex & index,int param,bool inbounds) const564 QString OperatorsModel::parameterHelp(const QModelIndex& index, int param, bool inbounds) const
565 {
566     Q_ASSERT(index.isValid());
567     QString ret;
568     Analitza::Operator oper((Analitza::Operator::OperatorType) (index.row()+1));
569     QString funcname = oper.toString();
570     const int op=oper.nparams();
571     if(op == -1) {
572         ret=QCoreApplication::translate("n-ary function prototype", "<em>%1</em>(..., <b>par%2</b>, ...)").arg(funcname).arg(param+1);
573     } else {
574         ret=standardFunctionCallHelp(funcname, param, op, inbounds, oper.isBounded());
575     }
576     return ret;
577 }
578 
standardFunctionCallHelp(const QString & funcname,int param,int paramcount,bool inbounds,bool isbounded)579 QString OperatorsModel::standardFunctionCallHelp(const QString& funcname, int param, int paramcount, bool inbounds, bool isbounded)
580 {
581     QString sample = (param < paramcount || (inbounds && isbounded)) ?
582         QCoreApplication::translate("Function name in function prototype", "<em>%1</em>(").arg(funcname) :
583         QCoreApplication::translate("Uncorrect function name in function prototype", "<em style='color:red'><b>%1</b></em>(").arg(funcname);
584 
585     for(int i=0; i<paramcount; ++i) {
586         QString current=QCoreApplication::translate("Parameter in function prototype", "par%1").arg(i+1);
587 
588         if(i==param)
589             current=QCoreApplication::translate("Current parameter in function prototype", "<b>%1</b>").arg(current);
590         sample += current;
591         if(i<paramcount-1)
592             sample += QCoreApplication::translate("Function parameter separator", ", ");
593     }
594 
595     if(isbounded) {
596         static QString bounds=QCoreApplication::translate("Current parameter is the bounding", " : bounds");
597         QString p=bounds;
598         if(inbounds)
599             p=QCoreApplication::translate("Current parameter in function prototype", "<b>%1</b>").arg(p);
600         sample += p;
601     }
602 
603     return sample+')';
604 
605 }
606 
lastWord(int pos,const QString & exp)607 QString OperatorsModel::lastWord(int pos, const QString& exp)
608 {
609     int act=pos-1;
610     for(; act>=0 && exp[act].isLetter(); act--) {}
611 
612     return exp.mid(act+1, pos-act-1);
613 }
614 
615 /*QString OperatorsModel::operToString(const Operator& op) const
616 {
617     QStandardItem *it;
618 
619     for(int i=0; i<KEYWORDNUM; i++) {
620         it=item(i,2);
621         if(it!=NULL && it->data(Qt::EditRole).toInt()==op.operatorType()) {
622             return item(i,0)->data(Qt::EditRole).toString();
623 }
624 }
625     return QString();
626 }*/
627 
628 
629