File indexing completed on 2024-04-21 03:41:34
0001 /************************************************************************************* 0002 * Copyright (C) 2007 by Aleix Pol <aleixpol@kde.org> * 0003 * * 0004 * This program is free software; you can redistribute it and/or * 0005 * modify it under the terms of the GNU General Public License * 0006 * as published by the Free Software Foundation; either version 2 * 0007 * of the License, or (at your option) any later version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, * 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0012 * GNU General Public License for more details. * 0013 * * 0014 * You should have received a copy of the GNU General Public License * 0015 * along with this program; if not, write to the Free Software * 0016 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 0017 *************************************************************************************/ 0018 0019 #include "kalgebra.h" 0020 #include "askname.h" 0021 #include "consolehtml.h" 0022 #include "dictionary.h" 0023 #include "functionedit.h" 0024 #include "varedit.h" 0025 #include "variablesdelegate.h" 0026 #include "viewportwidget.h" 0027 #include <analitzagui/plotsview3d_es.h> 0028 0029 #include <analitza/value.h> 0030 #include <analitza/variables.h> 0031 #include <analitzagui/expressionedit.h> 0032 #include <analitzagui/operatorsmodel.h> 0033 #include <analitzagui/plotsview2d.h> 0034 #include <analitzagui/variablesmodel.h> 0035 #include <analitzaplot/functiongraph.h> 0036 #include <analitzaplot/planecurve.h> 0037 #include <analitzaplot/plotsfactory.h> 0038 #include <analitzaplot/plotsmodel.h> 0039 0040 #include <KConfig> 0041 #include <KConfigGroup> 0042 #include <KHelpMenu> 0043 #include <KLocalizedString> 0044 #include <KRecentFilesAction> 0045 #include <KStandardAction> 0046 #include <KToggleFullScreenAction> 0047 #include <QAction> 0048 #include <QActionGroup> 0049 #include <QApplication> 0050 #include <QDockWidget> 0051 #include <QFileDialog> 0052 #include <QHeaderView> 0053 #include <QMenuBar> 0054 #include <QPointer> 0055 #include <QProcess> 0056 #include <QRandomGenerator> 0057 #include <QStatusBar> 0058 #include <QTableView> 0059 #include <QToolButton> 0060 #include <QVBoxLayout> 0061 0062 using namespace Qt::Literals::StringLiterals; 0063 0064 class Add2DOption : public InlineOptions 0065 { 0066 public: 0067 Add2DOption(KAlgebra *c) 0068 : m_kalgebra(c) 0069 { 0070 } 0071 0072 QString id() const override 0073 { 0074 return QStringLiteral("add2d"); 0075 } 0076 bool matchesExpression(const Analitza::Expression &exp) const override 0077 { 0078 return Analitza::PlotsFactory::self()->requestPlot(exp, Analitza::Dim2D).canDraw(); 0079 } 0080 0081 QString caption() const override 0082 { 0083 return i18n("Plot 2D"); 0084 } 0085 0086 void triggerOption(const Analitza::Expression &exp) override 0087 { 0088 m_kalgebra->add2D(exp); 0089 } 0090 0091 private: 0092 KAlgebra *m_kalgebra; 0093 }; 0094 0095 class Add3DOption : public InlineOptions 0096 { 0097 public: 0098 Add3DOption(KAlgebra *c) 0099 : m_kalgebra(c) 0100 { 0101 } 0102 0103 QString id() const override 0104 { 0105 return QStringLiteral("add3d"); 0106 } 0107 bool matchesExpression(const Analitza::Expression &exp) const override 0108 { 0109 return Analitza::PlotsFactory::self()->requestPlot(exp, Analitza::Dim3D).canDraw(); 0110 } 0111 0112 QString caption() const override 0113 { 0114 return i18n("Plot 3D"); 0115 } 0116 0117 void triggerOption(const Analitza::Expression &exp) override 0118 { 0119 m_kalgebra->add3D(exp); 0120 } 0121 0122 private: 0123 KAlgebra *m_kalgebra; 0124 }; 0125 0126 QColor randomFunctionColor() 0127 { 0128 return QColor::fromHsv(QRandomGenerator::global()->bounded(255), 255, 255); 0129 } 0130 0131 KAlgebra::KAlgebra(QWidget *parent) 0132 : QMainWindow(parent) 0133 { 0134 resize(900, 500); 0135 0136 m_tabs = new QTabWidget; 0137 setCentralWidget(m_tabs); 0138 0139 setStatusBar(new QStatusBar(this)); 0140 setMenuBar(new QMenuBar(this)); 0141 0142 KToggleFullScreenAction *fullScreenAction = KStandardAction::fullScreen(this, SLOT(fullScreen(bool)), this, this); 0143 0144 QMenu *g_menu = menuBar()->addMenu(i18n("Session")); 0145 g_menu->addAction(KStandardAction::openNew(this, SLOT(newInstance()), this)); 0146 g_menu->addAction(fullScreenAction); 0147 g_menu->addSeparator(); 0148 g_menu->addAction(KStandardAction::quit(this, SLOT(close()), this)); 0149 0150 QToolButton *fullScreenButton = new QToolButton(this); 0151 fullScreenButton->setDefaultAction(fullScreenAction); 0152 m_tabs->setCornerWidget(fullScreenButton); 0153 0154 m_status = new QLabel(this); 0155 statusBar()->insertWidget(0, m_status); 0156 menuBar()->addAction(QStringLiteral("|"))->setEnabled(false); 0157 0158 ///////Console 0159 QWidget *console = new QWidget(m_tabs); 0160 QVBoxLayout *c_layo = new QVBoxLayout(console); 0161 c_results = new ConsoleHtml(console); 0162 c_results->setFocusPolicy(Qt::NoFocus); 0163 c_dock_vars = new QDockWidget(i18n("Variables"), this); 0164 c_dock_vars->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable); 0165 addDockWidget(Qt::RightDockWidgetArea, c_dock_vars); 0166 0167 c_varsModel = new Analitza::VariablesModel(c_results->analitza()->variables()); 0168 c_varsModel->setEditable(false); 0169 0170 c_variables = new QTreeView(c_dock_vars); 0171 c_variables->setModel(c_varsModel); 0172 c_variables->setRootIsDecorated(false); 0173 c_variables->header()->setStretchLastSection(true); 0174 c_variables->setSelectionBehavior(QAbstractItemView::SelectRows); 0175 c_variables->setSelectionMode(QAbstractItemView::SingleSelection); 0176 0177 c_exp = new Analitza::ExpressionEdit(console); 0178 c_exp->setAnalitza(c_results->analitza()); 0179 c_exp->setExamples(QStringList() << QStringLiteral("square:=x->x**2") << QStringLiteral("fib:=n->piecewise { eq(n,0)?0, eq(n,1)?1, ?fib(n-1)+fib(n-2) }")); 0180 c_dock_vars->setWidget(c_variables); 0181 0182 m_tabs->addTab(console, i18n("&Calculator")); 0183 console->setLayout(c_layo); 0184 c_layo->addWidget(c_results); 0185 c_layo->addWidget(c_exp); 0186 0187 connect(c_exp, &Analitza::ExpressionEdit::returnPressed, this, &KAlgebra::operate); 0188 connect(c_results, &ConsoleHtml::status, this, &KAlgebra::changeStatusBar); 0189 connect(c_results, &ConsoleHtml::changed, this, &KAlgebra::updateInformation); 0190 connect(c_results, SIGNAL(changed()), c_exp, SLOT(updateCompleter())); 0191 connect(c_results, SIGNAL(paste(QString)), c_exp, SLOT(insertText(QString))); 0192 connect(c_variables, &QAbstractItemView::clicked, this, &KAlgebra::edit_var); 0193 ////////menu 0194 c_menu = menuBar()->addMenu(i18n("C&alculator")); 0195 c_menu->addAction(QIcon::fromTheme(QStringLiteral("document-open")), 0196 i18nc("@item:inmenu", "&Load Script..."), 0197 Qt::CTRL | Qt::Key_L, 0198 this, 0199 SLOT(loadScript())); 0200 c_recentScripts = new KRecentFilesAction(QIcon::fromTheme(QStringLiteral("document-open-recent")), i18n("Recent Scripts"), this); 0201 connect(c_recentScripts, SIGNAL(urlSelected(QUrl)), this, SLOT(loadScript(QUrl))); 0202 c_menu->addAction(c_recentScripts); 0203 0204 c_menu->addAction(QIcon::fromTheme(QStringLiteral("document-save")), 0205 i18nc("@item:inmenu", "&Save Script..."), 0206 Qt::CTRL | Qt::Key_G, 0207 this, 0208 &KAlgebra::saveScript); 0209 c_menu->addAction(QIcon::fromTheme(QStringLiteral("document-save")), i18nc("@item:inmenu", "&Export Log..."), QKeySequence::Save, this, &KAlgebra::saveLog); 0210 c_menu->addSeparator(); 0211 c_menu->addAction(i18nc("@item:inmenu", "&Insert ans..."), Qt::Key_F3, this, &KAlgebra::insertAns); 0212 c_menu->addSeparator()->setText(i18n("Execution Mode")); 0213 QActionGroup *execGroup = new QActionGroup(c_menu); 0214 QAction *calc = c_menu->addAction(i18nc("@item:inmenu", "Calculate"), this, &KAlgebra::consoleCalculate); 0215 QAction *eval = c_menu->addAction(i18nc("@item:inmenu", "Evaluate"), this, &KAlgebra::consoleEvaluate); 0216 0217 calc->setCheckable(true); 0218 eval->setCheckable(true); 0219 eval->setChecked(true); 0220 execGroup->addAction(calc); 0221 execGroup->addAction(eval); 0222 c_menu->addSeparator(); 0223 c_menu->addAction(KStandardAction::clear(c_results, SLOT(clear()), this)); 0224 initializeRecentScripts(); 0225 //////////// 0226 //////EOConsola 0227 0228 //////2D Graph 0229 b_funcsModel = new Analitza::PlotsModel(this); 0230 0231 m_graph2d = new Analitza::PlotsView2D(m_tabs); 0232 m_graph2d->setTicksShown(Qt::Orientation(0)); 0233 m_graph2d->setModel(b_funcsModel); 0234 0235 b_dock_funcs = new QDockWidget(i18n("Functions"), this); 0236 b_tools = new QTabWidget(b_dock_funcs); 0237 b_tools->setTabPosition(QTabWidget::South); 0238 addDockWidget(Qt::RightDockWidgetArea, b_dock_funcs); 0239 0240 b_funcs = new QTreeView(b_tools); 0241 b_funcs->setRootIsDecorated(false); 0242 b_funcs->setModel(b_funcsModel); 0243 b_funcs->header()->resizeSections(QHeaderView::ResizeToContents); 0244 b_funcs->setSelectionMode(QAbstractItemView::SingleSelection); 0245 m_graph2d->setSelectionModel(b_funcs->selectionModel()); 0246 0247 b_tools->addTab(b_funcs, i18n("List")); 0248 0249 b_funced = new FunctionEdit(b_tools); 0250 b_funced->setVariables(c_varsModel->variables()); 0251 connect(b_funced, &FunctionEdit::accept, this, &KAlgebra::new_func); 0252 connect(b_funced, &FunctionEdit::removeEditingPlot, this, &KAlgebra::remove_func); 0253 b_tools->addTab(b_funced, QIcon::fromTheme(QStringLiteral("list-add")), i18n("&Add")); 0254 0255 QTableView *b_varsView = new QTableView(b_tools); 0256 b_varsModel = new Analitza::VariablesModel(b_funced->variables()); 0257 b_varsView->setModel(b_varsModel); 0258 b_varsView->setShowGrid(false); 0259 b_varsView->verticalHeader()->hide(); 0260 b_varsView->horizontalHeader()->setStretchLastSection(true); 0261 b_varsView->setSelectionBehavior(QAbstractItemView::SelectRows); 0262 b_varsView->setContextMenuPolicy(Qt::CustomContextMenu); 0263 VariablesDelegate *delegate = new VariablesDelegate(b_varsView); 0264 b_varsView->setItemDelegate(delegate); 0265 b_tools->addTab(b_varsView, i18n("Variables")); 0266 0267 ViewportWidget *b_viewport = new ViewportWidget(this); 0268 b_viewport->setViewport(m_graph2d->definedViewport()); 0269 b_tools->addTab(b_viewport, i18n("Viewport")); 0270 0271 b_dock_funcs->setWidget(b_tools); 0272 b_dock_funcs->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable); 0273 m_tabs->addTab(m_graph2d, i18n("&2D Graph")); 0274 c_results->addOptionsObserver(new Add2DOption(this)); 0275 0276 connect(b_varsModel, &QAbstractItemModel::dataChanged, this, &KAlgebra::valueChanged); 0277 connect(b_funcs, &QAbstractItemView::doubleClicked, this, &KAlgebra::edit_func); 0278 connect(b_tools, &QTabWidget::currentChanged, this, &KAlgebra::functools); 0279 connect(m_graph2d, &Analitza::PlotsView2D::status, this, &KAlgebra::changeStatusBar); 0280 connect(m_graph2d, SIGNAL(viewportChanged(QRectF)), b_viewport, SLOT(setViewport(QRectF))); 0281 connect(b_viewport, SIGNAL(viewportChange(QRectF)), m_graph2d, SLOT(changeViewport(QRectF))); 0282 connect(b_varsView, &QWidget::customContextMenuRequested, this, &KAlgebra::varsContextMenu); 0283 0284 ////////menu 0285 b_menu = menuBar()->addMenu(i18n("2&D Graph")); 0286 QAction *b_actions[6]; 0287 b_actions[0] = b_menu->addAction(i18n("&Grid"), this, &KAlgebra::toggleSquares); 0288 b_actions[1] = b_menu->addAction(i18n("&Keep Aspect Ratio"), this, &KAlgebra::toggleKeepAspect); 0289 b_menu->addAction(KStandardAction::save(this, SLOT(saveGraph()), this)); 0290 b_menu->addSeparator(); 0291 b_menu->addAction(KStandardAction::zoomIn(m_graph2d, SLOT(zoomIn()), this)); 0292 b_menu->addAction(KStandardAction::zoomOut(m_graph2d, SLOT(zoomOut()), this)); 0293 QAction *ac = KStandardAction::actualSize(m_graph2d, SLOT(resetViewport()), this); 0294 ac->setShortcut({Qt::ControlModifier | Qt::Key_0}); 0295 b_menu->addAction(ac); 0296 b_menu->addSeparator()->setText(i18n("Resolution")); 0297 b_actions[2] = b_menu->addAction(i18nc("@item:inmenu", "Poor"), this, &KAlgebra::set_res_low); 0298 b_actions[3] = b_menu->addAction(i18nc("@item:inmenu", "Normal"), this, &KAlgebra::set_res_std); 0299 b_actions[4] = b_menu->addAction(i18nc("@item:inmenu", "Fine"), this, &KAlgebra::set_res_fine); 0300 b_actions[5] = b_menu->addAction(i18nc("@item:inmenu", "Very Fine"), this, &KAlgebra::set_res_vfine); 0301 m_graph2d->setContextMenuPolicy(Qt::ActionsContextMenu); 0302 m_graph2d->addActions(b_menu->actions()); 0303 0304 QActionGroup *res = new QActionGroup(b_menu); 0305 res->addAction(b_actions[2]); 0306 res->addAction(b_actions[3]); 0307 res->addAction(b_actions[4]); 0308 res->addAction(b_actions[5]); 0309 0310 b_actions[0]->setCheckable(true); 0311 b_actions[0]->setChecked(true); 0312 b_actions[1]->setCheckable(true); 0313 b_actions[1]->setChecked(true); 0314 b_actions[2]->setCheckable(true); 0315 b_actions[3]->setCheckable(true); 0316 b_actions[3]->setChecked(true); 0317 b_actions[4]->setCheckable(true); 0318 b_actions[5]->setCheckable(true); 0319 set_res_std(); 0320 //////EO2D Graph 0321 0322 /////3DGraph 0323 QWidget *tridim = new QWidget(m_tabs); 0324 QVBoxLayout *t_layo = new QVBoxLayout(tridim); 0325 t_exp = new Analitza::ExpressionEdit(tridim); 0326 t_exp->setExamples(Analitza::PlotsFactory::self()->examples(Analitza::Dim3D)); 0327 t_exp->setAns(QStringLiteral("x")); 0328 t_model3d = new Analitza::PlotsModel(this); 0329 m_graph3d = new Analitza::PlotsView3DES(tridim); 0330 m_graph3d->setModel(t_model3d); 0331 m_graph3d->setUseSimpleRotation(true); 0332 0333 tridim->setLayout(t_layo); 0334 m_tabs->addTab(tridim, i18n("&3D Graph")); 0335 t_layo->addWidget(m_graph3d); 0336 t_layo->addWidget(t_exp); 0337 0338 connect(t_exp, &Analitza::ExpressionEdit::returnPressed, this, &KAlgebra::new_func3d); 0339 c_results->addOptionsObserver(new Add3DOption(this)); 0340 0341 ////////menu 0342 t_menu = menuBar()->addMenu(i18n("3D &Graph")); 0343 QAction *t_actions[5]; 0344 t_menu->addAction(KStandardAction::save(this, SLOT(save3DGraph()), this)); 0345 t_menu->addAction(QIcon::fromTheme(QStringLiteral("zoom-original")), i18n("&Reset View"), m_graph3d, [this]() { 0346 m_graph3d->resetViewport(); 0347 }); 0348 t_menu->addSeparator(); 0349 t_actions[2] = t_menu->addAction(i18n("Dots"), this, &KAlgebra::set_dots); 0350 t_actions[3] = t_menu->addAction(i18n("Lines"), this, &KAlgebra::set_lines); 0351 t_actions[4] = t_menu->addAction(i18n("Solid"), this, &KAlgebra::set_solid); 0352 0353 QActionGroup *t_type = new QActionGroup(t_menu); 0354 t_type->addAction(t_actions[2]); 0355 t_type->addAction(t_actions[3]); 0356 t_type->addAction(t_actions[4]); 0357 0358 t_actions[2]->setCheckable(true); 0359 t_actions[3]->setCheckable(true); 0360 t_actions[4]->setCheckable(true); 0361 t_actions[4]->setChecked(true); 0362 0363 //////////// 0364 //////EO3D Graph 0365 menuBar()->addAction(QStringLiteral("|"))->setEnabled(false); 0366 0367 // Dictionary tab 0368 d_dock = new QDockWidget(i18n("Operations"), this); 0369 d_dock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable); 0370 addDockWidget(Qt::RightDockWidgetArea, d_dock); 0371 Dictionary *dic = new Dictionary(m_tabs); 0372 m_tabs->addTab(dic, i18n("&Dictionary")); 0373 0374 QWidget *w = new QWidget; 0375 QLayout *leftLayo = new QVBoxLayout(w); 0376 d_filter = new QLineEdit(w); 0377 d_filter->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed)); 0378 connect(d_filter, &QLineEdit::textChanged, dic, &Dictionary::setFilter); 0379 connect(d_filter, &QLineEdit::textChanged, this, &KAlgebra::dictionaryFilterChanged); 0380 d_list = new QListView(w); 0381 d_list->setModel(dic->model()); 0382 d_list->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding)); 0383 leftLayo->addWidget(new QLabel(i18n("Look for:"), d_dock)); 0384 leftLayo->addWidget(d_filter); 0385 leftLayo->addWidget(d_list); 0386 d_dock->setWidget(w); 0387 0388 connect(d_list->selectionModel(), &QItemSelectionModel::currentChanged, dic, &Dictionary::activated); 0389 0390 // EODictionary 0391 // Ego's reminder 0392 KHelpMenu *help = new KHelpMenu(this); 0393 menuBar()->addMenu(help->menu()); 0394 0395 #pragma message("TODO: Port to PlotsModel") 0396 // connect(b_funcsModel, SIGNAL(functionModified(QString,Analitza::Expression)), 0397 // c_results, SLOT(modifyVariable(QString,Analitza::Expression))); 0398 // connect(b_funcsModel, SIGNAL(functionRemoved(QString)), 0399 // c_results, SLOT(removeVariable(QString))); 0400 0401 connect(m_tabs, &QTabWidget::currentChanged, this, &KAlgebra::tabChanged); 0402 tabChanged(0); 0403 } 0404 0405 KAlgebra::~KAlgebra() 0406 { 0407 KConfig conf(QStringLiteral("kalgebrarc")); 0408 KConfigGroup config(&conf, QStringLiteral("Default")); 0409 QStringList urls; 0410 const auto recentScripts = c_recentScripts->urls(); 0411 for (const QUrl &url : recentScripts) 0412 urls += url.toDisplayString(); 0413 0414 config.writeEntry("recent", urls); 0415 } 0416 0417 void KAlgebra::initializeRecentScripts() 0418 { 0419 KConfig conf(QStringLiteral("kalgebrarc")); 0420 KConfigGroup config(&conf, QStringLiteral("Default")); 0421 0422 const QStringList urls = config.readEntry("recent", QStringList()); 0423 for (const QString &url : urls) { 0424 c_recentScripts->addUrl(QUrl(url)); 0425 } 0426 } 0427 0428 void KAlgebra::newInstance() 0429 { 0430 QProcess::startDetached(QApplication::applicationFilePath(), QStringList()); 0431 } 0432 0433 void KAlgebra::add2D(const Analitza::Expression &exp) 0434 { 0435 qDebug() << "adding" << exp.toString(); 0436 0437 Analitza::PlotBuilder req = Analitza::PlotsFactory::self()->requestPlot(exp, Analitza::Dim2D, c_results->analitza()->variables()); 0438 Analitza::PlotItem *curve = req.create(randomFunctionColor(), b_funcsModel->freeId()); 0439 b_funcsModel->addPlot(curve); 0440 0441 m_tabs->setCurrentIndex(1); 0442 } 0443 0444 void KAlgebra::new_func() 0445 { 0446 Analitza::FunctionGraph *f = b_funced->createFunction(); 0447 0448 if (b_funced->editing()) { 0449 QModelIndex idx = b_funcsModel->indexForName(f->name()); 0450 b_funcsModel->updatePlot(idx.row(), f); 0451 } else { 0452 b_funcsModel->addPlot(f); 0453 } 0454 0455 b_funced->setEditing(false); 0456 b_funced->clear(); 0457 b_tools->setCurrentIndex(0); 0458 b_funcs->setCurrentIndex(b_funcsModel->indexForName(f->name())); 0459 m_graph2d->setFocus(); 0460 } 0461 0462 void KAlgebra::remove_func() 0463 { 0464 Q_ASSERT(b_funced->editing()); 0465 b_funcsModel->removeRow(b_funcs->currentIndex().row()); 0466 0467 b_funced->setEditing(false); 0468 b_funced->clear(); 0469 b_tools->setCurrentIndex(0); 0470 b_funcs->setCurrentIndex(QModelIndex()); 0471 m_graph2d->setFocus(); 0472 } 0473 0474 void KAlgebra::edit_func(const QModelIndex &idx) 0475 { 0476 b_tools->setTabText(1, i18n("&Editing")); 0477 b_tools->setCurrentIndex(1); 0478 b_funced->setName(b_funcsModel->data(idx.sibling(idx.row(), 0)).toString()); 0479 b_funced->setFunction(b_funcsModel->data(idx.sibling(idx.row(), 1)).toString()); 0480 b_funced->setEditing(true); 0481 b_funced->setFocus(); 0482 } 0483 0484 void KAlgebra::functools(int i) 0485 { 0486 if (i == 0) 0487 b_tools->setTabText(1, i18n("&Add")); 0488 else { 0489 b_funced->setName(b_funcsModel->freeId()); 0490 b_funced->setColor(randomFunctionColor()); 0491 b_funced->setEditing(false); 0492 b_funced->setFocus(); 0493 } 0494 } 0495 0496 void KAlgebra::edit_var(const QModelIndex &idx) 0497 { 0498 if (idx.column() == 0) { 0499 c_exp->insertText(idx.data().toString()); 0500 } else { 0501 QModelIndex idxName = idx.sibling(idx.row(), 0); 0502 0503 QPointer<VarEdit> e(new VarEdit(this, false)); 0504 QString var = c_variables->model()->data(idxName, Qt::DisplayRole).toString(); 0505 0506 e->setAnalitza(c_results->analitza()); 0507 e->setName(var); 0508 0509 if (e->exec() == QDialog::Accepted) { 0510 QString str = var + u" := "_s + e->val().toString(); 0511 c_results->addOperation(Analitza::Expression(str, false), str); 0512 } 0513 delete e; 0514 } 0515 } 0516 0517 void KAlgebra::operate() 0518 { 0519 if (!c_exp->text().isEmpty()) { 0520 c_exp->setCorrect(c_results->addOperation(c_exp->expression(), c_exp->toPlainText())); 0521 c_exp->selectAll(); 0522 } 0523 } 0524 0525 void KAlgebra::changeStatusBar(const QString &msg) 0526 { 0527 // statusBar()->showMessage(msg); 0528 m_status->setText(msg); 0529 } 0530 0531 void KAlgebra::loadScript() 0532 { 0533 QUrl path = QFileDialog::getOpenFileUrl(this, i18n("Choose a script"), QUrl(), i18n("Script (*.kal)")); 0534 0535 if (!path.isEmpty()) 0536 loadScript(path); 0537 } 0538 0539 void KAlgebra::loadScript(const QUrl &path) 0540 { 0541 bool loaded = c_results->loadScript(path); 0542 0543 if (loaded) 0544 c_recentScripts->addUrl(path); 0545 } 0546 0547 void KAlgebra::saveScript() 0548 { 0549 QUrl path = QFileDialog::getSaveFileUrl(this, QString(), QUrl(), i18n("Script (*.kal)")); 0550 bool loaded = false; 0551 if (!path.isEmpty()) 0552 loaded = c_results->saveScript(path); 0553 0554 if (loaded) 0555 c_recentScripts->addUrl(path); 0556 } 0557 0558 void KAlgebra::saveLog() 0559 { 0560 QUrl path = QFileDialog::getSaveFileUrl(this, QString(), QUrl(), i18n("HTML File (*.html)")); 0561 if (!path.isEmpty()) 0562 c_results->saveLog(path); 0563 } 0564 0565 void KAlgebra::insertAns() 0566 { 0567 c_exp->insertText(QStringLiteral("ans")); 0568 } 0569 0570 void KAlgebra::set_res_low() 0571 { 0572 b_funcsModel->setResolution(416); 0573 } 0574 void KAlgebra::set_res_std() 0575 { 0576 b_funcsModel->setResolution(832); 0577 } 0578 void KAlgebra::set_res_fine() 0579 { 0580 b_funcsModel->setResolution(1664); 0581 } 0582 void KAlgebra::set_res_vfine() 0583 { 0584 b_funcsModel->setResolution(3328); 0585 } 0586 0587 void KAlgebra::new_func3d() 0588 { 0589 Analitza::Expression exp = t_exp->expression(); 0590 Analitza::PlotBuilder plot = Analitza::PlotsFactory::self()->requestPlot(exp, Analitza::Dim3D, c_results->analitza()->variables()); 0591 if (plot.canDraw()) { 0592 t_model3d->clear(); 0593 t_model3d->addPlot(plot.create(Qt::yellow, QStringLiteral("func3d"))); 0594 } else 0595 changeStatusBar(i18n("Errors: %1", plot.errors().join(i18n(", ")))); 0596 } 0597 0598 void KAlgebra::set_dots() 0599 { 0600 m_graph3d->setPlotStyle(Analitza::Dots); 0601 } 0602 0603 void KAlgebra::set_lines() 0604 { 0605 m_graph3d->setPlotStyle(Analitza::Wired); 0606 } 0607 0608 void KAlgebra::set_solid() 0609 { 0610 m_graph3d->setPlotStyle(Analitza::Solid); 0611 } 0612 0613 void KAlgebra::save3DGraph() 0614 { 0615 QString path = QFileDialog::getSaveFileName(this, QString(), QString(), m_graph3d->filters().join(QStringLiteral(";;"))); 0616 if (!path.isEmpty()) { 0617 m_graph3d->save(QUrl::fromLocalFile(path)); 0618 } 0619 } 0620 0621 void KAlgebra::toggleSquares() 0622 { 0623 m_graph2d->setTicksShown(m_graph2d->ticksShown() ? (Qt::Horizontal | Qt::Vertical) : ~(Qt::Horizontal | Qt::Vertical)); 0624 } 0625 0626 void KAlgebra::toggleKeepAspect() 0627 { 0628 m_graph2d->setKeepAspectRatio(!m_graph2d->keepAspectRatio()); 0629 } 0630 0631 void KAlgebra::saveGraph() 0632 { 0633 QPointer<QFileDialog> dialog = 0634 new QFileDialog(this, i18n("Select where to put the rendered plot"), QString(), i18n("Image File (*.png);;SVG File (*.svg)")); 0635 dialog->setOption(QFileDialog::DontConfirmOverwrite, false); 0636 if (dialog->exec() && !dialog->selectedFiles().isEmpty()) { 0637 QString filter = dialog->selectedNameFilter(); 0638 QString filename = dialog->selectedFiles().first(); 0639 0640 bool isSvg = filename.endsWith(QLatin1String(".svg")) || (!filename.endsWith(QLatin1String(".png")) && filter.mid(2, 3) == QLatin1String("svg")); 0641 Analitza::PlotsView2D::Format f = isSvg ? Analitza::PlotsView2D::SVG : Analitza::PlotsView2D::PNG; 0642 m_graph2d->toImage(filename, f); 0643 } 0644 delete dialog; 0645 } 0646 0647 void menuEnabledHelper(QMenu *m, bool enabled) 0648 { 0649 m->setEnabled(enabled); 0650 const auto actions = m->actions(); 0651 for (QAction *action : actions) { 0652 action->setEnabled(enabled); 0653 } 0654 } 0655 0656 void KAlgebra::tabChanged(int n) 0657 { 0658 c_dock_vars->hide(); 0659 b_dock_funcs->hide(); 0660 d_dock->hide(); 0661 0662 menuEnabledHelper(c_menu, n == 0); 0663 menuEnabledHelper(b_menu, n == 1); 0664 menuEnabledHelper(t_menu, n == 2); 0665 0666 m_status->clear(); 0667 0668 switch (n) { 0669 case 0: 0670 c_dock_vars->show(); 0671 c_dock_vars->raise(); 0672 c_exp->setFocus(); 0673 break; 0674 case 1: 0675 b_dock_funcs->show(); 0676 b_dock_funcs->raise(); 0677 0678 if (b_funcsModel->rowCount() == 0) 0679 b_tools->setCurrentIndex(1); // We set the Add tab 0680 // b_add->setFocus(); 0681 break; 0682 case 2: 0683 t_exp->setFocus(); 0684 break; 0685 case 3: 0686 d_filter->setFocus(); 0687 d_dock->show(); 0688 d_dock->raise(); 0689 default: 0690 break; 0691 } 0692 changeStatusBar(i18nc("@info:status", "Ready")); 0693 } 0694 0695 void KAlgebra::select(const QModelIndex &idx) 0696 { 0697 b_funcs->selectionModel()->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect); 0698 } 0699 0700 void KAlgebra::updateInformation() 0701 { 0702 c_varsModel->updateInformation(); 0703 c_variables->header()->resizeSections(QHeaderView::ResizeToContents); 0704 } 0705 0706 void KAlgebra::consoleCalculate() 0707 { 0708 c_results->setMode(ConsoleModel::Calculation); 0709 } 0710 0711 void KAlgebra::consoleEvaluate() 0712 { 0713 c_results->setMode(ConsoleModel::Evaluation); 0714 } 0715 0716 void KAlgebra::valueChanged() 0717 { 0718 // FIXME: Should only repaint the affected ones. 0719 if (b_funcsModel->rowCount() > 0) 0720 m_graph2d->updateFunctions(QModelIndex(), 0, b_funcsModel->rowCount() - 1); 0721 } 0722 0723 void KAlgebra::varsContextMenu(const QPoint &p) 0724 { 0725 QPointer<QMenu> m = new QMenu; 0726 m->addAction(i18n("Add variable")); 0727 QAction *ac = m->exec(b_dock_funcs->widget()->mapToGlobal(p)); 0728 0729 if (ac) { 0730 QPointer<AskName> a = new AskName(i18n("Enter a name for the new variable"), nullptr); 0731 0732 if (a->exec() == QDialog::Accepted) 0733 b_varsModel->insertVariable(a->name(), Analitza::Expression(Analitza::Cn(0))); 0734 delete a; 0735 } 0736 delete m; 0737 } 0738 0739 void KAlgebra::add3D(const Analitza::Expression &exp) 0740 { 0741 t_model3d->clear(); 0742 Analitza::PlotBuilder plot = Analitza::PlotsFactory::self()->requestPlot(exp, Analitza::Dim3D, c_results->analitza()->variables()); 0743 Q_ASSERT(plot.canDraw()); 0744 t_model3d->addPlot(plot.create(Qt::yellow, QStringLiteral("func3d_console"))); 0745 m_tabs->setCurrentIndex(2); 0746 } 0747 0748 void KAlgebra::dictionaryFilterChanged(const QString &) 0749 { 0750 if (d_list->model()->rowCount() == 1) 0751 d_list->setCurrentIndex(d_list->model()->index(0, 0)); 0752 } 0753 0754 void KAlgebra::fullScreen(bool isFull) 0755 { 0756 m_tabs->setDocumentMode(isFull); 0757 m_tabs->setTabEnabled(3, !isFull); 0758 if (isFull) { 0759 hide(); 0760 m_tabs->setParent(nullptr); 0761 setCentralWidget(nullptr); 0762 m_tabs->showFullScreen(); 0763 } else { 0764 setCentralWidget(m_tabs); 0765 show(); 0766 } 0767 }