Warning, file /education/kmplot/kmplot/kmplotio.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 KmPlot - a math. function plotter for the KDE-Desktop 0003 0004 SPDX-FileCopyrightText: 1998, 1999, 2000, 2002 Klaus-Dieter Möller <kd.moeller@t-online.de> 0005 0006 This file is part of the KDE Project. 0007 KmPlot is part of the KDE-EDU Project. 0008 0009 SPDX-License-Identifier: GPL-2.0-or-later 0010 0011 */ 0012 0013 #include "kmplotio.h" 0014 0015 // Qt includes 0016 #include <QDebug> 0017 #include <QDomDocument> 0018 #include <QDomElement> 0019 #include <QDomNode> 0020 #include <QDomText> 0021 #include <QFile> 0022 #include <QTemporaryFile> 0023 #include <QTextStream> 0024 0025 // KDE includes 0026 #include <KIO/StoredTransferJob> 0027 #include <KJobWidgets> 0028 #include <KLocalizedString> 0029 #include <KMessageBox> 0030 0031 // ANSI-C includes 0032 #include <stdlib.h> 0033 0034 // local includes 0035 #include "maindlg.h" 0036 #include "settings.h" 0037 #include "xparser.h" 0038 0039 static QString CurrentVersionString("4"); 0040 0041 class XParser; 0042 0043 KmPlotIO::KmPlotIO() 0044 { 0045 KmPlotIO::version = CurrentVersionString.toInt(); 0046 lengthScaler = 1.0; 0047 } 0048 0049 KmPlotIO::~KmPlotIO() 0050 { 0051 } 0052 0053 QDomDocument KmPlotIO::currentState() 0054 { 0055 // saving as xml by a QDomDocument 0056 QDomDocument doc("kmpdoc"); 0057 // the root tag 0058 QDomElement root = doc.createElement("kmpdoc"); 0059 root.setAttribute("version", CurrentVersionString); 0060 doc.appendChild(root); 0061 0062 // the axes tag 0063 QDomElement tag = doc.createElement("axes"); 0064 0065 tag.setAttribute("color", Settings::axesColor().name()); 0066 tag.setAttribute("width", Settings::axesLineWidth()); 0067 tag.setAttribute("tic-width", Settings::ticWidth()); 0068 tag.setAttribute("tic-legth", Settings::ticLength()); 0069 0070 addTag(doc, tag, "show-axes", Settings::showAxes() ? "1" : "-1"); 0071 addTag(doc, tag, "show-arrows", Settings::showArrows() ? "1" : "-1"); 0072 addTag(doc, tag, "show-label", Settings::showLabel() ? "1" : "-1"); 0073 0074 addTag(doc, tag, "xmin", Settings::xMin()); 0075 addTag(doc, tag, "xmax", Settings::xMax()); 0076 0077 addTag(doc, tag, "ymin", Settings::yMin()); 0078 addTag(doc, tag, "ymax", Settings::yMax()); 0079 0080 root.appendChild(tag); 0081 0082 tag = doc.createElement("grid"); 0083 0084 tag.setAttribute("color", Settings::gridColor().name()); 0085 tag.setAttribute("width", Settings::gridLineWidth()); 0086 0087 addTag(doc, tag, "mode", QString::number(Settings::gridStyle())); 0088 0089 root.appendChild(tag); 0090 0091 tag = doc.createElement("scale"); 0092 0093 addTag(doc, tag, "tic-x-mode", QString::number(Settings::xScalingMode())); 0094 addTag(doc, tag, "tic-y-mode", QString::number(Settings::yScalingMode())); 0095 addTag(doc, tag, "tic-x", Settings::xScaling()); 0096 addTag(doc, tag, "tic-y", Settings::yScaling()); 0097 0098 root.appendChild(tag); 0099 0100 for (Function *f : qAsConst(XParser::self()->m_ufkt)) 0101 addFunction(doc, root, f); 0102 0103 addConstants(doc, root); 0104 0105 tag = doc.createElement("fonts"); 0106 addTag(doc, tag, "axes-font", Settings::axesFont().family()); 0107 addTag(doc, tag, "label-font", Settings::labelFont().family()); 0108 addTag(doc, tag, "header-table-font", Settings::headerTableFont().family()); 0109 root.appendChild(tag); 0110 0111 return doc; 0112 } 0113 0114 bool KmPlotIO::save(const QUrl &url) 0115 { 0116 QDomDocument doc = currentState(); 0117 0118 if (!url.isLocalFile()) { 0119 QTemporaryFile tmpfile; 0120 if (!tmpfile.open()) { 0121 qWarning() << "Could not open " << QUrl(tmpfile.fileName()).toLocalFile() << " for writing.\n"; 0122 return false; 0123 } 0124 QTextStream ts(&tmpfile); 0125 doc.save(ts, 4); 0126 ts.flush(); 0127 0128 Q_CONSTEXPR int permission = -1; 0129 QFile file(tmpfile.fileName()); 0130 file.open(QIODevice::ReadOnly); 0131 KIO::StoredTransferJob *putjob = KIO::storedPut(file.readAll(), url, permission, KIO::JobFlag::Overwrite); 0132 if (!putjob->exec()) { 0133 qWarning() << "Could not open " << url.toString() << " for writing (" << putjob->errorString() << ").\n"; 0134 return false; 0135 } 0136 file.close(); 0137 } else { 0138 QFile xmlfile(url.toLocalFile()); 0139 if (!xmlfile.open(QIODevice::WriteOnly)) { 0140 qWarning() << "Could not open " << url.path() << " for writing.\n"; 0141 return false; 0142 } 0143 QTextStream ts(&xmlfile); 0144 doc.save(ts, 4); 0145 xmlfile.close(); 0146 return true; 0147 } 0148 return true; 0149 } 0150 0151 void KmPlotIO::addConstants(QDomDocument &doc, QDomElement &root) 0152 { 0153 ConstantList constants = XParser::self()->constants()->list(Constant::Document); 0154 0155 for (ConstantList::iterator it = constants.begin(); it != constants.end(); ++it) { 0156 QDomElement tag = doc.createElement("constant"); 0157 root.appendChild(tag); 0158 tag.setAttribute("name", it.key()); 0159 tag.setAttribute("value", it.value().value.expression()); 0160 } 0161 } 0162 0163 void KmPlotIO::addFunction(QDomDocument &doc, QDomElement &root, Function *function) 0164 { 0165 QDomElement tag = doc.createElement("function"); 0166 0167 QString names[] = {"f0", "f1", "f2", "integral"}; 0168 PlotAppearance *plots[] = {&function->plotAppearance(Function::Derivative0), 0169 &function->plotAppearance(Function::Derivative1), 0170 &function->plotAppearance(Function::Derivative2), 0171 &function->plotAppearance(Function::Integral)}; 0172 0173 for (int i = 0; i < 4; ++i) { 0174 tag.setAttribute(QString("%1-width").arg(names[i]), plots[i]->lineWidth); 0175 tag.setAttribute(QString("%1-color").arg(names[i]), plots[i]->color.name()); 0176 tag.setAttribute(QString("%1-use-gradient").arg(names[i]), plots[i]->useGradient); 0177 tag.setAttribute(QString("%1-gradient").arg(names[i]), gradientToString(plots[i]->gradient.stops())); 0178 tag.setAttribute(QString("%1-show-tangent-field").arg(names[i]), plots[i]->showTangentField); 0179 tag.setAttribute(QString("%1-visible").arg(names[i]), plots[i]->visible); 0180 tag.setAttribute(QString("%1-style").arg(names[i]), PlotAppearance::penStyleToString(plots[i]->style)); 0181 tag.setAttribute(QString("%1-show-extrema").arg(names[i]), plots[i]->showExtrema); 0182 tag.setAttribute(QString("%1-show-plot-name").arg(names[i]), plots[i]->showPlotName); 0183 } 0184 0185 // BEGIN parameters 0186 tag.setAttribute("use-parameter-slider", function->m_parameters.useSlider); 0187 tag.setAttribute("parameter-slider", function->m_parameters.sliderID); 0188 0189 tag.setAttribute("use-parameter-list", function->m_parameters.useList); 0190 QStringList str_parameters; 0191 for (const Value &k : qAsConst(function->m_parameters.list)) 0192 str_parameters << k.expression(); 0193 0194 if (!str_parameters.isEmpty()) 0195 addTag(doc, tag, "parameter-list", str_parameters.join(";")); 0196 // END parameters 0197 0198 tag.setAttribute("type", Function::typeToString(function->type())); 0199 for (int i = 0; i < function->eq.size(); ++i) { 0200 Equation *equation = function->eq[i]; 0201 0202 QString fstr = equation->fstr(); 0203 if (fstr.isEmpty()) 0204 continue; 0205 QDomElement element = addTag(doc, tag, QString("equation-%1").arg(i), fstr); 0206 element.setAttribute("step", equation->differentialStates.step().expression()); 0207 0208 for (int i = 0; i < equation->differentialStates.size(); ++i) { 0209 DifferentialState *state = &equation->differentialStates[i]; 0210 0211 QDomElement differential = doc.createElement("differential"); 0212 element.appendChild(differential); 0213 0214 bool first = true; 0215 QString ys; 0216 for (const Value &y : qAsConst(state->y0)) { 0217 if (!first) 0218 ys += ';'; 0219 first = false; 0220 ys += y.expression(); 0221 } 0222 0223 differential.setAttribute("x", state->x0.expression()); 0224 differential.setAttribute("y", ys); 0225 } 0226 } 0227 0228 addTag(doc, tag, "arg-min", function->dmin.expression()).setAttribute("use", function->usecustomxmin); 0229 addTag(doc, tag, "arg-max", function->dmax.expression()).setAttribute("use", function->usecustomxmax); 0230 0231 root.appendChild(tag); 0232 } 0233 0234 QDomElement KmPlotIO::addTag(QDomDocument &doc, QDomElement &parentTag, const QString &tagName, const QString &tagValue) 0235 { 0236 QDomElement tag = doc.createElement(tagName); 0237 QDomText value = doc.createTextNode(tagValue); 0238 tag.appendChild(value); 0239 parentTag.appendChild(tag); 0240 return tag; 0241 } 0242 0243 bool KmPlotIO::restore(const QDomDocument &doc) 0244 { 0245 // temporary measure: for now, delete all previous functions 0246 XParser::self()->removeAllFunctions(); 0247 0248 QDomElement element = doc.documentElement(); 0249 QString versionString = element.attribute("version"); 0250 if (versionString.isNull()) // an old kmplot-file 0251 { 0252 MainDlg::oldfileversion = true; 0253 for (QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling()) { 0254 version = 0; 0255 lengthScaler = 0.1; 0256 0257 if (n.nodeName() == "axes") 0258 parseAxes(n.toElement()); 0259 if (n.nodeName() == "grid") 0260 parseGrid(n.toElement()); 0261 if (n.nodeName() == "scale") 0262 parseScale(n.toElement()); 0263 if (n.nodeName() == "function") 0264 oldParseFunction(n.toElement()); 0265 } 0266 } else if (versionString == "1" || versionString == "2" || versionString == "3" || versionString == "4") { 0267 MainDlg::oldfileversion = false; 0268 version = versionString.toInt(); 0269 lengthScaler = (version < 3) ? 0.1 : 1.0; 0270 0271 for (QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling()) { 0272 if (n.nodeName() == "axes") 0273 parseAxes(n.toElement()); 0274 else if (n.nodeName() == "grid") 0275 parseGrid(n.toElement()); 0276 else if (n.nodeName() == "scale") 0277 parseScale(n.toElement()); 0278 else if (n.nodeName() == "constant") 0279 parseConstant(n.toElement()); 0280 else if (n.nodeName() == "function") { 0281 if (version < 3) 0282 oldParseFunction2(n.toElement()); 0283 else 0284 parseFunction(n.toElement()); 0285 } 0286 } 0287 } else { 0288 KMessageBox::error(0, i18n("The file had an unknown version number")); 0289 return false; 0290 } 0291 0292 // Because we may not have loaded the constants / functions in the right order 0293 // to account for dependencies 0294 XParser::self()->reparseAllFunctions(); 0295 0296 return true; 0297 } 0298 0299 bool KmPlotIO::load(const QUrl &url) 0300 { 0301 QDomDocument doc("kmpdoc"); 0302 QFile f; 0303 bool downloadedFile = false; 0304 if (!url.isLocalFile()) { 0305 if (!MainDlg::fileExists(url)) { 0306 KMessageBox::error(0, i18n("The file does not exist.")); 0307 return false; 0308 } 0309 downloadedFile = true; 0310 KIO::StoredTransferJob *transferjob = KIO::storedGet(url); 0311 KJobWidgets::setWindow(transferjob, 0); 0312 if (!transferjob->exec()) { 0313 KMessageBox::error(0, i18n("An error appeared when opening this file (%1)", transferjob->errorString())); 0314 return false; 0315 } 0316 QTemporaryFile file; 0317 file.setAutoRemove(false); 0318 file.open(); 0319 file.write(transferjob->data()); 0320 f.setFileName(file.fileName()); 0321 file.close(); 0322 } else 0323 f.setFileName(url.toLocalFile()); 0324 0325 if (!f.open(QIODevice::ReadOnly)) { 0326 KMessageBox::error(0, i18n("%1 could not be opened", f.fileName())); 0327 return false; 0328 } 0329 QString errorMessage; 0330 int errorLine, errorColumn; 0331 if (!doc.setContent(&f, &errorMessage, &errorLine, &errorColumn)) { 0332 KMessageBox::error(0, i18n("%1 could not be loaded (%2 at line %3, column %4)", f.fileName(), errorMessage, errorLine, errorColumn)); 0333 f.close(); 0334 return false; 0335 } 0336 f.close(); 0337 0338 if (!restore(doc)) 0339 return false; 0340 0341 if (downloadedFile) 0342 QFile::remove(f.fileName()); 0343 return true; 0344 } 0345 0346 void KmPlotIO::parseConstant(const QDomElement &n) 0347 { 0348 QString name = n.attribute("name"); 0349 QString value = n.attribute("value"); 0350 0351 /// \todo how to handle overwriting constants, etc? 0352 Constant c; 0353 c.value.updateExpression(value); 0354 c.type = Constant::Document; 0355 0356 if (XParser::self()->constants()->list(Constant::Global).contains(name)) 0357 c.type |= Constant::Global; 0358 0359 XParser::self()->constants()->add(name, c); 0360 } 0361 0362 void KmPlotIO::parseAxes(const QDomElement &n) 0363 { 0364 Settings::setAxesLineWidth(n.attribute("width", (version < 3) ? "2" : "0.2").toDouble() * lengthScaler); 0365 Settings::setAxesColor(QColor(n.attribute("color", "#000000"))); 0366 Settings::setTicWidth(n.attribute("tic-width", (version < 3) ? "3" : "0.3").toDouble() * lengthScaler); 0367 Settings::setTicLength(n.attribute("tic-length", (version < 3) ? "5" : "0.5").toDouble() * lengthScaler); 0368 0369 if (version < 1) { 0370 Settings::setShowAxes(true); 0371 Settings::setShowArrows(true); 0372 Settings::setShowLabel(true); 0373 } else { 0374 Settings::setShowAxes(n.namedItem("show-axes").toElement().text().toInt() == 1); 0375 Settings::setShowArrows(n.namedItem("show-arrows").toElement().text().toInt() == 1); 0376 Settings::setShowLabel(n.namedItem("show-label").toElement().text().toInt() == 1); 0377 } 0378 0379 Settings::setXMin(n.namedItem("xmin").toElement().text()); 0380 Settings::setXMax(n.namedItem("xmax").toElement().text()); 0381 Settings::setYMin(n.namedItem("ymin").toElement().text()); 0382 Settings::setYMax(n.namedItem("ymax").toElement().text()); 0383 } 0384 0385 void KmPlotIO::parseGrid(const QDomElement &n) 0386 { 0387 Settings::setGridColor(QColor(n.attribute("color", "#c0c0c0"))); 0388 Settings::setGridLineWidth(n.attribute("width", (version < 3) ? "1" : "0.1").toDouble() * lengthScaler); 0389 0390 Settings::setGridStyle(n.namedItem("mode").toElement().text().toInt()); 0391 } 0392 0393 int unit2index(const QString &unit) 0394 { 0395 QString units[9] = {"10", "5", "2", "1", "0.5", "pi/2", "pi/3", "pi/4", i18n("automatic")}; 0396 int index = 0; 0397 while ((index < 9) && (unit != units[index])) 0398 index++; 0399 if (index == 9) 0400 index = -1; 0401 return index; 0402 } 0403 0404 void KmPlotIO::parseScale(const QDomElement &n) 0405 { 0406 #if 0 0407 if ( version < 1 ) 0408 { 0409 Settings::setXScaling( unit2index( n.namedItem( "tic-x" ).toElement().text() ) ); 0410 Settings::setYScaling( unit2index( n.namedItem( "tic-y" ).toElement().text() ) ); 0411 Settings::setXPrinting( unit2index( n.namedItem( "print-tic-x" ).toElement().text() ) ); 0412 Settings::setYPrinting( unit2index( n.namedItem( "print-tic-y" ).toElement().text() ) ); 0413 } 0414 else 0415 { 0416 Settings::setXScaling( n.namedItem( "tic-x" ).toElement().text().toInt() ); 0417 Settings::setYScaling( n.namedItem( "tic-y" ).toElement().text().toInt() ); 0418 Settings::setXPrinting( n.namedItem( "print-tic-x" ).toElement().text().toInt() ); 0419 Settings::setYPrinting( n.namedItem( "print-tic-y" ).toElement().text().toInt() ); 0420 } 0421 #endif 0422 0423 if (version >= 4) { 0424 Settings::setXScalingMode(n.namedItem("tic-x-mode").toElement().text().toInt()); 0425 Settings::setYScalingMode(n.namedItem("tic-y-mode").toElement().text().toInt()); 0426 Settings::setXScaling(n.namedItem("tic-x").toElement().text()); 0427 Settings::setYScaling(n.namedItem("tic-y").toElement().text()); 0428 } 0429 } 0430 0431 void KmPlotIO::parseFunction(const QDomElement &n, bool allowRename) 0432 { 0433 QDomElement equation0 = n.namedItem("equation-0").toElement(); 0434 QDomElement equation1 = n.namedItem("equation-1").toElement(); 0435 0436 QString eq0 = equation0.text(); 0437 QString eq1 = equation1.text(); 0438 0439 Function::Type type = Function::stringToType(n.attribute("type")); 0440 0441 if (allowRename) { 0442 switch (type) { 0443 case Function::Polar: 0444 XParser::self()->fixFunctionName(eq0, Equation::Polar, -1); 0445 break; 0446 0447 case Function::Parametric: 0448 XParser::self()->fixFunctionName(eq0, Equation::ParametricX, -1); 0449 XParser::self()->fixFunctionName(eq1, Equation::ParametricY, -1); 0450 break; 0451 0452 case Function::Cartesian: 0453 XParser::self()->fixFunctionName(eq0, Equation::Cartesian, -1); 0454 break; 0455 0456 case Function::Implicit: 0457 XParser::self()->fixFunctionName(eq0, Equation::Implicit, -1); 0458 break; 0459 0460 case Function::Differential: 0461 XParser::self()->fixFunctionName(eq0, Equation::Differential, -1); 0462 break; 0463 } 0464 } 0465 0466 int functionID = XParser::self()->Parser::addFunction(eq0, eq1, type, true); 0467 if (functionID == -1) { 0468 qWarning() << "Could not create function!\n"; 0469 return; 0470 } 0471 Function *function = XParser::self()->functionWithID(functionID); 0472 0473 parseDifferentialStates(equation0, function->eq[0]); 0474 if (function->eq.size() > 1) 0475 parseDifferentialStates(equation1, function->eq[1]); 0476 0477 PlotAppearance *plots[] = {&function->plotAppearance(Function::Derivative0), 0478 &function->plotAppearance(Function::Derivative1), 0479 &function->plotAppearance(Function::Derivative2), 0480 &function->plotAppearance(Function::Integral)}; 0481 0482 QString names[] = {"f0", "f1", "f2", "integral"}; 0483 0484 for (int i = 0; i < 4; ++i) { 0485 plots[i]->lineWidth = n.attribute(QString("%1-width").arg(names[i])).toDouble() * lengthScaler; 0486 plots[i]->color = n.attribute(QString("%1-color").arg(names[i])); 0487 plots[i]->useGradient = n.attribute(QString("%1-use-gradient").arg(names[i])).toInt(); 0488 plots[i]->gradient.setStops(stringToGradient(n.attribute(QString("%1-gradient").arg(names[i])))); 0489 plots[i]->visible = n.attribute(QString("%1-visible").arg(names[i])).toInt(); 0490 plots[i]->style = PlotAppearance::stringToPenStyle(n.attribute(QString("%1-style").arg(names[i]))); 0491 plots[i]->showExtrema = n.attribute(QString("%1-show-extrema").arg(names[i])).toInt(); 0492 plots[i]->showTangentField = n.attribute(QString("%1-show-tangent-field").arg(names[i])).toInt(); 0493 plots[i]->showPlotName = n.attribute(QString("%1-show-plot-name").arg(names[i])).toInt(); 0494 } 0495 0496 // BEGIN parameters 0497 parseParameters(n, function); 0498 0499 function->m_parameters.useSlider = n.attribute("use-parameter-slider").toInt(); 0500 function->m_parameters.sliderID = n.attribute("parameter-slider").toInt(); 0501 function->m_parameters.useList = n.attribute("use-parameter-list").toInt(); 0502 // END parameters 0503 0504 QDomElement minElement = n.namedItem("arg-min").toElement(); 0505 QString expression = minElement.text(); 0506 if (expression.isEmpty()) 0507 function->usecustomxmin = false; 0508 else { 0509 function->dmin.updateExpression(expression); 0510 function->usecustomxmin = minElement.attribute("use", "1").toInt(); 0511 } 0512 0513 QDomElement maxElement = n.namedItem("arg-max").toElement(); 0514 expression = maxElement.text(); 0515 if (expression.isEmpty()) 0516 function->usecustomxmax = false; 0517 else { 0518 function->dmax.updateExpression(expression); 0519 function->usecustomxmax = maxElement.attribute("use", "1").toInt(); 0520 } 0521 } 0522 0523 void KmPlotIO::parseParameters(const QDomElement &n, Function *function) 0524 { 0525 QChar separator = (version < 1) ? ',' : ';'; 0526 QString tagName = (version < 4) ? "parameterlist" : "parameter-list"; 0527 0528 const QStringList str_parameters = n.namedItem(tagName).toElement().text().split(separator, Qt::SkipEmptyParts); 0529 for (QStringList::const_iterator it = str_parameters.constBegin(); it != str_parameters.constEnd(); ++it) 0530 function->m_parameters.list.append(Value(*it)); 0531 } 0532 0533 void KmPlotIO::parseDifferentialStates(const QDomElement &n, Equation *equation) 0534 { 0535 equation->differentialStates.setStep(n.attribute("step")); 0536 0537 QDomNode node = n.firstChild(); 0538 0539 while (!node.isNull()) { 0540 if (node.isElement()) { 0541 QDomElement e = node.toElement(); 0542 0543 QString x = e.attribute("x"); 0544 const QStringList y = e.attribute("y").split(';'); 0545 0546 DifferentialState *state = equation->differentialStates.add(); 0547 if (state->y0.size() != y.size()) { 0548 qWarning() << "Invalid y count!\n"; 0549 return; 0550 } 0551 0552 state->x0.updateExpression(x); 0553 0554 int at = 0; 0555 for (const QString &f : y) 0556 state->y0[at++] = f; 0557 } 0558 node = node.nextSibling(); 0559 } 0560 } 0561 0562 void KmPlotIO::oldParseFunction2(const QDomElement &n) 0563 { 0564 Function::Type type; 0565 QString eq0, eq1; 0566 0567 eq0 = n.namedItem("equation").toElement().text(); 0568 0569 switch (eq0[0].unicode()) { 0570 case 'r': 0571 type = Function::Polar; 0572 break; 0573 0574 case 'x': 0575 parametricXEquation = eq0; 0576 return; 0577 0578 case 'y': 0579 type = Function::Parametric; 0580 eq1 = eq0; 0581 eq0 = parametricXEquation; 0582 break; 0583 0584 default: 0585 type = Function::Cartesian; 0586 break; 0587 } 0588 0589 Function ufkt(type); 0590 ufkt.eq[0]->setFstr(eq0, 0, 0, true); 0591 if (!eq1.isEmpty()) 0592 ufkt.eq[1]->setFstr(eq1, 0, 0, true); 0593 0594 PlotAppearance *plots[] = {&ufkt.plotAppearance(Function::Derivative0), 0595 &ufkt.plotAppearance(Function::Derivative1), 0596 &ufkt.plotAppearance(Function::Derivative2), 0597 &ufkt.plotAppearance(Function::Integral)}; 0598 0599 plots[0]->visible = n.attribute("visible").toInt(); 0600 plots[0]->color = QColor(n.attribute("color")); 0601 plots[0]->lineWidth = n.attribute("width").toDouble() * lengthScaler; 0602 0603 plots[1]->visible = n.attribute("visible-deriv", "0").toInt(); 0604 plots[1]->color = QColor(n.attribute("deriv-color")); 0605 plots[1]->lineWidth = n.attribute("deriv-width").toDouble() * lengthScaler; 0606 0607 plots[2]->visible = n.attribute("visible-2nd-deriv", "0").toInt(); 0608 plots[2]->color = QColor(n.attribute("deriv2nd-color")); 0609 plots[2]->lineWidth = n.attribute("deriv2nd-width").toDouble() * lengthScaler; 0610 0611 plots[3]->visible = n.attribute("visible-integral", "0").toInt(); 0612 plots[3]->color = QColor(n.attribute("integral-color")); 0613 plots[3]->lineWidth = n.attribute("integral-width").toDouble() * lengthScaler; 0614 0615 // BEGIN parameters 0616 parseParameters(n, &ufkt); 0617 0618 int use_slider = n.attribute("use-slider").toInt(); 0619 ufkt.m_parameters.useSlider = (use_slider >= 0); 0620 ufkt.m_parameters.sliderID = use_slider; 0621 0622 ufkt.m_parameters.useList = !ufkt.m_parameters.list.isEmpty(); 0623 // END parameters 0624 0625 if (type == Function::Cartesian) { 0626 DifferentialState *state = &ufkt.eq[0]->differentialStates[0]; 0627 state->x0.updateExpression(n.attribute("integral-startx")); 0628 state->y0[0].updateExpression(n.attribute("integral-starty")); 0629 } 0630 0631 QDomElement minElement = n.namedItem("arg-min").toElement(); 0632 QString expression = minElement.text(); 0633 if (expression.isEmpty()) 0634 ufkt.usecustomxmin = false; 0635 else { 0636 ufkt.dmin.updateExpression(expression); 0637 ufkt.usecustomxmin = minElement.attribute("use", "1").toInt(); 0638 } 0639 0640 QDomElement maxElement = n.namedItem("arg-max").toElement(); 0641 expression = maxElement.text(); 0642 if (expression.isEmpty()) 0643 ufkt.usecustomxmax = false; 0644 else { 0645 ufkt.dmax.updateExpression(expression); 0646 ufkt.usecustomxmax = maxElement.attribute("use", "1").toInt(); 0647 } 0648 0649 QString fstr = ufkt.eq[0]->fstr(); 0650 if (!fstr.isEmpty()) { 0651 int const i = fstr.indexOf(';'); 0652 QString str; 0653 if (i == -1) 0654 str = fstr; 0655 else 0656 str = fstr.left(i); 0657 0658 int id = XParser::self()->Parser::addFunction(str, eq1, type, true); 0659 0660 Function *added_function = XParser::self()->m_ufkt[id]; 0661 added_function->copyFrom(ufkt); 0662 } 0663 } 0664 0665 void KmPlotIO::oldParseFunction(const QDomElement &n) 0666 { 0667 QString tmp_fstr = n.namedItem("equation").toElement().text(); 0668 if (tmp_fstr.isEmpty()) { 0669 qWarning() << "tmp_fstr is empty!\n"; 0670 return; 0671 } 0672 0673 Function::Type type; 0674 switch (tmp_fstr[0].unicode()) { 0675 case 'r': 0676 type = Function::Polar; 0677 break; 0678 0679 case 'x': 0680 parametricXEquation = tmp_fstr; 0681 return; 0682 0683 case 'y': 0684 type = Function::Parametric; 0685 break; 0686 0687 default: 0688 type = Function::Cartesian; 0689 break; 0690 } 0691 0692 Function ufkt(type); 0693 0694 ufkt.plotAppearance(Function::Derivative0).visible = n.attribute("visible").toInt(); 0695 ufkt.plotAppearance(Function::Derivative1).visible = n.attribute("visible-deriv").toInt(); 0696 ufkt.plotAppearance(Function::Derivative2).visible = n.attribute("visible-2nd-deriv").toInt(); 0697 ufkt.plotAppearance(Function::Derivative0).lineWidth = n.attribute("width").toDouble() * lengthScaler; 0698 ufkt.plotAppearance(Function::Derivative0).color = ufkt.plotAppearance(Function::Derivative1).color = ufkt.plotAppearance(Function::Derivative2).color = 0699 ufkt.plotAppearance(Function::Integral).color = QColor(n.attribute("color")); 0700 0701 QString expression = n.namedItem("arg-min").toElement().text(); 0702 ufkt.dmin.updateExpression(expression); 0703 ufkt.usecustomxmin = !expression.isEmpty(); 0704 0705 expression = n.namedItem("arg-max").toElement().text(); 0706 ufkt.dmax.updateExpression(expression); 0707 ufkt.usecustomxmax = !expression.isEmpty(); 0708 0709 if (ufkt.usecustomxmin && ufkt.usecustomxmax && ufkt.dmin.expression() == ufkt.dmax.expression()) { 0710 ufkt.usecustomxmin = false; 0711 ufkt.usecustomxmax = false; 0712 } 0713 0714 const int pos = tmp_fstr.indexOf(';'); 0715 if (pos == -1) 0716 ufkt.eq[0]->setFstr(tmp_fstr, 0, 0, true); 0717 else { 0718 ufkt.eq[0]->setFstr(tmp_fstr.left(pos), 0, 0, true); 0719 if (!XParser::self()->getext(&ufkt, tmp_fstr)) { 0720 KMessageBox::error(0, i18n("The function %1 could not be loaded", ufkt.eq[0]->fstr())); 0721 return; 0722 } 0723 } 0724 0725 QString fstr = ufkt.eq[0]->fstr(); 0726 if (!fstr.isEmpty()) { 0727 int const i = fstr.indexOf(';'); 0728 QString str; 0729 if (i == -1) 0730 str = fstr; 0731 else 0732 str = fstr.left(i); 0733 0734 int id; 0735 if (type == Function::Parametric) 0736 id = XParser::self()->Parser::addFunction(str, parametricXEquation, type, true); 0737 else 0738 id = XParser::self()->Parser::addFunction(str, 0, type, true); 0739 0740 Function *added_function = XParser::self()->m_ufkt[id]; 0741 added_function->copyFrom(ufkt); 0742 } 0743 } 0744 0745 // static 0746 QString KmPlotIO::gradientToString(const QGradientStops &stops) 0747 { 0748 QString string; 0749 for (const QGradientStop &stop : qAsConst(stops)) 0750 string += QString("%1;%2,").arg(stop.first).arg(stop.second.name()); 0751 return string; 0752 } 0753 0754 // static 0755 QGradientStops KmPlotIO::stringToGradient(const QString &string) 0756 { 0757 const QStringList stopStrings = string.split(',', Qt::SkipEmptyParts); 0758 0759 QGradientStops stops; 0760 for (const QString &stopString : stopStrings) { 0761 QString pos = stopString.section(';', 0, 0); 0762 QString color = stopString.section(';', 1, 1); 0763 0764 QGradientStop stop; 0765 stop.first = pos.toDouble(); 0766 stop.second = color; 0767 stops << stop; 0768 } 0769 0770 return stops; 0771 }