/*************************************************************************** PVarDialog.cpp Author: Andreas Suter e-mail: andreas.suter@psi.ch ***************************************************************************/ /*************************************************************************** * Copyright (C) 2007-2023 by Andreas Suter * * andreas.suter@psi.ch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include #include #include #include #include #include "PVarDialog.h" //-------------------------------------------------------------------------- /** * @brief PShowVarNameDialog::PShowVarNameDialog. Ctor * @param info containing the necessary information of the collection */ PShowVarNameDialog::PShowVarNameDialog(PCollInfo &info) { // if fCollName is a path name, extract the fln QString collNameStr(info.fCollName); if (collNameStr.contains("/")) { #if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0)) QStringList tok = collNameStr.split('/', QString::SkipEmptyParts); #else QStringList tok = collNameStr.split('/', Qt::SkipEmptyParts); #endif collNameStr = tok[tok.count()-1]; } QLabel *collName = new QLabel(collNameStr); QLabel *numVars = new QLabel(QString("#variables: %1").arg(info.fVarName.count())); QListWidget *list = new QListWidget(); for (int i=0; isetText(QString("%1 : %2").arg(i, 2).arg(info.fVarName[i])); list->addItem(newItem); } QPushButton *done = new QPushButton("Done", this); QVBoxLayout *vLayout = new QVBoxLayout; vLayout->addWidget(collName); vLayout->addWidget(numVars); vLayout->addWidget(list); vLayout->addWidget(done); connect(done, SIGNAL( clicked() ), this, SLOT( accept() )); resize(300, 450); setLayout(vLayout); setModal(false); setWindowTitle("Variable Names"); QString iconName(""); if (true) // <-- NEEDS TO BE PROPERLY IMPLEMENTED iconName = QString(":/icons/varEdit-dark.svg"); else iconName = QString(":/icons/varEdit-plain.svg"); setWindowIcon( QIcon( QPixmap(iconName) ) ); } //-------------------------------------------------------------------------- /** * @brief PVarDialog::PVarDialog. Variable GUI allowing the users to define * variables. * @param collection_list list of all the collections * @param darkTheme plain/dark theme flag * @param parent parent widget pointer * @param f window flag */ PVarDialog::PVarDialog(QVector collection_list, bool darkTheme, QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f), fCollList(collection_list) { fVarEdit = std::make_unique(); fCollectionView = std::make_unique(); fCancel = std::make_unique("&Cancel", this); fCheck = std::make_unique("Chec&k", this); fAdd = std::make_unique("&Add", this); fHelp = std::make_unique("&Help", this); fShowVarName = std::make_unique("Show&VarName", this); // fill collection view for (int i=0; isetText(fCollList[i].fCollName); fCollectionView->addItem(newItem); } fCollectionView->setCurrentRow(0, QItemSelectionModel::Select); fCollectionView->setSelectionMode(QAbstractItemView::ExtendedSelection); QHBoxLayout *hLayout0 = new QHBoxLayout; hLayout0->addWidget(fShowVarName.get()); hLayout0->addWidget(fHelp.get()); QHBoxLayout *hLayout1 = new QHBoxLayout; hLayout1->addWidget(fCancel.get()); hLayout1->addWidget(fCheck.get()); hLayout1->addWidget(fAdd.get()); QLabel *varLabel = new QLabel("Edit Variables:"); QVBoxLayout *varVLayout = new QVBoxLayout; varVLayout->addWidget(varLabel); varVLayout->addWidget(fVarEdit.get()); QLabel *collLabel = new QLabel("Collections:"); QVBoxLayout *collVLayout = new QVBoxLayout; collVLayout->addWidget(collLabel); collVLayout->addWidget(fCollectionView.get()); QWidget *varWidget = new QWidget(this); // only needed since splitter needs a QWidget varWidget->setLayout(varVLayout); QWidget *collWidget = new QWidget(this); // only needed since splitter needs a QWidget collWidget->setLayout(collVLayout); QSplitter *splitter = new QSplitter(Qt::Vertical, this); splitter->addWidget(varWidget); splitter->addWidget(collWidget); QVBoxLayout *vLayout = new QVBoxLayout; vLayout->addWidget(splitter); vLayout->addLayout(hLayout0); vLayout->addLayout(hLayout1); fVarEdit->resize(600, 300); setLayout(vLayout); resize(600, 450); connect(fCancel.get(), SIGNAL( clicked() ), this, SLOT( reject() )); connect(fCheck.get(), SIGNAL( clicked() ), this, SLOT( check() )); connect(fAdd.get(), SIGNAL( clicked() ), this, SLOT( add() )); connect(fHelp.get(), SIGNAL( clicked() ), this, SLOT( help() )); connect(fShowVarName.get(), SIGNAL( clicked() ), this, SLOT( showVarNames() )); QString iconName(""); if (darkTheme) iconName = QString(":/icons/varEdit-dark.svg"); else iconName = QString(":/icons/varEdit-plain.svg"); setWindowIcon( QIcon( QPixmap(iconName) ) ); } //-------------------------------------------------------------------------- /** * @brief PVarDialog::check. Allows the user to check the variable string. */ void PVarDialog::check() { if (!basic_check()) return; if (!var_consistency_check()) return; // create the collection index vector QVector idx; QList selected = fCollectionView->selectedItems(); for (int i=0; irow(selected[i])); } emit check_request(fVarEdit->toPlainText(), idx); } //-------------------------------------------------------------------------- /** * @brief PVarDialog::add. It is used to initiate the add variable to the mupp GUI. */ void PVarDialog::add() { if (fVarEdit->toPlainText().isEmpty()) { QMessageBox::critical(this, "**ERROR**", "No input available."); return; } if (fCollectionView->selectedItems().count() == 0) { QMessageBox::critical(this, "**ERROR**", "One or more collection(s) need to linked to the variable(s)."); return; } if (!basic_check()) return; if (!var_consistency_check()) return; // create the collection index vector QVector idx; QList selected = fCollectionView->selectedItems(); for (int i=0; irow(selected[i])); } emit add_request(fVarEdit->toPlainText(), idx); } //-------------------------------------------------------------------------- /** * @brief PVarDialog::help */ void PVarDialog::help() { QMessageBox::information(this, "Var Help", "Syntax: var = .\n"\ " can contain identifiers defined in the collections.\n"\ "An identifier is an addressed variable which is defined\n"\ "by a preceeding '$' before the variable name.\n"\ "Example: variable sigma -> identifier $sigma.\n"\ "Example:\nvar sigSC = pow(abs(pow($sigma,2.0)-pow(0.11,2.0)),0.5)"); } //-------------------------------------------------------------------------- /** * @brief PVarDialog::showVarNames. Show a variable name dialog for a given * selected collection. */ void PVarDialog::showVarNames() { // get the selected collection if (fCollectionView->selectedItems().count() == 0) { QMessageBox::critical(this, "**ERROR**", "At least one collection needs to be selected."); return; } if (fCollectionView->selectedItems().count() > 1) { QMessageBox::critical(this, "**ERROR**", "Currently only the vars of a single collection can be shown."); return; } int idx = fCollectionView->currentRow(); if (idx >= fCollList.count()) { QMessageBox::critical(this, "**ERROR**", QString("Collection idx=%1 > #Collections=%2. This never should have happened.").arg(idx).arg(fCollList.count())); return; } PCollInfo info = fCollList[idx]; PShowVarNameDialog *dialog = new PShowVarNameDialog(info); dialog->show(); } //-------------------------------------------------------------------------- /** * @brief PVarDialog::basic_check. Carry out basic checks before feeding it * to the parser. * @return true on success */ bool PVarDialog::basic_check() { QString varStr = fVarEdit->toPlainText(); bool ok; if (varStr.isEmpty()) { QMessageBox::critical(this, "**ERROR**", "No input available."); return false; } if (fCollectionView->selectedItems().count() == 0) { QMessageBox::critical(this, "**ERROR**", "One or more collection(s) need to linked to the variable(s)."); return false; } // tokenize variable input #if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0)) QStringList strList = varStr.split(QRegularExpression("\\s+"), QString::SkipEmptyParts); #else QStringList strList = varStr.split(QRegularExpression("\\s+"), Qt::SkipEmptyParts); #endif // check if there are ANY var definitions ok = false; for (int i=0; iNO 'var' definition found."); return false; } // check that for each variable, there is also an Err variable present QStringList varNames = collectVarNames(strList, ok); if (!ok) { QMessageBox::critical(this, "**ERROR**", "found 'var' without ."); return false; } QString name(""); if (!hasErrorDef(varNames, name)) { QMessageBox::critical(this, "**ERROR**", QString("found <var_name>=%1 without corresponding %1Err.
Both, a variable and its corresponding error variable needs to be defined.").arg(name)); return false; } return true; } //-------------------------------------------------------------------------- /** * @brief PVarDialog::var_consistency_check. Variable consistency checks. For * instance it is checked that for each variable there is also the corresponding * error variable defined. * @return true on success */ bool PVarDialog::var_consistency_check() { QString varStr = fVarEdit->toPlainText(); // collect all identifiers int idx = 0, idxEnd = 0; QStringList varNames; QVector isIdendifier; char ch; bool done; do { idx = varStr.indexOf("$", idx); if (idx > -1) { // found identifier idxEnd = idx+1; done = false; do { ch = varStr[idxEnd].toLatin1(); if (isalnum(ch) || (ch == '_')) idxEnd++; else done = true; } while (!done && (idxEnd <= varStr.length())); varNames << varStr.mid(idx+1, idxEnd-idx-1); isIdendifier.push_back(1); idx++; } } while (idx != -1); // collect all the variable names idx = 0; do { idx = varStr.indexOf("var ", idx); if (idx > -1) { // found variable idxEnd = varStr.indexOf("=", idx); if (idxEnd == -1) { return false; } varNames << varStr.mid(idx+4, idxEnd-idx-5); isIdendifier.push_back(0); idx++; } } while (idx != -1); // make sure that identifier is found in collection if it is not a variable bool isVar = false; bool found = false; QString str; QList selColl = fCollectionView->selectedItems(); for (int i=0; irow(selColl[j]); found = false; for (int k=0; k= list.count()) { ok = false; } else { name << list[i+1]; i++; } } } return name; } //-------------------------------------------------------------------------- /** * @brief PVarDialog::hasErrorDef. Check for error definition * @param varNames variable name list * @param name failed variable name * @return true on success */ bool PVarDialog::hasErrorDef(QStringList &varNames, QString &name) { QString errStr; for (int i=0; i