musrfit/src/musredit_qt5/mupp/PmuppGui.cpp

2658 lines
82 KiB
C++

/***************************************************************************
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 <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <cmath>
#include <iostream>
#include <QApplication>
#include <QToolBar>
#include <QMenuBar>
#include <QMessageBox>
#include <QRect>
#include <QSpacerItem>
#include <QFrame>
#include <QStringList>
#include <QFileDialog>
#include <QListWidgetItem>
#include <QInputDialog>
#include <QFile>
#include <QTextStream>
#include <QDateTime>
#include <QKeyEvent>
#include <QProcessEnvironment>
#include <QDir>
#include <QTextStream>
#include <QDateTime>
#include <QtDebug>
#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(); i++) {
if (fYlabel[i] == str) {
fYlabel.remove(i);
return;
}
}
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppXY::getYlabel. Get the y-label with index idx
* @param idx index of the requested y-label.
*
* @return requested y-label if found, empty string otherwise.
*/
QString PmuppXY::getYlabel(int idx)
{
if (idx >= 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();
}
//-----------------------------------------------------------------------------
/**
* <p>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; i<fCmdHistory.size(); i++)
fCmdLineHistory->insertPlainText(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; i<MAX_RECENT_FILES; i++) {
fRecentFilesAction[i] = new QAction(fRecentFilesMenu);
fRecentFilesAction[i]->setVisible(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; i<list.count(); i++) {
if (list[i].endsWith(".msr"))
msrPresent = true;
else if (list[i].endsWith(".db") || list[i].endsWith(".dat"))
dbPresent = true;
else {
QMessageBox::critical(this, "ERROR", QString("Found file with unkown extension:\n%1\nWill not do anything here.").arg(list[i]));
return;
}
}
if (msrPresent && dbPresent) {
QMessageBox::critical(this, "ERROR", "Currently mixed reading of msr and db/dat is not supported.");
return;
}
QString errorMsg("");
if (!fParamDataHandler->ReadParamFile(list, errorMsg)) {
QMessageBox::critical(this, "ERROR", errorMsg);
return;
}
// populate the recent files
if (msrPresent || dbPresent) {
for (int i=0; i<list.size(); i++) {
fAdmin->addRecentFile(list[i]); // keep it in admin
fillRecentFiles(); // update menu
}
}
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppGui::fileOpenRecent. Opens a selected recent file.
*/
void PmuppGui::fileOpenRecent()
{
QAction *action = qobject_cast<QAction *>(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<fXY.size(); i++) {
qInfo() << "<-><-><-><-><-><-><-><-><-><->";
qInfo() << i << ": collection tag: " << fXY[i].getCollectionTag();
qInfo() << " x-param: " << fXY[i].getXlabel();
for (int j=0; j<fXY[i].getYlabelSize(); j++)
qInfo() << " y-param: " << fXY[i].getYlabel(j);
}
} else {
QMessageBox::warning(this, "dump XY", "no XY list present yet");
}
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppGui::normalize. SLOT called when menu Tools/Normalize is selected.
* Keeps the normalizer flag
*/
void PmuppGui::normalize()
{
fNormalize = fNormalizeAction->isChecked();
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppGui::helpCmds. help command information popup.
*/
void PmuppGui::helpCmds()
{
QMessageBox::information(this, "cmd help", "<b>help:</b> this help.<br>"\
"<b>add var</b>: allows to add a variable which is formula of collection vars.<br>"\
"<b>ditto</b>: addX/Y for the new selection as for the previous ones.<br>"\
"<b>dump collections:</b> dumps all currently loaded collections.<br>"\
"<b>dump XY:</b> dumps X/Y tree.<br>"\
"<b>exit/quit:</b> close mupp.<br>"\
"<b>load:</b> calls the open file dialog.<br>"\
"<b>norm &lt;flag&gt;:</b> normalize plots to maximum if &lt;flag&gt; is true<br>"\
"<b>macro &lt;fln&gt;:</b> saves the X/Y data as a ROOT macro (*.C).<br>"\
"<b>path &lt;macroPath&gt;:</b> sets the path to the place where the macros will be saved.<br>"\
"<b>plot:</b> plot the X/Y data.<br>"\
"<b>refresh:</b> refresh the currently selected collection.<br>"\
"<b>select &lt;nn&gt;:</b> select collection in GUI.<br>"\
"&nbsp;&nbsp;&nbsp;&nbsp;&lt;nn&gt; is either the collection name or the row number.<br>"\
"<b>x &lt;param_name&gt; / y &lt;param_name&gt;:</b> add the parameter to the select axis.<br>"\
"<b>rmx &lt;param_name&gt; / rmy &lt;param_name&gt;:</b> remove the parameter of the select axis.<br>"\
"<b>flush:</b> 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<QKeyEvent*>(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<fCmdHistory.size(); i++) {
if (cmd == fCmdHistory[i]) {
found = true;
}
}
if (!found) {
if (fCmdHistory.size() >= 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;
}
}
}
//-----------------------------------------------------------------------------
/**
* <p>fill the recent file list in the menu.
*/
void PmuppGui::fillRecentFiles()
{
for (int i=0; i<fAdmin->getNumRecentFiles(); 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; i<fCmdHistory.size(); i++)
fout << fCmdHistory[i] << endl;
fout << "% end mupp history file" << endl;
file.close();
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppGui::refresh. Refresh the collections, i.e. re-read it from file.
*/
void PmuppGui::refresh()
{
QListWidgetItem *item = fColList->currentItem();
if (item == 0)
return;
QString label = item->text();
QString pathName("");
int collIdx=-1;
for (int i=0; i<fParamDataHandler->GetNoOfCollections(); 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; i<fViewX->count(); 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; i<fViewY->count(); 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<QListWidgetItem*> 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; i<items.count(); i++) {
ok = false;
muCol = fParamDataHandler->GetCollection(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; i<items.count(); i++) {
idx = fColList->row(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<PCollInfo> collection_list;
// go through all available collections and obtain the needed information
PCollInfo collInfo;
for (int i=0; i<fParamDataHandler->GetNoOfCollections(); i++) {
// get collection name
collInfo.fCollName = fParamDataHandler->GetCollectionName(i);
// get variable names
for (int j=0; j<fParamDataHandler->GetCollection(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<int>)), this, SLOT(check(QString,QVector<int>)));
connect(fVarDlg, SIGNAL(add_request(QString,QVector<int>)), this, SLOT(add(QString,QVector<int>)));
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<int> idx)
{
int count = 0;
for (int i=0; i<idx.size(); i++) {
PVarHandler var_check(fParamDataHandler->GetCollection(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<int> 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; i<idx.size(); i++) {
// go through all the defined variables
for (int j=0; j<varNames.count(); j++) {
PVarHandler var(fParamDataHandler->GetCollection(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<double> PmuppGui::getValues(QString collName, QString paramName, bool &ok)
{
ok = false;
QVector<double> 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<fVarHandler.size(); i++) {
if ((fVarHandler[i].getCollName() == collName) &&
(fVarHandler[i].getVarName() == paramName)) {
values = QVector<double>::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<double> PmuppGui::getPosErr(QString collName, QString paramName, bool &ok)
{
ok = false;
QVector<double> 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<fVarHandler.size(); i++) {
if ((fVarHandler[i].getCollName() == collName) &&
(fVarHandler[i].getVarName() == paramName)) {
values = QVector<double>::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<double> PmuppGui::getNegErr(QString collName, QString paramName, bool &ok)
{
ok = false;
QVector<double> 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<fVarHandler.size(); i++) {
if ((fVarHandler[i].getCollName() == collName) &&
(fVarHandler[i].getVarName() == paramName)) {
values = QVector<double>::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<fXY.size(); i++) {
for (int j=0; j<run.GetNoOfParam(); j++) {
if (fXY[i].getXlabel().startsWith(run.GetParam(j).GetName())) {
result = true;
break;
}
}
}
} else if (tag == kYaxis) {
for (int i=0; i<fXY.size(); i++) {
for (int j=0; j<fXY[i].getYlabelSize(); j++) {
for (int k=0; k<run.GetNoOfParam(); k++) {
if (fXY[i].getYlabel(j).startsWith(run.GetParam(k).GetName())) {
result = true;
break;
}
}
}
}
}
return result;
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppGui::allXYEqual. Check that all x-/y-labels present are equal.
* @return true if this is the case.
*/
bool PmuppGui::allXYEqual()
{
// first make sure that all x-labels are equivalent. They have the form '<label> (-#-)' and
// all <label> must be equal
QString str1, str2;
int idx;
str1 = fXY[0].getXlabel();
idx = str1.lastIndexOf(" (-");
str1.remove(idx, str1.length()-idx);
for (int i=1; i<fXY.size(); i++) {
str2 = fXY[i].getXlabel();
idx = str2.lastIndexOf(" (-");
str2.remove(idx, str2.length()-idx);
if (str1 != str2)
return false;
}
// make sure that the number of all y-label items is equal
for (int i=1; i<fXY.size(); i++) {
if (fXY[0].getYlabelSize() != fXY[i].getYlabelSize())
return false;
}
// make sure that the y-labels are equivalent.
for (int j=0; j<fXY[0].getYlabelSize(); j++) {
str1 = fXY[0].getYlabel(j);
idx = str1.lastIndexOf(" (-");
str1.remove(idx, str1.length()-idx);
for (int i=1; i<fXY.size(); i++) {
str2 = fXY[i].getYlabel(j);
idx = str2.lastIndexOf(" (-");
str2.remove(idx, str2.length()-idx);
if (str1 != str2)
return false;
}
}
return true;
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppGui::indexAlreadyPresent. Check if x-label as given by idx is
* already present.
* @param idx which gets the x-label.
* @return true, if found.
*/
bool PmuppGui::indexAlreadyPresent(const int idx)
{
QString str = QString("(-%1-)").arg(idx);
for (int i=0; i<fXY.size(); i++) {
if (fXY[i].getXlabel().contains(str))
return true;
}
return false;
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppGui::replaceIndex replace xy-object at position idx.
* @param data xy-object to be replaced
* @param idx index position where data needs to be replaced.
*/
void PmuppGui::replaceIndex(PmuppXY &data, const int idx)
{
// handle x-label
QString label = data.getXlabel();
int pos = label.lastIndexOf(" (-");
label.truncate(pos);
QString str = QString(" (-%1-)").arg(idx);
label += str;
data.setXlabel(label);
// handle y-label(s)
for (int i=0; i<data.getYlabelSize(); i++) {
label = data.getYlabel(i);
int pos = label.lastIndexOf(" (-");
label.truncate(pos);
label += str;
data.setYlabel(i, label);
}
data.setCollectionTag(idx);
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppGui::getXlabelIndex. Get x-label index for a given search label.
* @param label for which the index is searched for.
* @return idx of the searched label on success, -1 otherwise.
*/
int PmuppGui::getXlabelIndex(QString label)
{
int idx=-1;
for (int i=0; i<fXY.size(); i++) {
if (fXY[i].getXlabel() == label) {
idx = i;
break;
}
}
return idx;
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppGui::dropOnViewX. Drag and drop for x-axis.
* @param item to be dropped.
*/
void PmuppGui::dropOnViewX(QListWidgetItem *item)
{
if (item == 0)
return;
if (item->text().contains("(-"))
return;
int idx = fColList->currentRow();
QString xLabel = QString("%1 (-%2-)").arg(item->text()).arg(idx);
// check if it is not already present
for (int i=0; i<fViewX->count(); i++) {
if (fViewX->item(i)->text() == xLabel) {
fViewX->removeItemWidget(item);
delete item;
return;
}
}
fViewX->setCurrentItem(item);
fViewX->currentItem()->setText(xLabel);
// add the item to the XY list
PmuppXY xyItem;
xyItem.setCollectionTag(idx);
xyItem.setXlabel(xLabel);
fXY.push_back(xyItem);
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppGui::dropOnViewY. Drag and drop for y-axis.
* @param item to be dropped.
*/
void PmuppGui::dropOnViewY(QListWidgetItem *item)
{
if (item == 0)
return;
if (item->text().contains("(-"))
return;
// make sure that any x-parameter selection is already present
if (fViewX->count() == 0) {
fViewY->removeItemWidget(item);
delete item;
QMessageBox::warning(this, "**WARNING**", "It is compulsory to have at least one x-parameter set\nbefore trying to add a y-parameter.");
return;
}
int idx = fColList->currentRow();
QString yLabel = QString("%1 (-%2-)").arg(item->text()).arg(idx);
// check if it is not already present
for (int i=0; i<fViewY->count(); i++) {
if (fViewY->item(i)->text() == yLabel) {
fViewY->removeItemWidget(item);
delete item;
return;
}
}
fViewY->setCurrentItem(item);
fViewY->currentItem()->setText(yLabel);
// add the item to the XY list
idx=getXlabelIndex(fViewX->currentItem()->text());
if (idx == -1)
return;
fXY[idx].addYlabel(yLabel);
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppGui::refreshY. Refresh the y-axis objects.
*/
void PmuppGui::refreshY()
{
// clear Y view
fViewY->clear();
// get proper X view item
QListWidgetItem *item = fViewX->currentItem();
if (item == 0)
return;
QString xLabel = item->text();
int idx = getXlabelIndex(xLabel);
if (idx == -1)
return;
for (int i=0; i<fXY[idx].getYlabelSize(); i++)
fViewY->addItem(fXY[idx].getYlabel(i));
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppGui::createMacro. create a root macro based on the current settings.
*/
void PmuppGui::createMacro()
{
QVector<PmuppMarker> marker = fAdmin->getMarkers();
QVector<PmuppColor> color = fAdmin->getColors();
if (fXY.size() == 0) {
QMessageBox::information(this, "createMacro", "No parameter list present.");
return;
}
if (fMacroName.isEmpty()) {
fMacroName = "__mupp.C";
}
if (!fMacroPath.isEmpty()) {
if (fMacroPath.endsWith("/"))
fMacroName.prepend(fMacroPath);
else
fMacroName.prepend(fMacroPath + "/");
}
QFile file(fMacroName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QMessageBox::critical(this, "**ERROR**", "Couldn't open macro file for writting.");
return;
}
QTextStream fout(&file);
fout << "// " << fMacroName.toLatin1().data() << endl;
fout << "// " << QDateTime::currentDateTime().toString("yy/MM/dd - HH:mm:ss") << endl;
fout << "// " << endl;
fout << "{" << endl;
fout << " gROOT->Reset();" << endl;
fout << endl;
fout << " gStyle->SetOptTitle(0);" << endl;
fout << " gStyle->SetOptDate(0);" << endl;
fout << " gStyle->SetPadColor(TColor::GetColor(255,255,255)); // pad bkg to white" << endl;
fout << " gStyle->SetCanvasColor(TColor::GetColor(255,255,255)); // canvas bkg to white" << endl;
fout << endl;
fout << " Int_t nn=0, i=0;" << endl;
fout << " Double_t null[512];" << endl;
fout << " Double_t xx[512];" << endl;
fout << " Double_t yy[512];" << endl;
fout << " Double_t yyPosErr[512];" << endl;
fout << " Double_t yyNegErr[512];" << endl;
// create all the necessary TGraph's
int collTag = -1, pos;
QString collName("");
QString xLabel(""), yLabel("");
char gLabel[128];
QVector<double> xx, yy, yyPosErr, yyNegErr;
double xMin=1.0e10, xMax=-1.0e10, yMin=1.0e10, yMax=-1.0e10;
bool ok;
for (int i=0; i<fXY.size(); i++) {
collTag = fXY[i].getCollectionTag();
collName = fColList->item(collTag)->text();
// x-label
xLabel = fXY[i].getXlabel();
pos = xLabel.indexOf(" (-");
xLabel.remove(pos, xLabel.length()-pos);
// get x-vector
xx = getValues(collName, xLabel, ok);
if (!ok) {
QString msg = QString("Couldn't get x-axis data from '%1', coll: '%2'").arg(xLabel).arg(collName);
QMessageBox::critical(this, "**ERROR**", msg);
return;
}
//as35 xx = fParamDataHandler->GetValues(collName, xLabel);
getMinMax(xx, xMin, xMax);
// a couple of x-vector specifics
if ((xLabel == "dataT") || (xLabel == "dataE"))
xMin = 0.0;
// get y-, yPosErr-, and yNegErr-vector
for (int j=0; j<fXY[i].getYlabelSize(); j++) {
// y-label
yLabel = fXY[i].getYlabel(j);
pos = yLabel.indexOf(" (-");
yLabel.remove(pos, yLabel.length()-pos);
// get y-vector
yy = getValues(collName, yLabel, ok);
if (!ok) {
QString msg = QString("Couldn't get y-axis data from '%1', coll: '%2'").arg(yLabel).arg(collName);
QMessageBox::critical(this, "**ERROR**", msg);
return;
}
//as35 yy = fParamDataHandler->GetValues(collName, yLabel);
yyPosErr = getPosErr(collName, yLabel, ok);
if (!ok) {
QString msg = QString("Couldn't get y-axis pos. error data from '%1', coll: '%2'").arg(yLabel).arg(collName);
QMessageBox::critical(this, "**ERROR**", msg);
return;
}
//as35 yyPosErr = fParamDataHandler->GetPosErr(collName, yLabel);
yyNegErr = getNegErr(collName, yLabel, ok);
if (!ok) {
QString msg = QString("Couldn't get y-axis neg. error data from '%1', coll: '%2'").arg(yLabel).arg(collName);
QMessageBox::critical(this, "**ERROR**", msg);
return;
}
//as35 yyNegErr = fParamDataHandler->GetNegErr(collName, yLabel);
yLabel = substituteDefaultLabels(yLabel);
getMinMax(yy, yMin, yMax);
// create TGraph objects
fout << endl;
snprintf(gLabel, sizeof(gLabel), "g_%d_%d", i, j);
fout << " nn = " << xx.size() << ";" << endl;
fout << endl;
fout << " // null value vector" << endl;
for (int k=0; k<xx.size(); k++) {
fout << " null[" << k << "]=0.0;" << endl;
}
fout << " // xx" << endl;
for (int k=0; k<xx.size(); k++) {
fout << " xx[" << k << "]=" << xx[k] << ";" << endl;
}
fout << " // yy" << endl;
for (int k=0; k<xx.size(); k++) {
fout << " yy[" << k << "]=" << yy[k] << ";" << endl;
}
fout << " // yyPosErr" << endl;
for (int k=0; k<xx.size(); k++) {
fout << " yyPosErr[" << k << "]=" << yyPosErr[k] << ";" << endl;
}
fout << " // yyNegErr" << endl;
for (int k=0; k<xx.size(); k++) {
fout << " yyNegErr[" << k << "]=" << fabs(yyNegErr[k]) << ";" << endl;
}
fout << endl;
fout << " TGraphAsymmErrors *" << gLabel << " = new TGraphAsymmErrors(nn, xx, yy, null, null, yyNegErr, yyPosErr);" << endl;
}
}
fout << endl;
fout << " //***************" << endl;
fout << " // plotting " << endl;
fout << " //***************" << endl;
fout << " TCanvas *c1 = new TCanvas(\"c1\", \"" << fMacroName.toLatin1().data() << "\", 10, 10, 600, 700);" << endl;
fout << endl;
int idx, r, g, b;
PmuppMarker markerObj;
for (int i=0; i<fXY.size(); i++) {
xLabel = fXY[i].getXlabel();
pos = xLabel.indexOf(" (-");
xLabel.remove(pos, xLabel.length()-pos);
xLabel = substituteDefaultLabels(xLabel);
for (int j=0; j<fXY[i].getYlabelSize(); j++) {
idx = i*fXY[i].getYlabelSize()+j; // graph number idx
markerObj = marker[idx];
yLabel = fXY[i].getYlabel(j);
pos = yLabel.indexOf(" (-");
yLabel.remove(pos, yLabel.length()-pos);
yLabel = substituteDefaultLabels(yLabel);
snprintf(gLabel, sizeof(gLabel), "g_%d_%d", i, j);
if ((i==0) && (j==0)) { // first graph
if (idx < marker.size()) {
fout << " " << gLabel << "->SetMarkerStyle(" << markerObj.getMarker() << ");" << endl;
fout << " " << gLabel << "->SetMarkerSize(" << markerObj.getMarkerSize() << ");" << endl;
} else {
fout << " " << gLabel << "->SetMarkerStyle(20); // bullet" << endl;
fout << " " << gLabel << "->SetMarkerSize(1.5);" << endl;
}
if (idx < color.size()) {
color[idx].getRGB(r, g, b);
fout << " " << gLabel << "->SetMarkerColor(TColor::GetColor(" << r << "," << g << "," << b << "));" << endl;
fout << " " << gLabel << "->SetLineColor(TColor::GetColor(" << r << "," << g << "," << b << "));" << endl;
} else {
fout << " " << gLabel << "->SetMarkerColor(kBlue);" << endl;
fout << " " << gLabel << "->SetLineColor(kBlue);" << endl;
}
fout << " " << gLabel << "->SetFillColor(kWhite);" << endl;
fout << " " << gLabel << "->GetXaxis()->SetTitle(\"" << xLabel.toLatin1().data() << "\");" << endl;
fout << " " << gLabel << "->GetXaxis()->SetTitleSize(0.05);" << endl;
fout << " " << gLabel << "->GetXaxis()->SetRangeUser(" << 0.95*xMin << ", " << 1.05*xMax << ");" << endl;
fout << " " << gLabel << "->GetYaxis()->SetTitle(\"" << yLabel.toLatin1().data() << "\");" << endl;
fout << " " << gLabel << "->GetYaxis()->SetTitleSize(0.05);" << endl;
fout << " " << gLabel << "->GetYaxis()->SetTitleOffset(1.30);" << endl;
fout << " " << gLabel << "->GetYaxis()->SetRangeUser(" << 0.95*yMin << ", " << 1.05*yMax << ");" << endl;
fout << " " << gLabel << "->GetXaxis()->SetDecimals(kTRUE);" << endl;
fout << " " << gLabel << "->Draw(\"AP\");" << endl;
} else { // consecutive graphs
if (idx < marker.size()) {
fout << " " << gLabel << "->SetMarkerStyle(" << markerObj.getMarker() << ");" << endl;
fout << " " << gLabel << "->SetMarkerSize(" << markerObj.getMarkerSize() << ");" << endl;
} else {
fout << " " << gLabel << "->SetMarkerStyle(" << 21+j << ");" << endl;
fout << " " << gLabel << "->SetMarkerSize(1.5);" << endl;
}
if (idx < color.size()) {
color[idx].getRGB(r, g, b);
fout << " " << gLabel << "->SetMarkerColor(TColor::GetColor(" << r << "," << g << "," << b << "));" << endl;
fout << " " << gLabel << "->SetLineColor(TColor::GetColor(" << r << "," << g << "," << b << "));" << endl;
} else {
fout << " " << gLabel << "->SetMarkerColor(kBlue);" << endl;
fout << " " << gLabel << "->SetLineColor(kBlue);" << endl;
}
fout << " " << gLabel << "->SetFillColor(kWhite);" << endl;
fout << " " << gLabel << "->Draw(\"Psame\");" << endl;
}
}
}
fout << "}" << endl;
// clear macro name
fMacroName = QString("");
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppGui::plot. plot all the requested x-/y-axis settings. It first
* prepares all necessary data sets, afterwards is calling mupp_plotter.
*/
void PmuppGui::plot()
{
// check if there is something to be plotted
if (fXY.size() == 0) {
QMessageBox::information(this, "plot", "No parameter list present.");
return;
}
// write data file with path name: $HOME/.musrfit/mupp/_mupp_<startUpTime>.dat
// where <startUpTime> is the time when mupp has been started.
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
QString pathName = QString("%1/.musrfit/mupp/_mupp_%2.dat").arg(env.value("HOME")).arg(fDatime);
int collTag = -1, pos;
QString collName("");
QString xLabel(""), yLabel("");
QVector<double> xx, yy, yyPosErr, yyNegErr;
QVector< QVector<double> > yyy, yyyPosErr, yyyNegErr;
bool ok;
QFile file(pathName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QMessageBox::critical(this, "ERROR", "Couldn't write necessary temporary file!");
return;
}
QTextStream fout(&file);
fout << "% path file name: " << pathName << endl;
fout << "% creation time : " << QDateTime::currentDateTime().toString("yyyy.MM.dd - hh:mm:ss") << endl;
fout << "%" << endl;
for (int i=0; i<fXY.size(); i++) {
// header info
collTag = fXY[i].getCollectionTag();
collName = fColList->item(collTag)->text();
fout << "% ---------" << endl;
fout << "% collName = " << collName << endl;
fout << "% start ---" << endl;
// x-label
xLabel = fXY[i].getXlabel();
pos = xLabel.indexOf(" (-");
xLabel.remove(pos, xLabel.length()-pos);
// get x-vector
xx = getValues(collName, xLabel, ok);
if (!ok) {
QString msg = QString("Couldn't get x-axis data from '%1', coll: '%2'").arg(xLabel).arg(collName);
QMessageBox::critical(this, "**ERROR**", msg);
return;
}
//as35 xx = fParamDataHandler->GetValues(collName, xLabel);
xLabel = substituteDefaultLabels(xLabel);
fout << "xLabel: " << xLabel << ", ";
for (int j=0; j<fXY[i].getYlabelSize()-1; j++) {
// get y-label
yLabel = fXY[i].getYlabel(j);
pos = yLabel.indexOf(" (-");
yLabel.remove(pos, yLabel.length()-pos);
// get y-vector and errors
yy = getValues(collName, yLabel, ok);
if (!ok) {
QString msg = QString("Couldn't get y-axis data from '%1', coll: '%2'").arg(yLabel).arg(collName);
QMessageBox::critical(this, "**ERROR**", msg);
return;
}
//as35 yy = fParamDataHandler->GetValues(collName, yLabel);
yyy.push_back(yy);
yyPosErr = getPosErr(collName, yLabel, ok);
if (!ok) {
QString msg = QString("Couldn't get y-axis pos. error data from '%1', coll: '%2'").arg(yLabel).arg(collName);
QMessageBox::critical(this, "**ERROR**", msg);
return;
}
//as35 yyPosErr = fParamDataHandler->GetPosErr(collName, yLabel);
yyyPosErr.push_back(yyPosErr);
yyNegErr = getNegErr(collName, yLabel, ok);
if (!ok) {
QString msg = QString("Couldn't get y-axis neg. error data from '%1', coll: '%2'").arg(yLabel).arg(collName);
QMessageBox::critical(this, "**ERROR**", msg);
return;
}
//as35 yyNegErr = fParamDataHandler->GetNegErr(collName, yLabel);
yyyNegErr.push_back(yyNegErr);
yLabel = substituteDefaultLabels(yLabel);
fout << "yLabel: " << yLabel << ", ";
}
// get last y-label
int idx=fXY[i].getYlabelSize()-1;
yLabel = fXY[i].getYlabel(idx);
pos = yLabel.indexOf(" (-");
yLabel.remove(pos, yLabel.length()-pos);
// get y-vector and errors
yy = getValues(collName, yLabel, ok);
if (!ok) {
QString msg = QString("Couldn't get y-axis data from '%1', coll: '%2'").arg(yLabel).arg(collName);
QMessageBox::critical(this, "**ERROR**", msg);
return;
}
//as35 yy = fParamDataHandler->GetValues(collName, yLabel);
yyy.push_back(yy);
yyPosErr = getPosErr(collName, yLabel, ok);
if (!ok) {
QString msg = QString("Couldn't get y-axis pos. error data from '%1', coll: '%2'").arg(yLabel).arg(collName);
QMessageBox::critical(this, "**ERROR**", msg);
return;
}
//as35 yyPosErr = fParamDataHandler->GetPosErr(collName, yLabel);
yyyPosErr.push_back(yyPosErr);
yyNegErr = getNegErr(collName, yLabel, ok);
if (!ok) {
QString msg = QString("Couldn't get y-axis neg. error data from '%1', coll: '%2'").arg(yLabel).arg(collName);
QMessageBox::critical(this, "**ERROR**", msg);
return;
}
//as35 yyNegErr = fParamDataHandler->GetNegErr(collName, yLabel);
yyyNegErr.push_back(yyNegErr);
yLabel = substituteDefaultLabels(yLabel);
fout << "yLabel: " << yLabel << endl;
// normalize if wished
if (fNormalize) {
double max=0.0;
for (int k=0; k<yyy.size(); k++) {
max=0.0;
for (int j=0; j<xx.size(); j++) {
if (yyy[k][j] > max)
max = yyy[k][j];
}
for (int j=0; j<xx.size(); j++) {
yyy[k][j] /= max;
yyyPosErr[k][j] /= max;
yyyNegErr[k][j] /= max;
}
}
}
// data
for (int j=0; j<xx.size(); j++) {
fout << xx[j] << ", ";
for (int k=0; k<yyy.size()-1; k++) {
fout << yyy[k][j] << ", " << yyyPosErr[k][j] << ", " << yyyNegErr[k][j] << ", ";
}
idx = yyy.size()-1;
fout << yyy[idx][j] << ", " << yyyPosErr[idx][j] << ", " << yyyNegErr[idx][j];
fout << endl;
}
fout << "% end -----" << endl;
// clear collection related vectors
yyy.clear();
yyyPosErr.clear();
yyyNegErr.clear();
}
file.close();
// get first free mupp instance
fMuppInstance = getFirstAvailableMuppInstance();
// issue a system message to inform to ROOT parameter plotter (rpp) that new data are available
key_t key;
struct mbuf msg;
int flags, msqid;
// generate the ICP message queue key
QString tmpPathName = QString("%1/.musrfit/mupp/_mupp_ftok_%2.dat").arg(env.value("HOME")).arg(fMuppInstance);
file.setFileName(tmpPathName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QMessageBox::critical(this, "ERROR", "Couldn't write necessary temporary file!");
return;
}
fout.setDevice(&file);
fout << QCoreApplication::applicationFilePath().toLatin1().data() << endl;
file.close();
key = ftok(QCoreApplication::applicationFilePath().toLatin1().data(), fMuppInstance);
if (key == -1) {
QMessageBox::critical(this, "ERROR", "Couldn't obtain necessary key to install the IPC message queue.");
return;
}
// 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) {
QMessageBox::critical(this, "ERROR", "Couldn't open the IPC message queue.");
return;
}
// send message
flags = IPC_NOWAIT;
msg.mtype = 1;
strncpy(msg.mtext, pathName.toLatin1().data(), PMUPP_MAX_MTEXT);
if (msgsnd(msqid, &msg, strlen(msg.mtext)+1, flags) == -1) {
QMessageBox::critical(this, "ERROR", "Couldn't send the IPC message.");
return;
}
// start native ROOT parameter plot application if not already running
if (fMuppPlot == 0) { // not running yet
startMuppPlot();
} else {
// check if mupp_plot is still running
if (fMuppPlot->state() == QProcess::NotRunning) { // not running hence start it
startMuppPlot();
}
}
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppGui::startMuppPlot start the mupp_plotter
*/
void PmuppGui::startMuppPlot()
{
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
QString cmd = QString("%1/bin/mupp_plot").arg(MUPP_PREFIX);
#if defined(Q_OS_DARWIN) || defined(Q_OS_MAC)
cmd = QString("/Applications/mupp.app/Contents/MacOS/mupp_plot");
#endif
QString workDir = QString("./");
QStringList arg;
// feed the mupp instance
arg << QString("%1").arg(fMuppInstance);
fMuppPlot = new QProcess(this);
if (fMuppPlot == nullptr) {
QMessageBox::critical(0, "**ERROR**", "Couldn't invoke QProcess for mupp_plot!");
return;
}
// make sure that the system environment variables are properly set
env.insert("LD_LIBRARY_PATH", env.value("ROOTSYS") + "/lib:" + env.value("LD_LIBRARY_PATH"));
fMuppPlot->setProcessEnvironment(env);
fMuppPlot->setWorkingDirectory(workDir);
fMuppPlot->start(cmd, arg);
if (!fMuppPlot->waitForStarted()) {
// error handling
QString msg(tr("Could not execute the output command: ")+cmd);
QMessageBox::critical( 0,
tr("Fatal error"),
msg,
tr("Quit") );
return;
}
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppGui::handleCmds. Handles the commands form the command line.
*/
void PmuppGui::handleCmds()
{
QString cmd = fCmdLine->text();
fCmdLine->setText("$ ");
cmd = cmd.trimmed();
cmd = cmd.remove("$ ");
cmd = cmd.trimmed();
if (!cmd.compare("exit", Qt::CaseInsensitive) || !cmd.compare("quit", Qt::CaseInsensitive)) {
aboutToQuit();
} else if (!cmd.compare("load", Qt::CaseInsensitive) || !cmd.compare("open", Qt::CaseInsensitive)) {
fileOpen();
} else if (!cmd.compare("dump collections", Qt::CaseInsensitive)) {
toolDumpCollections();
} else if (!cmd.compare("dump XY", Qt::CaseInsensitive)) {
toolDumpXY();
} else if (!cmd.compare("refresh", Qt::CaseInsensitive)) {
refresh();
} else if (!cmd.compare("plot", Qt::CaseInsensitive)) {
plot();
} else if (cmd.startsWith("macro")) { // cmd: macro <fln>
QStringList tok = cmd.split(" ", QString::SkipEmptyParts);
if (tok.size() != 2) {
QMessageBox::critical(this, "ERROR", QString("wrong macro cmd: %1.\nPlease check the help.").arg(cmd));
return;
}
fMacroName = tok[1];
createMacro();
} else if (cmd.startsWith("path")) { // cmd: path <macro_path>
QMessageBox::information(0, "INFO", "set's eventually the path for the macros to be saved.");
// will set the path to where to save the macro
QStringList tok = cmd.split(" ", QString::SkipEmptyParts);
if (tok.size() != 2) {
QMessageBox::critical(this, "ERROR", QString("wrong path cmd: %1.\nPlease check the help.").arg(cmd));
return;
}
// replace "~" -> "$HOME"
fMacroPath = tok[1].replace("~", "$HOME");
// if environment variable is found -> expand it
QString envVar=fMacroPath;
if (envVar.startsWith("$")) {
envVar.remove("$");
int pos = envVar.indexOf("/");
if (pos > 0)
envVar.remove(pos, fMacroPath.length()-pos);
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
QString fullPath = env.value(envVar); // get environment variable value if present, otherwise "" is returned
if (fullPath.isEmpty()) {
fMacroPath = "";
QMessageBox::critical(0, "ERROR", QString("Environment variable '%1' not present. Typo?!").arg(envVar.prepend("$")));
return;
}
fMacroPath.replace(envVar.prepend("$"), fullPath);
}
} else if (cmd.startsWith("select") || cmd.startsWith("sc")) {
selectCollection(cmd);
} else if (cmd.startsWith("x")) {
QStringList tok = cmd.split(" ", QString::SkipEmptyParts);
if (tok.size() > 1)
addX(tok[1]);
else
QMessageBox::critical(0, "ERROR", QString("Found command 'x' without variable."));
} else if (cmd.startsWith("y")) {
QStringList tok = cmd.split(" ", QString::SkipEmptyParts);
if (tok.size() > 1)
addY(tok[1]);
else
QMessageBox::critical(0, "ERROR", QString("Found command 'y' without variable."));
} else if (cmd.startsWith("ditto")) {
addDitto();
} else if (cmd.startsWith("rmx")) {
QStringList tok = cmd.split(" ", QString::SkipEmptyParts);
if (tok.size() > 1)
removeX(tok[1]);
else
QMessageBox::critical(0, "ERROR", QString("Found command 'rmx' without variable."));
} else if (cmd.startsWith("rmy")) {
QStringList tok = cmd.split(" ", QString::SkipEmptyParts);
if (tok.size() > 1)
removeY(tok[1]);
else
QMessageBox::critical(0, "ERROR", QString("Found command 'rmy' without variable."));
} else if (cmd.startsWith("norm")) {
QStringList tok = cmd.split(" ", QString::SkipEmptyParts);
if (tok.size() != 2) {
QMessageBox::critical(this, "**ERROR**", "found wrong norm cmd, will ignore it.");
return;
}
if (!tok[1].trimmed().compare("true", Qt::CaseInsensitive)) {
fNormalizeAction->setChecked(true);
} else if (!tok[1].trimmed().compare("false", Qt::CaseInsensitive)) {
fNormalizeAction->setChecked(false);
} else {
QMessageBox::critical(this, "**ERROR**", "found wrong norm cmd, will ignore it.");
return;
}
} else if (cmd.startsWith("add var")) {
addVar();
} else if (cmd.startsWith("flush")) {
fCmdHistory.clear();
fCmdLine->setText("$ ");
fCmdLineHistory->clear();
fCmdLineHistory->insertPlainText("$");
} else if (cmd.startsWith("help")) {
helpCmds();
} else {
helpCmds();
}
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppGui::handleNewData. Handle new data from the fParamDataHandler.
*/
void PmuppGui::handleNewData()
{
// update collection list view
updateCollectionList();
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppGui::updateCollectionList. update collection list.
*/
void PmuppGui::updateCollectionList()
{
// check if collection is already present
bool valid=false;
PmuppCollection coll;
for (int i=0; i<fParamDataHandler->GetNoOfCollections(); i++) {
coll = fParamDataHandler->GetCollection(i, valid);
if (isNewCollection(coll)) {
fColList->addItem(coll.GetName());
}
}
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppGui::updateParamList. Update parameter list of the selected
* collection defined by currentRow. Check also for variables.
* @param currentRow is the index of the selected collection.
*/
void PmuppGui::updateParamList(int currentRow)
{
QListWidgetItem *item = fColList->item(currentRow);
if (item == 0) {
fParamList->clear();
return;
}
// update parameter list widget
bool valid = false;
PmuppCollection coll = fParamDataHandler->GetCollection(item->text(), valid);
if (!valid) {
return;
}
PmuppRun run = coll.GetRun(0);
fParamList->clear();
for (int i=0; i<run.GetNoOfParam(); i++) {
fParamList->insertItem(i, run.GetParam(i).GetName());
}
// check if this collection has defined variables, and if yes add them as well
for (int i=0; i<fVarHandler.size(); i++) {
if (fVarHandler[i].getCollName() == item->text()) {
fParamList->addItem(fVarHandler[i].getVarName());
}
}
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppGui::updateXYList. Update xy-objects.
* @param idx collection index which has been removed
*/
void PmuppGui::updateXYList(int idx)
{
// 1st: remove XY with collection index idx from the list
for (int i=0; i<fXY.size(); i++) {
// since each collection is only once present, the following is good enough
if (fXY[i].getCollectionTag() == idx) {
fXY.remove(i);
break;
}
}
// 2nd: re-number the XY list according to the new collections
QString str("");
int pos=-1;
int oldIdx=-1;
for (int i=0; i<fXY.size(); i++) {
oldIdx = fXY[i].getCollectionTag();
if (oldIdx > idx) {
// correct collection tag
fXY[i].setCollectionTag(oldIdx-1);
// correct X label
str = fXY[i].getXlabel();
pos = str.indexOf("(");
str.remove(pos, str.length()-pos);
str += QString("(-%1-)").arg(oldIdx-1);
fXY[i].setXlabel(str);
// correct Y label
for (int j=0; j<fXY[i].getYlabelSize(); j++) {
str = fXY[i].getYlabel(j);
pos = str.indexOf("(");
str.remove(pos, str.length()-pos);
str += QString("(-%1-)").arg(oldIdx-1);
fXY[i].setYlabel(j, str);
}
}
}
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppGui::updateXYListGui. Update x-axis settings. This is needed
* after a remove or refresh.
*/
void PmuppGui::updateXYListGui()
{
fViewX->clear();
for (int i=0; i<fXY.size(); i++) {
fViewX->addItem(fXY[i].getXlabel());
}
fViewX->setCurrentRow(0);
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppGui::isNewCollection. Check if coll is a new collection.
* @param coll collection which needs to be searched for.
* @return true if present, flase otherwise.
*/
bool PmuppGui::isNewCollection(PmuppCollection &coll)
{
for (int i=0; i<fColList->count(); i++)
if (fColList->item(i)->text() == coll.GetName())
return false;
return true;
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppGui::editCollName allow to edit the collection name.
* @param item from the listWidget.
*/
void PmuppGui::editCollName(QListWidgetItem *item)
{
bool ok;
QString oldName = item->text();
QString newName = QInputDialog::getText(this, "Change Collection Name", "Collection Name",
QLineEdit::Normal, oldName, &ok);
if (ok && !newName.isEmpty()) {
item->setText(newName);
fParamDataHandler->GetCollection(oldName)->SetName(newName);
fParamDataHandler->Dump();
}
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppGui::getMinMax. Get minimum and maximum from data set.
* @param data data set
* @param min minimum of data
* @param max maximum of data
*/
void PmuppGui::getMinMax(QVector<double> &data, double &min, double &max)
{
for (int i=0; i<data.size(); i++) {
if (data[i] < min)
min = data[i];
if (data[i] > max)
max = data[i];
}
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppGui::substituteDefaultLabels. Substitutes default labels, like
* sigma -> #sigma to make the plot nicer.
* @param label to be checked to prettify.
* @return prettified label string.
*/
QString PmuppGui::substituteDefaultLabels(QString label)
{
QString result(label);
if (label == "dataT") {
result = QString("T (K)");
} else if (label == "dataB") {
result = QString("B (G)");
} else if (label == "dataE") {
result =QString("E (keV)");
} else if (!label.compare("sigma", Qt::CaseInsensitive)) {
if (fNormalize) {
result = QString("#sigma/max(#sigma)");
} else {
result = QString("#sigma (1/#mus)");
}
} else if (!label.compare("lambda", Qt::CaseInsensitive)) {
if (fNormalize) {
result = QString("#lambda/max(#lambda)");
} else {
result = QString("#lambda (1/#mus)");
}
} else if (!label.compare("alpha_LR", Qt::CaseInsensitive)) {
if (fNormalize) {
result = QString("#alpha_{LR}/max(#alpha_{LR})");
} else {
result = QString("#alpha_{LR}");
}
} else if (!label.compare("alpha_TB", Qt::CaseInsensitive)) {
if (fNormalize) {
result = QString("#alpha_{TB}/max(#alpha_{TB})");
} else {
result = QString("#alpha_{TB}");
}
} else {
if (fNormalize) {
result = QString("Normalized ");
result += label;
}
}
return result;
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppGui::selectCollection. Called from the command line. It allows to
* select a collection.
* @param cmd string to select a collection
*/
void PmuppGui::selectCollection(QString cmd)
{
bool ok;
int ival, pos=-1;
QString str = cmd;
if (cmd.contains("select")) {
str.remove("select");
str = str.trimmed();
} else if (cmd.contains("sc")) {
pos = cmd.indexOf("sc");
str.remove(0, pos+2);
str = str.trimmed();
} else {
return;
}
ival = str.toInt(&ok);
if (ok) { // it is a number
if (ival < fColList->count())
fColList->setCurrentRow(ival);
else
QMessageBox::critical(this, "**ERROR**",
QString("Found Row Selection %1 which is > #Selections=%2").arg(ival).arg(fColList->count()));
} else { // assume it is a collection name
for (int i=0; i<fColList->count(); i++) {
if (fColList->item(i)->text() == str) {
fColList->setCurrentRow(i);
break;
}
}
}
}
//-----------------------------------------------------------------------------
/**
* @brief PmuppGui::getFirstAvailableMuppInstance. Get the first free mupp
* instance of the mupp <-> mupp_plotter ICP message queue
* @return the first free instance.
*/
uint PmuppGui::getFirstAvailableMuppInstance()
{
// if fMuppInstance already set, i.e. != -1, do nothing
if (fMuppInstance != -1)
return fMuppInstance;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
QString fln("");
uint i=0;
for (i=0; i<256; i++) {
fln = QString("%1/.musrfit/mupp/_mupp_ftok_%2.dat").arg(env.value("HOME")).arg(i);
if (!QFile::exists(fln))
break;
}
return i;
}