File indexing completed on 2024-04-14 03:40:45

0001 /*
0002     KmPlot - a math. function plotter for the KDE-Desktop
0003 
0004     SPDX-FileCopyrightText: 2004 Fredrik Edemar <f_edemar@linux.se>
0005     SPDX-FileCopyrightText: 2006 David Saxton <david@bluehaze.org>
0006 
0007     This file is part of the KDE Project.
0008     KmPlot is part of the KDE-EDU Project.
0009 
0010     SPDX-License-Identifier: GPL-2.0-or-later
0011 
0012 */
0013 
0014 #include "kconstanteditor.h"
0015 #include "kmplotio.h"
0016 #include "view.h"
0017 #include "xparser.h"
0018 
0019 #include <QDebug>
0020 #include <QDialogButtonBox>
0021 #include <QStandardPaths>
0022 #include <QTimer>
0023 
0024 #include <KConfigGroup>
0025 #include <KMessageBox>
0026 #include <assert.h>
0027 
0028 #include "ui_constantseditor.h"
0029 class ConstantsEditorWidget : public QWidget, public Ui::ConstantsEditor
0030 {
0031 public:
0032     ConstantsEditorWidget(QWidget *parent = nullptr)
0033         : QWidget(parent)
0034     {
0035         setupUi(this);
0036     }
0037 };
0038 
0039 // BEGIN class KConstantEditor
0040 KConstantEditor::KConstantEditor(QWidget *parent)
0041     : QDialog(parent)
0042 {
0043     m_widget = new ConstantsEditorWidget(this);
0044 
0045     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
0046     connect(buttonBox, &QDialogButtonBox::rejected, this, &KConstantEditor::reject);
0047     QVBoxLayout *dialogLayout = new QVBoxLayout(this);
0048     dialogLayout->addWidget(m_widget);
0049     dialogLayout->addWidget(buttonBox);
0050 
0051     m_widget->cmdNew->setIcon(QIcon::fromTheme("document-new"));
0052     m_widget->cmdDelete->setIcon(QIcon::fromTheme("edit-delete"));
0053 
0054     setWindowTitle(i18nc("@title:window", "Constants Editor"));
0055 
0056     connect(this, &KConstantEditor::finished, this, &KConstantEditor::dialogFinished);
0057 
0058     m_constantValidator = new ConstantValidator(this);
0059     m_widget->nameEdit->setValidator(m_constantValidator);
0060 
0061     updateConstantsList();
0062 
0063     connect(m_widget->nameEdit, &KLineEdit::textEdited, this, &KConstantEditor::constantNameEdited);
0064     connect(m_widget->valueEdit, &EquationEdit::textEdited, this, &KConstantEditor::saveCurrentConstant);
0065 
0066     connect(m_widget->nameEdit, &KLineEdit::textChanged, this, &KConstantEditor::checkValueValid);
0067     connect(m_widget->valueEdit, &EquationEdit::textChanged, this, &KConstantEditor::checkValueValid);
0068 
0069     connect(m_widget->cmdNew, &QPushButton::clicked, this, &KConstantEditor::cmdNew_clicked);
0070     connect(m_widget->cmdDelete, &QPushButton::clicked, this, &KConstantEditor::cmdDelete_clicked);
0071 
0072     connect(m_widget->constantList, &QTreeWidget::currentItemChanged, this, &KConstantEditor::selectedConstantChanged);
0073     connect(m_widget->constantList, &QTreeWidget::itemClicked, this, &KConstantEditor::itemClicked);
0074 
0075     connect(XParser::self()->constants(), &Constants::constantsChanged, this, &KConstantEditor::updateConstantsList);
0076 
0077     checkValueValid();
0078 }
0079 
0080 KConstantEditor::~KConstantEditor()
0081 {
0082 }
0083 
0084 void KConstantEditor::dialogFinished()
0085 {
0086     XParser::self()->reparseAllFunctions();
0087     View::self()->drawPlot();
0088 }
0089 
0090 void KConstantEditor::updateConstantsList()
0091 {
0092     m_widget->constantList->blockSignals(true);
0093 
0094     // This assumes that constants have only been added or their value changed.
0095     // (since constants can only be removed via this dialog)
0096 
0097     ConstantList constants = XParser::self()->constants()->list(Constant::All);
0098     for (ConstantList::iterator it = constants.begin(); it != constants.end(); ++it) {
0099         QList<QTreeWidgetItem *> list = m_widget->constantList->findItems(it.key(), Qt::MatchExactly);
0100         if (!list.isEmpty())
0101             init(list.first(), it.key(), it.value());
0102         else {
0103             QTreeWidgetItem *item = new QTreeWidgetItem(m_widget->constantList);
0104             init(item, it.key(), it.value());
0105         }
0106     }
0107 
0108     m_widget->constantList->blockSignals(false);
0109 }
0110 
0111 void KConstantEditor::init(QTreeWidgetItem *item, const QString &name, const Constant &constant)
0112 {
0113     item->setText(0, name);
0114     item->setText(1, constant.value.expression());
0115     item->setData(2, Qt::CheckStateRole, (constant.type & Constant::Document) ? Qt::Checked : Qt::Unchecked);
0116     item->setData(2, Qt::ToolTipRole, i18n("Check this to have the constant exported when saving."));
0117     //  item->setData( 2, Qt::WhatsThisRole, i18n("Document constants are saved with the documents, and will be loaded again when the document is opened.") );
0118     item->setData(3, Qt::CheckStateRole, (constant.type & Constant::Global) ? Qt::Checked : Qt::Unchecked);
0119     item->setData(3, Qt::ToolTipRole, i18n("Check this to have the constant permanently available between instances of KmPlot."));
0120     //  item->setData( 3, Qt::WhatsThisRole, i18n("Global constants are stored in KmPlot's settings. They are not lost when KmPlot is closed.") );
0121 }
0122 
0123 void KConstantEditor::cmdNew_clicked()
0124 {
0125     QTreeWidgetItem *item = new QTreeWidgetItem(m_widget->constantList);
0126 
0127     init(item, XParser::self()->constants()->generateUniqueName(), Constant());
0128 
0129     m_widget->constantList->setCurrentItem(item);
0130     m_widget->nameEdit->setFocus();
0131 }
0132 
0133 void KConstantEditor::cmdDelete_clicked()
0134 {
0135     QTreeWidgetItem *item = m_widget->constantList->currentItem();
0136     if (!item)
0137         return;
0138 
0139     XParser::self()->constants()->remove(item->text(0));
0140 
0141     m_widget->nameEdit->clear();
0142     m_widget->valueEdit->clear();
0143     m_widget->constantList->takeTopLevelItem(m_widget->constantList->indexOfTopLevelItem(item));
0144     delete item;
0145 
0146     m_widget->cmdDelete->setEnabled(m_widget->constantList->currentItem() != nullptr);
0147 }
0148 
0149 void KConstantEditor::selectedConstantChanged(QTreeWidgetItem *current)
0150 {
0151     m_widget->cmdDelete->setEnabled(current != nullptr);
0152 
0153     QString name = current ? current->text(0) : QString();
0154     QString value = current ? current->text(1) : QString();
0155 
0156     m_previousConstantName = name;
0157     m_constantValidator->setWorkingName(m_previousConstantName);
0158 
0159     m_widget->nameEdit->setText(name);
0160     m_widget->valueEdit->setText(value);
0161 }
0162 
0163 void KConstantEditor::constantNameEdited(const QString &newName)
0164 {
0165     QTreeWidgetItem *current = m_widget->constantList->currentItem();
0166     if (!current) {
0167         Constant constant;
0168         constant.value.updateExpression(m_widget->valueEdit->text());
0169 
0170         current = new QTreeWidgetItem(m_widget->constantList);
0171         init(current, newName, constant);
0172     }
0173 
0174     XParser::self()->constants()->remove(m_previousConstantName);
0175 
0176     current->setText(0, newName);
0177     m_widget->constantList->setCurrentItem(current); // make it the current item if no item was selected before
0178 
0179     m_previousConstantName = newName;
0180 
0181     m_constantValidator->setWorkingName(m_previousConstantName);
0182 
0183     saveCurrentConstant();
0184 }
0185 
0186 void KConstantEditor::saveCurrentConstant()
0187 {
0188     if (m_widget->nameEdit->text().isEmpty())
0189         return;
0190 
0191     QTreeWidgetItem *current = m_widget->constantList->currentItem();
0192     assert(current);
0193     current->setText(1, m_widget->valueEdit->text());
0194 
0195     Constant constant;
0196     constant.value.updateExpression(m_widget->valueEdit->text());
0197 
0198     // update type
0199     constant.type = 0;
0200     if (current->data(2, Qt::CheckStateRole).toBool())
0201         constant.type |= Constant::Document;
0202     if (current->data(3, Qt::CheckStateRole).toBool())
0203         constant.type |= Constant::Global;
0204 
0205     XParser::self()->constants()->add(m_widget->nameEdit->text(), constant);
0206 }
0207 
0208 bool KConstantEditor::checkValueValid()
0209 {
0210     Parser::Error error;
0211     (double)XParser::self()->eval(m_widget->valueEdit->text(), &error);
0212     bool valid = (error == Parser::ParseSuccess) && m_constantValidator->isValid(m_widget->nameEdit->text());
0213     m_widget->valueInvalidLabel->setVisible(!valid);
0214     return valid;
0215 }
0216 
0217 void KConstantEditor::itemClicked()
0218 {
0219     QTimer::singleShot(0, this, &KConstantEditor::saveCurrentConstant);
0220 }
0221 // END class KConstantEditor
0222 
0223 // BEGIN class ConstantValidator
0224 ConstantValidator::ConstantValidator(KConstantEditor *parent)
0225     : QValidator(parent)
0226 {
0227 }
0228 
0229 bool ConstantValidator::isValid(const QString &name) const
0230 {
0231     bool correct = XParser::self()->constants()->isValidName(name);
0232     bool inUse = XParser::self()->constants()->have(name) && (m_workingName != name);
0233 
0234     return correct && !inUse;
0235 }
0236 
0237 QValidator::State ConstantValidator::validate(QString &input, int & /*pos*/) const
0238 {
0239     return isValid(input) ? Acceptable : Intermediate;
0240 }
0241 
0242 void ConstantValidator::setWorkingName(const QString &name)
0243 {
0244     m_workingName = name;
0245 }
0246 // END class ConstantValidator
0247 
0248 #include "moc_kconstanteditor.cpp"