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