File indexing completed on 2024-04-28 11:20:38
0001 /* 0002 SPDX-FileCopyrightText: 2009 Milian Wolff <mail@milianw.de> 0003 SPDX-FileCopyrightText: 2011 Matteo Agostinelli <agostinelli@gmail.com> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include <config-cantorlib.h> 0009 0010 #include "textresult.h" 0011 #include "helpresult.h" 0012 #include "imageresult.h" 0013 #include "epsresult.h" 0014 #include "settings.h" 0015 #include "defaultvariablemodel.h" 0016 0017 #include "qalculateexpression.h" 0018 #include "qalculatesession.h" 0019 #include "qalculatesyntaxhelpobject.h" 0020 0021 #include <libqalculate/ExpressionItem.h> 0022 #include <libqalculate/Unit.h> 0023 #include <libqalculate/Prefix.h> 0024 #include <libqalculate/Variable.h> 0025 #include <libqalculate/Function.h> 0026 0027 // required for the plotting interface of Qalculator 0028 0029 #include <QDir> 0030 #include <QTemporaryFile> 0031 0032 #include <KMessageBox> 0033 #include <KColorScheme> 0034 #include <KLocalizedString> 0035 #include <QLocale> 0036 0037 #include <QApplication> 0038 #include <QStack> 0039 0040 QalculateExpression::QalculateExpression( QalculateSession* session, bool internal) 0041 : Cantor::Expression(session, internal) 0042 { 0043 } 0044 0045 QalculateExpression::~QalculateExpression() 0046 { 0047 if (m_tempFile) 0048 delete m_tempFile; 0049 } 0050 0051 void QalculateExpression::evaluate() 0052 { 0053 /* 0054 Use Api for: 0055 * help 0056 * plot 0057 Use qalc for any other command 0058 */ 0059 setStatus(Cantor::Expression::Computing); 0060 if (command().isEmpty()) { 0061 setStatus(Cantor::Expression::Done); 0062 return; 0063 } 0064 0065 0066 QStringList commands = command().split(QLatin1Char('\n')); 0067 foreach(const QString& command, commands) 0068 { 0069 if (command.contains(QLatin1String("help"))) { 0070 QalculateSyntaxHelpObject* helper = new QalculateSyntaxHelpObject(command, (QalculateSession*) session()); 0071 setResult(new Cantor::HelpResult(helper->answer())); 0072 setStatus(Cantor::Expression::Done); 0073 return; 0074 } 0075 else if (command.trimmed().startsWith(QLatin1String("plot")) && 0076 (command.indexOf(QLatin1String("plot"))+4 == command.size() || 0077 command[command.indexOf(QLatin1String("plot"))+4].isSpace())) { 0078 evaluatePlotCommand(); 0079 return; 0080 } 0081 } 0082 // we are here because the commands entered by user are regular commands. We would have returned by now otherwise 0083 QalculateSession* currentSession = dynamic_cast<QalculateSession*>(session()); 0084 currentSession->runExpression(); 0085 } 0086 0087 void QalculateExpression::parseOutput(const QString& output) 0088 { 0089 QString resultStr = output; 0090 resultStr.remove(QLatin1String(">")); 0091 resultStr = resultStr.trimmed(); 0092 0093 qDebug() << "output from qalc for command: " << command() << " " << resultStr; 0094 setResult(new Cantor::TextResult(resultStr)); 0095 // update the variable model 0096 updateVariables(); 0097 setStatus(Cantor::Expression::Done); 0098 } 0099 0100 void QalculateExpression::updateVariables() 0101 { 0102 auto* currentSession = dynamic_cast<QalculateSession*>(session()); 0103 auto& variables = currentSession->variables; 0104 auto it = variables.constBegin(); 0105 while (it != variables.constEnd()) { 0106 currentSession->variableModel()->addVariable(it.key(), it.value()); 0107 ++it; 0108 } 0109 } 0110 0111 void QalculateExpression::parseError(const QString& error) 0112 { 0113 QString errorStr = error; 0114 errorStr.remove(QLatin1String(">")); 0115 errorStr = errorStr.trimmed(); 0116 qDebug() << "Error from qalc for command: " << command() << " " << error; 0117 setErrorMessage(errorStr); 0118 setStatus(Cantor::Expression::Error); 0119 } 0120 0121 void QalculateExpression::evaluatePlotCommand() 0122 { 0123 QString argString = command().mid(command().indexOf(QLatin1String("plot"))+4); 0124 argString = QLatin1String(unlocalizeExpression(argString).c_str()); 0125 argString = argString.trimmed(); 0126 0127 QList<QStringList> argumentsList; 0128 QStringList arguments; 0129 0130 // For error handling 0131 KColorScheme scheme(QApplication::palette().currentColorGroup()); 0132 const QString errorColor = scheme.foreground(KColorScheme::NegativeText).color().name(); 0133 const QString warningColor = scheme.foreground(KColorScheme::NeutralText).color().name(); 0134 const QString msgFormat(QLatin1String("<font color=\"%1\">%2: %3</font><br>\n")); 0135 0136 if (!CALCULATOR->canPlot()) { 0137 showMessage(i18n("Qalculate reports it cannot print. Is gnuplot installed?"), MESSAGE_ERROR); 0138 return; 0139 } 0140 0141 // Split argString into the arguments 0142 int i=0; 0143 int j=0; 0144 QString arg = QLatin1String(""); 0145 while (i < argString.size()) { 0146 if (argString[i] == QLatin1Char('"') || argString[i] == QLatin1Char('\'')) { 0147 ++j; 0148 while(j < argString.size() && argString[j] != argString[i]) { 0149 if (argString[j] == QLatin1Char('\\')) { 0150 ++j; 0151 if (j == argString.size()) 0152 continue; // just ignore trailing backslashes 0153 } 0154 arg += argString[j]; 0155 ++j; 0156 } 0157 if (j == argString.size()) { 0158 showMessage(i18n("missing %1", argString[i]), MESSAGE_ERROR); 0159 return; 0160 } 0161 ++j; 0162 } else if (argString[i] == QLatin1Char(',')) { 0163 argumentsList.append(arguments); 0164 arguments.clear(); 0165 ++j; 0166 } else { 0167 while(j < argString.size() && !argString[j].isSpace() && 0168 argString[j] != QLatin1Char('=') && argString[j] != QLatin1Char(',')) { 0169 if (argString[j] == QLatin1Char('\\')) { 0170 ++j; 0171 if (j == argString.size()) 0172 continue; // just ignore trailing backslashes 0173 } 0174 arg += argString[j]; 0175 ++j; 0176 } 0177 } 0178 if (argString[j] == QLatin1Char('=')) { 0179 // Parse things like title="..." as one argument 0180 arg += QLatin1Char('='); 0181 i = ++j; 0182 continue; 0183 } 0184 if (!arg.isEmpty()) { 0185 arguments << arg; 0186 arg = QLatin1String(""); 0187 } 0188 while (j < argString.size() && argString[j].isSpace()) 0189 ++j; 0190 i = j; 0191 } 0192 argumentsList.append(arguments); 0193 0194 // Parse the arguments and compute the points to be plotted 0195 std::vector<MathStructure> y_vectors; 0196 std::vector<MathStructure> x_vectors; 0197 std::vector<PlotDataParameters*> plotDataParameterList; 0198 PlotParameters plotParameters; 0199 EvaluationOptions eo = evaluationOptions(); 0200 /// temporary 0201 plotParameters.title = ""; 0202 plotParameters.y_label = ""; 0203 plotParameters.x_label = ""; 0204 plotParameters.filename = ""; 0205 plotParameters.filetype = PLOT_FILETYPE_AUTO; 0206 plotParameters.color = QalculateSettings::coloredPlot(); 0207 plotParameters.auto_y_min = true; 0208 plotParameters.auto_x_min = true; 0209 plotParameters.auto_x_max = true; 0210 plotParameters.auto_y_max = true; 0211 plotParameters.y_log = false; 0212 plotParameters.x_log = false; 0213 plotParameters.grid = QalculateSettings::plotGrid(); 0214 plotParameters.linewidth = QalculateSettings::plotLineWidth(); 0215 plotParameters.show_all_borders = QalculateSettings::plotBorder(); 0216 switch (QalculateSettings::plotLegend()) { 0217 case QalculateSettings::LEGEND_NONE: 0218 plotParameters.legend_placement = PLOT_LEGEND_NONE; 0219 break; 0220 case QalculateSettings::LEGEND_TOP_LEFT: 0221 plotParameters.legend_placement = PLOT_LEGEND_TOP_LEFT; 0222 break; 0223 case QalculateSettings::LEGEND_TOP_RIGHT: 0224 plotParameters.legend_placement = PLOT_LEGEND_TOP_RIGHT; 0225 break; 0226 case QalculateSettings::LEGEND_BOTTOM_LEFT: 0227 plotParameters.legend_placement = PLOT_LEGEND_BOTTOM_LEFT; 0228 break; 0229 case QalculateSettings::LEGEND_BOTTOM_RIGHT: 0230 plotParameters.legend_placement = PLOT_LEGEND_BOTTOM_RIGHT; 0231 break; 0232 case QalculateSettings::LEGEND_BELOW: 0233 plotParameters.legend_placement = PLOT_LEGEND_BELOW; 0234 break; 0235 case QalculateSettings::LEGEND_OUTSIDE: 0236 plotParameters.legend_placement = PLOT_LEGEND_OUTSIDE; 0237 break; 0238 } 0239 bool plotInline = QalculateSettings::inlinePlot(); 0240 MathStructure xMin; 0241 MathStructure xMax; 0242 xMin.setUndefined(); 0243 xMax.setUndefined(); 0244 MathStructure stepLength; 0245 stepLength.setUndefined(); 0246 int steps = QalculateSettings::plotSteps(); 0247 0248 QString mustBeNumber = i18n("%1 must be a number."); 0249 QString mustBeInteger = i18n("%1 must be a integer."); 0250 QString mustBeBoolean = i18n("%1 must be a boolean."); 0251 QString invalidOption = i18n("invalid option for %1: %2"); 0252 0253 for (int i = 0; i < argumentsList.size(); ++i) { 0254 std::string xVariable = "x"; 0255 PlotDataParameters* plotDataParams = new PlotDataParameters; 0256 plotDataParameterList.push_back(plotDataParams); 0257 plotDataParams->title = ""; 0258 switch(QalculateSettings::plotSmoothing()) { 0259 case QalculateSettings::SMOOTHING_NONE: 0260 plotDataParams->smoothing = PLOT_SMOOTHING_NONE; 0261 break; 0262 case QalculateSettings::SMOOTHING_UNIQUE: 0263 plotDataParams->smoothing = PLOT_SMOOTHING_UNIQUE; 0264 break; 0265 case QalculateSettings::SMOOTHING_CSPLINES: 0266 plotDataParams->smoothing = PLOT_SMOOTHING_CSPLINES; 0267 break; 0268 case QalculateSettings::SMOOTHING_BEZIER: 0269 plotDataParams->smoothing = PLOT_SMOOTHING_BEZIER; 0270 break; 0271 case QalculateSettings::SMOOTHING_SBEZIER: 0272 plotDataParams->smoothing = PLOT_SMOOTHING_SBEZIER; 0273 break; 0274 } 0275 switch(QalculateSettings::plotStyle()) { 0276 case QalculateSettings::STYLE_LINES: 0277 plotDataParams->style = PLOT_STYLE_LINES; 0278 break; 0279 case QalculateSettings::STYLE_POINTS: 0280 plotDataParams->style = PLOT_STYLE_POINTS; 0281 break; 0282 case QalculateSettings::STYLE_LINES_POINTS: 0283 plotDataParams->style = PLOT_STYLE_POINTS_LINES; 0284 break; 0285 case QalculateSettings::STYLE_BOXES: 0286 plotDataParams->style = PLOT_STYLE_BOXES; 0287 break; 0288 case QalculateSettings::STYLE_HISTOGRAM: 0289 plotDataParams->style = PLOT_STYLE_HISTOGRAM; 0290 break; 0291 case QalculateSettings::STYLE_STEPS: 0292 plotDataParams->style = PLOT_STYLE_STEPS; 0293 break; 0294 case QalculateSettings::STYLE_CANDLESTICKS: 0295 plotDataParams->style = PLOT_STYLE_CANDLESTICKS; 0296 break; 0297 case QalculateSettings::STYLE_DOTS: 0298 plotDataParams->style = PLOT_STYLE_DOTS; 0299 break; 0300 } 0301 plotDataParams->yaxis2 = false; 0302 plotDataParams->xaxis2 = false; 0303 arguments = argumentsList[i]; 0304 std::string expression; 0305 int lastExpressionEntry = -1; 0306 for (int j = 0; j < arguments.size(); ++j) { 0307 QString argument = arguments[j]; 0308 // PlotParameters 0309 if (argument.startsWith(QLatin1String("plottitle="))) 0310 plotParameters.title = argument.mid(10).toLatin1().data(); 0311 else if (argument.startsWith(QLatin1String("ylabel="))) 0312 plotParameters.y_label = argument.mid(7).toLatin1().data(); 0313 else if (argument.startsWith(QLatin1String("xlabel="))) 0314 plotParameters.x_label = argument.mid(7).toLatin1().data(); 0315 else if (argument.startsWith(QLatin1String("filename="))) 0316 plotParameters.filename = argument.mid(9).toLatin1().data(); 0317 else if (argument.startsWith(QLatin1String("filetype="))) { 0318 QString option = argument.mid(9); 0319 if (option == QLatin1String("auto")) 0320 plotParameters.filetype = PLOT_FILETYPE_AUTO; 0321 else if (option == QLatin1String("png")) 0322 plotParameters.filetype = PLOT_FILETYPE_PNG; 0323 else if (option == QLatin1String("ps")) 0324 plotParameters.filetype = PLOT_FILETYPE_PS; 0325 else if (option == QLatin1String("eps")) 0326 plotParameters.filetype = PLOT_FILETYPE_EPS; 0327 else if (option == QLatin1String("latex")) 0328 plotParameters.filetype = PLOT_FILETYPE_LATEX; 0329 else if (option == QLatin1String("svg")) 0330 plotParameters.filetype = PLOT_FILETYPE_SVG; 0331 else if (option == QLatin1String("fig")) 0332 plotParameters.filetype = PLOT_FILETYPE_FIG; 0333 else { 0334 QString msg = invalidOption.arg(QLatin1String("filetype"), option); 0335 showMessage(msg, MESSAGE_ERROR); 0336 deletePlotDataParameters(plotDataParameterList); 0337 return; 0338 } 0339 } 0340 else if (argument.startsWith(QLatin1String("font="))) 0341 plotParameters.font = argument.mid(5).toLatin1().data(); 0342 else if (argument.startsWith(QLatin1String("color="))) { 0343 bool ok; 0344 plotParameters.color = stringToBool(argument.mid(6), &ok); 0345 if (!ok) { 0346 showMessage(mustBeBoolean.arg(QLatin1String("color")), 0347 MESSAGE_ERROR); 0348 deletePlotDataParameters(plotDataParameterList); 0349 return; 0350 } 0351 } 0352 else if (argument.startsWith(QLatin1String("ylog="))) { 0353 bool ok; 0354 plotParameters.y_log = stringToBool(argument.mid(5), &ok); 0355 if (!ok) { 0356 showMessage(mustBeBoolean.arg(QLatin1String("ylog")), MESSAGE_ERROR); 0357 deletePlotDataParameters(plotDataParameterList); 0358 return; 0359 } 0360 } 0361 else if (argument.startsWith(QLatin1String("xlog="))) { 0362 bool ok; 0363 plotParameters.x_log = stringToBool(argument.mid(5), &ok); 0364 if (!ok) { 0365 showMessage(mustBeBoolean.arg(QLatin1String("xlog")), MESSAGE_ERROR); 0366 return; 0367 } 0368 } 0369 else if (argument.startsWith(QLatin1String("ylogbase="))) { 0370 MathStructure ylogStr = CALCULATOR->calculate(argument.mid(9).toLatin1().data(), eo); 0371 if (checkForCalculatorMessages() & (MSG_WARN|MSG_ERR)) { 0372 deletePlotDataParameters(plotDataParameterList); 0373 return; 0374 } 0375 if (ylogStr.isNumber()) { 0376 Number ylogNum = ylogStr.number(); 0377 plotParameters.y_log_base = ylogNum.floatValue(); 0378 } else { 0379 showMessage(mustBeNumber.arg(QLatin1String("ylogbase")), MESSAGE_ERROR); 0380 deletePlotDataParameters(plotDataParameterList); 0381 return; 0382 } 0383 } 0384 else if (argument.startsWith(QLatin1String("xlogbase="))) { 0385 MathStructure xlogStr = CALCULATOR->calculate(argument.mid(9).toLatin1().data(), eo); 0386 if (checkForCalculatorMessages() & (MSG_WARN|MSG_ERR)) { 0387 deletePlotDataParameters(plotDataParameterList); 0388 return; 0389 } 0390 if (xlogStr.isNumber()) { 0391 Number xlogNum = xlogStr.number(); 0392 plotParameters.x_log_base = xlogNum.floatValue(); 0393 } else { 0394 showMessage(mustBeNumber.arg(QLatin1String("xlogbase")), MESSAGE_ERROR); 0395 deletePlotDataParameters(plotDataParameterList); 0396 return; 0397 } 0398 } 0399 else if (argument.startsWith(QLatin1String("grid="))) { 0400 bool ok; 0401 plotParameters.grid = stringToBool(argument.mid(5), &ok); 0402 if (!ok) { 0403 showMessage(mustBeBoolean.arg(QLatin1String("grid")), MESSAGE_ERROR); 0404 deletePlotDataParameters(plotDataParameterList); 0405 return; 0406 } 0407 } 0408 else if (argument.startsWith(QLatin1String("linewidth="))) { 0409 MathStructure lineWidthStr = CALCULATOR->calculate(argument.mid(10).toLatin1().data(), eo); 0410 Number lineWidthNum; 0411 if (lineWidthStr.isNumber() && lineWidthStr.number().isInteger()) { 0412 lineWidthNum = lineWidthStr.number(); 0413 plotParameters.linewidth = lineWidthNum.intValue(); 0414 } else { 0415 showMessage(mustBeInteger.arg(QLatin1String("linewidth")), MESSAGE_ERROR); 0416 deletePlotDataParameters(plotDataParameterList); 0417 return; 0418 } 0419 } 0420 else if (argument.startsWith(QLatin1String("border="))) { 0421 bool ok; 0422 plotParameters.show_all_borders = stringToBool(argument.mid(7), &ok); 0423 if (!ok) { 0424 showMessage(mustBeBoolean.arg(QLatin1String("border")), MESSAGE_ERROR); 0425 deletePlotDataParameters(plotDataParameterList); 0426 return; 0427 } 0428 } 0429 else if (argument.startsWith(QLatin1String("legend="))) { 0430 QString option = argument.mid(7); 0431 if (option == QLatin1String("none")) 0432 plotParameters.legend_placement = PLOT_LEGEND_NONE; 0433 else if (option == QLatin1String("top_left")) 0434 plotParameters.legend_placement = PLOT_LEGEND_TOP_LEFT; 0435 else if (option == QLatin1String("top_right")) 0436 plotParameters.legend_placement = PLOT_LEGEND_TOP_RIGHT; 0437 else if (option == QLatin1String("bottom_left")) 0438 plotParameters.legend_placement = PLOT_LEGEND_BOTTOM_LEFT; 0439 else if (option == QLatin1String("bottom_right")) 0440 plotParameters.legend_placement = PLOT_LEGEND_BOTTOM_RIGHT; 0441 else if (option == QLatin1String("below")) 0442 plotParameters.legend_placement = PLOT_LEGEND_BELOW; 0443 else if (option == QLatin1String("outside")) 0444 plotParameters.legend_placement = PLOT_LEGEND_OUTSIDE; 0445 else { 0446 QString msg = invalidOption.arg(QLatin1String("legend"), option); 0447 showMessage(msg, MESSAGE_ERROR); 0448 deletePlotDataParameters(plotDataParameterList); 0449 return; 0450 } 0451 } 0452 // PlotDataParameters 0453 else if (argument.startsWith(QLatin1String("title="))) { 0454 plotDataParams->title = argument.mid(6).toLatin1().data(); 0455 } 0456 else if (argument.startsWith(QLatin1String("smoothing="))) { 0457 QString option = argument.mid(10); 0458 if (option == QLatin1String("none")) 0459 plotDataParams->smoothing = PLOT_SMOOTHING_NONE; 0460 else if (option == QLatin1String("monotonic")) 0461 plotDataParams->smoothing = PLOT_SMOOTHING_UNIQUE; 0462 else if (option == QLatin1String("csplines")) 0463 plotDataParams->smoothing = PLOT_SMOOTHING_CSPLINES; 0464 else if (option == QLatin1String("bezier")) 0465 plotDataParams->smoothing = PLOT_SMOOTHING_BEZIER; 0466 else if (option == QLatin1String("sbezier")) 0467 plotDataParams->smoothing = PLOT_SMOOTHING_SBEZIER; 0468 else { 0469 QString msg = invalidOption.arg(QLatin1String("smoothing"), option); 0470 showMessage(msg, MESSAGE_ERROR); 0471 deletePlotDataParameters(plotDataParameterList); 0472 return; 0473 } 0474 } else if (argument.startsWith(QLatin1String("style="))) { 0475 QString option = argument.mid(6); 0476 if (option == QLatin1String("lines")) 0477 plotDataParams->style = PLOT_STYLE_LINES; 0478 else if (option == QLatin1String("points")) 0479 plotDataParams->style = PLOT_STYLE_POINTS; 0480 else if (option == QLatin1String("points_lines")) 0481 plotDataParams->style = PLOT_STYLE_POINTS_LINES; 0482 else if (option == QLatin1String("boxes")) 0483 plotDataParams->style = PLOT_STYLE_BOXES; 0484 else if (option == QLatin1String("histogram")) 0485 plotDataParams->style = PLOT_STYLE_HISTOGRAM; 0486 else if (option == QLatin1String("steps")) 0487 plotDataParams->style = PLOT_STYLE_STEPS; 0488 else if (option == QLatin1String("candlesticks")) 0489 plotDataParams->style = PLOT_STYLE_CANDLESTICKS; 0490 else if (option == QLatin1String("dots")) 0491 plotDataParams->style = PLOT_STYLE_DOTS; 0492 else { 0493 QString msg = invalidOption.arg(QLatin1String("style"), option); 0494 showMessage(msg, MESSAGE_ERROR); 0495 deletePlotDataParameters(plotDataParameterList); 0496 return; 0497 } 0498 } else if (argument.startsWith(QLatin1String("xaxis2="))) { 0499 bool ok; 0500 plotDataParams->xaxis2 = stringToBool(argument.mid(7), &ok); 0501 if (!ok) { 0502 showMessage(mustBeBoolean.arg(QLatin1String("xaxis2")), MESSAGE_ERROR); 0503 deletePlotDataParameters(plotDataParameterList); 0504 return; 0505 } 0506 } else if (argument.startsWith(QLatin1String("yaxis2="))) { 0507 bool ok; 0508 plotDataParams->yaxis2 = stringToBool(argument.mid(7), &ok); 0509 if (!ok) { 0510 showMessage(mustBeBoolean.arg(QLatin1String("yaxis2")), MESSAGE_ERROR); 0511 deletePlotDataParameters(plotDataParameterList); 0512 return; 0513 } 0514 } 0515 // inline, xmin, xmax, step, steps, xvar 0516 // Custom options 0517 else if (argument.startsWith(QLatin1String("inline="))) { 0518 bool ok; 0519 plotInline = stringToBool(argument.mid(7), &ok); 0520 if (!ok) { 0521 showMessage(mustBeBoolean.arg(QLatin1String("inline")), MESSAGE_ERROR); 0522 deletePlotDataParameters(plotDataParameterList); 0523 return; 0524 } 0525 } 0526 else if (argument.startsWith(QLatin1String("xmin="))) { 0527 xMin = CALCULATOR->calculate(argument.mid(5).toLatin1().data(), eo); 0528 if (checkForCalculatorMessages() & (MSG_WARN|MSG_ERR)) { 0529 deletePlotDataParameters(plotDataParameterList); 0530 return; 0531 } 0532 } 0533 else if (argument.startsWith(QLatin1String("xmax="))) { 0534 xMax = CALCULATOR->calculate(argument.mid(5).toLatin1().data(), eo); 0535 if (checkForCalculatorMessages() & (MSG_WARN|MSG_ERR)) { 0536 deletePlotDataParameters(plotDataParameterList); 0537 return; 0538 } 0539 } 0540 else if (argument.startsWith(QLatin1String("step="))) { 0541 stepLength = CALCULATOR->calculate(argument.mid(5).toLatin1().data(), eo); 0542 if (checkForCalculatorMessages() & (MSG_WARN|MSG_ERR)) { 0543 deletePlotDataParameters(plotDataParameterList); 0544 return; 0545 } 0546 steps = -1; 0547 } 0548 else if (argument.startsWith(QLatin1String("steps="))) { 0549 MathStructure stepsStr = CALCULATOR->calculate(argument.mid(6).toLatin1().data(), eo); 0550 if (checkForCalculatorMessages() & (MSG_WARN|MSG_ERR)) { 0551 deletePlotDataParameters(plotDataParameterList); 0552 return; 0553 } 0554 Number stepsNum; 0555 if (stepsStr.isNumber() && stepsStr.number().isInteger()) { 0556 stepsNum = stepsStr.number(); 0557 steps = stepsNum.intValue(); 0558 stepLength.setUndefined(); 0559 } else { 0560 showMessage(mustBeInteger.arg(QLatin1String("steps")), MESSAGE_ERROR); 0561 deletePlotDataParameters(plotDataParameterList); 0562 return; 0563 } 0564 } 0565 else if (argument.startsWith(QLatin1String("xvar="))) { 0566 xVariable = argument.mid(5).toLatin1().data(); 0567 } 0568 else if (expression.empty()) { 0569 expression = argument.toLatin1().data(); 0570 lastExpressionEntry = j; 0571 } 0572 else if (lastExpressionEntry == j-1) { 0573 expression += " "; 0574 expression += argument.toLatin1().data(); 0575 lastExpressionEntry = j; 0576 } 0577 else { 0578 QString msg = i18n("found multiple expressions in one plot command (%1 and %2).", QLatin1String(expression.c_str()), argument); 0579 showMessage(msg, MESSAGE_ERROR); 0580 deletePlotDataParameters(plotDataParameterList); 0581 return; 0582 } 0583 } 0584 if (expression.empty()) 0585 continue; 0586 if (xMin.isUndefined()) { 0587 if (!plotParameters.auto_x_min) 0588 xMin = plotParameters.x_min; 0589 else 0590 xMin = 0.0; 0591 } 0592 if (xMax.isUndefined()) { 0593 if (!plotParameters.auto_x_max) 0594 xMax = plotParameters.x_max; 0595 else 0596 xMax = 10.0; 0597 } 0598 if (plotDataParams->title.empty()) 0599 plotDataParams->title = expression; 0600 MathStructure x_vec, y_vec; 0601 x_vec.clearVector(); 0602 if (!stepLength.isUndefined()) 0603 y_vec = CALCULATOR->expressionToPlotVector(expression, xMin, xMax, stepLength, &x_vec, xVariable, eo.parse_options); 0604 else 0605 y_vec = CALCULATOR->expressionToPlotVector(expression, xMin, xMax, steps, &x_vec, xVariable, eo.parse_options); 0606 if (checkForCalculatorMessages() & (MSG_WARN|MSG_ERR)) { 0607 deletePlotDataParameters(plotDataParameterList); 0608 return; 0609 } 0610 0611 x_vectors.push_back(x_vec); 0612 y_vectors.push_back(y_vec); 0613 0614 //PrintOptions po; 0615 //y_vec.format(po); 0616 0617 //setResult(new Cantor::TextResult(y_vec.print(po).c_str())); 0618 //setStatus(Done); 0619 //deletePlotDataParameters(plotDataParameterList); 0620 //return; 0621 } 0622 0623 if (plotInline && plotParameters.filename.empty()) { 0624 // TODO: get a temporary file name here 0625 if (!m_tempFile) { 0626 #ifdef WITH_EPS 0627 m_tempFile=new QTemporaryFile(QDir::tempPath() + QLatin1String("/cantor_qalculate-XXXXXX.eps" )); 0628 #else 0629 m_tempFile=new QTemporaryFile(QDir::tempPath() + QLatin1String("/cantor_qalculate-XXXXXX.png")); 0630 #endif 0631 m_tempFile->open(); 0632 } 0633 plotParameters.filename = m_tempFile->fileName().toLatin1().data(); 0634 plotParameters.filetype = PLOT_FILETYPE_AUTO; 0635 } 0636 0637 CALCULATOR->plotVectors(&plotParameters, y_vectors, x_vectors, 0638 plotDataParameterList); 0639 if (checkForCalculatorMessages() & (MSG_WARN|MSG_ERR)) { 0640 deletePlotDataParameters(plotDataParameterList); 0641 return; 0642 } 0643 0644 deletePlotDataParameters(plotDataParameterList); 0645 0646 if (plotInline) { 0647 #ifdef WITH_EPS 0648 size_t p = plotParameters.filename.size(); 0649 if (plotParameters.filetype == PLOT_FILETYPE_EPS || 0650 plotParameters.filetype == PLOT_FILETYPE_PS || 0651 (plotParameters.filetype == PLOT_FILETYPE_AUTO && p >= 4 && 0652 plotParameters.filename.substr(p-4,4) == ".eps") || 0653 (plotParameters.filetype == PLOT_FILETYPE_AUTO && p >= 3 && 0654 plotParameters.filename.substr(p-3,3) == ".ps")) 0655 setResult(new Cantor::EpsResult(QUrl(QString::fromStdString(plotParameters.filename)))); 0656 else 0657 setResult(new Cantor::ImageResult(QUrl(QString::fromStdString(plotParameters.filename)))); 0658 #else 0659 setResult(new Cantor::ImageResult(QUrl::fromLocalFile(QString::fromStdString(plotParameters.filename)))); 0660 #endif 0661 setStatus(Cantor::Expression::Done); 0662 } 0663 } 0664 0665 void QalculateExpression::showMessage(QString msg, MessageType mtype) 0666 { 0667 KColorScheme scheme(QApplication::palette().currentColorGroup()); 0668 const QString errorColor = scheme.foreground(KColorScheme::NegativeText).color().name(); 0669 const QString warningColor = scheme.foreground(KColorScheme::NeutralText).color().name(); 0670 const QString msgFormat(QLatin1String("<font color=\"%1\">%2: %3</font><br>\n")); 0671 if(mtype == MESSAGE_ERROR || mtype == MESSAGE_WARNING) { 0672 msg.replace(QLatin1String("&"), QLatin1String("&")); 0673 msg.replace(QLatin1String(">"), QLatin1String(">")); 0674 msg.replace(QLatin1String("<"), QLatin1String("<")); 0675 0676 if (mtype == MESSAGE_ERROR) { 0677 msg = msgFormat.arg(errorColor, i18n("ERROR"), QLatin1String(msg.toLatin1().data())); 0678 } else { 0679 msg = msgFormat.arg(errorColor, i18n("WARNING"), QLatin1String(msg.toLatin1().data())); 0680 } 0681 setErrorMessage(msg); 0682 setStatus(Error); 0683 } else { 0684 KMessageBox::information(QApplication::activeWindow(), msg); 0685 } 0686 } 0687 0688 EvaluationOptions QalculateExpression::evaluationOptions() 0689 { 0690 EvaluationOptions eo; 0691 0692 eo.auto_post_conversion = QalculateSettings::postConversion() ? POST_CONVERSION_BEST : POST_CONVERSION_NONE; 0693 eo.keep_zero_units = false; 0694 0695 eo.parse_options = parseOptions(); 0696 0697 switch (QalculateSettings::structuring()) { 0698 case 0: 0699 eo.structuring = STRUCTURING_NONE; 0700 break; 0701 case 1: 0702 eo.structuring = STRUCTURING_SIMPLIFY; 0703 break; 0704 case 2: 0705 eo.structuring = STRUCTURING_FACTORIZE; 0706 break; 0707 } 0708 0709 return eo; 0710 } 0711 0712 ParseOptions QalculateExpression::parseOptions() 0713 { 0714 ParseOptions po; 0715 switch (QalculateSettings::angleUnit()) { 0716 case 0: 0717 po.angle_unit = ANGLE_UNIT_NONE; 0718 break; 0719 case 1: 0720 po.angle_unit = ANGLE_UNIT_RADIANS; 0721 break; 0722 case 2: 0723 po.angle_unit = ANGLE_UNIT_DEGREES; 0724 break; 0725 case 3: 0726 po.angle_unit = ANGLE_UNIT_GRADIANS; 0727 break; 0728 } 0729 0730 po.base = QalculateSettings::base(); 0731 po.comma_as_separator = false; 0732 0733 return po; 0734 } 0735 0736 void QalculateExpression::deletePlotDataParameters 0737 (const std::vector<PlotDataParameters*>& plotDataParameterList) 0738 { 0739 for(size_t i = 0; i < plotDataParameterList.size(); ++i) 0740 delete plotDataParameterList[i]; 0741 } 0742 0743 bool QalculateExpression::stringToBool(const QString &string, bool *ok) 0744 { 0745 if (string == QLatin1String("true") || string == QLatin1String("1")) { 0746 *ok = true; 0747 return true; 0748 } else if (string == QLatin1String("false") || string == QLatin1String("0")) { 0749 *ok = true; 0750 return false; 0751 } else { 0752 *ok = false; 0753 return false; 0754 } 0755 } 0756 0757 int QalculateExpression::checkForCalculatorMessages() 0758 { 0759 // error handling, most of it copied from qalculate-kde 0760 int msgType = MSG_NONE; 0761 if ( CALCULATOR->message() ) { 0762 QString msg; 0763 KColorScheme scheme(QApplication::palette().currentColorGroup()); 0764 const QString errorColor = scheme.foreground(KColorScheme::NegativeText).color().name(); 0765 const QString warningColor = scheme.foreground(KColorScheme::NeutralText).color().name(); 0766 const QString msgFormat(QLatin1String("<font color=\"%1\">%2: %3</font><br>\n")); 0767 MessageType mtype; 0768 while(true) { 0769 mtype = CALCULATOR->message()->type(); 0770 switch(mtype) { 0771 case MESSAGE_INFORMATION: 0772 msgType |= MSG_INFO; break; 0773 case MESSAGE_WARNING: 0774 msgType |= MSG_WARN; break; 0775 case MESSAGE_ERROR: 0776 msgType |= MSG_ERR; break; 0777 } 0778 if(mtype == MESSAGE_ERROR || mtype == MESSAGE_WARNING) { 0779 QString text = QLatin1String(CALCULATOR->message()->message().c_str()); 0780 text.replace(QLatin1String("&"), QLatin1String("&")); 0781 text.replace(QLatin1String(">"), QLatin1String(">")); 0782 text.replace(QLatin1String("<"), QLatin1String("<")); 0783 0784 if (mtype == MESSAGE_ERROR) { 0785 msg.append(msgFormat.arg(errorColor, i18n("ERROR"), text)); 0786 } else { 0787 msg.append(msgFormat.arg(errorColor, i18n("WARNING"), text)); 0788 } 0789 } else { 0790 KMessageBox::information(QApplication::activeWindow(), QLatin1String(CALCULATOR->message()->message().c_str())); 0791 } 0792 if(!CALCULATOR->nextMessage()) break; 0793 } 0794 if ( !msg.isEmpty() ) { 0795 m_message += msg; 0796 setErrorMessage(m_message); 0797 setStatus(Error); 0798 } 0799 } 0800 return msgType; 0801 } 0802 0803 std::string QalculateExpression::unlocalizeExpression(QString expr) 0804 { 0805 // copy'n'pasted from qalculate plasma applet 0806 0807 return CALCULATOR->unlocalizeExpression( 0808 expr.replace(QChar(0xA3), QLatin1String("GBP")) 0809 .replace(QChar(0xA5), QLatin1String("JPY")) 0810 .replace(QLatin1String("$"), QLatin1String("USD")) 0811 .replace(QChar(0x20AC), QLatin1String("EUR")) 0812 .toLatin1().data() 0813 ); 0814 } 0815 0816 QSharedPointer<PrintOptions> QalculateExpression::printOptions() 0817 { 0818 QSharedPointer<PrintOptions> po(new PrintOptions); 0819 0820 switch (QalculateSettings::fractionFormat()) { 0821 case 0: 0822 po->number_fraction_format = FRACTION_DECIMAL; 0823 break; 0824 case 1: 0825 po->number_fraction_format = FRACTION_DECIMAL_EXACT; 0826 break; 0827 case 2: 0828 po->number_fraction_format = FRACTION_FRACTIONAL; 0829 break; 0830 case 3: 0831 po->number_fraction_format = FRACTION_COMBINED; 0832 break; 0833 } 0834 po->indicate_infinite_series = QalculateSettings::indicateInfiniteSeries(); 0835 po->use_all_prefixes = QalculateSettings::useAllPrefixes(); 0836 po->negative_exponents = QalculateSettings::negativeExponents(); 0837 0838 po->lower_case_e = true; 0839 po->base = QalculateSettings::base(); 0840 po->decimalpoint_sign = QLocale().decimalPoint().toLatin1(); 0841 0842 switch (QalculateSettings::minExp()) { 0843 case 0: 0844 po->min_exp = EXP_NONE; 0845 break; 0846 case 1: 0847 po->min_exp = EXP_PURE; 0848 break; 0849 case 2: 0850 po->min_exp = EXP_SCIENTIFIC; 0851 break; 0852 case 3: 0853 po->min_exp = EXP_PRECISION; 0854 break; 0855 case 4: 0856 po->min_exp = EXP_BASE_3; 0857 break; 0858 } 0859 return po; 0860 }