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

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 "kparametereditor.h"
0015 
0016 #include <QDebug>
0017 #include <QDialogButtonBox>
0018 #include <QFile>
0019 #include <QFileDialog>
0020 #include <QListWidget>
0021 #include <QPushButton>
0022 #include <QTemporaryFile>
0023 #include <QTextStream>
0024 #include <QVBoxLayout>
0025 
0026 #include <KConfigGroup>
0027 #include <KIO/StoredTransferJob>
0028 #include <KJobWidgets>
0029 #include <KMessageBox>
0030 #include <kwidgetsaddons_version.h>
0031 
0032 #include "maindlg.h"
0033 
0034 #include <assert.h>
0035 
0036 class ParameterValueList;
0037 
0038 KParameterEditor::KParameterEditor(QList<Value> *l, QWidget *parent)
0039     : QDialog(parent)
0040     , m_parameter(l)
0041 {
0042     m_mainWidget = new QParameterEditor(this);
0043     setWindowTitle(i18nc("@title:window", "Parameter Editor"));
0044     QVBoxLayout *mainLayout = new QVBoxLayout;
0045     setLayout(mainLayout);
0046     mainLayout->addWidget(m_mainWidget);
0047 
0048     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
0049     QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
0050     okButton->setDefault(true);
0051     okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
0052     connect(buttonBox, &QDialogButtonBox::accepted, this, &KParameterEditor::accept);
0053     connect(buttonBox, &QDialogButtonBox::rejected, this, &KParameterEditor::reject);
0054     mainLayout->addWidget(buttonBox);
0055 
0056     mainLayout->setContentsMargins(0, 0, 0, 0);
0057 
0058     m_mainWidget->cmdNew->setIcon(QIcon::fromTheme("document-new"));
0059     m_mainWidget->cmdDelete->setIcon(QIcon::fromTheme("edit-delete"));
0060     m_mainWidget->moveUp->setIcon(QIcon::fromTheme("go-up"));
0061     m_mainWidget->moveDown->setIcon(QIcon::fromTheme("go-down"));
0062     m_mainWidget->cmdImport->setIcon(QIcon::fromTheme("document-open"));
0063     m_mainWidget->cmdExport->setIcon(QIcon::fromTheme("document-save"));
0064 
0065     m_mainWidget->list->setFocusPolicy(Qt::NoFocus);
0066 
0067     connect(m_mainWidget->value, &EquationEdit::upPressed, this, &KParameterEditor::prev);
0068     connect(m_mainWidget->value, &EquationEdit::downPressed, this, &KParameterEditor::next);
0069 
0070     for (const Value &v : qAsConst(*m_parameter))
0071         m_mainWidget->list->addItem(v.expression());
0072 
0073     connect(m_mainWidget->cmdNew, &QPushButton::clicked, this, &KParameterEditor::cmdNew_clicked);
0074     connect(m_mainWidget->cmdDelete, &QPushButton::clicked, this, &KParameterEditor::cmdDelete_clicked);
0075     connect(m_mainWidget->moveUp, &QPushButton::clicked, this, &KParameterEditor::moveUp);
0076     connect(m_mainWidget->moveDown, &QPushButton::clicked, this, &KParameterEditor::moveDown);
0077     connect(m_mainWidget->cmdImport, &QPushButton::clicked, this, &KParameterEditor::cmdImport_clicked);
0078     connect(m_mainWidget->cmdExport, &QPushButton::clicked, this, &KParameterEditor::cmdExport_clicked);
0079     connect(m_mainWidget->list, &QListWidget::currentItemChanged, this, &KParameterEditor::selectedConstantChanged);
0080 
0081     connect(m_mainWidget->value, &EquationEdit::textEdited, this, &KParameterEditor::saveCurrentValue);
0082     connect(m_mainWidget->value, &EquationEdit::textChanged, this, &KParameterEditor::checkValueValid);
0083     connect(m_mainWidget->value, &EquationEdit::returnPressed, m_mainWidget->cmdNew, &QAbstractButton::click);
0084 
0085     checkValueValid();
0086 
0087     m_mainWidget->value->setFocus();
0088 }
0089 
0090 KParameterEditor::~KParameterEditor()
0091 {
0092 }
0093 
0094 void KParameterEditor::accept()
0095 {
0096     qDebug() << "saving\n";
0097     m_parameter->clear();
0098     QString item_text;
0099     for (int i = 0; i < m_mainWidget->list->count(); i++) {
0100         item_text = m_mainWidget->list->item(i)->text();
0101         if (!item_text.isEmpty()) {
0102             Value value;
0103             if (value.updateExpression(item_text))
0104                 m_parameter->append(value);
0105         }
0106     }
0107 
0108     QDialog::accept();
0109 }
0110 
0111 void KParameterEditor::moveUp()
0112 {
0113     int current = m_mainWidget->list->currentRow();
0114 
0115     if (current == 0)
0116         return;
0117 
0118     QListWidgetItem *item = m_mainWidget->list->takeItem(current - 1);
0119     m_mainWidget->list->insertItem(current, item);
0120 }
0121 
0122 void KParameterEditor::moveDown()
0123 {
0124     int current = m_mainWidget->list->currentRow();
0125 
0126     if (current == m_mainWidget->list->count() - 1)
0127         return;
0128 
0129     QListWidgetItem *item = m_mainWidget->list->takeItem(current + 1);
0130     m_mainWidget->list->insertItem(current, item);
0131 }
0132 
0133 void KParameterEditor::cmdNew_clicked()
0134 {
0135     QListWidgetItem *item = new QListWidgetItem(m_mainWidget->list);
0136     item->setText("0");
0137     m_mainWidget->list->setCurrentItem(item);
0138     m_mainWidget->value->setFocus();
0139     m_mainWidget->value->selectAll();
0140 }
0141 
0142 void KParameterEditor::prev()
0143 {
0144     int current = m_mainWidget->list->currentRow();
0145     if (current > 0)
0146         m_mainWidget->list->setCurrentRow(current - 1);
0147 }
0148 
0149 void KParameterEditor::next()
0150 {
0151     int current = m_mainWidget->list->currentRow();
0152     if (current < m_mainWidget->list->count() - 1)
0153         m_mainWidget->list->setCurrentRow(current + 1);
0154     else
0155         cmdNew_clicked();
0156 }
0157 
0158 void KParameterEditor::selectedConstantChanged(QListWidgetItem *current)
0159 {
0160     m_mainWidget->cmdDelete->setEnabled(current != nullptr);
0161     m_mainWidget->value->setText(current ? current->text() : QString());
0162     m_mainWidget->value->selectAll();
0163 }
0164 
0165 void KParameterEditor::cmdDelete_clicked()
0166 {
0167     QListWidgetItem *item = m_mainWidget->list->currentItem();
0168     if (!item)
0169         return;
0170 
0171     m_mainWidget->value->clear();
0172     m_mainWidget->list->takeItem(m_mainWidget->list->currentRow());
0173     delete item;
0174 
0175     m_mainWidget->cmdDelete->setEnabled(m_mainWidget->list->currentItem() != nullptr);
0176 }
0177 
0178 void KParameterEditor::saveCurrentValue()
0179 {
0180     QListWidgetItem *current = m_mainWidget->list->currentItem();
0181     if (!current)
0182         current = new QListWidgetItem(m_mainWidget->list);
0183 
0184     current->setText(m_mainWidget->value->text());
0185     m_mainWidget->list->setCurrentItem(current);
0186 }
0187 
0188 bool KParameterEditor::checkValueValid()
0189 {
0190     QString valueText = m_mainWidget->value->text();
0191     Parser::Error error;
0192     (double)XParser::self()->eval(valueText, &error);
0193     bool valid = (error == Parser::ParseSuccess);
0194     m_mainWidget->valueInvalidLabel->setVisible(!valueText.isEmpty() && !valid);
0195     return valid;
0196 }
0197 
0198 void KParameterEditor::cmdImport_clicked()
0199 {
0200     QUrl url = QFileDialog::getOpenFileUrl(this, i18n("Open Parameter File"), QUrl(), i18n("Plain Text File (*.txt)"));
0201     if (url.isEmpty())
0202         return;
0203 
0204     if (!MainDlg::fileExists(url)) {
0205         KMessageBox::error(nullptr, i18n("The file does not exist."));
0206         return;
0207     }
0208 
0209     bool verbose = false;
0210     QFile file;
0211     if (!url.isLocalFile()) {
0212         KIO::StoredTransferJob *transferjob = KIO::storedGet(url);
0213         KJobWidgets::setWindow(transferjob, nullptr);
0214         if (!transferjob->exec()) {
0215             KMessageBox::error(nullptr, i18n("An error appeared when opening this file: %1", transferjob->errorString()));
0216             return;
0217         }
0218         QTemporaryFile tmpfile;
0219         tmpfile.setAutoRemove(false);
0220         tmpfile.open();
0221         tmpfile.write(transferjob->data());
0222         file.setFileName(tmpfile.fileName());
0223         tmpfile.close();
0224     } else
0225         file.setFileName(url.toLocalFile());
0226 
0227     if (file.open(QIODevice::ReadOnly)) {
0228         QTextStream stream(&file);
0229         QString line;
0230         for (int i = 1; !stream.atEnd(); i++) {
0231             line = stream.readLine();
0232             if (line.isEmpty())
0233                 continue;
0234 
0235             Parser::Error error;
0236             XParser::self()->eval(line, &error);
0237             if (error == Parser::ParseSuccess) {
0238                 if (!checkTwoOfIt(line)) {
0239                     m_mainWidget->list->addItem(line);
0240                 }
0241             } else if (!verbose) {
0242                 if (KMessageBox::warningContinueCancel(
0243                         this,
0244                         i18n("Line %1 is not a valid parameter value and will therefore not be included. Do you want to continue?", i))
0245                     == KMessageBox::Cancel) {
0246                     file.close();
0247                     QFile::remove(file.fileName());
0248                     return;
0249 #if KWIDGETSADDONS_VERSION < QT_VERSION_CHECK(5, 100, 0)
0250                 } else if (KMessageBox::warningYesNo(this,
0251 #else
0252                 } else if (KMessageBox::warningTwoActions(this,
0253 #endif
0254                                                      i18n("Would you like to be informed about other lines that cannot be read?"),
0255                                                      QString(),
0256                                                      KGuiItem(i18n("Get Informed")),
0257                                                      KGuiItem(i18n("Ignore Information")))
0258 #if KWIDGETSADDONS_VERSION < QT_VERSION_CHECK(5, 100, 0)
0259                            == KMessageBox::No)
0260 #else
0261                            == KMessageBox::SecondaryAction)
0262 #endif
0263                     verbose = true;
0264             }
0265         }
0266         file.close();
0267     } else
0268         KMessageBox::error(nullptr, i18n("An error appeared when opening this file"));
0269 
0270     if (!url.isLocalFile())
0271         QFile::remove(file.fileName());
0272 }
0273 
0274 void KParameterEditor::cmdExport_clicked()
0275 {
0276     if (!m_mainWidget->list->count())
0277         return;
0278     QUrl url = QFileDialog::getSaveFileUrl(this, i18n("Save File"), QUrl(), i18n("Plain Text File (*.txt)"));
0279     if (url.isEmpty())
0280         return;
0281 
0282     if (!MainDlg::fileExists(url)
0283         || KMessageBox::warningContinueCancel(
0284                this,
0285                i18n("A file named \"%1\" already exists. Are you sure you want to continue and overwrite this file?", url.toDisplayString()),
0286                i18n("Overwrite File?"),
0287                KStandardGuiItem::overwrite())
0288             == KMessageBox::Continue) {
0289         if (!url.isLocalFile()) {
0290             QTemporaryFile tmpfile;
0291 
0292             if (tmpfile.open()) {
0293                 QTextStream stream(&tmpfile);
0294                 for (int i = 0; i < m_mainWidget->list->count(); i++) {
0295                     QListWidgetItem *it = m_mainWidget->list->item(i);
0296                     stream << it->text();
0297                     if (i < m_mainWidget->list->count() - 1)
0298                         stream << '\n'; // only write a new line if there are more text
0299                 }
0300                 stream.flush();
0301             } else
0302                 KMessageBox::error(nullptr, i18n("An error appeared when saving this file"));
0303 
0304             Q_CONSTEXPR int permission = -1;
0305             QFile file(tmpfile.fileName());
0306             file.open(QIODevice::ReadOnly);
0307             KIO::StoredTransferJob *putjob = KIO::storedPut(file.readAll(), url, permission, KIO::JobFlag::Overwrite);
0308             if (!putjob->exec()) {
0309                 KMessageBox::error(nullptr, i18n("An error appeared when saving this file"));
0310                 return;
0311             }
0312             file.close();
0313         } else {
0314             QFile file;
0315             qDebug() << "url.path()=" << url.toLocalFile();
0316             file.setFileName(url.toLocalFile());
0317             if (file.open(QIODevice::WriteOnly)) {
0318                 QTextStream stream(&file);
0319                 for (int i = 0; i < m_mainWidget->list->count(); i++) {
0320                     QListWidgetItem *it = m_mainWidget->list->item(i);
0321                     stream << it->text();
0322                     if (i < m_mainWidget->list->count() - 1)
0323                         stream << '\n'; // only write a new line if there are more text
0324                 }
0325                 file.close();
0326             } else
0327                 KMessageBox::error(nullptr, i18n("An error appeared when saving this file"));
0328         }
0329     }
0330 }
0331 
0332 bool KParameterEditor::checkTwoOfIt(const QString &text)
0333 {
0334     return !m_mainWidget->list->findItems(text, Qt::MatchExactly).isEmpty();
0335 }
0336 
0337 #include "moc_kparametereditor.cpp"