/*************************************************************************** PmuppGui.cpp Author: Andreas Suter e-mail: andreas.suter@psi.ch ***************************************************************************/ /*************************************************************************** * Copyright (C) 2007-2020 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mupp_version.h" #include "PmuppGui.h" //---------------------------------------------------------------------------------------------------- /** * @brief PmuppXY::init the xy object */ void PmuppXY::init() { fCollectionTag = -1; fXlabel = ""; fYlabel.clear(); } //----------------------------------------------------------------------------- /** * @brief PmuppXY::setYlabel. Set the y-label * @param idx index of the y-label * @param str name of the y-label */ void PmuppXY::setYlabel(int idx, QString str) { if (idx >= fYlabel.size()) return; fYlabel[idx] = str; } //----------------------------------------------------------------------------- /** * @brief PmuppXY::removeYlabel. Remove the y-label at position idx. * @param idx index of the y-label to be removed. */ void PmuppXY::removeYlabel(int idx) { if (idx >= fYlabel.size()) return; fYlabel.remove(idx); } //----------------------------------------------------------------------------- /** * @brief PmuppXY::removeYlabel. Remove the y-label with name str. * @param str name of the y-label to be removed. */ void PmuppXY::removeYlabel(QString str) { for (int i=0; i= fYlabel.size()) return QString(""); return fYlabel[idx]; } //----------------------------------------------------------------------------- /** * @brief PmuppXY::getXlabelIdx. Get the x-label index. * @return x-label index if found, otherwise -1. */ int PmuppXY::getXlabelIdx() { QString str = fXlabel; // remove trailing '-)' int idx = fXlabel.lastIndexOf("-)"); if (idx == -1) return -1; str.remove(idx, str.length()-idx); // remove everything up to '(-' idx = fXlabel.indexOf("(-"); if (idx == -1) return -1; idx += 2; str.remove(0, idx); bool ok; idx = str.toInt(&ok); if (!ok) return -1; return idx; } //----------------------------------------------------------------------------- /** * @brief PmuppXY::getYlabelIdx. Get y-label index of index idx. * @param idx index of the y-label. * @return y-label index on success, -1 otherwise. */ int PmuppXY::getYlabelIdx(int idx) { if (idx >= fYlabel.size()) return -1; QString str = fYlabel[idx]; // remove trailing '-)' int iidx = fXlabel.lastIndexOf("-)"); if (iidx == -1) return -1; str.remove(iidx, str.length()-iidx); // remove everything up to '(-' iidx = fXlabel.indexOf("(-"); if (iidx == -1) return -1; iidx += 2; str.remove(0, iidx); bool ok; iidx = str.toInt(&ok); if (!ok) return -1; return iidx; } //----------------------------------------------------------------------------- /** * @brief PVarErrorDialog::PVarErrorDialog. Ctor * @param errMsg error message(s) to be displayed */ PVarErrorDialog::PVarErrorDialog(QString errMsg) { int length = errMsg.length(); fErrMsg = new QPlainTextEdit(errMsg); fOK = new QPushButton("Done", this); fErrMsg->setReadOnly(true); QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(fErrMsg); layout->addWidget(fOK); connect( fOK, SIGNAL( clicked() ), this, SLOT( accept() )); if (length > 0) { int noBreaks = errMsg.count('\n'); int width = 20*length / noBreaks; if (width < 300) width = 300; if (width > 900) width = 900; setMinimumWidth(width); } setLayout(layout); show(); } //----------------------------------------------------------------------------- /** *

Constructor * * \param fln file names to be loaded * \param parent pointer to the parent object * \param f qt windows flags */ PmuppGui::PmuppGui( QStringList fln, QWidget *parent, Qt::WindowFlags f ) : QMainWindow( parent, f ) { QDateTime dt = QDateTime::currentDateTime(); fDatime = dt.toTime_t(); fMuppInstance = -1; fMuppPlot = nullptr; fNormalizeAction = nullptr; fNormalize = false; fVarDlg = nullptr; fMacroPath = QString("./"); fMacroName = QString(""); readCmdHistory(); fAdmin = new PmuppAdmin(); fParamDataHandler = new PParamDataHandler(); bool dataAtStartup = false; if (fln.size() > 0) { if (fln[0].contains(".msr")) { // get collection Name QString collName = QString("collName0"); fParamDataHandler->NewCollection(collName); } QString errorMsg(""); if (!fParamDataHandler->ReadParamFile(fln, errorMsg)) { QMessageBox::critical(this, "ERROR", errorMsg); } else { dataAtStartup = true; // delay to deal with the data sets until the GUI is ready to do so } } getTheme(); QString iconName(""); if (fDarkTheme) iconName = QString(":/icons/mupp-dark.svg"); else iconName = QString(":/icons/mupp-plain.svg"); setWindowIcon( QIcon( QPixmap(iconName) ) ); // setup menus setupFileActions(); setupToolActions(); setupHelpActions(); // create central widget fCentralWidget = new QWidget(this); // setup widgets fBoxLayout_Main = new QBoxLayout(QBoxLayout::TopToBottom); fBoxLayout_Main->setGeometry(QRect(10, 40, 600, 500)); fBoxLayout_Top = new QBoxLayout(QBoxLayout::LeftToRight); fGridLayout_Left = new QGridLayout(); fGridLayout_Right = new QGridLayout(); fBoxLayout_Cmd = new QBoxLayout(QBoxLayout::LeftToRight); // label for the collection/parameter list widgets fColLabel = new QLabel(this); fColLabel->setText("Collection -> Parameter"); fColLabel->setMaximumHeight(15); // central widget for the collection/parameter list widgets fColParamSplitter = new QSplitter(Qt::Horizontal, this); fColParamSplitter->setMinimumSize(550,330); fColList = new QListWidget(this); fColList->setSelectionMode(QAbstractItemView::ExtendedSelection); fParamList = new QListWidget(this); // the next two lines enable drag and drop facility (drag) fParamList->setSelectionMode(QAbstractItemView::SingleSelection); fParamList->setDragEnabled(true); fColParamSplitter->addWidget(fColList); fColParamSplitter->addWidget(fParamList); fRemoveCollection = new QPushButton("Remove Collection", this); fRefreshCollection = new QPushButton("Refresh Collection", this); fGridLayout_Left->addWidget(fColLabel, 1, 1, 1, 2); fGridLayout_Left->addWidget(fColParamSplitter, 2, 1, 1, 2); fGridLayout_Left->addWidget(fRemoveCollection, 3, 1); fGridLayout_Left->addWidget(fRefreshCollection, 3, 2); // X-axis fXaxisLabel = new QLabel("x-axis"); fViewX = new QListWidget(this); // the next two lines enable drag and drop facility (copy drop) fViewX->viewport()->setAcceptDrops(true); fViewX->setDropIndicatorShown(true); fAddX = new QPushButton("add X", this); fRemoveX = new QPushButton("remove X", this); // Y-axis fYaxisLabel = new QLabel("y-axis"); fViewY = new QListWidget(this); // the next two lines enable drag and drop facility (copy drop) fViewY->viewport()->setAcceptDrops(true); fViewY->setDropIndicatorShown(true); fAddY = new QPushButton("add Y", this); fRemoveY = new QPushButton("remove Y", this); // 2 column button's for the right grid fAddDitto = new QPushButton("Add Ditto", this); fPlot = new QPushButton("Plot", this); fGridLayout_Right->addWidget(fXaxisLabel, 1, 1); fGridLayout_Right->addWidget(fYaxisLabel, 1, 2); fGridLayout_Right->addWidget(fViewX, 2, 1); fGridLayout_Right->addWidget(fViewY, 2, 2); fGridLayout_Right->addWidget(fAddX, 3, 1); fGridLayout_Right->addWidget(fAddY, 3, 2); fGridLayout_Right->addWidget(fRemoveX, 4, 1); fGridLayout_Right->addWidget(fRemoveY, 4, 2); fGridLayout_Right->addWidget(fAddDitto, 5, 1, 1, 2); fGridLayout_Right->addWidget(fPlot, 6, 1, 1, 2); fBoxLayout_Top->addLayout(fGridLayout_Left); fBoxLayout_Top->addLayout(fGridLayout_Right); fCmdLineHistory = new QPlainTextEdit(this); fCmdLineHistory->setReadOnly(true); fCmdLineHistory->setMaximumBlockCount(50); // fill cmd history for (int i=0; iinsertPlainText(QString("%1\n").arg(fCmdHistory[i])); fCmdLine = new QLineEdit(this); fCmdLine->installEventFilter(this); fCmdLine->setText("$ "); fCmdLine->setFocus(); // sets the keyboard focus fExitButton = new QPushButton("E&xit", this); QVBoxLayout *cmdLayout = new QVBoxLayout; QLabel *cmdLabel = new QLabel("History:"); cmdLayout->addWidget(cmdLabel); cmdLayout->addWidget(fCmdLineHistory); cmdLayout->addWidget(fCmdLine); fBoxLayout_Cmd = new QBoxLayout(QBoxLayout::LeftToRight); fBoxLayout_Cmd->addLayout(cmdLayout); fBoxLayout_Cmd->addWidget(fExitButton); fBoxLayout_Cmd->setAlignment(fCmdLine, Qt::AlignBottom); fBoxLayout_Cmd->setAlignment(fExitButton, Qt::AlignBottom); fCmdSplitter = new QSplitter(Qt::Vertical, this); QWidget *topWidget = new QWidget(this); // only needed since splitter needs a QWidget topWidget->setLayout(fBoxLayout_Top); QWidget *cmdWidget = new QWidget(this); // only needed since splitter needs a QWidget cmdWidget->setLayout(fBoxLayout_Cmd); fCmdSplitter->addWidget(topWidget); fCmdSplitter->addWidget(cmdWidget); fBoxLayout_Main->addWidget(fCmdSplitter); // establish all the necessary signal/slots connect(fRefreshCollection, SIGNAL( pressed() ), this, SLOT( refresh() )); connect(fRemoveCollection, SIGNAL( pressed() ), this, SLOT( remove() )); connect(fAddX, SIGNAL( pressed() ), this, SLOT( addX() )); connect(fAddY, SIGNAL( pressed() ), this, SLOT( addY() )); connect(fRemoveX, SIGNAL( pressed() ), this, SLOT( removeX() )); connect(fRemoveY, SIGNAL( pressed() ), this, SLOT( removeY() )); connect(fAddDitto, SIGNAL( pressed() ), this, SLOT( addDitto() )); connect(fPlot, SIGNAL( pressed()), this, SLOT( plot()) ); connect(fCmdLine, SIGNAL ( returnPressed() ), this, SLOT( handleCmds() )); connect(fExitButton, SIGNAL( pressed() ), this, SLOT( aboutToQuit() )); connect(fColList, SIGNAL( currentRowChanged(int) ), this, SLOT( updateParamList(int) )); connect(fColList, SIGNAL( itemDoubleClicked(QListWidgetItem*) ), this, SLOT( editCollName(QListWidgetItem*) )); connect(fViewX, SIGNAL( currentRowChanged(int) ), this, SLOT( refreshY() )); connect(fViewX, SIGNAL( itemChanged(QListWidgetItem*) ), this, SLOT( dropOnViewX(QListWidgetItem*) )); connect(fViewY, SIGNAL( itemChanged(QListWidgetItem*) ), this, SLOT( dropOnViewY(QListWidgetItem*) )); // deal with parameter data specifics if (dataAtStartup) handleNewData(); connect(fParamDataHandler, SIGNAL( newData() ), this, SLOT( handleNewData() )); fCentralWidget->setLayout(fBoxLayout_Main); setCentralWidget(fCentralWidget); // in case there is no db/dat file list given open the db/dat file open menu automatically. if (fln.size() == 0) { fileOpen(); if (fParamDataHandler->GetNoOfCollections() == 0) { // file open dialog has been cancelled exit(0); } } } //----------------------------------------------------------------------------- /** * @brief PmuppGui::~PmuppGui. Dtor */ PmuppGui::~PmuppGui() { // all relevant clean up job are done in ::aboutToQuit() } //----------------------------------------------------------------------------- /** * @brief PmuppGui::aboutToQuit. Called when the GUI is going to close. Cleans * up everything. */ void PmuppGui::aboutToQuit() { // kill mupp_plot if active if (fMuppPlot) { if (fMuppPlot->state() != QProcess::NotRunning) { fMuppPlot->terminate(); } } // remove message queue key_t key; int flags, msqid; // generate the ICP message queue key key = ftok(QCoreApplication::applicationFilePath().toLatin1().data(), 1); if (key != -1) { // set the necessary IPC message queue flags flags = IPC_CREAT; // open the message queue msqid = msgget(key, flags | S_IRUSR | S_IWUSR); if (msqid != -1) { if (msgctl(msqid, IPC_RMID, NULL) == -1) { std::cerr << "**ERROR** couldn't removed the message queue (msqid=" << msqid << ")." << std::endl << std::endl; } } } // clean up temporary plot files QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); if (fMuppInstance != -1) { QString pathName = QString("%1/.musrfit/mupp/_mupp_%2.dat").arg(env.value("HOME")).arg(fDatime); QFile::remove(pathName); pathName = QString("%1/.musrfit/mupp/_mupp_ftok_%2.dat").arg(env.value("HOME")).arg(fMuppInstance); QFile::remove(pathName); } // needed for clean up and to save the cmd history writeCmdHistory(); if (fParamDataHandler) { delete fParamDataHandler; fParamDataHandler = 0; } if (fAdmin) { delete fAdmin; fAdmin = 0; } exit(0); } //----------------------------------------------------------------------------- /** * @brief PmuppGui::setupFileActions. Setup the file action menus. */ void PmuppGui::setupFileActions() { QToolBar *tb = new QToolBar( this ); tb->setWindowTitle( "File Actions" ); addToolBar( tb ); QMenu *menu = new QMenu( tr( "F&ile" ), this ); menuBar()->addMenu( menu ); QAction *a; QString iconName(""); if (fDarkTheme) iconName = QString(":/icons/document-open-dark.svg"); else iconName = QString(":/icons/document-open-plain.svg"); a = new QAction( QIcon( QPixmap(iconName) ), tr( "&Open..." ), this ); a->setShortcut( tr("Ctrl+O") ); a->setStatusTip( tr("Open a musrfit parameter file.") ); connect( a, SIGNAL( triggered() ), this, SLOT( fileOpen() ) ); menu->addAction(a); if (!fDarkToolBarIcon) { // tool bar icon is not dark, even though the theme is (ubuntu) iconName = QString(":/icons/document-open-plain.svg"); a = new QAction( QIcon( QPixmap(iconName) ), tr( "&New..." ), this ); connect( a, SIGNAL( triggered() ), this, SLOT( fileOpen() ) ); } tb->addAction(a); fRecentFilesMenu = menu->addMenu( tr("Recent Files") ); for (int i=0; isetVisible(false); connect( fRecentFilesAction[i], SIGNAL(triggered()), this, SLOT(fileOpenRecent())); fRecentFilesMenu->addAction(fRecentFilesAction[i]); } fillRecentFiles(); a = new QAction( tr( "E&xit" ), this ); a->setShortcut( tr("Ctrl+Q") ); a->setStatusTip( tr("Exit Program") ); connect( a, SIGNAL( triggered() ), this, SLOT( fileExit() ) ); menu->addAction(a); } //----------------------------------------------------------------------------- /** * @brief PmuppGui::setupToolActions. Setup the tools action menu. */ void PmuppGui::setupToolActions() { QMenu *menu = new QMenu( tr( "&Tools" ), this ); menuBar()->addMenu( menu ); QAction *a; a = new QAction(tr( "Plot ..." ), this ); a->setStatusTip( tr("Plot x/y parameters") ); connect( a, SIGNAL( triggered() ), this, SLOT( plot() ) ); menu->addAction(a); a = new QAction(tr( "Create ROOT Macro ..." ), this ); a->setStatusTip( tr("Creates a ROOT Macro with the given x/y parameters") ); connect( a, SIGNAL( triggered() ), this, SLOT( createMacro() ) ); menu->addAction(a); menu->addSeparator(); a = new QAction(tr( "Dump Collections ..." ), this ); a->setStatusTip( tr("Dump all collections") ); connect( a, SIGNAL( triggered() ), this, SLOT( toolDumpCollections() ) ); menu->addAction(a); a = new QAction(tr( "Dump XY ..." ), this ); a->setStatusTip( tr("Dump XY parameter list") ); connect( a, SIGNAL( triggered() ), this, SLOT( toolDumpXY() ) ); menu->addAction(a); menu->addSeparator(); a = new QAction(tr( "Add Variable" ), this ); a->setStatusTip( tr("Calls a dialog which allows to add variables which are expressions of db/dat vars.") ); connect( a, SIGNAL( triggered() ), this, SLOT( addVar() )); menu->addAction(a); menu->addSeparator(); fNormalizeAction = new QAction(tr( "Normalize" ), this); fNormalizeAction->setStatusTip( tr("Plot Data Normalized (y-axis)") ); fNormalizeAction->setCheckable(true); connect( fNormalizeAction, SIGNAL( changed() ), this, SLOT( normalize() ) ); menu->addAction(fNormalizeAction); /* //as35 - eventually also remove PGetNormValDialog.* from the source a = new QAction(tr( "Normalize by Value" ), this); a->setStatusTip( tr("Normalize by Value") ); connect( a, SIGNAL( triggered() ), this, SLOT( normVal() ) ); menu->addAction(a); */ } //----------------------------------------------------------------------------- /** * @brief PmuppGui::setupHelpActions. Setup the help actions menu. */ void PmuppGui::setupHelpActions() { QMenu *menu = new QMenu( tr( "&Help" ), this ); menuBar()->addMenu( menu ); QAction *a; /* a = new QAction(tr( "Contents ..." ), this ); a->setStatusTip( tr("Help Contents") ); connect( a, SIGNAL( triggered() ), this, SLOT( helpContents() )); menu->addAction(a); */ a = new QAction( tr( "Cmd's" ), this ); a->setStatusTip( tr( "Lists the command line commands" ) ); connect( a, SIGNAL( triggered() ), this, SLOT( helpCmds() )); menu->addAction(a); a = new QAction( tr( "Author(s) ..." ), this ); a->setStatusTip( tr( "About the Author(s)") ); connect( a, SIGNAL( triggered() ), this, SLOT( helpAbout() )); menu->addAction(a); a = new QAction( tr( "About Qt..." ), this ); a->setStatusTip( tr( "Help About Qt") ); connect( a, SIGNAL( triggered() ), this, SLOT( helpAboutQt() )); menu->addAction(a); } //----------------------------------------------------------------------------- /** * @brief PmuppGui::fileOpen. Open muSR parameter files. */ void PmuppGui::fileOpen() { QStringList list = QFileDialog::getOpenFileNames( this, "muSR Parameter Files", "./", "db-files (*.db);; All Params (*.msr *.db *.dat);; Msr-Files (*.msr);; dat-Files (*.dat);; All (*)"); if (list.count() == 0) return; bool msrPresent = false; bool dbPresent = false; for (int i=0; iReadParamFile(list, errorMsg)) { QMessageBox::critical(this, "ERROR", errorMsg); return; } // populate the recent files if (msrPresent || dbPresent) { for (int i=0; iaddRecentFile(list[i]); // keep it in admin fillRecentFiles(); // update menu } } } //----------------------------------------------------------------------------- /** * @brief PmuppGui::fileOpenRecent. Opens a selected recent file. */ void PmuppGui::fileOpenRecent() { QAction *action = qobject_cast(sender()); if (action) { QStringList fln; fln << action->text(); QString errorMsg(""); if (!fParamDataHandler->ReadParamFile(fln, errorMsg)) { QMessageBox::critical(this, "ERROR", errorMsg); return; } } } //----------------------------------------------------------------------------- /** * @brief PmuppGui::fileExit. Exit mupp */ void PmuppGui::fileExit() { aboutToQuit(); } //----------------------------------------------------------------------------- /** * @brief PmuppGui::toolDump. Dumps collection for debug purposes. */ void PmuppGui::toolDumpCollections() { if (fParamDataHandler->GetNoOfCollections()) { fParamDataHandler->Dump(); } else { QMessageBox::warning(this, "dump collections", "no collections present"); } } //----------------------------------------------------------------------------- /** * @brief PmuppGui::toolDumpXY. Dump XY objects for debug purposes. */ void PmuppGui::toolDumpXY() { if (fXY.size() > 0) { for (int i=0; i<-><-><-><-><-><-><-><-><->"; qInfo() << i << ": collection tag: " << fXY[i].getCollectionTag(); qInfo() << " x-param: " << fXY[i].getXlabel(); for (int j=0; jisChecked(); } //----------------------------------------------------------------------------- /** * @brief PmuppGui::helpCmds. help command information popup. */ void PmuppGui::helpCmds() { QMessageBox::information(this, "cmd help", "help: this help.
"\ "add var: allows to add a variable which is formula of collection vars.
"\ "ditto: addX/Y for the new selection as for the previous ones.
"\ "dump collections: dumps all currently loaded collections.
"\ "dump XY: dumps X/Y tree.
"\ "exit/quit: close mupp.
"\ "load: calls the open file dialog.
"\ "norm <flag>: normalize plots to maximum if <flag> is true
"\ "macro <fln>: saves the X/Y data as a ROOT macro (*.C).
"\ "path <macroPath>: sets the path to the place where the macros will be saved.
"\ "plot: plot the X/Y data.
"\ "refresh: refresh the currently selected collection.
"\ "select <nn>: select collection in GUI.
"\ "    <nn> is either the collection name or the row number.
"\ "x <param_name> / y <param_name>: add the parameter to the select axis.
"\ "rmx <param_name> / rmy <param_name>: remove the parameter of the select axis.
"\ "flush: flush the history buffer."); } //----------------------------------------------------------------------------- /** * @brief PmuppGui::helpAbout. Help about message box. */ void PmuppGui::helpAbout() { QMessageBox::information(this, "about", QString("mupp: created by Andreas Suter.\nVersion: %1\nBranch: %2\nHash: %3").arg(MUPP_VERSION).arg(GIT_BRANCH).arg(GIT_COMMIT_HASH)); } //----------------------------------------------------------------------------- /** * @brief PmuppGui::helpAboutQt. Qt about message box. */ void PmuppGui::helpAboutQt() { QMessageBox::aboutQt(this); } //----------------------------------------------------------------------------- /** * @brief PmuppGui::eventFilter. Event filter for the history buffer. * @param o object pointer * @param e event pointer * * @return */ bool PmuppGui::eventFilter(QObject *o, QEvent *e) { static int idx = fCmdHistory.size(); if (e->type() == QEvent::KeyPress) { QKeyEvent *k = static_cast(e); int key = k->key(); if (key == Qt::Key_Up) { if (idx > 0) idx--; if (idx < fCmdHistory.size()) fCmdLine->setText(fCmdHistory[idx]); } else if (key == Qt::Key_Down) { if (idx < fCmdHistory.size()) idx++; if (idx < fCmdHistory.size()) fCmdLine->setText(fCmdHistory[idx]); else fCmdLine->setText("$ "); } else if (key == Qt::Key_Return) { QString cmd = fCmdLine->text(); bool found = false; for (int i=0; i= 50) fCmdHistory.removeFirst(); fCmdHistory.push_back(cmd); fCmdLineHistory->insertPlainText(QString("%1\n").arg(cmd)); } } return false; } // make sure the base class can handle all the events not handled here return QMainWindow::eventFilter(o, e); } //----------------------------------------------------------------------------- /** * @brief PmuppGui::getTheme. Tries to get the theme of the system. */ void PmuppGui::getTheme() { fDarkTheme = false; // true if theme is dark fDarkToolBarIcon = false; // needed for ubuntu dark since there the menu icons // are dark, however the toolbar icons are plain! QString str = QIcon::themeName(); if (str.isEmpty()) { if (fAdmin->isDarkTheme()) { fDarkTheme = true; fDarkToolBarIcon = true; } return; } if (str.contains("dark", Qt::CaseInsensitive)) { fDarkTheme = true; if (str.contains("ubuntu", Qt::CaseInsensitive)) { fDarkToolBarIcon = false; } else { fDarkToolBarIcon = true; } } } //----------------------------------------------------------------------------- /** *

fill the recent file list in the menu. */ void PmuppGui::fillRecentFiles() { for (int i=0; igetNumRecentFiles(); i++) { fRecentFilesAction[i]->setText(fAdmin->getRecentFile(i)); fRecentFilesAction[i]->setVisible(true); } } //----------------------------------------------------------------------------- /** * @brief PmuppGui::readCmdHistory. Read the command history from file * mupp_history.txt under $HOME/.musrfit/mupp */ void PmuppGui::readCmdHistory() { QProcessEnvironment procEnv = QProcessEnvironment::systemEnvironment(); QString home = procEnv.value("HOME", ""); if (home.isEmpty()) return; QString pathName = home + "/.musrfit/mupp/mupp_history.txt"; QFile file(pathName); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { std::cerr << std::endl; std::cerr << "***********" << std::endl; std::cerr << "**WARNING** readCmdHistory(): couldn't open mupp_history.txt for reading ..." << std::endl;; std::cerr << "***********" << std::endl; return; } QTextStream fin(&file); fCmdHistory.clear(); QString line; while (!fin.atEnd()) { line = fin.readLine(); if (line.startsWith("%") || line.isEmpty()) continue; fCmdHistory.push_back(line); } } //----------------------------------------------------------------------------- /** * @brief PmuppGui::writeCmdHistory. Write the command history buffer to file. */ void PmuppGui::writeCmdHistory() { QProcessEnvironment procEnv = QProcessEnvironment::systemEnvironment(); QString home = procEnv.value("HOME", ""); if (home.isEmpty()) return; QString pathName = home + "/.musrfit/mupp/"; QDir dir(pathName); if (!dir.exists()) { // directory $HOME/.musrfit/mupp does not exist hence create it dir.mkpath(pathName); } pathName += "mupp_history.txt"; QFile file(pathName); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) return; QTextStream fout(&file); // write header QDateTime dt = QDateTime::currentDateTime(); fout << "% mupp history file" << endl; fout << "% " << dt.toString("HH:mm:ss - yy/MM/dd") << endl; // write history for (int i=0; icurrentItem(); if (item == 0) return; QString label = item->text(); QString pathName(""); int collIdx=-1; for (int i=0; iGetNoOfCollections(); i++) { if (fParamDataHandler->GetCollection(i)->GetName() == label) { // found collection pathName = fParamDataHandler->GetCollection(i)->GetPathName(); collIdx = i; break; } } // re-load collection PmuppCollection coll; bool ok=false; if (pathName.endsWith(".db")) { QString errorMsg(""); coll = fParamDataHandler->ReadDbFile(pathName, ok, errorMsg); if (!ok) { QMessageBox::critical(this, "ERROR - REFRESH", QString("Couldn't refresh %1\nFile corrupted?!\n").arg(fParamDataHandler->GetCollection(collIdx)->GetName())+ errorMsg); return; } } else if (pathName.endsWith(".dat")) { QString errorMsg(""); coll = fParamDataHandler->ReadColumnParamFile(pathName, ok, errorMsg); if (!ok) { QMessageBox::critical(this, "ERROR - REFRESH", QString("Couldn't refresh %1\nFile corrupted?!\n").arg(fParamDataHandler->GetCollection(collIdx)->GetName())+ errorMsg); return; } } else { QMessageBox::critical(this, "ERROR - REFRESH", QString("Couldn't refresh %1").arg(fParamDataHandler->GetCollection(collIdx)->GetName())); return; } QString collName = pathName; int pos = collName.lastIndexOf("/"); collName.remove(0, pos+1); coll.SetName(collName); coll.SetPathName(pathName); fParamDataHandler->ReplaceCollection(coll, collIdx); // update the parameter list (GUI) updateParamList(collIdx); // update XY list (GUI) updateXYListGui(); } //----------------------------------------------------------------------------- /** * @brief PmuppGui::remove. Remove collection from data handler and GUI. */ void PmuppGui::remove() { // get current collection QListWidgetItem *item = fColList->currentItem(); if (item == 0) return; QString collName = item->text(); // remove it from the list widget but keep the index for further use int idx = fColList->row(item); fColList->removeItemWidget(item); delete item; // remove it from the collection handler fParamDataHandler->RemoveCollection(collName); // next it is necessary to update the XY-parameter list updateXYList(fColList->currentRow()); // if there no collections left remove all the parameters from the X/Y list // remove all fXY as well if (fColList->count() == 0) { fViewX->clear(); fViewY->clear(); fXY.clear(); return; } // select the row before the delete one if possible if (idx > 0) idx -= 1; fColList->setCurrentRow(idx, QItemSelectionModel::Select); // update the parameter list (GUI) updateParamList(idx); // update XY list (GUI) updateXYListGui(); } //----------------------------------------------------------------------------- /** * @brief PmuppGui::addX add param to x-axis * @param param name of the parameter */ void PmuppGui::addX(QString param) { QString paramName(""); if (!param.isEmpty()) { // check that param exists if (fParamList->findItems(param, Qt::MatchCaseSensitive).empty()) { QMessageBox::critical(this, "**ERROR**", QString("Parameter X '%1' not found").arg(param)); return; } paramName = param; } else { // get the parameter name from the parameter list widget QListWidgetItem *item = fParamList->currentItem(); if (item == 0) return; paramName = item->text(); } int idx = fColList->currentRow(); QString xLabel = QString("%1 (-%2-)").arg(paramName).arg(idx); // check if it is not already present for (int i=0; icount(); i++) { if (fViewX->item(i)->text() == xLabel) return; } // set the parameter name on the view X list widget fViewX->addItem(xLabel); fViewX->setCurrentRow(fViewX->count()-1); // add the item to the XY list PmuppXY xyItem; xyItem.setCollectionTag(idx); xyItem.setXlabel(xLabel); fXY.push_back(xyItem); } //----------------------------------------------------------------------------- /** * @brief PmuppGui::addY add param to y-labels * @param param name of the parameter */ void PmuppGui::addY(QString param) { QString paramName(""); if (!param.isEmpty()) { // check that param exists if (fParamList->findItems(param, Qt::MatchCaseSensitive).empty()) { QMessageBox::critical(this, "**ERROR**", QString("Parameter Y '%1' not found").arg(param)); return; } paramName = param; } else { // get the parameter name from the parameter list widget QListWidgetItem *item = fParamList->currentItem(); if (item == 0) return; paramName = item->text(); } int idx = fColList->currentRow(); QString yLabel = QString("%1 (-%2-)").arg(paramName).arg(idx); // make sure that any x-parameter selection is already present if (fViewX->count() == 0) { QMessageBox::warning(this, "**WARNING**", "It is compulsory to have at least one x-parameter set\nbefore trying to add a y-parameter."); return; } // check if collection of x- and y-parameter selection correspond idx=getXlabelIndex(fViewX->currentItem()->text()); if (idx == -1) return; if (fXY[idx].getCollectionTag() != fColList->currentRow()) { QMessageBox::warning(this, "**WARNING**", "x/y parameters need to originate from the same collection."); return; } // check if it is not already present for (int i=0; icount(); i++) { if (fViewY->item(i)->text() == yLabel) return; } // set the parameter name on the view Y list widget fViewY->addItem(yLabel); // add the item to the XY list idx=getXlabelIndex(fViewX->currentItem()->text()); if (idx == -1) return; fXY[idx].addYlabel(yLabel); } //----------------------------------------------------------------------------- /** * @brief PmuppGui::removeX. remove from the x-axis * @param param x-axis parameter name to be removed */ void PmuppGui::removeX(QString param) { QListWidgetItem *item = fViewX->currentItem(); if (item == 0) return; int idx; if (!param.isEmpty()) { idx=fColList->currentRow(); param = QString("%1 (-%2-)").arg(param).arg(idx); idx=getXlabelIndex(param); } else { idx=getXlabelIndex(item->text()); } if (idx == -1) return; fXY.remove(idx); fViewX->removeItemWidget(item); delete item; } //----------------------------------------------------------------------------- /** * @brief PmuppGui::removeY. remove from the y-axis * @param param y-axis paramter name to be removed. */ void PmuppGui::removeY(QString param) { QListWidgetItem *item = fViewY->currentItem(); if (item == 0) return; // find y in XY and remove it QString xLabel = fViewX->currentItem()->text(); QString yLabel = item->text(); if (!param.isEmpty()) { yLabel = param; } int idx = getXlabelIndex(xLabel); if (idx == -1) return; fXY[idx].removeYlabel(yLabel); fViewY->removeItemWidget(item); delete item; } //----------------------------------------------------------------------------- /** * @brief PmuppGui::addDitto. Add x-/y-axis settings present for selected * collection. */ void PmuppGui::addDitto() { if (fXY.size() == 0) { QMessageBox::critical(this, "ERROR", "No x/y items present.\nTherefore nothing to be done."); return; } if (!allXYEqual()) { QMessageBox::critical(this, "ERROR", "Multiple unequal sets of x/y items present.\nDo not know how to handle."); return; } // get the selected items from the collection QList items = fColList->selectedItems(); if (items.count() == 0) { // no selections present hence drop out return; } // verify that all selected items have corresponding x/y values bool ok=false; PmuppCollection muCol; PmuppRun muRun; for (int i=0; iGetCollection(items[i]->text(), ok); if (!ok) return; muRun = muCol.GetRun(0); // check x-values if (!findValue(muRun, kXaxis)) return; // check y-values if (!findValue(muRun, kYaxis)) return; } // populate all necessary x- and y-values for all selected collections PmuppXY muXY = fXY[0]; int idx; for (int i=0; irow(items[i]); if (indexAlreadyPresent(idx)) continue; replaceIndex(muXY, idx); fXY.push_back(muXY); // add x-axis view fViewX->addItem(muXY.getXlabel()); fViewX->setCurrentRow(fViewX->count()-1); } // un-select the collecion list fColList->clearSelection(); } //----------------------------------------------------------------------------- /** * @brief PmuppGui::addVar. Add a variable. A variable is an expression of * variables present in the collection. */ void PmuppGui::addVar() { // create collection list QVector collection_list; // go through all available collections and obtain the needed information PCollInfo collInfo; for (int i=0; iGetNoOfCollections(); i++) { // get collection name collInfo.fCollName = fParamDataHandler->GetCollectionName(i); // get variable names for (int j=0; jGetCollection(i)->GetRun(0).GetNoOfParam(); j++) { collInfo.fVarName << fParamDataHandler->GetCollection(i)->GetRun(0).GetParam(j).GetName(); } collection_list.push_back(collInfo); } // call variable dialog if (fVarDlg != nullptr) { delete fVarDlg; fVarDlg == nullptr; } fVarDlg = new PVarDialog(collection_list, fDarkTheme); connect(fVarDlg, SIGNAL(check_request(QString,QVector)), this, SLOT(check(QString,QVector))); connect(fVarDlg, SIGNAL(add_request(QString,QVector)), this, SLOT(add(QString,QVector))); fVarDlg->show(); } //----------------------------------------------------------------------------- /** * @brief PmuppGui::check a variable string syntactically and sementically for * validity. * @param varStr var string to be parsed. * @param idx vector of indices telling which collections have been selected. */ void PmuppGui::check(QString varStr, QVector idx) { int count = 0; for (int i=0; iGetCollection(i), varStr.toLatin1().data()); if (var_check.isValid()) { count++; } else { parseErrMsgDlg(); return; } } if (count == idx.size()) { QMessageBox::information(this, "**INFO**", "Parsing successful."); } fVarDlg->raise(); fVarDlg->setFocus(); } //----------------------------------------------------------------------------- /** * @brief PmuppGui::add a variable to the GUI for given collections. * @param varStr variable string to be parsed. * @param idx vector of indices telling which collections have been selected. */ void PmuppGui::add(QString varStr, QVector idx) { // analyze varStr to see how many variables are present // the PVarHandler class handles only ONE variable of ONE collection. QStringList varNames = getVarNames(varStr); // go through all collections for (int i=0; iGetCollection(idx[i]), varStr.toLatin1().data(), varNames[j].toLatin1().data()); if (!var.isValid()) { parseErrMsgDlg(); return; } fVarHandler.push_back(var); // collect all valid variables } } // add the new variable to the paramter list (fParamList) // update the parameter list (GUI) updateParamList(fColList->currentRow()); // update XY list (GUI) updateXYListGui(); } //----------------------------------------------------------------------------- /** * @brief PmuppGui::parseErrMsgDlg reads the parse error message log and creates * a dialog for the user. */ void PmuppGui::parseErrMsgDlg() { // get error messages QString mupp_err = QString("%1/.musrfit/mupp/mupp_err.log").arg(QString(qgetenv("HOME"))); QFile fin(mupp_err); QString errStr(""); if (fin.open(QIODevice::ReadOnly | QIODevice::Text)) { QTextStream in(&fin); while (!in.atEnd()) { errStr += in.readLine(); errStr += "\n"; } } fin.close(); QFile::remove(mupp_err); if (errStr.isEmpty()) errStr = "unknown error - should never happen."; QString msg = QString("Parse error(s):\n"); msg += errStr; PVarErrorDialog *errDlg = new PVarErrorDialog(msg); } //----------------------------------------------------------------------------- /** * @brief PmuppGui::getVarNames collects from the parse string the variable * names. * @param parseStr * @return */ QStringList PmuppGui::getVarNames(QString parseStr) { QStringList varNames; QString str; int idxS=0, idxE=0; while (idxS != -1) { idxS = parseStr.indexOf("var", idxS); if (idxS != -1) { idxE = parseStr.indexOf("=", idxS); str = parseStr.mid(idxS+4, idxE-idxS-4).trimmed(); if (!str.endsWith("Err")) varNames << str; idxS = idxE; } } return varNames; } //----------------------------------------------------------------------------- /** * @brief PmuppGui::getValues get parameter values from a collection or a variable. * @param collName name of the collection * @param paramName parameter name * @param ok true if any data are found, false otherwise * * @return requested values if found, otherwise and empty vector and ok set to false. */ QVector PmuppGui::getValues(QString collName, QString paramName, bool &ok) { ok = false; QVector values; // 1st check if paramName is found in collection values = fParamDataHandler->GetValues(collName, paramName); // 2nd check if paramName is found in variable handler if (values.size() == 0) { for (int i=0; i::fromStdVector(fVarHandler[i].getValues()); } } } if (values.size() > 0) ok = true; return values; } //----------------------------------------------------------------------------- /** * @brief PmuppGui::getPosErr get the positve error estimates of parameter from * a collection or a variable. * @param collName name of the collection * @param paramName parameter name * @param ok true if positive errors are found, false otherwise * * @return requested positive errors if found, otherwise and empty vector and ok set to false. */ QVector PmuppGui::getPosErr(QString collName, QString paramName, bool &ok) { ok = false; QVector values; // 1st check if paramName is found in collection values = fParamDataHandler->GetPosErr(collName, paramName); // 2nd check if paramName is found in variable handler if (values.size() == 0) { for (int i=0; i::fromStdVector(fVarHandler[i].getErrors()); } } } if (values.size() > 0) ok = true; return values; } //----------------------------------------------------------------------------- /** * @brief PmuppGui::getNegErr get the negative error estimates of parameter from * a collection or a variable. * @param collName name of the collection * @param paramName parameter name * @param ok true if negative errors are found, false otherwise * * @return requested negative errors if found, otherwise and empty vector and ok set to false. */ QVector PmuppGui::getNegErr(QString collName, QString paramName, bool &ok) { ok = false; QVector values; // 1st check if paramName is found in collection values = fParamDataHandler->GetNegErr(collName, paramName); // 2nd check if paramName is found in variable handler if (values.size() == 0) { for (int i=0; i::fromStdVector(fVarHandler[i].getErrors()); } } } if (values.size() > 0) ok = true; return values; } //----------------------------------------------------------------------------- /** * @brief PmuppGui::findValue check if run is found x-/y-axis * @param run which is searched * @param tag x-/y-axis selector * @return true if found */ bool PmuppGui::findValue(PmuppRun &run, EAxis tag) { bool result = false; if (tag == kXaxis) { for (int i=0; i (-#-)' and // all