diff --git a/CMakeLists.txt b/CMakeLists.txt index 8925072c..f7002393 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ if (CMAKE_VERSION GREATER_EQUAL 3.12) cmake_policy(SET CMP0075 NEW) endif (CMAKE_VERSION GREATER_EQUAL 3.12) -project(musrfit VERSION 1.6.4 LANGUAGES C CXX) +project(musrfit VERSION 1.6.5 LANGUAGES C CXX) #--- musrfit specific options ------------------------------------------------- option(dks "build musrfit with DKS (GPU/MIC) support" ON) @@ -150,49 +150,58 @@ endif (DKS_FOUND) if (qt_based_tools) # check for any Qt, i.e. AUTO if (qt_version STREQUAL AUTO) - # first try Qt5 - # Find the QtCore library + # try Qt6 + find_package(Qt6Core) + if (Qt6Core_FOUND) + find_package(Qt6Widgets CONFIG REQUIRED) + find_package(Qt6Xml CONFIG REQUIRED) + find_package(Qt6Network CONFIG REQUIRED) + find_package(Qt6Svg CONFIG REQUIRED) + find_package(Qt6PrintSupport CONFIG REQUIRED) + endif (Qt6Core_FOUND) + # try Qt5 find_package(Qt5Core) - if (Qt5Core_FOUND) - # Find the QtWidgets library + if (NOT Qt5Core_FOUND) find_package(Qt5Widgets CONFIG REQUIRED) - # Find the QtXml library find_package(Qt5Xml CONFIG REQUIRED) - # Find the QtNetwork library find_package(Qt5Network CONFIG REQUIRED) - # Find the QtSvg library find_package(Qt5Svg CONFIG REQUIRED) - # Fing the QtPrintSupport find_package(Qt5PrintSupport CONFIG REQUIRED) - endif (Qt5Core_FOUND) + endif (NOT Qt5Core_FOUND) - # if Qt5 is not found, try Qt4 - if (NOT Qt5Core_FOUND) + # if Qt6 and Qt5 is not found, try Qt4 + if (NOT Qt6Core_FOUND AND NOT Qt5Core_FOUND) find_package(Qt4 COMPONENTS QtGui QtWebKit QtXml) - endif (NOT Qt5Core_FOUND) + endif (NOT Qt6Core_FOUND AND NOT Qt5Core_FOUND) - # if Qt5 and Qt4 is not found try Qt3. Hopefully you never reach this point - if (NOT Qt5Core_FOUND) - if (NOT Qt4_FOUND) - find_package(Qt3) - endif (NOT Qt4_FOUND) - endif (NOT Qt5Core_FOUND) + # if Qt6, Qt5 and Qt4 is not found try Qt3. Hopefully you never reach this point + if (NOT Qt6Core_FOUND AND NOT Qt5Core_FOUND AND Qt4_FOUND) + find_package(Qt3) + endif (NOT Qt6Core_FOUND AND NOT Qt5Core_FOUND AND Qt4_FOUND) endif (qt_version STREQUAL AUTO) - # check specifically for Qt5 + # check specifically for Qt6 + if (qt_version STREQUAL 6) + find_package(Qt6Core) + if (Qt6Core_FOUND) + find_package(Qt6Widgets CONFIG REQUIRED) + find_package(Qt6Xml CONFIG REQUIRED) + find_package(Qt6Network CONFIG REQUIRED) + find_package(Qt6Svg CONFIG REQUIRED) + find_package(Qt6PrintSupport CONFIG REQUIRED) + else (Qt6Core_FOUND) + message(FATAL_ERROR "Couldn't find the specifically requested Qt6 version.") + endif (Qt6Core_FOUND) + endif (qt_version STREQUAL 6) + + # check specifically for Qt5 if (qt_version STREQUAL 5) - # Find the QtCore library find_package(Qt5Core) if (Qt5Core_FOUND) - # Find the QtWidgets library find_package(Qt5Widgets CONFIG REQUIRED) - # Find the QtXml library find_package(Qt5Xml CONFIG REQUIRED) - # Find the QtNetwork library find_package(Qt5Network CONFIG REQUIRED) - # Find the QtSvg library find_package(Qt5Svg CONFIG REQUIRED) - # Fing the QtPrintSupport find_package(Qt5PrintSupport CONFIG REQUIRED) else (Qt5Core_FOUND) message(FATAL_ERROR "Couldn't find the specifically requested Qt5 version.") @@ -219,7 +228,7 @@ endif (qt_based_tools) #--- if NeXus check also for HDF4, HDF5, and MXML ----------------------------- if (nexus) find_package(HDF5 COMPONENTS CXX REQUIRED ) - find_package(HDF4 REQUIRED) +#as35 find_package(HDF4 REQUIRED) find_package(NeXus REQUIRED) add_definitions(-DPNEXUS_ENABLED) endif (nexus) @@ -288,17 +297,21 @@ endif (nexus) message("") if (qt_based_tools) - if (Qt5Core_FOUND) - message(" Qt found in ${Qt5Core_INCLUDE_DIRS} (Version: ${Qt5Core_VERSION})") - else (Qt5Core_FOUND) - if (Qt4_FOUND) - message(" Qt found (Version: ${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}.${QT_VERSION_PATCH})") - else (Qt4_FOUND) - if (QT_FOUND) - message(" Qt found (Version: ${QT_VERSION})") - endif (QT_FOUND) - endif (Qt4_FOUND) - endif (Qt5Core_FOUND) + if (Qt6Core_FOUND) + message(" Qt found in ${Qt6Core_INCLUDE_DIRS} (Version: ${Qt6Core_VERSION})") + else (Qt6Core_FOUND) + if (Qt5Core_FOUND) + message(" Qt found in ${Qt5Core_INCLUDE_DIRS} (Version: ${Qt5Core_VERSION})") + else (Qt5Core_FOUND) + if (Qt4_FOUND) + message(" Qt found (Version: ${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}.${QT_VERSION_PATCH})") + else (Qt4_FOUND) + if (QT_FOUND) + message(" Qt found (Version: ${QT_VERSION})") + endif (QT_FOUND) + endif (Qt4_FOUND) + endif (Qt5Core_FOUND) + endif (Qt6Core_FOUND) endif (qt_based_tools) message("") message(" Features:") @@ -336,25 +349,27 @@ else (BNMRlibs) endif (BNMRlibs) if (qt_based_tools) -if (Qt5Core_FOUND) +if (Qt6Core_FOUND) + message("") + message(" Qt6 based tools:") + message(" musredit, musrStep, musrWiz, mupp : yes") +elseif (Qt5Core_FOUND) message("") message(" Qt5 based tools:") message(" musredit, musrStep, musrWiz, mupp : yes") -endif (Qt5Core_FOUND) -if (Qt4_FOUND) +elseif (Qt4_FOUND) message("") message(" Qt4 based tools (deprecated):") message(" musredit : yes") -endif (Qt4_FOUND) -if (QT_FOUND) +else () message("") message(" Qt3 based tools (outdated):") message(" musrgui : yes") -endif (QT_FOUND) -if (NOT Qt5Core_FOUND AND NOT Qt4_FOUND AND NOT QT_FOUND) +endif () +if (NOT Qt6Core_FOUND AND NOT Qt5Core_FOUND AND NOT Qt4_FOUND AND NOT QT_FOUND) message("") message(" NO Qt based tools will be installed since Qt is not found or not installed on the system") -endif (NOT Qt5Core_FOUND AND NOT Qt4_FOUND AND NOT QT_FOUND) +endif (NOT Qt6Core_FOUND AND NOT Qt5Core_FOUND AND NOT Qt4_FOUND AND NOT QT_FOUND) else (qt_based_tools) message("") message(" Qt based tools (musredit, musrStep, musrWiz, mupp) have been disabled") diff --git a/ChangeLog b/ChangeLog index 97be543f..41be0adc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,6 +12,11 @@ or https://bitbucket.org/muonspin/musrfit/commits/all +Release of V1.6.5, 2021/01/22 +============================= + +Add Qt6 version of musredit, mupp, etc. + Release of V1.6.4, 2020/08/29 ============================= diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c7b2d703..3204e2a0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,9 @@ #--- add further sub-directories ---------------------------------------------- add_subdirectory(classes) add_subdirectory(external) -if (Qt5Core_FOUND) +if (Qt6Core_FOUND) + add_subdirectory(musredit_qt6) +elseif (Qt5Core_FOUND) add_subdirectory(musredit_qt5) elseif (Qt4_FOUND) add_subdirectory(musredit) diff --git a/src/musredit_qt6/CMakeLists.txt b/src/musredit_qt6/CMakeLists.txt new file mode 100644 index 00000000..0aad99a7 --- /dev/null +++ b/src/musredit_qt6/CMakeLists.txt @@ -0,0 +1,12 @@ +#--- musredit_qt6 for Qt > 6.0 ------------------------------------------------ + +#--- create musrfit-info.h ---------------------------------------------------- +configure_file( + ${CMAKE_SOURCE_DIR}/cmake/musrfit-info.h.in + ${CMAKE_CURRENT_BINARY_DIR}/musrfit-info.h +) + +add_subdirectory(musredit) +add_subdirectory(musrStep) +add_subdirectory(musrWiz) +add_subdirectory(mupp) diff --git a/src/musredit_qt6/mupp/CMakeLists.txt b/src/musredit_qt6/mupp/CMakeLists.txt new file mode 100644 index 00000000..70ff1cbf --- /dev/null +++ b/src/musredit_qt6/mupp/CMakeLists.txt @@ -0,0 +1,107 @@ +#--- mupp for Qt > 6.0 -------------------------------------------------------- + +#--- Find includes in corresponding build directories ------------------------- +set(CMAKE_INCLUDE_CURRENT_DIR ON) +#--- instruct CMake to run moc automatically when needed ---------------------- +set(CMAKE_AUTOMOC ON) + +#--- define mupp version ------------------------------------------------------ +set(mupp_VERSION 1.0.0) + +#--- mupp_version.h generation - START ---------------------------------------- +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/configure_mupp_version_file.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/configure_mupp_version_file.cmake + @ONLY +) + +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/mupp_version.h + COMMAND ${CMAKE_COMMAND} -P + ${CMAKE_CURRENT_BINARY_DIR}/configure_mupp_version_file.cmake + DEPENDS + ${CMAKE_CURRENT_BINARY_DIR}/configure_mupp_version_file.cmake + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/mupp_version.h.in + COMMENT "Configuring mupp_version.h" + VERBATIM +) + +add_custom_target( + configure_mupp_version ALL + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/mupp_version.h +) +#--- mupp_version.h generation - END ------------------------------------------ + +add_subdirectory(plotter) + +qt6_add_resources(qrc_mupp.cpp mupp.qrc) +set_property(SOURCE qrc_mupp.cpp PROPERTY SKIP_AUTOMOC ON) # needed for cmake 3.x + +set(GENERATED_HEADER_FILES + mupp_version.h +) +set_property(SOURCE mupp_version.h PROPERTY SKIP_AUTOMOC ON) # needed for cmake 3.x + +set(MUPP_SOURCE_FILES + mupp.cpp + PmuppAdmin.cpp + Pmupp.cpp + PmuppScript.cpp + PmuppGui.cpp + PVarDialog.cpp +) + +if (APPLE) + set(RESOURCE_FILES icons/mupp.icns) + add_executable(mupp + MACOSX_BUNDLE ${GENERATED_HEADER_FILES} ${MUPP_SOURCE_FILES} + qrc_mupp.cpp ${RESOURCE_FILES} + ) +else (APPLE) + add_executable(mupp ${GENERATED_HEADER_FILES} ${MUPP_SOURCE_FILES} qrc_mupp.cpp) +endif (APPLE) + +#--- compiler option to workaround a little cast problem for some +#--- boost/compiler combinations ---------------------------------------------- +target_compile_options(mupp + PRIVATE + "-fpermissive" +) + +#--- add the variable related sources ----------------------------------------- +add_subdirectory(var) + +#--- add the necessary header includes ---------------------------------------- +target_include_directories(mupp + BEFORE PRIVATE + $ + $ + $ +) + +#--- use the Widgets and XML modules from Qt5 --------------------------------- +target_link_libraries(mupp Qt6::Widgets Qt6::Xml) + +#--- if macOS make an app rather than just a command line executable ---------- +set_target_properties(mupp PROPERTIES + VERSION ${mupp_VERSION} +) +if (APPLE) + set_target_properties(mupp PROPERTIES + MACOSX_BUNDLE TRUE + MACOSX_BUNDLE_BUNDLE_NAME "mupp" + MACOSX_BUNDLE_INFO_STRING "mupp is used to plot parameters from musrfit collections." + MACOSX_BUNDLE_ICON_FILE "mupp.icns" + MACOSX_BUNDLE_LONG_VERSION_STRING "${mupp_VERSION}" + MACOSX_FRAMEWORK_IDENTIFIER ch.psi.mupp + MACOSX_BUNDLE_COPYRIGHT "Andreas Suter" + RESOURCE "${RESOURCE_FILES}" + ) +endif (APPLE) + +#--- install ------------------------------------------------------------------ +if (APPLE) + install(TARGETS mupp BUNDLE DESTINATION /Applications) +else (APPLE) + install(TARGETS mupp DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) +endif (APPLE) diff --git a/src/musredit_qt6/mupp/PVarDialog.cpp b/src/musredit_qt6/mupp/PVarDialog.cpp new file mode 100644 index 00000000..e46b1cab --- /dev/null +++ b/src/musredit_qt6/mupp/PVarDialog.cpp @@ -0,0 +1,459 @@ +/*************************************************************************** + + PVarDialog.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 "PVarDialog.h" + +//-------------------------------------------------------------------------- +/** + * @brief PShowVarNameDialog::PShowVarNameDialog. Ctor + * @param info containing the necessary information of the collection + */ +PShowVarNameDialog::PShowVarNameDialog(PCollInfo &info) +{ + // if fCollName is a path name, extract the fln + QString collNameStr(info.fCollName); + if (collNameStr.contains("/")) { + QStringList tok = collNameStr.split('/', Qt::SkipEmptyParts); + collNameStr = tok[tok.count()-1]; + } + QLabel *collName = new QLabel(collNameStr); + QLabel *numVars = new QLabel(QString("#variables: %1").arg(info.fVarName.count())); + QListWidget *list = new QListWidget(); + for (int i=0; isetText(QString("%1 : %2").arg(i, 2).arg(info.fVarName[i])); + list->addItem(newItem); + } + QPushButton *done = new QPushButton("Done", this); + + QVBoxLayout *vLayout = new QVBoxLayout; + vLayout->addWidget(collName); + vLayout->addWidget(numVars); + vLayout->addWidget(list); + vLayout->addWidget(done); + + connect(done, SIGNAL( clicked() ), this, SLOT( accept() )); + + resize(300, 450); + setLayout(vLayout); + setModal(false); + setWindowTitle("Variable Names"); + + QString iconName(""); + if (true) // <-- NEEDS TO BE PROPERLY IMPLEMENTED + iconName = QString(":/icons/varEdit-dark.svg"); + else + iconName = QString(":/icons/varEdit-plain.svg"); + setWindowIcon( QIcon( QPixmap(iconName) ) ); +} + +//-------------------------------------------------------------------------- +/** + * @brief PVarDialog::PVarDialog. Variable GUI allowing the users to define + * variables. + * @param collection_list list of all the collections + * @param darkTheme plain/dark theme flag + * @param parent parent widget pointer + * @param f window flag + */ +PVarDialog::PVarDialog(QVector collection_list, bool darkTheme, + QWidget *parent, Qt::WindowFlags f) : + QDialog(parent, f), fCollList(collection_list) +{ + fVarEdit = new QPlainTextEdit(); + fCollectionView = new QListWidget(); + fCancel = new QPushButton("&Cancel", this); + fCheck = new QPushButton("Chec&k", this); + fAdd = new QPushButton("&Add", this); + fHelp = new QPushButton("&Help", this); + fShowVarName = new QPushButton("Show&VarName", this); + + // fill collection view + for (int i=0; isetText(fCollList[i].fCollName); + fCollectionView->addItem(newItem); + } + fCollectionView->setCurrentRow(0, QItemSelectionModel::Select); + fCollectionView->setSelectionMode(QAbstractItemView::ExtendedSelection); + + QHBoxLayout *hLayout0 = new QHBoxLayout; + hLayout0->addWidget(fShowVarName); + hLayout0->addWidget(fHelp); + + QHBoxLayout *hLayout1 = new QHBoxLayout; + hLayout1->addWidget(fCancel); + hLayout1->addWidget(fCheck); + hLayout1->addWidget(fAdd); + + QLabel *varLabel = new QLabel("Edit Variables:"); + QVBoxLayout *varVLayout = new QVBoxLayout; + varVLayout->addWidget(varLabel); + varVLayout->addWidget(fVarEdit); + + QLabel *collLabel = new QLabel("Collections:"); + QVBoxLayout *collVLayout = new QVBoxLayout; + collVLayout->addWidget(collLabel); + collVLayout->addWidget(fCollectionView); + + QWidget *varWidget = new QWidget(this); // only needed since splitter needs a QWidget + varWidget->setLayout(varVLayout); + QWidget *collWidget = new QWidget(this); // only needed since splitter needs a QWidget + collWidget->setLayout(collVLayout); + + QSplitter *splitter = new QSplitter(Qt::Vertical, this); + splitter->addWidget(varWidget); + splitter->addWidget(collWidget); + + QVBoxLayout *vLayout = new QVBoxLayout; + vLayout->addWidget(splitter); + vLayout->addLayout(hLayout0); + vLayout->addLayout(hLayout1); + + fVarEdit->resize(600, 300); + setLayout(vLayout); + resize(600, 450); + + connect(fCancel, SIGNAL( clicked() ), this, SLOT( reject() )); + connect(fCheck, SIGNAL( clicked() ), this, SLOT( check() )); + connect(fAdd, SIGNAL( clicked() ), this, SLOT( add() )); + connect(fHelp, SIGNAL( clicked() ), this, SLOT( help() )); + connect(fShowVarName, SIGNAL( clicked() ), this, SLOT( showVarNames() )); + + QString iconName(""); + if (darkTheme) + iconName = QString(":/icons/varEdit-dark.svg"); + else + iconName = QString(":/icons/varEdit-plain.svg"); + setWindowIcon( QIcon( QPixmap(iconName) ) ); +} + +//-------------------------------------------------------------------------- +/** + * @brief PVarDialog::check. Allows the user to check the variable string. + */ +void PVarDialog::check() +{ + if (!basic_check()) + return; + + if (!var_consistency_check()) + return; + + // create the collection index vector + QVector idx; + QList selected = fCollectionView->selectedItems(); + for (int i=0; irow(selected[i])); + } + emit check_request(fVarEdit->toPlainText(), idx); +} + +//-------------------------------------------------------------------------- +/** + * @brief PVarDialog::add. It is used to initiate the add variable to the mupp GUI. + */ +void PVarDialog::add() +{ + if (fVarEdit->toPlainText().isEmpty()) { + QMessageBox::critical(this, "**ERROR**", "No input available."); + return; + } + if (fCollectionView->selectedItems().count() == 0) { + QMessageBox::critical(this, "**ERROR**", "One or more collection(s) need to linked to the variable(s)."); + return; + } + + if (!basic_check()) + return; + + if (!var_consistency_check()) + return; + + // create the collection index vector + QVector idx; + QList selected = fCollectionView->selectedItems(); + for (int i=0; irow(selected[i])); + } + + emit add_request(fVarEdit->toPlainText(), idx); +} + +//-------------------------------------------------------------------------- +/** + * @brief PVarDialog::help + */ +void PVarDialog::help() +{ + QMessageBox::information(this, "Var Help", + "Syntax: var = .\n"\ + " can contain identifiers defined in the collections.\n"\ + "An identifier is an addressed variable which is defined\n"\ + "by a preceeding '$' before the variable name.\n"\ + "Example: variable sigma -> identifier $sigma.\n"\ + "Example:\nvar sigSC = pow(abs(pow($sigma,2.0)-pow(0.11,2.0)),0.5)"); +} + +//-------------------------------------------------------------------------- +/** + * @brief PVarDialog::showVarNames. Show a variable name dialog for a given + * selected collection. + */ +void PVarDialog::showVarNames() +{ + // get the selected collection + if (fCollectionView->selectedItems().count() == 0) { + QMessageBox::critical(this, "**ERROR**", "At least one collection needs to be selected."); + return; + } + if (fCollectionView->selectedItems().count() > 1) { + QMessageBox::critical(this, "**ERROR**", "Currently only the vars of a single collection can be shown."); + return; + } + int idx = fCollectionView->currentRow(); + + if (idx >= fCollList.count()) { + QMessageBox::critical(this, "**ERROR**", QString("Collection idx=%1 > #Collections=%2. This never should have happened.").arg(idx).arg(fCollList.count())); + return; + } + + PCollInfo info = fCollList[idx]; + + PShowVarNameDialog *dialog = new PShowVarNameDialog(info); + dialog->show(); +} + +//-------------------------------------------------------------------------- +/** + * @brief PVarDialog::basic_check. Carry out basic checks before feeding it + * to the parser. + * @return true on success + */ +bool PVarDialog::basic_check() +{ + QString varStr = fVarEdit->toPlainText(); + bool ok; + + if (varStr.isEmpty()) { + QMessageBox::critical(this, "**ERROR**", "No input available."); + return false; + } + if (fCollectionView->selectedItems().count() == 0) { + QMessageBox::critical(this, "**ERROR**", "One or more collection(s) need to linked to the variable(s)."); + return false; + } + + // tokenize variable input + QStringList strList = varStr.split(QRegularExpression("\\s+"), Qt::SkipEmptyParts); + + // check if there are ANY var definitions + ok = false; + for (int i=0; iNO 'var' definition found."); + return false; + } + + // check that for each variable, there is also an Err variable present + QStringList varNames = collectVarNames(strList, ok); + if (!ok) { + QMessageBox::critical(this, "**ERROR**", "found 'var' without ."); + return false; + } + QString name(""); + if (!hasErrorDef(varNames, name)) { + QMessageBox::critical(this, "**ERROR**", QString("found <var_name>=%1 without corresponding %1Err.
Both, a variable and its corresponding error variable needs to be defined.").arg(name)); + return false; + } + + return true; +} + +//-------------------------------------------------------------------------- +/** + * @brief PVarDialog::var_consistency_check. Variable consistency checks. For + * instance it is checked that for each variable there is also the corresponding + * error variable defined. + * @return true on success + */ +bool PVarDialog::var_consistency_check() +{ + QString varStr = fVarEdit->toPlainText(); + + // collect all identifiers + int idx = 0, idxEnd = 0; + QStringList varNames; + QVector isIdendifier; + char ch; + bool done; + do { + idx = varStr.indexOf("$", idx); + if (idx > -1) { // found identifier + idxEnd = idx+1; + done = false; + do { + ch = varStr[idxEnd].toLatin1(); + if (isalnum(ch) || (ch == '_')) + idxEnd++; + else + done = true; + } while (!done && (idxEnd <= varStr.length())); + varNames << varStr.mid(idx+1, idxEnd-idx-1); + isIdendifier.push_back(1); + idx++; + } + } while (idx != -1); + + // collect all the variable names + idx = 0; + do { + idx = varStr.indexOf("var ", idx); + if (idx > -1) { // found variable + idxEnd = varStr.indexOf("=", idx); + if (idxEnd == -1) { + return false; + } + varNames << varStr.mid(idx+4, idxEnd-idx-5); + isIdendifier.push_back(0); + idx++; + } + } while (idx != -1); + + // make sure that identifier is found in collection if it is not a variable + bool isVar = false; + bool found = false; + QString str; + QList selColl = fCollectionView->selectedItems(); + for (int i=0; irow(selColl[j]); + found = false; + for (int k=0; k= list.count()) { + ok = false; + } else { + name << list[i+1]; + i++; + } + } + } + + return name; +} + +//-------------------------------------------------------------------------- +/** + * @brief PVarDialog::hasErrorDef. Check for error definition + * @param varNames variable name list + * @param name failed variable name + * @return true on success + */ +bool PVarDialog::hasErrorDef(QStringList &varNames, QString &name) +{ + QString errStr; + for (int i=0; i +#include +#include +#include +#include + +//----------------------------------------------------------------------------- +/** + * @brief The PCollInfo struct + */ +struct PCollInfo +{ + QString fCollName; ///< collection name + QStringList fVarName; ///< variable names of the given collection +}; + +//----------------------------------------------------------------------------- +/** + * @brief The PShowVarNameDialog class. Class used to create a show variable + * name dialog. + */ +class PShowVarNameDialog : public QDialog +{ + Q_OBJECT + + public: + PShowVarNameDialog(PCollInfo &info); +}; + +//----------------------------------------------------------------------------- +/** + * @brief The PVarDialog class + */ +class PVarDialog : public QDialog +{ + Q_OBJECT + + public: + PVarDialog(QVector collection_list, bool darkTheme, + QWidget *parent = nullptr, + Qt::WindowFlags f = Qt::WindowFlags()); + + private: + QPlainTextEdit *fVarEdit; + QListWidget *fCollectionView; + QPushButton *fCancel; + QPushButton *fAdd; + QPushButton *fCheck; + QPushButton *fHelp; + QPushButton *fShowVarName; + + QVector fCollList; + + bool basic_check(); + bool var_consistency_check(); + QStringList collectVarNames(QStringList &list, bool& ok); + bool hasErrorDef(QStringList &varNames, QString& name); + + private slots: + void check(); + void add(); + void help(); + void showVarNames(); + + signals: + void check_request(QString varStr, QVector idx); + void add_request(QString varStr, QVector idx); +}; + +#endif // _PVARDIALOG_H_ diff --git a/src/musredit_qt6/mupp/Pmupp.cpp b/src/musredit_qt6/mupp/Pmupp.cpp new file mode 100644 index 00000000..dda003bc --- /dev/null +++ b/src/musredit_qt6/mupp/Pmupp.cpp @@ -0,0 +1,1044 @@ +/*************************************************************************** + + Pmupp.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 "Pmupp.h" + +#define PMUPP_UNDEF -1 +#define PMUPP_VALUE 0 +#define PMUPP_POSNEGERR 1 +#define PMUPP_POSERR 2 +#define PMUPP_NEGERR 3 +#define PMUPP_RUN 4 + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/** + * @brief PmuppParam::PmuppParam. Ctor + */ +PmuppParam::PmuppParam() { + ResetParam(); +} + +//-------------------------------------------------------------------------- +/** + * @brief PmuppParam::PmuppParam. Ctor + * @param name parameter name + * @param param parameter value + * @param posErr parameter error + */ +PmuppParam::PmuppParam(QString name, double param, double posErr) +{ + SetParam(name, param, posErr); +} + +//-------------------------------------------------------------------------- +/** + * @brief PmuppParam::PmuppParam. Ctor + * @param name parameter name + * @param param parameter value + * @param posErr positive parameter error + * @param negErr negative parameter error + */ +PmuppParam::PmuppParam(QString name, double param, double posErr, double negErr) +{ + SetParam(name, param, posErr, negErr); +} + +//-------------------------------------------------------------------------- +/** + * @brief PmuppParam::ResetParam. Reset the parameter values + */ +void PmuppParam::ResetParam() +{ + fName = ""; + fValue = MUPP_UNDEF; + fPosErr = MUPP_UNDEF; + fNegErr = MUPP_UNDEF; +} + +//-------------------------------------------------------------------------- +/** + * @brief PmuppParam::SetParam. Set a parameter + * @param name parameter name + * @param param parameter value + * @param posErr parameter error + */ +void PmuppParam::SetParam(QString name, double param, double posErr) +{ + fName = name; + fValue = param; + fPosErr = posErr; +} + +//-------------------------------------------------------------------------- +/** + * @brief PmuppParam::SetParam. Set a parameter + * @param name parameter name + * @param param parameter value + * @param posErr positive parameter value + * @param negErr negative parameter value + */ +void PmuppParam::SetParam(QString name, double param, double posErr, double negErr) +{ + fName = name; + fValue = param; + fPosErr = posErr; + fNegErr = negErr; +} + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/** + * @brief PmuppRun::GetParam. Get a parameter from a run + * @param idx index of the parameter + * @return the parameter value + */ +PmuppParam PmuppRun::GetParam(unsigned int idx) +{ + PmuppParam param; + + if (idx < (unsigned int)fParam.size()) + param = fParam[idx]; + + return param; +} + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/** + * @brief PmuppCollection::GetRun. Returns a run from a collection. + * @param idx of the run in a collection + * @return a run from a collection + */ +PmuppRun PmuppCollection::GetRun(unsigned int idx) +{ + PmuppRun run; + + if (idx < (unsigned int)fRun.size()) + run = fRun[idx]; + + return run; +} + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/** + * @brief PParamDataHandler::NewCollection. Adds an empty new collection with + * name 'name'. + * @param name of the new collection + */ +void PParamDataHandler::NewCollection(const QString name) +{ + PmuppCollection collection; + collection.SetName(name); + + fCollection.push_back(collection); +} + +//-------------------------------------------------------------------------- +/** + * @brief PParamDataHandler::analyzeFileList. In case the input is given by + * msr-files, the structure of the file names needs to be analyzed that + * msr2data can be called. + * + * @param fln list of msr-files to be analyzed. + * @param collectionName output collection name (db-/dat-file). + * @param arg argument list which is needed to feed msr2data + * @param workDir working directory + * @param errorMsg error message in case something went wrong. + * + * @return true if successful, false otherwise + */ +bool PParamDataHandler::analyzeFileList(const QStringList &fln, QString &collectionName, + QStringList &arg, QString &workDir, QString &errorMsg) +{ + // 1) check all the msr-files have the same structure: .msr with the same + // for all msr-files present. + QString ext(""); + QStringList run; + + QStringList tok; + int pos0=-1, pos1=-1; + QString flnCurrent(""), extCurrent(""), runStr(""); + bool ok; + + pos0 = fln[0].lastIndexOf("/"); + workDir = fln[0].left(pos0); + + for (int i=0; i and + pos0 = flnCurrent.indexOf("_"); + if (pos0 == -1) { + errorMsg = "msr-file name has a structure which cannot be handled.\n\ + It should be , where is the run number\n\ + and needs to start with a '_'."; + return false; + } + pos1 = flnCurrent.lastIndexOf("."); + if ((pos1 == -1) || (pos1 < pos0)) { + errorMsg = "msr-file name has a structure which cannot be handled.\n\ + It should be .msr, where is the run number\n\ + and needs to start with a '_'."; + return false; + } + + // get run number + runStr = flnCurrent.left(pos0); + runStr.toInt(&ok); // output not needed, only check that it is a number + if (!ok) { + errorMsg = QString("Found run number string '%1' which is not a number.").arg(runStr); + return false; + } + run << runStr; + + // keep extension + if (i == 0) + ext = flnCurrent.mid(pos0, pos1-pos0); + else + extCurrent = flnCurrent.mid(pos0, pos1-pos0); + + // make sure all extensions are identical + if ((i>0) && (ext != extCurrent)) { + errorMsg = "Currently mixed msr-file extensions cannot be handled."; + return false; + } + } + + arg << "["; + for (int i=0; isetProcessEnvironment(env); + fProc->setWorkingDirectory(workDir); + fProc->start(cmd, arg); + if (!fProc->waitForFinished()) { + errorMsg = QString(tr("Could not execute the output command: ")+cmd[0]); + return false; + } + + // since the db-file should now be present, just load it + collection = ReadDbFile(pathName, valid, errorMsg); + if (!valid) { + std::cerr << std::endl; + std::cerr << "----" << std::endl; + std::cerr << "**ERROR** read db-file failure (" << pathName.toLatin1().data() << "." << std::endl; + std::cerr << "----" << std::endl; + return false; + } + collName.remove(".db"); + collection.SetPathName(pathName); + collection.SetName(collName); + fCollection.push_back(collection); + } else { // db-, dat-file list + for (int i=0; i 0) { + if (collection.GetRun(0).GetNoOfParam() != run.GetNoOfParam()) { + errorMsg = fln + QString(".\n"); + errorMsg += QString(" first run (#%1) has %2 params.\n").arg(collection.GetRun(0).GetNumber()).arg(collection.GetRun(0).GetNoOfParam()); + errorMsg += QString(" current run (#%1) has %2 params.\n").arg(run.GetNumber()).arg(run.GetNoOfParam()); + errorMsg += QString(" Inspect your db-file!"); + std::cerr << std::endl; + std::cerr << "----" << std::endl; + std::cerr << "**ERROR** in " << errorMsg.toLatin1().data() << std::endl; + std::cerr << "----" << std::endl; + file.close(); + valid = false; + return collection; + } + } + collection.AddRun(run); + run.Clear(); + } else { // parameter + if (token.size() != 4) { // wrong number of parameter tokens + std::cerr << std::endl; + std::cerr << "----" << std::endl; + std::cerr << "**ERROR** in" << fln.toLatin1().data() <<". # parameter tokens != 4." << std::endl; + std::cerr << "----" << std::endl; + file.close(); + valid = false; + return collection; + } + subTok = token[0].split("="); + if (subTok.size() != 2) { + std::cerr << std::endl; + std::cerr << "----" << std::endl; + std::cerr << "**ERROR** in" << fln.toLatin1().data() <<". parameter name=value token missing." << std::endl; + std::cerr << "----" << std::endl; + file.close(); + valid = false; + return collection; + } + QString paramName = subTok[0].trimmed(); + param.ResetParam(); + param.SetName(paramName); + dval = subTok[1].toDouble(&ok); + if (ok) { + param.SetValue(dval); + } else { + std::cerr << std::endl; + std::cerr << "----" << std::endl; + std::cerr << "**ERROR** in" << fln.toLatin1().data() <<". parameter name=value token missing or wrong?!" << std::endl; + std::cerr << "----" << std::endl; + file.close(); + valid = false; + return collection; + } + // pos. err + dval = token[1].toDouble(&ok); + if (ok) { + param.SetPosErr(dval); + } else { + std::cerr << std::endl; + std::cerr << "----" << std::endl; + std::cerr << "**ERROR** in" << fln.toLatin1().data() <<". parameter pos. error not a number?!" << std::endl; + std::cerr << "----" << std::endl; + file.close(); + valid = false; + return collection; + } + // neg. err + dval = token[2].toDouble(&ok); + if (ok) { + param.SetNegErr(dval); + } else { + std::cerr << std::endl; + std::cerr << "----" << std::endl; + std::cerr << "**ERROR** in" << fln.toLatin1().data() <<". parameter neg. error not a number?!" << std::endl; + std::cerr << "----" << std::endl; + file.close(); + valid = false; + return collection; + } + run.AddParam(param); + } + } + } + if (!param_found) { + std::cerr << std::endl; + std::cerr << "----" << std::endl; + std::cerr << "**ERROR** in" << fln.toLatin1().data() <<". No parameter found." << std::endl; + std::cerr << "----" << std::endl; + } + file.close(); + + valid = true; + + return collection; +} + +//-------------------------------------------------------------------------- +/** + * @brief PParamDataHandler::ReadColumnParamFile. Reads a dat-file + * @param fln file name of the dat-file to be read + * @param valid true on success, false otherwise. + * @param errorMsg error message in case read fails. + * + * @return the collection object containing the dat-file on success. + */ +PmuppCollection PParamDataHandler::ReadColumnParamFile(const QString fln, bool &valid, QString &errorMsg) +{ + PmuppCollection collection; + PmuppRun run; + valid = true; + + QFile file(fln); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + errorMsg = QString("couldn't open ")+fln; + std::cerr << std::endl; + std::cerr << "----" << std::endl; + std::cerr << "**ERROR** " << errorMsg.toLatin1().data() << std::endl; + std::cerr << "----" << std::endl; + valid = false; + return collection; + } + + QTextStream in(&file); + QString line; + QStringList token; + bool done = false, ok; + double dval = 0; + int ival; + PmuppParam param; + run.SetName(fln); + + // read header information + line = in.readLine(); + token = line.split(QRegularExpression("\\s+"), Qt::SkipEmptyParts); + + QVector headerInfo; + QVector headerCode; // 0=value, 1=pos/neg err, 2=pos err, 3=neg err, 4=run number + int code=PMUPP_UNDEF; + for (int i=0; i=fCollection.size())) { + valid = false; + return collection; + } + + return fCollection[idx]; +} + +//-------------------------------------------------------------------------- +/** + * @brief PParamDataHandler::GetCollection. Get a pointer of the requested + * collection. + * @param idx of the collection + * + * @return requested pointer to the collection on success. + */ +PmuppCollection *PParamDataHandler::GetCollection(const int idx) +{ + if ((idx<0) || (idx>=fCollection.size())) { + return nullptr; + } + + return &fCollection[idx]; +} + +//-------------------------------------------------------------------------- +/** + * @brief PParamDataHandler::GetCollection. Get collection by name. + * @param name of the requested collection + * @param valid true if found + * + * @return requested collection on success. + */ +PmuppCollection PParamDataHandler::GetCollection(const QString name, bool &valid) +{ + valid = true; + PmuppCollection collection; + + int idx=-1; + for (int i=0; i= 0) && (idx < fCollection.size())) + name = fCollection[idx].GetName(); + + return name; +} + +//-------------------------------------------------------------------------- +/** + * @brief PParamDataHandler::GetValues. Get the data values of a parameter of + * a requested collection. + * @param collName name of the collection + * @param paramName parameter name + * + * @return data values of the requested parameter name of the collection collName. + * Empty data vector otherwise. + */ +QVector PParamDataHandler::GetValues(QString collName, QString paramName) +{ + QVector data; + + // find collection with correct name + int idx=-1; + for (int i=0; i PParamDataHandler::GetPosErr(QString collName, QString paramName) +{ + QVector data; + + // find collection with correct name + int idx=-1; + for (int i=0; i PParamDataHandler::GetNegErr(QString collName, QString paramName) +{ + QVector data; + + // find collection with correct name + int idx=-1; + for (int i=0; i= fCollection.size()) + return; + + fCollection.replace(idx, coll); +} + +//-------------------------------------------------------------------------- +/** + * @brief PParamDataHandler::Dump. Dumps the collection onto stdout + */ +void PParamDataHandler::Dump() +{ + PmuppRun run; + PmuppParam param; + + for (int i=0; i +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-" << std::endl; + std::cout << "debug> collection name: " << fCollection[i].GetName().toLatin1().data() << std::endl; + std::cout << "debug> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-" << std::endl; + for (int j=0; j ----------------------------------" << std::endl; + run = fCollection[i].GetRun(j); + std::cout << "debug>> run number: " << run.GetNumber() << std::endl; + std::cout << "debug>> run name : " << run.GetName().toLatin1().data() << std::endl; + std::cout << "debug>> ---------------------------------" << std::endl; + for (int k=0; k>> " << param.GetName().toLatin1().data() << ": " << param.GetValue() << " -+ " << param.GetNegErr() << " / " << param.GetPosErr() << std::endl; + } + } + } +} + +//-------------------------------------------------------------------------- +/** + * @brief PParamDataHandler::readFromStdOut + */ +void PParamDataHandler::readFromStdOut() +{ + qInfo() << fProc->readAllStandardOutput(); +} + +//-------------------------------------------------------------------------- +/** + * @brief PParamDataHandler::readFromStdErr + */ +void PParamDataHandler::readFromStdErr() +{ + qInfo() << fProc->readAllStandardError(); +} + +//-------------------------------------------------------------------------- +/** + * @brief PParamDataHandler::processDone + * @param exitCode + * @param exitStatus + */ +void PParamDataHandler::processDone(int exitCode, QProcess::ExitStatus exitStatus) +{ + qInfo() << "in processDone()"; + if ((exitStatus == QProcess::CrashExit) && (exitCode != 0)) { + qInfo() << "**ERROR** processDone: exitCode = " << exitCode << Qt::endl; + } +} diff --git a/src/musredit_qt6/mupp/Pmupp.h b/src/musredit_qt6/mupp/Pmupp.h new file mode 100644 index 00000000..69a9efcf --- /dev/null +++ b/src/musredit_qt6/mupp/Pmupp.h @@ -0,0 +1,171 @@ +/*************************************************************************** + + Pmupp.h + + 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. * + ***************************************************************************/ + +#ifndef _PMUPP_H_ +#define _PMUPP_H_ + +#include +#include +#include +#include +#include + +#define MUPP_UNDEF 1.0e99 + +//---------------------------------------------------------------------------- +/** + *

The PmuppParam class. It handles a single parameter: name, value, + * positive- and negative error. + */ +class PmuppParam { + public: + PmuppParam(); + PmuppParam(QString name, double param, double posErr); + PmuppParam(QString name, double param, double posErr, double negErr); + + void ResetParam(); + void SetParam(QString name, double param, double posErr); + void SetParam(QString name, double param, double posErr, double negErr); + void SetName(QString name) { fName = name; } + void SetValue(double dval) { fValue = dval; } + void SetPosErr(double dval) { fPosErr = dval; } + void SetNegErr(double dval) { fNegErr = dval; } + + QString GetName() { return fName; } + double GetValue() { return fValue; } + double GetPosErr() { return fPosErr; } + double GetNegErr() { return fNegErr; } + + private: + QString fName; ///< parameter name + double fValue; ///< parameter value + double fPosErr; ///< positive error of the parameter + double fNegErr; ///< negative error of the parameter +}; + +//---------------------------------------------------------------------------- +/** + *

The PmuppRun class. Contains all the parameters of a single run. + */ +class PmuppRun { + public: + PmuppRun() { fNumber = -1; fName=""; fParam.clear(); } + ~PmuppRun() { fNumber = -1; fName=""; fParam.clear(); } + + void Clear() { fNumber = -1; fName=""; fParam.clear(); } + void SetName(QString name) { fName = name; } + void SetNumber(int ival) { fNumber = ival; } + void AddParam(PmuppParam param) { fParam.push_back(param); } + + int GetNumber() { return fNumber; } + QString GetName() { return fName; } + int GetNoOfParam() { return fParam.size(); } + PmuppParam GetParam(unsigned int idx); + + private: + int fNumber; ///< run number + QString fName; ///< name of the run + QVector fParam; ///< parameters of the run +}; + +//---------------------------------------------------------------------------- +/** + *

The PmuppCollection class. Is collecting a number of runs. Typically + * something like a full temperature scan, an energy scan, etc. + */ +class PmuppCollection { + public: + PmuppCollection() { fPathName=""; fName = ""; fRun.clear(); } + + void SetPathName(QString pathName) { fPathName = pathName; } + void SetName (QString name) { fName = name; } + void AddRun(PmuppRun run) { fRun.push_back(run); } + + QString GetPathName() { return fPathName; } + QString GetName() { return fName; } + int GetNoOfRuns() { return fRun.size(); } + PmuppRun GetRun(unsigned int idx); + + private: + QString fPathName; ///< path-name of the collection + QString fName; ///< name of the collection + QVector fRun; ///< all the runs in the collection +}; + +//---------------------------------------------------------------------------- +/** + *

The PParamDataHandler class. This class handles all the collections + * loaded. + */ +class PParamDataHandler : public QObject { + Q_OBJECT + + public: + PParamDataHandler() {} + + int GetNoOfCollections() { return fCollection.size(); } + void NewCollection(const QString name); + + bool ReadParamFile(const QStringList fln, QString &errorMsg); + PmuppCollection ReadDbFile(const QString fln, bool &valid, QString &errorMsg); + PmuppCollection ReadColumnParamFile(const QString fln, bool &valid, QString &errorMsg); + + PmuppCollection GetCollection(const int idx, bool &valid); + PmuppCollection GetCollection(const QString name, bool &valid); + PmuppCollection *GetCollection(const int idx); + PmuppCollection *GetCollection(const QString name); + int GetCollectionIndex(const QString name); + QString GetCollectionName(const int idx); + + QVector GetValues(QString collName, QString paramName); + QVector GetPosErr(QString collName, QString paramName); + QVector GetNegErr(QString collName, QString paramName); + + void RemoveCollection(QString name); + void ReplaceCollection(PmuppCollection coll, int idx); + + void Dump(); + + signals: + void newData(); + + private: + QProcess *fProc; ///< this will be needed if msr2data needs to be called + QVector fCollection; ///< all the collections handeled + + bool analyzeFileList(const QStringList &fln, QString &collectionName, + QStringList &arg, QString &workDir, QString &errorMsg); + + private slots: + void readFromStdOut(); + void readFromStdErr(); + void processDone(int, QProcess::ExitStatus); +}; + +#endif // _PMUPP_H_ diff --git a/src/musredit_qt6/mupp/PmuppAdmin.cpp b/src/musredit_qt6/mupp/PmuppAdmin.cpp new file mode 100644 index 00000000..76dcbdfb --- /dev/null +++ b/src/musredit_qt6/mupp/PmuppAdmin.cpp @@ -0,0 +1,605 @@ +/**************************************************************************** + + PmuppAdmin.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2010-2017 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 "PmuppAdmin.h" + +//-------------------------------------------------------------------------- +// implementation of PmuppColor class +//-------------------------------------------------------------------------- +/** + * @brief PmuppColor::PmuppColor. Ctor + */ +PmuppColor::PmuppColor() +{ + fName = "UnDef"; + fRed = -1; + fGreen = -1; + fBlue = -1; +} + +//-------------------------------------------------------------------------- +/** + * @brief PmuppColor::setRGB. set RGB value + * @param r red (0..255) + * @param g green (0..255) + * @param b blue (0..255) + */ +void PmuppColor::setRGB(const int r, const int g, const int b) +{ + if ((r>=0) && (r<=255)) + fRed = r; + if ((g>=0) && (g<=255)) + fGreen = g; + if ((b>=0) && (b<=255)) + fBlue = b; +} + +//-------------------------------------------------------------------------- +// implementation of PmuppAdminXMLParser class +//-------------------------------------------------------------------------- +/** + *

XML Parser class for the mupp administration file. + * + * \param admin pointer to an admin class instance. + */ +PmuppAdminXMLParser::PmuppAdminXMLParser(const QString& fln, PmuppAdmin *admin) : fAdmin(admin) +{ + fValid = false; + fKeyWord = eEmpty; + + QFile file(fln); + if (!file.open(QFile::ReadOnly | QFile::Text)) { + // warning and create default - STILL MISSING + } + + fValid = parse(&file); +} + +//-------------------------------------------------------------------------- +/** + *

parse the mupp startup xml-file. + * + * \param device QFile object of the mupp startup xml-file + * + * @return true on success, false otherwise + */ +bool PmuppAdminXMLParser::parse(QIODevice *device) +{ + fXml.setDevice(device); + + bool expectChars = false; + while (!fXml.atEnd()) { + fXml.readNext(); + if (fXml.isStartDocument()) { + startDocument(); + } else if (fXml.isStartElement()) { + startElement(); + expectChars = true; + } else if (fXml.isCharacters() && expectChars) { + characters(); + } else if (fXml.isEndElement()) { + endElement(); + expectChars = false; + } else if (fXml.isEndDocument()) { + endDocument(); + } + } + if (fXml.hasError()) { + QString msg; + msg = QString("%1 Line %2, column %3").arg(fXml.errorString()).arg(fXml.lineNumber()).arg(fXml.columnNumber()); + QMessageBox::critical(0, "**ERROR**", msg, QMessageBox::Ok, QMessageBox::NoButton); + return false; + } + + return true; +} + +//-------------------------------------------------------------------------- +/** + *

Routine called at the beginning of the XML parsing process. + */ +bool PmuppAdminXMLParser::startDocument() +{ + // nothing to be done here for now + return true; +} + +//-------------------------------------------------------------------------- +/** + *

Routine called when a new XML tag is found. Here it is used + * to set a tag for filtering afterwards the content. + */ +bool PmuppAdminXMLParser::startElement() +{ + QString qName = fXml.name().toString(); + + if (qName == "path_file_name") { + fKeyWord = eRecentFile; + } else if (qName == "dark_theme") { + fKeyWord = eDarkTheme; + } else if (qName == "marker") { + fKeyWord = eMarker; + } else if (qName == "color") { + fKeyWord = eColor; + } + + return true; +} + +//-------------------------------------------------------------------------- +/** + *

Routine called when the end XML tag is found. It is used to + * put the filtering tag to 'empty'. It also resets the fFunc flag in case + * the entry was a theory function. + */ +bool PmuppAdminXMLParser::endElement() +{ + fKeyWord = eEmpty; + + return true; +} + +//-------------------------------------------------------------------------- +/** + *

This routine delivers the content of an XML tag. It fills the + * content into the load data structure. + */ +bool PmuppAdminXMLParser::characters() +{ + QString str = fXml.text().toString(); + if (str.isEmpty()) + return true; + + bool ok; + int ival, r, g, b; + double dval; + QString name(""); + QStringList tok; + + switch (fKeyWord) { + case eRecentFile: + fAdmin->addRecentFile(QString(str.toLatin1()).trimmed()); + break; + case eDarkTheme: + if ((str == "yes") || (str == "1") || (str == "true")) + fAdmin->setTheme(true); + else + fAdmin->setTheme(false); + break; + case eMarker: + tok = str.split(",", Qt::SkipEmptyParts); + + if ((tok.count() != 1) && (tok.count() != 2)) { + return false; + } + + ival = tok[0].toInt(&ok); + if (!ok) + return false; + + dval = 1.0; + if (tok.count() == 2) { + dval = tok[1].toDouble(&ok); + if (!ok) + return false; + } + fAdmin->setMarker(ival, dval); + break; + case eColor: + tok = str.split(",", Qt::SkipEmptyParts); + + if ((tok.count() != 3) && (tok.count() != 4)) { + return false; + } + ival = tok[0].toInt(&ok); + if (!ok) + return false; + r = ival; + ival = tok[1].toInt(&ok); + if (!ok) + return false; + g = ival; + ival = tok[2].toInt(&ok); + if (!ok) + return false; + b = ival; + if (tok.count() == 4) + name = tok[3]; + fAdmin->setColor(r, g, b, name); + break; + default: + break; + } + + return true; +} + +//-------------------------------------------------------------------------- +/** + *

Called at the end of the XML parse process. It checks if default paths + * contain system variables, and if so expand them for the further use. + */ +bool PmuppAdminXMLParser::endDocument() +{ + return true; +} + +//-------------------------------------------------------------------------- +// implementation of PmuppAdmin class +//-------------------------------------------------------------------------- +/** + *

Initializes that PmuppAdmin object, and calls the XML parser which feeds + * the object variables. + */ +PmuppAdmin::PmuppAdmin() : QObject(), fDarkTheme(false) +{ + // XML Parser part + // 1st: check local directory + QString path = QString("./"); + QString fln = QString("mupp_startup.xml"); + QString pathFln = path + fln; + QProcessEnvironment procEnv = QProcessEnvironment::systemEnvironment(); + if (!QFile::exists(pathFln)) { + // 2nd: check $HOME/.musrfit/mupp/mupp_startup.xml + path = procEnv.value("HOME", ""); + pathFln = path + "/.musrfit/mupp/" + fln; + if (!QFile::exists(pathFln)) { + // 3rd: check $MUSRFITPATH/mupp_startup.xml + path = procEnv.value("MUSRFITPATH", ""); + pathFln = path + "/" + fln; + if (!QFile::exists(pathFln)) { + // 4th: check $ROOTSYS/bin/mupp_startup.xml + path = procEnv.value("ROOTSYS", ""); + pathFln = path + "/bin/" + fln; + if (!QFile::exists(pathFln)) { + // 5th: not found anywhere hence create it + path = procEnv.value("HOME", ""); + pathFln = path + "/.musrfit/mupp/" + fln; + createMuppStartupFile(); + } + } + } + } + + if (QFile::exists(pathFln)) { // administration file present + PmuppAdminXMLParser handler(pathFln, this); + if (!handler.isValid()) { + QMessageBox::critical(0, "**ERROR**", + "Error parsing mupp_startup.xml settings file.\nProbably a few things will not work porperly.\nPlease fix this first.", + QMessageBox::Ok, QMessageBox::NoButton); + return; + } + } else { + QMessageBox::critical(0, "**ERROR**", + "Couldn't find the mupp_startup.xml settings file.\nProbably a few things will not work porperly.\nPlease fix this first.", + QMessageBox::Ok, QMessageBox::NoButton); + return; + } +} + +//-------------------------------------------------------------------------- +/** + *

Destructor + */ +PmuppAdmin::~PmuppAdmin() +{ + saveRecentFiles(); +} + +//-------------------------------------------------------------------------- +/** + *

Add recent path-file name to the internal ring-buffer. + * + * \param str recent path-file name to be added + */ +void PmuppAdmin::addRecentFile(const QString str) +{ + // check if file name is not already present + for (int i=0; i MAX_RECENT_FILES) + fRecentFile.resize(MAX_RECENT_FILES); +} + +//-------------------------------------------------------------------------- +/** + * @brief PmuppAdmin::getRecentFile. Get a file from the recent files with + * index idx. + * @param idx + * + * @return return the recent file with index idx if present, otherwise return + * an empty string. + */ +QString PmuppAdmin::getRecentFile(int idx) +{ + QString str(""); + + if ((idx >= 0) && (idx < fRecentFile.size())) + str = fRecentFile[idx]; + + return str; +} + +//-------------------------------------------------------------------------- +/** + * @brief PmuppAdmin::getMarker. Get the marker with index idx. + * @param idx marker index + * + * @return requested marker + */ +PmuppMarker PmuppAdmin::getMarker(int idx) { + PmuppMarker marker; + + if (idx >= fMarker.size()) + return marker; + + return fMarker[idx]; +} + +//-------------------------------------------------------------------------- +/** + * @brief PmuppAdmin::getColor. Get rgb color codes of name + * @param name of the requeset color. + * @param r red value (0..255) + * @param g green value (0..255) + * @param b blue value (0..255 + */ +void PmuppAdmin::getColor(QString name, int &r, int &g, int &b) +{ + int idx=-1; + for (int i=0; ifColor.size())) { + r = -1; + g = -1; + b = -1; + } else { + fColor[idx].getRGB(r, g, b); + } +} + +//-------------------------------------------------------------------------- +/** + * @brief PmuppAdmin::setMaker. Set a marker + * @param marker marker code + * @param size marker size + */ +void PmuppAdmin::setMarker(int marker, double size) +{ + PmuppMarker markerObj; + + // make sure marker is in proper range + if ((marker<1) || (marker>49)) { + QMessageBox::warning(0, "WARNING", QString("Found Marker (%1) not in the expected range.\nWill ignore it.").arg(marker)); + return; + } + markerObj.setMarker(marker); + markerObj.setMarkerSize(size); + + fMarker.push_back(markerObj); +} + +//-------------------------------------------------------------------------- +/** + * @brief PmuppAdmin::setColor. Set a color + * @param r red value (0..255) + * @param g green value (0..255) + * @param b blue value (0..255) + * @param name color name + */ +void PmuppAdmin::setColor(int r, int g, int b, QString name) +{ + if (((r<0) || (r>255)) || + ((g<0) || (g>255)) || + ((b<0) || (b>255))) { + QMessageBox::warning(0, "WARNING", QString("Found Color (%1,%2,%3) not in the expected range.\nWill ignore it.").arg(r).arg(g).arg(b)); + return; + } + + PmuppColor color; + color.setName(name); + color.setRGB(r,g,b); + + fColor.push_back(color); +} + +//-------------------------------------------------------------------------- +/** + *

Merges the recent file ring buffer into mupp_startup.xml and saves it. + * If a local copy is present it will be saved there, otherwise the master file + * will be used. + */ +void PmuppAdmin::saveRecentFiles() +{ + // check if mupp_startup.xml is present in the current directory, and if yes, use this file to + // save the recent file names otherwise use the "master" mupp_startup.xml + + QString str(""); + QString fln = QString("./mupp_startup.xml"); + if (!QFile::exists(fln)) { + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + fln = QString("%1/.musrfit/mupp/mupp_startup.xml").arg(env.value("HOME")); + } + + if (QFile::exists(fln)) { // administration file present + QVector data; + QFile file(fln); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + std::cerr << std::endl << ">> PmuppAdmin::saveRecentFile: **ERROR** Cannot open " << fln.toLatin1().data() << " for reading." << std::endl; + return; + } + QTextStream fin(&file); + while (!fin.atEnd()) { + data.push_back(fin.readLine()); + } + file.close(); + + // remove from data + for (QVector::iterator it = data.begin(); it != data.end(); ++it) { + if (it->contains("")) { + it = data.erase(it); + --it; + } + } + + // add recent files + int i; + for (i=0; i")) + break; + } + + if (i == data.size()) { + std::cerr << std::endl << ">> PmuppAdmin::saveRecentFile: **ERROR** " << fln.toLatin1().data() << " seems to be corrupt." << std::endl; + return; + } + i++; + for (int j=0; j"; + data.insert(i++, str); + } + + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + std::cerr << std::endl << ">> PmuppAdmin::saveRecentFile: **ERROR** Cannot open " << fln.toLatin1().data() << " for reading." << std::endl; + return; + } + fin.setDevice(&file); + for (int i=0; i +#include +#include +#include +#include + +#include "mupp.h" + +class PmuppAdmin; + +//--------------------------------------------------------------------------- +/** + * @brief The PmuppColor class. Contains to colors read from the xml-startup + * which are used for the plotted data. + */ +class PmuppColor { + public: + PmuppColor(); + virtual ~PmuppColor() {} + + QString getName() { return fName; } + void getRGB(int &r, int &g, int &b) { r=fRed; g=fGreen; b=fBlue; } + + void setName(const QString name) { fName = name; } + void setRGB(const int r, const int g, const int b); + + private: + QString fName; + int fRed; + int fGreen; + int fBlue; +}; + +//--------------------------------------------------------------------------- +/** + * @brief The PmuppMarker class. List of the markers used in the plotter. Read + * from the xml-startup. + */ +class PmuppMarker { + public: + PmuppMarker() { fMarker = 20; fMarkerSize = 1.0; } + PmuppMarker(int marker, double size) : fMarker(marker), fMarkerSize(size) {} + virtual ~PmuppMarker() {} + + void getMarker(int &marker, double &size) { marker = fMarker; size = fMarkerSize; } + int getMarker() { return fMarker; } + double getMarkerSize() { return fMarkerSize; } + + void setMarker(int marker) { fMarker = marker; } + void setMarkerSize(double size) { fMarkerSize = size; } + + private: + int fMarker; + double fMarkerSize; +}; + +//--------------------------------------------------------------------------- +/** + * PAdminXMLParser is an XML parser class used to handle the mupp startup + * XML-file called mupp_startup.xml. This startup file contains + * necessary informations about executable pathes, online help informations, + * default font sizes, etc. + */ +class PmuppAdminXMLParser +{ + public: + PmuppAdminXMLParser(const QString &fln, PmuppAdmin*); + virtual ~PmuppAdminXMLParser() {} + + virtual bool isValid() { return fValid; } + + private: + enum EAdminKeyWords {eEmpty, eRecentFile, eDarkTheme, eMarker, eColor}; + + bool parse(QIODevice *device); + bool startDocument(); + bool startElement(); + bool endElement(); + bool characters(); + bool endDocument(); + + QXmlStreamReader fXml; ///< xml stream reader object + bool fValid; ///< flag showing if XML read has been successful + EAdminKeyWords fKeyWord; ///< key word tag to know how to handle the content + PmuppAdmin *fAdmin; ///< a pointer to the main administration class object +}; + +//--------------------------------------------------------------------------- +/** + * The PMuppAdmin class is handling the informations contained in the XML startup file, + * mupp_startup.xml. This startup file contains + * necessary informations like marker style, marker color, etc. The XML parsing is done + * with the help of the PmuppAdminXMLParser class. + */ +class PmuppAdmin : public QObject +{ + public: + PmuppAdmin(); + virtual ~PmuppAdmin(); + + void addRecentFile(const QString str); + int getNumRecentFiles() { return fRecentFile.size(); } + QString getRecentFile(int idx); + + + + int getNoOfMarkers() { return fMarker.size(); } + QVector getMarkers() { return fMarker; } + PmuppMarker getMarker(int idx); + + int getNoOfColors() { return fColor.size(); } + QVector getColors() { return fColor; } + void getColor(QString name, int &r, int &g, int &b); + void getColor(int idx, int &r, int &g, int &b); + + bool isDarkTheme() { return fDarkTheme; } + + void setTheme(bool theme) { fDarkTheme = theme; } + void setMarker(int marker, double size); + void setColor(int r, int g, int b, QString name=""); + + private: + friend class PmuppAdminXMLParser; + + QVector fRecentFile; ///< keep vector of recent path-file names + + bool fDarkTheme; + QVector fMarker; + QVector fColor; + + void saveRecentFiles(); ///< save recent file list + void createMuppStartupFile(); ///< create default mupp_startup.xml +}; + +#endif // _PMUPPADMIN_H_ diff --git a/src/musredit_qt6/mupp/PmuppGui.cpp b/src/musredit_qt6/mupp/PmuppGui.cpp new file mode 100644 index 00000000..acc65d55 --- /dev/null +++ b/src/musredit_qt6/mupp/PmuppGui.cpp @@ -0,0 +1,2653 @@ +/*************************************************************************** + + 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) +{ + QDateTime dt = QDateTime::currentDateTime(); + fDatime = dt.toSecsSinceEpoch(); + 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); +} + +//----------------------------------------------------------------------------- +/** + * @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" << Qt::endl; + fout << "% " << dt.toString("HH:mm:ss - yy/MM/dd") << Qt::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; + } + // check if variable name for the given collection already exists + int var_idx=-1; + for (int k=0; kcurrentRow()); + // 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 qvec(fVarHandler[i].getValues().begin(), fVarHandler[i].getValues().end()); + values = qvec; + } + } + } + + 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 qvec(fVarHandler[i].getErrors().begin(), fVarHandler[i].getErrors().end()); + values = qvec; + } + } + } + + 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 qvec(fVarHandler[i].getErrors().begin(), fVarHandler[i].getErrors().end()); + values = qvec; + } + } + } + + 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

mupp script help. + */ +void mupp_script_syntax() +{ + std::cout << std::endl; + std::cout << "SCRIPT COMMANDS:" << std::endl; + std::cout << " Lines starting with '#', '%', or '//' are comments and will be ignored." << std::endl; + std::cout << " The same is true for empty lines. Comments are also allowed at the end" << std::endl; + std::cout << " for a command, i.e. loadPath ./ # the best place ever." << std::endl; + std::cout << std::endl; + std::cout << " load : load a collection. is the filename of the" << std::endl; + std::cout << " collection (*.db, *.dat)" << std::endl; + std::cout << " loadPath : set the load path to ; accepting bash variables" << std::endl; + std::cout << " like $HOME, etc." << std::endl; + std::cout << " x : set a x-axis variable. is a data tag of" << std::endl; + std::cout << " the db/dat-file." << std::endl; + std::cout << " y : set a y-axis variable. is a data tag of" << std::endl; + std::cout << " the db/dat-file." << std::endl; + std::cout << " select : select collection , where is the row-number" << std::endl; + std::cout << " or the name of the collection to be selected." << std::endl; + std::cout << " selectAll : i.e. already set addX, addY will apply to ALL collections" << std::endl; + std::cout << " present." << std::endl; + std::cout << " savePath : sets the save path to ; accepting bash variables" << std::endl; + std::cout << " like $HOME, etc." << std::endl; + std::cout << " plot : where is the file name with extension under which" << std::endl; + std::cout << " the plot should be saved." << std::endl; + std::cout << " macro : where is the file name under which the root macro" << std::endl; + std::cout << " should be saved." << std::endl; + std::cout << " var = : defines a variable." << std::endl; + std::cout << " is a mathematical expression where" << std::endl; + std::cout << " collection variables are addressed via the '$'," << std::endl; + std::cout << " e.g. dataT is addressed by $dataT, etc." << std::endl; + std::cout << " col : : links to the collection , where" << std::endl; + std::cout << " is the number of the collection as defined" << std::endl; + std::cout << " by the order of load, starting with 0." << std::endl; + std::cout << std::endl; +} + +//------------------------------------------------------------------------ +/** + *

mupp syntax help. + */ +void mupp_syntax() +{ + std::cout << std::endl; + std::cout << "usage: mupp [OPTIONS] [[--path ] ]" << std::endl; + std::cout << std::endl; + std::cout << "OPTIONS:" << std::endl; + std::cout << " -h, --help: this help" << std::endl; + std::cout << " -v, --version: current mupp version" << std::endl; + std::cout << " -s , --script : being a mupp script." << std::endl; + std::cout << " --path : path where to look for the " << std::endl; + std::cout << " : list of file name(s) to be loaded." << std::endl; + std::cout << " allowed formats are: db, dat, msr" << std::endl << std::endl; + mupp_script_syntax(); +} + +//------------------------------------------------------------------------ +/** + *

Reads a mupp script and feeds its content to list. + * + * @param fln mupp script file name + * @param list content of the mupp script + * + * @return 0 if success, otherwise -1 + */ +int mupp_script_read(const char *fln, QStringList &list) +{ + QFile file(fln); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + std::cerr << std::endl; + std::cerr << "*********" << std::endl; + std::cerr << "**ERROR** couldn't open '" << fln << "'." << std::endl; + std::cerr << "*********" << std::endl; + return -1; + } + + QTextStream fin(&file); + QString line; + int pos; + while (!fin.atEnd()) { + line = fin.readLine(); + line = line.simplified(); + if (line.isEmpty()) + continue; + if (line.startsWith("#") || line.startsWith("%") || line.startsWith("//")) + continue; + // remove all potentially present trailing comments + pos = line.indexOf("#"); + if (pos != -1) + line.remove(pos, line.length()-pos); + pos = line.indexOf("%"); + if (pos != -1) + line.remove(pos, line.length()-pos); + pos = line.indexOf("//"); + if (pos != -1) + line.remove(pos, line.length()-pos); + line = line.simplified(); + // feed script list + list << line; + } + + return 0; +} + +//------------------------------------------------------------------------ +/** + *

check if a bash environment variable exists. + * + * @param str name of bash variable to be checked. + * + * @return true if the bash variable exists, false otherwise. + */ +bool mupp_bash_variable_exists(const QString str) +{ + QString var = str; + var.remove("$"); + + QProcessEnvironment procEnv = QProcessEnvironment::systemEnvironment(); + QString varExpanded = procEnv.value(var, ""); + if (!varExpanded.isEmpty()) + return true; + + return false; +} + +//------------------------------------------------------------------------ +/** + *

checks the mupp script syntax. + * + * @param list mupp script content. + * + * @return 0 on success, negative numbers otherwise. + */ +int mupp_script_syntax_check(QStringList &list) +{ + QString str; + QStringList tok; + QVector var_names; + QVector var_linked; + int noOfCollections = 0; + for (int i=0; i is missing." << std::endl; + std::cerr << "****************" << std::endl; + return -1; + } + tok.clear(); + + // check if bash variables are present, and if yes try to resolve them making sure they or NOT empty. + str = str.remove("loadPath "); + tok = str.split('/'); + for (int i=0; i : . Where is the collection index, and the variable name to be linked." << std::endl; + std::cerr << "****************" << std::endl; + return -1; + } + if (tok[2] != ":") { + std::cerr << std::endl; + std::cerr << "****************" << std::endl; + std::cerr << "**SYNTAX ERROR** found '" << str.toLatin1().constData() << "'. Syntax for variable collection linking is:" << std::endl; + std::cerr << " col : . Where is the collection index, and the variable name to be linked." << std::endl; + std::cerr << "****************" << std::endl; + return -2; + } + // will check that the to be linked variable and the target collection exists + // first check that the collection exists + bool ok; + int idx = tok[1].toInt(&ok); + if (!ok) { + std::cerr << std::endl; + std::cerr << "****************" << std::endl; + std::cerr << "**SYNTAX ERROR** found '" << str.toLatin1().constData() << "'. Syntax for variable collection linking is:" << std::endl; + std::cerr << " col : . Where is the collection index, and the variable name to be linked." << std::endl; + std::cerr << " collection index is not a number here!" << std::endl; + std::cerr << "****************" << std::endl; + return -2; + } + if (idx >= noOfCollections) { + std::cerr << std::endl; + std::cerr << "****************" << std::endl; + std::cerr << "**SYNTAX ERROR** in '" << str.toLatin1().constData() << "'." << std::endl; + std::cerr << " Requested collection '" << idx << "' is out-of-range." << std::endl; + std::cerr << " Only " << noOfCollections << " or present." << std::endl; + std::cerr << " Collection indexing starts at 0, not 1." << std::endl; + std::cerr << "****************" << std::endl; + return -3; + } + // make sure that the variable to be linked has been defined and is NOT an error variable. + if (tok[3].endsWith("Err")) { + std::cerr << std::endl; + std::cerr << "****************" << std::endl; + std::cerr << "**SYNTAX ERROR** in '" << str.toLatin1().constData() << "'." << std::endl; + std::cerr << " Only variables can be linked, NOT error variables." << std::endl; + std::cerr << " Error variables are linked implicitly." << std::endl; + std::cerr << "****************" << std::endl; + return -4; + } + idx = -1; + for (unsigned int i=0; iDepending on whether a script or gui application is wished, select + * the proper Qt application class. + * + * @param argc + * @param argv + * @param gui if true, the gui is wanted, otherwise the script is called. + * + * @return the request qt application + */ +QCoreApplication* createApplication(int &argc, char *argv[], bool gui) +{ + if (gui) + return new QApplication(argc, argv); + else + return new QCoreApplication(argc, argv); +} + +//------------------------------------------------------------------------ +/** + *

Main mupp application. mupp stands for muon parameter plotter. It allows + * to plot the parameters of db- or dat-files. The typical use case is e.g. + * plotting parameters of muSR fits as function of temperature, pressure, + * energy, etc. + * + * @param argc + * @param argv + * + * @return return value of the Qt application + */ +int main(int argc, char *argv[]) +{ + Q_INIT_RESOURCE(mupp); + + QStringList fln; + QStringList script; + + if (argc > 1) { + if (!qstrcmp(argv[1], "-h") || !qstrcmp(argv[1], "--help")) { + mupp_syntax(); + return 0; + } else if (!qstrcmp(argv[1], "-v") || !qstrcmp(argv[1], "--version")) { + std::cout << std::endl << "mupp version: " << MUPP_VERSION << ", git-branch: " << GIT_BRANCH << ", git-rev: " << GIT_COMMIT_HASH << std::endl << std::endl; + return 0; + } else if (!qstrcmp(argv[1], "-s") || !qstrcmp(argv[1], "--script")) { + if (argc != 3) { + std::cerr << std::endl; + std::cerr << "*********" << std::endl; + std::cerr << "**ERROR** the script option cannot be combined with something else." << std::endl; + std::cerr << "*********" << std::endl; + mupp_syntax(); + return -1; + } + // make sure that the script file exists + if (!QFile::exists(argv[2])) { + std::cerr << std::endl; + std::cerr << "*********" << std::endl; + std::cerr << "**ERROR** the script file '" << argv[2] << "' doesn't exist." << std::endl; + std::cerr << "*********" << std::endl << std::endl; + return -1; + } + + // read script file + if (mupp_script_read(argv[2], script) != 0) { + std::cerr << std::endl; + std::cerr << "*********" << std::endl; + std::cerr << "**ERROR** couldn't read script '" << argv[2] << "'" << std::endl; + std::cerr << "*********" << std::endl; + return -1; + } + + // check syntax of the script + if (mupp_script_syntax_check(script) != 0) { + return -1; + } + } else if (argc >= 2) { // assume it should be a fit-param-file-name list + // check if a path is given + int start=1; + QString path=""; + if (!qstrcmp(argv[1], "--path")) { + if (argc < 4) { + std::cerr << std::endl; + std::cerr << "*********" << std::endl; + std::cerr << "**ERROR** tag '--path' needs to be followed by a and at least one " << std::endl; + std::cerr << "*********" << std::endl; + mupp_syntax(); + return -1; + } + path = argv[2]; + start = 3; + } + for (int i=start; i 0) { // script + guiFlag = false; + } + QCoreApplication *app = createApplication(argc, argv, guiFlag); + + if (qobject_cast(app)) { // GUI + PmuppGui *gui = new PmuppGui(fln); + gui->setWindowTitle( "muSR Parameter Plotter" ); + gui->resize( 800, 500 ); + gui->show(); + + app->connect( app, SIGNAL( lastWindowClosed() ), app, SLOT( quit() ) ); + app->connect( app, SIGNAL( aboutToQuit() ), gui, SLOT( aboutToQuit() ) ); + } else { // scripting + PmuppScript *mupp_script = new PmuppScript(script); + if (mupp_script == 0) { + std::cerr << std::endl; + std::cerr << "*********" << std::endl; + std::cerr << "**ERROR** couldn't invoke script class..." << std::endl; + std::cerr << "*********" << std::endl; + return -1; + } + + // This will cause the application to exit when the task signals finished. + QObject::connect( mupp_script, SIGNAL( finished() ), app, SLOT( quit() ) ); + + // This will run the task from the application event loop. + QTimer::singleShot(0, mupp_script, SLOT( executeScript() ) ); + } + + return app->exec(); +} diff --git a/src/musredit_qt6/mupp/mupp.dox b/src/musredit_qt6/mupp/mupp.dox new file mode 100644 index 00000000..0e6f6970 --- /dev/null +++ b/src/musredit_qt6/mupp/mupp.dox @@ -0,0 +1,19 @@ +/********************************************************************************************* + + name: mupp.dox + + created by: Andreas Suter, 2020/05/19 + + content: Description of mupp + +**********************************************************************************************/ + +/** + +\mainpage mupp - muon parameter plotter + +

mupp allows to quickly plot parameters found in db-/dat-files. db-/dat-files are typically generated by msr2data from msr-files after fitting. A db-/dat-file is a collection of fitting parameters from a collection of muSR measurements. For instance a db-/dat-file collects a full temperature scan, a field scan, an energy scan, etc. + +

mupp allows to load these collections, select parameters in a x/y fashion and allows to plot it. It furthermore allows to create new variables which are mathematical transformations of the parameter vectors of a collection. + +*/ diff --git a/src/musredit_qt6/mupp/mupp.h b/src/musredit_qt6/mupp/mupp.h new file mode 100644 index 00000000..b7f0e2b4 --- /dev/null +++ b/src/musredit_qt6/mupp/mupp.h @@ -0,0 +1,47 @@ +/*************************************************************************** + + mupp.h + + 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. * + ***************************************************************************/ + +#ifndef _MUPP_H_ +#define _MUPP_H_ + +#include +#include +#include +#include + +#define MAX_RECENT_FILES 5 + +#define PMUPP_MAX_MTEXT 512 + +struct mbuf { + long mtype; // message type + char mtext[PMUPP_MAX_MTEXT]; // message body +}; + +#endif // _MUPP_H_ diff --git a/src/musredit_qt6/mupp/mupp.qrc b/src/musredit_qt6/mupp/mupp.qrc new file mode 100644 index 00000000..8390e2e1 --- /dev/null +++ b/src/musredit_qt6/mupp/mupp.qrc @@ -0,0 +1,13 @@ + + + icons/mupp-plain.svg + icons/mupp-dark.svg + icons/document-open-plain.svg + icons/document-open-dark.svg + icons/varEdit-plain.svg + icons/varEdit-dark.svg + icons/mupp.icns + mupp_startup.xml.in + + + diff --git a/src/musredit_qt6/mupp/mupp_startup.xml.in b/src/musredit_qt6/mupp/mupp_startup.xml.in new file mode 100644 index 00000000..f7e218c3 --- /dev/null +++ b/src/musredit_qt6/mupp/mupp_startup.xml.in @@ -0,0 +1,43 @@ + + + + Defines default settings for the mupp helper program for musrfit + + + + no + + + + 20,1.3 + 21,1.3 + 22,1.5 + 23,1.5 + 34,1.3 + 47,1.3 + 24,1.3 + 25,1.3 + 26,1.5 + 27,1.5 + 28,1.5 + 29,1.5 + 30,1.5 + 2,1.5 + 3,1.5 + 5,1.5 + + + + 0,0,0,kBlack + 255,0,0,kRed + 0,0,255,kBlue + 0,255,0,kGreen + 255,0,255,kMagenta + 0,255,255,kCyan + 153,0,255,kViolet-3 + 102,102,51,kYellow-1 + 51,102,51,kGreen-1, + 153,0,0,kRed+2 + + + diff --git a/src/musredit_qt6/mupp/plotter/CMakeLists.txt b/src/musredit_qt6/mupp/plotter/CMakeLists.txt new file mode 100644 index 00000000..c0b83035 --- /dev/null +++ b/src/musredit_qt6/mupp/plotter/CMakeLists.txt @@ -0,0 +1,99 @@ +#--- mupp_plotter ------------------------------------------------------------- +message("-- Handle the plotter part of mupp") + +#--- instruct cmake NOT to run moc automatically when needed anymore ---------- +set(CMAKE_AUTOMOC OFF) + +#--- headers ------------------------------------------------------------------ +set(HEADER + mupp_plot.h + PMuppCanvas.h + PMuppCanvasLinkDef.h + PMuppStartupHandler.h + PMuppStartupHandlerLinkDef.h +) + +#--- sources ------------------------------------------------------------------ +set(SOURCE + mupp_plot.cpp + PMuppCanvas.cpp + PMuppStartupHandler.cpp +) + +#--- dictionary generated sources --------------------------------------------- +set ( PLOT_DIR + ${CMAKE_CURRENT_BINARY_DIR} +) +# ROOT requires that the dictonary header files are found at configuration time. +# Hence, target_include_directories cannot be used here because, targets are +# setup only afterwards. +include_directories(${PLOT_DIR}) + +#--- generate necessary dictionaries ------------------------------------------ +root_generate_dictionary( + PMuppCanvasDict + PMuppCanvas.h + OPTIONS + -I${CMAKE_CURRENT_SOURCE_DIR} + -I${CMAKE_CURRENT_SOURCE_DIR}/.. + -inlineInputHeader + LINKDEF PMuppCanvasLinkDef.h + MODULE PMuppCanvas +) +root_generate_dictionary( + PMuppStartupHandlerDict + PMuppStartupHandler.h + OPTIONS + -I${CMAKE_CURRENT_SOURCE_DIR} + -I${CMAKE_CURRENT_SOURCE_DIR}/.. + -inlineInputHeader + LINKDEF PMuppStartupHandlerLinkDef.h + MODULE PMuppStartupHandler +) + +#--- define all the dictonary cxx --------------------------------------------- +set(DICT + ${PLOT_DIR}/PMuppCanvasDict.cxx + ${PLOT_DIR}/PMuppStartupHandlerDict.cxx +) + +#--- define executable -------------------------------------------------------- +add_executable(mupp_plot ${SOURCE} ${DICT}) + +#--- add all needed include directories --------------------------------------- +target_include_directories(mupp_plot + PRIVATE + ${ROOT_INCLUDE_DIRS} + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_BINARY_DIR}/.. + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/.. +) + +#--- define all to be linked libs --------------------------------------------- +target_link_libraries(mupp_plot ${ROOT_LIBRARIES}) + +#--- install ------------------------------------------------------------------ +if (APPLE) + install(TARGETS mupp_plot DESTINATION /Applications/mupp.app/Contents/MacOS) +else (APPLE) + install(TARGETS mupp_plot DESTINATION bin) +endif (APPLE) + +#--- install root pcm's and rootmaps ------------------------------------------ +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/libPMuppCanvas_rdict.pcm + ${CMAKE_CURRENT_BINARY_DIR}/libPMuppCanvas.rootmap + ${CMAKE_CURRENT_BINARY_DIR}/libPMuppStartupHandler_rdict.pcm + ${CMAKE_CURRENT_BINARY_DIR}/libPMuppStartupHandler.rootmap + DESTINATION lib +) + +#--- install headers ---------------------------------------------------------- +install( + FILES ${CMAKE_CURRENT_SOURCE_DIR}/../mupp.h + ${CMAKE_CURRENT_SOURCE_DIR}/mupp_plot.h + ${CMAKE_CURRENT_SOURCE_DIR}/PMuppCanvas.h + ${CMAKE_CURRENT_SOURCE_DIR}/PMuppStartupHandler.h + DESTINATION include +) diff --git a/src/musredit_qt6/mupp/plotter/PMuppCanvas.cpp b/src/musredit_qt6/mupp/plotter/PMuppCanvas.cpp new file mode 100644 index 00000000..b9f3f7d6 --- /dev/null +++ b/src/musredit_qt6/mupp/plotter/PMuppCanvas.cpp @@ -0,0 +1,657 @@ +/*************************************************************************** + + PMuppCanvas.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 "PMuppCanvas.h" + +static const char *gFiletypes[] = { "Data files", "*.dat", + "All files", "*", + 0, 0 }; + +ClassImpQ(PMuppCanvas) + +//-------------------------------------------------------------------------- +// Constructor +//-------------------------------------------------------------------------- +/** + * @brief PMuppCanvas::PMuppCanvas + */ +PMuppCanvas::PMuppCanvas() +{ + fFtokName = TString(""); + fCheckMsgQueue = 0; + + fStyle = 0; + fImp = 0; + fBar = 0; + fPopupMain = 0; + + fMainCanvas = 0; + fMultiGraph = 0; + + gStyle->SetHistMinimumZero(kTRUE); // needed to enforce proper bar option handling +} + +//-------------------------------------------------------------------------- +// Constructor +//-------------------------------------------------------------------------- +/** + * @brief PMuppCanvas::PMuppCanvas + * @param title + * @param wtopx + * @param wtopy + * @param ww + * @param wh + * @param markerSytleList + * @param markerSizeList + * @param colorList + */ +PMuppCanvas::PMuppCanvas(const Char_t *title, Int_t wtopx, Int_t wtopy, + Int_t ww, Int_t wh, const PIntVector markerSytleList, + const PDoubleVector markerSizeList, const PIntVector colorList, + const int mupp_instance) : + fMuppInstance(mupp_instance), + fMarkerStyleList(markerSytleList), + fMarkerSizeList(markerSizeList), + fColorList(colorList) +{ + fValid = true; + + fFtokName = TString(""); + fCheckMsgQueue = 0; + + // install IPC message queue timer + fCheckMsgQueue = new TTimer(); + if (fCheckMsgQueue == 0) { + fValid = false; + std::cerr << "**ERROR** couldn't start IPC message queue timer..." << std::endl; + return; + } + fCheckMsgQueue->Connect("Timeout()", "PMuppCanvas", this, "CheckIPCMsgQueue()"); + fCheckMsgQueue->Start(200, kFALSE); + + CreateStyle(); + InitMuppCanvas(title, wtopx, wtopy, ww, wh); +} + +//-------------------------------------------------------------------------- +// Destructor +//-------------------------------------------------------------------------- +/** + * @brief PMuppCanvas::~PMuppCanvas + */ +PMuppCanvas::~PMuppCanvas() +{ + if (fMainCanvas) { + delete fMainCanvas; + } + if (fMultiGraph) { + delete fMultiGraph; + } + if (fStyle) { + delete fStyle; + } +} + +//-------------------------------------------------------------------------- +// Done (SIGNAL) +//-------------------------------------------------------------------------- +/** + *

Signal emitted that the user wants to terminate the application. + * + * \param status Status info + */ +void PMuppCanvas::Done(Int_t status) +{ + Emit("Done(Int_t)", status); +} + +//-------------------------------------------------------------------------- +// HandleCmdKey (SLOT) +//-------------------------------------------------------------------------- +/** + *

Filters keyboard events, and if they are a command key (see below) carries out the + * necessary actions. + *

Currently implemented command keys: + * - 'q' quit mupp_plot + * + * \param event event type + * \param x character key + * \param y not used + * \param selected not used + */ +void PMuppCanvas::HandleCmdKey(Int_t event, Int_t x, Int_t y, TObject *selected) +{ + if (event != kKeyPress) + return; + + // handle keys and popup menu entries + if (x == 'q') { // quit + Done(0); + } else if (x == 'b') { // about + new TGMsgBox(gClient->GetRoot(), 0, "About mupp", "created by Andreas Suter\nPSI/NUM/LMU/LEM\n2018", kMBIconAsterisk); + } +} + +//-------------------------------------------------------------------------- +// HandleMenuPopup (SLOT) +//-------------------------------------------------------------------------- +/** + *

Handles the mupp menu. + * + * \param id identification key of the selected menu + */ +void PMuppCanvas::HandleMenuPopup(Int_t id) +{ + if (id == P_MENU_ID_EXPORT) { + ExportData(); + } else if (id == P_MENU_ID_ABOUT) { + new TGMsgBox(gClient->GetRoot(), 0, "About mupp", "created by Andreas Suter\nPSI/NUM/LMU/LEM\n2017", kMBIconAsterisk); + } +} + +//-------------------------------------------------------------------------- +// LastCanvasClosed (SLOT) +//-------------------------------------------------------------------------- +/** + *

Slot called when the last canvas has been closed. Will emit Done(0) which will + * terminate the application. + */ +void PMuppCanvas::LastCanvasClosed() +{ + if (gROOT->GetListOfCanvases()->IsEmpty()) { + Done(0); + } +} + +//-------------------------------------------------------------------------- +// WindowClosed (SLOT) +//-------------------------------------------------------------------------- +/** + *

Slot called when the canvas is closed. Seems to be necessary on some systems. + */ +void PMuppCanvas::WindowClosed() +{ + gROOT->GetListOfCanvases()->Remove(fMainCanvas); + LastCanvasClosed(); +} + +//-------------------------------------------------------------------------- +// CreateStyle (private) +//-------------------------------------------------------------------------- +/** + *

Set styles for the canvas. Perhaps one could transfer them to the startup-file in the future. + */ +void PMuppCanvas::CreateStyle() +{ + TString muppStyle("muppStyle"); + fStyle = new TStyle(muppStyle, muppStyle); + fStyle->SetOptStat(0); // no statistics options + fStyle->SetOptTitle(0); // no title + // set margins + fStyle->SetPadLeftMargin(0.15); + fStyle->SetPadRightMargin(0.05); + fStyle->SetPadBottomMargin(0.12); + fStyle->SetPadTopMargin(0.05); + + fStyle->cd(); +} + +//-------------------------------------------------------------------------- +/** + * @brief PMuppCanvas::InitMuppCanvas + * @param title + * @param wtopx + * @param wtopy + * @param ww + * @param wh + */ +void PMuppCanvas::InitMuppCanvas(const Char_t *title, Int_t wtopx, Int_t wtopy, Int_t ww, Int_t wh) +{ + fValid = false; + + // invoke canvas + TString canvasName = TString("fMuppCanvas"); + fMainCanvas = new TCanvas(canvasName.Data(), title, wtopx, wtopy, ww, wh); + if (fMainCanvas == 0) { + std::cerr << std::endl << ">> PMuppCanvas::InitMuppCanvas(): **PANIC ERROR** Couldn't invoke " << canvasName.Data(); + std::cerr << std::endl; + return; + } + + fMainCanvas->SetFillColor(0); + + fMultiGraph = 0; + + fImp = (TRootCanvas*)fMainCanvas->GetCanvasImp(); + fImp->Connect("CloseWindow()", "PMuppCanvas", this, "WindowClosed()"); + fBar = fImp->GetMenuBar(); + fPopupMain = fBar->AddPopup("&Mupp"); + + fPopupMain->AddEntry("Export &Data", P_MENU_ID_EXPORT); + fPopupMain->AddSeparator(); + fPopupMain->AddEntry("A&bout", P_MENU_ID_ABOUT); + + fBar->MapSubwindows(); + fBar->Layout(); + + fPopupMain->Connect("TGPopupMenu", "Activated(Int_t)", "PMuppCanvas", this, "HandleMenuPopup(Int_t)"); + + fValid = true; + + fMainCanvas->cd(); + fMainCanvas->Show(); + fMainCanvas->Connect("ProcessedEvent(Int_t,Int_t,Int_t,TObject*)", "PMuppCanvas", + this, "HandleCmdKey(Int_t,Int_t,Int_t,TObject*)"); +} + +//-------------------------------------------------------------------------- +/** + * @brief PMuppCanvas::CheckIPCMsgQueue + */ +void PMuppCanvas::CheckIPCMsgQueue() +{ + int msqid, flags, type, key, status; + ssize_t msgLen; + struct mbuf msg; + char str[1024]; + + // get msqid + if (fFtokName.IsWhitespace()) { + strncpy(str, getenv("HOME"), sizeof(str)-1); + if (strlen(str) == 0) { + std::cerr << std::endl; + std::cerr << "**ERROR** couldn't get value of the environment variable HOME." << std::endl << std::endl; + return; + } + memset(str, '\0', sizeof(str)); + snprintf(str, sizeof(str), "%s/.musrfit/mupp/_mupp_ftok_%d.dat", getenv("HOME"), fMuppInstance); + std::ifstream fin(str, std::ifstream::in); + if (!fin.is_open()) { + std::cerr << std::endl; + std::cerr << "**ERROR** couldn't open " << str << std::endl; + return; + } + fin.getline(str, 1024); + fin.close(); + fFtokName = str; + } + + key = ftok(fFtokName.Data(), fMuppInstance); + flags = IPC_CREAT; + msqid = msgget(key, flags | S_IRUSR | S_IWUSR); + if (msqid == -1) { + std::cerr << std::endl; + std::cerr << "**ERROR** couldn't get msqid." << std::endl << std::endl; + return; + } + + // get message + flags = IPC_NOWAIT; + type = 1; + msgLen = msgrcv(msqid, &msg, PMUPP_MAX_MTEXT, type, flags); + + if (msgLen > 0) { + status = ReadPlotData(msg.mtext); + if (status != 0) { + std::cerr << "**ERROR** reading " << msg.mtext << std::endl; + } + } +} + +//-------------------------------------------------------------------------- +/** + * @brief PMuppCanvas::ReadPlotData + * @param fln + * @return + */ +int PMuppCanvas::ReadPlotData(const Char_t *fln) +{ + std::ifstream fin(fln, std::ifstream::in); + char line[1024]; + + if (!fin.is_open()) { + std::cerr << "**ERROR** Couldn't open " << fln << std::endl; + return -1; + } + + TString str; + TObjArray *tok; + TObjString *ostr; + Ssiz_t idx; + Int_t noOfDataTokens=0; + PDataCollection data; + PDataPoint dataPoint; + fPlotData.clear(); + while (fin.good()) { + fin.getline(line, 1024); + if (line[0] == '%') { + if (strstr(line, "% collName")) { + noOfDataTokens = 0; + InitDataCollection(data); // make sure that one starts with a fresh collection + str = line; + idx = str.First("="); + str = str.Remove(0,idx+2); + data.name = str; + } else if (strstr(line, "% end")) { + fPlotData.push_back(data); + } + } else if (strlen(line) == 0) { // ignore empty lines + continue; + } else if (strstr(line, "xLabel:")) { // header information + str = line; + tok = str.Tokenize(":,"); + if (tok == 0) { + std::cerr << "**ERROR** Couldn't tokenize the label line." << std::endl; + fin.close(); + return -2; + } + if (tok->GetEntries() < 4) { + std::cerr << "**ERROR** label line doesn't contain sufficient information." << std::endl; + fin.close(); + return -3; + } + ostr = dynamic_cast(tok->At(1)); + data.xLabel = ostr->GetString(); + noOfDataTokens++; + for (Int_t i=3; iGetEntries(); i+=2) { + ostr = dynamic_cast(tok->At(i)); + data.yLabel.push_back(ostr->GetString()); + noOfDataTokens++; + } + + // clean up + delete tok; + tok = 0; + } else { // data lines + str = line; + tok = str.Tokenize(", "); + if (tok == 0) { + std::cerr << "**ERROR** Couldn't tokenize data line." << std::endl; + fin.close(); + return -4; + } + if (tok->GetEntries() != (noOfDataTokens-1)*3+1) { + std::cerr << "**ERROR** number of token in data line (" << tok->GetEntries() << ") is inconsistent with no of labels (" << noOfDataTokens << ")." << std::endl; + fin.close(); + return -4; + } + + // resize y-value vector properly + data.yValue.resize(noOfDataTokens-1); + + // raw data point + // x-value + ostr = dynamic_cast(tok->At(0)); + str = ostr->GetString(); + if (!str.IsFloat()) { + std::cerr << "**ERROR** token found in data line is not a number (" << str << ")." << std::endl; + fin.close(); + return -5; + } + data.xValue.push_back(str.Atof()); + + // y-value(s) + Int_t idx=0; + for (Int_t i=1; iGetEntries(); i+=3) { + // y-value + ostr = dynamic_cast(tok->At(i)); + str = ostr->GetString(); + if (!str.IsFloat()) { + std::cerr << "**ERROR** token found in data line is not a number (" << str << ")." << std::endl; + fin.close(); + return -5; + } + dataPoint.y = str.Atof(); + + // pos y error-value + ostr = dynamic_cast(tok->At(i+1)); + str = ostr->GetString(); + if (!str.IsFloat()) { + std::cerr << "**ERROR** token found in data line is not a number (" << str << ")." << std::endl; + fin.close(); + return -5; + } + dataPoint.eYpos = str.Atof(); + + // neg y error-value + ostr = dynamic_cast(tok->At(i+2)); + str = ostr->GetString(); + if (!str.IsFloat()) { + std::cerr << "**ERROR** token found in data line is not a number (" << str << ")." << std::endl; + fin.close(); + return -5; + } + dataPoint.eYneg = str.Atof(); + + // push dataPoint back into data structure + data.yValue[idx].push_back(dataPoint); + idx++; + } + + // clean up + delete tok; + tok = 0; + } + } + + fin.close(); + + // check if data structure makes sense + for (UInt_t i=0; i collection " << i << std::endl; + std::cerr << "debug> name : " << fPlotData[i].name << std::endl; + std::cerr << "debug> x-label : " << fPlotData[i].xLabel << std::endl; + std::cerr << "debug> x-vales : " << std::endl; + std::cerr << "debug> "; + for (UInt_t j=0; j y-label : " << fPlotData[i].yLabel[j] << std::endl; + std::cerr << "debug> y-values " << j << ": " << std::endl; + for (UInt_t k=0; k " << k << ": " << fPlotData[i].yValue[j][k].y << "(" << fPlotData[i].yValue[j][k].eYneg << "/" << fPlotData[i].yValue[j][k].eYpos << ")" << std::endl; + } + } + std::cerr << std::endl; + } + + // feed graph objects + UpdateGraphs(); + + return 0; +} + +//-------------------------------------------------------------------------- +/** + * @brief PMuppCanvas::InitDataCollection + * @param coll + */ +void PMuppCanvas::InitDataCollection(PDataCollection &coll) +{ + coll.name = TString(""); + coll.xLabel = TString(""); + coll.yLabel.clear(); + coll.xValue.clear(); + coll.yValue.clear(); +} + +//-------------------------------------------------------------------------- +/** + * @brief PMuppCanvas::UpdateGraphs + */ +void PMuppCanvas::UpdateGraphs() +{ + // first: get rid of all previous plots + for (UInt_t i=0; iSetPoint(k, fPlotData[i].xValue[k], fPlotData[i].yValue[j][k].y); + gg->SetPointError(k, 0.0, 0.0, fabs(fPlotData[i].yValue[j][k].eYneg), fPlotData[i].yValue[j][k].eYpos); + // set marker style and size + if (idxS < fMarkerStyleList.size()) { + gg->SetMarkerStyle(fMarkerStyleList[idxS]); + gg->SetMarkerSize(fMarkerSizeList[idxS]); + } else { // random choice of the marker + // still missing as35 + } + // set color + if (idxC < fColorList.size()) { + gg->SetMarkerColor(fColorList[idxC]); + gg->SetLineColor(fColorList[idxC]); + gg->SetFillColor(kWhite); + } else { // random choise of the color + TRandom rand(i+j+k); + color = TColor::GetColor((Int_t)rand.Integer(255), (Int_t)rand.Integer(255), (Int_t)rand.Integer(255)); + gg->SetMarkerColor(color); + gg->SetLineColor(color); + gg->SetFillColor(kWhite); + } + } + idxS++; + idxC++; + + // set name + str = fPlotData[i].yLabel[j]; + if (fPlotData[i].yValue.size() > 1) { + str += "-"; + str += j; + } + gg->SetName(str); + gg->SetTitle(str); + + // set x-axis title + gg->GetXaxis()->SetTitle(fPlotData[i].xLabel); + // set y-axis title + gg->GetYaxis()->SetTitle(fPlotData[i].yLabel[j]); + + fGraphE.push_back(gg); + } + } + + fMultiGraph = new TMultiGraph(); + if (fMultiGraph == 0) { + std::cerr << "**ERROR** couldn't create necessary TMultiGraph object." << std::endl; + return; + } + + if (fGraphE.size() == 0) { + std::cerr << "**ERROR** NO graphs present! This should never happen." << std::endl; + return; + } + + for (UInt_t i=0; iAdd(fGraphE[i], "p"); + } + + fMultiGraph->Draw("a"); + + // set x-axis limits. This is needed that the graphs x-axis starts at 0.0 + Double_t xmin=fMultiGraph->GetXaxis()->GetXmin(); + Double_t xmax=fMultiGraph->GetXaxis()->GetXmax(); + if (xmin > 0.0) { + fMultiGraph->GetXaxis()->SetLimits(0.0, xmax); + } + + // set fMultiGraph x/y-axis title + if (fGraphE.size() == 1) { // only one data set + fMultiGraph->GetXaxis()->SetTitle(fGraphE[0]->GetXaxis()->GetTitle()); + fMultiGraph->GetXaxis()->SetTitleSize(0.05); + fMultiGraph->GetYaxis()->SetTitle(fGraphE[0]->GetYaxis()->GetTitle()); + fMultiGraph->GetYaxis()->SetTitleOffset(1.25); + fMultiGraph->GetYaxis()->SetTitleSize(0.05); + fMultiGraph->GetYaxis()->SetLabelOffset(0.01); + fMultiGraph->GetYaxis()->SetDecimals(); + } else { // multiple data sets + fMultiGraph->GetXaxis()->SetTitle(fGraphE[0]->GetXaxis()->GetTitle()); // need a better solution, as35 + fMultiGraph->GetXaxis()->SetTitleSize(0.05); + fMultiGraph->GetYaxis()->SetTitle(fGraphE[0]->GetYaxis()->GetTitle()); // need a better solution, as35 + fMultiGraph->GetYaxis()->SetTitleOffset(1.25); + fMultiGraph->GetYaxis()->SetTitleSize(0.05); + fMultiGraph->GetYaxis()->SetLabelOffset(0.01); + fMultiGraph->GetYaxis()->SetDecimals(); + } + gPad->Modified(); + + fMainCanvas->cd(); + fMainCanvas->Update(); + } else { // update of the graphs + // still missing, as35 + } +} + +//-------------------------------------------------------------------------- +/** + * @brief PMuppCanvas::ExportData + */ +void PMuppCanvas::ExportData() +{ + static TString dir("."); + TGFileInfo fi; + fi.fFileTypes = gFiletypes; + fi.fIniDir = StrDup(dir); + fi.fOverwrite = true; + new TGFileDialog(0, fImp, kFDSave, &fi); + if (fi.fFilename && strlen(fi.fFilename)) { + // still missing, as35 + new TGMsgBox(gClient->GetRoot(), 0, "ExportData", "NOT YET IMPLEMENTED", kMBIconAsterisk); + } +} diff --git a/src/musredit_qt6/mupp/plotter/PMuppCanvas.h b/src/musredit_qt6/mupp/plotter/PMuppCanvas.h new file mode 100644 index 00000000..a57a2228 --- /dev/null +++ b/src/musredit_qt6/mupp/plotter/PMuppCanvas.h @@ -0,0 +1,127 @@ +/*************************************************************************** + + PMuppCanvas.h + + 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. * + ***************************************************************************/ + +#ifndef _PMUPPCANVAS_H_ +#define _PMUPPCANVAS_H_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mupp_plot.h" +#include "mupp.h" + +// Canvas menu id's +#define P_MENU_ID_EXPORT 10001 +#define P_MENU_ID_ABOUT 10002 + +//-------------------------------------------------------------------------- +typedef struct { + Double_t y; + Double_t eYpos; + Double_t eYneg; +} PDataPoint; + +//-------------------------------------------------------------------------- +typedef struct { + TString name; // collection name + TString xLabel; + PStringVector yLabel; + PDoubleVector xValue; + std::vector< std::vector > yValue; +} PDataCollection; + +//-------------------------------------------------------------------------- +class PMuppCanvas : public TObject, public TQObject +{ +public: + PMuppCanvas(); + PMuppCanvas(const Char_t* title, + Int_t wtopx, Int_t wtopy, Int_t ww, Int_t wh, + const PIntVector markerSytleList, const PDoubleVector markerSizeList, + const PIntVector colorList, + const int mupp_instance); + virtual ~PMuppCanvas(); + + virtual Bool_t IsValid() { return fValid; } + + virtual void Done(Int_t status=0); // *SIGNAL* + virtual void HandleCmdKey(Int_t event, Int_t x, Int_t y, TObject *selected); // SLOT + virtual void HandleMenuPopup(Int_t id); // SLOT + virtual void LastCanvasClosed(); // SLOT + virtual void WindowClosed(); // SLOT + + virtual void CheckIPCMsgQueue(); + +private: + Bool_t fValid; + Int_t fMuppInstance; + + TString fFtokName; + TTimer *fCheckMsgQueue; ///< timer needed to check if a message in the IPC message queue is pending + + std::vector fPlotData; + + TStyle *fStyle; ///< A collection of all graphics attributes + + // canvas menu related variables + TRootCanvas *fImp; ///< ROOT native GUI version of main window with menubar and drawing area + TGMenuBar *fBar; ///< menu bar + TGPopupMenu *fPopupMain; ///< popup menu mupp in the main menu bar + + // canvas related variables + TCanvas *fMainCanvas; ///< main canvas + TMultiGraph *fMultiGraph; ///< main multi graph + std::vector fGraphE; ///< all error graphs + + // perdefined markers, colors + PIntVector fMarkerStyleList; + PDoubleVector fMarkerSizeList; + PIntVector fColorList; + + virtual void CreateStyle(); + virtual void InitMuppCanvas(const Char_t* title, Int_t wtopx, Int_t wtopy, Int_t ww, Int_t wh); + + virtual int ReadPlotData(const Char_t *fln); + virtual void InitDataCollection(PDataCollection &coll); + virtual void UpdateGraphs(); + virtual void ExportData(); + + ClassDef(PMuppCanvas, 1) +}; + +#endif // _PMUPPCANVAS_H_ diff --git a/src/musredit_qt6/mupp/plotter/PMuppCanvasLinkDef.h b/src/musredit_qt6/mupp/plotter/PMuppCanvasLinkDef.h new file mode 100644 index 00000000..ae26b70f --- /dev/null +++ b/src/musredit_qt6/mupp/plotter/PMuppCanvasLinkDef.h @@ -0,0 +1,38 @@ +/*************************************************************************** + + PMuppCanvasLinkDef.h + + 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. * + ***************************************************************************/ + +#ifdef __CINT__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class PMuppCanvas+; + +#endif diff --git a/src/musredit_qt6/mupp/plotter/PMuppStartupHandler.cpp b/src/musredit_qt6/mupp/plotter/PMuppStartupHandler.cpp new file mode 100644 index 00000000..1e6143b9 --- /dev/null +++ b/src/musredit_qt6/mupp/plotter/PMuppStartupHandler.cpp @@ -0,0 +1,457 @@ +/*************************************************************************** + + PMuppStartupHandler.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 "PMuppStartupHandler.h" + +ClassImpQ(PMuppStartupHandler) + +//-------------------------------------------------------------------------- +// This function is a replacement for the ParseFile method of TSAXParser. +// It is needed because in certain environments ParseFile does not work but ParseBuffer does. +//-------------------------------------------------------------------------- +/** + *

Replacement for the ParseFile method of TSAXParser. + * + *

return: + * - 1 if file cannot be read + * - 0 if the file has been parsed successfully + * - parse error code otherwise + * + * \param saxParser pointer to a TSAXParser object + * \param startup_path_name full path to the XML file to be read + */ +int parseXmlFile(TSAXParser *saxParser, const char *startup_path_name) +{ + int status; + std::fstream xmlFile; + unsigned int xmlSize = 0; + char *xmlBuffer = 0; + + xmlFile.open(startup_path_name, std::ios::in | std::ios::ate); // open file for reading and go to the end of the file + if (xmlFile.is_open()) { // check if file has been opened successfully + xmlSize = xmlFile.tellg(); // get the position within the stream == size of the file (since we are at the end) + xmlFile.seekg(0, std::ios::beg); // go back to the beginning of the stream + xmlBuffer = new char[xmlSize]; // allocate buffer memory for the whole XML file + xmlFile.read(xmlBuffer, xmlSize); // read in the whole XML file into the buffer + xmlFile.close(); // close the XML file + } + if (!xmlBuffer) { // file has not been read into the buffer + status = 1; + } else { + status = saxParser->ParseBuffer(xmlBuffer, xmlSize); // parse buffer + delete[] xmlBuffer; // free the buffer memory + xmlBuffer = 0; + } + + return status; +} + +//-------------------------------------------------------------------------- +// Constructor +//-------------------------------------------------------------------------- +/** + * @brief PMuppStartupHandler::PMuppStartupHandler + */ +PMuppStartupHandler::PMuppStartupHandler() +{ + fStartupFileFound = false; + fStartupFilePath = ""; + + // get default path (for the moment only linux like) + Char_t *home=0; + Char_t musrpath[128]; + Char_t startup_path_name[128]; + + strncpy(musrpath, "", sizeof(musrpath)); + + // check if the startup file is found in the current directory + strcpy(startup_path_name, "./mupp_startup.xml"); + if (StartupFileExists(startup_path_name)) { + fStartupFileFound = true; + fStartupFilePath = TString(startup_path_name); + } + if (!fStartupFileFound) { // startup file not found in the current directory + // check if the startup file is found under $HOME/.musrfit/mupp + home = getenv("HOME"); + if (home != 0) { + sprintf(startup_path_name, "%s/.musrfit/mupp/mupp_startup.xml", home); + if (StartupFileExists(startup_path_name)) { + fStartupFilePath = TString(startup_path_name); + fStartupFileFound = true; + } + } + } +} + +//-------------------------------------------------------------------------- +// Destructor +//-------------------------------------------------------------------------- +/** + * @brief PMuppStartupHandler::~PStartupHandler + */ +PMuppStartupHandler::~PMuppStartupHandler() +{ + fMarkerStyleList.clear(); + fMarkerSizeList.clear(); + fColorList.clear(); +} + +//-------------------------------------------------------------------------- +// OnStartDocument +//-------------------------------------------------------------------------- +/** + *

Called on start of the XML file reading. Initializes all necessary variables. + */ +void PMuppStartupHandler::OnStartDocument() +{ + fKey = eEmpty; +} + +//-------------------------------------------------------------------------- +// OnEndDocument +//-------------------------------------------------------------------------- +/** + *

Called on end of XML file reading. + */ +void PMuppStartupHandler::OnEndDocument() +{ + // check if anything was set, and if not set some default stuff + CheckLists(); +} + +//-------------------------------------------------------------------------- +// OnStartElement +//-------------------------------------------------------------------------- +/** + *

Called when a XML start element is found. Filters out the needed elements + * and sets a proper key. + * + * \param str XML element name + * \param attributes not used + */ +void PMuppStartupHandler::OnStartElement(const Char_t *str, const TList *attributes) +{ + if (!strcmp(str, "marker")) { + fKey = eMarker; + } else if (!strcmp(str, "color")) { + fKey = eColor; + } +} + +//-------------------------------------------------------------------------- +// OnEndElement +//-------------------------------------------------------------------------- +/** + *

Called when a XML end element is found. Resets the handler key. + * + * \param str not used + */ +void PMuppStartupHandler::OnEndElement(const Char_t *str) +{ + fKey = eEmpty; +} + +//-------------------------------------------------------------------------- +// OnCharacters +//-------------------------------------------------------------------------- +/** + *

Content of a given XML element. Filters out the data and feeds them to + * the internal variables. + * + * \param str XML element string + */ +void PMuppStartupHandler::OnCharacters(const Char_t *str) +{ + TObjArray *tokens; + TObjString *ostr; + TString tstr; + Int_t color, r, g, b; + + switch (fKey) { + case eMarker: + // check that str is , + tstr = TString(str); + tokens = tstr.Tokenize(","); + if (tokens == 0) { + std::cerr << std::endl << "PMuppStartupHandler **WARNING** '" << str << "' is not a marker code, will ignore it"; + std::cerr << std::endl; + return; + } + if (tokens->GetEntries() != 2) { + std::cerr << std::endl << "PMuppStartupHandler **WARNING** '" << str << "' is not a marker code, will ignore it"; + std::cerr << std::endl; + return; + } + // get marker style + ostr = dynamic_cast(tokens->At(0)); + tstr = ostr->GetString(); + if (tstr.IsDigit()) { + fMarkerStyleList.push_back(tstr.Atoi()); + } else { + std::cerr << std::endl << "PMuppStartupHandler **WARNING** marker style '" << str << "' is not a number, will ignore it"; + std::cerr << std::endl; + } + // get marker size + ostr = dynamic_cast(tokens->At(1)); + tstr = ostr->GetString(); + if (tstr.IsFloat()) { + fMarkerSizeList.push_back(tstr.Atof()); + } else { + std::cerr << std::endl << "PMuppStartupHandler **WARNING** marker size '" << str << "' is not a float, will ignore it"; + std::cerr << std::endl; + } + // clean up tokens + if (tokens) { + delete tokens; + tokens = 0; + } + break; + case eColor: + // check that str is a rbg code + tstr = TString(str); + tokens = tstr.Tokenize(","); + // check that there any tokens + if (tokens == 0) { + std::cerr << std::endl << "PMuppStartupHandler **WARNING** '" << str << "' is not a rbg code, will ignore it"; + std::cerr << std::endl; + return; + } + // check there is the right number of tokens + if (tokens->GetEntries() < 3) { + std::cerr << std::endl << "PMuppStartupHandler **WARNING** '" << str << "' is not a rbg code, will ignore it"; + std::cerr << std::endl; + return; + } + // get r + ostr = dynamic_cast(tokens->At(0)); + tstr = ostr->GetString(); + if (tstr.IsDigit()) { + r = tstr.Atoi(); + } else { + std::cerr << std::endl << "PMuppStartupHandler **WARNING** r within the rgb code is not a number, will ignore it"; + std::cerr << std::endl; + return; + } + // get g + ostr = dynamic_cast(tokens->At(1)); + tstr = ostr->GetString(); + if (tstr.IsDigit()) { + g = tstr.Atoi(); + } else { + std::cerr << std::endl << "PMuppStartupHandler **WARNING** g within the rgb code is not a number, will ignore it"; + std::cerr << std::endl; + return; + } + // get b + ostr = dynamic_cast(tokens->At(2)); + tstr = ostr->GetString(); + if (tstr.IsDigit()) { + b = tstr.Atoi(); + } else { + std::cerr << std::endl << "PMuppStartupHandler **WARNING** b within the rgb code is not a number, will ignore it"; + std::cerr << std::endl; + return; + } + // clean up tokens + if (tokens) { + delete tokens; + tokens = 0; + } + // generate the ROOT color code based on str + color = TColor::GetColor(r,g,b); + // add the color code to the color list + fColorList.push_back(color); + break; + default: + break; + } +} + +//-------------------------------------------------------------------------- +// OnComment +//-------------------------------------------------------------------------- +/** + *

Called when a XML comment is found. Not used. + * + * \param str not used. + */ +void PMuppStartupHandler::OnComment(const Char_t *str) +{ + // nothing to be done for now +} + +//-------------------------------------------------------------------------- +// OnWarning +//-------------------------------------------------------------------------- +/** + *

Called when the XML parser emits a warning. + * + * \param str warning string + */ +void PMuppStartupHandler::OnWarning(const Char_t *str) +{ + std::cerr << std::endl << "PMuppStartupHandler **WARNING** " << str; + std::cerr << std::endl; +} + +//-------------------------------------------------------------------------- +// OnError +//-------------------------------------------------------------------------- +/** + *

Called when the XML parser emits an error. + * + * \param str error string + */ +void PMuppStartupHandler::OnError(const Char_t *str) +{ + std::cerr << std::endl << "PMuppStartupHandler **ERROR** " << str; + std::cerr << std::endl; +} + +//-------------------------------------------------------------------------- +// OnFatalError +//-------------------------------------------------------------------------- +/** + *

Called when the XML parser emits a fatal error. + * + * \param str fatal error string + */ +void PMuppStartupHandler::OnFatalError(const Char_t *str) +{ + std::cerr << std::endl << "PMuppStartupHandler **FATAL ERROR** " << str; + std::cerr << std::endl; +} + +//-------------------------------------------------------------------------- +// OnCdataBlock +//-------------------------------------------------------------------------- +/** + *

Not used. + * + * \param str not used + * \param len not used + */ +void PMuppStartupHandler::OnCdataBlock(const Char_t *str, Int_t len) +{ + // nothing to be done for now +} + +//-------------------------------------------------------------------------- +// CheckLists +//-------------------------------------------------------------------------- +/** + *

Check if the default lists are present and if not, feed them with some default settings + * + */ +void PMuppStartupHandler::CheckLists() +{ + // check if anything was set, and if not set some default stuff + + // check if any marker styles are given + if (fMarkerStyleList.size() == 0) { + fMarkerStyleList.push_back(24); // open circle + fMarkerStyleList.push_back(25); // open square + fMarkerStyleList.push_back(26); // open triangle + fMarkerStyleList.push_back(27); // open diamond + fMarkerStyleList.push_back(28); // open cross + fMarkerStyleList.push_back(29); // full star + fMarkerStyleList.push_back(30); // open star + fMarkerStyleList.push_back(20); // full circle + fMarkerStyleList.push_back(21); // full square + fMarkerStyleList.push_back(22); // full triangle + fMarkerStyleList.push_back(23); // full down triangle + fMarkerStyleList.push_back(2); // thin cross + fMarkerStyleList.push_back(3); // thin star + fMarkerStyleList.push_back(5); // thin cross 45° rotated + } + + // check if any marker ssizes are given + if (fMarkerSizeList.size() == 0) { + fMarkerSizeList.push_back(1.3); + fMarkerSizeList.push_back(1.3); + fMarkerSizeList.push_back(1.5); + fMarkerSizeList.push_back(1.5); + fMarkerSizeList.push_back(1.5); + fMarkerSizeList.push_back(1.5); + fMarkerSizeList.push_back(1.3); + fMarkerSizeList.push_back(1.3); + fMarkerSizeList.push_back(1.5); + fMarkerSizeList.push_back(1.5); + fMarkerSizeList.push_back(1.5); + fMarkerSizeList.push_back(1.5); + fMarkerSizeList.push_back(1.5); + fMarkerSizeList.push_back(1.5); + } + + // check if any colors are given + if (fColorList.size() == 0) { + fColorList.push_back(TColor::GetColor(0, 0, 0)); // kBlack + fColorList.push_back(TColor::GetColor(255, 0, 0)); // kRed + fColorList.push_back(TColor::GetColor(0, 255, 0)); // kGreen + fColorList.push_back(TColor::GetColor(0, 0, 255)); // kBlue + fColorList.push_back(TColor::GetColor(255, 0, 255)); // kMagneta + fColorList.push_back(TColor::GetColor(0, 255, 255)); // kCyan + fColorList.push_back(TColor::GetColor(156, 0, 255)); // kViolette-3 + fColorList.push_back(TColor::GetColor(99, 101, 49)); // kYellow-1 + fColorList.push_back(TColor::GetColor(49, 101, 49)); // kGreen-1 + fColorList.push_back(TColor::GetColor(156, 48, 0)); // kOrange-4 + } +} + +//-------------------------------------------------------------------------- +// StartupFileExists +//-------------------------------------------------------------------------- +/** + *

Checks if a file is present on the disc. + * + * return: + * - true, if the file is present + * - false, otherwise + * + * \param fln file name + */ +Bool_t PMuppStartupHandler::StartupFileExists(Char_t *fln) +{ + Bool_t result = false; + + std::ifstream ifile(fln); + + if (ifile.fail()) { + result = false; + } else { + result = true; + ifile.close(); + } + + return result; +} + diff --git a/src/musredit_qt6/mupp/plotter/PMuppStartupHandler.h b/src/musredit_qt6/mupp/plotter/PMuppStartupHandler.h new file mode 100644 index 00000000..5fd6b76e --- /dev/null +++ b/src/musredit_qt6/mupp/plotter/PMuppStartupHandler.h @@ -0,0 +1,90 @@ +/*************************************************************************** + + PMuppStartupHandler.h + + 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. * + ***************************************************************************/ + +#ifndef _PMUPPSTARTUPHANDLER_H_ +#define _PMUPPSTARTUPHANDLER_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mupp_plot.h" + +//-------------------------------------------------------------------------- +// This function is a replacement for the ParseFile method of TSAXParser. +//-------------------------------------------------------------------------- +int parseXmlFile(TSAXParser*, const char*); + +class PMuppStartupHandler : public TObject, public TQObject +{ +public: + PMuppStartupHandler(); + virtual ~PMuppStartupHandler(); + + virtual void OnStartDocument(); // SLOT + virtual void OnEndDocument(); // SLOT + virtual void OnStartElement(const Char_t*, const TList*); // SLOT + virtual void OnEndElement(const Char_t*); // SLOT + virtual void OnCharacters(const Char_t*); // SLOT + virtual void OnComment(const Char_t*); // SLOT + virtual void OnWarning(const Char_t*); // SLOT + virtual void OnError(const Char_t*); // SLOT + virtual void OnFatalError(const Char_t*); // SLOT + virtual void OnCdataBlock(const Char_t*, Int_t); // SLOT + + virtual Bool_t StartupFileFound() { return fStartupFileFound; } ///< true = mupp_startup.xml found + virtual TString GetStartupFilePath() { return fStartupFilePath; } ///< returns FULLPATH/mupp_startup.xml, where FULLPATH=path were the mupp_startup.xml is found + + virtual void CheckLists(); + + virtual const PIntVector GetMarkerStyleList() const { return fMarkerStyleList; } ///< returns the marker style list + virtual const PDoubleVector GetMarkerSizeList() const { return fMarkerSizeList; } ///< returns the marker size list + virtual const PIntVector GetColorList() const { return fColorList; } ///< returns the color list + +private: + enum EKeyWords {eEmpty, eMarker, eColor}; + EKeyWords fKey; ///< xml filter key + + Bool_t fStartupFileFound; ///< startup file found flag + TString fStartupFilePath; ///< full mupp_startup.xml startup file paths + PIntVector fMarkerStyleList; ///< marker style list + PDoubleVector fMarkerSizeList; ///< marker size list + PIntVector fColorList; ///< color list + + Bool_t StartupFileExists(Char_t *fln); + + ClassDef(PMuppStartupHandler, 1) +}; + +#endif // _PMUPPSTARTUPHANDLER_H_ diff --git a/src/musredit_qt6/mupp/plotter/PMuppStartupHandlerLinkDef.h b/src/musredit_qt6/mupp/plotter/PMuppStartupHandlerLinkDef.h new file mode 100644 index 00000000..a576e83d --- /dev/null +++ b/src/musredit_qt6/mupp/plotter/PMuppStartupHandlerLinkDef.h @@ -0,0 +1,38 @@ +/*************************************************************************** + + PMuppStartupHandlerLinkDef.h + + 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. * + ***************************************************************************/ + +#ifdef __CINT__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class PMuppStartupHandler+; + +#endif diff --git a/src/musredit_qt6/mupp/plotter/mupp_plot.cpp b/src/musredit_qt6/mupp/plotter/mupp_plot.cpp new file mode 100644 index 00000000..a0903432 --- /dev/null +++ b/src/musredit_qt6/mupp/plotter/mupp_plot.cpp @@ -0,0 +1,142 @@ +/*************************************************************************** + + mupp_plot.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 "PMuppStartupHandler.h" +#include "PMuppCanvas.h" + +//-------------------------------------------------------------------------- +/** + * @brief main + * @param argc + * @param argv + * @return + */ +int main(int argc, char *argv[]) +{ + if (argc != 2) { + return -1; + } + int mupp_instance = (int)strtol(argv[1], NULL, 10); + if ((mupp_instance < 0) || (mupp_instance > 255)) { + return -2; + } + + // read startup file + char startup_path_name[128]; + TSAXParser *saxParser = new TSAXParser(); + PMuppStartupHandler *startupHandler = new PMuppStartupHandler(); + if (!startupHandler->StartupFileFound()) { + std::cerr << std::endl << ">> mupp_plot **WARNING** couldn't find " << startupHandler->GetStartupFilePath().Data(); + std::cerr << std::endl; + // clean up + if (saxParser) { + delete saxParser; + saxParser = 0; + } + if (startupHandler) { + delete startupHandler; + startupHandler = 0; + } + } else { + strcpy(startup_path_name, startupHandler->GetStartupFilePath().Data()); + saxParser->ConnectToHandler("PMuppStartupHandler", startupHandler); + // parsing the file as above seems to lead to problems in certain environments; + // use the parseXmlFile function instead (see PMuppStartupHandler.cpp for the definition) + Int_t status = parseXmlFile(saxParser, startup_path_name); + // check for parse errors + if (status) { // error + std::cerr << std::endl << ">> mupp_plot **WARNING** Reading/parsing mupp_startup.xml failed."; + std::cerr << std::endl << ">> Graph will appear with random symbols and colors!"; + std::cerr << std::endl; + // clean up + if (saxParser) { + delete saxParser; + saxParser = 0; + } + if (startupHandler) { + delete startupHandler; + startupHandler = 0; + } + } else { + startupHandler->CheckLists(); + } + } + + TApplication app("App", &argc, argv); + + Bool_t ok=kTRUE; + PMuppCanvas *muppCanvas = new PMuppCanvas("mupp", 10, 10, 600, 800, + startupHandler->GetMarkerStyleList(), + startupHandler->GetMarkerSizeList(), + startupHandler->GetColorList(), + mupp_instance); + + if (muppCanvas != 0) { + if (muppCanvas->IsValid()) { + // connect signal/slot + TQObject::Connect("TCanvas", "Closed()", "PMuppCanvas", muppCanvas, "LastCanvasClosed()"); + muppCanvas->Connect("Done(Int_t)", "TApplication", &app, "Terminate(Int_t)"); + } else { + std::cerr << std::endl << ">> mupp_plot **SEVERE ERROR** invoke object is invalid, will quit."; + std::cerr << std::endl; + ok = false; + } + } else { + std::cerr << std::endl << ">> mupp_plot **SEVERE ERROR** Couldn't invoke all necessary objects, will quit."; + std::cerr << std::endl; + ok = false; + } + + + // check that everything is ok + if (ok) + app.Run(true); // true needed that Run will return after quit so that cleanup works + + // clean up + if (saxParser) { + delete saxParser; + saxParser = 0; + } + if (startupHandler) { + delete startupHandler; + startupHandler = 0; + } + if (muppCanvas) { + delete muppCanvas; + muppCanvas = 0; + } + + return 0; +} diff --git a/src/musredit_qt6/mupp/plotter/mupp_plot.h b/src/musredit_qt6/mupp/plotter/mupp_plot.h new file mode 100644 index 00000000..f24d867a --- /dev/null +++ b/src/musredit_qt6/mupp/plotter/mupp_plot.h @@ -0,0 +1,93 @@ +/*************************************************************************** + + mupp_plot.h + + 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. * + ***************************************************************************/ + +#ifndef _MUPP_PLOT_H_ +#define _MUPP_PLOT_H_ + +#include +#include + +#include +#include + +//------------------------------------------------------------- +/** + *

typedef to make to code more readable. Definition of a bool vector. + */ +typedef std::vector PBoolVector; + +//------------------------------------------------------------- +/** + *

typedef to make to code more readable. Definition of an unsigned int vector + */ +typedef std::vector PUIntVector; + +//------------------------------------------------------------- +/** + *

typedef to make to code more readable. Definition of an int vector + */ +typedef std::vector PIntVector; + +//------------------------------------------------------------- +/** + *

typedef to make to code more readable. Definition of an int pair + */ +typedef std::pair PIntPair; + +//------------------------------------------------------------- +/** + *

typedef to make to code more readable. Definition of an int pair vector + */ +typedef std::vector PIntPairVector; + +//------------------------------------------------------------- +/** + *

typedef to make to code more readable. Definition of a double vector + */ +typedef std::vector PDoubleVector; + +//------------------------------------------------------------- +/** + *

typedef to make to code more readable. Definition of a double pair + */ +typedef std::pair PDoublePair; + +//------------------------------------------------------------- +/** + *

typedef to make to code more readable. Definition of a double pair vector + */ +typedef std::vector PDoublePairVector; + +//------------------------------------------------------------- +/** + *

typedef to make to code more readable. Definition of a string vector + */ +typedef std::vector PStringVector; + +#endif // _MUPP_PLOT_H_ diff --git a/src/musredit_qt6/mupp/var/CMakeLists.txt b/src/musredit_qt6/mupp/var/CMakeLists.txt new file mode 100644 index 00000000..febd4f0a --- /dev/null +++ b/src/musredit_qt6/mupp/var/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(src) diff --git a/src/musredit_qt6/mupp/var/include/PAnnotation.hpp b/src/musredit_qt6/mupp/var/include/PAnnotation.hpp new file mode 100644 index 00000000..4e4467c3 --- /dev/null +++ b/src/musredit_qt6/mupp/var/include/PAnnotation.hpp @@ -0,0 +1,103 @@ +/*************************************************************************** + + PAnnotation.hpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + + Based on Joel de Guzman example on calc7, + see https://github.com/boostorg/spirit + +***************************************************************************/ + +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef _PANNOTATION_HPP_ +#define _PANNOTATION_HPP_ + +#include +#include +#include +#include +#include "PAst.hpp" + +namespace mupp +{ + /////////////////////////////////////////////////////////////////////////////// + // The annotation handler links the AST to a map of iterator positions + // for the purpose of subsequent semantic error handling when the + // program is being compiled. + /////////////////////////////////////////////////////////////////////////////// + template + struct PAnnotation + { + template + struct result { typedef void type; }; + + std::vector& iters; + PAnnotation(std::vector& iters) : iters(iters) {} + + struct set_id + { + typedef void result_type; + + int id; + set_id(int id) : id(id) {} + + template + void operator()(T& x) const + { + this->dispatch(x, boost::is_base_of()); + } + + // This will catch all nodes except those inheriting from ast::tagged + template + void dispatch(T& x, boost::mpl::false_) const + { + // (no-op) no need for tags + } + + // This will catch all nodes inheriting from ast::tagged + template + void dispatch(T& x, boost::mpl::true_) const + { + x.id = id; + } + }; + + void operator()(ast::operand& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + boost::apply_visitor(set_id(id), ast); + } + + void operator()(ast::assignment& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + ast.lhs.id = id; + } + }; +} + +#endif // _PANNOTATION_HPP_ + diff --git a/src/musredit_qt6/mupp/var/include/PAst.hpp b/src/musredit_qt6/mupp/var/include/PAst.hpp new file mode 100644 index 00000000..45c69115 --- /dev/null +++ b/src/musredit_qt6/mupp/var/include/PAst.hpp @@ -0,0 +1,204 @@ +/*************************************************************************** + + PAst.hpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + + Based on Joel de Guzman example on calc7, + see https://github.com/boostorg/spirit + +***************************************************************************/ + +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef _PAST_HPP_ +#define _PAST_HPP_ + +#include +#include +#include +#include +#include +#include + +namespace mupp { namespace ast +{ + /////////////////////////////////////////////////////////////////////////// + // The AST + /////////////////////////////////////////////////////////////////////////// + struct tagged + { + int id; // Used to annotate the AST with the iterator position. + // This id is used as a key to a map + // (not really part of the AST.) + }; + + enum optoken + { + op_plus, + op_minus, + op_times, + op_divide, + op_positive, + op_negative, + }; + + enum funid + { + fun_max, + fun_min, + fun_abs, + fun_sin, + fun_cos, + fun_tan, + fun_sinh, + fun_cosh, + fun_tanh, + fun_asin, + fun_acos, + fun_atan, + fun_exp, + fun_log, + fun_ln, + fun_sqrt + }; + + struct nil {}; + struct unary; + struct expression; + struct function; + struct power; + + struct variable : tagged + { + variable(std::string const& name = "") : name(name) {} + std::string name; + }; + + typedef boost::variant< + nil + , double + , variable + , boost::recursive_wrapper + , boost::recursive_wrapper + , boost::recursive_wrapper + , boost::recursive_wrapper + > + operand; + + struct unary + { + optoken operator_; + operand operand_; + }; + + struct operation + { + optoken operator_; + operand operand_; + }; + + struct expression + { + operand first; + std::list rest; + }; + + struct function + { + funid func_id; + expression arg; + }; + + struct power + { + expression base; + expression pow; + }; + + struct assignment + { + variable lhs; + expression rhs; + }; + + struct variable_declaration + { + variable lhs; + boost::optional rhs; + }; + + typedef boost::variant< + variable_declaration + , assignment> + statement; + + typedef std::list statement_list; + + // print functions for debugging + inline std::ostream& operator<<(std::ostream& out, nil) { out << "nil"; return out; } + inline std::ostream& operator<<(std::ostream& out, variable const& var) { out << var.name; return out; } +}} + +BOOST_FUSION_ADAPT_STRUCT( + mupp::ast::unary, + (mupp::ast::optoken, operator_) + (mupp::ast::operand, operand_) +) + +BOOST_FUSION_ADAPT_STRUCT( + mupp::ast::operation, + (mupp::ast::optoken, operator_) + (mupp::ast::operand, operand_) +) + +BOOST_FUSION_ADAPT_STRUCT( + mupp::ast::expression, + (mupp::ast::operand, first) + (std::list, rest) +) + +BOOST_FUSION_ADAPT_STRUCT( + mupp::ast::function, + (mupp::ast::funid, func_id) + (mupp::ast::expression, arg) +) + +BOOST_FUSION_ADAPT_STRUCT( + mupp::ast::power, + (mupp::ast::expression, base) + (mupp::ast::expression, pow) +) + +BOOST_FUSION_ADAPT_STRUCT( + mupp::ast::variable_declaration, + (mupp::ast::variable, lhs) + (boost::optional, rhs) +) + +BOOST_FUSION_ADAPT_STRUCT( + mupp::ast::assignment, + (mupp::ast::variable, lhs) + (mupp::ast::expression, rhs) +) + +#endif // _PAST_HPP_ diff --git a/src/musredit_qt6/mupp/var/include/PErrorHandler.hpp b/src/musredit_qt6/mupp/var/include/PErrorHandler.hpp new file mode 100644 index 00000000..7c127ed2 --- /dev/null +++ b/src/musredit_qt6/mupp/var/include/PErrorHandler.hpp @@ -0,0 +1,118 @@ +/*************************************************************************** + + PErrorHandler.hpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + + Based on Joel de Guzman example on calc7, + see https://github.com/boostorg/spirit + +***************************************************************************/ + +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef _PERROR_HANDLER_HPP_ +#define _PERROR_HANDLER_HPP_ + +#include +#include +#include +#include + +namespace mupp +{ + /////////////////////////////////////////////////////////////////////////////// + // The error handler + /////////////////////////////////////////////////////////////////////////////// + template + struct PErrorHandler + { + template + struct result { typedef void type; }; + + PErrorHandler(Iterator first, Iterator last) + : first(first), last(last) {} + + template + void operator()( + Message const& message, + What const& what, + Iterator err_pos) const + { + int line; + Iterator line_start = get_pos(err_pos, line); + const char *homeStr = getenv("HOME"); + char fln[1024]; + sprintf(fln, "%s/.musrfit/mupp/mupp_err.log", homeStr); + std::ofstream fout(fln, std::ofstream::app); + if (err_pos != last) { + fout << message << what << ':' << std::endl; + fout << get_line(line_start) << std::endl; + for (; line_start != err_pos; ++line_start) + fout << ' '; + fout << "^~~" << std::endl; + } else { + fout << "**ERROR** Unexpected end of file. "; + fout << message << what << " line " << line << std::endl; + } + } + + Iterator get_pos(Iterator err_pos, int& line) const + { + line = 1; + Iterator i = first; + Iterator line_start = first; + while (i != err_pos) { + bool eol = false; + if (i != err_pos && *i == '\r') { // CR + eol = true; + line_start = ++i; + } + if (i != err_pos && *i == '\n') { // LF + eol = true; + line_start = ++i; + } + if (eol) + ++line; + else + ++i; + } + return line_start; + } + + std::string get_line(Iterator err_pos) const + { + Iterator i = err_pos; + // position i to the next EOL + while (i != last && (*i != '\r' && *i != '\n')) + ++i; + return std::string(err_pos, i); + } + + Iterator first; + Iterator last; + std::vector iters; + }; +} + +#endif //_PERROR_HANDLER_HPP_ + diff --git a/src/musredit_qt6/mupp/var/include/PExpression.hpp b/src/musredit_qt6/mupp/var/include/PExpression.hpp new file mode 100644 index 00000000..f8d3de0e --- /dev/null +++ b/src/musredit_qt6/mupp/var/include/PExpression.hpp @@ -0,0 +1,83 @@ +/*************************************************************************** + + PExpression.hpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + + Based on Joel de Guzman example on calc7, + see https://github.com/boostorg/spirit + +***************************************************************************/ + +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef _PEXPRESSION_HPP_ +#define _PEXPRESSION_HPP_ + +/////////////////////////////////////////////////////////////////////////////// +// Spirit v2.5 allows you to suppress automatic generation +// of predefined terminals to speed up complation. With +// BOOST_SPIRIT_NO_PREDEFINED_TERMINALS defined, you are +// responsible in creating instances of the terminals that +// you need (e.g. see qi::uint_type uint_ below). +#define BOOST_SPIRIT_NO_PREDEFINED_TERMINALS +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment this if you want to enable debugging +// #define BOOST_SPIRIT_QI_DEBUG +/////////////////////////////////////////////////////////////////////////////// + +#include +#include "PAst.hpp" +#include "PErrorHandler.hpp" +#include "PSkipper.hpp" +#include + +namespace mupp { namespace parser +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + + /////////////////////////////////////////////////////////////////////////////// + // The expression grammar + /////////////////////////////////////////////////////////////////////////////// + template + struct PExpression : qi::grammar > + { + PExpression(PErrorHandler& error_handler); + + qi::symbols additive_op, multiplicative_op, unary_op; + qi::symbols fun_tok; + + qi::rule > expr; + qi::rule > additive_expr; + qi::rule > multiplicative_expr; + qi::rule > unary_expr; + qi::rule > primary_expr; + qi::rule > identifier; + }; +}} + +#endif // _PEXPRESSION_HPP_ + + diff --git a/src/musredit_qt6/mupp/var/include/PExpressionDef.hpp b/src/musredit_qt6/mupp/var/include/PExpressionDef.hpp new file mode 100644 index 00000000..125df780 --- /dev/null +++ b/src/musredit_qt6/mupp/var/include/PExpressionDef.hpp @@ -0,0 +1,162 @@ +/*************************************************************************** + + PExpressionDef.hpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + + Based on Joel de Guzman example on calc7, + see https://github.com/boostorg/spirit + +***************************************************************************/ + +/*************************************************************************** + * Copyright (C) 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 "PExpression.hpp" +#include "PErrorHandler.hpp" +#include "PAnnotation.hpp" +#include + +namespace mupp { namespace parser +{ + template + PExpression::PExpression(PErrorHandler& error_handler) + : PExpression::base_type(expr) + { + qi::_1_type _1; + qi::_2_type _2; + qi::_3_type _3; + qi::_4_type _4; + + qi::char_type char_; + qi::double_type double_; + qi::_val_type _val; + qi::raw_type raw; + qi::lexeme_type lexeme; + qi::alpha_type alpha; + qi::alnum_type alnum; + + using qi::on_error; + using qi::on_success; + using qi::fail; + using boost::phoenix::function; + + typedef function > error_handler_function; + typedef function > annotation_function; + + /////////////////////////////////////////////////////////////////////// + // Tokens + additive_op.add + ("+", ast::op_plus) + ("-", ast::op_minus) + ; + + multiplicative_op.add + ("*", ast::op_times) + ("/", ast::op_divide) + ; + + unary_op.add + ("+", ast::op_positive) + ("-", ast::op_negative) + ; + + fun_tok.add + ("max", ast::fun_max) + ("min", ast::fun_min) + ("abs", ast::fun_abs) + ("sin", ast::fun_sin) + ("cos", ast::fun_cos) + ("tan", ast::fun_tan) + ("sinh", ast::fun_sinh) + ("cosh", ast::fun_cosh) + ("tanh", ast::fun_tanh) + ("asin", ast::fun_asin) + ("acos", ast::fun_acos) + ("atan", ast::fun_atan) + ("exp", ast::fun_exp) + ("log", ast::fun_log) + ("ln", ast::fun_ln) + ("sqrt", ast::fun_sqrt) + ; + + /////////////////////////////////////////////////////////////////////// + // Grammar + expr = + additive_expr.alias() + ; + + additive_expr = + multiplicative_expr + >> *(additive_op > multiplicative_expr) + ; + + multiplicative_expr = + unary_expr + >> *(multiplicative_op > unary_expr) + ; + + unary_expr = + primary_expr + | (unary_op > primary_expr) + ; + + primary_expr = + double_ + | identifier + | fun_tok > '(' > expr > ')' + | "pow(" > expr > ',' > expr > ')' + | '(' > expr > ')' + ; + + identifier = + raw[lexeme['$' >> *(alnum | '_')]] + ; + + // name all the rules + additive_expr.name("additive_expr"); + multiplicative_expr.name("multiplicative_expr"); + unary_expr.name("unary_expr"); + primary_expr.name("primary_expr"); + identifier.name("identifier"); + + // Debugging and error handling and reporting support. + BOOST_SPIRIT_DEBUG_NODES( + (expr) + (additive_expr) + (multiplicative_expr) + (unary_expr) + (primary_expr) + (identifier) + ); + + // Error handling: on error in expr, call error_handler. + on_error(expr, + error_handler_function(error_handler)( + "**ERROR** Expecting ", _4, _3)); + + // Annotation: on success in primary_expr, call annotation. + on_success(primary_expr, + annotation_function(error_handler.iters)(_val, _1)); + } +}} + + diff --git a/src/musredit_qt6/mupp/var/include/PProgram.hpp b/src/musredit_qt6/mupp/var/include/PProgram.hpp new file mode 100644 index 00000000..0eaa2aa1 --- /dev/null +++ b/src/musredit_qt6/mupp/var/include/PProgram.hpp @@ -0,0 +1,159 @@ +/*************************************************************************** + + PProgram.hpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + + Based on Joel de Guzman example on calc7, + see https://github.com/boostorg/spirit + +***************************************************************************/ + +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef _PPROGRAM_HPP_ +#define _PPROGRAM_HPP_ + +#include +#include +#include + +#include "PAst.hpp" +#include "PErrorHandler.hpp" + +#include +#include +#include +#include +#include + +namespace mupp { namespace prog { + /////////////////////////////////////////////////////////////////////////// + // Variable Handler + /////////////////////////////////////////////////////////////////////////// + class PVarHandler + { + public: + PVarHandler() : fName("") {} + + void SetName(std::string name) { fName = name; } + void SetValue(std::vector &dval) { fValue = dval; } + void SetValue(double dval, unsigned idx); + void SetError(std::vector &dval) { fError = dval; } + void SetError(double dval, unsigned idx); + + std::string GetName() { return fName; } + unsigned int GetSize() { return (fValue.size() == fError.size()) ? fValue.size() : 0; } + std::vector GetValue() { return fValue; } + double GetValue(unsigned int idx) { return (idx < fValue.size()) ? fValue[idx] : 0; } + std::vector GetError() { return fError; } + double GetError(unsigned int idx) { return (idx < fError.size()) ? fError[idx] : 0; } + + private: + std::string fName; + std::vector fValue; + std::vector fError; + }; + + /////////////////////////////////////////////////////////////////////////// + // Program Semantic Analysis + /////////////////////////////////////////////////////////////////////////// + struct PProgram + { + typedef bool result_type; + + template + PProgram(PErrorHandler& error_handler_) + { + using namespace boost::phoenix::arg_names; + namespace phx = boost::phoenix; + using boost::phoenix::function; + error_handler = function(error_handler_)( + "**ERROR** ", _2, phx::cref(error_handler_.iters)[_1]); + } + + bool operator()(ast::nil) { BOOST_ASSERT(0); return false; } + bool operator()(double x); + bool operator()(ast::assignment const &x); + bool operator()(ast::expression const &x); + bool operator()(ast::function const &x); + bool operator()(ast::operation const &x); + bool operator()(ast::power const &x); + bool operator()(ast::statement const &x); + bool operator()(ast::statement_list const &x); + bool operator()(ast::unary const &x); + bool operator()(ast::variable const &x); + bool operator()(ast::variable_declaration const &x); + + void add_predef_var_values(const std::string &name, + std::vector &val, + std::vector &err); + + void add_var(std::string const& name); + bool find_var(std::string const &name); + bool find_var(std::string const &name, unsigned int &idx); + std::string pos_to_var(std::string const &name, bool &ok); + + std::vector getVars() { return fVariable; } + + private: + std::vector fVariable; + std::map fVarPos; + + boost::function< + void(int tag, std::string const& what)> + error_handler; + }; + + /////////////////////////////////////////////////////////////////////////// + // Program Evaluation + /////////////////////////////////////////////////////////////////////////// + struct PProgEval + { + typedef std::vector result_type; + + PProgEval(std::vector var) : fVariable(var) {} + + std::vector operator()(ast::nil); + std::vector operator()(double x); + std::vector operator()(ast::assignment const &x); + std::vector operator()(ast::expression const &x); + std::vector operator()(ast::function const &x); + std::vector operator()(ast::operation const &x, std::vector lhs); + std::vector operator()(ast::power const &x); + std::vector operator()(ast::statement const &x); + std::vector operator()(ast::statement_list const &x); + std::vector operator()(ast::unary const &x); + std::vector operator()(ast::variable const &x); + std::vector operator()(ast::variable_declaration const &x); + + PVarHandler getVar(const std::string name, bool &ok); + void print_result(); + + private: + std::vector fVariable; + + unsigned int find_var(std::string const &name); + }; +}} + +#endif // _PPROGRAM_HPP_ diff --git a/src/musredit_qt6/mupp/var/include/PSkipper.hpp b/src/musredit_qt6/mupp/var/include/PSkipper.hpp new file mode 100644 index 00000000..5a8d103b --- /dev/null +++ b/src/musredit_qt6/mupp/var/include/PSkipper.hpp @@ -0,0 +1,73 @@ +/*************************************************************************** + + PSkipper.hpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + + Based on Joel de Guzman example on a mini_c, + see https://github.com/boostorg/spirit + +***************************************************************************/ + +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef _PSKIPPER_HPP_ +#define _PSKIPPER_HPP_ + +#include + +namespace mupp { namespace parser +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + + /////////////////////////////////////////////////////////////////////////////// + // The skipper grammar + /////////////////////////////////////////////////////////////////////////////// + template + struct PSkipper : qi::grammar + { + PSkipper() : PSkipper::base_type(start) + { + qi::char_type char_; + qi::lit_type lit; + qi::eol_type eol; + ascii::space_type space; + ascii::print_type print; + + single_line_comment = (lit('%') | lit('#') | lit("//")) >> *print >> eol; + + start = + space // tab/space/cr/lf + | "/*" >> *(char_ - "*/") >> "*/" // C-style comments + | single_line_comment + ; + } + + qi::rule single_line_comment; + qi::rule start; + }; +}} + +#endif // _PSKIPPER_HPP_ + + diff --git a/src/musredit_qt6/mupp/var/include/PStatement.hpp b/src/musredit_qt6/mupp/var/include/PStatement.hpp new file mode 100644 index 00000000..ccf5e7f9 --- /dev/null +++ b/src/musredit_qt6/mupp/var/include/PStatement.hpp @@ -0,0 +1,58 @@ +/*************************************************************************** + + PStatement.hpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + + Based on Joel de Guzman example on calc7, + see https://github.com/boostorg/spirit + +***************************************************************************/ + +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#ifndef _PSTATEMENT_HPP_ +#define _PSTATEMENT_HPP_ + +#include "PExpression.hpp" + +namespace mupp { namespace parser +{ + /////////////////////////////////////////////////////////////////////////////// + // The statement grammar + /////////////////////////////////////////////////////////////////////////////// + template + struct PStatement : qi::grammar > + { + PStatement(PErrorHandler& error_handler); + + PExpression expr; + qi::rule > statement_list; + qi::rule > variable_declaration; + qi::rule > assignment; + qi::rule > identifier; + }; +}} + +#endif // _PSTATEMENT_HPP_ + + diff --git a/src/musredit_qt6/mupp/var/include/PStatementDef.hpp b/src/musredit_qt6/mupp/var/include/PStatementDef.hpp new file mode 100644 index 00000000..0d114e3a --- /dev/null +++ b/src/musredit_qt6/mupp/var/include/PStatementDef.hpp @@ -0,0 +1,107 @@ +/*************************************************************************** + + PStatementDef.hpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + + Based on Joel de Guzman example on calc7, + see https://github.com/boostorg/spirit + +***************************************************************************/ + +/*************************************************************************** + * Copyright (C) 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 "PStatement.hpp" +#include "PErrorHandler.hpp" +#include "PAnnotation.hpp" + +namespace mupp { namespace parser +{ + template + PStatement::PStatement(PErrorHandler& error_handler) + : PStatement::base_type(statement_list), expr(error_handler) + { + qi::_1_type _1; + qi::_2_type _2; + qi::_3_type _3; + qi::_4_type _4; + + qi::_val_type _val; + qi::raw_type raw; + qi::lexeme_type lexeme; + qi::alpha_type alpha; + qi::alnum_type alnum; + + using qi::on_error; + using qi::on_success; + using qi::fail; + using boost::phoenix::function; + + typedef function > error_handler_function; + typedef function > annotation_function; + + statement_list = + +(variable_declaration | assignment) + ; + + identifier = + raw[lexeme[(alpha | '_') >> *(alnum | '_')]] + ; + + variable_declaration = + lexeme["var" >> !(alnum | '_')] // make sure we have whole words + > identifier + > -('=' > expr) + ; + + assignment = + identifier + > '=' + > expr + ; + + // name all the rules + statement_list.name("statement_list"); + identifier.name("identifier"); + variable_declaration.name("variable_declaration"); + assignment.name("assignment"); + + // Debugging and error handling and reporting support. + BOOST_SPIRIT_DEBUG_NODES( + (statement_list) + (identifier) + (variable_declaration) + (assignment) + ); + + // Error handling: on error in statement_list, call error_handler. + on_error(statement_list, + error_handler_function(error_handler)( + "**ERROR** Expecting ", _4, _3)); + + // Annotation: on success in assignment, call annotation. + on_success(assignment, + annotation_function(error_handler.iters)(_val, _1)); + } +}} + + diff --git a/src/musredit_qt6/mupp/var/include/PVarHandler.h b/src/musredit_qt6/mupp/var/include/PVarHandler.h new file mode 100644 index 00000000..2ba4f1c9 --- /dev/null +++ b/src/musredit_qt6/mupp/var/include/PVarHandler.h @@ -0,0 +1,69 @@ +/*************************************************************************** + + PVarHandler.h + + 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. * + ***************************************************************************/ + +#ifndef _PVARHANDLER_H_ +#define _PVARHANDLER_H_ + +#include +#include + +#include + +#include "Pmupp.h" +#include "PAst.hpp" +#include "PProgram.hpp" + +class PVarHandler { + public: + PVarHandler(); + PVarHandler(PmuppCollection *coll, std::string parse_str, std::string var_name=""); + + bool isValid() { return fIsValid; } + QString getCollName() { return fColl->GetName(); } + QString getVarName() { return QString(fVarName.c_str()); } + std::vector getValues(); + std::vector getErrors(); + + private: + PmuppCollection *fColl; ///< collection needed for parsing and evaluation + std::string fParseStr; ///< the variable input to be parsed + std::string fVarName; ///< variable name + mupp::prog::PVarHandler fVar; ///< values of the evaluation + + bool fIsValid; + mupp::ast::statement_list fAst; ///< the AST + + void injectPredefVariables(); + + std::string getVarName(int idx); + std::vector getData(int idx); + std::vector getDataErr(int idx); +}; + +#endif //_PVARHANDLER_H_ diff --git a/src/musredit_qt6/mupp/var/src/CMakeLists.txt b/src/musredit_qt6/mupp/var/src/CMakeLists.txt new file mode 100644 index 00000000..90abf78f --- /dev/null +++ b/src/musredit_qt6/mupp/var/src/CMakeLists.txt @@ -0,0 +1,7 @@ +target_sources(mupp + PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/PVarHandler.cpp + ${CMAKE_CURRENT_LIST_DIR}/PExpression.cpp + ${CMAKE_CURRENT_LIST_DIR}/PProgram.cpp + ${CMAKE_CURRENT_LIST_DIR}/PStatement.cpp +) diff --git a/src/musredit_qt6/mupp/var/src/PExpression.cpp b/src/musredit_qt6/mupp/var/src/PExpression.cpp new file mode 100644 index 00000000..351b5145 --- /dev/null +++ b/src/musredit_qt6/mupp/var/src/PExpression.cpp @@ -0,0 +1,40 @@ +/*************************************************************************** + + PExpression.hpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + + Based on Joel de Guzman example on calc7, + see https://github.com/boostorg/spirit + +***************************************************************************/ + +/*************************************************************************** + * Copyright (C) 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. * + ***************************************************************************/ + +#if defined(_MSC_VER) +# pragma warning(disable: 4345) +#endif + +#include "PExpressionDef.hpp" + +typedef std::string::const_iterator iterator_type; +template struct mupp::parser::PExpression; diff --git a/src/musredit_qt6/mupp/var/src/PProgram.cpp b/src/musredit_qt6/mupp/var/src/PProgram.cpp new file mode 100644 index 00000000..290761d4 --- /dev/null +++ b/src/musredit_qt6/mupp/var/src/PProgram.cpp @@ -0,0 +1,702 @@ +/*************************************************************************** + + PProgram.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + + Based on Joel de Guzman example on calc7, + see https://github.com/boostorg/spirit + +***************************************************************************/ + +/*************************************************************************** + * Copyright (C) 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 "PProgram.hpp" + +#include +#include +#include +#include +#include +#include + +namespace mupp { namespace prog { + void PVarHandler::SetValue(double dval, unsigned idx) + { + if (idx >= fValue.size()) { + std::cerr << "**ERROR** SetValue: idx=" << idx << " is out-of-range." << std::endl; + return; + } + fValue[idx] = dval; + } + + void PVarHandler::SetError(double dval, unsigned idx) + { + if (idx >= fError.size()) { + std::cerr << "**ERROR** SetError: idx=" << idx << " is out-of-range." << std::endl; + return; + } + fError[idx] = dval; + } + + bool PProgram::operator()(double x) + { + return true; + } + + bool PProgram::operator()(ast::assignment const &x) + { + // check that the variable exists + if (!find_var(x.lhs.name)) { + error_handler(0, "Undeclared variable: " + x.lhs.name); + return false; + } + + if (!(*this)(x.rhs)) { + std::cout << "**SEM ERROR** in var assignment of var: " << x.lhs.name << std::endl; + std::cout << " rhs is missing or has an error." << std::endl; + return false; + } + + return true; + } + + bool PProgram::operator()(ast::expression const &x) + { + if (!boost::apply_visitor(*this, x.first)) + return false; + + BOOST_FOREACH(ast::operation const& oper, x.rest) { + if (!(*this)(oper)) + return false; + } + + return true; + } + + bool PProgram::operator()(ast::function const &x) + { + switch (x.func_id) { + case ast::fun_max: + case ast::fun_min: + case ast::fun_abs: + case ast::fun_sin: + case ast::fun_cos: + case ast::fun_tan: + case ast::fun_sinh: + case ast::fun_cosh: + case ast::fun_tanh: + case ast::fun_asin: + case ast::fun_acos: + case ast::fun_atan: + case ast::fun_exp: + case ast::fun_log: + case ast::fun_ln: + case ast::fun_sqrt: + break; + default: + BOOST_ASSERT(0); + return false; + } + + if (!(*this)(x.arg)) { + std::cout << "**SEM ERROR** in function: arg is missing or has an error." << std::endl; + return false; + } + + return true; + } + + bool PProgram::operator()(ast::operation const &x) + { + if (!boost::apply_visitor(*this, x.operand_)) + return false; + + switch (x.operator_) { + case ast::op_plus: + break; + case ast::op_minus: + break; + case ast::op_times: + break; + case ast::op_divide: + break; + case ast::op_positive: + break; + case ast::op_negative: + break; + default: + BOOST_ASSERT(0); + return false; + } + + return true; + } + + bool PProgram::operator()(ast::power const &x) + { + if (!(*this)(x.base)) { + std::cout << "**SEM ERROR** in power: base argument is missing or has an error." << std::endl; + return false; + } + + if (!(*this)(x.pow)) { + std::cout << "**SEM ERROR** in power: power argument is missing or has an error." << std::endl; + return false; + } + + return true; + } + + bool PProgram::operator()(ast::statement const &x) + { + return boost::apply_visitor(*this, x); + } + + bool PProgram::operator()(ast::statement_list const &x) + { + BOOST_FOREACH(ast::statement const& s, x) { + if (!(*this)(s)) + return false; + } + return true; + } + + bool PProgram::operator()(ast::unary const &x) + { + if (!boost::apply_visitor(*this, x.operand_)) + return false; + + switch (x.operator_) { + case ast::op_negative: + break; + case ast::op_positive: + break; + default: + BOOST_ASSERT(0); + return false; + } + + return true; + } + + bool PProgram::operator()(ast::variable const &x) + { + bool ok(false); + std::string var_name; + + var_name = pos_to_var(x.name, ok); + if (!ok) { + error_handler(0, "Position variable out-of-range: " + x.name); + return false; + } + + if (!find_var(var_name)) { + error_handler(0, "Undeclared variable: " + var_name); + return false; + } + + return true; + } + + bool PProgram::operator()(ast::variable_declaration const &x) + { + if (find_var(x.lhs.name)) { + error_handler(0, "Duplicate variable: " + x.lhs.name); + return false; + } + + if (x.rhs) { // if there's a RHS initializer + bool r = (*this)(*x.rhs); + if (r) { // don't add the variable if the RHS fails + add_var(x.lhs.name); + } else { + std::cout << "**SEM ERROR** rhs of var decl, name: " << x.lhs.name << ", failed" << std::endl; + return r; + } + } else { + add_var(x.lhs.name); + } + + return true; + } + + void PProgram::add_predef_var_values(const std::string &name, + std::vector &val, + std::vector &err) + { + unsigned int idx; + if (!find_var(name, idx)) { + std::cerr << "**ERROR** couldn't find pre-def variable : " << name << std::endl; + return; + } + + fVariable[idx].SetValue(val); + fVariable[idx].SetError(err); + } + + void PProgram::add_var(std::string const& name) + { + PVarHandler var; + var.SetName(name); + fVariable.push_back(var); + // add map var <-> pos + std::size_t n = fVarPos.size(); + fVarPos[n] = name; + } + + bool PProgram::find_var(std::string const &name) + { + unsigned int idx; + return find_var(name, idx); + } + + bool PProgram::find_var(std::string const &name, unsigned int &idx) + { + bool result=false; + + // remove leading '$' of identifier + std::string id(""); + if (name[0] == '$') + id = name.substr(1); + else + id = name; + + for (unsigned int i=0; i= fVarPos.size()) + ok = false; + else + result = fVarPos[num]; + } + + return result; + } + + + std::vector PProgEval::operator()(ast::nil) + { + std::vector result; + result.resize(fVariable[0].GetSize()); + + for (unsigned int i=0; i PProgEval::operator()(double x) + { + std::vector result; + result.resize(fVariable[0].GetSize()); + + for (unsigned int i=0; i PProgEval::operator()(ast::assignment const &x) + { + std::vector result; + result.resize(fVariable[0].GetSize()); + + result = (*this)(x.rhs); + + // keep all data under not Err. + // Err data go to error, whereas + // data go to value + std::string name = x.lhs.name; + bool errorVal(false); + + // check for error variable + std::size_t pos = name.find("Err"); + if (pos != std::string::npos) { // it is an error variable + name = name.substr(0, pos); + errorVal = true; + } + + unsigned int idx = find_var(name); + if (errorVal) + fVariable[idx].SetError(result); + else + fVariable[idx].SetValue(result); + + return result; + } + + std::vector PProgEval::operator()(ast::expression const &x) + { + std::vector vec = boost::apply_visitor(*this, x.first); + + BOOST_FOREACH(ast::operation const& oper, x.rest) { + vec = (*this)(oper, vec); + } + return vec; + } + + std::vector PProgEval::operator()(ast::function const &x) + { + std::vector vec = (*this)(x.arg); + + double dval; + switch(x.func_id) { + case ast::fun_max: + dval = -1.0e10; + for (unsigned int i=0; i dval) + dval = vec[i]; + } + for (unsigned int i=0; i PProgEval::operator()(ast::operation const &x, std::vector lhs) + { + std::vector rhs = boost::apply_visitor(*this, x.operand_); + + // make sure both vectors have the same size + if (lhs.size() != rhs.size()) { + BOOST_ASSERT(0); + return lhs; + } + + switch (x.operator_) { + case ast::op_plus: + for (unsigned int i=0; i PProgEval::operator()(ast::power const &x) + { + std::vector baseV = (*this)(x.base); + std::vector powV = (*this)(x.pow); + + if (baseV.size() != powV.size()) { + BOOST_ASSERT(0); + return baseV; + } + + std::vector result; + result.resize(baseV.size()); + for (unsigned int i=0; i PProgEval::operator()(ast::statement const &x) + { + // as35: not-yet-implemented + std::vector result; + result.resize(fVariable[0].GetSize()); + + for (unsigned int i=0; i PProgEval::operator()(ast::statement_list const &x) + { + // as35: not-yet-implemented + std::vector result; + result.resize(fVariable[0].GetSize()); + + for (unsigned int i=0; i PProgEval::operator()(ast::unary const &x) + { + std::vector vec = boost::apply_visitor(*this, x.operand_); + + if (x.operator_ == ast::op_negative) { + for (unsigned int i=0; i PProgEval::operator()(ast::variable const &x) + { + std::string name = x.name; + bool errorVal(false); + + // check for injected error variable + std::size_t pos = name.find("Err"); + if (pos != std::string::npos) { // it is an error variable + name = name.substr(0, pos); + errorVal = true; + } + + unsigned idx = find_var(name); + + if (errorVal) + return fVariable[idx].GetError(); + else + return fVariable[idx].GetValue(); + } + + std::vector PProgEval::operator()(ast::variable_declaration const &x) + { + std::vector result; + result.resize(fVariable[0].GetSize()); + + // keep all data under not Err. + // Err data go to error, whereas + // data go to value + std::string name = x.lhs.name; + bool errorVal(false); + + // check for error variable + std::size_t pos = name.find("Err"); + if (pos != std::string::npos) { // it is an error variable + name = name.substr(0, pos); + errorVal = true; + } + + unsigned int idx = find_var(name); + + if (x.rhs) { // if there's a RHS initializer + result = (*this)(*x.rhs); + } else { + // injected variable content + if (errorVal) + result = fVariable[idx].GetError(); + else + result = fVariable[idx].GetValue(); + } + + if (errorVal) + fVariable[idx].SetError(result); + else + fVariable[idx].SetValue(result); + + return result; + } + + unsigned int PProgEval::find_var(std::string const &name) + { + // remove leading '$' of identifier + std::string id(""); + if (name[0] == '$') + id = name.substr(1); + else + id = name; + + unsigned idx = 0; + for (unsigned int i=0; i val, err; + for (unsigned int i=0; i; diff --git a/src/musredit_qt6/mupp/var/src/PVarHandler.cpp b/src/musredit_qt6/mupp/var/src/PVarHandler.cpp new file mode 100644 index 00000000..af0c0710 --- /dev/null +++ b/src/musredit_qt6/mupp/var/src/PVarHandler.cpp @@ -0,0 +1,212 @@ +/*************************************************************************** + + PVarHandler.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 "PVarHandler.h" + +#include "PSkipper.hpp" +#include "PErrorHandler.hpp" +#include "PStatement.hpp" +#include "PProgram.hpp" + +//-------------------------------------------------------------------------- +/** + * @brief PVarHandler::PVarHandler + */ +PVarHandler::PVarHandler() : + fColl(nullptr), fParseStr(""), fVarName(""), fIsValid(false) +{ + // nothing to be done here +} + +//-------------------------------------------------------------------------- +/** + * @brief PVarHandler::PVarHandler + */ +PVarHandler::PVarHandler(PmuppCollection *coll, std::string parse_str, std::string var_name) : + fColl(coll), fParseStr(parse_str), fVarName(var_name), fIsValid(false) +{ + injectPredefVariables(); + + typedef std::string::const_iterator iterator_type; + iterator_type iter = fParseStr.begin(); + iterator_type end = fParseStr.end(); + + mupp::PErrorHandler error_handler(iter, end); // the error handler + mupp::parser::PStatement parser(error_handler); // the parser + mupp::prog::PProgram prog(error_handler); // our compiler, and exec + mupp::parser::PSkipper skipper; // the skipper parser + + // perform the parsing + bool success = phrase_parse(iter, end, parser, skipper, fAst); + if (success && iter == end) { + if (prog(fAst)) { // semantic analysis + std::vector data, dataErr; + for (unsigned int i=0; iGetRun(0).GetNoOfParam(); i++) { + data = getData(i); + dataErr = getDataErr(i); + prog.add_predef_var_values(getVarName(i), data, dataErr); + } + if (!fVarName.empty()) { + mupp::prog::PProgEval eval(prog.getVars()); // setup evaluation stage + eval(fAst); // evaluate stuff + + // keep data + bool ok; + fVar = eval.getVar(fVarName, ok); + if (!ok) { + std::cerr << "**ERROR** evalution failed..." << std::endl; + fIsValid = false; + } + } + } + fIsValid = true; + } else { + std::cerr << "**ERROR** parsing failed..." << std::endl; + } +} + +//-------------------------------------------------------------------------- +/** + * @brief PVarHandler::getValues + * @return + */ +std::vector PVarHandler::getValues() +{ + std::vector data; + if (fIsValid) + data = fVar.GetValue(); + + return data; +} + +//-------------------------------------------------------------------------- +/** + * @brief PVarHandler::getErrors + * @return + */ +std::vector PVarHandler::getErrors() +{ + std::vector data; + if (fIsValid) + data = fVar.GetError(); + + return data; +} + +//-------------------------------------------------------------------------- +/** + * @brief PVarHandler::injectPredefVariables + */ +void PVarHandler::injectPredefVariables() +{ + mupp::ast::statement var_stat; + mupp::ast::variable_declaration var; + + std::string varName, errVarName; + PmuppRun run = fColl->GetRun(0); + for (int i=0; i= fColl->GetRun(0).GetNoOfParam()) + return name; + + return fColl->GetRun(0).GetParam(idx).GetName().toLatin1().data(); +} + +//-------------------------------------------------------------------------- +/** + * @brief PVarHandler::getData + * @param idx + * @return + */ +std::vector PVarHandler::getData(int idx) +{ + std::vector data; + + // make sure idx is in range + if (idx >= fColl->GetRun(0).GetNoOfParam()) + return data; + + double dval; + for (int i=0; iGetNoOfRuns(); i++) { + dval = fColl->GetRun(i).GetParam(idx).GetValue(); + data.push_back(dval); + } + + return data; +} + +//-------------------------------------------------------------------------- +/** + * @brief PVarHandler::getDataErr + * @param idx + * @return + */ +std::vector PVarHandler::getDataErr(int idx) +{ + std::vector err; + + // make sure idx is in range + if (idx >= fColl->GetRun(0).GetNoOfParam()) + return err; + + double dvalPos, dvalNeg; + for (int i=0; iGetNoOfRuns(); i++) { + dvalPos = fColl->GetRun(i).GetParam(idx).GetPosErr(); + dvalNeg = fColl->GetRun(i).GetParam(idx).GetNegErr(); + dvalPos = sqrt(fabs(dvalPos*dvalNeg)); // geometric mean of pos/neg error + err.push_back(dvalPos); + } + + return err; +} diff --git a/src/musredit_qt6/musrStep/CMakeLists.txt b/src/musredit_qt6/musrStep/CMakeLists.txt new file mode 100644 index 00000000..95e8af95 --- /dev/null +++ b/src/musredit_qt6/musrStep/CMakeLists.txt @@ -0,0 +1,75 @@ +#--- musrStep for Qt > 6.0 ---------------------------------------------------- + +set(qt_libs Qt6::Core Qt6::Widgets Qt6::Svg) + +set(musrStep_src + PMusrStep.cpp + musrStep.cpp +) + +# Instruct CMake to run moc automatically when needed +set(CMAKE_AUTOMOC ON) + +#[==[ +# as35 currently CMAKE_AUTOUIC -> ON doesn't work since it requires the ui-files +# in the same directory as the cpp-files. +# Create code from a list of Qt designer ui files +set(CMAKE_AUTOUIC ON) +#]==] +set(CMAKE_AUTOUIC OFF) + +# add qt/rcc +qt6_add_resources(musrStep_rcc musrStep.qrc) + +# remove generated files from automoc and autouic +set_property(SOURCE qrc_musrStep.cpp PROPERTY SKIP_AUTOMOC ON) + +set(macosx_icon icons/musrStep.icns) +if (APPLE) + add_executable(musrStep MACOSX_BUNDLE + ${musrStep_src} + ${musrStep_rcc} + ${macosx_icon} + ) +else (APPLE) + add_executable(musrStep + ${musrStep_src} + ${musrStep_rcc} + ) +endif (APPLE) + +target_include_directories(musrStep + BEFORE PRIVATE + $ + $ + $ + $ + $ +) + +target_link_libraries(musrStep ${qt_libs}) + +#--- installation info -------------------------------------------------------- +if (APPLE) + set_target_properties(musrStep PROPERTIES + MACOSX_BUNDLE TRUE + MACOSX_BUNDLE_BUNDLE_NAME "musrStep" + MACOSX_BUNDLE_INFO_STRING "musrfit: musrStep allows to reset/set the initial step size of a msr-files." + MACOSX_BUNDLE_ICON_FILE "musrStep.icns" + MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_VERSION}" + MACOSX_BUNDLE_GUI_IDENTIFIER "ch.psi.lmu.musrStep" + MACOSX_BUNDLE_COPYRIGHT "Andreas Suter" + RESOURCE ${macosx_icon} + ) +endif (APPLE) + +if (APPLE) + install( TARGETS musrStep + BUNDLE DESTINATION /Applications + ) +else (APPLE) + install( TARGETS musrStep + RUNTIME DESTINATION bin + ) +endif (APPLE) + diff --git a/src/musredit_qt6/musrStep/LICENSE b/src/musredit_qt6/musrStep/LICENSE new file mode 100644 index 00000000..53503fbf --- /dev/null +++ b/src/musredit_qt6/musrStep/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + musrStep_qt5 + Copyright (C) 2016 Andreas Suter + + 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 3 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, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + musrStep_qt5 Copyright (C) 2016 Andreas Suter + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/src/musredit_qt6/musrStep/PMusrStep.cpp b/src/musredit_qt6/musrStep/PMusrStep.cpp new file mode 100644 index 00000000..92feba83 --- /dev/null +++ b/src/musredit_qt6/musrStep/PMusrStep.cpp @@ -0,0 +1,623 @@ +/*************************************************************************** + + PMusrStep.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +***************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2007-2021 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 "PMusrStep.h" + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/** + * + */ +PModSelect::PModSelect(QWidget *parent) : + QDialog(parent) +{ + setWindowTitle("Modify Selected"); + + fScaleByFactor = new QPushButton("Scale by &Factor"); + fScaleByFactor->setWhatsThis("if pressed it will use the Factor value, and the absolut value selection to change the selected parameter steps."); + fFactorLabel = new QLabel("Factor"); + fFactorLineEdit = new QLineEdit("0.01"); + fFactorLineEdit->setValidator(new QDoubleValidator); + fAbsVal = new QCheckBox("Absolute Value"); + fAbsVal->setWhatsThis("if checked, the factor is used as an absolut value rather than a multiplication factor for the selected steps."); + + QHBoxLayout *top = new QHBoxLayout; + top->addWidget(fScaleByFactor); + top->addWidget(fFactorLabel); + top->addWidget(fFactorLineEdit); + top->addWidget(fAbsVal); + + fScaleAutomatic = new QPushButton("Scale &Automatically"); + fScaleAutomatic->setWhatsThis("Will try to reset the step size of the selected items based on some crude rules"); + fCancel = new QPushButton("&Cancel"); + + QHBoxLayout *bottom = new QHBoxLayout; + bottom->addWidget(fScaleAutomatic); + bottom->addWidget(fCancel); + + QVBoxLayout *main = new QVBoxLayout; + main->addLayout(top); + main->addLayout(bottom); + + setLayout(main); + + connect(fAbsVal, SIGNAL(stateChanged(int)), this, SLOT(absoluteValueStateChanged(int))); + connect(fScaleAutomatic, SIGNAL(pressed()), this, SLOT(scaleAuto())); + connect(fScaleByFactor, SIGNAL(pressed()), this, SLOT(getFactor())); + connect(fCancel, SIGNAL(pressed()), this, SLOT(reject())); +} + +//------------------------------------------------------------------------- +/** + * @brief PModSelect::absoluteValueStateChanged + * @param ival + */ +void PModSelect::absoluteValueStateChanged(int ival) +{ + if (ival == Qt::Unchecked) { + fFactorLabel->setText("Factor"); + fScaleByFactor->setText("Scale by &Factor"); + } else if (ival == Qt::Checked) { + fFactorLabel->setText("Value"); + fScaleByFactor->setText("Set Abs. Value"); + } +} + +//------------------------------------------------------------------------- +/** + * + */ +void PModSelect::scaleAuto() +{ + emit scale(true, 0.01, false); + done(1); +} + +//------------------------------------------------------------------------- +/** + * + */ +void PModSelect::getFactor() +{ + double factor = fFactorLineEdit->text().toDouble(); + bool state = fAbsVal->isChecked(); + + emit scale(false, factor, state); + done(1); +} + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/** + * + */ +PMusrStep::PMusrStep(const char *fln, QWidget *parent) : + QDialog(parent), + fMsrFileName(fln) +{ + setWindowTitle("musrStep"); + QString str = QIcon::themeName(); + bool isDarkTheme = false; + if (str.contains("dark", Qt::CaseInsensitive)) + isDarkTheme = true; + + if (isDarkTheme) + str = QString(":/icons/musrStep-22x22-dark.svg"); + else + str = QString(":/icons/musrStep-22x22.svg"); + setWindowIcon(QIcon(QPixmap(str))); + + fValid = false; + + QString title = QString("%1").arg(fMsrFileName); + fTitleLabel = new QLabel(title); + QLabel *icon = new QLabel(); + if (isDarkTheme) + str = QString(":/icons/musrStep-32x32-dark.svg"); + else + str = QString(":/icons/musrStep-32x32.svg"); + icon->setPixmap(QPixmap(str)); + + QHBoxLayout *titleLayout = new QHBoxLayout; + titleLayout->addWidget(fTitleLabel); + titleLayout->addWidget(icon); + titleLayout->insertStretch(1); + + int status = 0; + if ((status=readMsrFile()) == 1) { + fValid = true; + } else { + QString msg = QString("Failed to read msr-file: %1 (status=%2)").arg(fMsrFileName).arg(status); + QMessageBox::critical(0, "ERROR", msg); + } + + int height; + if (fParamVec.size() < 70) + height = 20*fParamVec.size(); + else + height = 900; + setMinimumSize(400, height); + + // populate dialog + fParamTable = new QTableWidget(fParamVec.size(), 3); + QStringList strL; + strL << "name" << "value" << "step"; + fParamTable->setHorizontalHeaderLabels(strL); + + QTableWidgetItem *item; + for (int i=0; isetFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable); + item->setCheckState(Qt::Unchecked); + fParamTable->setItem(i, 0, item); + item = new QTableWidgetItem(fParamVec[i].value); + item->setFlags(Qt::ItemIsEnabled); + fParamTable->setItem(i, 1, item); + item = new QTableWidgetItem(fParamVec[i].step); + fParamTable->setItem(i, 2, item); + } + fCheckSpecific = new QPushButton("Check S&pecific"); + fCheckSpecific->setWhatsThis("Allows to specify a template name which is used\nto select parameter names fitting to it."); + fCheckAll = new QPushButton("Check A&ll"); + fCheckAll->setWhatsThis("Select all parameter names,\nexcept the ones with step == 0"); + fUnCheckAll = new QPushButton("&Uncheck All"); + fUnCheckAll->setWhatsThis("Unselect all parameter names"); + + QHBoxLayout *checkLayout = new QHBoxLayout; + checkLayout->addWidget(fCheckSpecific); + checkLayout->addWidget(fCheckAll); + checkLayout->addWidget(fUnCheckAll); + + fModifyAuto = new QPushButton("Modify &Automatic"); + fModifyAuto->setWhatsThis("Will try to reset the step size,\nbased on some crude rules"); + fModifyAuto->setDefault(true); + fModifySelected = new QPushButton("&Modify Selected"); + fModifySelected->setWhatsThis("Will call a dialog which all to specify how\nto proceed with the selected parameter steps."); + + QHBoxLayout *modifyLayout = new QHBoxLayout; + modifyLayout->addWidget(fModifyAuto); + modifyLayout->addWidget(fModifySelected); + + fSave = new QPushButton("&Save&&Quit"); + fCancel = new QPushButton("&Cancel"); + + QHBoxLayout *buttomLayout = new QHBoxLayout; + buttomLayout->addWidget(fSave); + buttomLayout->addWidget(fCancel); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addLayout(titleLayout); + mainLayout->addWidget(fParamTable); + mainLayout->addLayout(checkLayout); + mainLayout->addLayout(modifyLayout); + mainLayout->addLayout(buttomLayout); + + setLayout(mainLayout); + + connect(fParamTable, SIGNAL(cellChanged(int, int)), this, SLOT(handleCellChanged(int, int))); + + connect(fCheckSpecific, SIGNAL(pressed()), this, SLOT(checkSpecific())); + connect(fCheckAll, SIGNAL(pressed()), this, SLOT(checkAll())); + connect(fUnCheckAll, SIGNAL(pressed()), this, SLOT(unCheckAll())); + + connect(fModifyAuto, SIGNAL(pressed()), this, SLOT(modifyAuto())); + connect(fModifySelected, SIGNAL(pressed()), this, SLOT(modifyChecked())); + connect(fSave, SIGNAL(pressed()), this, SLOT(saveAndQuit())); + connect(fCancel, SIGNAL(pressed()), this, SLOT(reject())); + + fModSelect = new PModSelect(this); + connect(fModSelect, SIGNAL(scale(bool,double,bool)), this, SLOT(handleModSelect(bool,double,bool))); +} + +//------------------------------------------------------------------------- +/** + * + */ +void PMusrStep::handleCellChanged(int row, int column) +{ + QString str; + bool ok; + if (column == 0) { + str = fParamTable->item(row, 2)->text(); + if ((fParamTable->item(row, column)->checkState() == Qt::Checked) && + ((str == "0") || (str == "0.0"))) { + fParamTable->item(row, column)->setCheckState(Qt::Unchecked); + QMessageBox::warning(0, "WARNING", "You cannot select a fixed value (step == 0)."); + } + } else if (column == 2) { + str = fParamTable->item(row, column)->text(); + str.toDouble(&ok); // result is of no interest + if (ok) { + fParamVec[row].step = str; + } else { + fParamTable->item(row, column)->setText(fParamVec[row].step); + } + } +} + +//------------------------------------------------------------------------- +/** + * + */ +void PMusrStep::checkSpecific() +{ + bool ok; + QString str = QInputDialog::getText(this, "Enter Param Name Template", "Template:", + QLineEdit::Normal, "", &ok); + if (!ok) + return; + + QString step(""); + for (int i=0; irowCount(); i++) { + if (fParamTable->item(i,0)->text().contains(str)) { + step = fParamTable->item(i,2)->text(); + if ((step != "0") && (step != "0.0")) + fParamTable->item(i,0)->setCheckState(Qt::Checked); + } + } +} + +//------------------------------------------------------------------------- +/** + * + */ +void PMusrStep::checkAll() +{ + QString str(""); + for (int i=0; irowCount(); i++) { + str = fParamTable->item(i,2)->text(); + if ((str != "0") && (str != "0.0")) + fParamTable->item(i,0)->setCheckState(Qt::Checked); + } +} + +//------------------------------------------------------------------------- +/** + * + */ +void PMusrStep::unCheckAll() +{ + for (int i=0; irowCount(); i++) { + fParamTable->item(i,0)->setCheckState(Qt::Unchecked); + } +} + +//------------------------------------------------------------------------- +/** + * + */ +void PMusrStep::modifyAuto() +{ + QString str; + bool absVal; + double factor; + for (int i=0; irowCount(); i++) { + str = fParamTable->item(i,2)->text(); + if ((str != "0") && (str != "0.0")) { + factor = lookupTable(fParamTable->item(i,0)->text(), absVal); + str = adoptStep(fParamTable->item(i,1)->text(), factor, absVal); + fParamTable->item(i,2)->setText(str); + fParamVec[i].step = str; + } + } +} + +//------------------------------------------------------------------------- +/** + * + */ +void PMusrStep::modifyChecked() +{ + fModSelect->show(); +} + +//------------------------------------------------------------------------- +/** + * + */ +void PMusrStep::handleModSelect(bool automatic, double factor, bool absVal) +{ + QString str; + for (int i=0; irowCount(); i++) { + if (fParamTable->item(i,0)->checkState() == Qt::Checked) { + if (automatic) { + factor = lookupTable(fParamTable->item(i,0)->text(), absVal); + } + str = adoptStep(fParamTable->item(i,1)->text(), factor, absVal); + fParamTable->item(i,2)->setText(str); + fParamVec[i].step = str; + } + } +} + +//------------------------------------------------------------------------- +/** + * + */ +void PMusrStep::saveAndQuit() +{ + writeMsrFile(); + accept(); +} + +//------------------------------------------------------------------------- +/** + * + */ +void PMusrStep::initParam(PParam ¶m) +{ + param.number = ""; + param.name = ""; + param.value = ""; + param.step = ""; + param.posErr = ""; + param.boundLow = ""; + param.boundHigh = ""; +} + +//------------------------------------------------------------------------- +/** + * + */ +double PMusrStep::lookupTable(const QString str, bool &absVal) +{ + double factor = 0.01; + absVal = false; + + if (str.startsWith("freq", Qt::CaseInsensitive) || + str.startsWith("frq", Qt::CaseInsensitive) || + str.startsWith("field", Qt::CaseInsensitive)) { + factor = 1.0e-3; + } else if (str.startsWith("lambda", Qt::CaseInsensitive) || + str.startsWith("sigma", Qt::CaseInsensitive) || + str.startsWith("rlx", Qt::CaseInsensitive) || + str.startsWith("rate", Qt::CaseInsensitive)) { + factor = 0.1; + } else if (str.startsWith("phase", Qt::CaseInsensitive) || + str.startsWith("phs", Qt::CaseInsensitive)) { + factor = 5.0; + absVal = true; + } else if (str.startsWith("N0", Qt::CaseInsensitive) || + str.startsWith("Nrm", Qt::CaseInsensitive) || + str.startsWith("N_bkg", Qt::CaseInsensitive) || + str.startsWith("Bgr", Qt::CaseInsensitive)) { + factor = 0.01; + } + + return factor; +} + +//------------------------------------------------------------------------- +/** + * + */ +QString PMusrStep::adoptStep(const QString str, double factor, bool absVal) +{ + bool ok; + double dval = str.toDouble(&ok); + + QString step(""); + if (absVal) + step = QString("%1").arg(factor); + else + step = QString("%1").arg(factor*dval); + + return step; +} + +//------------------------------------------------------------------------- +/** + * + */ +int PMusrStep::readMsrFile() +{ + fParamVec.clear(); + + QFile fin(fMsrFileName); + + if (!fin.open(QIODevice::ReadOnly|QIODevice::Text)) + return -1; + + bool done = false, parameter = false; + QByteArray line; + QString str; + QStringList strL; + PParam param; + + while(!done && !fin.atEnd()) { + line = fin.readLine(); + str = line.data(); + str = str.trimmed(); + if (str.isEmpty() || str.startsWith("#")) { + continue; + } else if (str.startsWith("FITPARAMETER")) { + parameter = true; + continue; + } else if (str.startsWith("THEORY")) { + done = true; + continue; + } + + if (parameter) { + strL = str.split(" ", Qt::SkipEmptyParts); + if ((strL.size() != 5) && (strL.size() != 7)) { + fin.close(); + return -2; + } + initParam(param); + + param.number = strL[0]; + param.name = strL[1]; + param.value = strL[2]; + param.step = strL[3]; + param.posErr = strL[4]; + if (strL.size() == 7) { + param.boundLow = strL[5]; + param.boundHigh= strL[6]; + } + fParamVec.push_back(param); + } + } + + fin.close(); + + return 1; +} + +//------------------------------------------------------------------------- +/** + * + */ +int PMusrStep::writeMsrFile() +{ + // read whole msr-file + QFile fin(fMsrFileName); + + if (!fin.open(QIODevice::ReadOnly|QIODevice::Text)) + return -1; + + QByteArray data = fin.readAll(); + + fin.close(); + + QFile fileOut(fMsrFileName); + + if (!fileOut.open(QIODevice::WriteOnly|QIODevice::Text)) + return -2; + + QTextStream fout(&fileOut); + + int idx = 0; + QString line, paramLine; + bool done = false; + bool paramBlock = false; + do { + line = getLine(data, idx); + if ((idx == -1) || (idx == data.count())) { + done = true; + } else { + if (line.startsWith("FITPARAMETER")) { + paramBlock = true; + } else if (line.startsWith("THEORY")) { + paramBlock = false; + } + if (paramBlock) { + paramLine = updateParamLine(line); + if (paramLine == "") // comment line, etc. + fout << line << "\n"; + else + fout << paramLine << "\n"; + } else { + fout << line << "\n"; + } + } + } while (!done); + fout << "*** FIT DID NOT CONVERGE ***\n"; + + fileOut.close(); + + return 1; +} + +//------------------------------------------------------------------------- +/** + * + */ +QString PMusrStep::getLine(QByteArray &data, int &idx) +{ + int newIdx = data.indexOf('\n', idx); + QString line(""); + + if (newIdx != -1) { + line = data.mid(idx, newIdx-idx).data(); + idx = newIdx+1; + } + + return line; +} + +//------------------------------------------------------------------------- +/** + * + */ +QString PMusrStep::updateParamLine(const QString str) +{ + // find proper parameter index + int idx = -1; + QString paramStr; + for (int i=0; i= 12) + width = fParamVec[idx].name.length()+1; + ss.setFieldWidth(width); + ss << fParamVec[idx].name; + ss.setFieldWidth(11); + ss << fParamVec[idx].value; + ss << fParamVec[idx].step; + ss << fParamVec[idx].posErr; + if (fParamVec[idx].boundLow != "") { + ss << fParamVec[idx].boundLow; + ss << fParamVec[idx].boundHigh; + } + + return result; +} diff --git a/src/musredit_qt6/musrStep/PMusrStep.h b/src/musredit_qt6/musrStep/PMusrStep.h new file mode 100644 index 00000000..aa60ec59 --- /dev/null +++ b/src/musredit_qt6/musrStep/PMusrStep.h @@ -0,0 +1,122 @@ +/*************************************************************************** + + PMusrStep.h + + 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. * + ***************************************************************************/ + +#ifndef _PMUSRSTEP_H_ +#define _PMUSRSTEP_H_ + +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + QString number; + QString name; + QString value; + QString step; + QString posErr; + QString boundLow; + QString boundHigh; +} PParam; + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +class PModSelect : public QDialog +{ + Q_OBJECT + + public: + PModSelect(QWidget *parent=Q_NULLPTR); + + signals: + void scale(bool automatic, double factor, bool absVal); + + private slots: + void absoluteValueStateChanged(int); + void scaleAuto(); + void getFactor(); + + private: + QCheckBox *fAbsVal; + QLabel *fFactorLabel; + QLineEdit *fFactorLineEdit; + QPushButton *fScaleByFactor; + QPushButton *fScaleAutomatic; + QPushButton *fCancel; +}; + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +class PMusrStep : public QDialog +{ + Q_OBJECT + + public: + PMusrStep(const char *fln, QWidget *parent=Q_NULLPTR); + bool isValid() { return fValid; } + + private slots: + void handleCellChanged(int row, int column); + void checkSpecific(); + void checkAll(); + void unCheckAll(); + void modifyAuto(); + void modifyChecked(); + void saveAndQuit(); + void handleModSelect(bool automatic, double factor, bool absVal); + + private: + QString fMsrFileName; + bool fValid; + + QVector fParamVec; + + QLabel *fTitleLabel; + QTableWidget *fParamTable; + QPushButton *fCheckSpecific; + QPushButton *fCheckAll; + QPushButton *fUnCheckAll; + QPushButton *fModifyAuto; + QPushButton *fModifySelected; + QPushButton *fSave; + QPushButton *fCancel; + + PModSelect *fModSelect; + + void initParam(PParam ¶m); + double lookupTable(const QString str, bool &absVal); + QString adoptStep(const QString str, double factor, bool absVal); + int readMsrFile(); + int writeMsrFile(); + QString getLine(QByteArray &data, int &idx); + QString updateParamLine(const QString str); +}; + +#endif // _PMUSRSTEP_H_ diff --git a/src/musredit_qt6/musrStep/README.md b/src/musredit_qt6/musrStep/README.md new file mode 100644 index 00000000..e4ed1aea --- /dev/null +++ b/src/musredit_qt6/musrStep/README.md @@ -0,0 +1,2 @@ +musrStep helps to intelligently reset the steps of a msr-file after a fit. +Often this is needed for refinement purposes. \ No newline at end of file diff --git a/src/musredit_qt6/musrStep/icons/musrStep-22x22-dark.svg b/src/musredit_qt6/musrStep/icons/musrStep-22x22-dark.svg new file mode 100644 index 00000000..a4855a18 --- /dev/null +++ b/src/musredit_qt6/musrStep/icons/musrStep-22x22-dark.svg @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musrStep/icons/musrStep-22x22.svg b/src/musredit_qt6/musrStep/icons/musrStep-22x22.svg new file mode 100644 index 00000000..0532ca29 --- /dev/null +++ b/src/musredit_qt6/musrStep/icons/musrStep-22x22.svg @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musrStep/icons/musrStep-32x32-dark.svg b/src/musredit_qt6/musrStep/icons/musrStep-32x32-dark.svg new file mode 100644 index 00000000..b7a44516 --- /dev/null +++ b/src/musredit_qt6/musrStep/icons/musrStep-32x32-dark.svg @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musrStep/icons/musrStep-32x32.svg b/src/musredit_qt6/musrStep/icons/musrStep-32x32.svg new file mode 100644 index 00000000..a0c6dbe1 --- /dev/null +++ b/src/musredit_qt6/musrStep/icons/musrStep-32x32.svg @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musrStep/icons/musrStep.icns b/src/musredit_qt6/musrStep/icons/musrStep.icns new file mode 100644 index 00000000..4a14ce55 Binary files /dev/null and b/src/musredit_qt6/musrStep/icons/musrStep.icns differ diff --git a/src/musredit_qt6/musrStep/musrStep.cpp b/src/musredit_qt6/musrStep/musrStep.cpp new file mode 100644 index 00000000..b2314b26 --- /dev/null +++ b/src/musredit_qt6/musrStep/musrStep.cpp @@ -0,0 +1,57 @@ +#include +#include + +#include + +#include + +#include "git-revision.h" +#include "PMusrStep.h" + +//------------------------------------------------------------------------- +void musrStep_syntax() +{ + std::cout << std::endl; + std::cout << "usage: musrStep | [-v | --version] | [-h | --help]" << std::endl; + std::cout << " : msr-file name." << std::endl; + std::cout << " -v, --version: print the current git-version to the stdout" << std::endl; + std::cout << " -h, --help: print this help" << std::endl; + std::cout << std::endl << std::endl; +} + +//------------------------------------------------------------------------- +int main(int argc, char *argv[]) +{ + char fln[1024]; + + if (argc != 2) { + musrStep_syntax(); + return 1; + } else { + if (!strcmp(argv[1], "--version") || (!strcmp(argv[1], "-v"))) { + std::cout << std::endl << "musrStep git-rev: " << GIT_CURRENT_SHA1 << std::endl << std::endl; + return 0; + } else if (!strcmp(argv[1], "--help") || (!strcmp(argv[1], "-h"))) { + musrStep_syntax(); + return 0; + } else { + strncpy(fln, argv[1], sizeof(fln)); + } + } + + Q_INIT_RESOURCE(musrStep); + + QApplication app(argc, argv); + + PMusrStep musrStep(fln); + if (!musrStep.isValid()) + return 1; + + musrStep.show(); + + app.exec(); + + int result = musrStep.result(); + + return result; +} diff --git a/src/musredit_qt6/musrStep/musrStep.pro b/src/musredit_qt6/musrStep/musrStep.pro new file mode 100644 index 00000000..daedf7c5 --- /dev/null +++ b/src/musredit_qt6/musrStep/musrStep.pro @@ -0,0 +1,75 @@ +TEMPLATE = app +TARGET = musrStep + +# install path for musrStep via given prefix +count( PREFIX, 1 ) { + MUSRSTEP_INSTALL_PATH = $${PREFIX}/bin +} +isEmpty( MUSRSTEP_INSTALL_PATH ) { + MUSR_FIT_PATH = $$(MUSRFITPATH) + count( MUSR_FIT_PATH, 1) { + MUSRSTEP_INSTALL_PATH = $$(MUSRFITPATH) + } +} +isEmpty( MUSRSTEP_INSTALL_PATH ) { + ROOT_SYS_PATH = $$(ROOTSYS) + count( ROOT_SYS_PATH, 1) { + MUSRSTEP_INSTALL_PATH = $$(ROOTSYS)/bin + } +} +isEmpty( MUSRSTEP_INSTALL_PATH ) { + MUSRSTEP_INSTALL_PATH = /usr/local/bin +} + +exists( /usr/bin/cygwin1.dll ) { + QMAKE_CXXFLAGS += -D_WIN32GCC + QMAKE_LFLAGS_APP = -Wl,--enable-auto-import +} + +isEmpty( CC ) { + CC = gcc +} + +isEmpty( CXX ) { + CXX = g++ +} + +QMAKE_CC = $${CC} +QMAKE_CXX = $${CXX} +QMAKE_LINK = $${CXX} + +# set proper permission for Mac OSX +macx { + QMAKE_INSTALL_FILE = install -m 6755 -p -o $$(USER) -g staff +} + +# install path for the application +unix { + message( "Determined installation path: $${MUSRSTEP_INSTALL_PATH}" ) +} + +unix:target.path = $${MUSRSTEP_INSTALL_PATH} +macx:target.path = /Applications +win32:target.path = c:/musrfit/bin + +INSTALLS += target + +CONFIG += qt \ + warn_on \ + release \ + console + +QT += widgets +QT += svg + +INCLUDEPATH += "../../include" + +HEADERS = ../../include/git-revision.h \ + PMusrStep.h + +SOURCES = PMusrStep.cpp \ + musrStep.cpp + +RESOURCES = musrStep.qrc + +macx:ICON = icons/musrStep.icns diff --git a/src/musredit_qt6/musrStep/musrStep.qrc b/src/musredit_qt6/musrStep/musrStep.qrc new file mode 100644 index 00000000..24bbe5af --- /dev/null +++ b/src/musredit_qt6/musrStep/musrStep.qrc @@ -0,0 +1,8 @@ + + + icons/musrStep-22x22.svg + icons/musrStep-22x22-dark.svg + icons/musrStep-32x32.svg + icons/musrStep-32x32-dark.svg + + diff --git a/src/musredit_qt6/musrWiz/CMakeLists.txt b/src/musredit_qt6/musrWiz/CMakeLists.txt new file mode 100644 index 00000000..c8511825 --- /dev/null +++ b/src/musredit_qt6/musrWiz/CMakeLists.txt @@ -0,0 +1,78 @@ +#--- musrWiz for Qt > 6.0 ----------------------------------------------------- + +set(qt_libs Qt6::Core Qt6::Widgets Qt6::Svg Qt6::Xml) + +set(musrWiz_src + PTheoTemplate.cpp + PMusrfitFunc.cpp + PInstrumentDef.cpp + PAdmin.cpp + PMusrWiz.cpp + musrWiz.cpp +) + +# Instruct CMake to run moc automatically when needed +set(CMAKE_AUTOMOC ON) + +#[==[ +# as35 currently CMAKE_AUTOUIC -> ON doesn't work since it requires the ui-files +# in the same directory as the cpp-files. +# Create code from a list of Qt designer ui files +set(CMAKE_AUTOUIC ON) +#]==] +set(CMAKE_AUTOUIC OFF) + +# add qt/rcc +qt6_add_resources(musrWiz_rcc musrWiz.qrc) + +# remove generated files from automoc and autouic +set_property(SOURCE qrc_musrWiz.cpp PROPERTY SKIP_AUTOMOC ON) + +set(macosx_icon icons/musrWiz.icns) +if (APPLE) + add_executable(musrWiz MACOSX_BUNDLE + ${musrWiz_src} + ${musrWiz_rcc} + ${macosx_icon} + ) +else (APPLE) + add_executable(musrWiz + ${musrWiz_src} + ${musrWiz_rcc} + ) +endif (APPLE) + +target_include_directories(musrWiz + BEFORE PRIVATE + $ + $ + $ + $ + $ +) + +target_link_libraries(musrWiz ${qt_libs}) + +#--- installation info -------------------------------------------------------- +if (APPLE) + set_target_properties(musrWiz PROPERTIES + MACOSX_BUNDLE TRUE + MACOSX_BUNDLE_BUNDLE_NAME "musrWiz" + MACOSX_BUNDLE_INFO_STRING "musrfit: musrWiz allows to create input msr-files if no templates are available." + MACOSX_BUNDLE_ICON_FILE "musrWiz.icns" + MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_VERSION}" + MACOSX_BUNDLE_GUI_IDENTIFIER "ch.psi.lmu.musrWiz" + MACOSX_BUNDLE_COPYRIGHT "Andreas Suter" + RESOURCE ${macosx_icon} + ) +endif (APPLE) + +if (APPLE) + install( TARGETS musrWiz + BUNDLE DESTINATION /Applications + ) +else (APPLE) + install( TARGETS musrWiz + RUNTIME DESTINATION bin + ) +endif (APPLE) diff --git a/src/musredit_qt6/musrWiz/PAdmin.cpp b/src/musredit_qt6/musrWiz/PAdmin.cpp new file mode 100644 index 00000000..92d20603 --- /dev/null +++ b/src/musredit_qt6/musrWiz/PAdmin.cpp @@ -0,0 +1,1305 @@ +/**************************************************************************** + + PAdmin.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2010-2021 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 +using namespace std; + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "PAdmin.h" + +//-------------------------------------------------------------------------- +// implementation of PFuncXMLParser class +//-------------------------------------------------------------------------- +/** + *

XML Parser class for the musrWiz function file. + * + * \param admin pointer to an admin class instance. + */ +PFuncXMLParser::PFuncXMLParser(const QString& fln, PAdmin *admin) : fAdmin(admin) +{ + fValid = false; + fKeyWord = eEmpty; + + QFile file(fln); + if (!file.open(QFile::ReadOnly | QFile::Text)) { + // warning and create default - STILL MISSING + } + + fValid = parse(&file); +} + +//-------------------------------------------------------------------------- +/** + *

parse musrfit_funcs.xml + * + * \param device QFile object of musrfit_funcs.xml + * + * @return true on success, false otherwise + */ +bool PFuncXMLParser::parse(QIODevice *device) +{ + fXml.setDevice(device); + + bool expectChars = false; + while (!fXml.atEnd()) { + fXml.readNext(); + if (fXml.isStartDocument()) { + startDocument(); + } else if (fXml.isStartElement()) { + startElement(); + expectChars = true; + } else if (fXml.isCharacters() && expectChars) { + characters(); + } else if (fXml.isEndElement()) { + endElement(); + expectChars = false; + } else if (fXml.isEndDocument()) { + endDocument(); + } + } + if (fXml.hasError()) { + QString msg; + msg = QString("%1 Line %2, column %3").arg(fXml.errorString()).arg(fXml.lineNumber()).arg(fXml.columnNumber()); + QMessageBox::critical(0, "**ERROR**", msg, QMessageBox::Ok, QMessageBox::NoButton); + return false; + } + + return true; +} + +//-------------------------------------------------------------------------- +/** + *

Routine called at the beginning of the XML parsing process. + */ +bool PFuncXMLParser::startDocument() +{ + // nothing to be done here for now + return true; +} + +//-------------------------------------------------------------------------- +/** + *

Routine called when a new XML tag is found. Here it is used + * to set a tag for filtering afterwards the content. + */ +bool PFuncXMLParser::startElement() +{ + QString qName = fXml.name().toString(); + QString str; + + QString errMsg(""); + int ival; + double dval; + bool ok; + + if (qName == "theo_template") { + fTheoTemplate.init(); + } else if (qName == "pre_def_name") { + fKeyWord = eTemplateName; + } else if (qName == "theory") { + fKeyWord = eTemplateTheo; + } else if (qName == "theo_fun") { + fKeyWord = eTemplateFunc; + } else if (qName == "theo_map") { + QXmlStreamAttributes qAttr = fXml.attributes(); + if (qAttr.count() != 2) { + errMsg = QString("theo_map should have 2 attributes, called 'no', and 'name', found %1").arg(qAttr.count()); + QMessageBox::critical(0, "ERROR", errMsg); + return false; + } + PParam map; + // get map number + str = qAttr.value("no").toString(); + ival = str.toInt(&ok); + if (!ok) { + errMsg = QString("theo_map attribute 'no' is not a number (%1)").arg(str); + QMessageBox::critical(0, "ERROR", errMsg); + return false; + } + map.setNumber(ival); + // get map name + str = qAttr.value("name").toString(); + map.setName(str); + + // check that all necessary attributes where found + if ((map.getName() == "UnDef") || (map.getNumber() == -1)) { + errMsg = QString("found theo_map with missing attribute(s)"); + QMessageBox::critical(0, "ERROR", errMsg); + return false; + } + fTheoTemplate.appendMap(map); + } else if (qName == "template_param") { + QXmlStreamAttributes qAttr = fXml.attributes(); + if ((qAttr.count() != 4) && (qAttr.count() != 6)) { + errMsg = QString("template_param should have 4 or 6 attributes, called\n'no', 'name', 'value', 'step', ['boundLow', 'boundHigh'] found %1").arg(qAttr.count()); + QMessageBox::critical(0, "ERROR", errMsg); + return false; + } + PParam param; + // parameter number + str = qAttr.value("no").toString(); + ival = str.toInt(&ok); + if (!ok) { + errMsg = QString("template_param attribute 'no' is not a number (%1)").arg(str); + QMessageBox::critical(0, "ERROR", errMsg); + return false; + } + param.setNumber(ival); + // parameter name + str = qAttr.value("name").toString(); + param.setName(str); + // parameter value + str = qAttr.value("value").toString(); + dval = str.toDouble(&ok); + if (!ok) { + errMsg = QString("template_param attribute 'value' is not a number (%1)").arg(str); + QMessageBox::critical(0, "ERROR", errMsg); + return false; + } + param.setValue(dval); + // parameter step + str = qAttr.value("step").toString(); + dval = str.toDouble(&ok); + if (!ok) { + errMsg = QString("template_param attribute 'step' is not a number (%1)").arg(str); + QMessageBox::critical(0, "ERROR", errMsg); + return false; + } + param.setStep(dval); + // parameter lower bound + str = qAttr.value("boundLow").toString(); + if (!str.isEmpty()) + param.setBoundLow(str); + // parameter upper bound + str = qAttr.value("boundHigh").toString(); + if (!str.isEmpty()) + param.setBoundHigh(str); + fTheoTemplate.appendParam(param); + } else if (qName == "func") { + fFunc.initFunc(); + } else if (qName == "name") { + fKeyWord = eName; + } else if (qName == "abbrv") { + fKeyWord = eAbbrv; + } else if (qName == "no_of_parameters") { + fKeyWord = eNoOfParam; + } else if (qName == "parameter") { + fParam.initParam(); + } else if (qName == "param_name") { + fKeyWord = eParamName; + } else if (qName == "param_value") { + fKeyWord = eParamValue; + } else if (qName == "param_is_map") { + fKeyWord = eParamMap; + } + + return true; +} + +//-------------------------------------------------------------------------- +/** + *

Routine called when the end XML tag is found. It is used to + * put the filtering tag to 'empty'. It also resets the fFunc flag in case + * the entry was a theory function. + */ +bool PFuncXMLParser::endElement() +{ + fKeyWord = eEmpty; + + QString qName = fXml.name().toString(); + + if (qName == "theo_template") { + fAdmin->fTheoTemplate.push_back(fTheoTemplate); + } else if (qName == "func") { + fAdmin->fMusrfitFunc.push_back(fFunc); + } else if (qName == "parameter") { + fFunc.addFuncParam(fParam); + } + + return true; +} + +//-------------------------------------------------------------------------- +/** + *

This routine delivers the content of an XML tag. It fills the + * content into the load data structure. + */ +bool PFuncXMLParser::characters() +{ + QString str = fXml.text().toString(); + if (str.isEmpty()) + return true; + + bool ok; + int ival; + double dval; + + switch (fKeyWord) { + case eTemplateName: + fTheoTemplate.setName(str); + break; + case eTemplateTheo: + fTheoTemplate.setTheory(str); + break; + case eTemplateFunc: + fTheoTemplate.appendFunc(str); + break; + case eName: + fFunc.setName(str); + break; + case eAbbrv: + fFunc.setAbbrv(str); + break; + case eNoOfParam: + ival = str.toInt(&ok); + if (ok) + fFunc.setNoOfParam(ival); + break; + case eParamName: + fParam.setParamName(str); + break; + case eParamValue: + dval = str.toDouble(&ok); + if (ok) + fParam.setParamValue(dval); + break; + case eParamMap: + if ((str == "y") || (str == "yes") || (str == "1")) + fParam.setParamMap(true); + break; + default: + break; + } + + return true; +} + +//-------------------------------------------------------------------------- +/** + *

Called at the end of the XML parse process. It checks if default paths + * contain system variables, and if so expand them for the further use. + */ +bool PFuncXMLParser::endDocument() +{ + return true; +} + +//-------------------------------------------------------------------------- +// implementation of PInstrumentDefXMLParser class +//-------------------------------------------------------------------------- +/** + *

XML Parser class for the instrument definition file(s). + * + * \param file name of the instrument definition file(s). + * \param admin pointer to an admin class instance. + */ +PInstrumentDefXMLParser::PInstrumentDefXMLParser(const QString& fln, PAdmin *admin) : fAdmin(admin) +{ + fValid = false; + fKeyWord = eEmpty; + + fInstituteName = ""; + fInstrument = 0; + fSetup = 0; + + QFile file(fln); + if (!file.open(QFile::ReadOnly | QFile::Text)) { + // warning and create default - STILL MISSING + } + + fValid = parse(&file); +} + +//-------------------------------------------------------------------------- +/** + *

parse the instrument definition xml-file(s). + * + * \param device QFile object of the instrument definition xml-file(s). + * + * @return true on success, false otherwise + */ +bool PInstrumentDefXMLParser::parse(QIODevice *device) +{ + fXml.setDevice(device); + + bool expectChars = false; + while (!fXml.atEnd()) { + fXml.readNext(); + if (fXml.isStartDocument()) { + startDocument(); + } else if (fXml.isStartElement()) { + startElement(); + expectChars = true; + } else if (fXml.isCharacters() && expectChars) { + characters(); + } else if (fXml.isEndElement()) { + endElement(); + expectChars = false; + } else if (fXml.isEndDocument()) { + endDocument(); + } + } + if (fXml.hasError()) { + QString msg; + msg = QString("%1 Line %2, column %3").arg(fXml.errorString()).arg(fXml.lineNumber()).arg(fXml.columnNumber()); + QMessageBox::critical(0, "**ERROR**", msg, QMessageBox::Ok, QMessageBox::NoButton); + return false; + } + + return true; +} + +//-------------------------------------------------------------------------- +/** + *

Routine called at the beginning of the XML parsing process. + */ +bool PInstrumentDefXMLParser::startDocument() +{ + // nothing to be done here for now + return true; +} + +//-------------------------------------------------------------------------- +/** + *

Routine called when a new XML tag is found. Here it is used + * to set a tag for filtering afterwards the content. + */ +bool PInstrumentDefXMLParser::startElement() +{ + QString qName = fXml.name().toString(); + + bool ok; + double dval; + double ival; + QString str, errMsg; + QStringList strL; + QVector forward; + QVector backward; + + if (qName == "institute") { + fKeyWord = eInstitute; + } else if (qName == "instrument") { + fKeyWord = eInstrument; + QXmlStreamAttributes qAttr = fXml.attributes(); + if (qAttr.count() != 1) { + errMsg = QString("instrument should have 1 attribute, called 'name', found %1").arg(qAttr.count()); + QMessageBox::critical(0, "ERROR", errMsg); + return false; + } + if (fInstituteName == "") { + errMsg = QString("found instrument without institute set."); + QMessageBox::critical(0, "ERROR", errMsg); + return false; + } + // create an instrument object + fInstrument = new PInstrument(); + fInstrument->setInstitue(fInstituteName); + fInstrument->setName(qAttr.value("name").toString()); + } else if (qName == "run_name_template") { + fKeyWord = eRunNameTemplate; + } else if (qName == "beamline") { + fKeyWord = eBeamline; + } else if (qName == "data_file_format") { + fKeyWord = eDataFileFormat; + } else if (qName == "tf") { + fKeyWord = eTf; + QXmlStreamAttributes qAttr = fXml.attributes(); + fSetup = new PSetup(); + if (qAttr.count() == 1) + fSetup->setName(qAttr.value("name").toString()); + else + fSetup->setName("Default"); + } else if (qName == "zf") { + fKeyWord = eZf; + QXmlStreamAttributes qAttr = fXml.attributes(); + fSetup = new PSetup(); + if (qAttr.count() == 1) + fSetup->setName(qAttr.value("name").toString()); + else + fSetup->setName("Default"); + } else if (qName == "lf") { + fKeyWord = eLf; + QXmlStreamAttributes qAttr = fXml.attributes(); + fSetup = new PSetup(); + if (qAttr.count() == 1) + fSetup->setName(qAttr.value("name").toString()); + else + fSetup->setName("Default"); + } else if (qName == "no_of_detectors") { + fKeyWord = eNoOfDetectors; + } else if (qName == "fgb_offset") { + fKeyWord = eFgbOffset; + } else if (qName == "lgb") { + fKeyWord = eLgb; + } else if (qName == "asym_bkg_range") { + fKeyWord = eBkgRange; + } else if (qName == "logic_detector") { + QXmlStreamAttributes qAttr = fXml.attributes(); + if (qAttr.count() < 3) + return false; + PDetector detect; + // detector name + str = qAttr.value("name").toString(); + detect.setName(str); + // detector relative phase + str = qAttr.value("rel_phase").toString(); + dval = str.toDouble(&ok); + if (!ok) { + return false; + } + detect.setRelGeomPhase(dval); + // detector number(s) + str = qAttr.value("forward").toString(); + strL.clear(); + strL = str.split(' '); + forward.clear(); + for (int j=0; jaddDetector(detect); + } else if (qName == "logic_asym_detector") { + QXmlStreamAttributes qAttr = fXml.attributes(); + if (qAttr.count() != 5) + return false; + PDetector detect; + // detector name + str = qAttr.value("name").toString(); + detect.setName(str); + // detector relative phase + str = qAttr.value("rel_phase").toString(); + dval = str.toDouble(&ok); + if (!ok) { + return false; + } + detect.setRelGeomPhase(dval); + // detector forward + str = qAttr.value("forward").toString(); + strL.clear(); + strL = str.split(' '); + forward.clear(); + for (int j=0; jaddAsymDetector(detect); + } + + return true; +} + +//-------------------------------------------------------------------------- +/** + *

Routine called when the end XML tag is found. It is used to + * put the filtering tag to 'empty'. It also resets the fFunc flag in case + * the entry was a theory function. + */ +bool PInstrumentDefXMLParser::endElement() +{ + fKeyWord = eEmpty; + + QString qName = fXml.name().toString(); + + if (qName == "instrument") { + // store instrument + fAdmin->addInstrument(fInstituteName, *fInstrument); + + // delete instrument object + if (fInstrument) { + delete fInstrument; + fInstrument = 0; + } + } else if (qName == "zf") { + // store setup + fInstrument->addSetupZF(*fSetup); + + // delete setup object + if (fSetup) { + delete fSetup; + fSetup = 0; + } + } else if (qName == "tf") { + // store setup + fInstrument->addSetupTF(*fSetup); + + // delete setup object + if (fSetup) { + delete fSetup; + fSetup = 0; + } + } else if (qName == "lf") { + // store setup + fInstrument->addSetupLF(*fSetup); + + // delete setup object + if (fSetup) { + delete fSetup; + fSetup = 0; + } + } + + return true; +} + +//-------------------------------------------------------------------------- +/** + *

This routine delivers the content of an XML tag. It fills the + * content into the load data structure. + */ +bool PInstrumentDefXMLParser::characters() +{ + QString str = fXml.text().toString(); + if (str.isEmpty()) + return true; + + bool ok; + int ival, start, end; + QString errMsg; + QStringList strList; + + switch (fKeyWord) { + case eInstitute: + fInstituteName = str; + break; + case eRunNameTemplate: + fInstrument->setRunNameTemplate(str); + break; + case eBeamline: + fInstrument->setBeamline(str); + break; + case eDataFileFormat: + fInstrument->setDataFileFormat(str); + break; + case eNoOfDetectors: + if (fSetup == 0) { + errMsg = "setup object not found."; + QMessageBox::critical(0, "ERROR", errMsg); + return false; + } + ival = str.toInt(&ok); + if (!ok) { + errMsg = QString("Setup Error: No of Detectors = '%1', which is not an int.").arg(str); + QMessageBox::critical(0, "ERROR", errMsg); + return false; + } + fSetup->setNoOfDetectors(ival); + break; + case eFgbOffset: + if (fSetup == 0) + return false; + ival = str.toInt(&ok); + if (!ok) + return false; + fSetup->setFgbOffset(ival); + break; + case eLgb: + if (fSetup == 0) + return false; + ival = str.toInt(&ok); + if (!ok) + return false; + fSetup->setLgb(ival); + break; + case eBkgRange: + strList = str.split(' ', Qt::SkipEmptyParts); + if (strList.size() != 2) { + errMsg = QString("Found wrong Asymmetry background range: '%1'").arg(str); + QMessageBox::critical(0, "ERROR", errMsg); + return false; + } + start = strList[0].toInt(&ok); + if (!ok) { + return false; + } + end = strList[1].toInt(&ok); + if (!ok) { + return false; + } + fSetup->setBkgRange(start, end); + break; + default: + break; + } + + return true; +} + +//-------------------------------------------------------------------------- +/** + *

Called at the end of the XML parse process. It checks if default paths + * contain system variables, and if so expand them for the further use. + */ +bool PInstrumentDefXMLParser::endDocument() +{ + if (fInstituteName == "") { + QMessageBox::critical(0, "FATAL ERROR", "Didn't find any institute name in the instrument definitions."); + return false; + } + + return true; +} + +//-------------------------------------------------------------------------- +// implementation of PMusrWizDefault class +//-------------------------------------------------------------------------- +/** + *

Initializes that PMusrWizDefault object. + */ +PMusrWizDefault::PMusrWizDefault() +{ + fInstitute = "UnDef"; + fInstrument = "UnDef"; + fFitType = "UnDef"; +} + +//-------------------------------------------------------------------------- +// implementation of PMusrWizDefaultXMLParser class +//-------------------------------------------------------------------------- +/** + *

XML Parser class for the musrWiz default settings. + * + * \param admin pointer to an admin class instance. + */ +PMusrWizDefaultXMLParser::PMusrWizDefaultXMLParser(const QString& fln, PAdmin *admin) : fAdmin(admin) +{ + fValid = false; + fKeyWord = eEmpty; + + QFile file(fln); + if (!file.open(QFile::ReadOnly | QFile::Text)) { + // warning and create default - STILL MISSING + } + + fValid = parse(&file); +} + +//-------------------------------------------------------------------------- +/** + *

parse the musrWiz startup xml-file. + * + * \param device QFile object of the musrWiz startup xml-file + * + * @return true on success, false otherwise + */ +bool PMusrWizDefaultXMLParser::parse(QIODevice *device) +{ + fXml.setDevice(device); + + bool expectChars = false; + while (!fXml.atEnd()) { + fXml.readNext(); + if (fXml.isStartDocument()) { + startDocument(); + } else if (fXml.isStartElement()) { + startElement(); + expectChars = true; + } else if (fXml.isCharacters() && expectChars) { + characters(); + } else if (fXml.isEndElement()) { + endElement(); + expectChars = false; + } else if (fXml.isEndDocument()) { + endDocument(); + } + } + if (fXml.hasError()) { + QString msg; + msg = QString("%1 Line %2, column %3").arg(fXml.errorString()).arg(fXml.lineNumber()).arg(fXml.columnNumber()); + QMessageBox::critical(0, "**ERROR**", msg, QMessageBox::Ok, QMessageBox::NoButton); + return false; + } + + return true; +} + +//-------------------------------------------------------------------------- +/** + *

Routine called at the beginning of the XML parsing process. + */ +bool PMusrWizDefaultXMLParser::startDocument() +{ + // nothing to be done here for now + return true; +} + +//-------------------------------------------------------------------------- +/** + *

Routine called when a new XML tag is found. Here it is used + * to set a tag for filtering afterwards the content. + */ +bool PMusrWizDefaultXMLParser::startElement() +{ + QString qName = fXml.name().toString(); + + if (qName == "institute") { + fKeyWord = eInstitute; + } else if (qName == "instrument") { + fKeyWord = eInstrument; + } else if (qName == "fit_type") { + fKeyWord = eFitType; + } + + return true; +} + +//-------------------------------------------------------------------------- +/** + *

Routine called when the end XML tag is found. It is used to + * put the filtering tag to 'empty'. It also resets the fFunc flag in case + * the entry was a theory function. + */ +bool PMusrWizDefaultXMLParser::endElement() +{ + fKeyWord = eEmpty; + + return true; +} + +//-------------------------------------------------------------------------- +/** + *

This routine delivers the content of an XML tag. It fills the + * content into the load data structure. + */ +bool PMusrWizDefaultXMLParser::characters() +{ + QString str = fXml.text().toString(); + if (str.isEmpty()) + return true; + + switch (fKeyWord) { + case eInstitute: + fDefault.setInstitute(str); + break; + case eInstrument: + fDefault.setInstrument(str); + break; + case eFitType: + fDefault.setFitType(str); + break; + default: + break; + } + + return true; +} + +//-------------------------------------------------------------------------- +/** + *

Called at the end of the XML parse process. + */ +bool PMusrWizDefaultXMLParser::endDocument() +{ + fAdmin->fDefault = fDefault; + + return true; +} + +//-------------------------------------------------------------------------- +// implementation of PAdmin class +//-------------------------------------------------------------------------- +/** + *

Initializes that PAdmin object, and calls the XML parser which feeds + * the object variables. + */ +PAdmin::PAdmin() : QObject() +{ + QString path, fln, pathFln; + int count = 0; + + fValid = true; + + // load musrWiz default settings + // 1st: check local directory + pathFln = QString("./musrWiz.xml"); + if (!QFile::exists(pathFln)) { + // 2nd: check $HOME/.musrfit/musrWiz/musrWiz.xml + path = std::getenv("HOME"); + pathFln = path + "/.musrfit/musrWiz/musrWiz.xml"; + if (loadMusrWizDefault(pathFln)) { + QMessageBox::warning(0, "WARNING", "Couldn't find musrWiz.xml file."); + } + } + + // load musrfit funcs + // 1st: check local directory + pathFln = QString("./musrfit_funcs.xml"); + if (!QFile::exists(pathFln)) { + // 2nd: check $HOME/.musrfit/musrWiz/musrfit_funcs.xml + path = std::getenv("HOME"); + pathFln = path + "/.musrfit/musrWiz/musrfit_funcs.xml"; + if (loadMusrfitFunc(pathFln)) { + fValid = false; + QMessageBox::critical(0, "FATAL ERROR", "Couldn't find any musrfit function definitions."); + return; + } + } + + // load instrument definitions + QStringList instStr; + instStr << "psi" << "triumf" << "isis" << "jparc"; + + for (int i=0; i instrument = fInstitute[idx].getInstruments(); + for (int i=0; i= fTheoTemplate.size())) + return theoTemplate; + + return fTheoTemplate[idx]; +} + +//-------------------------------------------------------------------------- +/** + * + */ +PMusrfitFunc PAdmin::getMusrfitFunc(QString name) +{ + PMusrfitFunc func; + + int idx=-1; + for (int i=0; idump all the instrument defs to stdout. This routine is there for debug + * purposes only. + */ +void PAdmin::dump(int tag) +{ + if (tag == -1) + return; + + if (tag != 1) { + QVector instrument; + QVector setup; + PDetector *detec; + QVector forward; + QString forwardStr; + QVector backward; + QString backwardStr; + + for (int i=0; i +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-"; + qInfo() << "debug> Institute: " << fInstitute[i].getName(); + qInfo() << "debug> ----"; + instrument = fInstitute[i].getInstruments(); + for (int j=0; j ----"; + qInfo() << "debug> Instrument Name: " << instrument[j].getName(); + // all TF setups + setup = instrument[j].getTFSetups(); + for (int k=0; k ----"; + qInfo() << "debug> TF setup, name: " << setup[k].getName(); + qInfo() << "debug> No of Detectors: " << setup[k].getNoOfDetectors(); + qInfo() << "debug> fgb Offset: " << setup[k].getFgbOffset(); + qInfo() << "debug> lgb: " << setup[k].getLgb(); + qInfo() << "debug> asymmetry bkg range: " << setup[k].getBkgStartBin() << " " << setup[k].getBkgEndBin(); + qInfo() << "debug> ----"; + for (int l=0; l detec == 0 for k=" << k << ", l=" << l; + return; + } + forward = detec->getForwards(); + forwardStr = ""; + for (int m=0; m detector : " << detec->getName() << ", " << detec->getRelGeomPhase() << "°, " << forwardStr; + } + qInfo() << "debug> ----"; + for (int l=0; l detec == 0 for k=" << k << ", l=" << l; + return; + } + forward = detec->getForwards(); + forwardStr = ""; + backward = detec->getBackwards(); + backwardStr = ""; + for (int m=0; m detectorAsym : " << detec->getName() << ", " << detec->getRelGeomPhase() << "°, " << forwardStr << "/" << backwardStr << ", alpha=" << detec->getAlpha(); + } + } + // all ZF setups + setup.clear(); + setup = instrument[j].getZFSetups(); + for (int k=0; k ----"; + qInfo() << "debug> ZF setup, name: " << setup[k].getName(); + qInfo() << "debug> No of Detectors: " << setup[k].getNoOfDetectors(); + qInfo() << "debug> fgb Offset: " << setup[k].getFgbOffset(); + qInfo() << "debug> lgb: " << setup[k].getLgb(); + qInfo() << "debug> asymmetry bkg range: " << setup[k].getBkgStartBin() << " " << setup[k].getBkgEndBin(); + qInfo() << "debug> ----"; + for (int l=0; l detec == 0 for k=" << k << ", l=" << l; + return; + } + forward = detec->getForwards(); + forwardStr = ""; + backward = detec->getBackwards(); + backwardStr = ""; + for (int m=0; m detectorAsym : " << detec->getName() << ", " << detec->getRelGeomPhase() << "°, " << forwardStr << "/" << backwardStr << ", alpha=" << detec->getAlpha(); + } + } + // all LF setups + setup.clear(); + setup = instrument[j].getLFSetups(); + for (int k=0; k ----"; + qInfo() << "debug> LF setup, name: " << setup[k].getName(); + qInfo() << "debug> No of Detectors: " << setup[k].getNoOfDetectors(); + qInfo() << "debug> fgb Offset: " << setup[k].getFgbOffset(); + qInfo() << "debug> lgb: " << setup[k].getLgb(); + qInfo() << "debug> asymmetry bkg range: " << setup[k].getBkgStartBin() << " " << setup[k].getBkgEndBin(); + qInfo() << "debug> ----"; + for (int l=0; l detec == 0 for k=" << k << ", l=" << l; + return; + } + forward = detec->getForwards(); + forwardStr = ""; + backward = detec->getBackwards(); + backwardStr = ""; + for (int m=0; m detectorAsym : " << detec->getName() << ", " << detec->getRelGeomPhase() << "°, " << forwardStr << "/" << backwardStr << ", alpha=" << detec->getAlpha(); + } + } + } + qInfo() << "debug> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-"; + } + } else if (tag != 0) { + qInfo() << "debug> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-"; + qInfo() << "debug> Available Musrfit Funcs of the Wizard"; + qInfo() << "debug> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-"; + PMusrfitFunc fun; + for (int i=0; i " << i << ": " << fun.getName() << " / " << fun.getAbbrv(); + qInfo() << "deubg> " << i << ": no of Parameters: " << fun.getNoOfParam(); + for (int j=0; jsize(); j++) { + qInfo() << "debug> " << i << "/" << j << ": param name: " << fun.getFuncParam(j).getParamName() << ", val: " << fun.getFuncParam(j).getParamValue(); + } + qInfo() << "debug> ----"; + } + qInfo() << "debug> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-"; + } +} + +//-------------------------------------------------------------------------- +/** + * + */ +PInstrument *PAdmin::getInstrument(QString institute, QString instrument) +{ + for (int i=0; i +#include +#include +#include +#include +#include + +#include "PTheoTemplate.h" +#include "PMusrfitFunc.h" +#include "PInstrumentDef.h" + +class PAdmin; + +//--------------------------------------------------------------------------- +class PFuncXMLParser +{ + public: + PFuncXMLParser(const QString &fln, PAdmin*); + virtual ~PFuncXMLParser() {} + + virtual bool isValid() { return fValid; } + + private: + enum EFuncKeyWords {eEmpty, + eTemplateName, eTemplateTheo, eTemplateFunc, + eName, eAbbrv, eNoOfParam, eParam, + eParamName, eParamValue, eParamMap}; + + bool parse(QIODevice *device); + bool startDocument(); + bool startElement(); + bool endElement(); + bool characters(); + bool endDocument(); + + + QXmlStreamReader fXml; ///< xml stream reader object + bool fValid; ///< flag showing if XML read has been successful + EFuncKeyWords fKeyWord; ///< key word tag to know how to handle the content + PAdmin *fAdmin; ///< a pointer to the main administration class object + + PTheoTemplate fTheoTemplate; + PMusrfitFunc fFunc; + PFuncParam fParam; +}; + +//--------------------------------------------------------------------------- +class PInstrumentDefXMLParser +{ + public: + PInstrumentDefXMLParser(const QString &fln, PAdmin*); + virtual ~PInstrumentDefXMLParser() {} + + virtual bool isValid() { return fValid; } + + private: + enum EKeyWords {eEmpty, eInstitute, eInstrument, eRunNameTemplate, + eBeamline, eDataFileFormat, eTf, eZf, eLf, + eNoOfDetectors, eFgbOffset, eLgb, eBkgRange, + eLogicDetector}; + + bool parse(QIODevice *device); + bool startDocument(); + bool startElement(); + bool endElement(); + bool characters(); + bool endDocument(); + + QXmlStreamReader fXml; ///< xml stream reader object + bool fValid; ///< flag showing if XML read has been successful + EKeyWords fKeyWord; ///< key word tag to know how to handle the content + PAdmin *fAdmin; ///< a pointer to the main administration class object + + QString fInstituteName; + PInstrument *fInstrument; + PSetup *fSetup; +}; + +//--------------------------------------------------------------------------- +class PMusrWizDefault +{ + public: + PMusrWizDefault(); + ~PMusrWizDefault() {} + + QString getInstitute() { return fInstitute; } + QString getInstrument() { return fInstrument; } + QString getFitType() { return fFitType; } + + void setInstitute(QString str) { fInstitute = str; } + void setInstrument(QString str) { fInstrument = str; } + void setFitType(QString str) { fFitType = str; } + + private: + QString fInstitute; + QString fInstrument; + QString fFitType; +}; + +//--------------------------------------------------------------------------- +class PMusrWizDefaultXMLParser +{ + public: + PMusrWizDefaultXMLParser(const QString &fln, PAdmin*); + virtual ~PMusrWizDefaultXMLParser() {} + + virtual bool isValid() { return fValid; } + + private: + enum EKeyWords {eEmpty, eInstitute, eInstrument, eFitType}; + + bool parse(QIODevice *device); + bool startDocument(); + bool startElement(); + bool endElement(); + bool characters(); + bool endDocument(); + + QXmlStreamReader fXml; ///< xml stream reader object + bool fValid; ///< flag showing if XML read has been successful + EKeyWords fKeyWord; ///< key word tag to know how to handle the content + PAdmin *fAdmin; ///< a pointer to the main administration class object + + PMusrWizDefault fDefault; +}; + +//--------------------------------------------------------------------------- +class PAdmin : public QObject +{ + public: + PAdmin(); + ~PAdmin() {} + + bool IsValid() { return fValid; } + void dump(int tag); + + QString getDefaultInstitute() { return fDefault.getInstitute(); } + QString getDefaultInstrument() { return fDefault.getInstrument(); } + QString getDefaultFitType() { return fDefault.getFitType(); } + + QStringList getInstituteList(); + QStringList getInstrumentList(QString institute); + PInstrument *getInstrument(QString institute, QString instrument); + int getTheoTemplateSize() { return fTheoTemplate.size(); } + QVector getTheoTemplates() { return fTheoTemplate; } + PTheoTemplate getTheoTemplate(int idx); + int getMusrfitFuncSize() { return fMusrfitFunc.size(); } + QVector getMusrfitFunc() { return fMusrfitFunc; } + PMusrfitFunc getMusrfitFunc(QString name); + + protected: + int addInstrument(QString institute, PInstrument instrument); + + private: + friend class PFuncXMLParser; + friend class PInstrumentDefXMLParser; + friend class PMusrWizDefaultXMLParser; + + bool fValid; + + PMusrWizDefault fDefault; + QVector fInstitute; + QVector fTheoTemplate; + QVector fMusrfitFunc; + + int loadMusrWizDefault(QString fln); + int loadMusrfitFunc(QString fln); + int loadInstrumentDef(QString path, QString fln); +}; + +#endif // _PADMIN_H_ diff --git a/src/musredit_qt6/musrWiz/PInstrumentDef.cpp b/src/musredit_qt6/musrWiz/PInstrumentDef.cpp new file mode 100644 index 00000000..659e3c4a --- /dev/null +++ b/src/musredit_qt6/musrWiz/PInstrumentDef.cpp @@ -0,0 +1,153 @@ +/*************************************************************************** + + PInstrumentDef.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 "PInstrumentDef.h" + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/** + * + */ +PSetup::PSetup() +{ + fName = ""; + fNoOfDetectors = -1; + fFgbOffset = -1; + fLgb = -1; + fBkgStartBin = -1; + fBkgEndBin = -1; +} + +//-------------------------------------------------------------------------- +/** + * @brief PSetup::getDetector + * @param idx + * @return + */ +PDetector* PSetup::getDetector(int idx) +{ + if (idx >= fLogicDetectors.size()) + return 0; + + return &fLogicDetectors[idx]; +} + +//-------------------------------------------------------------------------- +/** + * @brief PSetup::getAsymDetector + * @param idx + * @return + */ +PDetector* PSetup::getAsymDetector(int idx) +{ + if (idx >= fLogicAsymDetectors.size()) + return 0; + + return &fLogicAsymDetectors[idx]; +} + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/** + * + */ +PInstrument::PInstrument() +{ + fRunNameTemplate = ""; + fBeamline = ""; + fDataFileFormat = ""; + fInstitue = ""; + fName = ""; +} + +//-------------------------------------------------------------------------- +/** + * @brief PInstrument::getZFSetup + * @param name + * @return + */ +PSetup* PInstrument::getZFSetup(QString name) +{ + for (int i=0; i +#include + +//--------------------------------------------------------------------------- +class PDetector +{ + public: + PDetector() {} + ~PDetector() {} + + void setName(QString str) { fName = str; } + void setRelGeomPhase(double phase) { fRelGeomPhase = phase; } + void setForwards(QVector num) { fForward = num; } + void setBackwards(QVector num) { fBackward = num; } + void setAlpha(double alpha) { fAlpha = alpha; } + + QString getName() { return fName; } + double getRelGeomPhase() { return fRelGeomPhase; } + QVector getForwards() { return fForward; } + QVector getBackwards() { return fBackward; } + double getAlpha() { return fAlpha; } + + private: + QString fName; + QVector fForward; + QVector fBackward; + double fAlpha; + double fRelGeomPhase; +}; + +//--------------------------------------------------------------------------- +class PSetup +{ + public: + PSetup(); + ~PSetup() {} + + void setName(QString str) { fName = str; } + void setNoOfDetectors(int no) { fNoOfDetectors = no; } + void setFgbOffset(int fgbOffset) { fFgbOffset = fgbOffset; } + void setLgb(int lgb) { fLgb = lgb; } + void setBkgRange(int start, int end) { fBkgStartBin = start; fBkgEndBin = end; } + void addDetector(PDetector detector) { fLogicDetectors.push_back(detector); } + void addAsymDetector(PDetector detector) { fLogicAsymDetectors.push_back(detector); } + + QString getName() { return fName; } + int getNoOfDetectors() { return fNoOfDetectors; } + int getNoOfLogicalDetectors() { return fLogicDetectors.size(); } + int getNoOfLogicalAsymDetectors() { return fLogicAsymDetectors.size(); } + int getFgbOffset() { return fFgbOffset; } + int getLgb() { return fLgb; } + int getBkgStartBin() { return fBkgStartBin; } + int getBkgEndBin() { return fBkgEndBin; } + PDetector* getDetector(int idx); + PDetector* getAsymDetector(int idx); + + private: + QString fName; + int fNoOfDetectors; + int fFgbOffset; + int fLgb; + int fBkgStartBin; + int fBkgEndBin; + + QVector fLogicDetectors; + QVector fLogicAsymDetectors; +}; + +//--------------------------------------------------------------------------- +class PInstrument +{ + public: + PInstrument(); + ~PInstrument() {} + + void setRunNameTemplate(QString str) { fRunNameTemplate = str; } + void setBeamline(QString str) { fBeamline = str; } + void setDataFileFormat(QString str) { fDataFileFormat = str; } + void setInstitue(QString str) { fInstitue = str; } + void setName(QString str) { fName = str; } + + void addSetupZF(PSetup zf) { fZF.push_back(zf); } + void addSetupTF(PSetup tf) { fTF.push_back(tf); } + void addSetupLF(PSetup lf) { fLF.push_back(lf); } + + QString getRunNameTemplate() { return fRunNameTemplate; } + QString getBeamline() { return fBeamline; } + QString getDataFileFormat() { return fDataFileFormat; } + QString getInstitute() { return fInstitue; } + QString getName() { return fName; } + + QVector getZFSetups() { return fZF; } + QVector getTFSetups() { return fTF; } + QVector getLFSetups() { return fLF; } + + PSetup* getZFSetup(QString name=""); + PSetup* getTFSetup(QString name=""); + PSetup* getLFSetup(QString name=""); + + private: + QString fRunNameTemplate; + QString fBeamline; + QString fDataFileFormat; + QString fInstitue; + QString fName; + + QVector fZF; + QVector fTF; + QVector fLF; +}; + +//--------------------------------------------------------------------------- +class PInstitute +{ + public: + PInstitute(); + ~PInstitute() {} + + void setName(QString str) { fName = str; } + void addInstrument(PInstrument instrument) { fInstrument.push_back(instrument); } + + QString getName() { return fName; } + QVector getInstruments() { return fInstrument; } + PInstrument *getInstrument(QString name); + + private: + QString fName; + QVector fInstrument; +}; + +#endif // _PINSTRUMENTDEF_H_ diff --git a/src/musredit_qt6/musrWiz/PMusrWiz.cpp b/src/musredit_qt6/musrWiz/PMusrWiz.cpp new file mode 100644 index 00000000..83ed8f9a --- /dev/null +++ b/src/musredit_qt6/musrWiz/PMusrWiz.cpp @@ -0,0 +1,2583 @@ +/*************************************************************************** + + PMusrWiz.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +***************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2007-2021 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 "musrWiz.h" +#include "PTheoTemplate.h" +#include "PMusrfitFunc.h" +#include "PMusrWiz.h" + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/** + * @brief PMsrData::PMsrData + */ +PMsrData::PMsrData() +{ + fTemplate = -1; + + fMsrFileName = QString(""); + fRunNumber = -1; + fInstitute = "PSI"; + fInstrument = "HAL9500"; + fFitType = FIT_TYPE_SINGLE_HISTO; + fTypeOfMeasurement = MEASURE_UNDEF; + fT0Tag = T0_FROM_FILE; + fT0 = -1; + QDate date = QDate::currentDate(); + fYear = QString("%1").arg(date.year()); + + fPacking = 1; + fFitStart = 0.0; + fFitEnd = 10.0; + fCommands = ""; + + fTheo = ""; +} + +//------------------------------------------------------------------------- +/** + * @brief PMsrData::~PMsrData + */ +PMsrData::~PMsrData() +{ + +} + +//------------------------------------------------------------------------- +/** + * @brief PMsrData::getFitTypeString + * @return + */ +QString PMsrData::getFitTypeString() +{ + QString str("UnDef"); + + switch (fFitType) { + case FIT_TYPE_ASYMMETRY: + str = QString("Asymmetry"); + break; + case FIT_TYPE_ASYMMETRY_RRF: + str = QString("Asymmetry RRF"); + break; + case FIT_TYPE_SINGLE_HISTO: + str = QString("Single Histo"); + break; + case FIT_TYPE_SINGLE_HISTO_RRF: + str = QString("Single Histo RRF"); + break; + case FIT_TYPE_MU_MINUS: + str = QString("Mu Minus"); + break; + case FIT_TYPE_NONE_MUSR: + str = QString("None Musr"); + break; + case FIT_TYPE_UNDEF: + default: + break; + } + + return str; +} + +//------------------------------------------------------------------------- +/** + * @brief PMsrData::setParam + * @param idx + * @param param + */ +void PMsrData::setParam(int idx, PParam param) +{ + if (idx >= fParam.size()) + fParam.resize(idx+1); + + fParam[idx] = param; +} + +//------------------------------------------------------------------------- +/** + * @brief PMsrData::setMap + * @param idx + * @param map + */ +void PMsrData::setMap(int idx, PParam map) +{ + if (idx >= fMap.size()) + fMap.resize(idx+1); + + fMap[idx] = map; +} + +//------------------------------------------------------------------------- +/** + * @brief PMsrData::appendParam + * @param param + */ +void PMsrData::appendParam(QVector param) +{ + // check if parameter is aleady present. If yes, ignore it, otherwise add it + bool present = false; + for (int i=0; i map) +{ + // check if map is aleady present. If yes, replace it, otherwise add it + bool present = false; + for (int i=0; i fMap.size())) + return; + + fMap[idx].setName(name); +} + +//------------------------------------------------------------------------- +/** + * @brief PMsrData::setFunc + * @param funNo + * @param str + */ +void PMsrData::setFunc(int funNo, QString str) +{ + if (funNo < 0) + return; + + // check if not already present + for (int i=0; i fParam.size()) + return param; + + return fParam[idx]; +} + +//------------------------------------------------------------------------- +/** + * @brief PMsrData::getMap + * @param idx + * @return + */ +PParam PMsrData::getMap(int idx) +{ + PParam map; + + if (idx >= fMap.size()) + return map; + + return fMap[idx]; +} + +//------------------------------------------------------------------------- +/** + * @brief PMsrData::getFuncNo + * @param idx + * @return + */ +int PMsrData::getFuncNo(int idx) +{ + if ((idx < 0) || (idx >= fFunc.size())) + return -1; + + return fFunc[idx].number; +} + +//------------------------------------------------------------------------- +/** + * @brief PMsrData::isPresent + * @param funStr + * @return + */ +bool PMsrData::isPresent(const QString funStr) +{ + for (int i=0; i fParam[i+1].getNumber()) { + swap = fParam[i]; + fParam[i] = fParam[i+1]; + fParam[i+1] = swap; + swapped = true; + } + } + } + } else if (whichVec == "map") { + PParam swap; + while (swapped) { + swapped = false; + j++; + for (int i=0; i < fMap.size() - j; i++) { + if (fMap[i].getNumber() > fMap[i+1].getNumber()) { + swap = fMap[i]; + fMap[i] = fMap[i+1]; + fMap[i+1] = swap; + swapped = true; + } + } + } + } else if (whichVec == "func") { + PFunc swap; + while (swapped) { + swapped = false; + j++; + for (int i=0; i < fFunc.size() - j; i++) { + if (fFunc[i].number > fFunc[i+1].number) { + swap = fFunc[i]; + fFunc[i] = fFunc[i+1]; + fFunc[i+1] = swap; + swapped = true; + } + } + } + } +} + +//------------------------------------------------------------------------- +/** + * @brief PMsrData::removeFunc + * @param funList + */ +void PMsrData::removeFunc(QVector &funList) +{ + int idx; + for (int i=0; iused Theory"); + QPlainTextEdit *theoTextEdit = new QPlainTextEdit(theo); + theoTextEdit->setReadOnly(true); + QPlainTextEdit *funcTextEdit = 0; + if (!func.isEmpty()) { + funcTextEdit = new QPlainTextEdit(func); + funcTextEdit->setReadOnly(true); + } + QPushButton *cancel = new QPushButton("&Cancel"); + + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(label); + layout->addWidget(theoTextEdit); + if (funcTextEdit) + layout->addWidget(funcTextEdit); + layout->addWidget(cancel); + + setLayout(layout); + + connect(cancel, SIGNAL(pressed()), this, SLOT(accept())); +} + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/** + * @brief PIntroPage::PIntroPage + * @param data + * @param parent + */ +PIntroPage::PIntroPage(PAdmin *admin, PMsrData *data, QWidget *parent) : + QWizardPage(parent), + fAdmin(admin), + fMsrData(data) +{ + setTitle("

Introduction

"); + setSubTitle("This wizard will help you to create your msr-file."); + + fMsrFileName = new QLineEdit(); + fMsrFileName->setToolTip("enter msr-file name or leave it empty."); + fMsrFileName->setWhatsThis("If empty the file name will be generate,\nbased on the run number, the fit type\nand the type of measurement."); + + fYear = new QLineEdit(); + fYear->setValidator(new QIntValidator()); + QDate date = QDate::currentDate(); + fYear->setText(QString("%1").arg(date.year())); + fYear->setToolTip("year when the run took place."); + fYear->setWhatsThis("The year is used to generate\nthe RUN header information where\nmusrfit will look for the data."); + + fRunNumber = new QLineEdit(); + fRunNumber->setValidator(new QIntValidator()); + fRunNumber->setText(QString("%1").arg(fMsrData->getRunNumber())); + fRunNumber->setToolTip("enter the run number here."); + + fInstitute = new QComboBox(); + QStringList list = fAdmin->getInstituteList(); // get list form the instrument_def's + list.prepend("UnDef"); + fInstitute->addItems(list); + int idx = fInstitute->findText(fAdmin->getDefaultInstitute()); + if (idx != -1) + fInstitute->setCurrentIndex(idx); + + fInstrument = new QComboBox(); + list.clear(); + list << fAdmin->getInstrumentList(fMsrData->getInstitute()); + list.prepend("UnDef"); + fInstrument->addItems(list); + idx = fInstrument->findText(fAdmin->getDefaultInstrument()); + if (idx != -1) + fInstrument->setCurrentIndex(idx); + + fFitType = new QComboBox(); + list.clear(); + list << "UnDef" << "Single Histo" << "Single Histo RRF" << "Asymmetry" << "Asymmetry RRF" << "Mu Minus" << "None muSR"; + fFitType->addItems(list); + idx = fFitType->findText(fAdmin->getDefaultFitType()); + fFitType->setCurrentIndex(idx); + + fMeasurementType = new QComboBox(); + list.clear(); + list << "UnDef" << "ZF" << "TF" << "LF"; + fMeasurementType->addItems(list); + fMeasurementType->setCurrentIndex(fMsrData->getTypeOfMeasurement()); + + fT0 = new QComboBox(); + list.clear(); + list << "from data file" << "call musrT0" << "enter here"; + fT0->addItems(list); + fT0->setCurrentIndex(fMsrData->getT0Tag()); + fT0->setWhatsThis("choose if you want the t0's from the data file,\ncall musrT0 after the msr-files is generated,\nor enter the values within the wizard."); + + QFormLayout *layout = new QFormLayout; + + layout->addRow("Add msr-file name:", fMsrFileName); + layout->addRow("Year:", fYear); + layout->addRow("Run Number:", fRunNumber); + layout->addRow("Institute:", fInstitute); + layout->addRow("Instrument:", fInstrument); + layout->addRow("Fit Type:", fFitType); + layout->addRow("Type of Measurement:", fMeasurementType); + layout->addRow("T0's:", fT0); + + setLayout(layout); + + registerField("runNumber*", fRunNumber); + + QObject::connect(fInstitute, SIGNAL(activated(int)), this, SLOT(handleInstituteChanged(int))); + QObject::connect(fFitType, SIGNAL(activated(int)), this , SLOT(handleFitType(int))); + QObject::connect(fMeasurementType, SIGNAL(activated(int)), this, SLOT(checkSetup(int))); + QObject::connect(fT0, SIGNAL(activated(int)), this, SLOT(handleT0(int))); +} + +//------------------------------------------------------------------------- +void PIntroPage::handleInstituteChanged(int idx) +{ + QString str = fInstitute->itemText(idx); + QStringList list = fAdmin->getInstrumentList(str); + list.prepend("UnDef"); + + fInstrument->clear(); + fInstrument->addItems(list); +} + +//------------------------------------------------------------------------- +/** + * @brief PIntroPage::handleFitType + * @param idx + */ +void PIntroPage::handleFitType(int idx) +{ + if ( (idx != FIT_TYPE_SINGLE_HISTO) && + (idx != FIT_TYPE_ASYMMETRY) ){ + QMessageBox::warning(0, "WARNING", "Currently only fit type: single histo and asymmetry available."); + fFitType->setCurrentIndex(FIT_TYPE_SINGLE_HISTO); + } +} + +//------------------------------------------------------------------------- +/** + * @brief PIntroPage::checkSetup + * @param idx + */ +void PIntroPage::checkSetup(int idx) +{ + QString measure(""); + PInstrument *instru = fAdmin->getInstrument(fInstitute->currentText(), fInstrument->currentText()); + QVector setup; + switch (idx) { + case MEASURE_ZF: + setup = instru->getZFSetups(); + measure = "ZF"; + break; + case MEASURE_TF: + setup = instru->getTFSetups(); + measure = "TF"; + break; + case MEASURE_LF: + setup = instru->getLFSetups(); + measure = "LF"; + QMessageBox::information(0, "INFO", "Not yet implemented."); + break; + case MEASURE_UNDEF: + default: + break; + } + + if (setup.size() == 0) { + QString msg = QString("Didn't find any setup for:\nInstitute: %1\nInstrument: %2").arg(fInstitute->currentText()).arg(fInstrument->currentText()); + QMessageBox::critical(0, "ERROR", msg); + return; + } else if (setup.size() == 1) { + if (setup[0].getName() == "Default") { + fMsrData->setSetup("Default"); + return; + } + } + + QStringList items; + for (int i=0; isetSetup(setupName); + } +} + +//------------------------------------------------------------------------- +/** + * @brief PIntroPage::handleT0 + * @param idx + */ +void PIntroPage::handleT0(int idx) +{ + bool ok; + if (idx == T0_ENTER_WIZ) { + int t0 = QInputDialog::getInt(this, "Enter T0:", "T0:", 0, 0, 2147483647, 1, &ok); + if (ok) + fMsrData->setT0(t0); + } +} + +//------------------------------------------------------------------------- +/** + * @brief PIntroPage::nextId + * @return + */ +int PIntroPage::nextId() const +{ + return PMusrWiz::ePageTheory; +} + +//------------------------------------------------------------------------- +/** + * @brief PIntroPage::validatePage + * @return + */ +bool PIntroPage::validatePage() +{ + fMsrData->setMsrFileName(fMsrFileName->text()); + fMsrData->setYear(fYear->text()); + fMsrData->setRunNumber(fRunNumber->text().toInt()); + if (fInstitute->currentIndex() == INST_UNDEF) + return false; + fMsrData->setInstitute(fInstitute->currentText()); + if (fInstrument->currentIndex() == 0) // i.e. undefined + return false; + fMsrData->setInstrument(fInstrument->currentText()); + if (fFitType->currentIndex() == FIT_TYPE_UNDEF) + return false; + fMsrData->setFitType(fFitType->currentIndex()); + if (fMeasurementType->currentIndex() == MEASURE_UNDEF) + return false; + fMsrData->setTypeOfMeasurement(fMeasurementType->currentIndex()); + fMsrData->setT0Tag(fT0->currentIndex()); + + return true; +} + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/** + * @brief PTheoPage::PTheoPage + * @param data + * @param parent + */ +PTheoPage::PTheoPage(PAdmin *admin, PMsrData *data, QWidget *parent) : + QWizardPage(parent), + fAdmin(admin), + fMsrData(data) +{ + fTheoBlockNo = 0; + + fTheoValid = false; + fHaveMap = false; + fHaveFunc = false; + + setTitle("

Theory

"); + QString str = QString("Now you will need to enter your theory - fit type: %1").arg(fMsrData->getFitTypeString()); + setSubTitle(str); + + fTheo = new QPlainTextEdit(); + fTheo->setWhatsThis("Enter the theory function here."); + + fEditTemplate = new QCheckBox("Edit Template"); + fEditTemplate->setToolTip("if checked, it allows to edit the template"); + fEditTemplate->hide(); + + fClearAll = new QPushButton(); + fClearAll->setText("Clear All"); + fClearAll->setToolTip("will clear the theory edit field."); + fClearAll->setWhatsThis("will clear the theory edit field."); + + fCheckTheo = new QPushButton(); + fCheckTheo->setText("Check"); + fCheckTheo->setToolTip("check if the theory is valid."); + fCheckTheo->setWhatsThis("Check is the theory string is valid."); + + QVector templ = fAdmin->getTheoTemplates(); + QVector funcs = fAdmin->getMusrfitFunc(); + fTheoSelect = new QComboBox(); + QStringList list; + // all the templates defined in musrfit_func.xml + for (int i=0; iaddItems(list); + fTheoSelect->setWhatsThis("select some predef. theory functions.\nFor all theory functions available check the help"); + + fTheoAdd = new QPushButton("Add"); + + QHBoxLayout *hLayout = new QHBoxLayout(); + hLayout->addWidget(fTheoSelect); + hLayout->addWidget(fTheoAdd); + + QFormLayout *layout = new QFormLayout; + layout->addRow("Enter Theory:", fTheo); + layout->addRow(fEditTemplate); + layout->addRow("Clear Theory:", fClearAll); + layout->addRow("Pre Def. Theory Select:", hLayout); + layout->addRow("Press for Validation:", fCheckTheo); + + setLayout(layout); + + QObject::connect(fEditTemplate, SIGNAL(stateChanged(int)), this, SLOT(templateState(int))); + QObject::connect(fClearAll, SIGNAL(clicked()), this, SLOT(clearAll())); + QObject::connect(fCheckTheo, SIGNAL(clicked()), this, SLOT(checkTheory())); + QObject::connect(fTheoAdd, SIGNAL(clicked()), this, SLOT(addTheory())); +} + +//------------------------------------------------------------------------- +void PTheoPage::initializePage() +{ + QString str = QString("Now you will need to enter your theory. Fit type: %1").arg(fMsrData->getFitTypeString()); + setSubTitle(str); +} + +//------------------------------------------------------------------------- +/** + * @brief PTheoPage::nextId + * @return + */ +int PTheoPage::nextId() const +{ + if (fHaveFunc) + return PMusrWiz::ePageFunctions; + else if (fHaveMap) + return PMusrWiz::ePageMaps; + else + return PMusrWiz::ePageParameters; +} + +//------------------------------------------------------------------------- +/** + * @brief PTheoPage::validatePage + * @return + */ +bool PTheoPage::validatePage() +{ + if (fTheo->toPlainText().isEmpty()) + return false; + + fMsrData->clearParam(); + fFunList.clear(); +// fMsrData->clearFunc(); + fMsrData->clearMap(); + + checkTheory(); + if (!fTheoValid) + return false; + + // transfer theory string + fMsrData->setTheory(fTheo->toPlainText()); + + // transfer found parameters + fMsrData->setParam(fParamList); + + // transfer found maps + fMsrData->setMap(fMapList); + + // transfer found functions + if (fHaveFunc) { + QString funStr; + for (int i=0; iisPresent(funStr)) { + funStr = QString("fun%1 = ??").arg(fFunList[i]); + fMsrData->setFunc(fFunList[i], funStr); + } + } + } + + // check if it is necessary to eliminate functions which are not present anymore + if (fFunList.size() != fMsrData->getNoOfFunc()) { + // remove functions from fMsrData which are NOT found in fFuncList + fMsrData->removeFunc(fFunList); + } + + return true; +} + +//------------------------------------------------------------------------- +/** + * + */ +void PTheoPage::templateState(int state) +{ + if (state == Qt::Checked) { + fTheo->setTextInteractionFlags(Qt::TextEditorInteraction); + fMsrData->setTemplate(-1); + fEditTemplate->hide(); + fEditTemplate->setCheckState(Qt::Unchecked); + } +} + +//------------------------------------------------------------------------- +/** + * + */ +void PTheoPage::clearAll() +{ + fTheo->clear(); + fTheo->setTextInteractionFlags(Qt::TextEditorInteraction); + fEditTemplate->hide(); + fMsrData->setTemplate(-1); +} + +//------------------------------------------------------------------------- +/** + * @brief PTheoPage::addTheory + */ +void PTheoPage::addTheory() +{ + int idx = fTheoSelect->currentIndex(); + bool isTempl = false; + QString item = fTheoSelect->currentText(); + if (item.startsWith("T:")) { + fEditTemplate->show(); + isTempl = true; + } + + QString theo(""); + bool emptyTheo = false; + if (fTheo->toPlainText().isEmpty()) { // empty theory + emptyTheo = true; + theo = getTheoryFunction(idx); + if (theo == "??") + return; + fTheo->setPlainText(theo); + } else { // theory already has some stuff + emptyTheo = false; + theo = getTheoryFunction(idx); + if (theo == "??") + return; + fTheo->appendPlainText("+"); + fTheo->appendPlainText(theo); + } + + if (isTempl && emptyTheo) { + fTheo->setTextInteractionFlags(Qt::TextBrowserInteraction); + fMsrData->setTemplate(idx); + fMsrData->setTemplate(fAdmin->getTheoTemplate(idx)); + } +} + +//------------------------------------------------------------------------- +/** + * @brief PTheoPage::checkTheory + */ +void PTheoPage::checkTheory() +{ + fTheoValid = false; + + // reset all lists: + fParamList.clear(); + fMapList.clear(); + fFunList.clear(); + + // check theory the following way: + // (i) make sure that line by line is a valid function + // (ii) make a collection of parameters with names suggested + // (iii) make a collection of functions if present + // (iv) make a map list if present + + QString str = fTheo->toPlainText(); + QStringList line = str.split("\n"); + bool ok = true; + PMusrfitFunc func; + for (int i=0; igetMusrfitFunc(strList[0]); + if (func.getName() == "UnDef") { // function not found + QString str = QString("**ERROR** in line %1, '%2' is not a recognized musrfit function.").arg(i+1).arg(line[i]); + QMessageBox::critical(0, "Check Theory", str); + // eventually it would be nice to highlight the faulty line + return; + } + ok = analyzeTokens(line[i], func.getNoOfParam()); + if (!ok) { + QString str = QString("**ERROR** in line %1.\n %2 takes %3 parameter.").arg(i+1).arg(func.getName()).arg(func.getNoOfParam()); + QMessageBox::critical(0, "Check Theory", str); + // eventually it would be nice to highlight the faulty line + return; + } + } + } + + if (fMapList.size() > 0) + fHaveMap = true; + else + fHaveMap = false; + + if (fFunList.size() > 0) + fHaveFunc = true; + else + fHaveFunc = false; + + fTheoValid = true; + + QObject *obj = sender(); + if (obj == fCheckTheo) + QMessageBox::information(0, "Check Theory", "Theory seems to be OK."); +} + +//------------------------------------------------------------------------- +/** + * @brief PTheoPage::getTheoryFunction + * @param idx + * @return + */ +QString PTheoPage::getTheoryFunction(int idx) +{ + QString result("??"); + QVector templ = fAdmin->getTheoTemplates(); + QVector func = fAdmin->getMusrfitFunc(); + static int mapCount = 1; + + if (idx >= templ.size()) { // deal with musrfit functions + if (idx >= templ.size() + func.size()) + return result; + result = func[idx-templ.size()].getAbbrv(); + for (int i=0; igetMusrfitFunc(theo); + if (func.getName() == "UnDef") { + // something is fundamentaly wrong + return; + } + + QString str; + par.setNumber(paramNo); + str = QString("%1_%2").arg(func.getFuncParam(paramIdx-1).getParamName()).arg(fTheoBlockNo); + par.setName(str); + par.setValue(func.getFuncParam(paramIdx-1).getParamValue()); + if (par.getName().contains("Ph_")) + par.setStep(10.0); + else + par.setStep(par.getValue() * 0.1); + + // keep parameter entry + fParamList.push_back(par); +} + +//------------------------------------------------------------------------- +/** + * @brief PTheoPage::dealWithMap + * @param theo + * @param mapNo + * @param paramIdx + */ +void PTheoPage::dealWithMap(QString theo, int mapNo, int paramIdx) +{ + // check if mapNo is already in the map list + for (int i=0; igetMusrfitFunc(theo); + if (func.getName() == "UnDef") { + // something is fundamentaly wrong + return; + } + + map.setNumber(mapNo); + str = QString("%1_%2").arg(func.getFuncParam(paramIdx-1).getParamName()).arg(mapNo); + map.setName(str); + fMapList.push_back(map); + } +} + +//------------------------------------------------------------------------- +/** + * @brief PTheoPage::dealWithFun + * @param funNo + */ +void PTheoPage::dealWithFun(int funNo) +{ + // check if funNo is already in the fun list + for (int i=0; iMaps"); + QString str = QString("Here you can fine tune your map template names. Fit type: %1").arg(fMsrData->getFitTypeString()); + setSubTitle(str); + + // sort maps + fMsrData->sort("map"); + + fMapPageLayout = new QFormLayout; + setLayout(fMapPageLayout); + + // make sure that the map list is empty + fMapGuiVec.clear(); + + // fill Map + PParamGui mapGui; + PParam map; + + // check if this is a template. If this is the case, fill fMsrData maps with the template info. + if (fMsrData->isTemplate()) { + PTheoTemplate templ = fMsrData->getTemplate(); + fMsrData->clearMap(); + for (int i=0; isetMap(i, templ.getMap(i)); + } + } + + for (int i=0; igetNoOfMap(); i++) { + map = fMsrData->getMap(i); + mapGui.paramName = new QLineEdit(map.getName()); + mapGui.paramVal = new QLineEdit("3.45"); + mapGui.paramStep = new QLineEdit("0.01"); + mapGui.paramBoundLow = new QLineEdit(); + mapGui.paramBoundHigh = new QLineEdit(); + fMapGuiVec.push_back(mapGui); + } + + QHBoxLayout *hLayout; + + // header + hLayout = new QHBoxLayout(); + mapGui.paramName = new QLineEdit("Name"); + mapGui.paramName->setReadOnly(true); + mapGui.paramVal = new QLineEdit("Value"); + mapGui.paramVal->setReadOnly(true); + mapGui.paramStep = new QLineEdit("Step"); + mapGui.paramStep->setReadOnly(true); + mapGui.paramBoundLow = new QLineEdit("BoundLow"); + mapGui.paramBoundLow->setReadOnly(true); + mapGui.paramBoundHigh = new QLineEdit("BoundHigh"); + mapGui.paramBoundHigh->setReadOnly(true); + hLayout->addWidget(mapGui.paramName); + hLayout->addWidget(mapGui.paramVal); + hLayout->addWidget(mapGui.paramStep); + hLayout->addWidget(mapGui.paramBoundLow); + hLayout->addWidget(mapGui.paramBoundHigh); + + fMapPageLayout->addRow("No", hLayout); + + for (int i=0; iaddWidget(fMapGuiVec[i].paramName); + hLayout->addWidget(fMapGuiVec[i].paramVal); + hLayout->addWidget(fMapGuiVec[i].paramStep); + hLayout->addWidget(fMapGuiVec[i].paramBoundLow); + hLayout->addWidget(fMapGuiVec[i].paramBoundHigh); + + fMapPageLayout->addRow(QString("map%1").arg(i+1), hLayout); + } + + fShowTheo = new QPushButton("Show &Theory"); + fMapPageLayout->addRow(fShowTheo); + + update(); + + connect(fShowTheo, SIGNAL(pressed()), this, SLOT(showTheo())); +} + +//------------------------------------------------------------------------- +/** + * @brief PMapPage::validatePage + * @return + */ +bool PMapPage::validatePage() +{ + // collect the map information + PParam map; + QString str; + double dval; + bool ok; + + for (int i=0; igetMap(i).getNumber()); + str = fMapGuiVec[i].paramName->text(); + map.setName(str); + + dval = fMapGuiVec[i].paramVal->text().toDouble(&ok); + if (ok) + map.setValue(dval); + else + map.setValue(0.0); + + dval = fMapGuiVec[i].paramStep->text().toDouble(&ok); + if (ok) + map.setStep(dval); + else + map.setStep(0.0); + + map.setPosErr("none"); + map.setBoundLow(fMapGuiVec[i].paramBoundLow->text()); + map.setBoundHigh(fMapGuiVec[i].paramBoundHigh->text()); + + fMsrData->setMap(i, map); + } + + return true; +} + +//------------------------------------------------------------------------- +/** + * @brief PMapPage::showTheo + */ +void PMapPage::showTheo() +{ + PShowTheo *showTheo = new PShowTheo(fMsrData->getTheory(), fMsrData->getFuncAll(), this); + showTheo->show(); +} + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/** + * @brief PFuncPage::PFuncPage + */ +PFuncPage::PFuncPage(PMsrData *data, QWidget *parent) : + QWizardPage(parent), + fMsrData(data) +{ + setTitle("

Functions

"); + QString str = QString("Now you will need to enter your functions. Fit type: %1").arg(fMsrData->getFitTypeString()); + setSubTitle(str); + + fFunc = new QPlainTextEdit(); + fFunc->setWhatsThis("Enter the function(s) here."); + + fShowTheo = new QPushButton("Show &Theory"); + + QFormLayout *layout = new QFormLayout; + layout->addRow("Enter Function(s):", fFunc); + layout->addRow(fShowTheo); + + setLayout(layout); + + connect(fShowTheo, SIGNAL(pressed()), this, SLOT(showTheo())); +} + +//------------------------------------------------------------------------- +/** + * @brief PFuncPage::showTheo + */ +void PFuncPage::showTheo() +{ + PShowTheo *showTheo = new PShowTheo(fMsrData->getTheory(), "", this); + showTheo->show(); +} + +//------------------------------------------------------------------------- +/** + * @brief PFuncPage::nextId + * @return + */ +int PFuncPage::nextId() const +{ + if (fMsrData->getNoOfMap() > 0) + return PMusrWiz::ePageMaps; + else + return PMusrWiz::ePageParameters; +} + +//------------------------------------------------------------------------- +/** + * + */ +void PFuncPage::initializePage() +{ + QString str = QString("Now you will need to enter your functions. Fit type: %1").arg(fMsrData->getFitTypeString()); + setSubTitle(str); + + // check if this is a template. If this is the case, fill fMsrData functions with the template info. + if (fMsrData->isTemplate()) { + // fill functions according to the template + PTheoTemplate templ = fMsrData->getTemplate(); + fMsrData->clearFunc(); + for (int i=0; isetFunc(templ.getFuncNo(i), templ.getFunc(i)); + } + } + + fMsrData->sort("func"); + fFunc->clear(); + for (int i=0; igetNoOfFunc(); i++) { + fFunc->appendPlainText(fMsrData->getFunc(fMsrData->getFuncNo(i))); + } +} + +//------------------------------------------------------------------------- +/** + * + */ +void PFuncPage::cleanupPage() +{ + fMsrData->clearFunc(); + + // keep the function information + QString str = fFunc->toPlainText(); + QStringList funList = str.split("\n"); + int funNo=0; + for (int i=0; isetFunc(funNo, funList[i]); + } +} + +//------------------------------------------------------------------------- +/** + * @brief PFuncPage::validatePage + * @return + */ +bool PFuncPage::validatePage() +{ + QVector paramList; + QVector mapList; + + QString str = fFunc->toPlainText(); + QString sstr; + QString tok; + int idx = 0, parNo, mapNo; + bool ok; + + // collect potentially present parameters + PParam param; + while ((idx = str.indexOf("par", idx)) != -1) { + tok = ""; + idx += 3; + while (str[idx].isDigit()) { + tok += str[idx++]; + } + parNo = tok.toInt(&ok); + if (ok) { + param.setNumber(parNo); + sstr = QString("par%1").arg(parNo); + param.setName(sstr); + param.setValue(0.0); + param.setStep(0.1); + paramList.push_back(param); + } + } + fMsrData->appendParam(paramList); + + // collect potentially present maps + str = fFunc->toPlainText(); + PParam map; + idx = 0; + while ((idx = str.indexOf("map", idx)) != -1) { + tok = ""; + idx += 3; + while (str[idx].isDigit()) { + tok += str[idx++]; + } + mapNo = tok.toInt(&ok); + if (ok) { + map.setNumber(mapNo); + sstr = QString("map%1").arg(mapNo); + map.setName(sstr); + mapList.push_back(map); + } + } + fMsrData->appendMap(mapList); + + // keep the function information + str = fFunc->toPlainText(); + QStringList funList = str.split("\n"); + int funNo = 0; + fMsrData->clearFunc(); + for (int i=0; isetFunc(i, funList[i]); + } + + return true; +} + +//------------------------------------------------------------------------- +/** + * @brief PFuncPage::getFuncNo + * @param str + * @return + */ +int PFuncPage::getFuncNo(const QString str) +{ + QString strNo = str; + + // str should have to form fun = , where is an int + if (!str.startsWith("fun")) + return -1; + + strNo.remove(0, 3); // get rid of 'fun' + int idx = strNo.indexOf("="); + if (idx == -1) + return -1; + + strNo.remove(idx, str.length()-idx); + + bool ok; + int ival = strNo.toInt(&ok); + if (!ok) + return -1; + + return ival; +} + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/** + * @brief PParamPage::PParamPage + */ +PParamPage::PParamPage(PMsrData *data, QWidget *parent) : + QWizardPage(parent), + fMsrData(data) +{ + fParameterPageLayout = 0; +} + +//------------------------------------------------------------------------- +/** + * @brief PParamPage::nextId + * @return + */ +int PParamPage::nextId() const +{ + return PMusrWiz::ePageFitInfo; +} + +//------------------------------------------------------------------------- +/** + * @brief PParamPage::initializePage + */ +void PParamPage::initializePage() +{ + // sort parameter vector + fMsrData->sort("param"); + + setTitle("

Fit Parameters

"); + QString str = QString("Here you can fine tune your parameters. Fit type: %1").arg(fMsrData->getFitTypeString()); + setSubTitle(str); + + fParameterPageLayout = new QFormLayout; + setLayout(fParameterPageLayout); + + // make sure that parameter list is empty + fParamGuiVec.clear(); + + // fill parameters + PParamGui paramGui; + PParam param; + + // if a template replace the parameters found so far by the template parameter settings + if (fMsrData->isTemplate()) { + fMsrData->clearParam(); + PTheoTemplate templ = fMsrData->getTemplate(); + for (int i=0; isetParam(i, templ.getParam(i)); + } + } + + for (int i=0; igetNoOfParam(); i++) { + param = fMsrData->getParam(i); + paramGui.paramName = new QLineEdit(param.getName()); + paramGui.paramVal = new QLineEdit(QString("%1").arg(param.getValue())); + paramGui.paramStep = new QLineEdit(QString("%1").arg(param.getStep())); + paramGui.paramBoundLow = new QLineEdit(); + paramGui.paramBoundHigh = new QLineEdit(); + fParamGuiVec.push_back(paramGui); + } + + QHBoxLayout *hLayout; + + // header + hLayout = new QHBoxLayout(); + paramGui.paramName = new QLineEdit("Name"); + paramGui.paramName->setReadOnly(true); + paramGui.paramVal = new QLineEdit("Value"); + paramGui.paramVal->setReadOnly(true); + paramGui.paramStep = new QLineEdit("Step"); + paramGui.paramStep->setReadOnly(true); + paramGui.paramBoundLow = new QLineEdit("BoundLow"); + paramGui.paramBoundLow->setReadOnly(true); + paramGui.paramBoundHigh = new QLineEdit("BoundHigh"); + paramGui.paramBoundHigh->setReadOnly(true); + hLayout->addWidget(paramGui.paramName); + hLayout->addWidget(paramGui.paramVal); + hLayout->addWidget(paramGui.paramStep); + hLayout->addWidget(paramGui.paramBoundLow); + hLayout->addWidget(paramGui.paramBoundHigh); + fParameterPageLayout->addRow("No", hLayout); + + for (int i=0; iaddWidget(fParamGuiVec[i].paramName); + hLayout->addWidget(fParamGuiVec[i].paramVal); + hLayout->addWidget(fParamGuiVec[i].paramStep); + hLayout->addWidget(fParamGuiVec[i].paramBoundLow); + hLayout->addWidget(fParamGuiVec[i].paramBoundHigh); + fParameterPageLayout->addRow(QString("%1").arg(i+1), hLayout); + } + + fShowTheo = new QPushButton("Show &Theory"); + fParameterPageLayout->addRow(fShowTheo); + + update(); + + connect(fShowTheo, SIGNAL(pressed()), this, SLOT(showTheo())); +} + +//------------------------------------------------------------------------- +/** + * @brief PParamPage::validatePage + * @return + */ +bool PParamPage::validatePage() +{ + PParam param; + QString str; + double dval; + bool ok; + + for (int i=0; igetParam(i).getNumber()); + str = fParamGuiVec[i].paramName->text(); + param.setName(str); + + dval = fParamGuiVec[i].paramVal->text().toDouble(&ok); + if (ok) + param.setValue(dval); + else + param.setValue(0.0); + + dval = fParamGuiVec[i].paramStep->text().toDouble(&ok); + if (ok) + param.setStep(dval); + else + param.setStep(0.0); + + param.setPosErr("none"); + param.setBoundLow(fParamGuiVec[i].paramBoundLow->text()); + param.setBoundHigh(fParamGuiVec[i].paramBoundHigh->text()); + + fMsrData->setParam(i, param); + } + + return true; +} + +//------------------------------------------------------------------------- +/** + * @brief PParamPage::showTheo + */ +void PParamPage::showTheo() +{ + PShowTheo *showTheo = new PShowTheo(fMsrData->getTheory(), fMsrData->getFuncAll(), this); + showTheo->show(); +} + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/** + * @brief PFitInfoPage::PFitInfoPage + */ +PFitInfoPage::PFitInfoPage(PMsrData *data, QWidget *parent) : + QWizardPage(parent), + fMsrData(data) +{ + setTitle("

Fit Info

"); + QString str = QString("Collect necessary fit information. Fit type: %1").arg(fMsrData->getFitTypeString()); + setSubTitle(str); + + fFitRangeStart = new QLineEdit("0.0"); + fFitRangeStart->setValidator(new QDoubleValidator()); + fFitRangeEnd = new QLineEdit("9.0"); + fFitRangeEnd->setValidator(new QDoubleValidator()); + + QHBoxLayout *hLayout = new QHBoxLayout(); + hLayout->addWidget(fFitRangeStart); + hLayout->addWidget(fFitRangeEnd); + + fPacking = new QLineEdit("1"); + fPacking->setValidator(new QIntValidator()); + + fCommands = new QPlainTextEdit(); + fCommands->setPlainText("#MAX_LIKELIHOOD\nPRINT_LEVEL 2\nMINIMIZE\nMINOS\nSAVE"); + + QFormLayout *layout = new QFormLayout; + layout->addRow("Fit Range:", hLayout); + layout->addRow("Packing:", fPacking); + layout->addRow("Commands:", fCommands); + + setLayout(layout); +} + +//------------------------------------------------------------------------- +/** + * @brief PFitInfoPage::initializePage + */ +void PFitInfoPage::initializePage() +{ + QString str = QString("Collect necessary fit information. Fit type: %1").arg(fMsrData->getFitTypeString()); + setSubTitle(str); +} + +//------------------------------------------------------------------------- +/** + * @brief PFitInfoPage::nextId + * @return + */ +int PFitInfoPage::nextId() const +{ + return PMusrWiz::ePageConclusion; +} + +//------------------------------------------------------------------------- +/** + * @brief PFitInfoPage::validatePage + * @return + */ +bool PFitInfoPage::validatePage() +{ + bool ok; + int ival = fPacking->text().toInt(&ok); + if (ok) + fMsrData->setPacking(ival); + + double dval = fFitRangeStart->text().toDouble(&ok); + if (ok) + fMsrData->setFitStart(dval); + dval = fFitRangeEnd->text().toDouble(&ok); + if (ok) + fMsrData->setFitEnd(dval); + + fMsrData->setCmd(fCommands->toPlainText()); + + return true; +} + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/** + * @brief PConclusionPage::PConclusionPage + */ +PConclusionPage::PConclusionPage(PAdmin *admin, PMsrData *data, QString *msrFilePath, QWidget *parent) : + QWizardPage(parent), + fMsrFilePath(msrFilePath), + fAdmin(admin), + fMsrData(data) +{ + QDir ddir = QDir(*fMsrFilePath); + + setTitle("

Create

"); + setSubTitle("Now we create the msr-file."); + + QVBoxLayout *vLayout = new QVBoxLayout; + + fMsrPathFileLabel = new QLabel("Current msr-File Path:"); + fMsrFilePathLineEdit = new QLineEdit(ddir.absolutePath()); + fMsrFilePathLineEdit->setReadOnly(true); + fSaveAsMsrFile = new QPushButton("Save As (msr-file path)"); + fSaveAsTemplate = new QPushButton("Save As (template)"); + + vLayout->addWidget(fMsrPathFileLabel); + vLayout->addWidget(fMsrFilePathLineEdit); + vLayout->addWidget(fSaveAsMsrFile); + vLayout->addStretch(1); + vLayout->addWidget(fSaveAsTemplate); + + setLayout(vLayout); + + connect(fSaveAsMsrFile, SIGNAL(pressed()), this, SLOT(saveAsMsrFile())); + connect(fSaveAsTemplate, SIGNAL(pressed()), this, SLOT(saveAsTemplate())); +} + +//------------------------------------------------------------------------- +void PConclusionPage::saveAsMsrFile() +{ + QString str = QFileDialog::getExistingDirectory(this, tr("Save in Directory"), "./", + QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + if (!str.isEmpty()) { + *fMsrFilePath = str; + fMsrFilePathLineEdit->setText(str); + } +} + +//------------------------------------------------------------------------- +/** + * + */ +void PConclusionPage::saveAsTemplate() +{ + bool newTemplate = false; + + QStringList list; + list << ""; + for (int i=0; igetTheoTemplateSize(); i++) + list << fAdmin->getTheoTemplate(i).getName(); + + bool ok; + QString result = QInputDialog::getItem(this, "Save As Template", "Template Name", list, 0, false, &ok); + if (!ok) + return; + + if (result == "") { + QString text(""); + result = QInputDialog::getText(this, "New Template Name", "Enter Template Name", QLineEdit::Normal, text, &ok); + if (!ok) + return; + // analyze the name: it has to start with 'T: ' + if (!result.startsWith("T: ")) + result.prepend("T: "); + newTemplate = true; + } + + // read musrfit_funcs.xml + QString path = std::getenv("HOME"); + QString pathFln = path + "/.musrfit/musrWiz/musrfit_funcs.xml"; + bool found = false; + if (QFile::exists(pathFln)) { + found = true; + } + if (!found) { + QMessageBox::critical(this, "ERROR", "Couldn't find musrfit_funcs.xml"); + return; + } + + QFile fin(pathFln); + if (!fin.open(QIODevice::ReadOnly | QIODevice::Text)) { + QMessageBox::critical(this, "ERROR", "Couldn't open musrfit_funcs.xml for reading."); + return; + } + + QTextStream in(&fin); + QString data = in.readAll(); + fin.close(); + + int idx, idxEnd; + QString insertStr, errMsg; + if (newTemplate) { // new template + // first find the proper place where to insert the new template + idx = data.lastIndexOf(""); + if (idx == -1) { + QMessageBox::critical(this, "ERROR", "Couldn't find last theo_template. Something is very wrong."); + return; + } + idx = data.indexOf(" + + + + T: 1 [exp x cos](TF) + a 1\nse 2\ntf fun1 4 + fun1=par3+map1 + + + + + + + + T: 2 [exp x cos](TF) + a 1\nse 2\ntf fun1 4\n+\na 5\nse 6\ntf fun1 7 + fun1=par3+map1 + + + + + + + + + + + T: 3 [exp x cos](TF) + a 1\nse 2\ntf fun1 4\n+\na 5\nse 6\ntf fun1 7\n+\na 8\nse 9\ntf fun1 10 + fun1=par3+map1 + + + + + + + + + + + + + + T: 1 [gauss x cos](TF) + a 1\nsg 2\ntf fun1 4 + fun1=par3+map1 + + + + + + + + T: 2 [gauss x cos](TF) + a 1\nsg 2\ntf fun1 4\n+\na 5\nsg 6\ntf fun1 7 + fun1=par3+map1 + + + + + + + + + + + T: 3 [gauss x cos](TF) + a 1\nsg 2\ntf fun1 4\n+\na 5\nsg 6\ntf fun1 7\n+\na 8\nsg 9\ntf fun1 10 + fun1=par3+map1 + + + + + + + + + + + + + + + + + + asymmetry + a + 1 + + Asym + 0.2 + + + + + simplExpo + se + 1 + + Lambda + 0.5 + + + + + simpleGss + sg + 1 + + Sigma + 0.5 + + + + + generExpo + ge + 2 + + Lambda + 0.5 + + + Beta + 1.5 + + + + + TFieldCos + tf + 2 + + Ph + 0.0 + y + + + Freq + 10.0 + + + + + internFld + if + 5 + + Weight + 0.66 + + + Ph + 0.0 + + + Freq + 10.0 + + + LambdaT + 0.5 + + + LambdaL + 0.1 + + + + + Bessel + b + 2 + + Ph + 0.0 + + + Freq + 10.0 + + + + + internBsl + ib + 5 + + Weight + 0.66 + + + Ph + 0.0 + + + Freq + 10.0 + + + LambdaT + 0.5 + + + LambdaL + 0.1 + + + + + statGssKT + stg + 1 + + Sigma + 0.3 + + + + + statGssKTLF + sgktlf + 2 + + Hopp + 0.1 + + + Sigma + 0.3 + + + + + dynGssKTLF + dgktlf + 3 + + Freq + 0.0 + + + Sigma + 0.3 + + + Gamma + 0.5 + + + + + statExpKT + sekt + 1 + + Lambda + 0.3 + + + + + statExpKTLF + sektlf + 2 + + Hopp + 0.1 + + + Lambda + 0.3 + + + + + dynExpKTLF + dektlf + 3 + + Freq + 0.1 + + + Lambda + 0.3 + + + Gamma + 0.5 + + + + + combiLGKT + lgkt + 2 + + Lambda + 0.2 + + + Sigma + 0.3 + + + + + strKT + skt + 2 + + Sigma + 0.3 + + + Beta + 2.0 + + + + + spinGlass + spg + 3 + + Lambda + 0.3 + + + Gamma + 0.1 + + + q + 0.8 + + + + + rdAnisoHf + rahf + 2 + + Nu + 1.5 + + + Lambda + 0.3 + + + + + abragam + ab + 2 + + Sigma + 0.5 + + + Gamma + 0.2 + + + + + skewedGss + skg + 4 + + Ph + 0.0 + + + Freq + 10.0 + + + SigmaPlus + 1.1 + + + SigmaMinus + 0.3 + + + + + staticNKZF + snkzf + 2 + + Delta + 0.5 + + + Rb + 0.2 + + + + + staticNKTF + snktf + 4 + + Ph + 0.0 + + + Frq + 10.5 + + + Delta + 0.5 + + + Rb + 0.2 + + + + + dynamicNKZF + dnkzf + 3 + + Delta + 0.5 + + + Rb + 0.2 + + + Hopp + 1.0 + + + + + dynamicNKTF + dnktf + 5 + + Ph + 0.0 + + + Frq + 10.5 + + + Delta + 0.5 + + + Rb + 0.2 + + + Hopp + 1.0 + + + + + muMinusExpTF + mmsetf + 6 + + N0 + 100.0 + + + Tau + 1.0 + + + Asym + 0.08 + + + Lambda + 1.1 + + + Ph + 0.0 + + + Frq + 10.2 + + + diff --git a/src/musredit_qt6/musrWiz/icons/musrWiz-22x22-dark.svg b/src/musredit_qt6/musrWiz/icons/musrWiz-22x22-dark.svg new file mode 100644 index 00000000..69f78f45 --- /dev/null +++ b/src/musredit_qt6/musrWiz/icons/musrWiz-22x22-dark.svg @@ -0,0 +1,161 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musrWiz/icons/musrWiz-22x22.png b/src/musredit_qt6/musrWiz/icons/musrWiz-22x22.png new file mode 100644 index 00000000..17139ff3 Binary files /dev/null and b/src/musredit_qt6/musrWiz/icons/musrWiz-22x22.png differ diff --git a/src/musredit_qt6/musrWiz/icons/musrWiz-22x22.svg b/src/musredit_qt6/musrWiz/icons/musrWiz-22x22.svg new file mode 100644 index 00000000..94ad8bac --- /dev/null +++ b/src/musredit_qt6/musrWiz/icons/musrWiz-22x22.svg @@ -0,0 +1,161 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musrWiz/icons/musrWiz-32x32-dark.svg b/src/musredit_qt6/musrWiz/icons/musrWiz-32x32-dark.svg new file mode 100644 index 00000000..05c4e5fa --- /dev/null +++ b/src/musredit_qt6/musrWiz/icons/musrWiz-32x32-dark.svg @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musrWiz/icons/musrWiz-32x32.png b/src/musredit_qt6/musrWiz/icons/musrWiz-32x32.png new file mode 100644 index 00000000..5aa3f629 Binary files /dev/null and b/src/musredit_qt6/musrWiz/icons/musrWiz-32x32.png differ diff --git a/src/musredit_qt6/musrWiz/icons/musrWiz-32x32.svg b/src/musredit_qt6/musrWiz/icons/musrWiz-32x32.svg new file mode 100644 index 00000000..1b3cafe5 --- /dev/null +++ b/src/musredit_qt6/musrWiz/icons/musrWiz-32x32.svg @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musrWiz/icons/musrWiz.icns b/src/musredit_qt6/musrWiz/icons/musrWiz.icns new file mode 100644 index 00000000..1b8773c6 Binary files /dev/null and b/src/musredit_qt6/musrWiz/icons/musrWiz.icns differ diff --git a/src/musredit_qt6/musrWiz/instrument_defs/instrument_def_isis.xml b/src/musredit_qt6/musrWiz/instrument_defs/instrument_def_isis.xml new file mode 100644 index 00000000..7b5e2135 --- /dev/null +++ b/src/musredit_qt6/musrWiz/instrument_defs/instrument_def_isis.xml @@ -0,0 +1,23 @@ + + + ISIS + + + HIFINNNNNNNN + HIFI + NEXUS + + 128 + 0 + 2047 + + + + + + + + + + + \ No newline at end of file diff --git a/src/musredit_qt6/musrWiz/instrument_defs/instrument_def_psi.xml b/src/musredit_qt6/musrWiz/instrument_defs/instrument_def_psi.xml new file mode 100644 index 00000000..3c703ede --- /dev/null +++ b/src/musredit_qt6/musrWiz/instrument_defs/instrument_def_psi.xml @@ -0,0 +1,166 @@ + + + PSI + + + dYYYY/tdc/tdc_hifi_YYYY_NNNNN + PIE3 + PSI-MDU + + 16 + 50 + 409500 + 500 15000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + YYYY/lemYY_his_NNNN + MUE4 + MUSR-ROOT + + 8 + 0 + 63000 + 200 1500 + + + + + + + + + 8 + 0 + 63000 + 200 1500 + + + + + + + + + 4 + 0 + 63000 + 200 1500 + + + + + + 4 + 0 + 63000 + 200 1500 + + + + + + 4 + 0 + 63000 + 200 1500 + + + + 4 + 0 + 63000 + 200 1500 + + + + 8 + 0 + 63000 + 200 1500 + + + + 8 + 0 + 63000 + 200 1500 + + + + + + dYYYY/tdc/deltat_tdc_gps_NNNN + PIM3 + PSI-BIN + + 6 + 10 + 25600 + 50 300 + + + + + + + + + 6 + 10 + 25600 + 50 300 + + + + + + + + + 6 + 10 + 25600 + 50 300 + + + + 6 + 20 + 25600 + 50 300 + + + + diff --git a/src/musredit_qt6/musrWiz/musrWiz.cpp b/src/musredit_qt6/musrWiz/musrWiz.cpp new file mode 100644 index 00000000..68d09d62 --- /dev/null +++ b/src/musredit_qt6/musrWiz/musrWiz.cpp @@ -0,0 +1,140 @@ +#include +#include + +#include +#include +#include +#include + +#include "git-revision.h" +#include "musrWiz.h" +#include "PAdmin.h" +#include "PMusrWiz.h" + +//------------------------------------------------------------------- +/** + * + */ +void PParam::init() +{ + fName = QString("UnDef"); + fNumber = -1; + fValue = 0.0; + fStep = 0.0; + fPosErr = QString("UnDef"); + fBoundLow = QString("UnDef"); + fBoundHigh = QString("UnDef"); +} + +//------------------------------------------------------------------- +/** + * + */ +void musrWiz_syntax() +{ + std::cout << "usage: musrWiz [[--version | -v] | --debug [0|1|2] | --help]" << std::endl << std::endl; + std::cout << " --version | -v : print current git-version." << std::endl; + std::cout << " --debug 0 : dump's the instrument definition(s) at startup." << std::endl; + std::cout << " --debug 1 : dump's the musrfit functions at startup." << std::endl; + std::cout << " --debug 2 : dump's the musrfit functions and instrument definition(s) at startup." << std::endl; + std::cout << " --log : writes a log-file 'musrWiz.log' which contains the path-file-name of" << std::endl; + std::cout << " the created msr-file." << std::endl; + std::cout << " --help : shows this help." << std::endl << std::endl; +} + +//------------------------------------------------------------------- +/** + * + */ +int main(int argc, char *argv[]) +{ + int dump = -1; + bool logFile = false; + + if (argc == 2) { + if (!strcmp(argv[1], "--version") || (!strcmp(argv[1], "-v"))) { + std::cout << std::endl << "musrWiz - git-branch: " << GIT_BRANCH << ", git-rev: " << GIT_CURRENT_SHA1 << std::endl << std::endl; + return 0; + } else if (!strcmp(argv[1], "--help")) { + musrWiz_syntax(); + return 0; + } else if (!strcmp(argv[1], "--log")) { // thought to be used from within musredit only + logFile = true; + } else { + musrWiz_syntax(); + return 0; + } + } else if (argc == 3) { + dump = atoi(argv[2]); + if ((dump < 0) || (dump > 2)) { + musrWiz_syntax(); + return 0; + } + } + + Q_INIT_RESOURCE(musrWiz); + + QApplication app(argc, argv); + + PAdmin *admin = new PAdmin(); + if (!admin->IsValid()) { + delete admin; + return 1; + } + admin->dump(dump); + + PMsrData *info = new PMsrData(); // this content will eventually be set by the xml-handler + + PMusrWiz wizard(admin, info); + wizard.show(); + + app.exec(); + + int result = wizard.result(); + + if (result == 1) { // if everything went fine up to this point + // check if a log-file shall be written + QProcessEnvironment procEnv = QProcessEnvironment::systemEnvironment(); + QString pathName = procEnv.value("HOME", ""); + pathName += "/.musrfit/musredit/musrWiz.log"; + if (logFile) { + std::ofstream fout(pathName.toLatin1().data(), std::ofstream::out); + fout << "path-file-name: " << info->getMsrPathName().toLatin1().data() << "/" << info->getMsrFileName().toLatin1().data() << std::endl; + fout.close(); + } + + // check if musrt0 shall be called. If the option --log is set, only add musrt0 flag to in the musrWiz.log file + if (info->getT0Tag() == T0_FROM_MUSR_T0) { + if (logFile) { + std::ofstream fout(pathName.toLatin1().data(), std::ofstream::app); + fout << "musrt0-tag: yes" << std::endl; + fout.close(); + } else { + QString musrt0Path = procEnv.value("MUSRFITPATH", "??"); + if (musrt0Path == "??") { // not found hence try ROOTSYS + musrt0Path = procEnv.value("ROOTSYS", "??"); + if (musrt0Path != "??") { + musrt0Path += "/bin"; + } + } + + if (musrt0Path != "??") { + QString musrt0 = musrt0Path + "/musrt0"; + QString pathFln = QString("%1/%2").arg(info->getMsrPathName()).arg(info->getMsrFileName()); + QStringList arguments; + arguments << pathFln; + QProcess::startDetached(musrt0, arguments, "./"); + } else { + QMessageBox::warning(0, "WARNING", "Couldn't find musrt0 :-(.\n Only the msr-file has been generated."); + } + } + } + } + + if (info) + delete info; + if (admin) + delete admin; + + return result; +} diff --git a/src/musredit_qt6/musrWiz/musrWiz.h b/src/musredit_qt6/musrWiz/musrWiz.h new file mode 100644 index 00000000..aba308f3 --- /dev/null +++ b/src/musredit_qt6/musrWiz/musrWiz.h @@ -0,0 +1,75 @@ +/*************************************************************************** + + musrWiz.h + + 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. * + ***************************************************************************/ + +#ifndef _MUSRWIZ_H_ +#define _MUSRWIZ_H_ + +#include + +//------------------------------------------------------------------- +class PParam { + public: + PParam() { init(); } + ~PParam() {} + + void init(); + + QString getName() { return fName; } + int getNumber() { return fNumber; } + double getValue() { return fValue; } + double getStep() { return fStep; } + QString getPosErr() { return fPosErr; } + QString getBoundLow() { return fBoundLow; } + QString getBoundHigh() { return fBoundHigh; } + + void setName(QString str) { fName = str; } + void setNumber(int ival) { fNumber = ival; } + void setValue(double dval) { fValue = dval; } + void setStep(double dval) { fStep = dval; } + void setPosErr(QString str) { fPosErr = str; } + void setBoundLow(QString str) { fBoundLow = str; } + void setBoundHigh(QString str) { fBoundHigh = str; } + + private: + QString fName; + int fNumber; + double fValue; + double fStep; + QString fPosErr; + QString fBoundLow; + QString fBoundHigh; +}; + +//------------------------------------------------------------------- +typedef struct { + int number; + QString fun; +} PFunc; + +#endif // _MUSRWIZ_H_ diff --git a/src/musredit_qt6/musrWiz/musrWiz.pro b/src/musredit_qt6/musrWiz/musrWiz.pro new file mode 100644 index 00000000..8aa15983 --- /dev/null +++ b/src/musredit_qt6/musrWiz/musrWiz.pro @@ -0,0 +1,66 @@ +TEMPLATE = app +TARGET = musrWiz + +# install path for musrWiz +count( PREFIX, 1 ) { + MUSRWIZ_INSTALL_PATH = $${PREFIX}/bin +} +isEmpty( MUSRWIZ_INSTALL_PATH ) { + MUSR_FIT_PATH = $$(MUSRFITPATH) + count( MUSR_FIT_PATH, 1 ) { + MUSRWIZ_INSTALL_PATH = $$(MUSRFITPATH) + } +} +isEmpty( MUSRWIZ_INSTALL_PATH ) { + ROOT_SYS_PATH = $$(ROOTSYS) + count( ROOT_SYS_PATH, 1 ) { + MUSRWIZ_INSTALL_PATH = $$(ROOTSYS)/bin + } +} +isEmpty( MUSRWIZ_INSTALL_PATH ) { + MUSRWIZ_INSTALL_PATH = /usr/local/bin +} + +unix { + message( "Determined installation path: $${MUSRWIZ_INSTALL_PATH}" ) +} + +unix:target.path = $${MUSRWIZ_INSTALL_PATH} +macx:target.path = /Applications +win32:target.path = c:/musrfit/bin + +INSTALLS += target + +CONFIG += qt \ + warn_on \ + release + +QT += widgets +QT += xml +QT += core +QT += svg + +# set proper permission for Mac OSX +macx { + QMAKE_INSTALL_FILE = install -m 6755 -p -o $$(USER) -g staff +} + +INCLUDEPATH += "../../include" + +HEADERS = musrWiz.h \ + PTheoTemplate.h \ + PMusrfitFunc.h \ + PInstrumentDef.h \ + PAdmin.h \ + PMusrWiz.h + +SOURCES = PTheoTemplate.cpp \ + PMusrfitFunc.cpp \ + PInstrumentDef.cpp \ + PAdmin.cpp \ + PMusrWiz.cpp \ + musrWiz.cpp + +RESOURCES = musrWiz.qrc + +macx:ICON = icons/musrWiz.icns diff --git a/src/musredit_qt6/musrWiz/musrWiz.qrc b/src/musredit_qt6/musrWiz/musrWiz.qrc new file mode 100644 index 00000000..96164b50 --- /dev/null +++ b/src/musredit_qt6/musrWiz/musrWiz.qrc @@ -0,0 +1,12 @@ + + + icons/musrWiz-22x22.svg + icons/musrWiz-22x22-dark.svg + icons/musrWiz-32x32.svg + icons/musrWiz-32x32-dark.svg + musrWiz.xml + func_defs/musrfit_funcs.xml + instrument_defs/instrument_def_psi.xml + instrument_defs/instrument_def_isis.xml + + diff --git a/src/musredit_qt6/musrWiz/musrWiz.xml b/src/musredit_qt6/musrWiz/musrWiz.xml new file mode 100644 index 00000000..1d0225c4 --- /dev/null +++ b/src/musredit_qt6/musrWiz/musrWiz.xml @@ -0,0 +1,8 @@ + + + + PSI + LEM + Single Histo + + diff --git a/src/musredit_qt6/musredit/CMakeLists.txt b/src/musredit_qt6/musredit/CMakeLists.txt new file mode 100644 index 00000000..e3986681 --- /dev/null +++ b/src/musredit_qt6/musredit/CMakeLists.txt @@ -0,0 +1,148 @@ +#--- musredit for Qt > 6.0 ---------------------------------------------------- + +set(qt_libs Qt6::Core Qt6::Widgets Qt6::Network Qt6::Xml Qt6::Svg Qt6::PrintSupport) + +set(musredit_src + PTextEdit.cpp + PSubTextEdit.cpp + PAdmin.cpp + PFindDialog.cpp + PReplaceDialog.cpp + PReplaceConfirmationDialog.cpp + PFitOutputHandler.cpp + PDumpOutputHandler.cpp + PPrefsDialog.cpp + PGetMusrFTOptionsDialog.cpp + PGetTitleBlockDialog.cpp + PGetParameterBlockDialog.cpp + PGetTheoryBlockDialog.cpp + PGetFunctionsBlockDialog.cpp + PGetAsymmetryRunBlockDialog.cpp + PGetSingleHistoRunBlockDialog.cpp + PGetNonMusrRunBlockDialog.cpp + PGetFourierBlockDialog.cpp + PGetPlotBlockDialog.cpp + PMsr2DataDialog.cpp + PChangeDefaultPathsDialog.cpp + PMusrEditAbout.cpp + main.cpp +) + +set(musredit_ui + forms/PFindDialog.ui + forms/PReplaceDialog.ui + forms/PReplaceConfirmationDialog.ui + forms/PMusrEditAbout.ui + forms/PPrefsDialog.ui + forms/PGetMusrFTOptionsDialog.ui + forms/PGetTitleBlockDialog.ui + forms/PGetParameterBlockDialog.ui + forms/PGetTheoryBlockDialog.ui + forms/PGetFunctionsBlockDialog.ui + forms/PGetAsymmetryRunBlockDialog.ui + forms/PGetSingleHistoRunBlockDialog.ui + forms/PGetNonMusrRunBlockDialog.ui + forms/PGetFourierBlockDialog.ui + forms/PGetPlotBlockDialog.ui + forms/PMsr2DataDialog.ui + forms/PChangeDefaultPathsDialog.ui +) + +# Instruct CMake to run moc automatically when needed +set(CMAKE_AUTOMOC ON) + +#[==[ +# as35 currently CMAKE_AUTOUIC -> ON doesn't work since it requires the ui-files +# in the same directory as the cpp-files. +# Create code from a list of Qt designer ui files +set(CMAKE_AUTOUIC ON) +#]==] +set(CMAKE_AUTOUIC OFF) + +# call qt/uic +qt6_wrap_ui(out_ui ${musredit_ui}) +# add qt/rcc +qt6_add_resources(musredit_rcc musredit.qrc) + +# remove generated files from automoc and autouic +set_property(SOURCE ui_PFindDialog.h PROPERTY SKIP_AUTOMOC ON) +set_property(SOURCE ui_PReplaceDialog.h PROPERTY SKIP_AUTOMOC ON) +set_property(SOURCE ui_PReplaceConfirmationDialog.h PROPERTY SKIP_AUTOMOC ON) +set_property(SOURCE ui_PMusrEditAbout.h PROPERTY SKIP_AUTOMOC ON) +set_property(SOURCE ui_PPrefsDialog.h PROPERTY SKIP_AUTOMOC ON) +set_property(SOURCE ui_PGetMusrFTOptionsDialog.h PROPERTY SKIP_AUTOMOC ON) +set_property(SOURCE ui_PGetTitleBlockDialog.h PROPERTY SKIP_AUTOMOC ON) +set_property(SOURCE ui_PGetParameterBlockDialog.h PROPERTY SKIP_AUTOMOC ON) +set_property(SOURCE ui_PGetTheoryBlockDialog.h PROPERTY SKIP_AUTOMOC ON) +set_property(SOURCE ui_PGetFunctionsBlockDialog.h PROPERTY SKIP_AUTOMOC ON) +set_property(SOURCE ui_PGetAsymmetryRunBlockDialog.h PROPERTY SKIP_AUTOMOC ON) +set_property(SOURCE ui_PGetSingleHistoRunBlockDialog.h PROPERTY SKIP_AUTOMOC ON) +set_property(SOURCE ui_PGetNonMusrRunBlockDialog.h PROPERTY SKIP_AUTOMOC ON) +set_property(SOURCE ui_PGetFourierBlockDialog.h PROPERTY SKIP_AUTOMOC ON) +set_property(SOURCE ui_PGetPlotBlockDialog.h PROPERTY SKIP_AUTOMOC ON) +set_property(SOURCE ui_PMsr2DataDialog.h PROPERTY SKIP_AUTOMOC ON) +set_property(SOURCE ui_PChangeDefaultPathsDialog.h PROPERTY SKIP_AUTOMOC ON) +set_property(SOURCE qrc_musredit.cpp PROPERTY SKIP_AUTOMOC ON) + +set(macosx_icon icons/musredit.icns) +if (APPLE) + add_executable(musredit MACOSX_BUNDLE + ${musredit_src} + ${out_ui} + ${musredit_rcc} + ${macosx_icon} + ) +else (APPLE) + add_executable(musredit + ${musredit_src} + ${out_ui} + ${musredit_rcc} + ) +endif (APPLE) + +target_include_directories(musredit + BEFORE PRIVATE + $ + $ + $ + $ + $ +) + +target_link_libraries(musredit ${qt_libs}) + +#--- installation info -------------------------------------------------------- +if (APPLE) + set_target_properties(musredit PROPERTIES + MACOSX_BUNDLE TRUE + MACOSX_BUNDLE_BUNDLE_NAME "musredit" + MACOSX_BUNDLE_INFO_STRING "musrfit: musredit simplifies the handling of the msr-files for uSR fitting." + MACOSX_BUNDLE_ICON_FILE "musredit.icns" + MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_VERSION}" + MACOSX_BUNDLE_GUI_IDENTIFIER "ch.psi.lmu.musredit" + MACOSX_BUNDLE_COPYRIGHT "Andreas Suter" + RESOURCE ${macosx_icon} + ) +endif (APPLE) + +if (APPLE) + install( TARGETS musredit + BUNDLE DESTINATION /Applications + ) +else (APPLE) + install( TARGETS musredit + RUNTIME DESTINATION bin + ) +endif (APPLE) + +#--- documentation installation info ------------------------------------------ +install( + DIRECTORY + ${CMAKE_SOURCE_DIR}/doc/examples + ${CMAKE_SOURCE_DIR}/doc/html + ${CMAKE_SOURCE_DIR}/doc/memos + DESTINATION + ${CMAKE_INSTALL_PREFIX}/share/doc/musrfit + MESSAGE_NEVER +) + diff --git a/src/musredit_qt6/musredit/PAdmin.cpp b/src/musredit_qt6/musredit/PAdmin.cpp new file mode 100644 index 00000000..9c3093b8 --- /dev/null +++ b/src/musredit_qt6/musredit/PAdmin.cpp @@ -0,0 +1,1193 @@ +/**************************************************************************** + + PAdmin.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2010-2019 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 "musrfit-info.h" +#include "PAdmin.h" + +//-------------------------------------------------------------------------- +// implementation of PAdminXMLParser class +//-------------------------------------------------------------------------- +/** + *

XML Parser class for the musredit administration file. + * + * \param fln file name of the musredit startup xml-file + * \param admin pointer to an admin class instance. + */ +PAdminXMLParser::PAdminXMLParser(const QString& fln, PAdmin *admin) : fAdmin(admin) +{ + fValid = false; + fKeyWord = eEmpty; + fFunc = false; + + QFile file(fln); + if (!file.open(QFile::ReadOnly | QFile::Text)) { + // warning and create default - STILL MISSING + } + + fValid = parse(&file); +} + +//-------------------------------------------------------------------------- +/** + *

parse the musredit startup xml-file. + * + * \param device QFile object of the musredit startup xml-file + * + * @return true on success, false otherwise + */ +bool PAdminXMLParser::parse(QIODevice *device) +{ + fXml.setDevice(device); + + bool expectChars = false; + while (!fXml.atEnd()) { + fXml.readNext(); + if (fXml.isStartDocument()) { + startDocument(); + } else if (fXml.isStartElement()) { + startElement(); + expectChars = true; + } else if (fXml.isCharacters() && expectChars) { + characters(); + } else if (fXml.isEndElement()) { + endElement(); + expectChars = false; + } else if (fXml.isEndDocument()) { + endDocument(); + } + } + if (fXml.hasError()) { + QString msg; + msg = QString("%1 Line %2, column %3").arg(fXml.errorString()).arg(fXml.lineNumber()).arg(fXml.columnNumber()); + QMessageBox::critical(0, "**ERROR**", msg, QMessageBox::Ok, QMessageBox::NoButton); + return false; + } + + return true; +} + +//-------------------------------------------------------------------------- +/** + *

Routine called at the beginning of the XML parsing process. + */ +bool PAdminXMLParser::startDocument() +{ + // nothing to be done here for now + return true; +} + +//-------------------------------------------------------------------------- +/** + *

Routine called when a new XML tag is found. Here it is used + * to set a tag for filtering afterwards the content. + */ +bool PAdminXMLParser::startElement() +{ + QString qName = fXml.name().toString(); + + if (qName == "timeout") { + fKeyWord = eTimeout; + } else if (qName == "font_name") { + fKeyWord = eFontName; + } else if (qName == "font_size") { + fKeyWord = eFontSize; + } else if (qName == "exec_path") { + fKeyWord = eExecPath; + } else if (qName == "default_save_path") { + fKeyWord = eDefaultSavePath; + } else if (qName == "title_from_data_file") { + fKeyWord = eTitleFromDataFile; + } else if (qName == "musrview_show_fourier") { + fKeyWord = eMusrviewShowFourier; + } else if (qName == "musrview_show_avg") { + fKeyWord = eMusrviewShowAvg; + } else if (qName == "musrview_show_one_to_one") { + fKeyWord = eMusrviewShowOneToOne; + } else if (qName == "enable_musrt0") { + fKeyWord = eEnableMusrT0; + } else if (qName == "dark_theme_icons_menu") { + fKeyWord = eDarkThemeIconsMenu; + } else if (qName == "dark_theme_icons_toolbar") { + fKeyWord = eDarkThemeIconsToolbar; + } else if (qName =="keep_minuit2_output") { + fKeyWord = eKeepMinuit2Output; + } else if (qName == "dump_ascii") { + fKeyWord = eDumpAscii; + } else if (qName =="dump_root") { + fKeyWord = eDumpRoot; + } else if (qName == "estimate_n0") { + fKeyWord = eEstimateN0; + } else if (qName == "chisq_per_run_block") { + fKeyWord = eChisqPreRunBlock; + } else if (qName == "path_file_name") { + fKeyWord = eRecentFile; + } else if (qName == "beamline") { + fKeyWord = eBeamline; + } else if (qName == "institute") { + fKeyWord = eInstitute; + } else if (qName == "file_format") { + fKeyWord = eFileFormat; + } else if (qName == "lifetime_correction") { + fKeyWord = eLifetimeCorrection; + } else if (qName == "musr_web_main") { + fKeyWord = eHelpMain; + } else if (qName == "musr_web_title") { + fKeyWord = eHelpTitle; + } else if (qName == "musr_web_parameters") { + fKeyWord = eHelpParameters; + } else if (qName == "musr_web_theory") { + fKeyWord = eHelpTheory; + } else if (qName == "musr_web_functions") { + fKeyWord = eHelpFunctions; + } else if (qName == "musr_web_run") { + fKeyWord = eHelpRun; + } else if (qName == "musr_web_command") { + fKeyWord = eHelpCommand; + } else if (qName == "musr_web_fourier") { + fKeyWord = eHelpFourier; + } else if (qName == "musr_web_plot") { + fKeyWord = eHelpPlot; + } else if (qName == "musr_web_statistic") { + fKeyWord = eHelpStatistic; + } else if (qName == "musr_web_msr2data") { + fKeyWord = eHelpMsr2Data; + } else if (qName == "musr_web_musrFT") { + fKeyWord = eHelpMusrFT; + } else if (qName == "chain_fit") { + fKeyWord = eChainFit; + } else if (qName == "write_data_header") { + fKeyWord = eWriteDataHeader; + } else if (qName == "ignore_data_header_info") { + fKeyWord = eIgnoreDataHeaderInfo; + } else if (qName == "keep_minuit2_output") { + fKeyWord = eKeepMinuit2Output; + } else if (qName == "write_column_data") { + fKeyWord = eWriteColumnData; + } else if (qName == "recreate_data_file") { + fKeyWord = eRecreateDataFile; + } else if (qName == "open_file_after_fitting") { + fKeyWord = eOpenFileAfterFitting; + } else if (qName == "create_msr_file_only") { + fKeyWord = eCreateMsrFileOnly; + } else if (qName == "fit_only") { + fKeyWord = eFitOnly; + } else if (qName == "global") { + fKeyWord = eGlobal; + } else if (qName == "global_plus") { + fKeyWord = eGlobalPlus; + } else if (qName == "func_pixmap_path") { + fKeyWord = eTheoFuncPixmapPath; + } else if (qName == "func") { + fKeyWord = eFunc; + fFunc = true; + // init theory item + fTheoryItem.name = ""; + fTheoryItem.comment = ""; + fTheoryItem.label = ""; + fTheoryItem.pixmapName = ""; + fTheoryItem.pixmap = QPixmap(); + fTheoryItem.params = -1; + } else if (qName == "name") { + fKeyWord = eFuncName; + } else if (qName == "comment") { + fKeyWord = eFuncComment; + } else if (qName == "label") { + fKeyWord = eFuncLabel; + } else if (qName == "pixmap") { + fKeyWord = eFuncPixmap; + } else if (qName == "params") { + fKeyWord = eFuncParams; + } + + return true; +} + +//-------------------------------------------------------------------------- +/** + *

Routine called when the end XML tag is found. It is used to + * put the filtering tag to 'empty'. It also resets the fFunc flag in case + * the entry was a theory function. + */ +bool PAdminXMLParser::endElement() +{ + fKeyWord = eEmpty; + + QString qName = fXml.name().toString(); + + if (qName == "func") { + fFunc = false; + fAdmin->addTheoryItem(fTheoryItem); + } + + return true; +} + +//-------------------------------------------------------------------------- +/** + *

This routine delivers the content of an XML tag. It fills the + * content into the load data structure. + */ +bool PAdminXMLParser::characters() +{ + QString str = fXml.text().toString(); + + if (str.isEmpty()) + return true; + + QString help; + bool flag, ok; + int ival; + + switch (fKeyWord) { + case eTimeout: + ival = QString(str.toLatin1()).trimmed().toInt(&ok); + if (ok) + fAdmin->setTimeout(ival); + break; + case eFontName: + fAdmin->setFontName(QString(str.toLatin1()).trimmed()); + break; + case eFontSize: + ival = QString(str.toLatin1()).trimmed().toInt(&ok); + if (ok) + fAdmin->setFontSize(ival); + break; + case eExecPath: + fAdmin->setExecPath(QString(str.toLatin1()).trimmed()); + break; + case eDefaultSavePath: + fAdmin->setDefaultSavePath(QString(str.toLatin1()).trimmed()); + break; + case eTitleFromDataFile: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->setTitleFromDataFileFlag(flag); + break; + case eMusrviewShowFourier: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->setMusrviewShowFourierFlag(flag); + break; + case eMusrviewShowAvg: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->setMusrviewShowAvgFlag(flag); + break; + case eMusrviewShowOneToOne: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->setMusrviewShowOneToOneFlag(flag); + break; + case eEnableMusrT0: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->setEnableMusrT0Flag(flag); + break; + case eDarkThemeIconsMenu: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->setDarkThemeIconsMenuFlag(flag); + break; + case eDarkThemeIconsToolbar: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->setDarkThemeIconsToolbarFlag(flag); + break; + case eKeepMinuit2Output: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->fMsr2DataParam.keepMinuit2Output = flag; + fAdmin->setKeepMinuit2OutputFlag(flag); + break; + case eDumpAscii: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->setDumpAsciiFlag(flag); + break; + case eDumpRoot: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->setDumpRootFlag(flag); + break; + case eEstimateN0: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->fMsr2DataParam.estimateN0 = flag; + fAdmin->setEstimateN0Flag(flag); + break; + case eChisqPreRunBlock: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->fMsr2DataParam.perRunBlockChisq = flag; + fAdmin->setChisqPerRunBlockFlag(flag); + break; + case eRecentFile: + fAdmin->addRecentFile(QString(str.toLatin1()).trimmed()); + break; + case eBeamline: + fAdmin->setBeamline(QString(str.toLatin1()).trimmed()); + break; + case eInstitute: + fAdmin->setInstitute(QString(str.toLatin1()).trimmed()); + break; + case eFileFormat: + fAdmin->setFileFormat(QString(str.toLatin1()).trimmed()); + break; + case eLifetimeCorrection: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->setLifetimeCorrectionFlag(flag); + break; + case eHelpMain: + fAdmin->setHelpUrl("main", str); + break; + case eHelpTitle: + fAdmin->setHelpUrl("title", str); + break; + case eHelpParameters: + fAdmin->setHelpUrl("parameters", str); + break; + case eHelpTheory: + fAdmin->setHelpUrl("theory", str); + break; + case eHelpFunctions: + fAdmin->setHelpUrl("functions", str); + break; + case eHelpRun: + fAdmin->setHelpUrl("run", str); + break; + case eHelpCommand: + fAdmin->setHelpUrl("command", str); + break; + case eHelpFourier: + fAdmin->setHelpUrl("fourier", str); + break; + case eHelpPlot: + fAdmin->setHelpUrl("plot", str); + break; + case eHelpStatistic: + fAdmin->setHelpUrl("statistic", str); + break; + case eHelpMsr2Data: + fAdmin->setHelpUrl("msr2data", str); + break; + case eHelpMusrFT: + fAdmin->setHelpUrl("musrFT", str); + break; + case eChainFit: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->fMsr2DataParam.chainFit = flag; + break; + case eWriteDataHeader: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->fMsr2DataParam.writeDbHeader = flag; + break; + case eIgnoreDataHeaderInfo: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->fMsr2DataParam.ignoreDataHeaderInfo = flag; + break; + case eWriteColumnData: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->fMsr2DataParam.writeColumnData = flag; + break; + case eRecreateDataFile: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->fMsr2DataParam.recreateDbFile = flag; + break; + case eOpenFileAfterFitting: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->fMsr2DataParam.openFilesAfterFitting = flag; + break; + case eCreateMsrFileOnly: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->fMsr2DataParam.createMsrFileOnly = flag; + break; + case eFitOnly: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->fMsr2DataParam.fitOnly = flag; + break; + case eGlobal: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->fMsr2DataParam.global = flag; + break; + case eGlobalPlus: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->fMsr2DataParam.globalPlus = flag; + break; + case eTheoFuncPixmapPath: + fAdmin->setTheoFuncPixmapPath(QString(str.toLatin1()).trimmed()); + break; + default: + break; + } + + if (fFunc) { + bool ok; + switch (fKeyWord) { + case eFuncName: + fTheoryItem.name = QString(str.toLatin1()).trimmed(); + break; + case eFuncComment: + fTheoryItem.comment = QString(str.toLatin1()).trimmed(); + break; + case eFuncLabel: + fTheoryItem.label = QString(str.toLatin1()).trimmed(); + break; + case eFuncPixmap: + fTheoryItem.pixmapName = QString(str.toLatin1()).trimmed(); + break; + case eFuncParams: + fTheoryItem.params = str.toInt(&ok); + if (!ok) + return false; + break; + default: + break; + } + } + + return true; +} + +//-------------------------------------------------------------------------- +/** + *

Called at the end of the XML parse process. It checks if default paths + * contain system variables, and if so expand them for the further use. + */ +bool PAdminXMLParser::endDocument() +{ + // check if all necessary items are found + QString str; + + if (fAdmin->getExecPath().indexOf('$') >= 0) { + str = expandPath(fAdmin->getExecPath()); + if (!str.isEmpty()) + fAdmin->setExecPath(str); + } + + if (fAdmin->getDefaultSavePath().indexOf('$') >= 0) { + str = expandPath(fAdmin->getDefaultSavePath()); + if (!str.isEmpty()) + fAdmin->setDefaultSavePath(str); + } + + if (fAdmin->getTheoFuncPixmapPath().indexOf('$') >=0) { + str = expandPath(fAdmin->getTheoFuncPixmapPath()); + if (!str.isEmpty()) + fAdmin->setTheoFuncPixmapPath(str); + } + + //as35 dump admin - only for debugging + //as35 dump(); + + return true; +} + +//-------------------------------------------------------------------------- +/** + *

Dumps the content of the admin class. For debugging purposes only. + */ +void PAdminXMLParser::dump() +{ + std::cout << "debug> +++++++++++++++++++++++" << std::endl; + std::cout << "debug> general:" << std::endl; + std::cout << "debug> exec_path : " << fAdmin->getExecPath().toLatin1().data() << std::endl; + std::cout << "debug> default_save_path : " << fAdmin->getDefaultSavePath().toLatin1().data() << std::endl; + std::cout << "debug> timeout : " << fAdmin->getTimeout() << std::endl; + std::cout << "debug> keep_minuit2_output : " << fAdmin->getKeepMinuit2OutputFlag() << std::endl; + std::cout << "debug> dump_ascii : " << fAdmin->getDumpAsciiFlag() << std::endl; + std::cout << "debug> dump_root : " << fAdmin->getDumpRootFlag() << std::endl; + std::cout << "debug> title_from_data_file : " << fAdmin->getTitleFromDataFileFlag() << std::endl; + std::cout << "debug> chisq_per_run_block : " << fAdmin->getChisqPerRunBlockFlag() << std::endl; + std::cout << "debug> estimate_n0 : " << fAdmin->getEstimateN0Flag() << std::endl; + std::cout << "debug> musrview_show_fourier : " << fAdmin->getMusrviewShowFourierFlag() << std::endl; + std::cout << "debug> musrview_show_avg : " << fAdmin->getMusrviewShowAvgFlag() << std::endl; + std::cout << "debug> enable_musrt0 : " << fAdmin->getEnableMusrT0Flag() << std::endl; + std::cout << "debug> dark_theme_icons_menu : " << fAdmin->getDarkThemeIconsMenuFlag() << std::endl; + std::cout << "debug> dark_theme_icons_toolbar : " << fAdmin->getDarkThemeIconsToolbarFlag() << std::endl; + std::cout << "debug> +++++++++++++++++++++++" << std::endl; + std::cout << "debug> recent_files:" << std::endl; + for (int i=0; igetNumRecentFiles(); i++) { + std::cout << "debug> recent_file " << i << ":" << fAdmin->getRecentFile(i).toLatin1().data() << std::endl; + } + std::cout << "debug> +++++++++++++++++++++++" << std::endl; + std::cout << "debug> help_section:" << std::endl; + std::cout << "debug> musr_web_main : " << fAdmin->getHelpUrl("main").toLatin1().data() << std::endl; + std::cout << "debug> musr_web_title : " << fAdmin->getHelpUrl("title").toLatin1().data() << std::endl; + std::cout << "debug> musr_web_parameters : " << fAdmin->getHelpUrl("parameters").toLatin1().data() << std::endl; + std::cout << "debug> musr_web_theory : " << fAdmin->getHelpUrl("theory").toLatin1().data() << std::endl; + std::cout << "debug> musr_web_functions : " << fAdmin->getHelpUrl("functions").toLatin1().data() << std::endl; + std::cout << "debug> musr_web_run : " << fAdmin->getHelpUrl("run").toLatin1().data() << std::endl; + std::cout << "debug> musr_web_command : " << fAdmin->getHelpUrl("command").toLatin1().data() << std::endl; + std::cout << "debug> musr_web_fourier : " << fAdmin->getHelpUrl("fourier").toLatin1().data() << std::endl; + std::cout << "debug> musr_web_plot : " << fAdmin->getHelpUrl("plot").toLatin1().data() << std::endl; + std::cout << "debug> musr_web_statistic : " << fAdmin->getHelpUrl("statistic").toLatin1().data() << std::endl; + std::cout << "debug> musr_web_msr2data : " << fAdmin->getHelpUrl("msr2data").toLatin1().data() << std::endl; + std::cout << "debug> musr_web_musrFT : " << fAdmin->getHelpUrl("musrFT").toLatin1().data() << std::endl; + std::cout << "debug> +++++++++++++++++++++++" << std::endl; + std::cout << "debug> font_section:" << std::endl; + std::cout << "debug> font_name : " << fAdmin->getFontName().toLatin1().data() << std::endl; + std::cout << "debug> font_size : " << fAdmin->getFontSize() << std::endl; + std::cout << "debug> +++++++++++++++++++++++" << std::endl; + std::cout << "debug> msr_file_defaults:" << std::endl; + std::cout << "debug> beamline : " << fAdmin->getBeamline().toLatin1().data() << std::endl; + std::cout << "debug> institute : " << fAdmin->getInstitute().toLatin1().data() << std::endl; + std::cout << "debug> file_format : " << fAdmin->getFileFormat().toLatin1().data() << std::endl; + std::cout << "debug> lifetime_correction : " << fAdmin->getLifetimeCorrectionFlag() << std::endl; + std::cout << "debug> +++++++++++++++++++++++" << std::endl; + std::cout << "debug> msr2data_defaults:" << std::endl; + std::cout << "debug> chain_fit : " << fAdmin->getMsr2DataParam().chainFit << std::endl; + std::cout << "debug> write_data_header : " << fAdmin->getMsr2DataParam().writeDbHeader << std::endl; + std::cout << "debug> ignore_data_header_info : " << fAdmin->getMsr2DataParam().ignoreDataHeaderInfo << std::endl; + std::cout << "debug> keep_minuit2_output : " << fAdmin->getMsr2DataParam().keepMinuit2Output << std::endl; + std::cout << "debug> write_column_data : " << fAdmin->getMsr2DataParam().writeColumnData << std::endl; + std::cout << "debug> recreate_data_file : " << fAdmin->getMsr2DataParam().recreateDbFile << std::endl; + std::cout << "debug> open_file_after_fitting : " << fAdmin->getMsr2DataParam().openFilesAfterFitting << std::endl; + std::cout << "debug> create_msr_file_only : " << fAdmin->getMsr2DataParam().createMsrFileOnly << std::endl; + std::cout << "debug> fit_only : " << fAdmin->getMsr2DataParam().fitOnly << std::endl; + std::cout << "debug> global : " << fAdmin->getMsr2DataParam().global << std::endl; + std::cout << "debug> global_plus : " << fAdmin->getMsr2DataParam().globalPlus << std::endl; + std::cout << "debug> +++++++++++++++++++++++" << std::endl; + std::cout << "debug> theory_functions:" << std::endl; + std::cout << "debug> func_pixmap_path : " << fAdmin->getTheoFuncPixmapPath().toLatin1().data() << std::endl; + std::cout << "debug> #theory : " << fAdmin->getTheoryCounts() << std::endl; + PTheory *theo; + for (unsigned int i=0; igetTheoryCounts(); i++) { + theo = fAdmin->getTheoryItem(i); + std::cout << "debug> -------" << std::endl; + std::cout << "debug> name : " << theo->name.toLatin1().data() << std::endl; + std::cout << "debug> comment : " << theo->comment.toLatin1().data() << std::endl; + std::cout << "debug> label : " << theo->label.toLatin1().data() << std::endl; + std::cout << "debug> pixmapName : " << theo->pixmapName.toLatin1().data() << std::endl; + std::cout << "debug> params : " << theo->params << std::endl; + } +} + +//-------------------------------------------------------------------------- +/** + *

Expands system variables to full path, e.g. $HOME -> \home\user + * + * \param str path string with none expanded system variables. + */ +QString PAdminXMLParser::expandPath(const QString &str) +{ + QString token; + QString path; + QString msg; + QString newStr=""; + + QProcessEnvironment procEnv = QProcessEnvironment::systemEnvironment(); + + QStringList list = str.split("/"); + + for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { + token = *it; + if (token.contains("$")) { + token.remove('$'); + if (!procEnv.contains(token)) { + msg = QString("Couldn't find '%1'. Some things might not work properly").arg(token); + QMessageBox::warning(0, "**WARNING**", msg, QMessageBox::Ok, QMessageBox::NoButton); + newStr = ""; + break; + } + path = procEnv.value(token, ""); + if (path.isEmpty()) { + msg = QString("Couldn't expand '%1'. Some things might not work properly").arg(token); + QMessageBox::warning(0, "**WARNING**", msg, QMessageBox::Ok, QMessageBox::NoButton); + newStr = ""; + break; + } + newStr += path; + } else { + newStr += "/" + token; + } + } + + return newStr; +} + +//-------------------------------------------------------------------------- +// implementation of PAdmin class +//-------------------------------------------------------------------------- +/** + *

Initializes that PAdmin object, and calls the XML parser which feeds + * the object variables. + */ +PAdmin::PAdmin() : QObject() +{ + fTimeout = 3600; + + fFontName = QString("Courier"); // default font + fFontSize = 11; // default font size + + fPrefPathName = QString(""); + fExecPath = QString(""); + fDefaultSavePath = QString(""); + fTheoFuncPixmapPath = QString(""); + + fBeamline = QString(""); + fInstitute = QString(""); + fFileFormat = QString(""); + + fMusrviewShowFourier = false; + fMusrviewShowAvg = false; + + fTitleFromDataFile = false; + fEnableMusrT0 = false; + fLifetimeCorrection = true; + fEstimateN0 = true; + fChisqPreRunBlock = false; + + fMsr2DataParam.runList = QString(""); + fMsr2DataParam.runListFileName = QString(""); + fMsr2DataParam.msrFileExtension = QString(""); + fMsr2DataParam.templateRunNo = -1; + fMsr2DataParam.dbOutputFileName = QString(""); + fMsr2DataParam.writeDbHeader = true; + fMsr2DataParam.ignoreDataHeaderInfo = false; + fMsr2DataParam.keepMinuit2Output = false; + fMsr2DataParam.estimateN0 = fEstimateN0; + fMsr2DataParam.writeColumnData = false; + fMsr2DataParam.recreateDbFile = false; + fMsr2DataParam.chainFit = true; + fMsr2DataParam.openFilesAfterFitting = true; + fMsr2DataParam.perRunBlockChisq = fChisqPreRunBlock; + fMsr2DataParam.titleFromDataFile = true; + fMsr2DataParam.createMsrFileOnly = false; + fMsr2DataParam.fitOnly = false; + fMsr2DataParam.global = false; + fMsr2DataParam.globalPlus = false; + + // XML Parser part + // 1st: check local directory + QString path = QString("./"); + QString fln = QString("musredit_startup.xml"); + QString pathFln = path + fln; + QProcessEnvironment procEnv = QProcessEnvironment::systemEnvironment(); + if (!QFile::exists(pathFln)) { + // 2nd: check $HOME/.musrfit/musredit/musredit_startup.xml + path = procEnv.value("HOME", ""); + pathFln = path + "/.musrfit/musredit/" + fln; + if (!QFile::exists(pathFln)) { + // 3rd: check $MUSRFITPATH/musredit_startup.xml + path = procEnv.value("MUSRFITPATH", ""); + pathFln = path + "/" + fln; + if (!QFile::exists(pathFln)) { + // 4th: check $ROOTSYS/bin/musredit_startup.xml + path = procEnv.value("ROOTSYS", ""); + pathFln = path + "/bin/" + fln; + if (!QFile::exists(pathFln)) { + // 5th: not found anywhere hence create it + path = procEnv.value("HOME", ""); + pathFln = path + "/.musrfit/musredit/" + fln; + createMusreditStartupFile(); + } + } + } + } + fPrefPathName = pathFln; + + loadPrefs(fPrefPathName); + + // make sure that musrfit, musrview, etc are found under the fExecPath provided + QString str = fExecPath + "/musrfit"; + QFileInfo info(str); + if (info.exists()) { + if (!info.isExecutable()) + QMessageBox::critical(0, "ERROR", "musrfit found but not recognized as executable.\nPlease check!"); + } else { + QMessageBox::critical(0, "ERROR", "musrfit not found.\nHave you set the necessary system variables properly?\nPlease check the manual.\nBefore you can use musrfit, this needs to be fixed."); + } + + // check if system variables are set properly + bool sysVarMissing = false; + QString msg("Missing System Variables:\n"); + path = procEnv.value("ROOTSYS", ""); + if (path.isEmpty()) { + msg += "> ROOTSYS\n"; + sysVarMissing = true; + } + path = procEnv.value("MUSRFITPATH", ""); + if (path.isEmpty()) { + msg += "> MUSRFITPATH\n"; + sysVarMissing = true; + } + if (sysVarMissing) { + msg += "Please set this/these system variables."; + QMessageBox::warning(0, "WARNING", msg); + } +} + +//-------------------------------------------------------------------------- +/** + *

Destructor + */ +PAdmin::~PAdmin() +{ + saveRecentFiles(); +} + +//-------------------------------------------------------------------------- +/** + *

returns the help url corresponding the the tag. + * + * \param tag to map the help url. At the moment the following tags should be present: + * main, title, parameters, theory, functions, run, command, fourier, plot, statistic + */ +QString PAdmin::getHelpUrl(QString tag) +{ + return fHelpUrl[tag]; +} + +//-------------------------------------------------------------------------- +/** + *

returns a theory item from position idx. If idx is out of the range, a null pointer is returned. + * + * \param idx position of the theory item. + */ +PTheory* PAdmin::getTheoryItem(const unsigned int idx) +{ + if (idx > (unsigned int)fTheory.size()) + return 0; + else + return &fTheory[idx]; +} + +//-------------------------------------------------------------------------- +/** + *

returns the recent path-file name at position idx. If idx is out of scope, + * an empty string is returned. + * + * \param idx index of the recent path-file name to be retrieved. + */ +QString PAdmin::getRecentFile(int idx) +{ + if (idx >= fRecentFile.size()) + return QString(""); + + return fRecentFile[idx]; +} + +//-------------------------------------------------------------------------- +/** + *

set the help url, addressed via a tag. At the moment the following tags should be present: + * main, title, parameters, theory, functions, run, command, fourier, plot, statistic, msr2data + * + * \param tag to address the help url + * \param url help url corresponding to the tag. + */ +void PAdmin::setHelpUrl(const QString tag, const QString url) +{ + fHelpUrl[tag] = url; +} + +//-------------------------------------------------------------------------- +/** + *

Loads the preference file fln. + * + * return: 1 on success, 0 otherwise + * + * \param fln path-file name of the preference file to be loaded. + */ +int PAdmin::loadPrefs(QString fln) +{ + if (QFile::exists(fln)) { // administration file present + PAdminXMLParser handler(fln, this); + if (!handler.isValid()) { + QMessageBox::critical(0, "**ERROR**", + "Error parsing musredit_startup.xml settings file.\nProbably a few things will not work porperly.\nPlease fix this first.", + QMessageBox::Ok, QMessageBox::NoButton); + return 0; + } + } else { + QMessageBox::critical(0, "**ERROR**", + "Couldn't find the musredit_startup.xml settings file.\nProbably a few things will not work porperly.\nPlease fix this first.", + QMessageBox::Ok, QMessageBox::NoButton); + return 0; + } + return 1; +} + +//-------------------------------------------------------------------------- +/** + *

Save the preference file pref_fln. + * + * return: 1 on success, 0 otherwise + * + * \param pref_fln preference path-file name + */ +int PAdmin::savePrefs(QString pref_fln) +{ + // check if musredit_startup.xml is present in the current directory, and if yes, use this file to + // save the recent file names otherwise use the "master" musredit_startup.xml + QString fln = QString("./musredit_startup.xml"); + if (!QFile::exists(fln)) + fln = fPrefPathName; + + if (QFile::exists(fln)) { // administration file present + QVector data; + QFile file(fln); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + std::cerr << std::endl << ">> PAdmin::savePrefs: **ERROR** Cannot open " << fln.toLatin1().data() << " for reading." << std::endl; + return 1; + } + QTextStream fin(&file); + while (!fin.atEnd()) { + data.push_back(fin.readLine()); + } + file.close(); + + // replace all the prefs + for (int i=0; i") && data[i].contains("")) { + data[i] = " " + QString("%1").arg(fTimeout) + ""; + } + if (data[i].contains("") && data[i].contains("")) { + if (fKeepMinuit2Output) + data[i] = " y"; + else + data[i] = " n"; + } + if (data[i].contains("") && data[i].contains("")) { + if (fDumpAscii) + data[i] = " y"; + else + data[i] = " n"; + } + if (data[i].contains("") && data[i].contains("")) { + if (fDumpRoot) + data[i] = " y"; + else + data[i] = " n"; + } + if (data[i].contains("") && data[i].contains("")) { + if (fTitleFromDataFile) + data[i] = " y"; + else + data[i] = " n"; + } + if (data[i].contains("") && data[i].contains("")) { + if (fChisqPreRunBlock) + data[i] = " y"; + else + data[i] = " n"; + } + if (data[i].contains("") && data[i].contains("")) { + if (fEstimateN0) + data[i] = " y"; + else + data[i] = " n"; + } + if (data[i].contains("") && data[i].contains("")) { + if (fMusrviewShowFourier) + data[i] = " y"; + else + data[i] = " n"; + } + if (data[i].contains("") && data[i].contains("")) { + if (fMusrviewShowAvg) + data[i] = " y"; + else + data[i] = " n"; + } + if (data[i].contains("") && data[i].contains("")) { + if (fEnableMusrT0) + data[i] = " y"; + else + data[i] = " n"; + } + if (data[i].contains("") && data[i].contains("")) { + if (fDarkThemeIconsMenu) + data[i] = " y"; + else + data[i] = " n"; + } + if (data[i].contains("") && data[i].contains("")) { + if (fDarkThemeIconsToolbar) + data[i] = " y"; + else + data[i] = " n"; + } + if (data[i].contains("") && data[i].contains("")) { + data[i] = QString(" %1").arg(fFontName); + } + if (data[i].contains("") && data[i].contains("")) { + data[i] = QString(" %1").arg(fFontSize); + } + } + + // write prefs + file.setFileName(pref_fln); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + std::cerr << std::endl << ">> PAdmin::savePrefs: **ERROR** Cannot open " << pref_fln.toLatin1().data() << " for writing." << std::endl; + return 0; + } + fin.setDevice(&file); + for (int i=0; iAdd recent path-file name to the internal ring-buffer. + * + * \param str recent path-file name to be added + */ +void PAdmin::addRecentFile(const QString str) +{ + // check if file name is not already present + for (int i=0; i MAX_RECENT_FILES) + fRecentFile.resize(MAX_RECENT_FILES); +} + +//-------------------------------------------------------------------------- +/** + *

Merges the recent file ring buffer into musredit_startup.xml and saves it. + * If a local copy is present it will be saved there, otherwise the master file + * will be used. + */ +void PAdmin::saveRecentFiles() +{ + // check if musredit_startup.xml is present in the current directory, and if yes, use this file to + // save the recent file names otherwise use the "master" musredit_startup.xml + + QString str(""); + QString fln = QString("./musredit_startup.xml"); + if (!QFile::exists(fln)) + fln = fPrefPathName; + + if (QFile::exists(fln)) { // administration file present + QVector data; + QFile file(fln); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + std::cerr << std::endl << ">> PAdmin::saveRecentFile: **ERROR** Cannot open " << fln.toLatin1().data() << " for reading." << std::endl; + return; + } + QTextStream fin(&file); + while (!fin.atEnd()) { + data.push_back(fin.readLine()); + } + file.close(); + + // remove from data + for (QVector::iterator it = data.begin(); it != data.end(); ++it) { + if (it->contains("")) { + it = data.erase(it); + --it; + } + } + + // add recent files + int i; + for (i=0; i")) + break; + } + + if (i == data.size()) { + std::cerr << std::endl << ">> PAdmin::saveRecentFile: **ERROR** " << fln.toLatin1().data() << " seems to be corrupt." << std::endl; + return; + } + i++; + for (int j=0; j"; + data.insert(i++, str); + } + + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + std::cerr << std::endl << ">> PAdmin::saveRecentFile: **ERROR** Cannot open " << fln.toLatin1().data() << " for reading." << std::endl; + return; + } + fin.setDevice(&file); + for (int i=0; i")) { // defaults: linux: Monospace, macOS: Courier New + if (QSysInfo::productType().contains("osx")) { + line.replace("Monospace", "Courier New"); + } + } + if (line.contains("")) { // defaults: linux: 12, macOS: 16 + if (QSysInfo::productType().contains("osx")) { + line.replace("12", "16"); + } + } + fout << line << Qt::endl; + } + + file.close(); + fres.close(); +} + +//-------------------------------------------------------------------------- +// END +//-------------------------------------------------------------------------- diff --git a/src/musredit_qt6/musredit/PAdmin.h b/src/musredit_qt6/musredit/PAdmin.h new file mode 100644 index 00000000..9c95f7d9 --- /dev/null +++ b/src/musredit_qt6/musredit/PAdmin.h @@ -0,0 +1,223 @@ +/**************************************************************************** + + PAdmin.h + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2010-2019 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. * + ***************************************************************************/ + +#ifndef _PADMIN_H_ +#define _PADMIN_H_ + +#include +#include +#include +#include +#include + +#include + +class PAdmin; + +//--------------------------------------------------------------------------- +/** + *

This structure is keeping informations necessary to handle musrfit + * theory functions (see also http://lmu.web.psi.ch/musrfit/user/html/user-manual.html#the-theory-block). + */ +typedef struct { + QString name; + QString comment; + QString label; + QString pixmapName; + QPixmap pixmap; + int params; +} PTheory; + +//--------------------------------------------------------------------------- +/** + * PAdminXMLParser is an XML parser class used to handle the musredit startup + * XML-file called musredit_startup.xml. This startup file contains + * necessary informations about executable pathes, online help informations, + * default font sizes, etc. + */ +class PAdminXMLParser +{ + public: + PAdminXMLParser(const QString &fln, PAdmin*); + virtual ~PAdminXMLParser() {} + + virtual bool isValid() { return fValid; } + + private: + enum EAdminKeyWords {eEmpty, eTimeout, eKeepMinuit2Output, eDumpAscii, eDumpRoot, + eTitleFromDataFile, eChisqPreRunBlock, eEstimateN0, + eMusrviewShowFourier, eMusrviewShowAvg, eMusrviewShowOneToOne, eEnableMusrT0, + eDarkThemeIconsMenu, eDarkThemeIconsToolbar, + eFontName, eFontSize, eExecPath, eDefaultSavePath, + eRecentFile, eBeamline, eInstitute, eFileFormat, eLifetimeCorrection, + eTheoFuncPixmapPath, eFunc, eFuncName, eFuncComment, eFuncLabel, + eFuncPixmap, eFuncParams, eHelpMain, eHelpTitle, eHelpParameters, eHelpTheory, eHelpFunctions, + eHelpRun, eHelpCommand, eHelpFourier, eHelpPlot, eHelpStatistic, eHelpMsr2Data, eHelpMusrFT, + eChainFit, eWriteDataHeader, eIgnoreDataHeaderInfo, eWriteColumnData, + eRecreateDataFile, eOpenFileAfterFitting, eCreateMsrFileOnly, eFitOnly, eGlobal, eGlobalPlus}; + + bool parse(QIODevice *device); + bool startDocument(); + bool startElement(); + bool endElement(); + bool characters(); + bool endDocument(); + + void dump(); + + QString expandPath(const QString&); + + QXmlStreamReader fXml; ///< xml stream reader object + bool fValid; ///< flag showing if XML read has been successful + EAdminKeyWords fKeyWord; ///< key word tag to know how to handle the content + bool fFunc; ///< flag needed to indicate that a new theory function is found + PTheory fTheoryItem; ///< holding the informations necessary for a theory item + PAdmin *fAdmin; ///< a pointer to the main administration class object +}; + +//--------------------------------------------------------------------------- +/** + * The PAdmin class is handling the informations contained in the XML startup file, + * musredit_startup.xml. This startup file contains + * necessary informations about executable pathes, online help informations, + * default font sizes, etc. The XML parsing is done with the help of the PAdminXMLParser + * class. + */ +class PAdmin : public QObject +{ + public: + PAdmin(); + virtual ~PAdmin(); + + int getTimeout() { return fTimeout; } + QString getFontName() { return fFontName; } + int getFontSize() { return fFontSize; } + QString getExecPath() { return fExecPath; } + QString getDefaultSavePath() { return fDefaultSavePath; } + bool getTitleFromDataFileFlag() { return fTitleFromDataFile; } + bool getMusrviewShowFourierFlag() { return fMusrviewShowFourier; } + bool getMusrviewShowAvgFlag() { return fMusrviewShowAvg; } + bool getMusrviewShowOneToOneFlag() { return fMusrviewShowOneToOne; } + bool getEnableMusrT0Flag() { return fEnableMusrT0; } + bool getKeepMinuit2OutputFlag() { return fKeepMinuit2Output; } + bool getDumpAsciiFlag() { return fDumpAscii; } + bool getDumpRootFlag() { return fDumpRoot; } + bool getEstimateN0Flag() { return fEstimateN0; } + bool getChisqPerRunBlockFlag() { return fChisqPreRunBlock; } + bool getDarkThemeIconsMenuFlag() { return fDarkThemeIconsMenu; } + bool getDarkThemeIconsToolbarFlag() { return fDarkThemeIconsToolbar; } + QString getBeamline() { return fBeamline; } + QString getInstitute() { return fInstitute; } + QString getFileFormat() { return fFileFormat; } + bool getLifetimeCorrectionFlag() { return fLifetimeCorrection; } + QString getHelpUrl(QString tag); + QString getTheoFuncPixmapPath() { return fTheoFuncPixmapPath; } + unsigned int getTheoryCounts() { return fTheory.size(); } + PTheory* getTheoryItem(const unsigned int idx); + PMsr2DataParam getMsr2DataParam() { return fMsr2DataParam; } + int getNumRecentFiles() { return fRecentFile.size(); } + QString getDefaultPrefPathName() { return fPrefPathName; } + QString getRecentFile(int idx); + + void setTimeout(const int ival) { fTimeout = ival; } + void setTitleFromDataFileFlag(const bool flag) { fTitleFromDataFile = flag; } + void setMusrviewShowFourierFlag(const bool flag) { fMusrviewShowFourier = flag; } + void setMusrviewShowAvgFlag(const bool flag) { fMusrviewShowAvg = flag; } + void setMusrviewShowOneToOneFlag(const bool flag) { fMusrviewShowOneToOne = flag; } + void setEnableMusrT0Flag(const bool flag) { fEnableMusrT0 = flag; } + void setKeepMinuit2OutputFlag(const bool flag) { fKeepMinuit2Output = flag; } + void setDumpAsciiFlag(const bool flag) { fDumpAscii = flag; } + void setDumpRootFlag(const bool flag) { fDumpRoot = flag; } + void setEstimateN0Flag(const bool flag) { fEstimateN0 = flag; } + void setChisqPerRunBlockFlag(const bool flag) { fChisqPreRunBlock = flag; } + void setDarkThemeIconsMenuFlag(const bool flag) { fDarkThemeIconsMenu = flag; } + void setDarkThemeIconsToolbarFlag(const bool flag) { fDarkThemeIconsToolbar = flag; } + + void setFontName(const QString str) { fFontName = str; } + void setFontSize(const int ival) { fFontSize = ival; } + void addRecentFile(const QString str); + + int loadPrefs(QString fln); + int savePrefs(QString pref_fln); + + protected: + void setExecPath(const QString str) { fExecPath = str; } + void setDefaultSavePath(const QString str) { fDefaultSavePath = str; } + void setBeamline(const QString str) { fBeamline = str; } + void setInstitute(const QString str) { fInstitute = str; } + void setFileFormat(const QString str) { fFileFormat = str; } + void setLifetimeCorrectionFlag(const bool flag) { fLifetimeCorrection = flag; } + void setHelpUrl(const QString tag, const QString url); + void setTheoFuncPixmapPath (const QString str) { fTheoFuncPixmapPath = str; } + void addTheoryItem(const PTheory theo) { fTheory.push_back(theo); } + + private: + friend class PAdminXMLParser; + + int fTimeout; ///< timeout in seconds + + QString fFontName; ///< default font name + int fFontSize; ///< default font size + + QString fPrefPathName; ///< path-name of the musredit_startup.xml + QString fExecPath; ///< system path to the musrfit executables + QString fDefaultSavePath; ///< default path where the msr-file should be saved + QString fTheoFuncPixmapPath; ///< path where the default pixmaps can be found + + QVector fRecentFile; ///< keep vector of recent path-file names + + bool fMusrviewShowFourier; ///< flag indicating if musrview should show at startup data (=false) or Fourier of data (=true). + bool fMusrviewShowAvg; ///< flag indicating if musrview should show at startup averaged (=true) or original (=false) data/Fourier. + bool fMusrviewShowOneToOne; ///< flag indicating if theory points are calculate only at the data points (=true) or a higher density theory points is calculated + bool fKeepMinuit2Output; ///< flag indicating if the Minuit2 output shall be kept (default: no) + bool fDumpAscii; ///< flag indicating if musrfit shall make an ascii-dump file (for debugging purposes, default: no). + bool fDumpRoot; ///< flag indicating if musrfit shall make an root-dump file (for debugging purposes, default: no). + bool fTitleFromDataFile; ///< flag indicating if the title should be extracted from the data file (default: yes). + bool fChisqPreRunBlock; ///< flag indicating if musrfit shall write 'per run block' chisq to the msr-file (default: no). + bool fEstimateN0; ///< flag indicating if musrfit shall estimate N0 for single histogram fits (default: yes). + bool fEnableMusrT0; ///< flag indicating if musrT0 shall be enabled at startup from within musredit (default: yes). + bool fDarkThemeIconsMenu; ///< flag indicating if dark theme icons shall be used in the menu (default: no) + bool fDarkThemeIconsToolbar; ///< flag indicating if dark theme icons shall be used in the toolbar (default: no) + + QString fBeamline; ///< name of the beamline. Used to generate default run header lines. + QString fInstitute; ///< name of the institute. Used to generate default run header lines. + QString fFileFormat; ///< default file format. Used to generate default run header lines. + bool fLifetimeCorrection; ///< flag indicating if by default the lifetime-correction-flag in a single histo file shall be set. + + mutable PMsr2DataParam fMsr2DataParam; ///< keeps msr2data default parameter flags + + QMap fHelpUrl; ///< maps tag to help url + + QVector fTheory; ///< stores all known theories. Needed when generating theory blocks from within musredit. + + void saveRecentFiles(); ///< save recent file list + void createMusreditStartupFile(); ///< create default musredit_startup.xml +}; + +#endif // _PADMIN_H_ diff --git a/src/musredit_qt6/musredit/PChangeDefaultPathsDialog.cpp b/src/musredit_qt6/musredit/PChangeDefaultPathsDialog.cpp new file mode 100644 index 00000000..0ab70a12 --- /dev/null +++ b/src/musredit_qt6/musredit/PChangeDefaultPathsDialog.cpp @@ -0,0 +1,339 @@ +/**************************************************************************** + + PChangeDefaultPathsDialog.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2010-2021 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 "PChangeDefaultPathsDialog.h" + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/** + *

XML Parser class for the musrfit administration file. + * + * \param fln file name of the musredit startup xml-file + * @param defaultPaths + */ +PDefaultPathsXMLParser::PDefaultPathsXMLParser(const QString& fln, PDefaultPaths *defaultPaths) : + fDefaultPaths(defaultPaths) +{ + fValid = false; + fKeyWord = eEmpty; + + QFile file(fln); + if (!file.open(QFile::ReadOnly | QFile::Text)) { + // warning and create default - STILL MISSING + } + + fValid = parse(&file); +} + +//-------------------------------------------------------------------------- +/** + *

parse the musrfit startup xml-file. + * + * \param device QFile object of the musrfit startup xml-file + * + * @return true on success, false otherwise + */ +bool PDefaultPathsXMLParser::parse(QIODevice *device) +{ + fXml.setDevice(device); + + bool expectChars = false; + while (!fXml.atEnd()) { + fXml.readNext(); + if (fXml.isStartDocument()) { + startDocument(); + } else if (fXml.isStartElement()) { + startElement(); + expectChars = true; + } else if (fXml.isCharacters() && expectChars) { + characters(); + } else if (fXml.isEndElement()) { + endElement(); + expectChars = false; + } else if (fXml.isEndDocument()) { + endDocument(); + } + } + if (fXml.hasError()) { + QString msg; + msg = QString("%1 Line %2, column %3").arg(fXml.errorString()).arg(fXml.lineNumber()).arg(fXml.columnNumber()); + QMessageBox::critical(0, "**ERROR**", msg, QMessageBox::Ok, QMessageBox::NoButton); + return false; + } + + return true; +} + +//-------------------------------------------------------------------------- +/** + *

Routine called at the beginning of the XML parsing process. + */ +bool PDefaultPathsXMLParser::startDocument() +{ + // nothing to be done here for now + return true; +} + +//-------------------------------------------------------------------------- +/** + *

Routine called when a new XML tag is found. Here it is used + * to set a tag for filtering afterwards the content. + */ +bool PDefaultPathsXMLParser::startElement() +{ + QString qName = fXml.name().toString(); + + if (qName == "data_path") { + fKeyWord = eDataPath; + } + + return true; +} + +//-------------------------------------------------------------------------- +/** + *

Routine called when the end XML tag is found. It is used to + * put the filtering tag to 'empty'. + */ +bool PDefaultPathsXMLParser::endElement() +{ + fKeyWord = eEmpty; + + return true; +} + +//-------------------------------------------------------------------------- +/** + *

This routine delivers the content of an XML tag. It fills the + * content into the load data structure. + */ +bool PDefaultPathsXMLParser::characters() +{ + QString str = fXml.text().toString(); + if (str.isEmpty()) + return true; + + switch (fKeyWord) { + case eDataPath: + fDefaultPaths->appendDefaultPath(str); + break; + default: + break; + } + + return true; +} + +//-------------------------------------------------------------------------- +/** + *

Called at the end of the XML parse process. It checks if default paths + * contain system variables, and if so expand them for the further use. + */ +bool PDefaultPathsXMLParser::endDocument() +{ + return true; +} + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/** + * @brief PDefaultPaths::PDefaultPaths + */ +PDefaultPaths::PDefaultPaths() : QObject() +{ + fValid = true; + + // XML Parser part + // 1st: check local directory + QString path = QString("./"); + QString fln = QString("musrfit_startup.xml"); + QString pathFln = path + fln; + QProcessEnvironment procEnv = QProcessEnvironment::systemEnvironment(); + if (!QFile::exists(pathFln)) { + // 2nd: check $HOME/.musrfit/musrfit_startup.xml + path = procEnv.value("HOME", ""); + pathFln = path + "/.musrfit/" + fln; + if (!QFile::exists(pathFln)) { + // 3rd: check $MUSRFITPATH/musrfit_startup.xml + path = procEnv.value("MUSRFITPATH", ""); + pathFln = path + "/" + fln; + if (!QFile::exists(pathFln)) { + // 4th: check $ROOTSYS/bin/musrfit_startup.xml + path = procEnv.value("ROOTSYS", ""); + pathFln = path + "/bin/" + fln; + } + } + } + fPrefPathName = pathFln; + + // read musrfit_startup.xml and extract default data file search paths + PDefaultPathsXMLParser handler(fPrefPathName, this); + if (!handler.isValid()) { + fValid = false; + QMessageBox::critical(0, "ERROR", + "Error parsing musrfit_startup.xml settings file.\nProbably a few things will not work porperly.\nPlease fix this first.", + QMessageBox::Ok, QMessageBox::NoButton); + return; + } +} + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/** + *

Constructor. + * + * \param fAdmin keeps all the needed flags + */ +PChangeDefaultPathsDialog::PChangeDefaultPathsDialog() +{ + fDefaultPath = 0; + fDefaultPath = new PDefaultPaths(); + if (!fDefaultPath->isValid()) + return; + + QStringList *strList = fDefaultPath->getDefaultPathList(); + if (strList == 0) + return; + + setupUi(this); + + setModal(true); + + // populate default search paths + for (int i=0; icount(); i++) { + fSearchPath_listWidget->addItem(strList->at(i)); + } + + QObject::connect(fDelete_pushButton, SIGNAL(clicked()), this, SLOT(deleteItem())); + QObject::connect(fAdd_pushButton, SIGNAL(clicked()), this, SLOT(addItem())); + QObject::connect(buttonBox, SIGNAL(accepted()), this, SLOT(saveDefaultPathList())); +} + +//---------------------------------------------------------------------------------------------------- +/** + * @brief PChangeDefaultPathsDialog::addItem + */ +void PChangeDefaultPathsDialog::addItem() +{ + // call QFileDialog in order to get the proper directory + QString dirName = QFileDialog::getExistingDirectory(this, tr("Data File Directory"), "", + QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + if (dirName == "") + return; + + // insert the new directory in fSearchPath_listWidget + QListWidgetItem *item = new QListWidgetItem; + if (item == 0) { + QMessageBox::critical(this, "ERROR", "Couldn't invoke QListWidgetItem! Won't do anything."); + return; + } + item->setText(dirName); + fSearchPath_listWidget->insertItem(fSearchPath_listWidget->currentRow()+1, item); +} + +//---------------------------------------------------------------------------------------------------- +/** + * @brief PChangeDefaultPathsDialog::deleteItem + */ +void PChangeDefaultPathsDialog::deleteItem() +{ + QListWidgetItem *item = fSearchPath_listWidget->takeItem(fSearchPath_listWidget->currentRow()); + if (item != 0) + delete item; +} + +//---------------------------------------------------------------------------------------------------- +/** + * @brief PChangeDefaultPathsDialog::saveDefaultPathList + */ +void PChangeDefaultPathsDialog::saveDefaultPathList() +{ + // read the used musrfit_startup.xml + QFile fileIn(fDefaultPath->getPrefPathName()); + if (!fileIn.open(QIODevice::ReadOnly | QIODevice::Text)) { + QMessageBox::critical(this, "ERROR", QString("Cannot read '%1'. Won't do anything.").arg(fDefaultPath->getPrefPathName())); + return; + } + QTextStream in(&fileIn); + QStringList fileContent; + while (!in.atEnd()) { + fileContent << in.readLine(); + } + fileIn.close(); + + // check if there is any data_path is present in the musrfit_startup.xml + bool dataPathPresent = false; + QString str; + for (int i=0; i")) { + dataPathPresent = true; + break; + } + } + + // write the new musrfit_startup.xml + QFile fileOut(fDefaultPath->getPrefPathName()); + if (!fileOut.open(QIODevice::WriteOnly | QIODevice::Text)) { + QMessageBox::critical(this, "ERROR", QString("Cannot write to '%1'.").arg(fDefaultPath->getPrefPathName())); + return; + } + QTextStream out(&fileOut); + bool first = true; + for (int i=0; i")) { + // if not data_path was present, add the new data_paths just before the end of the musrfit_start.xml close tag + if ((dataPathPresent == false) && (str.trimmed().startsWith(""))) { + for (int j=0; jcount(); j++) { + out << " " << fSearchPath_listWidget->item(j)->text() << "" << Qt::endl; + } + } + out << fileContent[i] << Qt::endl; + } else { + if (first) { + first = false; + for (int j=0; jcount(); j++) + out << " " << fSearchPath_listWidget->item(j)->text() << "" << Qt::endl; + } + } + } + fileOut.close(); +} + +//---------------------------------------------------------------------------------------------------- +// END +//---------------------------------------------------------------------------------------------------- diff --git a/src/musredit_qt6/musredit/PChangeDefaultPathsDialog.h b/src/musredit_qt6/musredit/PChangeDefaultPathsDialog.h new file mode 100644 index 00000000..e4aa0de4 --- /dev/null +++ b/src/musredit_qt6/musredit/PChangeDefaultPathsDialog.h @@ -0,0 +1,104 @@ +/**************************************************************************** + + PChangeDefaultPathsDialog.h + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2010-2019 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. * + ***************************************************************************/ + +#ifndef _PCHANGEDEFAULTPATHSDIALOG_H_ +#define _PCHANGEDEFAULTPATHSDIALOG_H_ + +#include +#include +#include +#include + +#include "ui_PChangeDefaultPathsDialog.h" + +class PDefaultPaths; + +//--------------------------------------------------------------------------- +class PDefaultPathsXMLParser +{ + public: + PDefaultPathsXMLParser(const QString &fln, PDefaultPaths *defaultPaths); + virtual ~PDefaultPathsXMLParser() {} + + virtual bool isValid() { return fValid; } + + private: + enum EAdminKeyWords {eEmpty, eDataPath}; + + bool parse(QIODevice *device); + bool startDocument(); + bool startElement(); + bool endElement(); + bool characters(); + bool endDocument(); + + QXmlStreamReader fXml; ///< xml stream reader object + bool fValid; ///< flag showing if XML read has been successful + EAdminKeyWords fKeyWord; ///< key word tag to know how to handle the content + PDefaultPaths *fDefaultPaths; ///< keeps the default search paths for the data files +}; + +//--------------------------------------------------------------------------- +class PDefaultPaths : public QObject +{ + public: + PDefaultPaths(); + virtual ~PDefaultPaths() {} + + virtual bool isValid() { return fValid; } + virtual void appendDefaultPath(QString str) { fDefaultPath << str; } + virtual QStringList *getDefaultPathList() { return &fDefaultPath; } + virtual QString getPrefPathName() { return fPrefPathName; } + + private: + friend class PDefaultPathsXMLParser; + + bool fValid; + QString fPrefPathName; + QStringList fDefaultPath; +}; + +//--------------------------------------------------------------------------- +class PChangeDefaultPathsDialog : public QDialog, private Ui::PChangeDefaultPathsDialog +{ + Q_OBJECT + + public: + PChangeDefaultPathsDialog(); + + private slots: + void deleteItem(); + void addItem(); + void saveDefaultPathList(); + + private: + PDefaultPaths *fDefaultPath; +}; + +#endif // _PCHANGEDEFAULTPATHSDIALOG_H_ diff --git a/src/musredit_qt6/musredit/PDumpOutputHandler.cpp b/src/musredit_qt6/musredit/PDumpOutputHandler.cpp new file mode 100644 index 00000000..1a17fcbe --- /dev/null +++ b/src/musredit_qt6/musredit/PDumpOutputHandler.cpp @@ -0,0 +1,160 @@ +/**************************************************************************** + + PDumpOutputHandler.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2012-2019 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 "PDumpOutputHandler.h" + +//---------------------------------------------------------------------------------------------------- +/** + *

Sets up the dump output handler GUI and starts the actual dump_header command + * + * \param cmd command string vector. From this the actual dump_header command will be generated and executed. + */ +PDumpOutputHandler::PDumpOutputHandler(QVector &cmd) +{ + if (cmd.empty()) + return; + + // Layout + fVbox = new QVBoxLayout( this ); + fOutput = new QTextEdit(); + fVbox->addWidget(fOutput); + fOutput->setMinimumSize(600, 755); + fOutput->setReadOnly(true); + connect( fOutput, SIGNAL( destroyed() ), this, SLOT( quitButtonPressed() ) ); + fQuitButton = new QPushButton( tr("Quit") ); + fVbox->addWidget(fQuitButton); + connect( fQuitButton, SIGNAL( clicked() ), this, SLOT( quitButtonPressed() ) ); + resize( 600, 800 ); + fQuitButton->setFocus(); + + // QProcess related code + fProc = new QProcess( this ); + + // make sure that the system environment variables are properly set + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + env.insert("LD_LIBRARY_PATH", env.value("ROOTSYS") + "/lib:" + env.value("LD_LIBRARY_PATH")); + fProc->setProcessEnvironment(env); + + // Set up the command and arguments. + QString program = cmd[0]; + QStringList arguments; + for (int i=1; istart(program, arguments); + if ( !fProc->waitForStarted() ) { + // error handling + QString msg(tr("Could not execute the output command: ")+cmd[0]); + QMessageBox::critical( 0, + tr("Fatal error"), + msg, + tr("Quit") ); + done(0); + } + + fProcPID = fProc->processId(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Destructor. Checks if the a dump_header is still running and if yes try to kill it. + */ +PDumpOutputHandler::~PDumpOutputHandler() +{ + if (fProc->state() == QProcess::Running) { + fProc->terminate(); + if (!fProc->waitForFinished()) { + qDebug() << "fProc still running, will call kill." << Qt::endl; + fProc->kill(); + } + fProc->waitForFinished(); + } + if (fProc->state() == QProcess::Running) { + QString cmd = "kill -9 "+ QString("%1").arg(fProcPID); + QString msg = "fProc still running even after Qt kill, will try system kill cmd: "+cmd; + qDebug() << msg << Qt::endl; + system(cmd.toLatin1()); + } + if (fProc) { + delete fProc; + fProc = 0; + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Captures the standard output and adds it to the output text edit. + */ +void PDumpOutputHandler::readFromStdOut() +{ + // Read and process the data. + // Bear in mind that the data might be output in chunks. + fOutput->append( fProc->readAllStandardOutput() ); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Captures the standard error and adds it to the output text edit. + */ +void PDumpOutputHandler::readFromStdErr() +{ + // Read and process the data. + // Bear in mind that the data might be output in chunks. + fOutput->append( fProc->readAllStandardError() ); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

If the quit button is pressed while the dump_header is still running, try to terminate dump_header, if this + * does not work, try to kill dump_header. + */ +void PDumpOutputHandler::quitButtonPressed() +{ + // if the fitting is still taking place, kill it + if (fProc->state() == QProcess::Running) { + fProc->terminate(); + if (!fProc->waitForFinished()) { + fProc->kill(); + } + } + + accept(); +} + +//---------------------------------------------------------------------------------------------------- +// END +//---------------------------------------------------------------------------------------------------- diff --git a/src/musredit_qt6/musredit/PDumpOutputHandler.h b/src/musredit_qt6/musredit/PDumpOutputHandler.h new file mode 100644 index 00000000..5a726bd9 --- /dev/null +++ b/src/musredit_qt6/musredit/PDumpOutputHandler.h @@ -0,0 +1,72 @@ +/**************************************************************************** + + PDumpOutputHandler.h + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2012-2019 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. * + ***************************************************************************/ + +#ifndef _PDUMPOUTPUTHANDLER_H_ +#define _PDUMPOUTPUTHANDLER_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +//--------------------------------------------------------------------------------------- +/** + *

This class is the capturing the output of musrfit and displays it in a dialog so + * the user has the chance to follow the fitting process, warnings, error messages of + * musrfit. + */ +class PDumpOutputHandler : public QDialog +{ + Q_OBJECT + + public: + PDumpOutputHandler(QVector &cmd); + virtual ~PDumpOutputHandler(); + + private slots: + virtual void readFromStdOut(); + virtual void readFromStdErr(); + virtual void quitButtonPressed(); + +private: + qint64 fProcPID; ///< keeps the process PID + QProcess *fProc; ///< pointer to the dump_header process + + QVBoxLayout *fVbox; ///< pointer to the dialog layout manager + QTextEdit *fOutput; ///< the captured dump_header output is written (read only) into this text edit object. + QPushButton *fQuitButton; ///< quit button +}; + +#endif // _PDUMPOUTPUTHANDLER_H_ diff --git a/src/musredit_qt6/musredit/PFindDialog.cpp b/src/musredit_qt6/musredit/PFindDialog.cpp new file mode 100644 index 00000000..d512d40c --- /dev/null +++ b/src/musredit_qt6/musredit/PFindDialog.cpp @@ -0,0 +1,108 @@ +/**************************************************************************** + + PFindDialog.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2009-2019 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 "PFindDialog.h" + +//---------------------------------------------------------------------------------------------------- +/** + *

Sets up the find dialog. + * + * \param data pointer to the find/replace data structure needed to perform the task. + * \param selection flag indicating if the find shall be restricted to the selected area + * \param parent pointer to the parent object + * \param f qt specific window flags + */ +PFindDialog::PFindDialog(PFindReplaceData *data, const bool selection, QWidget *parent) : + QDialog(parent), fData(data) +{ + setupUi(this); + + setModal(true); + + // if only empty text, disable find button + if (fData->findText == "") { + fFind_pushButton->setEnabled(false); + } + + // if there is no selection, disable that option + if (!selection) { + fSelectedText_checkBox->setChecked(false); + fSelectedText_checkBox->setEnabled(false); + } + + fFind_comboBox->setItemText(0, fData->findText); + fCaseSensitive_checkBox->setChecked(fData->caseSensitive); + fWholeWordsOnly_checkBox->setChecked(fData->wholeWordsOnly); + fFromCursor_checkBox->setChecked(fData->fromCursor); + fFindBackwards_checkBox->setChecked(fData->findBackwards); + + if (selection) { + fSelectedText_checkBox->setChecked(fData->selectedText); + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Extracts all the necessary informations from the find dialog, feeds it to the find/replace + * structure and returns a point to this structure. + */ +PFindReplaceData* PFindDialog::getData() +{ + fData->findText = fFind_comboBox->currentText(); + fData->caseSensitive = fCaseSensitive_checkBox->isChecked(); + fData->wholeWordsOnly = fWholeWordsOnly_checkBox->isChecked(); + fData->fromCursor = fFromCursor_checkBox->isChecked(); + fData->findBackwards = fFindBackwards_checkBox->isChecked(); + if (fSelectedText_checkBox->isEnabled()) + fData->selectedText = fSelectedText_checkBox->isChecked(); + + return fData; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Enables the find button only if there is any find text entered. + */ +void PFindDialog::onFindTextAvailable(const QString&) +{ + if (fFind_comboBox->currentText() != "") + fFind_pushButton->setEnabled(true); + else + fFind_pushButton->setEnabled(false); +} + +//---------------------------------------------------------------------------------------------------- +// END +//---------------------------------------------------------------------------------------------------- diff --git a/src/musredit_qt6/musredit/PFindDialog.h b/src/musredit_qt6/musredit/PFindDialog.h new file mode 100644 index 00000000..55ed89a7 --- /dev/null +++ b/src/musredit_qt6/musredit/PFindDialog.h @@ -0,0 +1,57 @@ +/**************************************************************************** + + PFindDialog.h + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2010-2019 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. * + ***************************************************************************/ + +#ifndef _PFINDDIALOG_H_ +#define _PFINDDIALOG_H_ + +#include "musredit.h" +#include "ui_PFindDialog.h" + +//-------------------------------------------------------------------------------------------------- +/** + *

PFindDialog is the class handling the find dialog. + */ +class PFindDialog : public QDialog, private Ui::PFindDialog +{ + Q_OBJECT + + public: + PFindDialog(PFindReplaceData *data, const bool selection, QWidget *parent = nullptr); + virtual ~PFindDialog() {} + + virtual PFindReplaceData *getData(); + + protected slots: + virtual void onFindTextAvailable(const QString&); + + private: + PFindReplaceData *fData; ///< stores the data necessary to perform find/replace. +}; + +#endif // _PFINDDIALOG_H_ diff --git a/src/musredit_qt6/musredit/PFitOutputHandler.cpp b/src/musredit_qt6/musredit/PFitOutputHandler.cpp new file mode 100644 index 00000000..5e240a8a --- /dev/null +++ b/src/musredit_qt6/musredit/PFitOutputHandler.cpp @@ -0,0 +1,178 @@ +/**************************************************************************** + + PFitOutputHandler.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2009-2019 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 "PFitOutputHandler.h" + +//---------------------------------------------------------------------------------------------------- +/** + *

Sets up the fit output handler GUI and starts the actual fit + * + * \param workingDirectory string holding the working directory wished. In this directory the mlog-file will be saved. + * \param cmd command string vector. From this the actuall fit command will be generated and executed. + */ +PFitOutputHandler::PFitOutputHandler(QString workingDirectory, QVector &cmd) +{ + if (cmd.empty()) + return; + + // Layout + fVbox = new QVBoxLayout( this ); +//Qt.3x fVbox->resize(800, 500); + fOutput = new QPlainTextEdit(); + fOutput->setMaximumBlockCount(1000); + fVbox->addWidget(fOutput); + fOutput->setMinimumSize(800, 455); + fOutput->setReadOnly(true); + connect( fOutput, SIGNAL( destroyed() ), this, SLOT( quitButtonPressed() ) ); + fQuitButton = new QPushButton( tr("Fitting...") ); + fVbox->addWidget(fQuitButton); + connect( fQuitButton, SIGNAL( clicked() ), this, SLOT( quitButtonPressed() ) ); + resize( 800, 500 ); + fQuitButton->setFocus(); + + // QProcess related code + fProc = new QProcess( this ); + + // make sure that the system environment variables are properly set + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + env.insert("LD_LIBRARY_PATH", env.value("ROOTSYS") + "/lib:" + env.value("LD_LIBRARY_PATH")); + fProc->setProcessEnvironment(env); + fProc->setWorkingDirectory(workingDirectory); + + // Set up the command and arguments. + QString program = cmd[0]; + QStringList arguments; + for (int i=1; istart(program, arguments); + if ( !fProc->waitForStarted() ) { + // error handling + QString msg(tr("Could not execute the output command: ")+cmd[0]); + QMessageBox::critical( nullptr, + tr("Fatal error"), + msg, + tr("Quit") ); + done(0); + } + fProcPID = fProc->processId(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Destructor. Checks if the a fit is still running and if yes try to kill it. + */ +PFitOutputHandler::~PFitOutputHandler() +{ + if (fProc->state() == QProcess::Running) { + fProc->terminate(); + if (!fProc->waitForFinished()) { + qDebug() << "fProc still running, will call kill." << Qt::endl; + fProc->kill(); + } + fProc->waitForFinished(); + } + if (fProc->state() == QProcess::Running) { + QString cmd = "kill -9 "+ QString("%1").arg(fProcPID); + QString msg = "fProc still running even after Qt kill, will try system kill cmd: "+cmd; + qDebug() << msg << Qt::endl; + system(cmd.toLatin1()); + } + if (fProc) { + delete fProc; + fProc = nullptr; + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Captures the standard output and adds it to the output text edit. + */ +void PFitOutputHandler::readFromStdOut() +{ + // Read and process the data. + // Bear in mind that the data might be output in chunks. + fOutput->appendPlainText( fProc->readAllStandardOutput() ); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Captures the standard error and adds it to the output text edit. + */ +void PFitOutputHandler::readFromStdErr() +{ + // Read and process the data. + // Bear in mind that the data might be output in chunks. + fOutput->appendPlainText( fProc->readAllStandardError() ); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

If musrfit finishes, crashes, ..., the quit button text will be changed to done. + * + * \param exitCode exit code of musrfit + * \param exitStatus exit status of musrfit + */ +void PFitOutputHandler::processDone(int exitCode, QProcess::ExitStatus exitStatus) +{ + if ((exitStatus == QProcess::CrashExit) && (exitCode != 0)) { + qDebug() << "**ERROR** PFitOutputHandler::processDone: exitCode = " << exitCode << Qt::endl; + } + fQuitButton->setText("Done"); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

If the quit button is pressed while the fit is still running, try to terminate musrfit, if this + * does not work, try to kill musrfit. + */ +void PFitOutputHandler::quitButtonPressed() +{ + // if the fitting is still taking place, kill it + if (fProc->state() == QProcess::Running) { + fProc->terminate(); + if (!fProc->waitForFinished()) { + fProc->kill(); + } + } + + accept(); +} + +//---------------------------------------------------------------------------------------------------- +// END +//---------------------------------------------------------------------------------------------------- diff --git a/src/musredit_qt6/musredit/PFitOutputHandler.h b/src/musredit_qt6/musredit/PFitOutputHandler.h new file mode 100644 index 00000000..66f80a98 --- /dev/null +++ b/src/musredit_qt6/musredit/PFitOutputHandler.h @@ -0,0 +1,73 @@ +/**************************************************************************** + + PFitOutputHandler.h + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2010-2019 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. * + ***************************************************************************/ + +#ifndef _PFITOUTPUTHANDLER_H_ +#define _PFITOUTPUTHANDLER_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +//--------------------------------------------------------------------------------------- +/** + *

This class is the capturing the output of musrfit and displays it in a dialog so + * the user has the chance to follow the fitting process, warnings, error messages of + * musrfit. + */ +class PFitOutputHandler : public QDialog +{ + Q_OBJECT + + public: + PFitOutputHandler(QString workingDirectory, QVector &cmd); + virtual ~PFitOutputHandler(); + + private slots: + virtual void readFromStdOut(); + virtual void readFromStdErr(); + virtual void quitButtonPressed(); + virtual void processDone(int exitCode, QProcess::ExitStatus exitStatus); + +private: + qint64 fProcPID; ///< keeps the process PID + QProcess *fProc; ///< pointer to the musrfit process + + QVBoxLayout *fVbox; ///< pointer to the dialog layout manager + QPlainTextEdit *fOutput; ///< the captured musrfit output is written (read only) into this text edit object. + QPushButton *fQuitButton; ///< quit button, either to interrupt the fit or to close the dialog at the end of the fit. +}; + +#endif // _PFITOUTPUTHANDLER_H_ diff --git a/src/musredit_qt6/musredit/PGetAsymmetryRunBlockDialog.cpp b/src/musredit_qt6/musredit/PGetAsymmetryRunBlockDialog.cpp new file mode 100644 index 00000000..7d6f2658 --- /dev/null +++ b/src/musredit_qt6/musredit/PGetAsymmetryRunBlockDialog.cpp @@ -0,0 +1,300 @@ +/**************************************************************************** + + PGetAsymmetryRunBlockDialog.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2009-2019 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 "PGetAsymmetryRunBlockDialog.h" + + +//---------------------------------------------------------------------------------------------------- +/** + *

Constructor. + * + * \param helpUrl help url for the asymmetry run block + */ +PGetAsymmetryRunBlockDialog::PGetAsymmetryRunBlockDialog(const QString helpUrl) : fHelpUrl(helpUrl) +{ + setupUi(this); + + setModal(true); + + fForwardHistoNo_lineEdit->setValidator( new QIntValidator(fForwardHistoNo_lineEdit) ); + fBackwardHistoNo_lineEdit->setValidator( new QIntValidator(fBackwardHistoNo_lineEdit) ); + fDataForwardStart_lineEdit->setValidator( new QIntValidator(fDataForwardStart_lineEdit) ); + fDataForwardEnd_lineEdit->setValidator( new QIntValidator(fDataForwardEnd_lineEdit) ); + fDataBackwardStart_lineEdit->setValidator( new QIntValidator(fDataBackwardStart_lineEdit) ); + fDataBackwardEnd_lineEdit->setValidator( new QIntValidator(fDataBackwardEnd_lineEdit) ); + fBackgroundForwardStart_lineEdit->setValidator( new QIntValidator(fBackgroundForwardStart_lineEdit) ); + fBackgroundForwardEnd_lineEdit->setValidator( new QIntValidator(fBackgroundForwardEnd_lineEdit) ); + fBackgroundBackwardStart_lineEdit->setValidator( new QIntValidator(fBackgroundBackwardStart_lineEdit) ); + fBackgroundBackwardEnd_lineEdit->setValidator( new QIntValidator(fBackgroundBackwardEnd_lineEdit) ); + fBackgroundForwardFix_lineEdit->setValidator( new QDoubleValidator(fBackgroundForwardFix_lineEdit) ); + fBackgroundBackwardFix_lineEdit->setValidator( new QDoubleValidator(fBackgroundBackwardFix_lineEdit) ); + fFitRangeStart_lineEdit->setValidator( new QDoubleValidator(fFitRangeStart_lineEdit) ); + fFitRangeEnd_lineEdit->setValidator( new QDoubleValidator(fFitRangeEnd_lineEdit) ); + fPacking_lineEdit->setValidator( new QIntValidator(fPacking_lineEdit) ); + fAlpha_lineEdit->setValidator( new QIntValidator(fAlpha_lineEdit) ); + fBeta_lineEdit->setValidator( new QIntValidator(fBeta_lineEdit) ); + fT0Forward_lineEdit->setValidator( new QIntValidator(fT0Forward_lineEdit) ); + fT0Backward_lineEdit->setValidator( new QIntValidator(fT0Backward_lineEdit) ); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

returns the run information line of the asymmetry run block. + */ +QString PGetAsymmetryRunBlockDialog::getRunHeaderInfo() +{ + QString str; + + str = "RUN " + fRunFileName_lineEdit->text() + " "; + str += fBeamline_lineEdit->text().toUpper() + " "; + str += fInstitute_comboBox->currentText() + " "; + str += fFileFormat_comboBox->currentText() + " (name beamline institute data-file-format)\n"; + + return str; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

returns the alpha parameter for the asymmetry run block. + * + * \param present flag indicating if the alpha parameter is used, or a default alpha==1 is going to be used. + */ +QString PGetAsymmetryRunBlockDialog::getAlphaParameter(bool &present) +{ + QString str = "alpha " + fAlpha_lineEdit->text() + "\n"; + + if (str.isEmpty()) + present = false; + else + present = true; + + return str; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

returns the beta parameter for the asymmetry run block + * + * \param present flag indicating if the beta parameter is used, or a default beta==1 is going to be used. + */ +QString PGetAsymmetryRunBlockDialog::getBetaParameter(bool &present) +{ + QString str = "beta " + fBeta_lineEdit->text() + "\n"; + + if (str.isEmpty()) + present = false; + else + present = true; + + return str; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

returns the map for the asymmetry run block. + * + * \param valid flag indicating if the map is potentially valid. + */ +QString PGetAsymmetryRunBlockDialog::getMap(bool &valid) +{ + QString str = fMap_lineEdit->text().trimmed().remove(" "); + + // check if potentially proper map line + for (int i=0; itext() + "\n"; + + return str; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

returns the background information for the asymmetry run block. + * + * \param valid flag indicating if a valid background (either backgr.fix or background is given, but not both) + * is present. + */ +QString PGetAsymmetryRunBlockDialog::getBackground(bool &valid) +{ + QString str = ""; + + valid = true; + + // check that either backgr.fix or background is given, but not both + if (fBackgroundForwardStart_lineEdit->text().isEmpty() && fBackgroundForwardEnd_lineEdit->text().isEmpty() && + fBackgroundBackwardStart_lineEdit->text().isEmpty() && fBackgroundBackwardEnd_lineEdit->text().isEmpty() && + fBackgroundForwardFix_lineEdit->text().isEmpty() && fBackgroundBackwardFix_lineEdit->text().isEmpty()) { + valid = false; + str = "background 0 10 0 10\n"; + } else { + if (!fBackgroundForwardStart_lineEdit->text().isEmpty()) { // assume the rest is given, not fool prove but ... + str = "background "; + str += fBackgroundForwardStart_lineEdit->text() + " "; + str += fBackgroundForwardEnd_lineEdit->text() + " "; + str += fBackgroundBackwardStart_lineEdit->text() + " "; + str += fBackgroundBackwardEnd_lineEdit->text() + "\n"; + } + if (!fBackgroundForwardFix_lineEdit->text().isEmpty()) { // assume the rest is given, not fool prove but ... + str = "backgr.fix "; + str += fBackgroundForwardFix_lineEdit->text() + " "; + str += fBackgroundBackwardFix_lineEdit->text() + "\n"; + } + } + + return str; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

returns a data range (in bins) entry for the asymmetry run block. + * + * \param valid flag indicating if the data entries are valid. + */ +QString PGetAsymmetryRunBlockDialog::getData(bool &valid) +{ + QString str = ""; + + if (fDataForwardStart_lineEdit->text().isEmpty() || fDataForwardEnd_lineEdit->text().isEmpty() || + fDataBackwardStart_lineEdit->text().isEmpty() || fDataBackwardEnd_lineEdit->text().isEmpty()) { + valid = false; + } else { + str = "data "; + str += fDataForwardStart_lineEdit->text() + " "; + str += fDataForwardEnd_lineEdit->text() + " "; + str += fDataBackwardStart_lineEdit->text() + " "; + str += fDataBackwardEnd_lineEdit->text() + "\n"; + valid = true; + } + + return str; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

returns a t0 parameter for the asymmetry run block. + * + * \param present flag indicating if a t0 parameter is set. + */ +QString PGetAsymmetryRunBlockDialog::getT0(bool &present) +{ + QString str = ""; + + if (!fT0Forward_lineEdit->text().isEmpty() && !fT0Forward_lineEdit->text().isEmpty()) { + str = "t0 "; + str += fT0Forward_lineEdit->text() + " "; + str += fT0Backward_lineEdit->text() + "\n"; + present = true; + } else { + present = false; + } + + return str; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

returns a fit range entry for the asymmetry run block. If no fit range has been provided, + * a fit range [0,10] will be set and the valid flag will be set to false. + * + * \param valid flag indicating if a fit range was provided. + */ +QString PGetAsymmetryRunBlockDialog::getFitRange(bool &valid) +{ + QString str = ""; + + if (fFitRangeStart_lineEdit->text().isEmpty() || fFitRangeEnd_lineEdit->text().isEmpty()) { + str += "fit 0.0 10.0\n"; + valid = false; + } else { + str += "fit "; + str += fFitRangeStart_lineEdit->text() + " "; + str += fFitRangeEnd_lineEdit->text() + "\n"; + valid = true; + } + + return str; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

returns the packing/binning of the asymmetry run block. If no packing has been provided, + * a packing of '1' will be set and the present flag will be set to false. + * + * \param present flag indicating if a packing parameter was provided. + */ +QString PGetAsymmetryRunBlockDialog::getPacking(bool &present) +{ + QString str = ""; + + if (fPacking_lineEdit->text().isEmpty()) { + present = false; + str += "packing 1\n"; + } else { + present = true; + str += "packing " + fPacking_lineEdit->text() + "\n\n"; + } + + return str; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Generates a help content window showing the description of the asymmetry run block. + */ +void PGetAsymmetryRunBlockDialog::helpContent() +{ + if (fHelpUrl.isEmpty()) { + QMessageBox::information(this, "**INFO**", "Will eventually show a help window"); + } else { + bool ok = QDesktopServices::openUrl(QUrl(fHelpUrl, QUrl::TolerantMode)); + if (!ok) { + QString msg = QString("

Sorry: Couldn't open default web-browser for the help.
Please try: musrfit docu in your web-browser.").arg(fHelpUrl); + QMessageBox::critical( nullptr, + tr("Fatal Error"), + msg, + tr("Quit") ); + } + } +} + +//---------------------------------------------------------------------------------------------------- +// END +//---------------------------------------------------------------------------------------------------- diff --git a/src/musredit_qt6/musredit/PGetAsymmetryRunBlockDialog.h b/src/musredit_qt6/musredit/PGetAsymmetryRunBlockDialog.h new file mode 100644 index 00000000..c6c2cce3 --- /dev/null +++ b/src/musredit_qt6/musredit/PGetAsymmetryRunBlockDialog.h @@ -0,0 +1,65 @@ +/**************************************************************************** + + PGetAsymmetryRunBlockDialog.h + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2009-2019 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. * + ***************************************************************************/ + +#ifndef _PGETASYMMETRYRUNBLOCKDIALOG_H_ +#define _PGETASYMMETRYRUNBLOCKDIALOG_H_ + +#include "ui_PGetAsymmetryRunBlockDialog.h" + +//--------------------------------------------------------------------------- +/** + *

Class handling the content of the menu: Edit/Add Block/Asymmetry Run Block. + */ +class PGetAsymmetryRunBlockDialog : public QDialog, private Ui::PGetAsymmetryRunBlockDialog +{ + Q_OBJECT + + public: + PGetAsymmetryRunBlockDialog(const QString helpUrl); + + QString getRunHeaderInfo(); + QString getAlphaParameter(bool &present); + QString getBetaParameter(bool &present); + QString getMap(bool &valid); + QString getForward() { return QString("forward " + fForwardHistoNo_lineEdit->text() + "\n"); } + QString getBackward() { return QString("backward " + fBackwardHistoNo_lineEdit->text() + "\n"); } + QString getBackground(bool &valid); + QString getData(bool &valid); + QString getT0(bool &present); + QString getFitRange(bool &valid); + QString getPacking(bool &present); + + private slots: + void helpContent(); + + private: + QString fHelpUrl; ///< help url for the asymmetry run block +}; + +#endif // _PGETASYMMETRYRUNBLOCKDIALOG_H_ diff --git a/src/musredit_qt6/musredit/PGetDefaultDialog.cpp b/src/musredit_qt6/musredit/PGetDefaultDialog.cpp new file mode 100644 index 00000000..0c5ae759 --- /dev/null +++ b/src/musredit_qt6/musredit/PGetDefaultDialog.cpp @@ -0,0 +1,118 @@ +/**************************************************************************** + + PGetDefaultDialog.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2009-2019 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 "PHelp.h" + +#include "PGetDefaultDialog.h" + +#define INSTITUTE_PSI 0 +#define INSTITUTE_RAL 1 +#define INSTITUTE_TRIUMF 2 +#define INSTITUTE_JPARC 3 + +#define FILE_FORMAT_NEXUS 0 +#define FILE_FORMAT_ROOT_NPP 1 +#define FILE_FORMAT_ROOT_PPC 2 +#define FILE_FORMAT_PSIBIN 3 +#define FILE_FORMAT_MUD 4 +#define FILE_FORMAT_WKM 5 +#define FILE_FORMAT_ASCII 6 +#define FILE_FORMAT_DB 7 + + +//--------------------------------------------------------------------------- +/** + *

Constructor + * + * \param helpUrl help url for the default dialog + */ +PGetDefaultDialog::PGetDefaultDialog(const QString helpUrl) : fHelpUrl(helpUrl) +{ + setupUi(this); + + setModal(true); +} + + +//--------------------------------------------------------------------------- +/** + *

Finds the name of the institute in the combo box and selects it. + * + * \param str name of the institute + */ +void PGetDefaultDialog::setInstitute(const QString &str) { + + for (int i=0; icount(); i++) { + if (fInstitute_comboBox->itemText(i).toLower() == str.toLower()) { + fInstitute_comboBox->setCurrentIndex(i); + break; + } + } + +} + +//--------------------------------------------------------------------------- +/** + *

Finds the file format in the combo box and selects it. + * + * \param str file format + */ +void PGetDefaultDialog::setFileFormat(const QString &str) +{ + + for (int i=0; icount(); i++) { + if (fFileFormat_comboBox->itemText(i).toLower() == str.toLower()) { + fFileFormat_comboBox->setCurrentIndex(i); + break; + } + } + +} + +//--------------------------------------------------------------------------- +/** + *

Generates a help content window showing the description fitting the default dialog. + */ +void PGetDefaultDialog::helpContent() +{ + #ifdef _WIN32GCC + QMessageBox::information(this, "**INFO**", "If a newer Qt version was available, a help window would be shown!"); + #else + PHelp *help = new PHelp(fHelpUrl); + help->show(); + #endif // _WIN32GCC +} + +//--------------------------------------------------------------------------- +// END +//--------------------------------------------------------------------------- diff --git a/src/musredit_qt6/musredit/PGetDefaultDialog.h b/src/musredit_qt6/musredit/PGetDefaultDialog.h new file mode 100644 index 00000000..8ef8f216 --- /dev/null +++ b/src/musredit_qt6/musredit/PGetDefaultDialog.h @@ -0,0 +1,69 @@ +/**************************************************************************** + + PGetDefaultDialog.h + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2010-2019 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. * + ***************************************************************************/ + +#ifndef _PGETDEFAULTDIALOG_H_ +#define _PGETDEFAULTDIALOG_H_ + +#include +#include +#include +#include + +#include "ui_PGetDefaultDialog.h" + +//--------------------------------------------------------------------------- +/** + *

Handels the default dialog which is used to generate a default asymmetry or + * single histogram msr input file. + */ +class PGetDefaultDialog : public QDialog, private Ui::PGetDefaultDialog +{ + Q_OBJECT + + public: + PGetDefaultDialog(const QString helpUrl = ""); + virtual ~PGetDefaultDialog() {} + + virtual const QString getRunFileName() const { return fRunFileName_lineEdit->text(); } + virtual const QString getBeamline() const { return fBeamline_lineEdit->text(); } + virtual const QString getInstitute() const { return fInstitute_comboBox->currentText(); } + virtual const QString getFileFormat() const { return fFileFormat_comboBox->currentText(); } + + virtual void setBeamline(const QString &str) { fBeamline_lineEdit->setText(str); } + virtual void setInstitute(const QString &str); + virtual void setFileFormat(const QString &str); + + protected slots: + virtual void helpContent(); + + private: + QString fHelpUrl; ///< help url for the default dialog +}; + +#endif // _PGETDEFAULTDIALOG_H_ diff --git a/src/musredit_qt6/musredit/PGetFourierBlockDialog.cpp b/src/musredit_qt6/musredit/PGetFourierBlockDialog.cpp new file mode 100644 index 00000000..2f76e66b --- /dev/null +++ b/src/musredit_qt6/musredit/PGetFourierBlockDialog.cpp @@ -0,0 +1,148 @@ +/**************************************************************************** + + PGetFourierBlockDialog.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2009-2019 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 "PGetFourierBlockDialog.h" + +//---------------------------------------------------------------------------------------------------- +/** + *

Constructor + * + * \param helpUrl help url address for the Fourier block. + */ +PGetFourierBlockDialog::PGetFourierBlockDialog(const QString helpUrl) : fHelpUrl(helpUrl) +{ + setupUi(this); + + setModal(true); + + fFourierBlock = ""; + fFourierPower_lineEdit->setValidator( new QIntValidator(fFourierPower_lineEdit) ); + fPhaseCorrectionRangeLow_lineEdit->setValidator( new QDoubleValidator(fPhaseCorrectionRangeLow_lineEdit) ); + fPhaseCorrectionRangeUp_lineEdit->setValidator( new QDoubleValidator(fPhaseCorrectionRangeUp_lineEdit) ); + fRangeLow_lineEdit->setValidator( new QDoubleValidator(fRangeLow_lineEdit) ); + fRangeUp_lineEdit->setValidator( new QDoubleValidator(fRangeUp_lineEdit) ); + + connect( fPhase_lineEdit, SIGNAL( lostFocus() ), this, SLOT( checkPhaseParameter() ) ); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Checks if the phase parameter is either a number are has the form parXX, where XX is a number. + */ +void PGetFourierBlockDialog::checkPhaseParameter() +{ + QString str = fPhase_lineEdit->text(); + + if (str.isEmpty()) + return; + + bool ok; + int ival; + + ival = str.toInt(&ok); + if (!ok) { // i.e. the phase entry is not a number. Check for parXX + str = str.trimmed(); + if (str.startsWith("par")) { // + str.remove("par"); + ival = str.toInt(&ok); + if (!ok) { + fPhase_lineEdit->clear(); + QMessageBox::critical(this, "**ERROR**", + "Allowed phase entries are either a parameter number,\n or an parXX entry, where XX is a parameter number", + QMessageBox::Ok, QMessageBox::NoButton); + fPhase_lineEdit->setFocus(); + } + } else { // neither a parXX nor a number + fPhase_lineEdit->clear(); + QMessageBox::critical(this, "**ERROR**", + "Allowed phase entries are either a parameter number,\n or an parXX entry, where XX is a parameter number", + QMessageBox::Ok, QMessageBox::NoButton); + fPhase_lineEdit->setFocus(); + } + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Transfers the data of the dialog into a valid msr-file Fourier block string. + */ +void PGetFourierBlockDialog::fillFourierBlock() +{ + fFourierBlock = "###############################################################\n"; + fFourierBlock += "FOURIER\n"; + fFourierBlock += "units " + fUnits_comboBox->currentText() + "\n"; + QString str = fFourierPower_lineEdit->text(); + if (!str.isEmpty()) + fFourierBlock += "fourier_power " + str + "\n"; + fFourierBlock += "apodization " + fApodization_comboBox->currentText() + "\n"; + fFourierBlock += "plot " + fPlot_comboBox->currentText() + "\n"; + str = fPhase_lineEdit->text(); + if (!str.isEmpty()) + fFourierBlock += "phase " + str + "\n"; + if (!fPhaseCorrectionRangeLow_lineEdit->text().isEmpty() && !fPhaseCorrectionRangeUp_lineEdit->text().isEmpty()) { + fFourierBlock += "range_for_phase_correction " + fPhaseCorrectionRangeLow_lineEdit->text() + " " + + fPhaseCorrectionRangeUp_lineEdit->text() + "\n"; + } + if (!fRangeLow_lineEdit->text().isEmpty() && !fRangeUp_lineEdit->text().isEmpty()) { + fFourierBlock += "range " + fRangeLow_lineEdit->text() + " " + fRangeUp_lineEdit->text() + "\n"; + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Generates a help content window showing the description of the Fourier block. + */ +void PGetFourierBlockDialog::helpContent() +{ + if (fHelpUrl.isEmpty()) { + QMessageBox::information(this, "**INFO**", "Will eventually show a help window"); + } else { + bool ok = QDesktopServices::openUrl(QUrl(fHelpUrl, QUrl::TolerantMode)); + if (!ok) { + QString msg = QString("

Sorry: Couldn't open default web-browser for the help.
Please try: musrfit docu in your web-browser.").arg(fHelpUrl); + QMessageBox::critical( nullptr, + tr("Fatal Error"), + msg, + tr("Quit") ); + } + } +} + +//---------------------------------------------------------------------------------------------------- +// END +//---------------------------------------------------------------------------------------------------- diff --git a/src/musredit_qt6/musredit/PGetFourierBlockDialog.h b/src/musredit_qt6/musredit/PGetFourierBlockDialog.h new file mode 100644 index 00000000..3006c2e7 --- /dev/null +++ b/src/musredit_qt6/musredit/PGetFourierBlockDialog.h @@ -0,0 +1,60 @@ +/**************************************************************************** + + PGetFourierBlockDialog.h + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2009-2016 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. * + ***************************************************************************/ + +#ifndef _PGETFOURIERBLOCKDIALOG_H_ +#define _PGETFOURIERBLOCKDIALOG_H_ + +#include + +#include "ui_PGetFourierBlockDialog.h" + +//------------------------------------------------------------------------------- +/** + *

Handles the Fourier dialog. + */ +class PGetFourierBlockDialog : public QDialog, private Ui::PGetFourierBlockDialog +{ + Q_OBJECT + + public: + PGetFourierBlockDialog(const QString helpUrl); + + QString getFourierBlock() { return fFourierBlock; } + + private slots: + void checkPhaseParameter(); + void fillFourierBlock(); + void helpContent(); + + private: + QString fFourierBlock; ///< keeps the msr Fourier block + QString fHelpUrl; ///< help url for the Fourier block +}; + +#endif // _PGETFOURIERBLOCKDIALOG_H_ diff --git a/src/musredit_qt6/musredit/PGetFunctionsBlockDialog.cpp b/src/musredit_qt6/musredit/PGetFunctionsBlockDialog.cpp new file mode 100644 index 00000000..861af5dc --- /dev/null +++ b/src/musredit_qt6/musredit/PGetFunctionsBlockDialog.cpp @@ -0,0 +1,124 @@ +/**************************************************************************** + + PGetFunctionsBlockDialog.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2009-2019 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 "PGetFunctionsBlockDialog.h" + +//---------------------------------------------------------------------------------------------------- +/** + *

Constructor. + * + * \param helpUrl help url for the FUNCTIONS block. + */ +PGetFunctionsBlockDialog::PGetFunctionsBlockDialog(const QString helpUrl) : fHelpUrl(helpUrl) +{ + setupUi(this); + + setModal(true); + + fFunctionInput_lineEdit->setFocus(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Adds a function to the FUNCTIONS block text edit after carrying out some primitve tests about + * the consistency of the function (far from being a syntax/semantic checker!!). + */ +void PGetFunctionsBlockDialog::addFunction() +{ + QString str = fFunctionInput_lineEdit->text(); + + if (str.isEmpty()) + return; + + // validation + + // check that the function string starts with 'fun' + if (!str.trimmed().startsWith("fun")) { + QMessageBox::critical(this, "addFunction", + "a function has to start with 'funX' (X a number).\nNeeds to be fixed.", + QMessageBox::Ok, QMessageBox::NoButton); + return; + } + + // check if function string contains 'funX =' + if (str.indexOf( QRegularExpression("fun\\d+\\s*=") ) == -1) { + QMessageBox::critical(this, "addFunction", + "a function has to start with 'funX =' (X a positive number).\nNeeds to be fixed.", + QMessageBox::Ok, QMessageBox::NoButton); + return; + } + + // check if function string contains more than one 'funX' + if (str.trimmed().lastIndexOf("fun", -1, Qt::CaseInsensitive) > 0) { + QMessageBox::critical(this, "addFunction", + "a function cannot contain more than one function,\ni.e. fun2 = fun1 + par1 is not OK.", + QMessageBox::Ok, QMessageBox::NoButton); + return; + } + + // add to Functions block + fFunctionBlock_plainTextEdit->appendPlainText(str); + + // clear functions input text + fFunctionInput_lineEdit->clear(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Generates a help content window showing the description of the FUNCTIONS block. + */ +void PGetFunctionsBlockDialog::helpContent() +{ + if (fHelpUrl.isEmpty()) { + QMessageBox::information(this, "**INFO**", "Will eventually show a help window"); + } else { + bool ok = QDesktopServices::openUrl(QUrl(fHelpUrl, QUrl::TolerantMode)); + if (!ok) { + QString msg = QString("

Sorry: Couldn't open default web-browser for the help.
Please try: musrfit docu in your web-browser.").arg(fHelpUrl); + QMessageBox::critical( nullptr, + tr("Fatal Error"), + msg, + tr("Quit") ); + } + } +} + +//---------------------------------------------------------------------------------------------------- +// END +//---------------------------------------------------------------------------------------------------- diff --git a/src/musredit_qt6/musredit/PGetFunctionsBlockDialog.h b/src/musredit_qt6/musredit/PGetFunctionsBlockDialog.h new file mode 100644 index 00000000..c70427f6 --- /dev/null +++ b/src/musredit_qt6/musredit/PGetFunctionsBlockDialog.h @@ -0,0 +1,56 @@ +/**************************************************************************** + + PGetFunctionsBlockDialog.h + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2009-2019 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. * + ***************************************************************************/ + +#ifndef _PGETFUNCTIONSBLOCKDIALOG_H_ +#define _PGETFUNCTIONSBLOCKDIALOG_H_ + +#include "ui_PGetFunctionsBlockDialog.h" + +//----------------------------------------------------------------------------------- +/** + *

Handles the content of the FUNCTIONS block dialog. + */ +class PGetFunctionsBlockDialog : public QDialog, private Ui::PGetFunctionsBlockDialog +{ + Q_OBJECT + + public: + PGetFunctionsBlockDialog(const QString helpUrl = ""); + + QString getFunctionsBlock() { return fFunctionBlock_plainTextEdit->toPlainText(); } + + private slots: + void addFunction(); + void helpContent(); + + private: + QString fHelpUrl; ///< help url address for the FUNCTIONS block. +}; + +#endif // _PGETFUNCTIONSBLOCKDIALOG_H_ diff --git a/src/musredit_qt6/musredit/PGetMusrFTOptionsDialog.cpp b/src/musredit_qt6/musredit/PGetMusrFTOptionsDialog.cpp new file mode 100644 index 00000000..bf0d0b66 --- /dev/null +++ b/src/musredit_qt6/musredit/PGetMusrFTOptionsDialog.cpp @@ -0,0 +1,599 @@ +/**************************************************************************** + + PGetMusrFTOptionsDialog.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2009-2019 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 "PGetMusrFTOptionsDialog.h" + +#define MUSRFT_OPT_UNDEF 0 +#define MUSRFT_OPT_REAL 1 +#define MUSRFT_OPT_IMAG 2 +#define MUSRFT_OPT_REAL_AND_IMAG 3 +#define MUSRFT_OPT_POWER 4 +#define MUSRFT_OPT_PHASE 5 + +#define MUSRFT_APOD_UNDEF 0 +#define MUSRFT_APOD_WEAK 1 +#define MUSRFT_APOD_MEDIUM 2 +#define MUSRFT_APOD_STRONG 3 + +#define MUSRFT_UNIT_UNDEF 0 +#define MUSRFT_UNIT_GAUSS 1 +#define MUSRFT_UNIT_TESLA 2 +#define MUSRFT_UNIT_FREQ 3 +#define MUSRFT_UNIT_CYCLE 4 + +//---------------------------------------------------------------------------------------------------- +/** + *

Constructor. + * + * \param currentMsrFile path-file name of the currently active msr-file in musredit + * \param prevCmd list of the last (potential) previously call. + * \param helpUrl help url for the asymmetry run block + */ +PGetMusrFTOptionsDialog::PGetMusrFTOptionsDialog(QString currentMsrFile, QStringList &prevCmd, const QString helpUrl) : + fCurrentMsrFileName(currentMsrFile), fHelpUrl(helpUrl) +{ + setupUi(this); + setModal(true); + + fBkgRangeStartBin_lineEdit->setValidator( new QIntValidator(fBkgRangeStartBin_lineEdit) ); + fBkgRangeEndBin_lineEdit->setValidator( new QIntValidator(fBkgRangeEndBin_lineEdit) ); + fPacking_lineEdit->setValidator( new QIntValidator(fPacking_lineEdit) ); + fTimeRangeStart_lineEdit->setValidator( new QDoubleValidator(fTimeRangeStart_lineEdit) ); + fTimeRangeEnd_lineEdit->setValidator( new QDoubleValidator(fTimeRangeEnd_lineEdit) ); + fFourierPower_lineEdit->setValidator( new QIntValidator(fFourierPower_lineEdit) ); + fLifetimeCorrection_lineEdit->setValidator( new QDoubleValidator(fLifetimeCorrection_lineEdit) ); + fFourierRangeStart_lineEdit->setValidator( new QDoubleValidator(fFourierRangeStart_lineEdit) ); + fFourierRangeEnd_lineEdit->setValidator( new QDoubleValidator(fFourierRangeEnd_lineEdit) ); + fPacking_lineEdit->setText("1"); + + // populate dialog with the previous cmd call + bool msrTag = true; + QString str, str1, line; + int idx; + for (int i=0; isetText(line); + msrTag = false; + } + // collect data-file-names + if (prevCmd[i] == "-df") { + i++; + line = ""; + while (!prevCmd[i].startsWith("-") && (isetText(line); + } + // background-range + if (prevCmd[i] == "-br") { + fBkgRangeStartBin_lineEdit->setText(prevCmd[++i]); + fBkgRangeEndBin_lineEdit->setText(prevCmd[++i]); + } + // fourier-option + if (prevCmd[i] == "-fo") { + if (prevCmd[i+1] == "real") + fFourierOption_comboBox->setCurrentIndex(MUSRFT_OPT_REAL); + else if (prevCmd[i+1] == "imag") + fFourierOption_comboBox->setCurrentIndex(MUSRFT_OPT_IMAG); + else if (prevCmd[i+1] == "real+imag") + fFourierOption_comboBox->setCurrentIndex(MUSRFT_OPT_REAL_AND_IMAG); + else if (prevCmd[i+1] == "power") + fFourierOption_comboBox->setCurrentIndex(MUSRFT_OPT_POWER); + else if (prevCmd[i+1] == "phase") + fFourierOption_comboBox->setCurrentIndex(MUSRFT_OPT_PHASE); + else + fFourierOption_comboBox->setCurrentIndex(MUSRFT_OPT_UNDEF); + i++; + } + // apodization + if (prevCmd[i] == "-ap") { + if (prevCmd[i+1] == "weak") + fApodization_comboBox->setCurrentIndex(MUSRFT_APOD_WEAK); + else if (prevCmd[i+1] == "medium") + fApodization_comboBox->setCurrentIndex(MUSRFT_APOD_MEDIUM); + else if (prevCmd[i+1] == "strong") + fApodization_comboBox->setCurrentIndex(MUSRFT_APOD_STRONG); + else + fApodization_comboBox->setCurrentIndex(MUSRFT_APOD_UNDEF); + i++; + } + // fourier-power + if (prevCmd[i] == "-fp") { + fFourierPower_lineEdit->setText(prevCmd[++i]); + } + // units + if (prevCmd[i] == "-u") { + if (prevCmd[i+1] == "Gauss") + fFourierUnits_comboBox->setCurrentIndex(MUSRFT_UNIT_GAUSS); + else if (prevCmd[i+1] == "Tesla") + fFourierUnits_comboBox->setCurrentIndex(MUSRFT_UNIT_TESLA); + else if (prevCmd[i+1] == "MHz") + fFourierUnits_comboBox->setCurrentIndex(MUSRFT_UNIT_FREQ); + else if (prevCmd[i+1] == "Mc/s") + fFourierUnits_comboBox->setCurrentIndex(MUSRFT_UNIT_CYCLE); + else + fFourierUnits_comboBox->setCurrentIndex(MUSRFT_UNIT_UNDEF); + i++; + } + // phase + if (prevCmd[i] == "-ph") { + // NOT YET IMPLEMENTED + } + // fourier-range + if (prevCmd[i] == "-fr") { + fFourierRangeStart_lineEdit->setText(prevCmd[++i]); + fFourierRangeEnd_lineEdit->setText(prevCmd[++i]); + } + // time-range + if (prevCmd[i] == "-tr") { + fTimeRangeStart_lineEdit->setText(prevCmd[++i]); + fTimeRangeEnd_lineEdit->setText(prevCmd[++i]); + } + // histo list + if (prevCmd[i] == "--histo") { + i++; + line = ""; + while (!prevCmd[i].startsWith("-") && (isetText(line); + } + // average ALL tag + if (prevCmd[i] == "-a") { + fAveragedView_checkBox->setCheckState(Qt::Checked); + } + // average per data set tag + if (prevCmd[i] == "-ad") { + fAveragePerDataSet_checkBox->setCheckState(Qt::Checked); + } + // t0 list + if (prevCmd[i] == "--t0") { + i++; + line = ""; + while (!prevCmd[i].startsWith("-") && (isetText(line); + } + // packing + if (prevCmd[i] == "-pa") { + fPacking_lineEdit->setText(prevCmd[++i]); + } + // title + if (prevCmd[i] == "--title") { + fFourierTitle_lineEdit->setText(prevCmd[i+1]); + } + // create msr-file tag + if (prevCmd[i] == "--create-msr-file") { + fCreateMsrFileName = prevCmd[++i]; + fCreateMsrFile_checkBox->setCheckState(Qt::Checked); + } + // lifetime correction + if (prevCmd[i] == "-lc") { + fLifetimeCorrection_lineEdit->setText(prevCmd[++i]); + } + } + + // connect all necessary single and slots + connect(fCurrentMsrFile_checkBox, SIGNAL( stateChanged(int) ), this, SLOT( currentMsrFileTagChanged(int) ) ); + connect(fAllMsrFiles_checkBox, SIGNAL( stateChanged(int) ), this, SLOT( allMsrFileTagChanged(int) ) ); + connect(fMsrFileSelector_pushButton, SIGNAL( clicked() ), this, SLOT( selectMsrFileNames() ) ); + connect(fDataFileSelector_pushButton, SIGNAL( clicked() ), this, SLOT( selectDataFileNames() ) ); + connect(fCreateMsrFile_checkBox, SIGNAL( stateChanged(int) ), this, SLOT( createMsrFileChanged(int) ) ); + connect(fMsrFileNameClear_pushButton, SIGNAL (clicked() ), this, SLOT( clearMsrFileNames() ) ); + connect(fDataFileNameClear_pushButton, SIGNAL (clicked() ), this, SLOT( clearDataFileNames() ) ); + connect(fResetAll_pushButton, SIGNAL( clicked() ), this, SLOT( resetAll() ) ); + connect(fAveragedView_checkBox, SIGNAL ( stateChanged(int) ), this, SLOT( averagedAll(int) ) ); + connect(fAveragePerDataSet_checkBox, SIGNAL ( stateChanged(int) ), this, SLOT( averagedPerDataSet(int) ) ); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

returns the musrFT command line options. + */ +QStringList PGetMusrFTOptionsDialog::getMusrFTOptions() +{ + QStringList cmd; + QString str(""); + QStringList strList; + + // check if currently active msr-file shall be used + if (fCurrentMsrFile_checkBox->checkState() == Qt::Checked) { + cmd << fCurrentMsrFileName; + } else { + // msr-files + for (int i=0; i 0) { + cmd << "-df"; + for (int i=0; itext().length() > 0) && (fBkgRangeEndBin_lineEdit->text().length() > 0)) { + cmd << "-br"; + cmd << fBkgRangeStartBin_lineEdit->text(); + cmd << fBkgRangeEndBin_lineEdit->text(); + } + + // background values + if (fBkgList_lineEdit->text().length() > 0) { + + } + + // fourier-option + if (fFourierOption_comboBox->currentText() != "UnDef") { + cmd << "-fo"; + cmd << fFourierOption_comboBox->currentText(); + } + + // apodization + cmd << "-ap"; + cmd << fApodization_comboBox->currentText(); + + // fourier-power + if (fFourierPower_lineEdit->text().length() > 0) { + cmd << "-fp"; + cmd << fFourierPower_lineEdit->text(); + } + + // units + if (fFourierUnits_comboBox->currentText() != "UnDef") { + cmd << "-u"; + cmd << fFourierUnits_comboBox->currentText(); + } + + // phase + + // fourier-range + if ((fFourierRangeStart_lineEdit->text().length() > 0) && (fFourierRangeEnd_lineEdit->text().length() > 0)) { + cmd << "-fr"; + cmd << fFourierRangeStart_lineEdit->text(); + cmd << fFourierRangeEnd_lineEdit->text(); + } + + // time-range + if ((fTimeRangeStart_lineEdit->text().length() > 0) && (fTimeRangeEnd_lineEdit->text().length() > 0)) { + cmd << "-tr"; + cmd << fTimeRangeStart_lineEdit->text(); + cmd << fTimeRangeEnd_lineEdit->text(); + } + + // histo list + if (fHistoList_lineEdit->text().length() > 0) { + cmd << "--histo"; + strList = fHistoList_lineEdit->text().split(" ", Qt::SkipEmptyParts); + for (int i=0; icheckState() == Qt::Checked) + cmd << "-a"; + + // averaged view per data set + if (fAveragePerDataSet_checkBox->checkState() == Qt::Checked) + cmd << "-ad"; + + // t0 list + if (fT0_lineEdit->text().length() > 0) { + cmd << "--t0"; + strList = fT0_lineEdit->text().split(" ", Qt::SkipEmptyParts); + for (int i=0; itext().length() > 0) { + cmd << "-pa"; + cmd << fPacking_lineEdit->text(); + } + + // title + if (fFourierTitle_lineEdit->text().length() > 0) { + cmd << "--title"; + cmd << fFourierTitle_lineEdit->text(); + } + + // create-msr-file + if (fCreateMsrFile_checkBox->checkState() == Qt::Checked) { + cmd << "--create-msr-file"; + cmd << fCreateMsrFileName; + } + + // lifetimecorrection + if (fLifetimeCorrection_lineEdit->text().length() > 0) { + cmd << "-lc"; + cmd << fLifetimeCorrection_lineEdit->text(); + } + + return cmd; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT called when fCurrentMsrFile_checkBox is checked/unchecked. If checked, it will clean up + * the msr-file path-file list and the data-file path-file list. + */ +void PGetMusrFTOptionsDialog::currentMsrFileTagChanged(int state) +{ + if (state == Qt::Checked) { + fAllMsrFiles_checkBox->setCheckState(Qt::Unchecked); + + // remove all msr-data-file-names and data-path-file-names + fMsrFilePaths.clear(); + fMsrFileNames.clear(); + fMsrFileSelector_lineEdit->setText(""); + fDataFilePaths.clear(); + fDataFileNames.clear(); + fDataFileSelector_lineEdit->setText(""); + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT called when fAllMsrFiles_checkBox is checked/unchecked. Currently it has no functionality. + */ +void PGetMusrFTOptionsDialog::allMsrFileTagChanged(int state) +{ + if (state == Qt::Checked) { + fCurrentMsrFile_checkBox->setCheckState(Qt::Unchecked); + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT called when fMsrFileSelector_pushButton is clicked. Collects the msr-file path-name list. + */ +void PGetMusrFTOptionsDialog::selectMsrFileNames() +{ + QStringList flns = QFileDialog::getOpenFileNames( this, tr("Open msr-File(s)"), tr( "./" ), + tr( "msr-Files (*.msr);;All Files (*)" )); + + QString str(""), str1(""); + int idx; + if (flns.size() > 0) { + // delete already present elements + fMsrFilePaths.clear(); + fMsrFileNames.clear(); + + // split path-name into path and name + for (int i=0; isetText(str); + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT called when the fMsrFileNameClear_pushButton is clicked. + */ +void PGetMusrFTOptionsDialog::clearMsrFileNames() +{ + fMsrFileSelector_lineEdit->setText(""); + fMsrFilePaths.clear(); + fMsrFileNames.clear(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT called when fDataFileSelector_pushButton is clicked. Collects the data-file path-name list. + */ +void PGetMusrFTOptionsDialog::selectDataFileNames() +{ + QStringList flns = QFileDialog::getOpenFileNames( this, tr("Open msr-File(s)"), tr( "./" ), + tr( "data-Files (*.root *.bin *.msr *.nxs *.mdu);;All Files (*)" )); + + QString str(""), str1(""); + int idx; + if (flns.size() > 0) { + // delete already present elements + fDataFilePaths.clear(); + fDataFileNames.clear(); + + // split path-name into path and name + for (int i=0; isetText(str); + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT called when the fDataFileNameClear_pushButton is clicked. + */ +void PGetMusrFTOptionsDialog::clearDataFileNames() +{ + fDataFileSelector_lineEdit->setText(""); + fDataFilePaths.clear(); + fDataFileNames.clear(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT called when the create-msr-file tag has changed + */ +void PGetMusrFTOptionsDialog::createMsrFileChanged(int state) +{ + if (state == Qt::Checked) { + fCreateMsrFileName = QFileDialog::getSaveFileName(this, tr("Create msr-file"), "./", tr("msr-Files (*.msr);;All Files (*)")); + if (fCreateMsrFileName.length() == 0) + fCreateMsrFile_checkBox->setCheckState(Qt::Unchecked); + } else { + fCreateMsrFileName = ""; + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT called when the Reset All button is pressed. Will remove all settings. + */ +void PGetMusrFTOptionsDialog::resetAll() +{ + fCurrentMsrFile_checkBox->setCheckState(Qt::Unchecked); + fAllMsrFiles_checkBox->setCheckState(Qt::Unchecked); + fMsrFilePaths.clear(); + fMsrFileNames.clear(); + fMsrFileSelector_lineEdit->setText(""); + fDataFilePaths.clear(); + fDataFileNames.clear(); + fDataFileSelector_lineEdit->setText(""); + fBkgRangeStartBin_lineEdit->setText(""); + fBkgRangeEndBin_lineEdit->setText(""); + fBkgList_lineEdit->setText(""); + fApodization_comboBox->setCurrentIndex(MUSRFT_APOD_UNDEF); + fPacking_lineEdit->setText(""); + fTimeRangeStart_lineEdit->setText(""); + fTimeRangeEnd_lineEdit->setText(""); + fHistoList_lineEdit->setText(""); + fT0_lineEdit->setText(""); + fFourierOption_comboBox->setCurrentIndex(MUSRFT_OPT_UNDEF); + fFourierUnits_comboBox->setCurrentIndex(MUSRFT_UNIT_UNDEF); + fFourierPower_lineEdit->setText(""); + fLifetimeCorrection_lineEdit->setText(""); + fFourierRangeStart_lineEdit->setText(""); + fFourierRangeEnd_lineEdit->setText(""); + fAveragedView_checkBox->setCheckState(Qt::Unchecked); + fAveragePerDataSet_checkBox->setCheckState(Qt::Unchecked); + fCreateMsrFile_checkBox->setCheckState(Qt::Unchecked); + fFourierTitle_lineEdit->setText(""); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT called when averaged view for ALL data is checked. + */ +void PGetMusrFTOptionsDialog::averagedAll(int state) +{ + if ((state == Qt::Checked) && fAveragePerDataSet_checkBox->isChecked()) + fAveragePerDataSet_checkBox->setCheckState(Qt::Unchecked); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT called when averaged view per data set is checked. + */ +void PGetMusrFTOptionsDialog::averagedPerDataSet(int state) +{ + if ((state == Qt::Checked) && fAveragedView_checkBox->isChecked()) + fAveragedView_checkBox->setCheckState(Qt::Unchecked); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Generates a help content window showing the description for musrFT. + */ +void PGetMusrFTOptionsDialog::helpContent() +{ + if (fHelpUrl.isEmpty()) { + QMessageBox::information(this, "**INFO**", "Will eventually show a help window"); + } else { + bool ok = QDesktopServices::openUrl(QUrl(fHelpUrl, QUrl::TolerantMode)); + if (!ok) { + QString msg = QString("

Sorry: Couldn't open default web-browser for the help.
Please try: musrfit docu in your web-browser.").arg(fHelpUrl); + QMessageBox::critical( nullptr, + tr("Fatal Error"), + msg, + tr("Quit") ); + } + } +} diff --git a/src/musredit_qt6/musredit/PGetMusrFTOptionsDialog.h b/src/musredit_qt6/musredit/PGetMusrFTOptionsDialog.h new file mode 100644 index 00000000..bc2d5421 --- /dev/null +++ b/src/musredit_qt6/musredit/PGetMusrFTOptionsDialog.h @@ -0,0 +1,71 @@ +/**************************************************************************** + + PGetMusrFTOptionsDialog.h + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2010-2019 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. * + ***************************************************************************/ + +#ifndef _PGETMUSRFTOPTIONSDIALOG_H_ +#define _PGETMUSRFTOPTIONSDIALOG_H_ + +#include +#include + +#include "ui_PGetMusrFTOptionsDialog.h" + +class PGetMusrFTOptionsDialog : public QDialog, private Ui::PGetMusrFTOptionsDialog +{ + Q_OBJECT + + public: + PGetMusrFTOptionsDialog(QString currentMsrFile, QStringList &prevCmd, const QString helpUrl); + QStringList getMusrFTOptions(); + + public slots: + void helpContent(); + + private slots: + void currentMsrFileTagChanged(int state); + void allMsrFileTagChanged(int state); + void selectMsrFileNames(); + void clearMsrFileNames(); + void selectDataFileNames(); + void clearDataFileNames(); + void createMsrFileChanged(int state); + void resetAll(); + void averagedAll(int state); + void averagedPerDataSet(int state); + + private: + QStringList fMsrFilePaths; ///< list keeping all the paths from the msr-file path-name list + QStringList fMsrFileNames; ///< list keeping all the names from the msr-file path-name list + QStringList fDataFilePaths; ///< list keeping all the paths from the data-file path-name list + QStringList fDataFileNames; ///< list keeping all the names from the data-file path-name list + QString fCreateMsrFileName; ///< keeps the msr-path-file name for msr-file creation + QString fCurrentMsrFileName; ///< keeps the msr-path-file name of the currently active msr-file in musredit. + QString fHelpUrl; ///< help url for the asymmetry run block +}; + +#endif // _PGETMUSRFTOPTIONSDIALOG_H_ diff --git a/src/musredit_qt6/musredit/PGetNonMusrRunBlockDialog.cpp b/src/musredit_qt6/musredit/PGetNonMusrRunBlockDialog.cpp new file mode 100644 index 00000000..4e91478c --- /dev/null +++ b/src/musredit_qt6/musredit/PGetNonMusrRunBlockDialog.cpp @@ -0,0 +1,173 @@ +/**************************************************************************** + + PGetNonMusrRunBlockDialog.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2009-2019 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 "PGetNonMusrRunBlockDialog.h" + +//---------------------------------------------------------------------------------------------------- +/** + *

Constructor + * + * \param helpUrl help url for the NonMusr run block. + */ +PGetNonMusrRunBlockDialog::PGetNonMusrRunBlockDialog(const QString helpUrl) : fHelpUrl(helpUrl) +{ + setupUi(this); + + setModal(true); + + fFitRangeStart_lineEdit->setValidator( new QDoubleValidator(fFitRangeStart_lineEdit) ); + fFitRangeEnd_lineEdit->setValidator( new QDoubleValidator(fFitRangeEnd_lineEdit) ); + + int idx = -1; + for (int i=0; icount(); i++) { + if (fFileFormat_comboBox->itemText(i) == "DB") { + idx = i; + break; + } + } + if (idx >= 0) { + fFileFormat_comboBox->setCurrentIndex(idx); + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Extracts the run header information from the dialog, and returns it as a string. + */ +QString PGetNonMusrRunBlockDialog::getRunHeaderInfo() +{ + QString str; + + str = "RUN " + fRunFileName_lineEdit->text() + " "; + str += fBeamline_lineEdit->text().toUpper() + " "; + str += fInstitute_comboBox->currentText() + " "; + str += fFileFormat_comboBox->currentText() + " (name beamline institute data-file-format)\n"; + + return str; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Extracts the map from the dialog, and returns it as a string. + * + * \param valid flag indicating of the map is potentially being valid. + */ +QString PGetNonMusrRunBlockDialog::getMap(bool &valid) +{ + QString str = fMap_lineEdit->text().trimmed().remove(" "); + + // check if potentially proper map line + for (int i=0; itext() + "\n"; + + return str; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Extracts xy-data from the dialog and returns it as a string. + * + * \param valid flag showing that x/y-data are present. + */ +QString PGetNonMusrRunBlockDialog::getXYData(bool &valid) +{ + QString str = ""; + + if (fXData_lineEdit->text().isEmpty() || fYData_lineEdit->text().isEmpty()) { + valid = false; + } else { + str = "xy-data "; + str += fXData_lineEdit->text() + " "; + str += fYData_lineEdit->text() + "\n"; + valid = true; + } + + return str; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Extracts the fit-range from the dialog and returns it as a string. If not fit-range was given, + * a fit-range from 0 to 10 us will be returned and the valid flag will be set to false. + * + * \param valid flag showing if a fit-range is given. + */ +QString PGetNonMusrRunBlockDialog::getFitRange(bool &valid) +{ + QString str = ""; + + if (fFitRangeStart_lineEdit->text().isEmpty() || fFitRangeEnd_lineEdit->text().isEmpty()) { + str += "fit 0.0 10.0\n"; + valid = false; + } else { + str += "fit "; + str += fFitRangeStart_lineEdit->text() + " "; + str += fFitRangeEnd_lineEdit->text() + "\n"; + valid = true; + } + + return str; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Generates a help content window showing the description of the NonMusr run block. + */ +void PGetNonMusrRunBlockDialog::helpContent() +{ + if (fHelpUrl.isEmpty()) { + QMessageBox::information(this, "**INFO**", "Will eventually show a help window"); + } else { + bool ok = QDesktopServices::openUrl(QUrl(fHelpUrl, QUrl::TolerantMode)); + if (!ok) { + QString msg = QString("

Sorry: Couldn't open default web-browser for the help.
Please try: musrfit docu in your web-browser.").arg(fHelpUrl); + QMessageBox::critical( nullptr, + tr("Fatal Error"), + msg, + tr("Quit") ); + } + } +} + +//---------------------------------------------------------------------------------------------------- +// END +//---------------------------------------------------------------------------------------------------- diff --git a/src/musredit_qt6/musredit/PGetNonMusrRunBlockDialog.h b/src/musredit_qt6/musredit/PGetNonMusrRunBlockDialog.h new file mode 100644 index 00000000..9ed00d9f --- /dev/null +++ b/src/musredit_qt6/musredit/PGetNonMusrRunBlockDialog.h @@ -0,0 +1,58 @@ +/**************************************************************************** + + PGetNonMusrRunBlockDialog.h + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2009-2019 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. * + ***************************************************************************/ + +#ifndef _PGETNONMUSRRUNBLOCKDIALOG_H_ +#define _PGETNONMUSRRUNBLOCKDIALOG_H_ + +#include "ui_PGetNonMusrRunBlockDialog.h" + +//------------------------------------------------------------------------------------- +/** + *

Handles the content of the NonMusr run block dialog. + */ +class PGetNonMusrRunBlockDialog : public QDialog, private Ui::PGetNonMusrRunBlockDialog +{ + Q_OBJECT + + public: + PGetNonMusrRunBlockDialog(const QString helpUrl = ""); + + QString getRunHeaderInfo(); + QString getMap(bool &valid); + QString getXYData(bool &valid); + QString getFitRange(bool &valid); + + private slots: + void helpContent(); + + private: + QString fHelpUrl; ///< help url address for the NonMusr run block. +}; + +#endif // _PGETNONMUSRRUNBLOCKDIALOG_H_ diff --git a/src/musredit_qt6/musredit/PGetParameterBlockDialog.cpp b/src/musredit_qt6/musredit/PGetParameterBlockDialog.cpp new file mode 100644 index 00000000..5e986ebb --- /dev/null +++ b/src/musredit_qt6/musredit/PGetParameterBlockDialog.cpp @@ -0,0 +1,236 @@ +/**************************************************************************** + + PGetParameterBlockDialog.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2009-2019 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 "PGetParameterBlockDialog.h" + +//---------------------------------------------------------------------------------------------------- +/** + *

Constructor. + * + * \param helpUrl help url of the PARAMETER block. + */ +PGetParameterBlockDialog::PGetParameterBlockDialog(const QString helpUrl) : fHelpUrl(helpUrl) +{ + setupUi(this); + + setModal(true); + + // setup event filter + installEventFilter(this); + + fValue_lineEdit->setValidator( new QDoubleValidator(fValue_lineEdit) ); + fStep_lineEdit->setValidator( new QDoubleValidator(fStep_lineEdit) ); + + fParam_plainTextEdit->setFont(QFont("Courier", 10)); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

This event filter is filtering out the return key, and if present adds the current parameters + * to the parameter list. + * + * \param obj object which was generating the event. + * \param ev event of the object. + */ +bool PGetParameterBlockDialog::eventFilter( QObject *obj, QEvent *ev ) +{ + if (obj == this) { + if (ev->type() == QEvent::KeyPress) { + QKeyEvent *k = (QKeyEvent*)ev; + if (k->key() == Qt::Key_Return) { + paramAdd(); + return true; + } else { + return false; + } + } else { + return false; + } + } else { + return false; + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Adds a parameter to the text edit window. + */ +void PGetParameterBlockDialog::paramAdd() +{ + QString param, str, spaces; + + // get No + str = fParamNo_spinBox->text(); + if (str.toInt() < 10) + param = " " + str + " "; + else + param = " " + str + " "; + + // get name + str = fName_lineEdit->text(); + if (str.isEmpty()) { + QMessageBox::critical(this, "**ERROR**", + "empty parameter name not allowed!", + QMessageBox::Ok, QMessageBox::NoButton); + return; + } else { + param += str; + if (str.length() < 13) + param += spaces.fill(' ', 13-str.length()); + else + param += " "; + } + + // get value + str = fValue_lineEdit->text(); + if (str.isEmpty()) { + QMessageBox::critical(this, "**ERROR**", + "empty parameter value not allowed!", + QMessageBox::Ok, QMessageBox::NoButton); + return; + } else { + param += str; + if (str.length() < 10) + param += spaces.fill(' ', 10-str.length()); + else + param += " "; + } + + // get step + str = fStep_lineEdit->text(); + if (str.isEmpty()) { + QMessageBox::critical(this, "**ERROR**", + "empty parameter step not allowed!", + QMessageBox::Ok, QMessageBox::NoButton); + return; + } else { + param += str; + if (str.length() < 10) + param += spaces.fill(' ', 10-str.length()); + else + param += " "; + } + + // add positive error none + param += "none "; + + if ((fLower_lineEdit->text() != "none") || (fUpper_lineEdit->text() != "none")) { + // get lower boundary + str = fLower_lineEdit->text(); + bool ok; + double val = str.toDouble(&ok); + if (!ok && (str != "none")) { + QMessageBox::critical(this, "**ERROR**", + "invalid lower boundary! Must be a double are the key word 'none'", + QMessageBox::Ok, QMessageBox::NoButton); + return; + } else { + param += str; + if (str.length() < 10) + param += spaces.fill(' ', 10-str.length()); + else + param += " "; + } + + // get upper boundary + str = fUpper_lineEdit->text(); + val = str.toDouble(&ok); + if (!ok && (str != "none")) { + QMessageBox::critical(this, "**ERROR**", + "invalid upper boundary! Must be a double are the key word 'none'", + QMessageBox::Ok, QMessageBox::NoButton); + return; + } else { + param += str; + if (str.length() < 10) + param += spaces.fill(' ', 10-str.length()); + else + param += " "; + } + } + +// param += "\n"; + + // write parameter string into fParam_textEdit + fParam_plainTextEdit->appendPlainText(param); + + // increment No counter in spinBox + fParamNo_spinBox->stepUp(); + + // reset name lineEdit + fName_lineEdit->setText(""); + + // reset value lineEdit + fValue_lineEdit->setText(""); + + // reset step lineEdit + fStep_lineEdit->setText(""); + + // reset lower boundary lineEdit + fLower_lineEdit->setText("none"); + + // reset upper boundary lineEdit + fUpper_lineEdit->setText("none"); + + fName_lineEdit->setFocus(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Generates a help content window showing the description of the FITPARAMETER block. + */ +void PGetParameterBlockDialog::helpContent() +{ + if (fHelpUrl.isEmpty()) { + QMessageBox::information(this, "**INFO**", "Will eventually show a help window"); + } else { + bool ok = QDesktopServices::openUrl(QUrl(fHelpUrl, QUrl::TolerantMode)); + if (!ok) { + QString msg = QString("

Sorry: Couldn't open default web-browser for the help.
Please try: musrfit docu in your web-browser.").arg(fHelpUrl); + QMessageBox::critical( nullptr, + tr("Fatal Error"), + msg, + tr("Quit") ); + } + } +} + +//---------------------------------------------------------------------------------------------------- +// END +//---------------------------------------------------------------------------------------------------- diff --git a/src/musredit_qt6/musredit/PGetParameterBlockDialog.h b/src/musredit_qt6/musredit/PGetParameterBlockDialog.h new file mode 100644 index 00000000..6e235bef --- /dev/null +++ b/src/musredit_qt6/musredit/PGetParameterBlockDialog.h @@ -0,0 +1,59 @@ +/**************************************************************************** + + PGetParameterBlockDialog.h + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2009-2019 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. * + ***************************************************************************/ + +#ifndef _PGETPARAMETERBLOCKDIALOG_H_ +#define _PGETPARAMETERBLOCKDIALOG_H_ + +#include "ui_PGetParameterBlockDialog.h" + +//----------------------------------------------------------------------------------- +/** + *

Handles the content of the PARAMETER block dialog. + */ +class PGetParameterBlockDialog : public QDialog, private Ui::PGetParameterBlockDialog +{ + Q_OBJECT + + public: + PGetParameterBlockDialog(const QString helpUrl); + + QString getParams() { return fParam_plainTextEdit->toPlainText(); } + + protected: + bool eventFilter( QObject *obj, QEvent *ev ); + + private slots: + void paramAdd(); + void helpContent(); + + private: + QString fHelpUrl; ///< help url of the PARAMETER block description. +}; + +#endif // _PGETPARAMETERBLOCKDIALOG_H_ diff --git a/src/musredit_qt6/musredit/PGetPlotBlockDialog.cpp b/src/musredit_qt6/musredit/PGetPlotBlockDialog.cpp new file mode 100644 index 00000000..128f3a64 --- /dev/null +++ b/src/musredit_qt6/musredit/PGetPlotBlockDialog.cpp @@ -0,0 +1,203 @@ +/**************************************************************************** + + PGetPlotBlockDialog.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2009-2019 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 "PGetPlotBlockDialog.h" + +//---------------------------------------------------------------------------------------------------- +/** + *

Constructor. + * + * \param helpUrl help url for the PLOT block. + */ +PGetPlotBlockDialog::PGetPlotBlockDialog(const QString helpUrl) : fHelpUrl(helpUrl) +{ + setupUi(this); + + setModal(true); + + // setup event filter + installEventFilter(this); + + fXRangeLow_lineEdit->setValidator( new QDoubleValidator(fXRangeLow_lineEdit) ); + fXRangeUp_lineEdit->setValidator( new QDoubleValidator(fXRangeUp_lineEdit) ); + fYRangeLow_lineEdit->setValidator( new QDoubleValidator(fYRangeLow_lineEdit) ); + fYRangeUp_lineEdit->setValidator( new QDoubleValidator(fYRangeUp_lineEdit) ); + + fPlot_plainTextEdit->setFont(QFont("Courier", 10)); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Extracts the information of the top part of the dialog, constructs a msr-file PLOT block and + * writes it into the text edit window. + */ +void PGetPlotBlockDialog::addPlot() +{ + QString param = ""; + QString str = ""; + QString spaces; + + // add begining of plot block if fPlot_plainTextEdit is still empty + if (fPlot_plainTextEdit->toPlainText().isEmpty()) { + param = "###############################################################\n"; + } + + // write type + param += "PLOT "; + if (fType_comboBox->currentText() == "Single Histo") { + param += "0 (single histo plot)\n"; + } else if (fType_comboBox->currentText() == "Asymmetry") { + param += "2 (asymmetry plot)\n"; + } else if (fType_comboBox->currentText() == "MuMinus") { + param += "4 (mu minus plot)\n"; + } else if (fType_comboBox->currentText() == "NonMusr") { + param += "8 (non muSR plot)\n"; + } + + // write runs + param += "runs " + fRunList_lineEdit->text() + "\n"; + + // write range + param += "range "; + // lower x-/time range + str = fXRangeLow_lineEdit->text(); + if (str.isEmpty()) { + QMessageBox::critical(this, "**ERROR**", + "empty lower time-/x-range name not allowed!", + QMessageBox::Ok, QMessageBox::NoButton); + return; + } + param += str; + if (str.length() < 8) + param += spaces.fill(' ', 8 - str.length()); + else + param += " "; + + // upper x-/time range + str = fXRangeUp_lineEdit->text(); + if (str.isEmpty()) { + QMessageBox::critical(this, "**ERROR**", + "empty upper time-/x-range name not allowed!", + QMessageBox::Ok, QMessageBox::NoButton); + return; + } + param += str; + if (str.length() < 8) + param += spaces.fill(' ', 8 - str.length()); + else + param += " "; + + // check y-range: either none given or both + if ((fYRangeLow_lineEdit->text().isEmpty() && !fYRangeUp_lineEdit->text().isEmpty()) || + (!fYRangeLow_lineEdit->text().isEmpty() && fYRangeUp_lineEdit->text().isEmpty())) { + QMessageBox::critical(this, "**ERROR**", + "Only fully empty y-range, or give lower AND upper y-range is acceptable!\n Will ignore the y-range", + QMessageBox::Ok, QMessageBox::NoButton); + } else if (!fYRangeLow_lineEdit->text().isEmpty() && !fYRangeUp_lineEdit->text().isEmpty()) { + str = fYRangeLow_lineEdit->text(); + param += str; + if (str.length() < 8) + param += spaces.fill(' ', 8 - str.length()); + else + param += " "; + param += fYRangeUp_lineEdit->text() + "\n"; + } else { + param += "\n"; + } + param += "\n"; + + fPlot_plainTextEdit->appendPlainText(param); + + // clean input + fRunList_lineEdit->clear(); + fXRangeLow_lineEdit->clear(); + fXRangeUp_lineEdit->clear(); + fYRangeLow_lineEdit->clear(); + fYRangeUp_lineEdit->clear(); + fRunList_lineEdit->setFocus(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Generates a help content window showing the description of the PLOT block. + */ +void PGetPlotBlockDialog::helpContent() +{ + if (fHelpUrl.isEmpty()) { + QMessageBox::information(this, "**INFO**", "Will eventually show a help window"); + } else { + bool ok = QDesktopServices::openUrl(QUrl(fHelpUrl, QUrl::TolerantMode)); + if (!ok) { + QString msg = QString("

Sorry: Couldn't open default web-browser for the help.
Please try: musrfit docu in your web-browser.").arg(fHelpUrl); + QMessageBox::critical( nullptr, + tr("Fatal Error"), + msg, + tr("Quit") ); + } + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

This event filter is filtering out the return key, and if present adds the current plot. + * + * \param obj object which is triggering the event + * \param ev the triggered event + */ +bool PGetPlotBlockDialog::eventFilter( QObject *obj, QEvent *ev ) +{ + if (obj == this) { + if (ev->type() == QEvent::KeyPress) { + QKeyEvent *k = (QKeyEvent*)ev; + if (k->key() == Qt::Key_Return) { + addPlot(); + return true; + } else { + return false; + } + } else { + return false; + } + } else { + return false; + } +} + +//---------------------------------------------------------------------------------------------------- +// END +//---------------------------------------------------------------------------------------------------- diff --git a/src/musredit_qt6/musredit/PGetPlotBlockDialog.h b/src/musredit_qt6/musredit/PGetPlotBlockDialog.h new file mode 100644 index 00000000..ba545cb9 --- /dev/null +++ b/src/musredit_qt6/musredit/PGetPlotBlockDialog.h @@ -0,0 +1,59 @@ +/**************************************************************************** + + PGetPlotBlockDialog.h + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2009-2019 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. * + ***************************************************************************/ + +#ifndef _PGETPLOTBLOCKDIALOG_H_ +#define _PGETPLOTBLOCKDIALOG_H_ + +#include "ui_PGetPlotBlockDialog.h" + +//-------------------------------------------------------------------------- +/** + *

Handels content of the PLOT block dialog. + */ +class PGetPlotBlockDialog : public QDialog, private Ui::PGetPlotBlockDialog +{ + Q_OBJECT + + public: + PGetPlotBlockDialog(const QString helpUrl); + + QString getPlotBlock() { return fPlot_plainTextEdit->toPlainText(); } + + public slots: + void addPlot(); + void helpContent(); + + protected: + bool eventFilter( QObject *obj, QEvent *ev ); + + private: + QString fHelpUrl; ///< help url for the PLOT block +}; + +#endif // _PGETPLOTBLOCKDIALOG_H_ diff --git a/src/musredit_qt6/musredit/PGetSingleHistoRunBlockDialog.cpp b/src/musredit_qt6/musredit/PGetSingleHistoRunBlockDialog.cpp new file mode 100644 index 00000000..54a65a98 --- /dev/null +++ b/src/musredit_qt6/musredit/PGetSingleHistoRunBlockDialog.cpp @@ -0,0 +1,299 @@ +/**************************************************************************** + + PGetSingleHistoRunBlockDialog.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2009-2019 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 "PGetSingleHistoRunBlockDialog.h" + +//---------------------------------------------------------------------------------------------------- +/** + *

Constructor. + * + * \param helpUrl help url for the asymmetry run block + * \param lifetimeCorrection flag indicating if lifetime correction shall be enabled. + */ +PGetSingleHistoRunBlockDialog::PGetSingleHistoRunBlockDialog(const QString helpUrl, + const bool lifetimeCorrection) : fHelpUrl(helpUrl) +{ + setupUi(this); + + setModal(true); + + fForwardHistoNo_lineEdit->setValidator( new QIntValidator(fForwardHistoNo_lineEdit) ); + fNorm_lineEdit->setValidator( new QIntValidator(fNorm_lineEdit) ); + fDataStart_lineEdit->setValidator( new QIntValidator(fDataStart_lineEdit) ); + fDataEnd_lineEdit->setValidator( new QIntValidator(fDataEnd_lineEdit) ); + fBackgroundFix_lineEdit->setValidator( new QDoubleValidator(fBackgroundFix_lineEdit) ); + fBackgroundFit_lineEdit->setValidator( new QIntValidator(fBackgroundFit_lineEdit) ); + fBackgroundStart_lineEdit->setValidator( new QIntValidator(fBackgroundStart_lineEdit) ); + fBackgroundEnd_lineEdit->setValidator( new QIntValidator(fBackgroundEnd_lineEdit) ); + fFitRangeStart_lineEdit->setValidator( new QDoubleValidator(fFitRangeStart_lineEdit) ); + fFitRangeEnd_lineEdit->setValidator( new QDoubleValidator(fFitRangeEnd_lineEdit) ); + fPacking_lineEdit->setValidator( new QIntValidator(fPacking_lineEdit) ); + fT0_lineEdit->setValidator( new QIntValidator(fT0_lineEdit) ); + fLifetime_lineEdit->setValidator( new QIntValidator(fLifetime_lineEdit) ); + fLifetimeCorrection_checkBox->setChecked(lifetimeCorrection); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

returns the run information line of the single histogram run block. + */ +QString PGetSingleHistoRunBlockDialog::getRunHeaderInfo() +{ + QString str=""; + + str = "RUN " + fRunFileName_lineEdit->text() + " "; + str += fBeamline_lineEdit->text().toUpper() + " "; + str += fInstitute_comboBox->currentText() + " "; + str += fFileFormat_comboBox->currentText() + " (name beamline institute data-file-format)\n"; + + return str; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

returns the map for the single histogram run block. + * + * \param valid flag indicating if the map is potentially valid. + */ +QString PGetSingleHistoRunBlockDialog::getMap(bool &valid) +{ + QString str = fMap_lineEdit->text().trimmed().remove(" "); + + // check if potentially proper map line + for (int i=0; itext() + "\n"; + + return str; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

returns a data range (in bins) entry for the single histogram run block. + * + * \param valid flag indicating if the data entries are valid. + */ +QString PGetSingleHistoRunBlockDialog::getData(bool &valid) +{ + QString str=""; + + if (fDataStart_lineEdit->text().isEmpty() || fDataEnd_lineEdit->text().isEmpty()) { + valid = false; + } else { + str = "data "; + str += fDataStart_lineEdit->text() + " "; + str += fDataEnd_lineEdit->text() + "\n"; + valid = true; + } + + return str; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

returns the background information for the single histogram run block. + * + * \param valid flag indicating if a valid background (either backgr.fix, background, or backgr.fit is given, but only one) + * is present. + */ +QString PGetSingleHistoRunBlockDialog::getBackground(bool &valid) +{ + QString str=""; + + valid = true; + + // check that either backgr.fix or background is given, but not both + if (fBackgroundStart_lineEdit->text().isEmpty() && fBackgroundEnd_lineEdit->text().isEmpty() && + fBackgroundFix_lineEdit->text().isEmpty() && + fBackgroundFit_lineEdit->text().isEmpty()) { + valid = false; + str = "background 0 10\n"; + } else { + if (!fBackgroundStart_lineEdit->text().isEmpty()) { // assume the rest is given, not fool prove but ... + str = "background "; + str += fBackgroundStart_lineEdit->text() + " "; + str += fBackgroundEnd_lineEdit->text() + "\n"; + } + if (!fBackgroundFix_lineEdit->text().isEmpty()) { + str = "backgr.fix "; + str += fBackgroundFix_lineEdit->text() + "\n"; + } + if (!fBackgroundFit_lineEdit->text().isEmpty()) { + str = "backgr.fit "; + str += fBackgroundFit_lineEdit->text() + "\n"; + } + } + + return str; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

returns a fit range entry for the single histogram run block. If no fit range has been provided, + * a fit range [0,10] will be set and the valid flag will be set to false. + * + * \param valid flag indicating if a fit range was provided. + */ +QString PGetSingleHistoRunBlockDialog::getFitRange(bool &valid) +{ + QString str=""; + + if (fFitRangeStart_lineEdit->text().isEmpty() || fFitRangeEnd_lineEdit->text().isEmpty()) { + str += "fit 0.0 10.0\n"; + valid = false; + } else { + str += "fit "; + str += fFitRangeStart_lineEdit->text() + " "; + str += fFitRangeEnd_lineEdit->text() + "\n"; + valid = true; + } + + return str; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

returns the packing/binning of the single histogram run block. If no packing has been provided, + * a packing of '1' will be set and the present flag will be set to false. + * + * \param present flag indicating if a packing parameter was provided. + */ +QString PGetSingleHistoRunBlockDialog::getPacking(bool &present) +{ + QString str=""; + + if (fPacking_lineEdit->text().isEmpty()) { + present = false; + str += "packing 1\n"; + } else { + present = true; + str += "packing " + fPacking_lineEdit->text() + "\n\n"; + } + + return str; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

returns a t0 parameter for the single histogram run block. + * + * \param present flag indicating if a t0 parameter is set. + */ +QString PGetSingleHistoRunBlockDialog::getT0(bool &present) +{ + QString str=""; + + if (!fT0_lineEdit->text().isEmpty()) { + str = "t0 "; + str += fT0_lineEdit->text() + "\n"; + present = true; + } else { + present = false; + } + + return str; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

returns the muon lifetime parameter if present. + * + * \param present flag indicating if a muon life time parameter has been present. + */ +QString PGetSingleHistoRunBlockDialog::getMuonLifetimeParam(bool &present) +{ + QString str=""; + + if (!fLifetime_lineEdit->text().isEmpty()) { + str = "lifetime "; + str += fLifetime_lineEdit->text() + "\n"; + present = true; + } else { + present = false; + } + + return str; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

returns the lifetime correction flag. + * + * \param present flag showing if the lifetime correction flag should be set. + */ +QString PGetSingleHistoRunBlockDialog::getLifetimeCorrection(bool &present) +{ + QString str=""; + + if (fLifetimeCorrection_checkBox->isChecked()) { + str = "lifetimecorrection\n"; + present = true; + } else { + present = false; + } + + return str; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Generates a help content window showing the description of the single histogram run block. + */ +void PGetSingleHistoRunBlockDialog::helpContent() +{ + if (fHelpUrl.isEmpty()) { + QMessageBox::information(this, "**INFO**", "Will eventually show a help window"); + } else { + bool ok = QDesktopServices::openUrl(QUrl(fHelpUrl, QUrl::TolerantMode)); + if (!ok) { + QString msg = QString("

Sorry: Couldn't open default web-browser for the help.
Please try: musrfit docu in your web-browser.").arg(fHelpUrl); + QMessageBox::critical( nullptr, + tr("Fatal Error"), + msg, + tr("Quit") ); + } + } +} + +//---------------------------------------------------------------------------------------------------- +// END +//---------------------------------------------------------------------------------------------------- diff --git a/src/musredit_qt6/musredit/PGetSingleHistoRunBlockDialog.h b/src/musredit_qt6/musredit/PGetSingleHistoRunBlockDialog.h new file mode 100644 index 00000000..5b2701a3 --- /dev/null +++ b/src/musredit_qt6/musredit/PGetSingleHistoRunBlockDialog.h @@ -0,0 +1,68 @@ +/**************************************************************************** + + PGetSingleHistoRunBlockDialog.h + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2009-2019 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. * + ***************************************************************************/ + +#ifndef _PGETSINGLEHISTORUNBLOCKDIALOG_H_ +#define _PGETSINGLEHISTORUNBLOCKDIALOG_H_ + +#include +#include + +#include "ui_PGetSingleHistoRunBlockDialog.h" + +//-------------------------------------------------------------------------- +/** + *

Class handling the content of the menu: Edit/Add Block/Single Histo Run Block. + */ +class PGetSingleHistoRunBlockDialog : public QDialog, private Ui::PGetSingleHistoRunBlockDialog +{ + Q_OBJECT + + public: + PGetSingleHistoRunBlockDialog(const QString helpUrl = "", const bool lifetimeCorrection = true); + + QString getRunHeaderInfo(); + QString getMap(bool &valid); + QString getForward() { return QString("forward " + fForwardHistoNo_lineEdit->text() + "\n"); } + QString getNorm() { return QString("norm " + fNorm_lineEdit->text() + "\n"); } + QString getData(bool &valid); + QString getBackground(bool &valid); + QString getFitRange(bool &valid); + QString getPacking(bool &present); + QString getT0(bool &present); + QString getMuonLifetimeParam(bool &present); + QString getLifetimeCorrection(bool &present); + + private slots: + void helpContent(); + + private: + QString fHelpUrl; ///< help url for the asymmetry run block +}; + +#endif // _PGETSINGLEHISTORUNBLOCKDIALOG_H_ diff --git a/src/musredit_qt6/musredit/PGetTheoryBlockDialog.cpp b/src/musredit_qt6/musredit/PGetTheoryBlockDialog.cpp new file mode 100644 index 00000000..d6bf5f3b --- /dev/null +++ b/src/musredit_qt6/musredit/PGetTheoryBlockDialog.cpp @@ -0,0 +1,143 @@ +/**************************************************************************** + + PGetTheoryBlockDialog.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2009-2019 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 "PGetTheoryBlockDialog.h" + +//---------------------------------------------------------------------------------------------------- +/** + *

Constructor. + * + * \param admin pointer to the administration class object needed to extract the default theory set informations. + * \param helpUrl help url for the asymmetry run block + */ +PGetTheoryBlockDialog::PGetTheoryBlockDialog(PAdmin *admin, const QString helpUrl) : + fAdmin(admin), + fHelpUrl(helpUrl) +{ + setupUi(this); + + setModal(true); + + // feed theory function combo box + fTheoryFunction_comboBox->setIconSize(QSize(250, 20)); + PTheory *theoItem; + QIcon *icon; + QString iconName; + for (unsigned int i=0; igetTheoryCounts(); i++) { + theoItem = fAdmin->getTheoryItem(i); + if (theoItem->pixmapName.length() > 0) { + iconName = QString(":/latex_images/") + theoItem->pixmapName; + icon = new QIcon(QPixmap(iconName)); + fTheoryFunction_comboBox->insertItem(i, *icon, theoItem->label); + } else { + fTheoryFunction_comboBox->insertItem(i, theoItem->label); + } + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

returns the theory function string of the currently selected theory function. + */ +QString PGetTheoryBlockDialog::getTheoFuncString() +{ + QString str = "????"; + int idx = fTheoryFunction_comboBox->currentIndex(); + PTheory *theoItem = fAdmin->getTheoryItem(idx); + if (theoItem == 0) + return str; + + // add theory function name + str = theoItem->name + " "; + if (theoItem->name == "userFcn") { + str += "libMyLibrary.so TMyFunction "; + } + // add pseudo parameters + for (int i=0; iparams; i++) { + str += QString("%1").arg(i+1) + " "; + } + // add comment + str += theoItem->comment; + + return str; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

adds the current theory function to the text field and additionally adds a '+'. + */ +void PGetTheoryBlockDialog::addPlus() +{ + QString str = getTheoFuncString() + "\n+"; + fTheoryBlock_plainTextEdit->appendPlainText(str); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

adds the current theory function to the text field (newline == '*'). + */ +void PGetTheoryBlockDialog::addMultiply() +{ + QString str = getTheoFuncString(); + fTheoryBlock_plainTextEdit->appendPlainText(str); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Generates a help content window showing the description of the theory block. + */ +void PGetTheoryBlockDialog::helpContent() +{ + if (fHelpUrl.isEmpty()) { + QMessageBox::information(this, "**INFO**", "Will eventually show a help window"); + } else { + bool ok = QDesktopServices::openUrl(QUrl(fHelpUrl, QUrl::TolerantMode)); + if (!ok) { + QString msg = QString("

Sorry: Couldn't open default web-browser for the help.
Please try: musrfit docu in your web-browser.").arg(fHelpUrl); + QMessageBox::critical( nullptr, + tr("Fatal Error"), + msg, + tr("Quit") ); + } + } +} + +//---------------------------------------------------------------------------------------------------- +// END +//---------------------------------------------------------------------------------------------------- diff --git a/src/musredit_qt6/musredit/PGetTheoryBlockDialog.h b/src/musredit_qt6/musredit/PGetTheoryBlockDialog.h new file mode 100644 index 00000000..f6d3c2d8 --- /dev/null +++ b/src/musredit_qt6/musredit/PGetTheoryBlockDialog.h @@ -0,0 +1,60 @@ +/**************************************************************************** + + PGetTheoryBlockDialog.h + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2009-2019 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. * + ***************************************************************************/ + +#ifndef _PGETTHEORYBLOCKDIALOG_H_ +#define _PGETTHEORYBLOCKDIALOG_H_ + +#include "PAdmin.h" +#include "ui_PGetTheoryBlockDialog.h" + +//----------------------------------------------------------------------------- +/** + *

Class handling the content of the menu: Edit/Add Block/Theory Block. + */ +class PGetTheoryBlockDialog : public QDialog, private Ui::PGetTheoryBlockDialog +{ + Q_OBJECT + + public: + PGetTheoryBlockDialog(PAdmin *admin = 0, const QString helpUrl = ""); + + QString getTheoryBlock() { return fTheoryBlock_plainTextEdit->toPlainText(); } + + private slots: + QString getTheoFuncString(); + void addPlus(); + void addMultiply(); + void helpContent(); + + private: + PAdmin *fAdmin; ///< pointer to the administration class object needed to extract the default theory set informations. + QString fHelpUrl; ///< help url for the asymmetry run block +}; + +#endif // _PGETTHEORYBLOCKDIALOG_H_ diff --git a/src/musredit_qt6/musredit/PGetTitleBlockDialog.cpp b/src/musredit_qt6/musredit/PGetTitleBlockDialog.cpp new file mode 100644 index 00000000..22ae3675 --- /dev/null +++ b/src/musredit_qt6/musredit/PGetTitleBlockDialog.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** + + PGetTitleBlockDialog.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2010-2019 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 "PGetTitleBlockDialog.h" + +//--------------------------------------------------------------------------- +/** + *

Constructor. + * + * \param helpUrl help url for the title. + */ +PGetTitleBlockDialog::PGetTitleBlockDialog(const QString helpUrl) : fHelpUrl(helpUrl) +{ + setupUi(this); + + setModal(true); +} + +//--------------------------------------------------------------------------- +/** + *

Generates a help content window showing the description of title block. + */ +void PGetTitleBlockDialog::helpContent() +{ + if (fHelpUrl.isEmpty()) { + QMessageBox::information(this, "**INFO**", "Will eventually show a help window"); + } else { + bool ok = QDesktopServices::openUrl(QUrl(fHelpUrl, QUrl::TolerantMode)); + if (!ok) { + QString msg = QString("

Sorry: Couldn't open default web-browser for the help.
Please try: musrfit docu in your web-browser.").arg(fHelpUrl); + QMessageBox::critical( nullptr, + tr("Fatal Error"), + msg, + tr("Quit") ); + } + } +} + +//--------------------------------------------------------------------------- +// END +//--------------------------------------------------------------------------- diff --git a/src/musredit_qt6/musredit/PGetTitleBlockDialog.h b/src/musredit_qt6/musredit/PGetTitleBlockDialog.h new file mode 100644 index 00000000..e9eb1853 --- /dev/null +++ b/src/musredit_qt6/musredit/PGetTitleBlockDialog.h @@ -0,0 +1,57 @@ +/**************************************************************************** + + PGetTitleBlockDialog.h + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2010-2019 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. * + ***************************************************************************/ + +#ifndef _PGETTITLEBLOCKDIALOG_H_ +#define _PGETTITLEBLOCKDIALOG_H_ + +#include "musredit.h" +#include "ui_PGetTitleBlockDialog.h" + +//-------------------------------------------------------------------------- +/** + *

Class handling the content of the menu: Edit/Add Block/Title Block. + */ +class PGetTitleBlockDialog : public QDialog, private Ui::PGetTitleBlockDialog +{ + Q_OBJECT + + public: + PGetTitleBlockDialog(const QString helpUrl); + virtual ~PGetTitleBlockDialog() {} + + QString getTitle() { return fTitle_lineEdit->text(); } + + private slots: + void helpContent(); + + private: + QString fHelpUrl; ///< help url for the asymmetry run block +}; + +#endif // _PGETTITLEBLOCKDIALOG_H_ diff --git a/src/musredit_qt6/musredit/PMsr2DataDialog.cpp b/src/musredit_qt6/musredit/PMsr2DataDialog.cpp new file mode 100644 index 00000000..45785f6a --- /dev/null +++ b/src/musredit_qt6/musredit/PMsr2DataDialog.cpp @@ -0,0 +1,268 @@ +/**************************************************************************** + + PMsr2DataDialog.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2009-2019 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 "PMsr2DataDialog.h" + +//---------------------------------------------------------------------------------------------------- +/** + *

Constructor. + * + * \param msr2DataParam data structure keeping the necessary information to feed msr2data + * \param helpUrl help url for msr2data + */ +PMsr2DataDialog::PMsr2DataDialog(PMsr2DataParam *msr2DataParam, const QString helpUrl) : fMsr2DataParam(msr2DataParam), fHelpUrl(helpUrl) +{ + setupUi(this); + + setModal(true); + + QString str; + + fRunTag = -1; + + if (!fMsr2DataParam->runListFileName.isEmpty()) { + fRunListFileName_lineEdit->setText(fMsr2DataParam->runListFileName); + } + + if (!fMsr2DataParam->runList.isEmpty()) { + fRunList_lineEdit->setText(fMsr2DataParam->runList); + } + + if (!fMsr2DataParam->msrFileExtension.isEmpty()) { + fMsrFileExtension_lineEdit->setText(fMsr2DataParam->msrFileExtension); + } + + fTemplateRunNumber_lineEdit->setValidator( new QIntValidator(fTemplateRunNumber_lineEdit) ); + if (fMsr2DataParam->templateRunNo != -1) { + str = QString("%1").arg(fMsr2DataParam->templateRunNo); + fTemplateRunNumber_lineEdit->setText(str); + } + + if (!fMsr2DataParam->dbOutputFileName.isEmpty()) { + fDataOutputFileName_lineEdit->setText(fMsr2DataParam->dbOutputFileName); + } + + if (!fMsr2DataParam->paramList.isEmpty()) { + fParamList_lineEdit->setText(fMsr2DataParam->paramList); + } + + fWriteDataHeader_checkBox->setChecked(fMsr2DataParam->writeDbHeader); + fIgnoreDataHeaderInfo_checkBox->setChecked(fMsr2DataParam->ignoreDataHeaderInfo); + fKeepMinuit2Output_checkBox->setChecked(fMsr2DataParam->keepMinuit2Output); + fEstimateN0_checkBox->setChecked(fMsr2DataParam->estimateN0); + fWriteColumnData_checkBox->setChecked(fMsr2DataParam->writeColumnData); + fRecreateDataFile_checkBox->setChecked(fMsr2DataParam->recreateDbFile); + fChainFit_checkBox->setChecked(fMsr2DataParam->chainFit); + fOpenFilesAfterFitting_checkBox->setChecked(fMsr2DataParam->openFilesAfterFitting); + fWritePerRunBlockChisq_checkBox->setChecked(fMsr2DataParam->perRunBlockChisq); + fTitleFromData_checkBox->setChecked(fMsr2DataParam->titleFromDataFile); + fCreateMsrFileOnly_checkBox->setChecked(fMsr2DataParam->createMsrFileOnly); + fFitOnly_checkBox->setChecked(fMsr2DataParam->fitOnly); + fGlobal_checkBox->setChecked(fMsr2DataParam->global); + fGlobalPlus_checkBox->setChecked(fMsr2DataParam->globalPlus); + + fOk_pushButton->setDefault(true); + + connect(fGlobal_checkBox, SIGNAL(clicked(bool)), this, SLOT(globalOptionSet(bool))); + connect(fGlobalPlus_checkBox, SIGNAL(clicked(bool)), this, SLOT(globalPlusOptionSet(bool))); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

returns the msr2data relavant parameters from the GUI. + */ +PMsr2DataParam* PMsr2DataDialog::getMsr2DataParam() +{ + fMsr2DataParam->runList = fRunList_lineEdit->text(); + fMsr2DataParam->runListFileName = fRunListFileName_lineEdit->text(); + fMsr2DataParam->msrFileExtension = fMsrFileExtension_lineEdit->text(); + if (fTemplateRunNumber_lineEdit->text().isEmpty()) { + fMsr2DataParam->templateRunNo = -1; + } else { + fMsr2DataParam->templateRunNo = fTemplateRunNumber_lineEdit->text().toInt(); + } + fMsr2DataParam->paramList = fParamList_lineEdit->text(); + fMsr2DataParam->dbOutputFileName = fDataOutputFileName_lineEdit->text(); + fMsr2DataParam->writeDbHeader = fWriteDataHeader_checkBox->isChecked(); + fMsr2DataParam->ignoreDataHeaderInfo = fIgnoreDataHeaderInfo_checkBox->isChecked(); + fMsr2DataParam->keepMinuit2Output = fKeepMinuit2Output_checkBox->isChecked(); + fMsr2DataParam->estimateN0 = fEstimateN0_checkBox->isChecked(); + fMsr2DataParam->writeColumnData = fWriteColumnData_checkBox->isChecked(); + fMsr2DataParam->recreateDbFile = fRecreateDataFile_checkBox->isChecked(); + fMsr2DataParam->chainFit = fChainFit_checkBox->isChecked(); + fMsr2DataParam->openFilesAfterFitting = fOpenFilesAfterFitting_checkBox->isChecked(); + fMsr2DataParam->perRunBlockChisq = fWritePerRunBlockChisq_checkBox->isChecked(); + fMsr2DataParam->titleFromDataFile = fTitleFromData_checkBox->isChecked(); + fMsr2DataParam->createMsrFileOnly = fCreateMsrFileOnly_checkBox->isChecked(); + fMsr2DataParam->fitOnly = fFitOnly_checkBox->isChecked(); + fMsr2DataParam->global = fGlobal_checkBox->isChecked(); + fMsr2DataParam->globalPlus = fGlobalPlus_checkBox->isChecked(); + + return fMsr2DataParam; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT: called when in the 'Run List Input', the 'Run List' text field is activated. It clears any + * entries in 'First', 'Last', and 'Run List File Name'. It furthermore sets the run tag. + * + * \param str string content of the QTextEdit field. + */ +void PMsr2DataDialog::runListEntered(const QString &str) +{ + if (str.length() == 0) + return; + + fRunTag = 0; + + if (!fRunListFileName_lineEdit->text().isEmpty()) + fRunListFileName_lineEdit->clear(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT: called when in the 'Run List Input', the 'Run List File Name' text field is activated. It clears any + * entries in 'First', 'Last', and 'Run List'. It furthermore sets the run tag. + * + * \param str string content of the QTextEdit field. + */ +void PMsr2DataDialog::runListFileNameEntered(const QString &str) +{ + if (str.length() == 0) + return; + + fRunTag = 1; + + if (!fRunList_lineEdit->text().isEmpty()) + fRunList_lineEdit->clear(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT: called when in 'Template Run Input', the 'Template Run Number' text field is activated. + * It set at the same time the fit-only flag to false. + * + * \param str string content of the QTextEdit field. + */ +void PMsr2DataDialog::templateRunEntered(const QString &str) +{ + if (!str.isEmpty()) + fFitOnly_checkBox->setChecked(false); + fTemplateRunNumber_lineEdit->setText(str); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT: called when the 'Create msr-File only' QCheckBox under 'Options' is activated. + * Sets at the same time the fit-only flag to false. + * + * \param buttonState state of the button. + */ +void PMsr2DataDialog::createMsrFileOnlyChanged(int buttonState) +{ + if (buttonState == Qt::Checked) { + fFitOnly_checkBox->setChecked(false); + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT: called when the 'Fit Only' QCheckBox under 'Options' is activated. + * Sets at the same time the create-msr-file-only and global flags to false. Clears the 'Template Run Number' + * field. + * + * \param buttonState state of the button. + */ +void PMsr2DataDialog::fitOnlyChanged(int buttonState) +{ + if (buttonState == Qt::Checked) { + fCreateMsrFileOnly_checkBox->setChecked(false); + fTemplateRunNumber_lineEdit->clear(); + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Generates a help content window showing the description for msr2data. + */ +void PMsr2DataDialog::helpContent() +{ + if (fHelpUrl.isEmpty()) { + QMessageBox::information(this, "**INFO**", "Will eventually show a help window"); + } else { + bool ok = QDesktopServices::openUrl(QUrl(fHelpUrl, QUrl::TolerantMode)); + if (!ok) { + QString msg = QString("

Sorry: Couldn't open default web-browser for the help.
Please try: musrfit docu in your web-browser.").arg(fHelpUrl); + QMessageBox::critical( nullptr, + tr("Fatal Error"), + msg, + tr("Quit") ); + } + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Unchecks global+ if global is checked since global/global+ are excluding options + * + * \param checked true, if the check-box is checked + */ +void PMsr2DataDialog::globalOptionSet(bool checked) +{ + if (checked) { + if (fGlobalPlus_checkBox->isChecked()) + fGlobalPlus_checkBox->setChecked(false); + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Unchecks global if global+ is checked since global/global+ are excluding options + * + * \param checked true, if the check-box is checked + */ +void PMsr2DataDialog::globalPlusOptionSet(bool checked) +{ + if (checked) { + if (fGlobal_checkBox->isChecked()) + fGlobal_checkBox->setChecked(false); + } +} + +//---------------------------------------------------------------------------------------------------- +// END +//---------------------------------------------------------------------------------------------------- diff --git a/src/musredit_qt6/musredit/PMsr2DataDialog.h b/src/musredit_qt6/musredit/PMsr2DataDialog.h new file mode 100644 index 00000000..88a05959 --- /dev/null +++ b/src/musredit_qt6/musredit/PMsr2DataDialog.h @@ -0,0 +1,71 @@ +/**************************************************************************** + + PMsr2DataDialog.h + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2010-2019 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. * + ***************************************************************************/ + +#ifndef _PMSR2DATADIALOG_H_ +#define _PMSR2DATADIALOG_H_ + +#include +#include + +#include "musredit.h" +#include "ui_PMsr2DataDialog.h" + +/** + *

Class handling the content of the MusrFit/Msr2Data GUI. It collects the input + * for B.M. Wojek's msr2data program. + */ +class PMsr2DataDialog : public QDialog, private Ui::PMsr2DataDialog +{ + Q_OBJECT + + public: + PMsr2DataDialog(PMsr2DataParam *msr2DataParam, const QString helpUrl); + + virtual int getRunTag() { return fRunTag; } + virtual PMsr2DataParam* getMsr2DataParam(); + + public slots: + void runListEntered(const QString&); + void runListFileNameEntered(const QString&); + void templateRunEntered(const QString&); + void createMsrFileOnlyChanged(int); + void fitOnlyChanged(int); + void helpContent(); + + private slots: + void globalOptionSet(bool checked); + void globalPlusOptionSet(bool checked); + + private: + int fRunTag; ///< -1 = not valid, 0 = run list, 1 = run list file name + PMsr2DataParam *fMsr2DataParam; ///< data structure used to handle the necessary input for msr2data. + QString fHelpUrl; ///< help url for the Fourier block +}; + +#endif // _PMSR2DATADIALOG_H_ diff --git a/src/musredit_qt6/musredit/PMusrEditAbout.cpp b/src/musredit_qt6/musredit/PMusrEditAbout.cpp new file mode 100644 index 00000000..16916f0a --- /dev/null +++ b/src/musredit_qt6/musredit/PMusrEditAbout.cpp @@ -0,0 +1,49 @@ +/**************************************************************************** + + PMusrEditAbout.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2010-2019 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 "git-revision.h" +#include "PMusrEditAbout.h" + +//--------------------------------------------------------------------------- +/** + *

Handles the musredit about popup. + */ +PMusrEditAbout::PMusrEditAbout(QWidget *parent) : QDialog(parent) +{ + setupUi(this); + + fGitBranch_label->setText(QString("git-branch: %1").arg(GIT_BRANCH)); + fGitRev_label->setText(QString("git-rev: %1").arg(GIT_CURRENT_SHA1)); + + setModal(true); +} + +//--------------------------------------------------------------------------- +// END +//--------------------------------------------------------------------------- diff --git a/src/musredit_qt6/musredit/PMusrEditAbout.h b/src/musredit_qt6/musredit/PMusrEditAbout.h new file mode 100644 index 00000000..aaa5adf8 --- /dev/null +++ b/src/musredit_qt6/musredit/PMusrEditAbout.h @@ -0,0 +1,46 @@ +/**************************************************************************** + + PMusrEditAbout.h + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2010-2019 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. * + ***************************************************************************/ + +#ifndef _PMUSREDITABOUT_H_ +#define _PMUSREDITABOUT_H_ + +#include "musredit.h" +#include "ui_PMusrEditAbout.h" + +class PMusrEditAbout : public QDialog, private Ui::PMusrEditAbout +{ + Q_OBJECT + + public: + PMusrEditAbout(QWidget *parent = nullptr); + virtual ~PMusrEditAbout() {} + +}; + +#endif // _PMUSREDITABOUT_H_ diff --git a/src/musredit_qt6/musredit/PPrefsDialog.cpp b/src/musredit_qt6/musredit/PPrefsDialog.cpp new file mode 100644 index 00000000..07a1e534 --- /dev/null +++ b/src/musredit_qt6/musredit/PPrefsDialog.cpp @@ -0,0 +1,143 @@ +/**************************************************************************** + + PPrefsDialog.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2009-2019 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 "PChangeDefaultPathsDialog.h" +#include "PPrefsDialog.h" + +//---------------------------------------------------------------------------------------------------- +/** + *

Constructor. + * + * \param fAdmin keeps all the needed flags + */ +PPrefsDialog::PPrefsDialog(PAdmin *admin) : fAdmin(admin) +{ + if (!fAdmin) + return; + + setupUi(this); + + setModal(true); + + if (fAdmin->getDarkThemeIconsMenuFlag()) { + fDarkThemeIconsMenu_checkBox->setCheckState(Qt::Checked); + } else { + fDarkThemeIconsMenu_checkBox->setCheckState(Qt::Unchecked); + } + + if (fAdmin->getDarkThemeIconsToolbarFlag()) { + fDarkThemeIconsToolbar_checkBox->setCheckState(Qt::Checked); + } else { + fDarkThemeIconsToolbar_checkBox->setCheckState(Qt::Unchecked); + } + + fKeepMn2Output_checkBox->setChecked(fAdmin->getKeepMinuit2OutputFlag()); + + if (fAdmin->getDumpAsciiFlag() && !fAdmin->getDumpRootFlag()) { + fDumpAscii_checkBox->setChecked(true); + fDumpRoot_checkBox->setChecked(false); + } else if (!fAdmin->getDumpAsciiFlag() && fAdmin->getDumpRootFlag()) { + fDumpAscii_checkBox->setChecked(false); + fDumpRoot_checkBox->setChecked(true); + } else { + fDumpAscii_checkBox->setChecked(false); + fDumpRoot_checkBox->setChecked(false); + } + + fTitleFromData_checkBox->setChecked(fAdmin->getTitleFromDataFileFlag()); + fEnableMusrT0_checkBox->setChecked(fAdmin->getEnableMusrT0Flag()); + fPerRunBlockChisq_checkBox->setChecked(fAdmin->getChisqPerRunBlockFlag()); + fEstimateN0_checkBox->setChecked(fAdmin->getEstimateN0Flag()); + fFourier_checkBox->setChecked(fAdmin->getMusrviewShowFourierFlag()); + fAvg_checkBox->setChecked(fAdmin->getMusrviewShowAvgFlag()); + fOneToOne_checkBox->setChecked(fAdmin->getMusrviewShowOneToOneFlag()); + + fTimeout_lineEdit->setText(QString("%1").arg(fAdmin->getTimeout())); + fTimeout_lineEdit->setValidator(new QIntValidator(fTimeout_lineEdit)); + + QObject::connect(fDefaultPath_pushButton, SIGNAL(clicked()), this, SLOT(handleDefaultPaths())); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

returns the dump flag (see the '--dump' option of musrfit). 0 == no dump, 1 == ascii dump, 2 == root dump + */ +int PPrefsDialog::getDump() +{ + int result = 0; + + if (fDumpAscii_checkBox->isChecked()) + result = 1; + else if (fDumpRoot_checkBox->isChecked()) + result = 2; + + return result; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT: called when the QCheckBox 'dump ascii' is selected. Will uncheck 'dump root' since these + * two options are mutually exclusive. + */ +void PPrefsDialog::dumpAscii() +{ + if (fDumpAscii_checkBox->isChecked()) + fDumpRoot_checkBox->setChecked(false); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT: called when the QCheckBox 'dump root' is selected. Will uncheck 'dump ascii' since these + * two options are mutually exclusive. + */ +void PPrefsDialog::dumpRoot() +{ + if (fDumpRoot_checkBox->isChecked()) + fDumpAscii_checkBox->setChecked(false); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT: called when the QPushButton 'Change Default Search Paths' is clicked. Will call a + * dialog which allows to deal with the default search paths to look for data files. + */ +void PPrefsDialog::handleDefaultPaths() +{ + PChangeDefaultPathsDialog *dlg = new PChangeDefaultPathsDialog(); + + if (dlg->exec() == QDialog::Accepted) { + + } + + delete dlg; +} + +//---------------------------------------------------------------------------------------------------- +// END +//---------------------------------------------------------------------------------------------------- diff --git a/src/musredit_qt6/musredit/PPrefsDialog.h b/src/musredit_qt6/musredit/PPrefsDialog.h new file mode 100644 index 00000000..63c3c270 --- /dev/null +++ b/src/musredit_qt6/musredit/PPrefsDialog.h @@ -0,0 +1,72 @@ +/**************************************************************************** + + PPrefsDialog.h + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2010-2019 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. * + ***************************************************************************/ + +#ifndef _PPREFSDIALOG_H_ +#define _PPREFSDIALOG_H_ + +#include + +#include + +#include "ui_PPrefsDialog.h" + +/** + *

Class handling the content of the MusrFit/Preferences. + */ +class PPrefsDialog : public QDialog, private Ui::PPrefsDialog +{ + Q_OBJECT + + public: + PPrefsDialog(PAdmin *admin); + + bool getMusrviewShowFourierFlag() { return fFourier_checkBox->isChecked(); } + bool getMusrviewShowAvgFlag() { return fAvg_checkBox->isChecked(); } + bool getMusrviewShowOneToOneFlag() { return fOneToOne_checkBox->isChecked(); } + bool getKeepMinuit2OutputFlag() { return fKeepMn2Output_checkBox->isChecked(); } + bool getTitleFromDataFileFlag() { return fTitleFromData_checkBox->isChecked(); } + bool getEnableMusrT0Flag() { return fEnableMusrT0_checkBox->isChecked(); } + bool getKeepRunPerBlockChisqFlag() { return fPerRunBlockChisq_checkBox->isChecked(); } + bool getEstimateN0Flag() { return fEstimateN0_checkBox->isChecked(); } + bool getDarkThemeIconsMenuFlag() { return fDarkThemeIconsMenu_checkBox->isChecked(); } + bool getDarkThemeIconsToolbarFlag() { return fDarkThemeIconsToolbar_checkBox->isChecked(); } + bool getOneToOneFlag() { return fOneToOne_checkBox->isChecked(); } + int getDump(); + int getTimeout() { return fTimeout_lineEdit->text().toInt(); } + + public slots: + void dumpAscii(); + void dumpRoot(); + void handleDefaultPaths(); + + private: + PAdmin *fAdmin; +}; + +#endif // _PPREFSDIALOG_H_ diff --git a/src/musredit_qt6/musredit/PReplaceConfirmationDialog.cpp b/src/musredit_qt6/musredit/PReplaceConfirmationDialog.cpp new file mode 100644 index 00000000..42e75973 --- /dev/null +++ b/src/musredit_qt6/musredit/PReplaceConfirmationDialog.cpp @@ -0,0 +1,44 @@ +/**************************************************************************** + + PReplaceConfirmationDialog.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2010-2019 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 "PReplaceConfirmationDialog.h" + +//---------------------------------------------------------------------------------------------------- +/** + *

Constructor. + * + * \param parent pointer to the parent object + * \param f qt windows flags + */ +PReplaceConfirmationDialog::PReplaceConfirmationDialog(QWidget *parent) : QDialog(parent) +{ + setupUi(this); + + setModal(true); +} diff --git a/src/musredit_qt6/musredit/PReplaceConfirmationDialog.h b/src/musredit_qt6/musredit/PReplaceConfirmationDialog.h new file mode 100644 index 00000000..c097c067 --- /dev/null +++ b/src/musredit_qt6/musredit/PReplaceConfirmationDialog.h @@ -0,0 +1,47 @@ +/**************************************************************************** + + PReplaceConfirmationDialog.h + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2010-2019 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. * + ***************************************************************************/ + +#ifndef _PREPLACECONFIRMATIONDIALOG_H_ +#define _PREPLACECONFIRMATIONDIALOG_H_ + +#include +#include + +#include "ui_PReplaceConfirmationDialog.h" + +class PReplaceConfirmationDialog : public QDialog, public Ui::PReplaceConfirmationDialog +{ + Q_OBJECT + + public: + PReplaceConfirmationDialog(QWidget *parent = nullptr); + virtual ~PReplaceConfirmationDialog() {} +}; + +#endif // _PREPLACECONFIRMATIONDIALOG_H_ diff --git a/src/musredit_qt6/musredit/PReplaceDialog.cpp b/src/musredit_qt6/musredit/PReplaceDialog.cpp new file mode 100644 index 00000000..bc095646 --- /dev/null +++ b/src/musredit_qt6/musredit/PReplaceDialog.cpp @@ -0,0 +1,109 @@ +/**************************************************************************** + + PReplaceDialog.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2009-2019 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 "PReplaceDialog.h" + +//---------------------------------------------------------------------------------------------------- +/** + *

Constructor. + * + * \param data find/replace data structure + * \param selection if true, find/replace only of the selection + * \param parent pointer to the parent object + * \param f qt windows flag + */ +PReplaceDialog::PReplaceDialog(PFindReplaceData *data, const bool selection, QWidget *parent) : + QDialog(parent), fData(data) +{ + setupUi(this); + + setModal(true); + + // if only empty text, disable find button + if (fData->findText == "") { + fReplace_pushButton->setEnabled(false); + } + + // if there is no selection, disable that option + if (!selection) { + fSelectedText_checkBox->setChecked(false); + fSelectedText_checkBox->setEnabled(false); + } + + fFind_comboBox->setItemText(0, fData->findText); + fReplacementText_comboBox->setItemText(0, fData->replaceText); + fCaseSensitive_checkBox->setChecked(fData->caseSensitive); + fWholeWordsOnly_checkBox->setChecked(fData->wholeWordsOnly); + fFromCursor_checkBox->setChecked(fData->fromCursor); + fFindBackwards_checkBox->setChecked(fData->findBackwards); + fPromptOnReplace_checkBox->setChecked(fData->promptOnReplace); + + if (selection) { + fSelectedText_checkBox->setChecked(fData->selectedText); + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

returns the pointer to the find/replace data structure which is updated from the GUI content. + */ +PFindReplaceData* PReplaceDialog::getData() +{ + fData->findText = fFind_comboBox->currentText(); + fData->replaceText = fReplacementText_comboBox->currentText(); + fData->caseSensitive = fCaseSensitive_checkBox->isChecked(); + fData->wholeWordsOnly = fWholeWordsOnly_checkBox->isChecked(); + fData->fromCursor = fFromCursor_checkBox->isChecked(); + fData->findBackwards = fFindBackwards_checkBox->isChecked(); + if (fSelectedText_checkBox->isEnabled()) + fData->selectedText = fSelectedText_checkBox->isChecked(); + fData->promptOnReplace = fPromptOnReplace_checkBox->isChecked(); + + return fData; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT: called on find text available. + */ +void PReplaceDialog::onFindTextAvailable(const QString&) +{ + if (fFind_comboBox->currentText() != "") + fReplace_pushButton->setEnabled(true); + else + fReplace_pushButton->setEnabled(false); +} + +//---------------------------------------------------------------------------------------------------- +// END +//---------------------------------------------------------------------------------------------------- diff --git a/src/musredit_qt6/musredit/PReplaceDialog.h b/src/musredit_qt6/musredit/PReplaceDialog.h new file mode 100644 index 00000000..5e63cccd --- /dev/null +++ b/src/musredit_qt6/musredit/PReplaceDialog.h @@ -0,0 +1,53 @@ +/**************************************************************************** + + PReplaceDialog.h + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2010-2019 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. * + ***************************************************************************/ + +#ifndef _PREPLACEDIALOG_H_ +#define _PREPLACEDIALOG_H_ + +#include "musredit.h" +#include "ui_PReplaceDialog.h" + +class PReplaceDialog : public QDialog, private Ui::PReplaceDialog +{ + Q_OBJECT + + public: + PReplaceDialog(PFindReplaceData *data, const bool selection, QWidget *parent = nullptr); + virtual ~PReplaceDialog() {} + + virtual PFindReplaceData *getData(); + + protected slots: + virtual void onFindTextAvailable(const QString&); + + private: + PFindReplaceData *fData; ///< pointer to the find/replace data +}; + +#endif // _PREPLACEDIALOG_H_ diff --git a/src/musredit_qt6/musredit/PSubTextEdit.cpp b/src/musredit_qt6/musredit/PSubTextEdit.cpp new file mode 100644 index 00000000..542adf48 --- /dev/null +++ b/src/musredit_qt6/musredit/PSubTextEdit.cpp @@ -0,0 +1,559 @@ +/**************************************************************************** + + PSubTextEdit.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2009-2019 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 "PAdmin.h" +#include "PSubTextEdit.h" +#include "PGetTitleBlockDialog.h" +#include "PGetParameterBlockDialog.h" +#include "PGetTheoryBlockDialog.h" +#include "PGetFunctionsBlockDialog.h" +#include "PGetAsymmetryRunBlockDialog.h" +#include "PGetSingleHistoRunBlockDialog.h" +#include "PGetNonMusrRunBlockDialog.h" +#include "PGetFourierBlockDialog.h" +#include "PGetPlotBlockDialog.h" + +//---------------------------------------------------------------------------------------------------- +/** + *

Constructor. + * + * \param admin pointer to the musredit internal administration object. + * \param parent pointer to the parent object. + */ +PSubTextEdit::PSubTextEdit(PAdmin *admin, QWidget *parent) : + QPlainTextEdit(parent), + fAdmin(admin) +{ +} + +//---------------------------------------------------------------------------------------------------- +/** + * @brief PSubTextEdit::getFitType + * @return + */ +int PSubTextEdit::getFitType() +{ + QString str = toPlainText(); + int idx = str.indexOf("fittype"); + if (idx == -1) + return -1; + + bool ok; + for (int i=idx+7; iStarts the msr-title input dialog window. + */ +void PSubTextEdit::insertTitle() +{ + // for the time being the url's are hard coded but should be transfered to the XML startup + PGetTitleBlockDialog *dlg = new PGetTitleBlockDialog(fAdmin->getHelpUrl("title")); + + if (dlg == 0) + return; + + if (dlg->exec() == QDialog::Accepted) { + QString title = dlg->getTitle(); + insertPlainText(title+"\n"); + } + + delete dlg; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Starts the msr-fit-parameter input dialog window. + */ +void PSubTextEdit::insertParameterBlock() +{ + // for the time being the url's are hard coded but should be transfered to the XML startup + PGetParameterBlockDialog *dlg = new PGetParameterBlockDialog(fAdmin->getHelpUrl("parameters")); + + if (dlg == 0) + return; + + if (dlg->exec() == QDialog::Accepted) { + insertPlainText(dlg->getParams()); + } + + delete dlg; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Inserts the selected theory item. + * + * \param name of the theory item to be added. + */ +void PSubTextEdit::insertTheoryFunction(QString name) +{ + QString str = "????"; + + int idx = -1; + for (unsigned int i=0; igetTheoryCounts(); i++) { + if (name == fAdmin->getTheoryItem(i)->label) { + idx = i; + break; + } + } + + if (idx == -1) + return; + + PTheory *theoItem = fAdmin->getTheoryItem(idx); + if (theoItem == 0) + return; + + // add theory function name + str = theoItem->name + " "; + if (theoItem->name == "userFcn") { + str += "libMyLibrary.so TMyFunction "; + } + + // add pseudo parameters + for (int i=0; iparams; i++) { + str += QString("%1").arg(i+1) + " "; + } + + // add comment + str += theoItem->comment; + + // add newline + str += "\n"; + + insertPlainText(str); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Starts the msr-theory input dialog window. + */ +void PSubTextEdit::insertTheoryBlock() +{ + // for the time being the url's are hard coded but should be transfered to the XML startup + PGetTheoryBlockDialog *dlg = new PGetTheoryBlockDialog(fAdmin, fAdmin->getHelpUrl("theory")); + + if (dlg == 0) + return; + + if (dlg->exec() == QDialog::Accepted) { + insertPlainText(dlg->getTheoryBlock()); + insertPlainText("\n"); + } + + delete dlg; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Starts the msr-functions input dialog window. + */ +void PSubTextEdit::insertFunctionBlock() +{ + // for the time being the url's are hard coded but should be transfered to the XML startup + PGetFunctionsBlockDialog *dlg = new PGetFunctionsBlockDialog(fAdmin->getHelpUrl("functions")); + + if (dlg == 0) + return; + + if (dlg->exec() == QDialog::Accepted) { + insertPlainText(dlg->getFunctionsBlock()); + insertPlainText("\n\n"); + } + + delete dlg; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Starts the msr-asymmetry-run input dialog window. + */ +void PSubTextEdit::insertAsymRunBlock() +{ + // for the time being the url's are hard coded but should be transfered to the XML startup + PGetAsymmetryRunBlockDialog *dlg = new PGetAsymmetryRunBlockDialog(fAdmin->getHelpUrl("run")); + + if (dlg == 0) + return; + + if (dlg->exec() == QDialog::Accepted) { + QString str, workStr; + bool valid = true, present = true; + // check if there is already a run block present, necessary because of the '####' line + // STILL MISSING + + // add run line + str += dlg->getRunHeaderInfo(); + + // add fittype + str += "fittype 2 (asymmetry fit)\n"; + + // add alpha if present + workStr = dlg->getAlphaParameter(present); + if (present) { + str += workStr; + } + + // add beta if present + workStr = dlg->getBetaParameter(present); + if (present) { + str += workStr; + } + + // add map + workStr = dlg->getMap(valid); + if (valid) { + str += workStr; + } else { + QMessageBox::critical(this, "**ERROR**", + "Given map not valid, will add a default map line", + QMessageBox::Ok, QMessageBox::NoButton); + str += "map 0 0 0 0 0 0 0 0 0 0\n"; + } + + // add forward + str += dlg->getForward(); + + // add backward + str += dlg->getBackward(); + + // add background or backgr.fix + workStr = dlg->getBackground(valid); + str += workStr; + if (!valid) { + QMessageBox::critical(this, "**ERROR**", + "Either background or backgr.fix is needed!\nWill set background to 0..10, please correct!", + QMessageBox::Ok, QMessageBox::NoButton); + } + + // add data + workStr = dlg->getData(valid); + if (valid) { + str += workStr; + } else { + QMessageBox::critical(this, "**ERROR**", + "Not all Data entries are present.Fix is needed!\nWill not set anything!", + QMessageBox::Ok, QMessageBox::NoButton); + } + + // add t0 if present + workStr = dlg->getT0(present); + if (present) { + str += workStr; + } else { + QMessageBox::warning(this, "**ERROR**", + "T0's not given, assume that they are present in the data file!", + QMessageBox::Ok, QMessageBox::NoButton); + } + + // add fit range + workStr = dlg->getFitRange(valid); + str += workStr; + if (!valid) { + QMessageBox::critical(this, "**ERROR**", + "No valid fit range is given.Fix is needed!\nWill add a default one!", + QMessageBox::Ok, QMessageBox::NoButton); + } + + // add packing + workStr = dlg->getPacking(present); + str += workStr; + if (!present) { + QMessageBox::critical(this, "**ERROR**", + "No valid packing/binning is given.Fix is needed!\nWill add a default one!", + QMessageBox::Ok, QMessageBox::NoButton); + } + + // insert Asymmetry Run Block at the current cursor position + insertPlainText(str); + } + + delete dlg; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Starts the msr-single-historgram-run input dialog window. + */ +void PSubTextEdit::insertSingleHistRunBlock() +{ + // for the time being the url's are hard coded but should be transfered to the XML startup + PGetSingleHistoRunBlockDialog *dlg = new PGetSingleHistoRunBlockDialog(fAdmin->getHelpUrl("run")); + + if (dlg == 0) + return; + + if (dlg->exec() == QDialog::Accepted) { + QString str, workStr; + bool valid = true, present = true; + // check if there is already a run block present, necessary because of the '####' line + // STILL MISSING + + // add run line + str += dlg->getRunHeaderInfo(); + + // add fittype + str += "fittype 0 (single histogram fit)\n"; + + // add map + workStr = dlg->getMap(valid); + if (valid) { + str += workStr; + } else { + QMessageBox::critical(this, "**ERROR**", + "Given map not valid, will add a default map line", + QMessageBox::Ok, QMessageBox::NoButton); + str += "map 0 0 0 0 0 0 0 0 0 0\n"; + } + + // add forward + str += dlg->getForward(); + + // add norm + str += dlg->getNorm(); + + // add lifetime parameter + workStr = dlg->getMuonLifetimeParam(present); + if (present) { + str += workStr; + } + + // add lifetime correction flag if present + workStr = dlg->getLifetimeCorrection(present); + if (present) { + str += workStr; + } + + // add background, backgr.fix or backgr.fit + workStr = dlg->getBackground(valid); + str += workStr; + if (!valid) { + QMessageBox::critical(this, "**ERROR**", + "Either background, backgr.fix, or backgr.fit is needed!\nWill set background to 0..10, please correct!", + QMessageBox::Ok, QMessageBox::NoButton); + } + + // add t0 if present + workStr = dlg->getT0(present); + if (present) { + str += workStr; + } else { + QMessageBox::warning(this, "**ERROR**", + "T0's not given, assume that they are present in the data file!", + QMessageBox::Ok, QMessageBox::NoButton); + } + + // add data + workStr = dlg->getData(valid); + if (valid) { + str += workStr; + } else { + QMessageBox::critical(this, "**ERROR**", + "Not all Data entries are present.Fix is needed!\nWill not set anything!", + QMessageBox::Ok, QMessageBox::NoButton); + } + + // add fit range + workStr = dlg->getFitRange(valid); + str += workStr; + if (!valid) { + QMessageBox::critical(this, "**ERROR**", + "No valid fit range is given.Fix is needed!\nWill add a default one!", + QMessageBox::Ok, QMessageBox::NoButton); + } + + // add packing + workStr = dlg->getPacking(present); + str += workStr; + if (!present) { + QMessageBox::critical(this, "**ERROR**", + "No valid packing/binning is given.Fix is needed!\nWill add a default one!", + QMessageBox::Ok, QMessageBox::NoButton); + } + + // insert Single Histogram Run Block at the current cursor position + insertPlainText(str); + } + + delete dlg; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Starts the msr-nonMusr-run input dialog window. + */ +void PSubTextEdit::insertNonMusrRunBlock() +{ + PGetNonMusrRunBlockDialog *dlg = new PGetNonMusrRunBlockDialog(fAdmin->getHelpUrl("run")); + + if (dlg == 0) + return; + + if (dlg->exec() == QDialog::Accepted) { + QString str, workStr; + bool valid = true; + // check if there is already a run block present, necessary because of the '####' line + // STILL MISSING + + // add run line + str += dlg->getRunHeaderInfo(); + + // add fittype + str += "fittype 8 (non musr fit)\n"; + + // add map + workStr = dlg->getMap(valid); + if (valid) { + str += workStr; + } else { + QMessageBox::critical(this, "**ERROR**", + "Given map not valid, will add a default map line", + QMessageBox::Ok, QMessageBox::NoButton); + str += "map 0 0 0 0 0 0 0 0 0 0\n"; + } + + // add xy-data + workStr = dlg->getXYData(valid); + if (valid) { + str += workStr; + } else { + QMessageBox::critical(this, "**ERROR**", + "Not all xy-data entries are present.Fix is needed!\nWill not set anything!", + QMessageBox::Ok, QMessageBox::NoButton); + } + + // add fit range + workStr = dlg->getFitRange(valid); + str += workStr; + if (!valid) { + QMessageBox::critical(this, "**ERROR**", + "No valid fit range is given.Fix is needed!\nWill add a default one!", + QMessageBox::Ok, QMessageBox::NoButton); + } + + // add packing + str += "packing 1\n"; + + // insert NonMusr Run Block at the current cursor position + insertPlainText(str); + } + + delete dlg; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Insert the command block. + */ +void PSubTextEdit::insertCommandBlock() +{ + insertPlainText("###############################################################\n"); + insertPlainText("COMMANDS\n"); + insertPlainText("SET BATCH\n"); + insertPlainText("STRATEGY 1\n"); + insertPlainText("MINIMIZE\n"); + insertPlainText("#MINOS\n"); + insertPlainText("SAVE\n"); + insertPlainText("END RETURN\n\n"); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Starts the msr-Fourier input dialog window. + */ +void PSubTextEdit::insertFourierBlock() +{ + // for the time being the url's are hard coded but should be transfered to the XML startup + PGetFourierBlockDialog *dlg = new PGetFourierBlockDialog(fAdmin->getHelpUrl("fourier")); + + if (dlg == 0) + return; + + if (dlg->exec() == QDialog::Accepted) { + insertPlainText(dlg->getFourierBlock()+"\n"); + } + + delete dlg; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Starts the msr-plot input dialog window. + */ +void PSubTextEdit::insertPlotBlock() +{ + // for the time being the url's are hard coded but should be transfered to the XML startup + PGetPlotBlockDialog *dlg = new PGetPlotBlockDialog(fAdmin->getHelpUrl("plot")); + + if (dlg == 0) + return; + + if (dlg->exec() == QDialog::Accepted) { + insertPlainText(dlg->getPlotBlock()+"\n"); + } + + delete dlg; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Insert a default msr-statistics block. + */ +void PSubTextEdit::insertStatisticBlock() +{ + QDateTime dt = QDateTime::currentDateTime(); + insertPlainText("###############################################################\n"); + insertPlainText("STATISTIC --- " + dt.toString("yyyy-MM-dd hh:mm:ss") + "\n"); + insertPlainText("chisq = ????, NDF = ????, chisq/NDF = ????\n\n"); +} + +//---------------------------------------------------------------------------------------------------- +// END +//---------------------------------------------------------------------------------------------------- diff --git a/src/musredit_qt6/musredit/PSubTextEdit.h b/src/musredit_qt6/musredit/PSubTextEdit.h new file mode 100644 index 00000000..5836800c --- /dev/null +++ b/src/musredit_qt6/musredit/PSubTextEdit.h @@ -0,0 +1,69 @@ +/**************************************************************************** + + PSubTextEdit.h + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2009-2019 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. * + ***************************************************************************/ + +#ifndef _PSUBTEXTEDIT_H_ +#define _PSUBTEXTEDIT_H_ + +#include +#include + +#include "PAdmin.h" + +//------------------------------------------------------------------------------------------ +/** + *

Class handling a single text edit tab within musredit. + */ +class PSubTextEdit : public QPlainTextEdit +{ + Q_OBJECT + + public: + PSubTextEdit(PAdmin *admin = 0, QWidget *parent = 0); + virtual ~PSubTextEdit() {} + int getFitType(); + + public slots: + void insertTitle(); + void insertParameterBlock(); + void insertTheoryFunction(QString name); + void insertTheoryBlock(); + void insertFunctionBlock(); + void insertAsymRunBlock(); + void insertSingleHistRunBlock(); + void insertNonMusrRunBlock(); + void insertCommandBlock(); + void insertFourierBlock(); + void insertPlotBlock(); + void insertStatisticBlock(); + + private: + PAdmin *fAdmin; ///< pointer to the administration object which holds working-, executable-paths etc. +}; + +#endif // _PSUBTEXTEDIT_H_ diff --git a/src/musredit_qt6/musredit/PTextEdit.cpp b/src/musredit_qt6/musredit/PTextEdit.cpp new file mode 100644 index 00000000..fb519ab0 --- /dev/null +++ b/src/musredit_qt6/musredit/PTextEdit.cpp @@ -0,0 +1,3551 @@ +/**************************************************************************** + + PTextEdit.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2010-2021 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 +#include +#include +#include +#include +#include +#include + +#include + +#include "PTextEdit.h" +#include "PSubTextEdit.h" +#include "PAdmin.h" +#include "PFindDialog.h" +#include "PReplaceDialog.h" +#include "PReplaceConfirmationDialog.h" +#include "PFitOutputHandler.h" +#include "PDumpOutputHandler.h" +#include "PPrefsDialog.h" +#include "PGetMusrFTOptionsDialog.h" +#include "PMusrEditAbout.h" +#include "PMsr2DataDialog.h" + +//---------------------------------------------------------------------------------------------------- +/** + *

Constructor + * + * \param parent pointer to the parent object + * \param f qt windows flags + */ +PTextEdit::PTextEdit( QWidget *parent ) + : QMainWindow( parent ) +{ + bool gotTheme = getTheme(); + + // reads and manages the conents of the xml-startup (musredit_startup.xml) file + fAdmin = new PAdmin(); + + // set default setting of the fDarkMenuIconIcons only if a theme has been recognized, otherwise take the + // one from the xml startup file. + if (gotTheme) { + fAdmin->setDarkThemeIconsMenuFlag(fDarkMenuIcon); + fAdmin->setDarkThemeIconsToolbarFlag(fDarkToolBarIcon); + } else { + fDarkMenuIcon = fAdmin->getDarkThemeIconsMenuFlag(); + fDarkToolBarIcon = fAdmin->getDarkThemeIconsToolbarFlag(); + } + + // enable file system watcher. Needed to get notification if the msr-file is changed outside of musrfit at runtime + fFileSystemWatcherActive = true; + fFileSystemWatcher = new QFileSystemWatcher(); + if (fFileSystemWatcher == nullptr) { + QMessageBox::information(this, "**ERROR**", "Couldn't invoke QFileSystemWatcher!"); + } else { + connect( fFileSystemWatcher, SIGNAL(fileChanged(const QString&)), this, SLOT(fileChanged(const QString&))); + } + + // initialize stuff + fMusrT0Action = nullptr; + + fMsr2DataParam = nullptr; + fFindReplaceData = nullptr; + + fTabWidget = nullptr; + + // setup menus + setupFileActions(); + setupEditActions(); + setupTextActions(); + setupMusrActions(); + setupHelpActions(); + + fTabWidget = new QTabWidget( this ); + fTabWidget->setMovable(true); // allows to shuffle around tabs + setCentralWidget( fTabWidget ); + + textFamily(fAdmin->getFontName()); + textSize(QString("%1").arg(fAdmin->getFontSize())); + fFontChanging = false; + + QString iconName(""); + if (fDarkMenuIcon) + iconName = QString(":/icons/musrfit-dark.svg"); + else + iconName = QString(":/icons/musrfit-plain.svg"); + setWindowIcon( QIcon( QPixmap(iconName) ) ); + + // if arguments are give, try to load those files, otherwise create an empty new file + if ( qApp->arguments().size() != 1 ) { + for ( int i = 1; i < qApp->arguments().size(); ++i ) + load( qApp->arguments()[ i ] ); + } else { + fileNew(); + } + + connect( fTabWidget, SIGNAL( currentChanged(int) ), this, SLOT( applyFontSettings(int) )); + + fLastDirInUse = fAdmin->getDefaultSavePath(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

This slot is called if the main application is on the way to quit. This ensures that allocated + * memory indeed can be free'd. + */ +void PTextEdit::aboutToQuit() +{ + if (fAdmin) { + delete fAdmin; + fAdmin = nullptr; + } + if (fMusrT0Action) { + delete fMusrT0Action; + fMusrT0Action = nullptr; + } + if (fMsr2DataParam) { + delete fMsr2DataParam; + fMsr2DataParam = nullptr; + } + if (fFindReplaceData) { + delete fFindReplaceData; + fFindReplaceData = nullptr; + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Setup the file menu and the necessary actions. + */ +void PTextEdit::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(""); + + // New + if (fDarkMenuIcon) + iconName = QString(":/icons/document-new-dark.svg"); + else + iconName = QString(":/icons/document-new-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&New..." ), this ); + a->setShortcut( tr("Ctrl+N") ); + a->setStatusTip( tr("Create a new msr-file") ); + connect( a, SIGNAL( triggered() ), this, SLOT( fileNew() ) ); + menu->addAction(a); + fActions["New"] = a; + + if (!fDarkToolBarIcon) { // tool bar icon is not dark, even though the theme is (ubuntu) + iconName = QString(":/icons/document-new-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&New..." ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( fileNew() ) ); + } + tb->addAction(a); + fActions["New-tb"] = a; + + // Open + if (fDarkMenuIcon) + 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("Opens a msr-file") ); + connect( a, SIGNAL( triggered() ), this, SLOT( fileOpen() ) ); + menu->addAction(a); + fActions["Open"] = 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( "&Open..." ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( fileOpen() ) ); + } + tb->addAction(a); + fActions["Open-tb"] = a; + + // Recent Files + 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(); + + // Reload + if (fDarkMenuIcon) + iconName = QString(":/icons/view-refresh-dark.svg"); + else + iconName = QString(":/icons/view-refresh-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "Reload..." ), this ); + a->setShortcut( tr("F5") ); + a->setStatusTip( tr("Reload msr-file") ); + connect( a, SIGNAL( triggered() ), this, SLOT( fileReload() ) ); + menu->addAction(a); + fActions["Reload"] = a; + + if (!fDarkToolBarIcon) { // tool bar icon is not dark, even though the theme is (ubuntu) + iconName = QString(":/icons/view-refresh-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "Reload..." ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( fileReload() ) ); + } + tb->addAction(a); + fActions["Reload-tb"] = a; + + a = new QAction( tr( "Open Prefs..." ), this); + connect( a, SIGNAL( triggered() ), this, SLOT( fileOpenPrefs() ) ); + menu->addAction(a); + + menu->addSeparator(); + + // Save + if (fDarkMenuIcon) + iconName = QString(":/icons/document-save-dark.svg"); + else + iconName = QString(":/icons/document-save-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&Save..." ), this ); + a->setShortcut( tr("Ctrl+S") ); + a->setStatusTip( tr("Save msr-file") ); + connect( a, SIGNAL( triggered() ), this, SLOT( fileSave() ) ); + menu->addAction(a); + fActions["Save"] = a; + + if (!fDarkToolBarIcon) { // tool bar icon is not dark, even though the theme is (ubuntu) + iconName = QString(":/icons/document-save-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&Save..." ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( fileSave() ) ); + } + tb->addAction(a); + fActions["Save-tb"] = a; + + // Save As + a = new QAction( tr( "Save &As..." ), this ); + a->setStatusTip( tr("Save msr-file As") ); + connect( a, SIGNAL( triggered() ), this, SLOT( fileSaveAs() ) ); + menu->addAction(a); + + // Save Prefs + a = new QAction( tr( "Save Prefs..." ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( fileSavePrefs() ) ); + menu->addAction(a); + + menu->addSeparator(); + + // Print + if (fDarkMenuIcon) + iconName = QString(":/icons/document-print-dark.svg"); + else + iconName = QString(":/icons/document-print-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&Print..." ), this ); + a->setShortcut( tr("Ctrl+P") ); + a->setStatusTip( tr("Print msr-file") ); + connect( a, SIGNAL( triggered() ), this, SLOT( filePrint() ) ); + menu->addAction(a); + fActions["Print"] = a; + + if (!fDarkToolBarIcon) { // tool bar icon is not dark, even though the theme is (ubuntu) + iconName = QString(":/icons/document-print-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&Print..." ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( filePrint() ) ); + } + tb->addAction(a); + fActions["Print-tb"] = a; + + menu->addSeparator(); + + // Close + a = new QAction( tr( "&Close" ), this ); + a->setShortcut( tr("Ctrl+W") ); + a->setStatusTip( tr("Close msr-file") ); + connect( a, SIGNAL( triggered() ), this, SLOT( fileClose() ) ); + menu->addAction(a); + + // Close All + a = new QAction( tr( "Close &All" ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( fileCloseAll() ) ); + menu->addAction(a); + + // Close All Others + a = new QAction( tr( "Clo&se All Others" ), this ); + a->setShortcut( tr("Ctrl+Shift+W") ); + a->setStatusTip( tr("Close All Other Tabs") ); + connect( a, SIGNAL( triggered() ), this, SLOT( fileCloseAllOthers() ) ); + menu->addAction(a); + + menu->addSeparator(); + + // Exit + 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); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Setup the edit menu and the necessary actions. + */ +void PTextEdit::setupEditActions() +{ + QToolBar *tb = new QToolBar( this ); + tb->setWindowTitle( "Edit Actions" ); + addToolBar( tb ); + + QMenu *menu = new QMenu( tr( "&Edit" ), this ); + menuBar()->addMenu( menu ); + + QAction *a; + QString iconName(""); + + // Undo + if (fDarkMenuIcon) + iconName = QString(":/icons/edit-undo-dark.svg"); + else + iconName = QString(":/icons/edit-undo-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&Undo" ), this ); + a->setShortcut( tr("Ctrl+Z") ); + a->setStatusTip( tr("Edit Undo") ); + connect( a, SIGNAL( triggered() ), this, SLOT( editUndo() ) ); + menu->addAction(a); + fActions["Undo"] = a; + + if (!fDarkToolBarIcon) { // tool bar icon is not dark, even though the theme is (ubuntu) + iconName = QString(":/icons/edit-undo-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&Undo" ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( editUndo() ) ); + } + tb->addAction(a); + fActions["Undo-tb"] = a; + + // Redo + if (fDarkMenuIcon) + iconName = QString(":/icons/edit-redo-dark.svg"); + else + iconName = QString(":/icons/edit-redo-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&Redo" ), this ); + a->setShortcut( tr("Ctrl+Y") ); + a->setStatusTip( tr("Edit Redo") ); + connect( a, SIGNAL( triggered() ), this, SLOT( editRedo() ) ); + menu->addAction(a); + fActions["Redo"] = a; + + if (!fDarkToolBarIcon) { // tool bar icon is not dark, even though the theme is (ubuntu) + iconName = QString(":/icons/edit-redo-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&Redo" ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( editRedo() ) ); + } + tb->addAction(a); + fActions["Redo-tb"] = a; + + menu->addSeparator(); + + // Select All + a = new QAction( tr( "Select &All" ), this ); + a->setShortcut( tr("Ctrl+A") ); + a->setStatusTip( tr("Edit Select All") ); + connect( a, SIGNAL( triggered() ), this, SLOT( editSelectAll() ) ); + menu->addAction(a); + + menu->addSeparator(); + tb->addSeparator(); + + // Copy + if (fDarkMenuIcon) + iconName = QString(":/icons/edit-copy-dark.svg"); + else + iconName = QString(":/icons/edit-copy-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&Copy" ), this ); + a->setShortcut( tr("Ctrl+C") ); + a->setStatusTip( tr("Edit Copy") ); + connect( a, SIGNAL( triggered() ), this, SLOT( editCopy() ) ); + menu->addAction(a); + fActions["Copy"] = a; + + if (!fDarkToolBarIcon) { // tool bar icon is not dark, even though the theme is (ubuntu) + iconName = QString(":/icons/edit-copy-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&Copy" ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( editCopy() ) ); + } + tb->addAction(a); + fActions["Copy-tb"] = a; + + // Cut + if (fDarkMenuIcon) + iconName = QString(":/icons/edit-cut-dark.svg"); + else + iconName = QString(":/icons/edit-cut-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "Cu&t" ), this ); + a->setShortcut( tr("Ctrl+X") ); + a->setStatusTip( tr("Edit Cut") ); + connect( a, SIGNAL( triggered() ), this, SLOT( editCut() ) ); + menu->addAction(a); + fActions["Cut"] = a; + + if (!fDarkToolBarIcon) { // tool bar icon is not dark, even though the theme is (ubuntu) + iconName = QString(":/icons/edit-cut-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "Cu&t" ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( editCut() ) ); + } + tb->addAction(a); + fActions["Cut-tb"] = a; + + // Paste + if (fDarkMenuIcon) + iconName = QString(":/icons/edit-paste-dark.svg"); + else + iconName = QString(":/icons/edit-paste-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&Paste" ), this ); + a->setShortcut( tr("Ctrl+V") ); + a->setStatusTip( tr("Edit Paste") ); + connect( a, SIGNAL( triggered() ), this, SLOT( editPaste() ) ); + menu->addAction(a); + fActions["Paste"] = a; + + if (!fDarkToolBarIcon) { // tool bar icon is not dark, even though the theme is (ubuntu) + iconName = QString(":/icons/edit-paste-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&Paste" ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( editPaste() ) ); + } + tb->addAction(a); + fActions["Paste-tb"] = a; + + menu->addSeparator(); + tb->addSeparator(); + + // Find + if (fDarkMenuIcon) + iconName = QString(":/icons/edit-find-dark.svg"); + else + iconName = QString(":/icons/edit-find-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&Find" ), this ); + a->setShortcut( tr("Ctrl+F") ); + a->setStatusTip( tr("Edit Find") ); + connect( a, SIGNAL( triggered() ), this, SLOT( editFind() ) ); + menu->addAction(a); + fActions["Find"] = a; + + if (!fDarkToolBarIcon) { // tool bar icon is not dark, even though the theme is (ubuntu) + iconName = QString(":/icons/edit-find-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&Find" ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( editFind() ) ); + } + tb->addAction(a); + fActions["Find-tb"] = a; + + // Find Next + if (fDarkMenuIcon) + iconName = QString(":/icons/go-next-use-dark.svg"); + else + iconName = QString(":/icons/go-next-use-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "Find &Next" ), this ); + a->setShortcut( tr("F3") ); + a->setStatusTip( tr("Edit Find Next") ); + connect( a, SIGNAL( triggered() ), this, SLOT( editFindNext() ) ); + menu->addAction(a); + fActions["Find Next"] = a; + + if (!fDarkToolBarIcon) { // tool bar icon is not dark, even though the theme is (ubuntu) + iconName = QString(":/icons/go-next-use-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "Find &Next" ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( editFindNext() ) ); + } + tb->addAction(a); + fActions["Find Next-tb"] = a; + + // Find Previous + if (fDarkMenuIcon) + iconName = QString(":/icons/go-previous-use-dark.svg"); + else + iconName = QString(":/icons/go-previous-use-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ) , tr( "Find Pre&vious" ), this ); + a->setShortcut( tr("Shift+F4") ); + a->setStatusTip( tr("Edit Find Previous") ); + connect( a, SIGNAL( triggered() ), this, SLOT( editFindPrevious() ) ); + menu->addAction(a); + fActions["Find Previous"] = a; + + if (!fDarkToolBarIcon) { // tool bar icon is not dark, even though the theme is (ubuntu) + iconName = QString(":/icons/go-previous-use-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "Find Pre&vious" ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( editFindPrevious() ) ); + } + tb->addAction(a); + fActions["Find Previous-tb"] = a; + + // Replace + a = new QAction( tr( "Replace..." ), this ); + a->setShortcut( tr("Ctrl+R") ); + a->setStatusTip( tr("Edit Replace") ); + connect( a, SIGNAL( triggered() ), this, SLOT( editFindAndReplace() ) ); + menu->addAction(a); + menu->addSeparator(); + + QMenu *addSubMenu = new QMenu( tr ("Add Block"), this); + + a = new QAction( tr("Title Block"), this ); + a->setStatusTip( tr("Invokes MSR Title Block Dialog") ); + connect( a, SIGNAL( triggered() ), this, SLOT( insertTitle() )); + addSubMenu->addAction(a); + + a = new QAction( tr("Parameter Block"), this ); + a->setStatusTip( tr("Invokes MSR Parameter Block Dialog") ); + connect( a, SIGNAL( triggered() ), this, SLOT( insertParameterBlock() )); + addSubMenu->addAction(a); + + a = new QAction( tr("Theory Block"), this ); + a->setStatusTip( tr("Invokes MSR Theory Block Dialog") ); + connect( a, SIGNAL( triggered() ), this, SLOT( insertTheoryBlock() )); + addSubMenu->addAction(a); + + a = new QAction( tr("Function Block"), this ); + a->setStatusTip( tr("Invokes MSR Function Block Dialog") ); + connect( a, SIGNAL( triggered() ), this, SLOT( insertFunctionBlock() )); + addSubMenu->addAction(a); + + // feed the theoryFunctions popup menu + QMenu *theoryFunctions = new QMenu( tr("Add Theory Function"), this ); + for (unsigned int i=0; igetTheoryCounts(); i++) { + PTheory *theoryItem = fAdmin->getTheoryItem(i); + a = new QAction( theoryItem->label, this); + theoryFunctions->addAction(a); + } + connect( theoryFunctions, SIGNAL( triggered(QAction*)), this, SLOT( insertTheoryFunction(QAction*) ) ); + + a = new QAction( tr("Asymmetry Run Block"), this ); + a->setStatusTip( tr("Invokes MSR Asymmetry Run Block Dialog") ); + connect( a, SIGNAL( triggered() ), this, SLOT( insertAsymRunBlock() )); + addSubMenu->addAction(a); + + a = new QAction( tr("Single Histo Run Block"), this ); + a->setStatusTip( tr("Invokes MSR Single Histo Run Block Dialog") ); + connect( a, SIGNAL( triggered() ), this, SLOT( insertSingleHistRunBlock() )); + addSubMenu->addAction(a); + + a = new QAction( tr("NonMuSR Run Block"), this ); + a->setStatusTip( tr("Invokes MSR NonMuSR Run Block Dialog") ); + connect( a, SIGNAL( triggered() ), this, SLOT( insertNonMusrRunBlock() )); + addSubMenu->addAction(a); + + a = new QAction( tr("Command Block"), this ); + a->setStatusTip( tr("Invokes MSR Command Block Dialog") ); + connect( a, SIGNAL( triggered() ), this, SLOT( insertCommandBlock() )); + addSubMenu->addAction(a); + + a = new QAction( tr("Fourier Block"), this ); + a->setStatusTip( tr("Invokes MSR Fourier Block Dialog") ); + connect( a, SIGNAL( triggered() ), this, SLOT( insertFourierBlock() )); + addSubMenu->addAction(a); + + a = new QAction( tr("Plot Block"), this ); + a->setStatusTip( tr("Invokes MSR Plot Block Dialog") ); + connect( a, SIGNAL( triggered() ), this, SLOT( insertPlotBlock() )); + addSubMenu->addAction(a); + + a = new QAction( tr("Statistic Block"), this ); + a->setStatusTip( tr("Invokes MSR Statistic Block Dialog") ); + connect( a, SIGNAL( triggered() ), this, SLOT( insertStatisticBlock() )); + addSubMenu->addAction(a); + + menu->addMenu(addSubMenu); + menu->addMenu(theoryFunctions); + menu->addSeparator(); + + a = new QAction( tr( "Co&mment" ), this ); + a->setShortcut( tr("Ctrl+M") ); + a->setStatusTip( tr("Edit Comment Selected Lines") ); + connect( a, SIGNAL( triggered() ), this, SLOT( editComment() ) ); + menu->addAction(a); + + a = new QAction( tr( "Unco&mment" ), this ); + a->setShortcut( tr("Ctrl+Shift+M") ); + a->setStatusTip( tr("Edit Uncomment Selected Lines") ); + connect( a, SIGNAL( triggered() ), this, SLOT( editUncomment() ) ); + menu->addAction(a); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Setup the font/font size menu. + */ +void PTextEdit::setupTextActions() +{ + QToolBar *tb = new QToolBar( this ); + tb->setWindowTitle( "Format Actions" ); + addToolBar( tb ); + + fComboFont = new QComboBox(); + fComboFont->setEditable(true); + QFontDatabase db; + fComboFont->addItems( db.families() ); + connect( fComboFont, SIGNAL( currentTextChanged( const QString & ) ), + this, SLOT( textFamily( const QString & ) ) ); + QLineEdit *edit = fComboFont->lineEdit(); + if (edit == nullptr) { + return; + } + edit->setText( fAdmin->getFontName() ); + tb->addWidget(fComboFont); + + fComboSize = new QComboBox( tb ); + fComboSize->setEditable(true); + QList sizes = db.standardSizes(); + QList::Iterator it = sizes.begin(); + for ( ; it != sizes.end(); ++it ) + fComboSize->addItem( QString::number( *it ) ); + connect( fComboSize, SIGNAL( currentTextChanged( const QString & ) ), + this, SLOT( textSize( const QString & ) ) ); + edit = fComboSize->lineEdit(); + if (edit == nullptr) { + return; + } + edit->setText( QString("%1").arg(fAdmin->getFontSize()) ); + tb->addWidget(fComboSize); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Setup the musrfit menu and the necessary actions. + */ +void PTextEdit::setupMusrActions() +{ + addToolBarBreak(); + + QToolBar *tb = new QToolBar( this ); + tb->setWindowTitle( "Musr Actions" ); + addToolBar( tb ); + + QMenu *menu = new QMenu( tr( "&MusrFit" ), this ); + menuBar()->addMenu( menu ); + + QAction *a; + QString iconName(""); + + // musrWiz + if (fDarkMenuIcon) + iconName = QString(":/icons/musrWiz-32x32-dark.svg"); + else + iconName = QString(":/icons/musrWiz-32x32.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "musr&Wiz" ), this ); + a->setShortcut( tr("Alt+W") ); + a->setStatusTip( tr("Call musrWiz which helps to create msr-files") ); + connect( a, SIGNAL( triggered() ), this, SLOT( musrWiz() ) ); + menu->addAction(a); + fActions["musrWiz"] = a; + + if (!fDarkToolBarIcon) { // tool bar icon is not dark, even though the theme is (ubuntu) + iconName = QString(":/icons/musrWiz-32x32.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "musr&Wiz" ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( musrWiz() ) ); + } + tb->addAction(a); + fActions["musrWiz-tb"] = a; + + menu->addSeparator(); + tb->addSeparator(); + + // Calculate Chisq + if (fDarkMenuIcon) + iconName = QString(":/icons/musrchisq-dark.svg"); + else + iconName = QString(":/icons/musrchisq-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "Calculate &Chisq" ), this ); + a->setShortcut( tr("Alt+C") ); + a->setStatusTip( tr("Calculate Chi Square (Log Max Likelihood)") ); + connect( a, SIGNAL( triggered() ), this, SLOT( musrCalcChisq() ) ); + menu->addAction(a); + fActions["calcChisq"] = a; + + if (!fDarkToolBarIcon) { // tool bar icon is not dark, even though the theme is (ubuntu) + iconName = QString(":/icons/musrchisq-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "Calculate &Chisq" ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( musrCalcChisq() ) ); + } + tb->addAction(a); + fActions["calcChisq-tb"] = a; + + // musrfit + if (fDarkMenuIcon) + iconName = QString(":/icons/musrfit-dark.svg"); + else + iconName = QString(":/icons/musrfit-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&Fit" ), this ); + a->setShortcut( tr("Alt+F") ); + a->setStatusTip( tr("Fit") ); + connect( a, SIGNAL( triggered() ), this, SLOT( musrFit() ) ); + menu->addAction(a); + fActions["musrfit"] = a; + + if (!fDarkToolBarIcon) { // tool bar icon is not dark, even though the theme is (ubuntu) + iconName = QString(":/icons/musrfit-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&Fit" ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( musrFit() ) ); + } + tb->addAction(a); + fActions["musrfit-tb"] = a; + + // Swap Msr/Mlog + if (fDarkMenuIcon) + iconName = QString(":/icons/musrswap-dark.svg"); + else + iconName = QString(":/icons/musrswap-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&Swap Msr <-> Mlog" ), this ); + a->setShortcut( tr("Alt+S") ); + a->setStatusTip( tr("Swap msr-file <-> mlog-file") ); + connect( a, SIGNAL( triggered() ), this, SLOT( musrSwapMsrMlog() ) ); + menu->addAction(a); + fActions["Swap Msr/Mlog"] = a; + + if (!fDarkToolBarIcon) { // tool bar icon is not dark, even though the theme is (ubuntu) + iconName = QString(":/icons/musrswap-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&Swap Msr <-> Mlog" ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( musrSwapMsrMlog() ) ); + } + tb->addAction(a); + fActions["Swap Msr/Mlog-tb"] = a; + + // musrStep + if (fDarkMenuIcon) + iconName = QString(":/icons/musrStep-32x32-dark.svg"); + else + iconName = QString(":/icons/musrStep-32x32.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "Set Ste&ps" ), this ); + a->setShortcut( tr("Alt+P") ); + a->setStatusTip( tr("Set Steps") ); + connect( a, SIGNAL( triggered() ), this, SLOT( musrSetSteps() ) ); + menu->addAction(a); + fActions["musrStep"] = a; + + if (!fDarkToolBarIcon) { // tool bar icon is not dark, even though the theme is (ubuntu) + iconName = QString(":/icons/musrStep-32x32.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "Set Ste&ps" ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( musrSetSteps() ) ); + } + tb->addAction(a); + fActions["musrStep-tb"] = a; + + // msr2data + if (fDarkMenuIcon) + iconName = QString(":/icons/msr2data-dark.svg"); + else + iconName = QString(":/icons/msr2data-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "Msr&2Data" ), this ); + a->setShortcut( tr("Alt+2") ); + a->setStatusTip( tr("Start msr2data interface") ); + connect( a, SIGNAL( triggered() ), this, SLOT( musrMsr2Data() ) ); + menu->addAction(a); + fActions["msr2data"] = a; + + if (!fDarkToolBarIcon) { // tool bar icon is not dark, even though the theme is (ubuntu) + iconName = QString(":/icons/msr2data-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&Msr2Data" ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( musrMsr2Data() ) ); + } + tb->addAction(a); + fActions["msr2data-tb"] = a; + + // mupp + if (fDarkMenuIcon) + iconName = QString(":/icons/mupp-dark.svg"); + else + iconName = QString(":/icons/mupp-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "m&upp" ), this ); + a->setShortcut( tr("Alt+U") ); + a->setStatusTip( tr("Start mupp, the muSR parameter plotter") ); + connect( a, SIGNAL( triggered() ), this, SLOT( mupp() ) ); + menu->addAction(a); + fActions["mupp"] = a; + + if (!fDarkToolBarIcon) { // tool bar icon is not dark, even though the theme is (ubuntu) + iconName = QString(":/icons/mupp-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "m&upp" ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( mupp() ) ); + } + tb->addAction(a); + fActions["mupp-tb"] = a; + + menu->addSeparator(); + tb->addSeparator(); + + // musrview + if (fDarkMenuIcon) + iconName = QString(":/icons/musrview-dark.svg"); + else + iconName = QString(":/icons/musrview-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&View" ), this ); + a->setShortcut( tr("Alt+V") ); + a->setStatusTip( tr("Start musrview") ); + connect( a, SIGNAL( triggered() ), this, SLOT( musrView() ) ); + menu->addAction(a); + fActions["musrview"] = a; + + if (!fDarkToolBarIcon) { // tool bar icon is not dark, even though the theme is (ubuntu) + iconName = QString(":/icons/musrview-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&View" ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( musrView() ) ); + } + tb->addAction(a); + fActions["musrview-tb"] = a; + + // musrt0 + if (fDarkMenuIcon) + iconName = QString(":/icons/musrt0-dark.svg"); + else + iconName = QString(":/icons/musrt0-plain.svg"); + fMusrT0Action = new QAction( QIcon( QPixmap(iconName) ), tr( "&T0" ), this ); + fMusrT0Action->setStatusTip( tr("Start musrt0") ); + connect( fMusrT0Action, SIGNAL( triggered() ), this, SLOT( musrT0() ) ); + menu->addAction(fMusrT0Action); + fActions["musrt0"] = fMusrT0Action; + if (!fDarkToolBarIcon) { // tool bar icon is not dark, even though the theme is (ubuntu) + iconName = QString(":/icons/musrt0-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&T0" ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( musrT0() ) ); + } + tb->addAction(fMusrT0Action); + fMusrT0Action->setEnabled(fAdmin->getEnableMusrT0Flag()); + fActions["musrt0-tb"] = fMusrT0Action; + + // musrFT + if (fDarkMenuIcon) + iconName = QString(":/icons/musrFT-dark.svg"); + else + iconName = QString(":/icons/musrFT-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "Raw Fourier" ), this ); + a->setStatusTip( tr("Start musrFT") ); + connect( a, SIGNAL( triggered() ), this, SLOT( musrFT() ) ); + menu->addAction(a); + fActions["musrFT"] = a; + + if (!fDarkToolBarIcon) { // tool bar icon is not dark, even though the theme is (ubuntu) + iconName = QString(":/icons/musrFT-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "Raw Fourier" ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( musrFT() ) ); + } + tb->addAction(a); + fActions["musrFT-tb"] = a; + + // musrprefs + if (fDarkMenuIcon) + iconName = QString(":/icons/musrprefs-dark.svg"); + else + iconName = QString(":/icons/musrprefs-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&Preferences" ), this ); + a->setStatusTip( tr("Show Preferences") ); + connect( a, SIGNAL( triggered() ), this, SLOT( musrPrefs() ) ); + menu->addAction(a); + fActions["musrprefs"] = a; + + if (!fDarkToolBarIcon) { // tool bar icon is not dark, even though the theme is (ubuntu) + iconName = QString(":/icons/musrprefs-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&Preferences" ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( musrPrefs() ) ); + } + tb->addAction(a); + fActions["musrprefs-tb"] = a; + + menu->addSeparator(); + tb->addSeparator(); + + // musrdump + if (fDarkMenuIcon) + iconName = QString(":/icons/musrdump-dark.svg"); + else + iconName = QString(":/icons/musrdump-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName)), tr( "&Dump Header"), this); + a->setStatusTip( tr("Dumps muSR File Header Information") ); + connect( a, SIGNAL(triggered()), this, SLOT(musrDump())); + menu->addAction(a); + fActions["musrdump"] = a; + if (!fDarkToolBarIcon) { // tool bar icon is not dark, even though the theme is (ubuntu) + iconName = QString(":/icons/musrdump-plain.svg"); + a = new QAction( QIcon( QPixmap(iconName) ), tr( "&Dump Header" ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( musrDump() ) ); + } + tb->addAction(a); + fActions["musrdump-tb"] = a; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Setup the help menu and the necessary actions. + */ +void PTextEdit::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( "Author(s) ..." ), this ); + a->setStatusTip( tr("Help About") ); + 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); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

load a msr-file. + * + * \param f filename + * \param index if == -1, add the file as a new tab, otherwise, replace the contents of the tab at index. + */ +void PTextEdit::load( const QString &f, const int index ) +{ + // check if the file exists + if ( !QFile::exists( f ) ) + return; + + // create a new text edit object + PSubTextEdit *edit = new PSubTextEdit( fAdmin ); + edit->setFont(QFont(fAdmin->getFontName(), fAdmin->getFontSize())); + + // place the text edit object at the appropriate tab position + if (index == -1) + fTabWidget->addTab( edit, QFileInfo( f ).fileName() ); + else + fTabWidget->insertTab( index, edit, QFileInfo( f ).fileName() ); + QFile file( f ); + if ( !file.open( QIODevice::ReadOnly ) ) + return; + + // add file name to recent file names + fAdmin->addRecentFile(f); // keep it in admin + fillRecentFiles(); // update menu + + // add the msr-file to the file system watchersssss + fFileSystemWatcher->addPath(f); + + // read the file + QTextStream ts( &file ); + QString txt = ts.readAll(); + edit->setPlainText( txt ); + doConnections( edit ); // add all necessary signal/slot connections + + // set the tab widget to the current tab + fTabWidget->setCurrentIndex(fTabWidget->indexOf(edit)); + edit->viewport()->setFocus(); + + // update the filename mapper + fFilenames.remove( edit ); + fFilenames.insert( edit, f ); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

returns the currently tab selected textedit object. + */ +PSubTextEdit *PTextEdit::currentEditor() const +{ + if (fTabWidget == nullptr) + return nullptr; + + if ( fTabWidget->currentWidget() ) { + if (fTabWidget->currentWidget()->inherits( "PSubTextEdit" )) { + return dynamic_cast(fTabWidget->currentWidget()); + } + } + + return nullptr; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Setup the necessray signal/slot connections for the textedit object. + * + * \param e textedit object + */ +void PTextEdit::doConnections( PSubTextEdit *e ) +{ +// connect( e, SIGNAL( currentFontChanged( const QFont & ) ), +// this, SLOT( fontChanged( const QFont & ) ) ); + + connect( e, SIGNAL( textChanged() ), this, SLOT( textChanged() )); + + connect( e, SIGNAL( cursorPositionChanged() ), this, SLOT( currentCursorPosition() )); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Start the dialog to enter a msr-file title. See also http://lmu.web.psi.ch/musrfit/user/html/user-manual.html#the-title + */ +void PTextEdit::insertTitle() +{ + currentEditor()->insertTitle(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Start the dialog to enter a msr-file fit-parameter block. See also http://lmu.web.psi.ch/musrfit/user/html/user-manual.html#the-fitparameter-block + */ +void PTextEdit::insertParameterBlock() +{ + currentEditor()->insertParameterBlock(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Start the dialog to enter a msr-file theory block. See also http://lmu.web.psi.ch/musrfit/user/html/user-manual.html#the-theory-block + */ +void PTextEdit::insertTheoryBlock() +{ + currentEditor()->insertTheoryBlock(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Insert a selected theory function. See also http://lmu.web.psi.ch/musrfit/user/html/user-manual.html#the-theory-block + * + * \param a action of the selected theory function + */ +void PTextEdit::insertTheoryFunction(QAction *a) +{ + currentEditor()->insertTheoryFunction(a->text()); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Start the dialog to enter a msr-file function block. See also http://lmu.web.psi.ch/musrfit/user/html/user-manual.html#the-functions-block + */ +void PTextEdit::insertFunctionBlock() +{ + currentEditor()->insertFunctionBlock(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Start the dialog to enter a msr-file asymmetry run block. See also http://lmu.web.psi.ch/musrfit/user/html/user-manual.html#the-run-block + */ +void PTextEdit::insertAsymRunBlock() +{ + currentEditor()->insertAsymRunBlock(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Start the dialog to enter a msr-file single histogram run block. See also http://lmu.web.psi.ch/musrfit/user/html/user-manual.html#the-run-block + */ +void PTextEdit::insertSingleHistRunBlock() +{ + currentEditor()->insertSingleHistRunBlock(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Start the dialog to enter a msr-file nonMusr run block. See also http://lmu.web.psi.ch/musrfit/user/html/user-manual.html#the-run-block + */ +void PTextEdit::insertNonMusrRunBlock() +{ + currentEditor()->insertNonMusrRunBlock(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Inserts a default command block. See also http://lmu.web.psi.ch/musrfit/user/html/user-manual.html#the-commands-block + */ +void PTextEdit::insertCommandBlock() +{ + currentEditor()->insertCommandBlock(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Start the dialog to enter a msr-file Fourier block. See also http://lmu.web.psi.ch/musrfit/user/html/user-manual.html#the-fourier-block + */ +void PTextEdit::insertFourierBlock() +{ + currentEditor()->insertFourierBlock(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Start the dialog to enter a msr-file plot block. See also http://lmu.web.psi.ch/musrfit/user/html/user-manual.html#the-plot-block + */ +void PTextEdit::insertPlotBlock() +{ + currentEditor()->insertPlotBlock(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Inserts a default statistics block. See also http://lmu.web.psi.ch/musrfit/user/html/user-manual.html#the-statistic-block + */ +void PTextEdit::insertStatisticBlock() +{ + currentEditor()->insertStatisticBlock(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT: called when File/New is selected. Will generate an empty tab-textedit field in musredit. + */ +void PTextEdit::fileNew() +{ + PSubTextEdit *edit = new PSubTextEdit( fAdmin ); + edit->setFont(QFont(fAdmin->getFontName(), fAdmin->getFontSize())); + doConnections( edit ); + fTabWidget->addTab( edit, tr( "noname" ) ); + fTabWidget->setCurrentIndex(fTabWidget->indexOf(edit)); + fFilenames.insert(edit, tr("noname")); + edit->viewport()->setFocus(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT: called when File/Open is selected. Will open an msr-/mlog-file. It checks if the file is + * already open, and if so will just select the current tab. If you want to reload the file use the + * fileReload() slot. + */ +void PTextEdit::fileOpen() +{ + QStringList flns = QFileDialog::getOpenFileNames( this, tr("Open msr-/mlog-File"), + fLastDirInUse, + tr( "msr-Files (*.msr);;msr-Files (*.msr *.mlog);;All Files (*)" )); + + QStringList::Iterator it = flns.begin(); + QFileInfo finfo1; + bool alreadyOpen = false; + int idx; + + // if flns are present, keep the corresponding directory + if (flns.size() > 0) { + finfo1.setFile(flns.at(0)); + fLastDirInUse = finfo1.absoluteFilePath(); + } + + while( it != flns.end() ) { + // check if the file is not already open + finfo1.setFile(*it); + alreadyOpen = fileAlreadyOpen(finfo1, idx); + + if (!alreadyOpen) { + load(*it); + } else { + fTabWidget->setCurrentIndex(idx); + fileReload(); + } + + ++it; + } + + // in case there is a 1st empty tab "noname", remove it + QString tabStr = fTabWidget->tabText(0); + tabStr.remove('&'); // this is needed since the QTabWidget adds short-cut info as '&' to the tab name + if (tabStr == "noname") { // has to be the first, otherwise do nothing + fFileSystemWatcher->removePath("noname"); + + delete fTabWidget->widget(0); + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

This slot will open the file from the recent file list. If already open, it will reload it. + */ +void PTextEdit::fileOpenRecent() +{ + QAction *action = qobject_cast(sender()); + + if (action) { + // check if this file is already open and if so, switch the tab + QFileInfo finfo1, finfo2; + QString tabFln; + bool alreadyOpen = false; + QString fln = action->text(); + fln.remove('&'); + finfo1.setFile(fln); + + for (int i=0; icount(); i++) { + tabFln = *fFilenames.find( dynamic_cast(fTabWidget->widget(i))); + finfo2.setFile(tabFln); + if (finfo1.absoluteFilePath() == finfo2.absoluteFilePath()) { + alreadyOpen = true; + fTabWidget->setCurrentIndex(i); + break; + } + } + + if (!alreadyOpen) { + // make sure the file exists + if (!finfo1.exists()) { + QMessageBox::critical(this, "ERROR", QString("File '%1' does not exist.\nWill not do anything.").arg(fln)); + return; + } + load(fln); + } else { + fileReload(); + } + + // in case there is a 1st empty tab "noname", remove it + fln = fTabWidget->tabText(0); + fln.remove("&"); + if (fln == "noname") { // has to be the first, otherwise do nothing + fFileSystemWatcher->removePath("noname"); + + delete fTabWidget->widget(0); + } + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Will reload the currently selected msr-file. + */ +void PTextEdit::fileReload() +{ + if ( fFilenames.find( currentEditor() ) == fFilenames.end() ) { + QMessageBox::critical(this, "**ERROR**", "Cannot reload a file not previously saved ;-)"); + } else { + int index = fTabWidget->currentIndex(); + QString fln = *fFilenames.find( currentEditor() ); + fileClose(false); + load(fln, index); + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Will save the currently selected file. + */ +void PTextEdit::fileOpenPrefs() +{ + QString fln(""); + QString msg(""); + QMessageBox msgBox; + msgBox.setText("Which Preferences do you want to open?"); + msgBox.addButton("Default", QMessageBox::AcceptRole); + msgBox.addButton("Custom", QMessageBox::AcceptRole); + msgBox.setStandardButtons(QMessageBox::Cancel); + int result = msgBox.exec(); + if (result == QMessageBox::Cancel) { + return; + } else if (result == 0) { // default dir + fln = fAdmin->getDefaultPrefPathName(); + msg = QString("Current Default Preferences Path-Name:\n") + fln; + if (QMessageBox::information(this, "Info", msg, QMessageBox::Ok, QMessageBox::Cancel) == QMessageBox::Cancel) + return; + } else if (result == 1) { // custom dir + fln = QFileDialog::getOpenFileName( this, tr("Open Prefs"), + fLastDirInUse, + tr( "xml-Files (*.xml);; All Files (*)" )); + } + + if (fAdmin->loadPrefs(fln)) { + msg = QString("Prefs from '") + fln + QString("' loaded."); + QMessageBox::information(nullptr, "Info", msg); + } + + // make sure that dark/plain icon scheme is properly loaded + if (getTheme()) { + switchMenuIcons(); + switchToolbarIcons(); + } + + if (fAdmin->getDarkThemeIconsMenuFlag() != fDarkMenuIcon) { + fDarkMenuIcon = !fDarkMenuIcon; + switchMenuIcons(); + } + + if (fAdmin->getDarkThemeIconsToolbarFlag() != fDarkToolBarIcon) { + fDarkToolBarIcon = !fDarkToolBarIcon; + switchToolbarIcons(); + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Will save the currently selected file. + */ +void PTextEdit::fileSave() +{ + if ( !currentEditor() ) + return; + + fFileSystemWatcherActive = false; + + if ( *fFilenames.find( currentEditor() ) == QString("noname") ) { + fileSaveAs(); + } else { + QFile file( *fFilenames.find( currentEditor() ) ); + if ( !file.open( QIODevice::WriteOnly ) ) { + QMessageBox::critical(this, "**ERROR**", "Couldn't save the file!\nDisk full?\nNo write access?"); + return; + } + QTextStream ts( &file ); + ts << currentEditor()->toPlainText(); + + // remove trailing '*' modification indicators + QString fln = *fFilenames.find( currentEditor() ); + fTabWidget->setTabText(fTabWidget->indexOf( currentEditor() ), QFileInfo(fln).fileName()); + } + + fileSystemWatcherActivation(); // delayed activation of fFileSystemWatcherActive +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Will open a file selector dialog to obtain a file name, and then save the file under the newly + * selected file name. + */ +void PTextEdit::fileSaveAs() +{ + if ( !currentEditor() ) + return; + + fFileSystemWatcherActive = false; + + QString fn = QFileDialog::getSaveFileName( this, + tr( "Save msr-/mlog-file As" ), *fFilenames.find( currentEditor() ), + tr( "msr-Files (*.msr *.mlog);;All Files (*)" ) ); + if ( !fn.isEmpty() ) { + fFilenames.remove( currentEditor() ); + fFilenames.insert( currentEditor(), fn ); + fileSave(); + } + + fileSystemWatcherActivation(); // delayed activation of fFileSystemWatcherActive +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Will save the current preferences. + */ +void PTextEdit::fileSavePrefs() +{ + QString fln(""); + QString msg(""); + QMessageBox msgBox; + msgBox.setText("Which Preferences do you want to open?"); + msgBox.addButton("Default", QMessageBox::AcceptRole); + msgBox.addButton("Custom", QMessageBox::AcceptRole); + msgBox.setStandardButtons(QMessageBox::Cancel); + int result = msgBox.exec(); + if (result == QMessageBox::Cancel) { + return; + } else if (result == 0) { // default dir + fln = fAdmin->getDefaultPrefPathName(); + msg = QString("Current Default Preferences Path-Name:\n") + fln; + if (QMessageBox::information(this, "Info", msg, QMessageBox::Ok, QMessageBox::Cancel) == QMessageBox::Cancel) + return; + } else if (result == 1) { // custom dir + fln = QFileDialog::getSaveFileName( this, + tr( "Save Prefs As" ), "musredit_startup.xml", + tr( "xml-Files (*.xml);;All Files (*)" ) ); + } + + if ( !fln.isEmpty() ) { + fAdmin->savePrefs(fln); + msg = QString("Prefs to '") + fln + QString("' saved."); + QMessageBox::information(nullptr, "Info", msg); + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Will call a print dialog and print the msr-file. + */ +void PTextEdit::filePrint() +{ + if ( !currentEditor() ) + return; +#ifndef QT_NO_PRINTER + QPrinter printer( QPrinter::HighResolution ); + printer.setFullPage(true); + QPrintDialog dialog(&printer, this); + if (dialog.exec()) { // printer dialog + statusBar()->showMessage( "Printing..." ); + + QPainter p( &printer ); + // Check that there is a valid device to print to. + if ( !p.device() ) + return; + + QFont font( currentEditor()->QWidget::font() ); + font.setPointSize( 10 ); // we define 10pt to be a nice base size for printing + p.setFont( font ); + + int yPos = 0; // y-position for each line + QFontMetrics fm = p.fontMetrics(); + int dpiy = printer.logicalDpiY(); + int margin = static_cast( (2/2.54)*dpiy ); // 2 cm margins + + // print msr-file + QString fln = *fFilenames.find(currentEditor()); + QString header1(fln); + QFileInfo flnInfo(fln); + QString header2 = QString("last modified: ") + flnInfo.lastModified().toString("dd.MM.yyyy - hh:mm:ss"); + QString line("-------------------------------------"); + QStringList strList = currentEditor()->toPlainText().split("\n"); + for (QStringList::Iterator it = strList.begin(); it != strList.end(); ++it) { + // new page needed? + if ( margin + yPos > printer.height() - margin ) { + printer.newPage(); // no more room on this page + yPos = 0; // back to top of page + } + + if (yPos == 0) { // print header + font.setPointSize( 8 ); + p.setFont( font ); + + p.drawText(margin, margin+yPos, printer.width(), fm.lineSpacing(), + Qt::TextExpandTabs | Qt::TextDontClip, header1); + yPos += fm.lineSpacing(); + p.drawText(margin, margin+yPos, printer.width(), fm.lineSpacing(), + Qt::TextExpandTabs | Qt::TextDontClip, header2); + yPos += fm.lineSpacing(); + p.drawText(margin, margin+yPos, printer.width(), fm.lineSpacing(), + Qt::TextExpandTabs | Qt::TextDontClip, line); + yPos += 1.5*fm.lineSpacing(); + + font.setPointSize( 10 ); + p.setFont( font ); + } + + // print data + p.drawText(margin, margin+yPos, printer.width(), fm.lineSpacing(), + Qt::TextExpandTabs | Qt::TextDontClip, *it); + yPos += fm.lineSpacing(); + } + + p.end(); + } +#endif +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Will remove a textedit tab from musredit. Depending on check it will done with or without checking + * if the file has been saved before. + * + * \param check if set to true, a warning dialog will popup if the file is not saved yet. + */ +void PTextEdit::fileClose(const bool check) +{ + // first check if there is any tab present + if (fTabWidget->count()==0) // no tabs present + return; + + // check if the has modification + int idx = fTabWidget->currentIndex(); + + if ((fTabWidget->tabText(idx).indexOf("*")>0) && check) { + int result = QMessageBox::warning(this, "**WARNING**", + "Do you really want to close this file.\nChanges will be lost", + "Close", "Cancel"); + if (result == 1) // Cancel + return; + } + + QString str = *fFilenames.find(currentEditor()); + fFileSystemWatcher->removePath(str); + + delete currentEditor(); + + if ( currentEditor() ) + currentEditor()->viewport()->setFocus(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Removes all textedit tabs from musredit. It checks if the files haven't been saved, and if so it will + * popup a warning dialog. + */ +void PTextEdit::fileCloseAll() +{ + // check if any editor tab is present, if not: get out of here + if ( !currentEditor() ) + return; + + // check if there are any unsaved tabs + for (int i=0; icount(); i++) { + if (fTabWidget->tabText(i).indexOf("*") > 0) { + int result = QMessageBox::warning(this, "**WARNING**", + "Do you really want to close all files.\nChanges of unsaved files will be lost", + "Close", "Cancel"); + if (result == 1) // Cancel + return; + break; + } + } + + // close all editor tabs + QString str; + do { + // remove file from file system watcher + str = *fFilenames.find(currentEditor()); + fFileSystemWatcher->removePath(str); + + delete currentEditor(); + + if ( currentEditor() ) + currentEditor()->viewport()->setFocus(); + } while ( currentEditor() ); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Will close all textedit tabs but the selected one. It checks if the files haven't been saved, and if so it will + * popup a warning dialog. + */ +void PTextEdit::fileCloseAllOthers() +{ + // check if any editor tab is present, if not: get out of here + if ( !currentEditor() ) + return; + + // check if there are any unsaved tabs + for (int i=0; icount(); i++) { + if (fTabWidget->tabText(i).indexOf("*") > 0) { + int result = QMessageBox::warning(this, "**WARNING**", + "Do you really want to close all files.\nChanges of unsaved files will be lost", + "Close", "Cancel"); + if (result == 1) // Cancel + return; + break; + } + } + + // keep label of the current editor + QString label = fTabWidget->tabText(fTabWidget->currentIndex()); + + // check if only the current editor is present. If yes: nothing to be done + if (fTabWidget->count() == 1) + return; + + // close all editor tabs + int i=0; + QString str; + do { + if (fTabWidget->tabText(i) != label) { + // remove file from file system watcher + str = *fFilenames.find(dynamic_cast(fTabWidget->widget(i))); + fFileSystemWatcher->removePath(str); + + delete fTabWidget->widget(i); + } else { + i++; + } + } while ( fTabWidget->count() > 1 ); + + currentEditor()->viewport()->setFocus(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Will quit musredit. + */ +void PTextEdit::fileExit() +{ + // check if there are still some modified files open + for (int i=0; i < fTabWidget->count(); i++) { + if (fTabWidget->tabText(i).indexOf("*") > 0) { + int result = QMessageBox::warning(this, "**WARNING**", + "Do you really want to exit from the applcation.\nChanges will be lost", + "Exit", "Cancel"); + if (result == 1) // Cancel + return; + break; + } + } + + qApp->quit(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Text undo of the current textedit tab. + */ +void PTextEdit::editUndo() +{ + if ( !currentEditor() ) + return; + currentEditor()->undo(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Text redo of the current textedit tab + */ +void PTextEdit::editRedo() +{ + if ( !currentEditor() ) + return; + currentEditor()->redo(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Select all text of the current textedit tab. + */ +void PTextEdit::editSelectAll() +{ + if ( !currentEditor() ) + return; + currentEditor()->selectAll(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Cut the selection of the current textedit tab. + */ +void PTextEdit::editCut() +{ + if ( !currentEditor() ) + return; + currentEditor()->cut(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Copy the selection of the current textedit tab. + */ +void PTextEdit::editCopy() +{ + if ( !currentEditor() ) + return; + currentEditor()->copy(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Paste at the cursor position of the current textedit tab. + */ +void PTextEdit::editPaste() +{ + if ( !currentEditor() ) + return; + currentEditor()->paste(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Starts a find dialog, and searches for a find string. + */ +void PTextEdit::editFind() +{ + if ( !currentEditor() ) + return; + + // check if first time called, and if yes create find and replace data structure + if (fFindReplaceData == nullptr) { + fFindReplaceData = new PFindReplaceData(); + fFindReplaceData->findText = QString(""); + fFindReplaceData->replaceText = QString(""); + fFindReplaceData->caseSensitive = true; + fFindReplaceData->wholeWordsOnly = false; + fFindReplaceData->fromCursor = true; + fFindReplaceData->findBackwards = false; + fFindReplaceData->selectedText = false; + fFindReplaceData->promptOnReplace = true; + } + + if (fFindReplaceData == nullptr) { + QMessageBox::critical(this, "**ERROR**", "Couldn't invoke find data structure, sorry :-(", QMessageBox::Ok, QMessageBox::NoButton); + return; + } + + PFindDialog *dlg = new PFindDialog(fFindReplaceData, currentEditor()->textCursor().hasSelection()); + if (dlg == nullptr) { + QMessageBox::critical(this, "**ERROR**", "Couldn't invoke find dialog, sorry :-(", QMessageBox::Ok, QMessageBox::NoButton); + return; + } + + dlg->exec(); + + if (dlg->result() != QDialog::Accepted) { + delete dlg; + return; + } + + fFindReplaceData = dlg->getData(); + + delete dlg; + dlg = nullptr; + + // try to find the search text + if (!fFindReplaceData->fromCursor) + currentEditor()->textCursor().setPosition(0); + + QTextDocument::FindFlags flags; + if (fFindReplaceData->caseSensitive) + flags |= QTextDocument::FindCaseSensitively; + else if (fFindReplaceData->findBackwards) + flags |= QTextDocument::FindBackward; + else if (fFindReplaceData->wholeWordsOnly) + flags |= QTextDocument::FindWholeWords; + + currentEditor()->find(fFindReplaceData->findText, flags); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Searches for a find string in the forward direction. + */ +void PTextEdit::editFindNext() +{ + QTextDocument::FindFlags flags; + if (fFindReplaceData->caseSensitive) + flags |= QTextDocument::FindCaseSensitively; + else if (fFindReplaceData->wholeWordsOnly) + flags |= QTextDocument::FindWholeWords; + + currentEditor()->find(fFindReplaceData->findText, flags); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Searches for a find string in the backward direction. + */ +void PTextEdit::editFindPrevious() +{ + QTextDocument::FindFlags flags; + if (fFindReplaceData->caseSensitive) + flags |= QTextDocument::FindCaseSensitively; + else if (fFindReplaceData->wholeWordsOnly) + flags |= QTextDocument::FindWholeWords; + + flags |= QTextDocument::FindBackward; + + currentEditor()->find(fFindReplaceData->findText, flags); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Starts a find/replace dialog, and searches for a find string and replaces it depending of the replace options. + */ +void PTextEdit::editFindAndReplace() +{ + if ( !currentEditor() ) + return; + + // check if first time called, and if yes create find and replace data structure + if (fFindReplaceData == nullptr) { + fFindReplaceData = new PFindReplaceData(); + fFindReplaceData->findText = QString(""); + fFindReplaceData->replaceText = QString(""); + fFindReplaceData->caseSensitive = true; + fFindReplaceData->wholeWordsOnly = false; + fFindReplaceData->fromCursor = true; + fFindReplaceData->findBackwards = false; + fFindReplaceData->selectedText = false; + fFindReplaceData->promptOnReplace = true; + } + + if (fFindReplaceData == nullptr) { + QMessageBox::critical(this, "**ERROR**", "Couldn't invoke find&replace data structure, sorry :-(", QMessageBox::Ok, QMessageBox::NoButton); + return; + } + + PReplaceDialog *dlg = new PReplaceDialog(fFindReplaceData, currentEditor()->textCursor().hasSelection()); + if (dlg == nullptr) { + QMessageBox::critical(this, "**ERROR**", "Couldn't invoke find&replace dialog, sorry :-(", QMessageBox::Ok, QMessageBox::NoButton); + return; + } + + dlg->exec(); + + if (dlg->result() != QDialog::Accepted) { + delete dlg; + return; + } + + fFindReplaceData = dlg->getData(); + + delete dlg; + dlg = nullptr; + + if (fFindReplaceData->promptOnReplace) { + editFindNext(); + + PReplaceConfirmationDialog confirmDlg(this); + + // connect all the necessary signals/slots + QObject::connect(confirmDlg.fReplace_pushButton, SIGNAL(clicked()), this, SLOT(replace())); + QObject::connect(confirmDlg.fReplaceAndClose_pushButton, SIGNAL(clicked()), this, SLOT(replaceAndClose())); + QObject::connect(confirmDlg.fReplaceAll_pushButton, SIGNAL(clicked()), this, SLOT(replaceAll())); + QObject::connect(confirmDlg.fFindNext_pushButton, SIGNAL(clicked()), this, SLOT(editFindNext())); + QObject::connect(this, SIGNAL(close()), &confirmDlg, SLOT(accept())); + + confirmDlg.exec(); + } else { + replaceAll(); + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Comment a selection, i.e. add a '#' character in front of each line of the selection. + * (Multiple selections not yet supported). + */ +void PTextEdit::editComment() +{ + if ( !currentEditor() ) + return; + + + QTextCursor curs = currentEditor()->textCursor(); + + if (curs.hasComplexSelection()) { // multiple selections + // multiple selections (STILL MISSING) + } else if (curs.hasSelection()) { // simple selection + int pos = curs.position(); + int secStart = curs.selectionStart(); // keep start position of the selection + int secEnd = curs.selectionEnd(); // keep end position of the selection + curs.clearSelection(); + curs.setPosition(secStart); // set the anchor to the start of the selection + curs.movePosition(QTextCursor::StartOfBlock); + do { + curs.insertText("#"); + } while (curs.movePosition(QTextCursor::NextBlock) && (curs.position() <= secEnd)); + curs.setPosition(pos+1); + } else { // no selection + int pos = curs.position(); + curs.clearSelection(); + curs.movePosition(QTextCursor::StartOfLine); + curs.insertText("#"); + curs.setPosition(pos+1); + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Uncomment a selection, i.e. remove a '#' character in front of each line of the selection. + * (Multiple selections not yet supported). + */ +void PTextEdit::editUncomment() +{ + if ( !currentEditor() ) + return; + + + QTextCursor curs = currentEditor()->textCursor(); + + if (curs.hasComplexSelection()) { + // multiple selections (STILL MISSING) + } else if (curs.hasSelection()) { + int pos = curs.position(); + int secStart = curs.selectionStart(); // keep start position of the selection + int secEnd = curs.selectionEnd(); // keep end position of the selection + curs.clearSelection(); + curs.setPosition(secStart); // set the anchor to the start of the selection + curs.movePosition(QTextCursor::StartOfBlock); + while (curs.position() < secEnd) { + QString line = curs.block().text(); + if (line.startsWith("#")) { + line.remove(0, 1); + curs.select(QTextCursor::BlockUnderCursor); + curs.removeSelectedText(); + curs.insertText("\n"+line); + pos -= 1; + } + curs.movePosition(QTextCursor::NextBlock); + } + curs.setPosition(pos); + currentEditor()->setTextCursor(curs); // needed to update document cursor + } else { // no selection + int pos = curs.position(); + curs.clearSelection(); + curs.movePosition(QTextCursor::StartOfLine, QTextCursor::MoveAnchor, 1); + QString line = curs.block().text(); + if (line.startsWith("#")) { + line.remove(0, 1); + curs.select(QTextCursor::BlockUnderCursor); + curs.removeSelectedText(); + if (currentEditor()->textCursor().columnNumber() == 0) + curs.insertText(line); + else + curs.insertText("\n"+line); + pos -= 1; + } + curs.setPosition(pos); + currentEditor()->setTextCursor(curs); // needed to update document cursor + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Changes the font. + * + * \param f font name + */ +void PTextEdit::textFamily( const QString &f ) +{ + fAdmin->setFontName(f); + + if ( currentEditor() == nullptr ) + return; + + currentEditor()->setFont(QFont(f,fAdmin->getFontSize())); + currentEditor()->viewport()->setFocus(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Changes the font size. + * + * \param p font size in points. + */ +void PTextEdit::textSize( const QString &p ) +{ + fAdmin->setFontSize(p.toInt()); + + if ( currentEditor() == nullptr) + return; + + currentEditor()->setFont(QFont(fAdmin->getFontName(), p.toInt())); + currentEditor()->viewport()->setFocus(); +} + +//---------------------------------------------------------------------------------------------------- +/** + * @brief PTextEdit::musrWiz + */ +void PTextEdit::musrWiz() +{ + QString cmd = fAdmin->getExecPath() + "/musrWiz"; +#if defined(Q_OS_DARWIN) || defined(Q_OS_MAC) + cmd = QString("/Applications/musrWiz.app/Contents/MacOS/musrWiz"); +#endif + QString workDir = "./"; // think about it!! + QStringList arg; + arg << "--log"; + + QProcess *proc = new QProcess(this); + if (proc == nullptr) { + QMessageBox::critical(nullptr, "**ERROR**", "Couldn't invoke QProcess!"); + return; + } + + // handle return status of musrWiz + connect(proc, static_cast(&QProcess::finished), + [=](int exitCode, QProcess::ExitStatus exitStatus){ exitStatusMusrWiz(exitCode, exitStatus); }); + + // make sure that the system environment variables are properly set + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + env.insert("LD_LIBRARY_PATH", env.value("ROOTSYS") + "/lib:" + env.value("LD_LIBRARY_PATH")); + proc->setProcessEnvironment(env); + proc->setWorkingDirectory(workDir); + proc->start(cmd, arg); + if (!proc->waitForStarted()) { + // error handling + QString msg(tr("Could not execute the output command: ")+cmd[0]); + QMessageBox::critical( nullptr, + tr("Fatal error"), + msg, + tr("Quit") ); + return; + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

calls musrfit --chisq-only . + */ +void PTextEdit::musrCalcChisq() +{ + if ( !currentEditor() ) + return; + + int result = 0; + int fittype = currentEditor()->getFitType(); + if (fAdmin->getEstimateN0Flag() && ((fittype==0) || (fittype==4))) + result = QMessageBox::question(this, "Estimate N0 active", + "Do you wish a chisq/mlh evaluation with an automatic N0 estimate?"); + + QString tabLabel = fTabWidget->tabText(fTabWidget->currentIndex()); + if (tabLabel == "noname") { + QMessageBox::critical(this, "**ERROR**", "For a fit a real msr-file is needed."); + return; + } else if (tabLabel == "noname*") { + fileSaveAs(); + } else if (tabLabel.indexOf("*") > 0) { + fileSave(); + } + + QVector cmd; + QString str; + str = fAdmin->getExecPath() + "/musrfit"; + + cmd.append(str); + cmd.append(QFileInfo(*fFilenames.find( currentEditor())).fileName() ); + cmd.append("--chisq-only"); + if (fAdmin->getEstimateN0Flag() && (result == QMessageBox::Yes) && ((fittype==0) || (fittype==4))) + cmd.append("--estimateN0"); + PFitOutputHandler fitOutputHandler(QFileInfo(*fFilenames.find( currentEditor() )).absolutePath(), cmd); + fitOutputHandler.setModal(true); + fitOutputHandler.exec(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

calls musrfit . can be set in the MusrFit/Preferences. + */ +void PTextEdit::musrFit() +{ + if ( !currentEditor() ) + return; + + QString tabLabel = fTabWidget->tabText(fTabWidget->currentIndex()); + if (tabLabel == "noname") { + QMessageBox::critical(this, "**ERROR**", "For a fit a real msr-file is needed."); + return; + } else if (tabLabel == "noname*") { + fileSaveAs(); + } else if (tabLabel.indexOf("*") > 0) { + fileSave(); + } + + QVector cmd; + QString str; + str = fAdmin->getExecPath() + "/musrfit"; + + cmd.append(str); + cmd.append(QFileInfo(*fFilenames.find( currentEditor())).fileName() ); + + // check if keep minuit2 output is wished + if (fAdmin->getKeepMinuit2OutputFlag()) + cmd.append("--keep-mn2-output"); + + // check if title of the data file should be used to replace the msr-file title + if (fAdmin->getTitleFromDataFileFlag()) + cmd.append("--title-from-data-file"); + + // check if dump files are wished + if (fAdmin->getDumpAsciiFlag()) { + cmd.append("--dump"); + cmd.append("ascii"); + } + if (fAdmin->getDumpRootFlag()) { + cmd.append("--dump"); + cmd.append("root"); + } + + // check estimate N0 flag + if (fAdmin->getEstimateN0Flag()) { + cmd.append("--estimateN0"); + } + + // check per-run-block-chisq flag + if (fAdmin->getChisqPerRunBlockFlag()) { + cmd.append("--per-run-block-chisq"); + } + + // add timeout + cmd.append("--timeout"); + QString numStr; + numStr.setNum(fAdmin->getTimeout()); + cmd.append(numStr); + + PFitOutputHandler fitOutputHandler(QFileInfo(*fFilenames.find( currentEditor() )).absolutePath(), cmd); + fitOutputHandler.setModal(true); + fFileSystemWatcherActive = false; + fitOutputHandler.exec(); + + // handle the reloading of the files + + // get current file name + QString currentFileName = *fFilenames.find( currentEditor() ); + QString complementFileName; + // check if it is a msr-, mlog-, or another file + int idx; + if ((idx = currentFileName.indexOf(".msr")) > 0) { // msr-file + complementFileName = currentFileName; + complementFileName.replace(idx, 5, ".mlog"); + } else if ((idx = currentFileName.indexOf(".mlog")) > 0) { // mlog-file + complementFileName = currentFileName; + complementFileName.replace(idx, 5, ".msr "); + complementFileName = complementFileName.trimmed(); + } else { // neither a msr- nor a mlog-file + QMessageBox::information( this, "musrFit", + "This is neither a msr- nor a mlog-file, hence no idea what to be done.\n", + QMessageBox::Ok ); + return; + } + + int currentIdx = fTabWidget->currentIndex(); + + // reload current file + fileClose(); + load(currentFileName, currentIdx); + + // check if swap file is open as well, and if yes, reload it + idx = -1; + for (int i=0; icount(); i++) { + if (fTabWidget->tabText(i).indexOf(complementFileName) >= 0) { + idx = i; + break; + } + } + if (idx >= 0) { // complement file is open + fTabWidget->setCurrentIndex(idx); + fileClose(); + load(complementFileName, idx); + fTabWidget->setCurrentIndex(currentIdx); + } + + fileSystemWatcherActivation(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Starts a msr2data input dialog which collects all the necessary data before calling msr2data. + */ +void PTextEdit::musrMsr2Data() +{ + if (fMsr2DataParam == nullptr) { + fMsr2DataParam = new PMsr2DataParam(); + *fMsr2DataParam = fAdmin->getMsr2DataParam(); + } + + // init fMsr2DataParam + fMsr2DataParam->keepMinuit2Output = fAdmin->getKeepMinuit2OutputFlag(); + fMsr2DataParam->titleFromDataFile = fAdmin->getTitleFromDataFileFlag(); + fMsr2DataParam->estimateN0 = fAdmin->getEstimateN0Flag(); + fMsr2DataParam->perRunBlockChisq = fAdmin->getChisqPerRunBlockFlag(); + + PMsr2DataDialog *dlg = new PMsr2DataDialog(fMsr2DataParam, fAdmin->getHelpUrl("msr2data")); + + if (dlg == nullptr) { + QMessageBox::critical(this, "**ERROR**", "Couldn't invoke msr2data dialog, sorry :-(", QMessageBox::Ok, QMessageBox::NoButton); + return; + } + + if (dlg->exec() == QDialog::Accepted) { + QString runList; + QString runListFileName; + QFileInfo fi; + QString str; + int i, end; + QStringList list; + bool ok; + + fMsr2DataParam = dlg->getMsr2DataParam(); + fAdmin->setKeepMinuit2OutputFlag(fMsr2DataParam->keepMinuit2Output); + fAdmin->setTitleFromDataFileFlag(fMsr2DataParam->titleFromDataFile); + fAdmin->setEstimateN0Flag(fMsr2DataParam->estimateN0); + fAdmin->setChisqPerRunBlockFlag(fMsr2DataParam->perRunBlockChisq); + + // analyze parameters + switch (dlg->getRunTag()) { + case -1: // not valid + QMessageBox::critical(this, "**ERROR**", + "No valid run list input found :-(\nCannot do anything.", + QMessageBox::Ok, QMessageBox::NoButton); + return; + break; + case 0: // run list + runList = fMsr2DataParam->runList; + break; + case 1: // run list file name + runListFileName = fMsr2DataParam->runListFileName; + fi.setFile(QFileInfo(*fFilenames.find( currentEditor() )).absolutePath() + "/" + runListFileName); + if (!fi.exists()) { + str = QString("Run List File '%1' doesn't exist.").arg(runListFileName); + QMessageBox::critical(this, "**ERROR**", + str, QMessageBox::Ok, QMessageBox::NoButton); + return; + } + break; + default: // never should reach this point + QMessageBox::critical(this, "**ERROR**", + "No idea how you could reach this point.\nPlease contact the developers.", + QMessageBox::Ok, QMessageBox::NoButton); + return; + break; + } + + // form command + QVector cmd; + + str = fAdmin->getExecPath() + "/msr2data"; + cmd.append(str); + + // run list argument + switch (dlg->getRunTag()) { + case 0: + end = 0; + while (!runList.section(' ', end, end, QString::SectionSkipEmpty).isEmpty()) { + end++; + } + // first element + if (end == 1) { + str = "[" + runList + "]"; + cmd.append(str); + } else { + str = "[" + runList.section(' ', 0, 0, QString::SectionSkipEmpty); + cmd.append(str); + // middle elements + for (i=1; imsrFileExtension; + if (str.isEmpty()) + cmd.append(""); + else + cmd.append(str); + + // options + + // parameter export list + if (!fMsr2DataParam->paramList.isEmpty()) { + cmd.append("paramList"); + QStringList list = fMsr2DataParam->paramList.split(' '); + for (int i=0; iwriteDbHeader) + cmd.append("noheader"); + + // ignore data header info flag present? + if (fMsr2DataParam->ignoreDataHeaderInfo) + cmd.append("nosummary"); + + // template run no fitting but: (i) no fit only flag, (ii) no create msr-file only flag + if ((fMsr2DataParam->templateRunNo != -1) && !fMsr2DataParam->fitOnly && !fMsr2DataParam->createMsrFileOnly) { + str = QString("%1").arg(fMsr2DataParam->templateRunNo); + str = "fit-" + str; + if (!fMsr2DataParam->chainFit) { + str += "!"; + } + cmd.append(str); + } + + // template run no AND create msr-file only flag + if ((fMsr2DataParam->templateRunNo != -1) && fMsr2DataParam->createMsrFileOnly) { + str = QString("%1").arg(fMsr2DataParam->templateRunNo); + str = "msr-" + str; + cmd.append(str); + } + + // fit only + if (fMsr2DataParam->fitOnly) { + str = "fit"; + cmd.append(str); + } + + // keep minuit2 output + if (fMsr2DataParam->keepMinuit2Output) { + cmd.append("-k"); + } + + // replace msr-file title by data file title. Add flag only if a fit is done + if (fMsr2DataParam->titleFromDataFile && (fMsr2DataParam->fitOnly || fMsr2DataParam->templateRunNo != -1)) { + cmd.append("-t"); + } + + // estimate N0 (makes sence for single histo and muMinus fits only). Add flag only if a fit is done + if (fMsr2DataParam->estimateN0 && (fMsr2DataParam->fitOnly || fMsr2DataParam->templateRunNo != -1)) { + cmd.append("-e"); + } + + // write per-run-block chisq. Add flag only if a fit is done + if (fMsr2DataParam->perRunBlockChisq && (fMsr2DataParam->fitOnly || fMsr2DataParam->templateRunNo != -1)) { + cmd.append("-p"); + } + + // DB output wished + if (!fMsr2DataParam->dbOutputFileName.isEmpty()) { + str = "-o" + fMsr2DataParam->dbOutputFileName; + cmd.append(str); + } + + // write column data + if (fMsr2DataParam->writeColumnData) { + cmd.append("data"); + } + + // global flag check + if (fMsr2DataParam->global) { + cmd.append("global"); + } + + // global+ flag check + if (fMsr2DataParam->globalPlus) { + if (fMsr2DataParam->chainFit) { + cmd.append("global+"); + } else { + cmd.append("global+!"); + } + } + + // recreate db file + if (fMsr2DataParam->recreateDbFile) { + cmd.append("new"); + } + + // if NO tab is present use the local directory + QString workDir = QString("./"); + if (fTabWidget->count() != 0) { + workDir = QFileInfo(*fFilenames.find( currentEditor() )).absolutePath(); + } + PFitOutputHandler fitOutputHandler(workDir, cmd); + fitOutputHandler.setModal(true); + fFileSystemWatcherActive = false; + fitOutputHandler.exec(); + + // check if it is necessary to load msr-files + if (fMsr2DataParam->openFilesAfterFitting) { + QString fln; + QFile *file; + QTextStream *stream; + QFileInfo finfo; + bool alreadOpen=false; + int idx=0; + + if (!fMsr2DataParam->global) { // standard fits + switch(dlg->getRunTag()) { + case 0: // run list + list = getRunList(runList, ok); + if (!ok) + return; + for (int i=0; imsrFileExtension.isEmpty()) + fln += ".msr"; + else + fln += fMsr2DataParam->msrFileExtension + ".msr"; + + workDir = QString("./"); + if (fTabWidget->count() != 0) { + workDir = QFileInfo(*fFilenames.find( currentEditor() )).absolutePath(); + } + finfo.setFile(workDir + "/" + fln); + alreadOpen = fileAlreadyOpen(finfo, idx); + if (!alreadOpen) { + load(workDir + "/" + fln); + } else { + fTabWidget->setCurrentIndex(idx); + fileReload(); + } + } + break; + case 1: // run list file + file = new QFile(QFileInfo(*fFilenames.find( currentEditor() )).absolutePath() + "/" + fMsr2DataParam->runListFileName); + if (!file->open(QIODevice::ReadOnly)) { + str = QString("Couldn't open run list file %1, sorry.").arg(fMsr2DataParam->runListFileName); + QMessageBox::critical(this, "**ERROR**", str.toLatin1(), QMessageBox::Ok, QMessageBox::NoButton); + return; + } + + stream = new QTextStream(file); + while ( !stream->atEnd() ) { + str = stream->readLine(); // line of text excluding '\n' + str = str.trimmed(); + if (!str.isEmpty() && !str.startsWith("#") && !str.startsWith("run", Qt::CaseInsensitive)) { + fln = str.section(' ', 0, 0, QString::SectionSkipEmpty); + if (fMsr2DataParam->msrFileExtension.isEmpty()) + fln += ".msr"; + else + fln += fMsr2DataParam->msrFileExtension + ".msr"; + + workDir = QString("./"); + if (fTabWidget->count() != 0) { + workDir = QFileInfo(*fFilenames.find( currentEditor() )).absolutePath(); + } + finfo.setFile(workDir + "/" + fln); + alreadOpen = fileAlreadyOpen(finfo, idx); + if (!alreadOpen) { + load(workDir + "/" + fln); + } else { + fTabWidget->setCurrentIndex(idx); + fileReload(); + } + } + } + + file->close(); + + // clean up + delete stream; + delete file; + break; + default: + break; + } + } else { // global tag set + // get the first run number needed to build the global fit file name + fln = QString(""); + switch(dlg->getRunTag()) { + case 0: // run list + fln = runList.section(" ", 0, 0, QString::SectionSkipEmpty) + QString("+global") + fMsr2DataParam->msrFileExtension + QString(".msr"); + break; + case 1: // run list file name + file = new QFile(QFileInfo(*fFilenames.find( currentEditor() )).absolutePath() + "/" + fMsr2DataParam->runListFileName); + if (!file->open(QIODevice::ReadOnly)) { + str = QString("Couldn't open run list file %1, sorry.").arg(fMsr2DataParam->runListFileName); + QMessageBox::critical(this, "**ERROR**", str.toLatin1(), QMessageBox::Ok, QMessageBox::NoButton); + return; + } + + stream = new QTextStream(file); + while ( !stream->atEnd() ) { + str = stream->readLine(); // line of text excluding '\n' + str = str.trimmed(); + if (!str.isEmpty() && !str.startsWith("#") && !str.startsWith("run", Qt::CaseInsensitive)) { + fln = str.section(' ', 0, 0, QString::SectionSkipEmpty); + break; + } + } + + file->close(); + + fln += QString("+global") + fMsr2DataParam->msrFileExtension + QString(".msr"); + + // clean up + delete stream; + delete file; + break; + default: + break; + } + + load(QFileInfo(*fFilenames.find( currentEditor() )).absolutePath() + "/" + fln); + } + } + } + + delete dlg; + dlg = nullptr; + + fileSystemWatcherActivation(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Calls musrview . + */ +void PTextEdit::musrView() +{ + if ( !currentEditor() ) + return; + + QString tabLabel = fTabWidget->tabText(fTabWidget->currentIndex()); + if (tabLabel == "noname") { + QMessageBox::critical(this, "**ERROR**", "For a view a real mlog/msr-file is needed."); + return; + } else if (tabLabel == "noname*") { + fileSaveAs(); + } else if (tabLabel.indexOf("*") > 0) { + fileSave(); + } + + QString cmd = fAdmin->getExecPath() + "/musrview"; + QString workDir = QFileInfo(*fFilenames.find( currentEditor() )).absolutePath(); + QStringList arg; + QString str; + + // file name + str = *fFilenames.find( currentEditor() ); + int pos = str.lastIndexOf("/"); + if (pos != -1) + str.remove(0, pos+1); + arg << str; + + // timeout + str.setNum(fAdmin->getTimeout()); + arg << "--timeout" << str; + + // start with Fourier? + if (fAdmin->getMusrviewShowFourierFlag()) + arg << "-f"; + + // start with averaged data/Fourier? + if (fAdmin->getMusrviewShowAvgFlag()) + arg << "-a"; + + // check if theory shall only be calculated at the data points + if (fAdmin->getMusrviewShowOneToOneFlag()) + arg << "-1"; + + QProcess *proc = new QProcess(this); + connect(proc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(musrViewFinished(int, QProcess::ExitStatus))); + + // make sure that the system environment variables are properly set + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + env.insert("LD_LIBRARY_PATH", env.value("ROOTSYS") + "/lib:" + env.value("LD_LIBRARY_PATH")); + proc->setProcessEnvironment(env); + proc->setWorkingDirectory(workDir); + proc->start(cmd, arg); + if (!proc->waitForStarted()) { + // error handling + QString msg(tr("Could not execute the output command: ")+cmd[0]); + QMessageBox::critical( nullptr, + tr("Fatal error"), + msg, + tr("Quit") ); + return; + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Checks if musrview terminated with error, and if yes pop up a message box. + * @param exitCode + */ +void PTextEdit::musrViewFinished(int exitCode, QProcess::ExitStatus) +{ + if (exitCode != 0) { + QString msg = QString("musrview failed. Possible reasons:\n"); + msg += QString("* corrupted msr-file.\n"); + msg += QString("* cannot read data-file.\n"); + msg += QString("* many more things can go wrong.\n"); + msg += QString("Please check!"); + QMessageBox::critical(nullptr, tr("Fatal Error"), msg, tr("Quit")); + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Calls musrt0 . + */ +void PTextEdit::musrT0() +{ + if ( !currentEditor() ) + return; + + QString tabLabel = fTabWidget->tabText(fTabWidget->currentIndex()); + if (tabLabel == "noname") { + QMessageBox::critical(this, "**ERROR**", "For a view a real mlog/msr-file is needed."); + return; + } else if (tabLabel == "noname*") { + fileSaveAs(); + } else if (tabLabel.indexOf("*") > 0) { + fileSave(); + } + + QString cmd = fAdmin->getExecPath() + "/musrt0"; + QString workDir = QFileInfo(*fFilenames.find( currentEditor() )).absolutePath(); + QStringList arg; + QString str; + + // file name + str = *fFilenames.find( currentEditor() ); + int pos = str.lastIndexOf("/"); + if (pos != -1) + str.remove(0, pos+1); + arg << str; + + // timeout + str.setNum(fAdmin->getTimeout()); + arg << "--timeout" << str; + + QProcess *proc = new QProcess(this); + + // make sure that the system environment variables are properly set + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + env.insert("LD_LIBRARY_PATH", env.value("ROOTSYS") + "/lib:" + env.value("LD_LIBRARY_PATH")); + proc->setProcessEnvironment(env); + proc->setWorkingDirectory(workDir); + proc->start(cmd, arg); + if (!proc->waitForStarted()) { + // error handling + QString msg(tr("Could not execute the output command: ")+cmd[0]); + QMessageBox::critical( nullptr, + tr("Fatal error"), + msg, + tr("Quit") ); + return; + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Calls musrFT via selection/option dialog. It will ask the user if he/she wants to overwrite some + * of the default settings. + */ +void PTextEdit::musrFT() +{ + + PGetMusrFTOptionsDialog *dlg = new PGetMusrFTOptionsDialog(*fFilenames.find( currentEditor() ), fMusrFTPrevCmd, fAdmin->getHelpUrl("musrFT")); + + if (dlg == nullptr) { + QMessageBox::critical(this, "**ERROR** musrFT", "Couldn't invoke musrFT Options Dialog."); + return; + } + + if (dlg->exec() == QDialog::Accepted) { + fMusrFTPrevCmd = dlg->getMusrFTOptions(); + QProcess *proc = new QProcess(this); + proc->setStandardOutputFile("musrFT.log"); + proc->setStandardErrorFile("musrFT.log"); + QString cmd = fAdmin->getExecPath() + "/musrFT"; + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + env.insert("LD_LIBRARY_PATH", env.value("ROOTSYS") + "/lib:" + env.value("LD_LIBRARY_PATH")); + proc->setProcessEnvironment(env); + proc->start(cmd, fMusrFTPrevCmd); + if (!proc->waitForStarted()) { + // error handling + QString msg(tr("Could not execute the output command: ")+cmd[0]); + QMessageBox::critical( nullptr, + tr("Fatal error"), + msg, + tr("Quit") ); + return; + } + } + + delete dlg; + dlg = nullptr; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Calls the preferences dialog which is used to set some global options. + */ +void PTextEdit::musrPrefs() +{ + PPrefsDialog *dlg = new PPrefsDialog(fAdmin); + + if (dlg == nullptr) { + QMessageBox::critical(this, "**ERROR** musrPrefs", "Couldn't invoke Preferences Dialog."); + return; + } + + if (dlg->exec() == QDialog::Accepted) { + fAdmin->setDarkThemeIconsMenuFlag(dlg->getDarkThemeIconsMenuFlag()); + fAdmin->setDarkThemeIconsToolbarFlag(dlg->getDarkThemeIconsToolbarFlag()); + fAdmin->setMusrviewShowFourierFlag(dlg->getMusrviewShowFourierFlag()); + fAdmin->setMusrviewShowAvgFlag(dlg->getMusrviewShowAvgFlag()); + fAdmin->setMusrviewShowOneToOneFlag(dlg->getMusrviewShowOneToOneFlag()); + fAdmin->setKeepMinuit2OutputFlag(dlg->getKeepMinuit2OutputFlag()); + fAdmin->setTitleFromDataFileFlag(dlg->getTitleFromDataFileFlag()); + fAdmin->setEnableMusrT0Flag(dlg->getEnableMusrT0Flag()); + fMusrT0Action->setEnabled(fAdmin->getEnableMusrT0Flag()); + if (dlg->getDump() == 1) { + fAdmin->setDumpAsciiFlag(true); + fAdmin->setDumpRootFlag(false); + } else if (dlg->getDump() == 2) { + fAdmin->setDumpAsciiFlag(false); + fAdmin->setDumpRootFlag(true); + } else { + fAdmin->setDumpAsciiFlag(false); + fAdmin->setDumpRootFlag(false); + } + fAdmin->setTimeout(dlg->getTimeout()); + fAdmin->setChisqPerRunBlockFlag(dlg->getKeepRunPerBlockChisqFlag()); + fAdmin->setEstimateN0Flag(dlg->getEstimateN0Flag()); + } + + delete dlg; + dlg = nullptr; + + // check if the dark theme menu icons flag has changed + if (fAdmin->getDarkThemeIconsMenuFlag() != fDarkMenuIcon) { + fDarkMenuIcon = !fDarkMenuIcon; + switchMenuIcons(); + } + // check if the dark theme toolbar icons flag has changed + if (fAdmin->getDarkThemeIconsToolbarFlag() != fDarkToolBarIcon) { + fDarkToolBarIcon = !fDarkToolBarIcon; + switchToolbarIcons(); + } +} + +//---------------------------------------------------------------------------------------------------- +/** + * @brief PTextEdit::musrSetSteps + */ +void PTextEdit::musrSetSteps() +{ + if ( !currentEditor() ) + return; + + // make sure I have a saved msr-file to work on + QString tabLabel = fTabWidget->tabText(fTabWidget->currentIndex()); + if (tabLabel == "noname") { + QMessageBox::critical(this, "**ERROR**", "For musrStep a real mlog/msr-file is needed."); + return; + } else if (tabLabel == "noname*") { + fileSaveAs(); + } else if (tabLabel.indexOf("*") > 0) { + fileSave(); + } + + // fill the command queue + QString cmd = fAdmin->getExecPath() + "/musrStep"; +#if defined(Q_OS_DARWIN) || defined(Q_OS_MAC) + cmd = QString("/Applications/musrStep.app/Contents/MacOS/musrStep"); +#endif + QString workDir = QFileInfo(*fFilenames.find( currentEditor() )).absolutePath(); + QStringList arg; + QString str; + + // get file name and feed it to the command queue + str = *fFilenames.find( currentEditor() ); + int pos = str.lastIndexOf("/"); + if (pos != -1) + str.remove(0, pos+1); + arg << str; + + QProcess *proc = new QProcess(this); + if (proc == nullptr) { + QMessageBox::critical(nullptr, "**ERROR**", "Couldn't invoke QProcess!"); + return; + } + + // handle return status of musrStep + connect(proc, static_cast(&QProcess::finished), + [=](int exitCode, QProcess::ExitStatus exitStatus){ exitStatusMusrSetSteps(exitCode, exitStatus); }); + + // make sure that the system environment variables are properly set + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + env.insert("LD_LIBRARY_PATH", env.value("ROOTSYS") + "/lib:" + env.value("LD_LIBRARY_PATH")); + proc->setProcessEnvironment(env); + proc->setWorkingDirectory(workDir); + proc->start(cmd, arg); + if (!proc->waitForStarted()) { + // error handling + QString msg(tr("Could not execute the output command: ")+cmd[0]); + QMessageBox::critical( nullptr, + tr("Fatal error"), + msg, + tr("Quit") ); + return; + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Swaps the currently open msr-file with its mlog-file (if present) and updates musredit accordingly. + */ +void PTextEdit::musrSwapMsrMlog() +{ + if ( !currentEditor() ) + return; + + // get current file name + QString currentFileName = *fFilenames.find( currentEditor() ); + QString swapFileName; + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + QString tempFileName = QString("%1/.musrfit/__swap__.msr").arg(env.value("HOME")); + + // check if it is a msr-, mlog-, or another file + int idx; + if ((idx = currentFileName.indexOf(".msr")) > 0) { // msr-file + swapFileName = currentFileName; + swapFileName.replace(idx, 5, ".mlog"); + } else if ((idx = currentFileName.indexOf(".mlog")) > 0) { // mlog-file + swapFileName = currentFileName; + swapFileName.replace(idx, 5, ".msr "); + swapFileName = swapFileName.trimmed(); + } else { // neither a msr- nor a mlog-file + QMessageBox::information( this, "musrSwapMsrMlog", + "This is neither a msr- nor a mlog-file, hence nothing to be swapped.\n", + QMessageBox::Ok ); + return; + } + + // check if the swapFile exists + if (!QFile::exists(swapFileName)) { + QString msg = "swap file '" + swapFileName + "' doesn't exist.\nCannot swap anything."; + QMessageBox::warning( this, "musrSwapMsrMlog", + msg, QMessageBox::Ok, QMessageBox::NoButton ); + return; + } + + // check if the file needs to be saved + if (fTabWidget->tabText(fTabWidget->currentIndex()).indexOf("*") > 0) { // needs to be saved first + fileSave(); + } + + QMessageBox::information(nullptr, "INFO", QString("Will now swap files: %1 <-> %2").arg(currentFileName).arg(swapFileName)); + + // swap files + + // copy currentFile -> tempFile + if (QFile::exists(tempFileName)) { + if (!QFile::remove(tempFileName)) { + QMessageBox::critical(nullptr, "ERROR", QString("failed to remove %1").arg(tempFileName)); + return; + } + } + if (!QFile::copy(currentFileName, tempFileName)) { + QMessageBox::critical(nullptr, "ERROR", QString("failed to copy %1 -> %2").arg(currentFileName).arg(tempFileName)); + return; + } + // copy swapFile -> currentFile + if (!QFile::remove(currentFileName)) { + QMessageBox::critical(nullptr, "ERROR", QString("failed to remove %1").arg(currentFileName)); + return; + } + if (!QFile::copy(swapFileName, currentFileName)) { + QMessageBox::critical(nullptr, "ERROR", QString("failed to copy %1 -> %2").arg(swapFileName).arg(currentFileName)); + return; + } + // copy tempFile -> swapFile + if (!QFile::remove(swapFileName)) { + QMessageBox::critical(nullptr, "ERROR", QString("failed to remove %1").arg(swapFileName)); + return; + } + if (!QFile::copy(tempFileName, swapFileName)) { + QMessageBox::critical(nullptr, "ERROR", QString("failed to copy %1 -> %2").arg(tempFileName).arg(swapFileName)); + return; + } + // clean up + if (!QFile::remove(tempFileName)) { + QMessageBox::critical(nullptr, "ERROR", QString("failed to remove %1").arg(tempFileName)); + return; + } + + int currentIdx = fTabWidget->currentIndex(); + + // reload current file + fileClose(); + load(currentFileName); + + // check if swap file is open as well, and if yes, reload it + idx = -1; + for (int i=0; icount(); i++) { + if (fTabWidget->tabText(i).indexOf(swapFileName) >= 0) { + idx = i; + break; + } + } + if (idx >= 0) { // swap file is open + fTabWidget->setCurrentIndex(idx); + fileClose(); + load(swapFileName); + fTabWidget->setCurrentIndex(currentIdx); + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Dumps the run header information of a selected muSR data file. + */ +void PTextEdit::musrDump() +{ + // select a muSR data filename + QString fileName = QFileDialog::getOpenFileName(this, tr("Select muSR Data File"), "./", tr("muSR Data Files (*.root *.bin *.msr *.nxs)")); + if (fileName.isEmpty()) + return; + + QVector cmd; + QString str = fAdmin->getExecPath() + "/dump_header"; + cmd.append(str); + cmd.append("-fn"); + cmd.append(fileName); + + PDumpOutputHandler dumpOutputHandler(cmd); + dumpOutputHandler.setModal(false); + dumpOutputHandler.exec(); +} + +//---------------------------------------------------------------------------------------------------- +/** + * @brief PTextEdit::mupp + *

Calls mupp, the muSR parameter plotter. + */ +void PTextEdit::mupp() +{ + QString cmd(""); + cmd = fAdmin->getExecPath() + "/mupp"; +#if defined(Q_OS_DARWIN) || defined(Q_OS_MAC) + cmd = QString("/Applications/mupp.app/Contents/MacOS/mupp"); +#endif + + QStringList arg; + + QProcess *proc = new QProcess(this); + + QString workDir = QFileInfo(*fFilenames.find( currentEditor() )).absolutePath(); + + // make sure that the system environment variables are properly set + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + env.insert("LD_LIBRARY_PATH", env.value("ROOTSYS") + "/lib:" + env.value("LD_LIBRARY_PATH")); + proc->setProcessEnvironment(env); + proc->setWorkingDirectory(workDir); + proc->start(cmd, arg); + if (!proc->waitForStarted()) { + // error handling + QString msg(tr("Could not execute the output command: ")+cmd); + QMessageBox::critical( nullptr, + tr("Fatal error"), + msg, + tr("Quit") ); + return; + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Starts the help content browser. + */ +void PTextEdit::helpContents() +{ + bool ok = QDesktopServices::openUrl(QUrl(fAdmin->getHelpUrl("main"), QUrl::TolerantMode)); + if (!ok) { + QString msg = QString("

Sorry: Couldn't open default web-browser for the help.
Please try: musrfit docu in your web-browser.").arg(fAdmin->getHelpUrl("main")); + QMessageBox::critical( nullptr, + tr("Fatal Error"), + msg, + tr("Quit") ); + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Starts the help about info box. + */ +void PTextEdit::helpAbout() +{ + PMusrEditAbout *about = new PMusrEditAbout(); + about->show(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Starts the help about Qt info box. + */ +void PTextEdit::helpAboutQt() +{ + QMessageBox::aboutQt(this); +} + + +//---------------------------------------------------------------------------------------------------- +/** + * @brief PTextEdit::exitStatusMusrWiz + * @param exitCode + * @param exitStatus + */ +void PTextEdit::exitStatusMusrWiz(int exitCode, QProcess::ExitStatus exitStatus) +{ + if (exitStatus == QProcess::CrashExit) { + QMessageBox::critical(nullptr, "**FATAL**", "musrWiz returned CrashExit."); + return; + } + + // dialog finished with reject + if (exitCode == 0) + return; + + // read .musrWiz.log + QProcessEnvironment procEnv = QProcessEnvironment::systemEnvironment(); + QString pathName = procEnv.value("HOME", ""); + pathName += "/.musrfit/musredit/musrWiz.log"; + QString errMsg; + std::ifstream fin(pathName.toLatin1().data(), std::ifstream::in); + if (!fin.is_open()) { + errMsg = QString("PTextEdit::exitStatusMusrWiz: couldn't read %1 file.").arg(pathName); + QMessageBox::critical(nullptr, "**ERROR**", errMsg); + return; + } + char line[128]; + bool musrT0tag = false; + QString str, pathFileName(""); + while (fin.good()) { + fin.getline(line, 128); + str = line; + if (str.startsWith("path-file-name:")) { + pathFileName = str.mid(16); + } else if (str.startsWith("musrt0-tag: yes")) { + musrT0tag = true; + } + } + fin.close(); + + load(pathFileName); + + // in case there is a 1st empty tab "noname", remove it + QString tabStr = fTabWidget->tabText(0); + tabStr.remove('&'); // this is needed since the QTabWidget adds short-cut info as '&' to the tab name + if (tabStr == "noname") { // has to be the first, otherwise do nothing + fFileSystemWatcher->removePath("noname"); + + delete fTabWidget->widget(0); + } + + if (musrT0tag) + musrT0(); + + // remove musrWiz.log file + QFile logFile(pathName); + if (!logFile.remove()) { + errMsg = QString("PTextEdit::exitStatusMusrWiz: couldn't delete %1 file.").arg(pathName); + QMessageBox::critical(nullptr, "**ERROR**", errMsg); + } +} + +//---------------------------------------------------------------------------------------------------- +/** + * @brief PTextEdit::existStatusMusrSetSteps + * @param exitCode + * @param exitStatus + */ +void PTextEdit::exitStatusMusrSetSteps(int exitCode, QProcess::ExitStatus exitStatus) +{ + if (exitStatus == QProcess::CrashExit) { + QMessageBox::critical(nullptr, "**FATAL**", "musrStep returned CrashExit."); + return; + } + + // dialog finished with reject + if (exitCode == 0) + return; + + // dialog finished with save and quite, i.e. accept, hence reload + QString fln = *fFilenames.find( currentEditor() ); + int idx = fTabWidget->currentIndex(); + + fileClose(); + load(fln, idx); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT: called when the font shall be changed. + * + * \param f font object + */ +void PTextEdit::fontChanged( const QFont &f ) +{ + fFontChanging = true; + fComboFont->lineEdit()->setText( f.family() ); + fComboSize->lineEdit()->setText( QString::number( f.pointSize() ) ); + + if (!currentEditor()) + return; + + currentEditor()->setFont(f); + currentEditor()->setWindowModified(false); + currentEditor()->viewport()->setFocus(); + fFontChanging = false; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT: called when the text of the document has changed. It adds a star to the tab label if the + * document has been modified. + * + * \param forced + */ +void PTextEdit::textChanged(const bool forced) +{ + + if (!currentEditor()) + return; + + if (fFontChanging) + return; + + QString tabLabel = fTabWidget->tabText(fTabWidget->currentIndex()); + + if ((fTabWidget->tabText(fTabWidget->currentIndex()).indexOf("*") > 0) && + !currentEditor()->document()->isModified()) { + tabLabel.truncate(tabLabel.length()-1); + fTabWidget->setTabText(fTabWidget->currentIndex(), tabLabel); + } + + if ((fTabWidget->tabText(fTabWidget->currentIndex()).indexOf("*") < 0) && + currentEditor()->document()->isModified()) { + fTabWidget->setTabText(fTabWidget->currentIndex(), tabLabel+"*"); + } + + if ((fTabWidget->tabText(fTabWidget->currentIndex()).indexOf("*") < 0) && + forced) + fTabWidget->setTabText(fTabWidget->currentIndex(), tabLabel+"*"); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT: called when the cursor position has changed. Updates the status bar with the current + * cursor position. + */ +void PTextEdit::currentCursorPosition() +{ + QString str; + int line=0, pos=0; + + pos = currentEditor()->textCursor().columnNumber(); + line = currentEditor()->textCursor().blockNumber(); + + str = QString("cursor pos: %1, %2").arg(line+1).arg(pos+1); + statusBar()->showMessage(str); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT: handles the replaced command. + */ +void PTextEdit::replace() +{ + currentEditor()->insertPlainText(fFindReplaceData->replaceText); + + editFindNext(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT: handles the repalce and close command. + */ +void PTextEdit::replaceAndClose() +{ + currentEditor()->insertPlainText(fFindReplaceData->replaceText); + + emit close(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT: handles the replace all command. + */ +void PTextEdit::replaceAll() +{ + // set the cursor to the start of the document + currentEditor()->moveCursor(QTextCursor::Start); + + // construct search flags + QTextDocument::FindFlags flags; + if (fFindReplaceData->caseSensitive) + flags |= QTextDocument::FindCaseSensitively; + else if (fFindReplaceData->findBackwards) + flags |= QTextDocument::FindBackward; + else if (fFindReplaceData->wholeWordsOnly) + flags |= QTextDocument::FindWholeWords; + + while (currentEditor()->find(fFindReplaceData->findText, flags)) { + currentEditor()->insertPlainText(fFindReplaceData->replaceText); + } + + emit close(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

SLOT: updates the fonts if the textedit tab has changed. + */ +void PTextEdit::applyFontSettings(int) +{ + QFont font(fAdmin->getFontName(), fAdmin->getFontSize()); + fontChanged(font); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Called when an open file is changing outside the editor (SLOT). + * + * \param fileName file name of the changed file. + */ +void PTextEdit::fileChanged(const QString &fileName) +{ + if (!fFileSystemWatcherActive) + return; + + fFileSystemWatcherActive = false; + + QString str = "File '" + fileName + "' changed on the system.\nDo you want to reload it?"; + int result = QMessageBox::question(this, "**INFO**", str, QMessageBox::Yes, QMessageBox::No); + if (result == QMessageBox::Yes) { + // find correct file + int idx = -1; + for (int i=0; icount(); i++) { + if (fTabWidget->tabText(i) == QFileInfo(fileName).fileName()) { + idx = i; + break; + } + } + + if (idx == -1) { + fileSystemWatcherActivation(); + return; + } + + // remove file from file system watcher + fFileSystemWatcher->removePath(fileName); + + // close tab + fTabWidget->removeTab(idx); + // load it + load(fileName, idx); + } + + fileSystemWatcherActivation(); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Delayed reactivation of file system watcher, needed when saving files. At the moment the delay + * is set to 2000 ms. + */ +void PTextEdit::fileSystemWatcherActivation() +{ + if (fFileSystemWatcherTimeout.isActive()) + return; + + fFileSystemWatcherTimeout.singleShot(2000, this, SLOT(setFileSystemWatcherActive())); +} + +//---------------------------------------------------------------------------------------------------- +/** + *

slot needed to reactivate the file system watcher. It is called by PTextEdit::fileSystemWatcherActivation() + * after some given timeout. + */ +void PTextEdit::setFileSystemWatcherActive() +{ + fFileSystemWatcherActive = true; +} + +//---------------------------------------------------------------------------------------------------- +/** + * @brief PTextEdit::getTheme + */ +bool PTextEdit::getTheme() +{ + fDarkMenuIcon = 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()) { // this is ugly and eventually needs to be fixed in a more coherent way + str = QProcessEnvironment::systemEnvironment().value("HOME", QString("??")); + str += "/.kde4/share/config/kdeglobals"; + bool done = false; + if (QFile::exists(str)) { + QFile fln(str); + fln.open(QIODevice::ReadOnly | QIODevice::Text); + QTextStream fin(&fln); + QString line(""); + while (!fin.atEnd() && !done) { + line = fin.readLine(); + if (line.contains("ColorScheme")) { + if (line.contains("dark", Qt::CaseInsensitive)) { + fDarkMenuIcon = true; + fDarkToolBarIcon = true; + } + done = true; + } + } + fln.close(); + } + return done; + } + + if (str.contains("dark", Qt::CaseInsensitive)) { + fDarkMenuIcon = true; + if (str.contains("ubuntu", Qt::CaseInsensitive)) { + fDarkMenuIcon = false; + fDarkToolBarIcon = false; + } else if (str.contains("xfce", Qt::CaseInsensitive)) { + fDarkMenuIcon = false; + fDarkToolBarIcon = false; + } else { + fDarkToolBarIcon = true; + } + } + + return true; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

fill the recent file list in the menu. + */ +void PTextEdit::fillRecentFiles() +{ + for (int i=0; igetNumRecentFiles(); i++) { + fRecentFilesAction[i]->setText(fAdmin->getRecentFile(i)); + fRecentFilesAction[i]->setVisible(true); + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

run list is split (space separated) and expanded (start-end -> start, start+1, ..., end) to a list + * + * \param runListStr list to be split and expanded + * \param ok true if everything is fine; false if an error has been encountered + * + * \return fully expanded run list + */ +QStringList PTextEdit::getRunList(QString runListStr, bool &ok) +{ + QStringList result; + bool isInt; + QString str; + + ok = true; + + // first split space separated parts + QStringList tok = runListStr.split(' ', Qt::SkipEmptyParts); + for (int i=0; icount(); i++) { + tabFln = *fFilenames.find( dynamic_cast(fTabWidget->widget(i))); + finfo2.setFile(tabFln); + if (finfo.absoluteFilePath() == finfo2.absoluteFilePath()) { + result = true; + idx = i; + break; + } + } + + return result; +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Switch menu icons according to the fAdmin settings + */ +void PTextEdit::switchMenuIcons() +{ + if (fAdmin->getDarkThemeIconsMenuFlag()) { // dark theme icons + fActions["New"]->setIcon(QIcon(QPixmap(":/icons/document-new-dark.svg"))); + fActions["Open"]->setIcon(QIcon(QPixmap(":/icons/document-open-dark.svg"))); + fActions["Reload"]->setIcon(QIcon(QPixmap(":/icons/view-refresh-dark.svg"))); + fActions["Save"]->setIcon(QIcon(QPixmap(":/icons/document-save-dark.svg"))); + fActions["Print"]->setIcon(QIcon(QPixmap(":/icons/document-print-dark.svg"))); + fActions["Undo"]->setIcon(QIcon(QPixmap(":/icons/edit-undo-dark.svg"))); + fActions["Redo"]->setIcon(QIcon(QPixmap(":/icons/edit-redo-dark.svg"))); + fActions["Copy"]->setIcon(QIcon(QPixmap(":/icons/edit-copy-dark.svg"))); + fActions["Cut"]->setIcon(QIcon(QPixmap(":/icons/edit-cut-dark.svg"))); + fActions["Paste"]->setIcon(QIcon(QPixmap(":/icons/edit-paste-dark.svg"))); + fActions["Find"]->setIcon(QIcon(QPixmap(":/icons/edit-find-dark.svg"))); + fActions["Find Next"]->setIcon(QIcon(QPixmap(":/icons/go-next-use-dark.svg"))); + fActions["Find Previous"]->setIcon(QIcon(QPixmap(":/icons/go-previous-use-dark.svg"))); + fActions["musrWiz"]->setIcon(QIcon(QPixmap(":/icons/musrWiz-32x32-dark.svg"))); + fActions["calcChisq"]->setIcon(QIcon(QPixmap(":/icons/musrchisq-dark.svg"))); + fActions["musrfit"]->setIcon(QIcon(QPixmap(":/icons/musrfit-dark.svg"))); + fActions["Swap Msr/Mlog"]->setIcon(QIcon(QPixmap(":/icons/musrswap-dark.svg"))); + fActions["musrStep"]->setIcon(QIcon(QPixmap(":/icons/musrStep-32x32-dark.svg"))); + fActions["msr2data"]->setIcon(QIcon(QPixmap(":/icons/msr2data-dark.svg"))); + fActions["mupp"]->setIcon(QIcon(QPixmap(":/icons/mupp-dark.svg"))); + fActions["musrview"]->setIcon(QIcon(QPixmap(":/icons/musrview-dark.svg"))); + fActions["musrt0"]->setIcon(QIcon(QPixmap(":/icons/musrt0-dark.svg"))); + fActions["musrFT"]->setIcon(QIcon(QPixmap(":/icons/musrFT-dark.svg"))); + fActions["musrprefs"]->setIcon(QIcon(QPixmap(":/icons/musrprefs-dark.svg"))); + fActions["musrdump"]->setIcon(QIcon(QPixmap(":/icons/musrdump-dark.svg"))); + } else { // plain theme icons + fActions["New"]->setIcon(QIcon(QPixmap(":/icons/document-new-plain.svg"))); + fActions["Open"]->setIcon(QIcon(QPixmap(":/icons/document-open-plain.svg"))); + fActions["Reload"]->setIcon(QIcon(QPixmap(":/icons/view-refresh-plain.svg"))); + fActions["Save"]->setIcon(QIcon(QPixmap(":/icons/document-save-plain.svg"))); + fActions["Print"]->setIcon(QIcon(QPixmap(":/icons/document-print-plain.svg"))); + fActions["Undo"]->setIcon(QIcon(QPixmap(":/icons/edit-undo-plain.svg"))); + fActions["Redo"]->setIcon(QIcon(QPixmap(":/icons/edit-redo-plain.svg"))); + fActions["Copy"]->setIcon(QIcon(QPixmap(":/icons/edit-copy-plain.svg"))); + fActions["Cut"]->setIcon(QIcon(QPixmap(":/icons/edit-cut-plain.svg"))); + fActions["Paste"]->setIcon(QIcon(QPixmap(":/icons/edit-paste-plain.svg"))); + fActions["Find"]->setIcon(QIcon(QPixmap(":/icons/edit-find-plain.svg"))); + fActions["Find Next"]->setIcon(QIcon(QPixmap(":/icons/go-next-use-plain.svg"))); + fActions["Find Previous"]->setIcon(QIcon(QPixmap(":/icons/go-previous-use-plain.svg"))); + fActions["musrWiz"]->setIcon(QIcon(QPixmap(":/icons/musrWiz-32x32.svg"))); + fActions["calcChisq"]->setIcon(QIcon(QPixmap(":/icons/musrchisq-plain.svg"))); + fActions["musrfit"]->setIcon(QIcon(QPixmap(":/icons/musrfit-plain.svg"))); + fActions["Swap Msr/Mlog"]->setIcon(QIcon(QPixmap(":/icons/musrswap-plain.svg"))); + fActions["musrStep"]->setIcon(QIcon(QPixmap(":/icons/musrStep-32x32.svg"))); + fActions["msr2data"]->setIcon(QIcon(QPixmap(":/icons/msr2data-plain.svg"))); + fActions["mupp"]->setIcon(QIcon(QPixmap(":/icons/mupp-plain.svg"))); + fActions["musrview"]->setIcon(QIcon(QPixmap(":/icons/musrview-plain.svg"))); + fActions["musrt0"]->setIcon(QIcon(QPixmap(":/icons/musrt0-plain.svg"))); + fActions["musrFT"]->setIcon(QIcon(QPixmap(":/icons/musrFT-plain.svg"))); + fActions["musrprefs"]->setIcon(QIcon(QPixmap(":/icons/musrprefs-plain.svg"))); + fActions["musrdump"]->setIcon(QIcon(QPixmap(":/icons/musrdump-plain.svg"))); + } +} + +//---------------------------------------------------------------------------------------------------- +/** + *

Switch toolbar icons according to the fAdmin settings + */ +void PTextEdit::switchToolbarIcons() +{ + if (fAdmin->getDarkThemeIconsToolbarFlag()) { // dark theme icons + fActions["New-tb"]->setIcon(QIcon(QPixmap(":/icons/document-new-dark.svg"))); + fActions["Open-tb"]->setIcon(QIcon(QPixmap(":/icons/document-open-dark.svg"))); + fActions["Reload-tb"]->setIcon(QIcon(QPixmap(":/icons/view-refresh-dark.svg"))); + fActions["Save-tb"]->setIcon(QIcon(QPixmap(":/icons/document-save-dark.svg"))); + fActions["Print-tb"]->setIcon(QIcon(QPixmap(":/icons/document-print-dark.svg"))); + fActions["Undo-tb"]->setIcon(QIcon(QPixmap(":/icons/edit-undo-dark.svg"))); + fActions["Redo-tb"]->setIcon(QIcon(QPixmap(":/icons/edit-redo-dark.svg"))); + fActions["Copy-tb"]->setIcon(QIcon(QPixmap(":/icons/edit-copy-dark.svg"))); + fActions["Cut-tb"]->setIcon(QIcon(QPixmap(":/icons/edit-cut-dark.svg"))); + fActions["Paste-tb"]->setIcon(QIcon(QPixmap(":/icons/edit-paste-dark.svg"))); + fActions["Find-tb"]->setIcon(QIcon(QPixmap(":/icons/edit-find-dark.svg"))); + fActions["Find Next-tb"]->setIcon(QIcon(QPixmap(":/icons/go-next-use-dark.svg"))); + fActions["Find Previous-tb"]->setIcon(QIcon(QPixmap(":/icons/go-previous-use-dark.svg"))); + fActions["musrWiz-tb"]->setIcon(QIcon(QPixmap(":/icons/musrWiz-32x32-dark.svg"))); + fActions["calcChisq-tb"]->setIcon(QIcon(QPixmap(":/icons/musrchisq-dark.svg"))); + fActions["musrfit-tb"]->setIcon(QIcon(QPixmap(":/icons/musrfit-dark.svg"))); + fActions["Swap Msr/Mlog-tb"]->setIcon(QIcon(QPixmap(":/icons/musrswap-dark.svg"))); + fActions["musrStep-tb"]->setIcon(QIcon(QPixmap(":/icons/musrStep-32x32-dark.svg"))); + fActions["msr2data-tb"]->setIcon(QIcon(QPixmap(":/icons/msr2data-dark.svg"))); + fActions["mupp-tb"]->setIcon(QIcon(QPixmap(":/icons/mupp-dark.svg"))); + fActions["musrview-tb"]->setIcon(QIcon(QPixmap(":/icons/musrview-dark.svg"))); + fActions["musrt0-tb"]->setIcon(QIcon(QPixmap(":/icons/musrt0-dark.svg"))); + fActions["musrFT-tb"]->setIcon(QIcon(QPixmap(":/icons/musrFT-dark.svg"))); + fActions["musrprefs-tb"]->setIcon(QIcon(QPixmap(":/icons/musrprefs-dark.svg"))); + fActions["musrdump-tb"]->setIcon(QIcon(QPixmap(":/icons/musrdump-dark.svg"))); + } else { // plain theme icons + fActions["New-tb"]->setIcon(QIcon(QPixmap(":/icons/document-new-plain.svg"))); + fActions["Open-tb"]->setIcon(QIcon(QPixmap(":/icons/document-open-plain.svg"))); + fActions["Reload-tb"]->setIcon(QIcon(QPixmap(":/icons/view-refresh-plain.svg"))); + fActions["Save-tb"]->setIcon(QIcon(QPixmap(":/icons/document-save-plain.svg"))); + fActions["Print-tb"]->setIcon(QIcon(QPixmap(":/icons/document-print-plain.svg"))); + fActions["Undo-tb"]->setIcon(QIcon(QPixmap(":/icons/edit-undo-plain.svg"))); + fActions["Redo-tb"]->setIcon(QIcon(QPixmap(":/icons/edit-redo-plain.svg"))); + fActions["Copy-tb"]->setIcon(QIcon(QPixmap(":/icons/edit-copy-plain.svg"))); + fActions["Cut-tb"]->setIcon(QIcon(QPixmap(":/icons/edit-cut-plain.svg"))); + fActions["Paste-tb"]->setIcon(QIcon(QPixmap(":/icons/edit-paste-plain.svg"))); + fActions["Find-tb"]->setIcon(QIcon(QPixmap(":/icons/edit-find-plain.svg"))); + fActions["Find Next-tb"]->setIcon(QIcon(QPixmap(":/icons/go-next-use-plain.svg"))); + fActions["Find Previous-tb"]->setIcon(QIcon(QPixmap(":/icons/go-previous-use-plain.svg"))); + fActions["musrWiz-tb"]->setIcon(QIcon(QPixmap(":/icons/musrWiz-32x32.svg"))); + fActions["calcChisq-tb"]->setIcon(QIcon(QPixmap(":/icons/musrchisq-plain.svg"))); + fActions["musrfit-tb"]->setIcon(QIcon(QPixmap(":/icons/musrfit-plain.svg"))); + fActions["Swap Msr/Mlog-tb"]->setIcon(QIcon(QPixmap(":/icons/musrswap-plain.svg"))); + fActions["musrStep-tb"]->setIcon(QIcon(QPixmap(":/icons/musrStep-32x32.svg"))); + fActions["msr2data-tb"]->setIcon(QIcon(QPixmap(":/icons/msr2data-plain.svg"))); + fActions["mupp-tb"]->setIcon(QIcon(QPixmap(":/icons/mupp-plain.svg"))); + fActions["musrview-tb"]->setIcon(QIcon(QPixmap(":/icons/musrview-plain.svg"))); + fActions["musrt0-tb"]->setIcon(QIcon(QPixmap(":/icons/musrt0-plain.svg"))); + fActions["musrFT-tb"]->setIcon(QIcon(QPixmap(":/icons/musrFT-plain.svg"))); + fActions["musrprefs-tb"]->setIcon(QIcon(QPixmap(":/icons/musrprefs-plain.svg"))); + fActions["musrdump-tb"]->setIcon(QIcon(QPixmap(":/icons/musrdump-plain.svg"))); + } +} + +//---------------------------------------------------------------------------------------------------- +// END +//---------------------------------------------------------------------------------------------------- diff --git a/src/musredit_qt6/musredit/PTextEdit.h b/src/musredit_qt6/musredit/PTextEdit.h new file mode 100644 index 00000000..37651141 --- /dev/null +++ b/src/musredit_qt6/musredit/PTextEdit.h @@ -0,0 +1,200 @@ +/**************************************************************************** + + PTextEdit.h + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2010-2019 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. * + ***************************************************************************/ + +#ifndef _PTEXTEDIT_H_ +#define _PTEXTEDIT_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#include "musredit.h" + +class PSubTextEdit; +class PAdmin; +class QFileSystemWatcher; +class QAction; +class QComboBox; +class QTabWidget; +class QTextEdit; +class QMenu; + +//---------------------------------------------------------------------------------------------- +/** + *

Main class for musredit. + */ +class PTextEdit : public QMainWindow +{ + Q_OBJECT + +public: + PTextEdit( QWidget *parent = nullptr ); + virtual ~PTextEdit() {} + +public slots: + void aboutToQuit(); + +signals: + void close(); + +private: + void setupFileActions(); + void setupEditActions(); + void setupTextActions(); + void setupMusrActions(); + void setupHelpActions(); + void load( const QString &f, const int index=-1 ); + PSubTextEdit *currentEditor() const; + void doConnections( PSubTextEdit *e ); + void fileSystemWatcherActivation(); + +private slots: + void insertTitle(); + void insertParameterBlock(); + void insertTheoryBlock(); + void insertTheoryFunction(QAction *a); + void insertFunctionBlock(); + void insertAsymRunBlock(); + void insertSingleHistRunBlock(); + void insertNonMusrRunBlock(); + void insertCommandBlock(); + void insertFourierBlock(); + void insertPlotBlock(); + void insertStatisticBlock(); + + void fileNew(); + void fileOpen(); + void fileOpenRecent(); + void fileReload(); + void fileOpenPrefs(); + void fileSave(); + void fileSaveAs(); + void fileSavePrefs(); + void filePrint(); + void fileClose( const bool check = true ); + void fileCloseAll(); + void fileCloseAllOthers(); + void fileExit(); + + void editUndo(); + void editRedo(); + void editSelectAll(); + void editCut(); + void editCopy(); + void editPaste(); + void editFind(); + void editFindNext(); + void editFindPrevious(); + void editFindAndReplace(); + void editComment(); + void editUncomment(); + + void textFamily( const QString &f ); + void textSize( const QString &p ); + + void musrWiz(); + void musrCalcChisq(); + void musrFit(); + void musrMsr2Data(); + void musrView(); + void musrViewFinished(int, QProcess::ExitStatus); + void musrT0(); + void musrFT(); + void musrPrefs(); + void musrSwapMsrMlog(); + void musrSetSteps(); + void musrDump(); + void mupp(); + + void helpContents(); + void helpAboutQt(); + void helpAbout(); + + void exitStatusMusrWiz(int exitCode, QProcess::ExitStatus exitStatus); + void exitStatusMusrSetSteps(int exitCode, QProcess::ExitStatus exitStatus); + + void fontChanged( const QFont &f ); + void textChanged(const bool forced = false); + void currentCursorPosition(); + + void replace(); + void replaceAndClose(); + void replaceAll(); + + void applyFontSettings(int); + void fileChanged(const QString &fileName); + void setFileSystemWatcherActive(); + +private: + bool fDarkMenuIcon; ///< flag indicating if a dark or plain icon shall be used in the menu pull-downs + bool fDarkToolBarIcon; ///< flag indicating if a dark or plain icon shall be used in the toolbar + PAdmin *fAdmin; ///< pointer to the xml-startup file informations. Needed for different purposes like default working- and executable directories etc. + QFileSystemWatcher *fFileSystemWatcher; ///< checks if msr-files are changing on the disk while being open in musredit. + bool fFileSystemWatcherActive; ///< flag to enable/disable the file system watcher + QTimer fFileSystemWatcherTimeout; ///< timer used to re-enable file system watcher. Needed to delay the re-enabling + QString fLastDirInUse; ///< string holding the path from where the last file was loaded. + QStringList fMusrFTPrevCmd; + + QMap fActions; + QAction *fMusrT0Action; + + PMsr2DataParam *fMsr2DataParam; ///< structure holding the necessary input information for msr2data + PFindReplaceData *fFindReplaceData; ///< structure holding the ncessary input for find/replace + + QComboBox *fComboFont; ///< combo box for the font selector + QComboBox *fComboSize; ///< combo box for the font size + bool fFontChanging; ///< flag needed to prevent some textChanged feature to occure when only the font changed + + QTabWidget *fTabWidget; ///< tab widget in which the text editor(s) are placed + QMap fFilenames; ///< mapper between tab widget object and filename + + QMenu *fRecentFilesMenu; ///< recent file menu + QAction *fRecentFilesAction[MAX_RECENT_FILES]; ///< array of the recent file actions + + bool getTheme(); + void fillRecentFiles(); + QStringList getRunList(QString runListStr, bool &ok); + bool fileAlreadyOpen(QFileInfo &finfo, int &idx); + + void switchMenuIcons(); + void switchToolbarIcons(); +}; + + +#endif // _PTEXTEDIT_H_ diff --git a/src/musredit_qt6/musredit/README b/src/musredit_qt6/musredit/README new file mode 100644 index 00000000..061bb915 --- /dev/null +++ b/src/musredit_qt6/musredit/README @@ -0,0 +1,10 @@ +#--------------------------------------------------------------------- +# README +# Andreas Suter, 2015/10/26 +#--------------------------------------------------------------------- + +musredit_qt5 requires Qt 5.4.x or newer. + +#--------------------------------------------------------------------- +# this is the end ... +#--------------------------------------------------------------------- diff --git a/src/musredit_qt6/musredit/forms/PChangeDefaultPathsDialog.ui b/src/musredit_qt6/musredit/forms/PChangeDefaultPathsDialog.ui new file mode 100644 index 00000000..08f553af --- /dev/null +++ b/src/musredit_qt6/musredit/forms/PChangeDefaultPathsDialog.ui @@ -0,0 +1,114 @@ + + + PChangeDefaultPathsDialog + + + + 0 + 0 + 528 + 363 + + + + + 0 + 0 + + + + Dialog + + + + + 9 + 10 + 512 + 341 + + + + + + + + + + + + Qt::Horizontal + + + + 328 + 20 + + + + + + + + Add + + + + + + + Delete + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + buttonBox + accepted() + PChangeDefaultPathsDialog + accept() + + + 228 + 332 + + + 157 + 274 + + + + + buttonBox + rejected() + PChangeDefaultPathsDialog + reject() + + + 296 + 338 + + + 286 + 274 + + + + + diff --git a/src/musredit_qt6/musredit/forms/PFindDialog.ui b/src/musredit_qt6/musredit/forms/PFindDialog.ui new file mode 100644 index 00000000..b47be748 --- /dev/null +++ b/src/musredit_qt6/musredit/forms/PFindDialog.ui @@ -0,0 +1,215 @@ + + + PFindDialog + + + + 0 + 0 + 349 + 271 + + + + Find Text - musredit + + + + :/images/musrfit.xpm:/images/musrfit.xpm + + + + + 0 + 0 + 342 + 264 + + + + + + + Find + + + + + + + + Text to find: + + + + + + + true + + + + + + + + + + + + Options + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + + C&ase Sensitive + + + + + + + Find &backwards + + + + + + + &Whole words only + + + + + + + &Selected text + + + + + + + From c&ursor + + + + + + + + + + + + Qt::Horizontal + + + + + + + + + Qt::Horizontal + + + + 168 + 20 + + + + + + + + &Find + + + + + + + &Close + + + + + + + + + + fFind_comboBox + fCaseSensitive_checkBox + fWholeWordsOnly_checkBox + fFromCursor_checkBox + fFindBackwards_checkBox + fSelectedText_checkBox + fFind_pushButton + fClose_pushButton + + + + + + + fClose_pushButton + clicked() + PFindDialog + reject() + + + 287 + 205 + + + 344 + 228 + + + + + fFind_pushButton + clicked() + PFindDialog + accept() + + + 208 + 211 + + + 171 + 211 + + + + + fFind_comboBox + editTextChanged(QString) + PFindDialog + onFindTextAvailable(QString) + + + 126 + 58 + + + 105 + 218 + + + + + + onFindTextAvailable(QString) + + diff --git a/src/musredit_qt6/musredit/forms/PGetAsymmetryRunBlockDialog.ui b/src/musredit_qt6/musredit/forms/PGetAsymmetryRunBlockDialog.ui new file mode 100644 index 00000000..8a7053cf --- /dev/null +++ b/src/musredit_qt6/musredit/forms/PGetAsymmetryRunBlockDialog.ui @@ -0,0 +1,707 @@ + + + PGetAsymmetryRunBlockDialog + + + Qt::WindowModal + + + + 0 + 0 + 462 + 506 + + + + Get Asymmetry Run Block Parameters + + + + :/images/musrfit.xpm:/images/musrfit.xpm + + + + + 10 + 0 + 441 + 121 + + + + Run Header Info + + + + + 20 + 30 + 91 + 16 + + + + Run File Name + + + + + + 20 + 60 + 71 + 16 + + + + Beamline + + + + + + 20 + 90 + 56 + 16 + + + + Institute + + + + + + 260 + 90 + 91 + 16 + + + + File Format + + + + + + 120 + 26 + 311 + 26 + + + + + + + 120 + 56 + 113 + 26 + + + + + + + 120 + 86 + 77 + 25 + + + + + PSI + + + + + RAL + + + + + TRIUMF + + + + + JPARC + + + + + + + 336 + 86 + 91 + 25 + + + + + NeXuS + + + + + ROOT-NPP + + + + + ROOT-PPC + + + + + PSI-BIN + + + + + PSI-MDU + + + + + MUD + + + + + MDU-ASCII + + + + + ASCII + + + + + DB + + + + + + + + 10 + 120 + 441 + 241 + + + + Required Entries + + + + + 20 + 30 + 56 + 16 + + + + Map + + + + + + 20 + 60 + 111 + 16 + + + + Forward Histo No + + + + + + 240 + 60 + 121 + 16 + + + + Backward Histo No + + + + + + 20 + 90 + 81 + 16 + + + + Data Range + + + + + + 20 + 120 + 111 + 16 + + + + Background Fix + + + + + + 310 + 120 + 31 + 16 + + + + + 75 + true + + + + OR + + + + + + 20 + 150 + 121 + 16 + + + + Background Range + + + + + + 20 + 180 + 71 + 16 + + + + Fit Range + + + + + + 60 + 26 + 371 + 26 + + + + 0 0 0 0 0 0 0 0 0 + + + + + + 150 + 56 + 71 + 26 + + + + + + + 360 + 56 + 71 + 26 + + + + + + + 150 + 86 + 71 + 26 + + + + + + + 220 + 86 + 71 + 26 + + + + + + + 290 + 86 + 71 + 26 + + + + + + + 360 + 86 + 71 + 26 + + + + + + + 150 + 116 + 71 + 26 + + + + + + + 220 + 116 + 71 + 26 + + + + + + + 150 + 146 + 71 + 26 + + + + + + + 220 + 146 + 71 + 26 + + + + + + + 290 + 146 + 71 + 26 + + + + + + + 360 + 146 + 71 + 26 + + + + + + + 150 + 176 + 71 + 26 + + + + + + + 220 + 176 + 71 + 26 + + + + + + + 150 + 206 + 71 + 26 + + + + 1 + + + + + + 20 + 210 + 111 + 16 + + + + Packing/Binning + + + + + + + 10 + 360 + 441 + 91 + + + + Optional Entries + + + + + 20 + 30 + 131 + 16 + + + + Alpha (default = 1.0) + + + + + + 240 + 30 + 121 + 16 + + + + Beta (default = 1.0) + + + + + + 20 + 60 + 241 + 16 + + + + t0 (reqired if not given in the data file) + + + + + + 150 + 26 + 71 + 26 + + + + + + + + + + 360 + 26 + 71 + 26 + + + + + + + + + + 290 + 56 + 71 + 26 + + + + + + + 360 + 56 + 71 + 26 + + + + + + + + 10 + 460 + 441 + 39 + + + + + + + Qt::Horizontal + + + + + + + + + &Help + + + + + + + Qt::Horizontal + + + + 188 + 20 + + + + + + + + &OK + + + + + + + &Cancel + + + + + + + + + + + + + + fCancel_pushButton + clicked() + PGetAsymmetryRunBlockDialog + reject() + + + 458 + 434 + + + 471 + 415 + + + + + fOk_pushButton + clicked() + PGetAsymmetryRunBlockDialog + accept() + + + 394 + 438 + + + 407 + 406 + + + + + fHelp_pushButton + clicked() + PGetAsymmetryRunBlockDialog + helpContent() + + + 47 + 437 + + + 70 + 398 + + + + + + helpContent() + + diff --git a/src/musredit_qt6/musredit/forms/PGetFourierBlockDialog.ui b/src/musredit_qt6/musredit/forms/PGetFourierBlockDialog.ui new file mode 100644 index 00000000..fb742e99 --- /dev/null +++ b/src/musredit_qt6/musredit/forms/PGetFourierBlockDialog.ui @@ -0,0 +1,399 @@ + + + PGetFourierBlockDialog + + + Qt::WindowModal + + + + 0 + 0 + 367 + 269 + + + + Get Fourier + + + + :/images/musrfit.xpm:/images/musrfit.xpm + + + + + 10 + 230 + 351 + 32 + + + + + + + &Help + + + + + + + Qt::Horizontal + + + + 118 + 20 + + + + + + + + &OK + + + + + + + &Cancel + + + + + + + + + 10 + 10 + 61 + 17 + + + + Units + + + + + + 10 + 45 + 91 + 17 + + + + Fourier Power + + + + + + 10 + 75 + 141 + 17 + + + + Apodization + + + + + + 10 + 110 + 61 + 17 + + + + Plot + + + + + + 10 + 140 + 61 + 17 + + + + Phase + + + + + + 0 + 160 + 111 + 41 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:8pt;">Phase Correction</span></p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:8pt;">Range</span></p></body></html> + + + + + + 10 + 200 + 61 + 17 + + + + Range + + + + + + 130 + 5 + 111 + 26 + + + + + Gauss + + + + + Tesla + + + + + MHz + + + + + Mc/s + + + + + + + 130 + 40 + 113 + 22 + + + + + + + 130 + 70 + 111 + 26 + + + + + None + + + + + Weak + + + + + Medium + + + + + Strong + + + + + + + 130 + 105 + 111 + 26 + + + + + Power + + + + + Real + + + + + Imag + + + + + Real & Imag + + + + + Phase + + + + + + + 130 + 140 + 113 + 22 + + + + + + + 130 + 170 + 113 + 22 + + + + + + + 250 + 170 + 113 + 22 + + + + + + + 130 + 200 + 113 + 22 + + + + + + + 250 + 200 + 113 + 22 + + + + + + fOk_pushButton + fCancel_pushButton + fHelp_pushButton + + + + + + + fCancel_pushButton + clicked() + PGetFourierBlockDialog + reject() + + + 337 + 272 + + + 355 + 225 + + + + + fOk_pushButton + clicked() + PGetFourierBlockDialog + accept() + + + 286 + 265 + + + 243 + 227 + + + + + fHelp_pushButton + clicked() + PGetFourierBlockDialog + helpContent() + + + 50 + 273 + + + 115 + 221 + + + + + fOk_pushButton + clicked() + PGetFourierBlockDialog + fillFourierBlock() + + + 247 + 274 + + + 175 + 264 + + + + + + helpContent() + fillFourierBlock() + + diff --git a/src/musredit_qt6/musredit/forms/PGetFunctionsBlockDialog.ui b/src/musredit_qt6/musredit/forms/PGetFunctionsBlockDialog.ui new file mode 100644 index 00000000..2b0913a6 --- /dev/null +++ b/src/musredit_qt6/musredit/forms/PGetFunctionsBlockDialog.ui @@ -0,0 +1,259 @@ + + + PGetFunctionsBlockDialog + + + Qt::WindowModal + + + + 0 + 0 + 636 + 604 + + + + Get Functions + + + + :/images/musrfit.xpm:/images/musrfit.xpm + + + + + 0 + 570 + 631 + 32 + + + + + + + &Help + + + + + + + Qt::Horizontal + + + + 118 + 20 + + + + + + + + &OK + + + + + + + &Cancel + + + + + + + + + 0 + 10 + 631 + 201 + + + + true + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<table style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> +<tr> +<td style="border: none;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:10pt;">Supported basic arithmetics: </span><span style=" font-family:'Courier New,courier'; font-size:10pt;">+, -, *, /, ()</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:10pt;">Supported built-in functions; </span><span style=" font-family:'Courier New,courier'; font-size:10pt;">cos(), sin(), tan(), acos(), asin(), atan(), cosh(), sinh(), tanh(), acosh(), asinh(), atanh(), exp(), log(), ln()</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:10pt;">Supported pre-defined constants</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier'; font-size:10pt;">gamma_mu = 0.0135538817 (MHz/G)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier'; font-size:10pt;">pi = 3.1415926535897932846</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:10pt;">Parameters and Maps are reached via parX, mapY, where X, Y are numbers, e.g. par1, map3</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:10pt;">Examples:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier'; font-size:10pt;">fun1 = gamma_mu * par3</span><span style=" font-family:'Lucida Grande'; font-size:10pt;"> valid</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier'; font-size:10pt;">fun2 = par2/map4 * sin(par3*par5)</span><span style=" font-family:'Lucida Grande'; font-size:10pt;"> valid</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier'; font-size:10pt;">fun3 = fun1 + par6</span><span style=" font-family:'Lucida Grande'; font-size:10pt;"> invalid, since functions cannot be used with the functions definition</span></p></td></tr></table></body></html> + + + + + + 0 + 210 + 631 + 101 + + + + Input + + + + + 90 + 30 + 521 + 22 + + + + + + + 20 + 30 + 71 + 17 + + + + Function: + + + + + + 500 + 60 + 113 + 32 + + + + Add + + + + + + + 0 + 310 + 631 + 251 + + + + ##################################################### +FUNCTIONS + + + + + fOk_pushButton + fCancel_pushButton + fHelp_pushButton + + + + + + + fCancel_pushButton + clicked() + PGetFunctionsBlockDialog + reject() + + + 629 + 584 + + + 368 + 565 + + + + + fOk_pushButton + clicked() + PGetFunctionsBlockDialog + accept() + + + 538 + 577 + + + 265 + 583 + + + + + fHelp_pushButton + clicked() + PGetFunctionsBlockDialog + helpContent() + + + 41 + 585 + + + 111 + 582 + + + + + fAdd_pushButton + clicked() + PGetFunctionsBlockDialog + addFunction() + + + 555 + 289 + + + 410 + 591 + + + + + fFunctionInput_lineEdit + returnPressed() + PGetFunctionsBlockDialog + addFunction() + + + 399 + 252 + + + 413 + 570 + + + + + + helpContent() + addFunction() + + diff --git a/src/musredit_qt6/musredit/forms/PGetMusrFTOptionsDialog.ui b/src/musredit_qt6/musredit/forms/PGetMusrFTOptionsDialog.ui new file mode 100644 index 00000000..3b958e65 --- /dev/null +++ b/src/musredit_qt6/musredit/forms/PGetMusrFTOptionsDialog.ui @@ -0,0 +1,863 @@ + + + PGetMusrFTOptionsDialog + + + Qt::WindowModal + + + + 0 + 0 + 711 + 650 + + + + musrFT Options + + + + + 20 + 400 + 671 + 201 + + + + + 75 + true + + + + Fourier + + + + + 21 + 31 + 641 + 156 + + + + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Options</span></p></body></html> + + + + + + + + UnDef + + + + + real + + + + + imag + + + + + real+imag + + + + + power + + + + + phase + + + + + + + + + + Qt::Horizontal + + + + 218 + 20 + + + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Units</span></p></body></html> + + + + + + + + UnDef + + + + + Gauss + + + + + Tesla + + + + + MHz + + + + + Mc/s + + + + + + + + + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Power</span></p></body></html> + + + + + + + + + + + + Qt::Horizontal + + + + 88 + 20 + + + + + + + + + + Lifetime Correction + + + + + + + + + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Range</span></p></body></html> + + + + + + + + + Start + + + + + + + + + + + + + + End + + + + + + + + + + + + Qt::Horizontal + + + + 118 + 20 + + + + + + + + + + + + Average All + + + + + + + Average per Data Set + + + + + + + Qt::Horizontal + + + + 88 + 20 + + + + + + + + Create msr-File + + + + + + + + + + + Title + + + + + + + + + + + + + + + 20 + 160 + 671 + 231 + + + + + 75 + true + + + + Histo Info + + + + + 20 + 30 + 641 + 188 + + + + + + + + + + 75 + true + + + + Background Range (in Bins) + + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:10pt; font-weight:600; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">StartBin</p></body></html> + + + + + + + + + + + + + + EndBin: + + + + + + + + + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Background List</span></p></body></html> + + + + + + + + + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Apodization</span></p></body></html> + + + + + + + + none + + + + + weak + + + + + medium + + + + + strong + + + + + + + + + + + + Packing + + + + + + + + + + + + Qt::Horizontal + + + + 168 + 20 + + + + + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:10pt; font-weight:600; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Time Range (usec)</p></body></html> + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:10pt; font-weight:600; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Start</p></body></html> + + + + + + + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:10pt; font-weight:600; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">End</p></body></html> + + + + + + + + + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:10pt; font-weight:600; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Histo List</p></body></html> + + + + + + + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:10pt; font-weight:600; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">T0's</p></body></html> + + + + + + + + + + + + + + + 20 + 10 + 671 + 141 + + + + + 75 + true + + + + File Selection + + + + + 19 + 31 + 641 + 96 + + + + + + + + + Current msr-File + + + + + + + ALL msr-Files + + + + + + + Qt::Horizontal + + + + 318 + 20 + + + + + + + + + + + + Select msr-File(s) + + + + + + + + 0 + 23 + + + + + + + + clear msr-file name list + + + Clear + + + + + + + + + + + Select data-File(s) + + + + + + + + 0 + 23 + + + + + + + + clear data-file name list + + + Clear + + + + + + + + + + + + 20 + 610 + 671 + 29 + + + + + + + Help + + + + + + + Qt::Horizontal + + + + 78 + 20 + + + + + + + + + 75 + true + + + + Reset All + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + fCurrentMsrFile_checkBox + fAllMsrFiles_checkBox + fMsrFileSelector_pushButton + fMsrFileSelector_lineEdit + fMsrFileNameClear_pushButton + fDataFileSelector_pushButton + fDataFileSelector_lineEdit + fDataFileNameClear_pushButton + fBkgRangeStartBin_lineEdit + fBkgRangeEndBin_lineEdit + fBkgList_lineEdit + fApodization_comboBox + fPacking_lineEdit + fTimeRangeStart_lineEdit + fTimeRangeEnd_lineEdit + fHistoList_lineEdit + fT0_lineEdit + fFourierOption_comboBox + fFourierUnits_comboBox + fFourierPower_lineEdit + fLifetimeCorrection_lineEdit + fFourierRangeStart_lineEdit + fFourierRangeEnd_lineEdit + fAveragedView_checkBox + fCreateMsrFile_checkBox + fFourierTitle_lineEdit + fResetAll_pushButton + fHelp_pushButton + buttonBox + + + + + buttonBox + accepted() + PGetMusrFTOptionsDialog + accept() + + + 683 + 611 + + + 157 + 274 + + + + + buttonBox + rejected() + PGetMusrFTOptionsDialog + reject() + + + 689 + 611 + + + 286 + 274 + + + + + fHelp_pushButton + clicked() + PGetMusrFTOptionsDialog + helpContent() + + + 85 + 627 + + + 147 + 624 + + + + + + helpContent() + + diff --git a/src/musredit_qt6/musredit/forms/PGetNonMusrRunBlockDialog.ui b/src/musredit_qt6/musredit/forms/PGetNonMusrRunBlockDialog.ui new file mode 100644 index 00000000..026fa8d1 --- /dev/null +++ b/src/musredit_qt6/musredit/forms/PGetNonMusrRunBlockDialog.ui @@ -0,0 +1,465 @@ + + + PGetNonMusrRunBlockDialog + + + Qt::WindowModal + + + + 0 + 0 + 419 + 307 + + + + Get NonMusr Run Block Parameters + + + + :/images/musrfit.xpm:/images/musrfit.xpm + + + + + 10 + 0 + 401 + 131 + + + + Run Header Info + + + + + 10 + 30 + 381 + 28 + + + + + + + Run File Name + + + + + + + + + + + + 11 + 60 + 381 + 28 + + + + + + + Beamline + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 23 + 20 + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 10 + 91 + 381 + 27 + + + + + + + Institute + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 34 + 20 + + + + + + + + + PSI + + + + + RAL + + + + + TRIUMF + + + + + JPARC + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + File Format + + + + + + + + ASCII + + + + + DB + + + + + + + + + + + 10 + 130 + 401 + 131 + + + + Required Entries + + + + + 10 + 30 + 381 + 28 + + + + + + + Map + + + + + + + 0 0 0 0 0 0 0 0 0 0 + + + + + + + + + 11 + 60 + 281 + 28 + + + + + + + xy-Data + + + + + + + Qt::Horizontal + + + + 37 + 20 + + + + + + + + + + + + + + + + 10 + 92 + 291 + 28 + + + + + + + + 0 + 0 + + + + Fit Range + + + + + + + + 0 + 0 + + + + + 105 + 0 + + + + + 105 + 16777215 + + + + + + + + + 0 + 0 + + + + + 105 + 0 + + + + + 105 + 16777215 + + + + + + + + + + + 10 + 270 + 401 + 27 + + + + + + + &Help + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + &OK + + + + + + + &Cancel + + + + + + + + fRunFileName_lineEdit + fBeamline_lineEdit + fInstitute_comboBox + fFileFormat_comboBox + fMap_lineEdit + fXData_lineEdit + fYData_lineEdit + fFitRangeStart_lineEdit + fFitRangeEnd_lineEdit + fOk_pushButton + fCancel_pushButton + fHelp_pushButton + + + + + + + fCancel_pushButton + clicked() + PGetNonMusrRunBlockDialog + reject() + + + 337 + 281 + + + 364 + 216 + + + + + fOk_pushButton + clicked() + PGetNonMusrRunBlockDialog + accept() + + + 289 + 277 + + + 238 + 220 + + + + + fHelp_pushButton + clicked() + PGetNonMusrRunBlockDialog + helpContent() + + + 37 + 286 + + + 78 + 229 + + + + + + helpContent() + + diff --git a/src/musredit_qt6/musredit/forms/PGetParameterBlockDialog.ui b/src/musredit_qt6/musredit/forms/PGetParameterBlockDialog.ui new file mode 100644 index 00000000..399a7ff0 --- /dev/null +++ b/src/musredit_qt6/musredit/forms/PGetParameterBlockDialog.ui @@ -0,0 +1,347 @@ + + + PGetParameterBlockDialog + + + Qt::WindowModal + + + + 0 + 0 + 656 + 476 + + + + Get Parameter + + + + :/images/musrfit.xpm:/images/musrfit.xpm + + + + + 10 + 430 + 631 + 32 + + + + + + + &Help + + + + + + + Qt::Horizontal + + + + 118 + 20 + + + + + + + + &OK + + + + + + + &Cancel + + + + + + + + + 10 + 90 + 631 + 331 + + + + ############################################################### +FITPARAMETER +# Nr. Name Value Step Pos_Error Boundaries + + + + + + 560 + 50 + 75 + 23 + + + + &Add + + + + + + 10 + 30 + 31 + 13 + + + + No. + + + + + + 60 + 30 + 46 + 13 + + + + Name + + + + + + 180 + 30 + 46 + 13 + + + + Value + + + + + + 270 + 30 + 46 + 13 + + + + Step + + + + + + 370 + 10 + 171 + 71 + + + + Boundaries + + + + + 10 + 20 + 46 + 13 + + + + Lower + + + + + + 90 + 20 + 46 + 13 + + + + Upper + + + + + + 10 + 40 + 71 + 20 + + + + none + + + + + + 90 + 40 + 71 + 20 + + + + none + + + + + + + 10 + 50 + 42 + 22 + + + + 1 + + + 999 + + + + + + 60 + 50 + 113 + 20 + + + + + + + 180 + 50 + 81 + 20 + + + + + + + 270 + 50 + 81 + 20 + + + + + + fParamNo_spinBox + fName_lineEdit + fValue_lineEdit + fStep_lineEdit + fLower_lineEdit + fUpper_lineEdit + fAdd_pushButton + fOk_pushButton + fCancel_pushButton + fParam_plainTextEdit + fHelp_pushButton + + + + + + + fCancel_pushButton + clicked() + PGetParameterBlockDialog + reject() + + + 639 + 434 + + + 338 + 429 + + + + + fOk_pushButton + clicked() + PGetParameterBlockDialog + accept() + + + 548 + 436 + + + 448 + 438 + + + + + fAdd_pushButton + clicked() + PGetParameterBlockDialog + paramAdd() + + + 594 + 59 + + + 562 + 16 + + + + + fHelp_pushButton + clicked() + PGetParameterBlockDialog + helpContent() + + + 62 + 447 + + + 148 + 443 + + + + + + helpContent() + paramAdd() + + diff --git a/src/musredit_qt6/musredit/forms/PGetPlotBlockDialog.ui b/src/musredit_qt6/musredit/forms/PGetPlotBlockDialog.ui new file mode 100644 index 00000000..575b3f35 --- /dev/null +++ b/src/musredit_qt6/musredit/forms/PGetPlotBlockDialog.ui @@ -0,0 +1,269 @@ + + + PGetPlotBlockDialog + + + Qt::WindowModal + + + + 0 + 0 + 719 + 312 + + + + Get Plot + + + + :/musredit/musrfit.xpm:/musredit/musrfit.xpm + + + + + 10 + 10 + 702 + 292 + + + + + + + + + + + + 9 + 75 + true + + + + Type + + + + + + + + Single Histo + + + + + Asymmetry + + + + + MuMinus + + + + + NonMusr + + + + + + + + + 9 + 75 + true + + + + Run List + + + + + + + + + + + + + + + 9 + 75 + true + + + + Time-/x-Range + + + + + + + + + + + + + + 9 + 75 + true + + + + y-Range + + + + + + + + + + + + + + + &Add + + + + + + + + + + + + + + &Help + + + + + + + Qt::Horizontal + + + + 118 + 20 + + + + + + + + &OK + + + + + + + &Cancel + + + + + + + + + + fOk_pushButton + fCancel_pushButton + fHelp_pushButton + + + + + + + fCancel_pushButton + clicked() + PGetPlotBlockDialog + reject() + + + 579 + 311 + + + 355 + 225 + + + + + fOk_pushButton + clicked() + PGetPlotBlockDialog + accept() + + + 488 + 311 + + + 243 + 227 + + + + + fHelp_pushButton + clicked() + PGetPlotBlockDialog + helpContent() + + + 51 + 311 + + + 115 + 221 + + + + + fAdd_pushButton + clicked() + PGetPlotBlockDialog + addPlot() + + + 536 + 36 + + + 291 + 316 + + + + + + helpContent() + addPlot() + + diff --git a/src/musredit_qt6/musredit/forms/PGetSingleHistoRunBlockDialog.ui b/src/musredit_qt6/musredit/forms/PGetSingleHistoRunBlockDialog.ui new file mode 100644 index 00000000..7d823aa3 --- /dev/null +++ b/src/musredit_qt6/musredit/forms/PGetSingleHistoRunBlockDialog.ui @@ -0,0 +1,654 @@ + + + PGetSingleHistoRunBlockDialog + + + Qt::WindowModal + + + + 0 + 0 + 440 + 592 + + + + Get Single Histogram Run Block Parameters + + + + :/images/musrfit.xpm:/images/musrfit.xpm + + + + + 10 + 0 + 421 + 121 + + + + Run Header Info + + + + + 20 + 30 + 91 + 16 + + + + Run File Name + + + + + + 20 + 60 + 71 + 16 + + + + Beamline + + + + + + 20 + 90 + 56 + 16 + + + + Institute + + + + + + 240 + 90 + 91 + 16 + + + + File Format + + + + + + 120 + 26 + 291 + 26 + + + + + + + 120 + 56 + 113 + 26 + + + + + + + 120 + 86 + 77 + 25 + + + + + PSI + + + + + RAL + + + + + TRIUMF + + + + + JPARC + + + + + + + 316 + 86 + 91 + 25 + + + + + NeXuS + + + + + ROOT-NPP + + + + + ROOT-PPC + + + + + PSI-BIN + + + + + PSI-MDU + + + + + MUD + + + + + MDU-ASCII + + + + + ASCII + + + + + DB + + + + + + + + 10 + 120 + 421 + 301 + + + + Required Entries + + + + + 20 + 30 + 56 + 16 + + + + Map + + + + + + 20 + 60 + 111 + 20 + + + + Forward Histo No + + + + + + 20 + 120 + 81 + 16 + + + + Data Range + + + + + + 20 + 150 + 111 + 16 + + + + Background Fix + + + + + + 240 + 150 + 31 + 16 + + + + + 75 + true + + + + OR + + + + + + 20 + 210 + 121 + 16 + + + + Background Range + + + + + + 20 + 240 + 71 + 16 + + + + Fit Range + + + + + + 60 + 26 + 351 + 26 + + + + 0 0 0 0 0 0 0 0 0 + + + + + + 150 + 56 + 71 + 26 + + + + + + + 150 + 116 + 71 + 26 + + + + + + + 220 + 116 + 71 + 26 + + + + + + + 150 + 146 + 71 + 26 + + + + + + + 150 + 206 + 71 + 26 + + + + + + + 220 + 206 + 71 + 26 + + + + + + + 150 + 236 + 71 + 26 + + + + + + + 220 + 236 + 71 + 26 + + + + + + + 150 + 266 + 71 + 26 + + + + 1 + + + + + + 20 + 270 + 111 + 16 + + + + Packing/Binning + + + + + + 20 + 90 + 56 + 20 + + + + Norm + + + + + + 150 + 86 + 71 + 26 + + + + + + + 20 + 180 + 101 + 16 + + + + Background Fit + + + + + + 150 + 176 + 71 + 26 + + + + + + + + 10 + 420 + 421 + 121 + + + + Optional Entries + + + + + 20 + 30 + 241 + 16 + + + + t0 (reqired if not given in the data file) + + + + + + 260 + 26 + 71 + 26 + + + + + + + 20 + 60 + 211 + 16 + + + + Muon Lifetime Parameter + + + + + + 180 + 56 + 71 + 26 + + + + + + + 18 + 90 + 151 + 23 + + + + Lifetime Correction + + + + + + + 10 + 545 + 421 + 39 + + + + + + + Qt::Horizontal + + + + + + + + + &Help + + + + + + + Qt::Horizontal + + + + 188 + 20 + + + + + + + + &OK + + + + + + + &Cancel + + + + + + + + + + + + + + fCancel_pushButton + clicked() + PGetSingleHistoRunBlockDialog + reject() + + + 458 + 434 + + + 471 + 415 + + + + + fOk_pushButton + clicked() + PGetSingleHistoRunBlockDialog + accept() + + + 394 + 438 + + + 407 + 406 + + + + + fHelp_pushButton + clicked() + PGetSingleHistoRunBlockDialog + helpContent() + + + 47 + 437 + + + 70 + 398 + + + + + + helpContent() + + diff --git a/src/musredit_qt6/musredit/forms/PGetTheoryBlockDialog.ui b/src/musredit_qt6/musredit/forms/PGetTheoryBlockDialog.ui new file mode 100644 index 00000000..5dce995a --- /dev/null +++ b/src/musredit_qt6/musredit/forms/PGetTheoryBlockDialog.ui @@ -0,0 +1,264 @@ + + + PGetTheoryBlockDialog + + + Qt::WindowModal + + + + 0 + 0 + 698 + 546 + + + + Get Theory + + + + :/images/musrfit.xpm:/images/musrfit.xpm + + + + + 10 + 10 + 681 + 211 + + + + true + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<table border="0" style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> +<tr> +<td style="border: none;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Every theory function has to be written on a single line. It starts with the theory function name or its abbreviation followed by the parameters. Consecutive lines of theory functions will be multiplied. If theory functions need to be added, a line with a '+' has to separate them. The parameters are given as the numbers assigned to them in the FITPARAMETER-block.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Example:</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">asymmetry 2</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">simplExpo 3</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">TFieldCos map1 fun2</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">+</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">asymmetry 6</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">simplExpo 7</p></td></tr></table></body></html> + + + + + + 10 + 220 + 681 + 71 + + + + Theory Input Line + + + + + 10 + 20 + 541 + 41 + + + + + + + 560 + 30 + 51 + 25 + + + + + + + + + + + 620 + 30 + 51 + 25 + + + + * + + + + + + + 10 + 300 + 681 + 201 + + + + ##################################################### +THEORY + + + + + + 10 + 510 + 681 + 29 + + + + + + + &Help + + + + + + + Qt::Horizontal + + + + 178 + 20 + + + + + + + + &OK + + + + + + + &Cancel + + + + + + + + fTheoryFunction_comboBox + fPlus_pushButton + fMultiply_pushButton + fTheoryBlock_plainTextEdit + fOk_pushButton + fCancel_pushButton + fHelp_pushButton + fDescription_textEdit + + + + + + + fCancel_pushButton + clicked() + PGetTheoryBlockDialog + reject() + + + 539 + 502 + + + 492 + 411 + + + + + fOk_pushButton + clicked() + PGetTheoryBlockDialog + accept() + + + 458 + 502 + + + 380 + 472 + + + + + fHelp_pushButton + clicked() + PGetTheoryBlockDialog + helpContent() + + + 45 + 502 + + + 90 + 440 + + + + + fPlus_pushButton + clicked() + PGetTheoryBlockDialog + addPlus() + + + 434 + 257 + + + 173 + 500 + + + + + fMultiply_pushButton + clicked() + PGetTheoryBlockDialog + addMultiply() + + + 500 + 263 + + + 256 + 504 + + + + + + helpContent() + addPlus() + addMultiply() + + diff --git a/src/musredit_qt6/musredit/forms/PGetTitleBlockDialog.ui b/src/musredit_qt6/musredit/forms/PGetTitleBlockDialog.ui new file mode 100644 index 00000000..64d0086f --- /dev/null +++ b/src/musredit_qt6/musredit/forms/PGetTitleBlockDialog.ui @@ -0,0 +1,166 @@ + + + PGetTitleBlockDialog + + + Qt::WindowModal + + + + 0 + 0 + 556 + 90 + + + + Get Title + + + + :/images/musrfit.xpm:/images/musrfit.xpm + + + + + 10 + 10 + 31 + 16 + + + + Title + + + + + + 50 + 6 + 501 + 26 + + + + + + + 10 + 40 + 541 + 47 + + + + + + + Qt::Horizontal + + + + + + + + + &Help + + + + + + + Qt::Horizontal + + + + 138 + 20 + + + + + + + + &OK + + + + + + + &Cancel + + + + + + + + + + fTitle_lineEdit + fOk_pushButton + fCancel_pushButton + fHelp_pushButton + + + + + + + fOk_pushButton + clicked() + PGetTitleBlockDialog + accept() + + + 467 + 78 + + + 286 + 221 + + + + + fCancel_pushButton + clicked() + PGetTitleBlockDialog + reject() + + + 548 + 78 + + + 350 + 219 + + + + + fHelp_pushButton + clicked() + PGetTitleBlockDialog + helpContent() + + + 59 + 64 + + + 149 + 49 + + + + + + helpContent() + + diff --git a/src/musredit_qt6/musredit/forms/PMsr2DataDialog.ui b/src/musredit_qt6/musredit/forms/PMsr2DataDialog.ui new file mode 100644 index 00000000..32178f4f --- /dev/null +++ b/src/musredit_qt6/musredit/forms/PMsr2DataDialog.ui @@ -0,0 +1,742 @@ + + + PMsr2DataDialog + + + Qt::WindowModal + + + + 0 + 0 + 585 + 594 + + + + msr2data input + + + + :/images/musrmsr2data.xpm:/images/musrmsr2data.xpm + + + + + 0 + 0 + 581 + 111 + + + + + 50 + false + + + + Run List Input + + + false + + + false + + + + + 10 + 30 + 561 + 70 + + + + + + + + + Run List + + + + + + + <html><head/><body><p>The run list consists of a collection of run number. Accepted input formats are:</p><p>(i) &lt;run0&gt; &lt;run1&gt; ... &lt;runN&gt;, e.g. 124 126 129</p><p>(ii) &lt;run0&gt;-&lt;runN&gt;, e.g. 124-126, i.e. 124 125 126</p><p>(iii) &lt;run0&gt;:&lt;runN&gt;:&lt;step&gt;, e.g 124:128:2, i.e. 124 126 128</p><p>or combination of those three.</p></body></html> + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 28 + 20 + + + + + + + + <b>OR</b> + + + Qt::AutoText + + + + + + + + + + + Run List File Name + + + + + + + <html><head/><body><p>an ASCII file containing a list of run numbers and optional external parameters is passed to msr2data. </p><p>For details see the online documentation.</p></body></html> + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 52 + 20 + + + + + + + + + + + + + 0 + 110 + 581 + 71 + + + + msr File Extension + + + + + 10 + 30 + 561 + 31 + + + + + + + Extension + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 30 + 20 + + + + + + + + <html><head/><body><p>the extension will be used together with the run number to generate the msr-file name. For example: the run number being 123 and the extension _tf_h13, an msr-file name 123_tf_h13.msr will result.</p></body></html> + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + 180 + 581 + 80 + + + + Template Run Input + + + + + 10 + 30 + 561 + 31 + + + + + + + Template Run Number + + + + + + + <html><head/><body><p>the run number given here will be used as a msr-file template number to generate/fit the run's given in the 'Run List Input'.</p></body></html> + + + + + + + <html><head/><body><p>unselected means: all msr-files generated and fitted will start from the given template.</p><p>selected means: the msr-files generated and fitted will use the previously fitted msr-file as an input. This makes sense if the run list given has continously changing parameters, e.g. as function of the temperature.</p></body></html> + + + Chain Fit + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + 260 + 581 + 80 + + + + Parameter Output File Name + + + + + 10 + 30 + 561 + 31 + + + + + + + Parameters Output File Name + + + + + + + <html><head/><body><p>db- or dat-output file name for the parameter files.</p></body></html> + + + + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 40 + 20 + + + + + + + + + + + 0 + 340 + 581 + 191 + + + + Options + + + + + 6 + 20 + 560 + 131 + + + + + + + + + <html><head/><body><p>For db-files, a Data Header will be written.</p></body></html> + + + Write Data Header + + + + + + + <html><head/><body><p>This tag is used in conjunction with LEM. If <span style=" font-weight:600;">not</span> selected, it will try to extract experiment specific parameters from the data file like implantation energy, transport HV settings, etc.</p></body></html> + + + Ignore Data Header Info + + + + + + + <html><head/><body><p>selected: for each run fitted, two additional files will be written, namely a &lt;msr-filename&gt;-mn2.output and &lt;msr-filename&gt;-mn2.root, which contain a richer set of information about fit, i.e. the covariance matrix, the correlation coefficients, etc.</p></body></html> + + + Keep Minuit2 Output + + + + + + + Estimate N0 + + + + + + + + + + + <html><head/><body><p>unselected: the output parameter file is written in so called db-format.</p><p>selected: the output parameter file is written in column like ascii-format.</p></body></html> + + + Write Column Data + + + + + + + <html><head/><body><p>unselected: if the parameter output file already exists, the parameters will be appended.</p><p>selected: if the parameter output file already exists: it will be deleted and a new one will be written.</p></body></html> + + + Recreate Data File + + + + + + + <html><head/><body><p>selected: the newly generated msr-files will be opened in musredit after the fit took place.</p></body></html> + + + Open Files after Fitting + + + + + + + Write per-run-block Chisq + + + + + + + + + + + <html><head/><body><p>if selected: the run title of the generated msr-file will be the one given in the muSR data file.</p></body></html> + + + Take Data File Title + + + + + + + <html><head/><body><p>if selected: the msr-files will be created, but <span style=" font-weight:600;">no </span>fitting will take place.</p></body></html> + + + Create msr-File only + + + + + + + <html><head/><body><p>selected: it is assumed that the msr-files already exist, and only musrfit is called.</p></body></html> + + + Fit Only + + + + + + + + + <html><head/><body><p>selected: will generate a msr-file for a global fit. Please check the online documentation for further details.</p></body></html> + + + Global + + + + + + + <html><head/><body><p>selected: will generate a msr-file for a global fit. The difference between Global and Global+ is that for Global+ the input parameters of the msr-file are originating from the single run fits. Please check the online documentation for further details.</p></body></html> + + + Global+ + + + + + + + + + + + + + 9 + 160 + 141 + 16 + + + + <html><head/><body><p>parameter numbers to be exported, e.g. 1-16, or 1 3-7, etc.</p></body></html> + + + Parameter Export List + + + + + + 164 + 157 + 401 + 23 + + + + <html><head/><body><p>parameter numbers to be exported, e.g. 1-16, or 1 3-7, etc.</p></body></html> + + + + + + + 5 + 540 + 571 + 51 + + + + + + + Qt::Horizontal + + + + + + + + + &Help + + + + + + + Qt::Horizontal + + + + 178 + 20 + + + + + + + + &OK + + + + + + + &Cancel + + + + + + + + + + fRunList_lineEdit + fRunListFileName_lineEdit + fMsrFileExtension_lineEdit + fTemplateRunNumber_lineEdit + fChainFit_checkBox + fDataOutputFileName_lineEdit + fWriteDataHeader_checkBox + fIgnoreDataHeaderInfo_checkBox + fKeepMinuit2Output_checkBox + fWriteColumnData_checkBox + fRecreateDataFile_checkBox + fOpenFilesAfterFitting_checkBox + fTitleFromData_checkBox + fCreateMsrFileOnly_checkBox + fFitOnly_checkBox + fGlobal_checkBox + fGlobalPlus_checkBox + fParamList_lineEdit + fCancel_pushButton + fHelp_pushButton + fOk_pushButton + + + + + + + fCancel_pushButton + clicked() + PMsr2DataDialog + reject() + + + 538 + 534 + + + 508 + 358 + + + + + fOk_pushButton + clicked() + PMsr2DataDialog + accept() + + + 456 + 541 + + + 380 + 364 + + + + + fHelp_pushButton + clicked() + PMsr2DataDialog + helpContent() + + + 59 + 534 + + + 96 + 370 + + + + + fRunList_lineEdit + textChanged(QString) + PMsr2DataDialog + runListEntered(QString) + + + 151 + 77 + + + 183 + 515 + + + + + fRunListFileName_lineEdit + textChanged(QString) + PMsr2DataDialog + runListFileNameEntered(QString) + + + 295 + 115 + + + 332 + 492 + + + + + fTemplateRunNumber_lineEdit + textChanged(QString) + PMsr2DataDialog + templateRunEntered(QString) + + + 190 + 245 + + + 137 + 516 + + + + + fFitOnly_checkBox + stateChanged(int) + PMsr2DataDialog + fitOnlyChanged(int) + + + 544 + 445 + + + 301 + 484 + + + + + fCreateMsrFileOnly_checkBox + stateChanged(int) + PMsr2DataDialog + createMsrFileOnlyChanged(int) + + + 544 + 423 + + + 150 + 487 + + + + + + helpContent() + fitOnlyChanged(int) + createMsrFileOnlyChanged(int) + runFirstEntered(QString) + runLastEntered(QString) + runListEntered(QString) + runListFileNameEntered(QString) + templateRunEntered(QString) + globalChanged(int) + + diff --git a/src/musredit_qt6/musredit/forms/PMusrEditAbout.ui b/src/musredit_qt6/musredit/forms/PMusrEditAbout.ui new file mode 100644 index 00000000..95858b64 --- /dev/null +++ b/src/musredit_qt6/musredit/forms/PMusrEditAbout.ui @@ -0,0 +1,128 @@ + + + PMusrEditAbout + + + + 0 + 0 + 395 + 225 + + + + Musr Edit About + + + + :/images/musrfit.xpm:/images/musrfit.xpm + + + + + 13 + 13 + 371 + 201 + + + + + + + + 24 + 50 + true + false + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:24pt; font-weight:400; font-style:italic;"> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">musredit ...</p></body></html> + + + + + + + + 75 + true + true + + + + <html><head/><body><p><span style=" font-weight:600; font-style:italic;">git-branch: </span></p></body></html> + + + Qt::AlignCenter + + + + + + + + 75 + true + true + + + + git-rev: + + + Qt::AlignCenter + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal;"> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">by Andreas Suter</p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">andreas.suter@psi.ch</p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Paul Scherrer Institute</p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Switzerland</p></body></html> + + + + + + + &OK + + + + + + + + + + + + fOk_pushButton + clicked() + PMusrEditAbout + accept() + + + 178 + 271 + + + 226 + 228 + + + + + diff --git a/src/musredit_qt6/musredit/forms/PPrefsDialog.ui b/src/musredit_qt6/musredit/forms/PPrefsDialog.ui new file mode 100644 index 00000000..b1eb78f0 --- /dev/null +++ b/src/musredit_qt6/musredit/forms/PPrefsDialog.ui @@ -0,0 +1,344 @@ + + + PPrefsDialog + + + Qt::WindowModal + + + + 0 + 0 + 452 + 180 + + + + Preferences + + + + :/images/musrfit.xpm:/images/musrfit.xpm + + + + + 0 + 5 + 451 + 171 + + + + + + + 2 + + + + general + + + + + 10 + 70 + 421 + 31 + + + + Change Default Search Paths + + + + + + 12 + 10 + 415 + 62 + + + + + + + + + + timeout + + + + + + + Qt::Horizontal + + + + 38 + 30 + + + + + + + + + + Dark Theme Icons Menu + + + + + + + Dark Theme Icons Toolbar + + + + + + + + + + + musrfit + + + + + 10 + 10 + 161 + 23 + + + + keep minuit2 output + + + + + + 10 + 35 + 151 + 23 + + + + dump ascii + + + + + + 10 + 60 + 131 + 23 + + + + dump root + + + + + + 190 + 10 + 241 + 23 + + + + take title from data file + + + + + + 190 + 35 + 241 + 22 + + + + keep per run block chisq + + + + + + 190 + 60 + 241 + 22 + + + + estimate N0 + + + + + + musrview + + + + + 10 + 10 + 421 + 22 + + + + start with Fourier + + + + + + 10 + 40 + 421 + 21 + + + + start with averaged data/Fourier + + + + + + 260 + 10 + 181 + 26 + + + + theo at data points only + + + + + + musrt0 + + + + + 10 + 10 + 131 + 23 + + + + enable it + + + + + + + + + + + &Help + + + + + + + Qt::Horizontal + + + + 88 + 20 + + + + + + + + &OK + + + + + + + &Cancel + + + + + + + + + + fTabWidget + fKeepMn2Output_checkBox + fDumpAscii_checkBox + fDumpRoot_checkBox + fTitleFromData_checkBox + fOk_pushButton + fCancel_pushButton + fHelp_pushButton + + + + + + + fCancel_pushButton + clicked() + PPrefsDialog + reject() + + + 391 + 198 + + + 422 + 142 + + + + + fOk_pushButton + clicked() + PPrefsDialog + accept() + + + 331 + 199 + + + 293 + 144 + + + + + diff --git a/src/musredit_qt6/musredit/forms/PReplaceConfirmationDialog.ui b/src/musredit_qt6/musredit/forms/PReplaceConfirmationDialog.ui new file mode 100644 index 00000000..3765321c --- /dev/null +++ b/src/musredit_qt6/musredit/forms/PReplaceConfirmationDialog.ui @@ -0,0 +1,136 @@ + + + PReplaceConfirmationDialog + + + Qt::WindowModal + + + + 0 + 0 + 513 + 65 + + + + Replace Confirmation - musredit + + + + :/images/musrfit.xpm:/images/musrfit.xpm + + + + + 10 + 10 + 461 + 16 + + + + Found an occurrence of your search term.What do you want to do? + + + + + + 7 + 20 + 521 + 20 + + + + Qt::Horizontal + + + + + + 7 + 35 + 81 + 25 + + + + &Replace + + + + + + 87 + 35 + 131 + 25 + + + + Re&place and Close + + + + + + 217 + 35 + 97 + 25 + + + + Replace &All + + + + + + 317 + 35 + 91 + 25 + + + + &Find Next + + + + + + 407 + 35 + 97 + 25 + + + + &Close + + + + + + + + + fClose_pushButton + clicked() + PReplaceConfirmationDialog + reject() + + + 457 + 58 + + + 468 + 71 + + + + + diff --git a/src/musredit_qt6/musredit/forms/PReplaceDialog.ui b/src/musredit_qt6/musredit/forms/PReplaceDialog.ui new file mode 100644 index 00000000..11131623 --- /dev/null +++ b/src/musredit_qt6/musredit/forms/PReplaceDialog.ui @@ -0,0 +1,300 @@ + + + PReplaceDialog + + + + 0 + 0 + 345 + 315 + + + + Replace Text - musredit + + + + :/images/musrfit.xpm:/images/musrfit.xpm + + + + + 0 + 0 + 341 + 81 + + + + Find + + + + + 10 + 20 + 91 + 16 + + + + Text to find: + + + + + + 10 + 40 + 321 + 31 + + + + true + + + + + + + 190 + 290 + 71 + 25 + + + + &Replace + + + + + + 270 + 290 + 71 + 25 + + + + &Close + + + + + + 0 + 160 + 341 + 121 + + + + Options + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + 10 + 30 + 141 + 23 + + + + C&ase Sensitive + + + + + + 10 + 60 + 141 + 23 + + + + &Whole words only + + + + + + 10 + 90 + 141 + 23 + + + + From c&ursor + + + + + + 180 + 30 + 141 + 23 + + + + Find &backwards + + + + + + 180 + 60 + 141 + 23 + + + + &Selected text + + + + + + 180 + 90 + 151 + 23 + + + + &Prompt on replace + + + + + + + 0 + 280 + 351 + 16 + + + + Qt::Horizontal + + + + + + 0 + 80 + 341 + 81 + + + + Replace With + + + + + 10 + 20 + 111 + 16 + + + + Replacement text: + + + + + + 10 + 40 + 321 + 31 + + + + true + + + + + + fFind_comboBox + fReplacementText_comboBox + fCaseSensitive_checkBox + fWholeWordsOnly_checkBox + fFromCursor_checkBox + fFindBackwards_checkBox + fSelectedText_checkBox + fPromptOnReplace_checkBox + fReplace_pushButton + fClose_pushButton + + + + + + + fClose_pushButton + clicked() + PReplaceDialog + reject() + + + 287 + 205 + + + 344 + 228 + + + + + fReplace_pushButton + clicked() + PReplaceDialog + accept() + + + 208 + 211 + + + 171 + 211 + + + + + fFind_comboBox + editTextChanged(QString) + PReplaceDialog + onFindTextAvailable(QString) + + + 183 + 63 + + + 90 + 298 + + + + + + onFindTextAvailable(QString) + + diff --git a/src/musredit_qt6/musredit/icons/MuonSpin-Avatar.gif b/src/musredit_qt6/musredit/icons/MuonSpin-Avatar.gif new file mode 100644 index 00000000..c87243be Binary files /dev/null and b/src/musredit_qt6/musredit/icons/MuonSpin-Avatar.gif differ diff --git a/src/musredit_qt6/musredit/icons/MuonSpin-Avatar.nb b/src/musredit_qt6/musredit/icons/MuonSpin-Avatar.nb new file mode 100644 index 00000000..8d33b60c --- /dev/null +++ b/src/musredit_qt6/musredit/icons/MuonSpin-Avatar.nb @@ -0,0 +1,2432 @@ +(* Content-type: application/vnd.wolfram.mathematica *) + +(*** Wolfram Notebook File ***) +(* http://www.wolfram.com/nb *) + +(* CreatedBy='Mathematica 8.0' *) + +(*CacheID: 234*) +(* Internal cache information: +NotebookFileLineBreakTest +NotebookFileLineBreakTest +NotebookDataPosition[ 157, 7] +NotebookDataLength[ 142995, 2422] +NotebookOptionsPosition[ 142528, 2401] +NotebookOutlinePosition[ 142865, 2416] +CellTagsIndexPosition[ 142822, 2413] +WindowFrame->Normal*) + +(* Beginning of Notebook Content *) +Notebook[{ + +Cell[CellGroupData[{ +Cell[BoxData[ + RowBox[{"rr", " ", "=", + RowBox[{"(", + RowBox[{"1", "-", + RowBox[{ + RowBox[{"Cos", "[", "tt", "]"}], + RowBox[{ + RowBox[{"(", + RowBox[{"1", "-", + RowBox[{"2", "x"}]}], ")"}], "/", + RowBox[{"(", + RowBox[{"3", "-", + RowBox[{"2", "x"}]}], ")"}]}]}]}], ")"}]}]], "Input", + CellChangeTimes->{{3.620489478312991*^9, 3.620489596409531*^9}, { + 3.620489675621357*^9, 3.620489676632785*^9}, {3.6204898595692368`*^9, + 3.620489869999764*^9}, {3.620489902333275*^9, 3.620489907462965*^9}, { + 3.620490060833705*^9, 3.620490094471711*^9}}], + +Cell[BoxData[ + RowBox[{"1", "-", + FractionBox[ + RowBox[{ + RowBox[{"(", + RowBox[{"1", "-", + RowBox[{"2", " ", "x"}]}], ")"}], " ", + RowBox[{"Cos", "[", "tt", "]"}]}], + RowBox[{"3", "-", + RowBox[{"2", " ", "x"}]}]]}]], "Output", + CellChangeTimes->{ + 3.620489598633787*^9, 3.620489677771926*^9, 3.620489870992437*^9, + 3.62048990845961*^9, {3.6204900799170923`*^9, 3.620490095138709*^9}}] +}, Open ]], + +Cell[CellGroupData[{ + +Cell[BoxData[ + RowBox[{"PolarPlot", "[", + RowBox[{ + RowBox[{"{", + RowBox[{ + RowBox[{"rr", "/.", + RowBox[{"x", "\[Rule]", "0.5"}]}], ",", + RowBox[{"rr", "/.", + RowBox[{"x", "\[Rule]", "0.65"}]}], ",", + RowBox[{"rr", "/.", + RowBox[{"x", "\[Rule]", "0.8"}]}], ",", + RowBox[{"rr", "/.", + RowBox[{"x", "\[Rule]", "0.9"}]}], ",", + RowBox[{"rr", "/.", + RowBox[{"x", "\[Rule]", "0.99"}]}]}], "}"}], ",", + RowBox[{"{", + RowBox[{"tt", ",", "0", ",", + RowBox[{"2", "Pi"}]}], "}"}], ",", + RowBox[{"Axes", "\[Rule]", "False"}], ",", " ", + RowBox[{"PlotStyle", "\[Rule]", + RowBox[{"{", + RowBox[{ + RowBox[{"{", + RowBox[{"Blue", ",", + RowBox[{"Thickness", "[", "0.01", "]"}]}], "}"}], ",", " ", + RowBox[{"{", + RowBox[{"Cyan", ",", " ", + RowBox[{"Thickness", "[", "0.01", "]"}]}], "}"}], ",", " ", + RowBox[{"{", + RowBox[{"Green", ",", + RowBox[{"Thickness", "[", "0.01", "]"}]}], "}"}], ",", + RowBox[{"{", + RowBox[{"Orange", ",", + RowBox[{"Thickness", "[", "0.01", "]"}]}], "}"}], ",", " ", + RowBox[{"{", + RowBox[{"Red", ",", + RowBox[{"Thickness", "[", "0.01", "]"}]}], "}"}]}], "}"}]}]}], + "]"}]], "Input", + CellChangeTimes->{{3.620489601691044*^9, 3.620489656394434*^9}, { + 3.6204896894706097`*^9, 3.6204898252410297`*^9}, {3.6204898920305347`*^9, + 3.62048989541327*^9}, {3.6204899420804577`*^9, 3.6204899519892473`*^9}, { + 3.620490006961562*^9, 3.6204900151066523`*^9}, {3.620490115961823*^9, + 3.620490175106708*^9}, {3.620490214560876*^9, 3.6204902239067163`*^9}, { + 3.6204902915033712`*^9, 3.6204904451164293`*^9}, {3.620490487640355*^9, + 3.6204905052907743`*^9}, {3.620490590163651*^9, 3.620490699300071*^9}, { + 3.620490759971017*^9, 3.620490761675695*^9}, {3.62049086679007*^9, + 3.620490946980547*^9}, {3.6204909944370737`*^9, 3.6204910496397057`*^9}}], + +Cell[BoxData[ + GraphicsBox[{{{}, {}}, {}, {{}, {}, + {RGBColor[0, 0, 1], Thickness[0.01], LineBox[CompressedData[" +1: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 +WHxm8f8DJChnmQ== + "]]}, + {RGBColor[0, 1, 1], Thickness[0.01], LineBox[CompressedData[" +1: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 +iOh7lGYW/B+Fs7yW + "]]}, + {RGBColor[0, 1, 0], Thickness[0.01], LineBox[CompressedData[" +1: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 +yC34Pxum7FE= + "]]}, + {RGBColor[1, 0.5, 0], Thickness[0.01], LineBox[CompressedData[" +1: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 +DOb5ef8HmNKkzA== + "]]}, + {RGBColor[1, 0, 0], Thickness[0.01], LineBox[CompressedData[" +1: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 +4XqGWY86+BO2WeeyYy3u28IhTL5bB179p92O3qvF76bbrBlXayHVXXXXwIFa +fHfsvZz4tVoYEem/LfitBtmO7D1W2VcNrU7Na+ZvarA243fxWFo17AxXqv7x +tAZ/9sytn/KqhvtqI4HlajXI3aTiIHKmGrpNn5kK7qpBJv/fHvSvquDNXeOF +qx7V2LevctO8WCWEZCiYWehU4eFWowPHk8rg5tC1fYPyVdiY+UN9yrMM9gd/ +9pETqyL6w0hj570y4JrfVt69vQq/Pr3z6drWMjhNVbtxPbMSf43belx9UApH +ps7qSrNU4u4uIcd5/hLofnPy2PPEciwqiz7AUFQIHVJqP65/K0e7l3ST74IL +4bjInZ+ML8uR+7JI41WHQnjxtUDO6G45PvZdqZcWLQTnDeUyXCvDjGu1ZK3w +AlgLnd7BKl+GS8UWFhp8CILXr+bnd5Tg6/mN/D6u32B56nzq+ZIStOdPf/Ck +MweUykobk36V4Jv75mb3f+QAf/uwdZBbCZ58yHfy0tEcmLsUIG1ypAQ3/ad+ +d+VSNnAvyDiu2hRj0t+e7c8cMoGSNT72fXsRzh7iTH8vkgbRTgvW16iFyPQ0 +IyxxPRW4qj9OUroL8V7TjMPhmlSIvk7z0k8uxGM7WaXpzFIhz9yJx1WjEJ9e +vyjqFZMC/x2jkP9GFaBiwWOeJIlk2PWiQepDYD56H2kdGD/4Cxh05NcLbPPx +r5tRyfU/8VBs4Xd9s2I+0kI3JIW84kGXKzW2ZjUP1Z63m9gsxcHuDbOTqrp5 +eKokQ52vNRZ+OURRnYRyMZg9JMcvKRq20WVful+TjZqshyRWCkiAp/Ye+RKV +jd36F+o2vyLBvHZFy9iLbCzKd1v1UiTBdwbvqEHJbHSUvn9roTUcnl0W/Cwd +k4XdhpkK0ks/oS8s6EDp+0y0mXhfpy0fBq77b0z0W6UjZ7OncrFrEEQMmena +KqWjVdNI+ZGDQTAUpnX1lHA6Zr+gozrnfoc3ceFfhQfT0INVRnBtPRBMggoS +xTXTULDpvxW+d9/g8P69nyaVU9F5ftmu7U8AhNNL1CTdS8aP2gPJWlv84HUs +HbvmyXj0Y83rlL7nCT+bGrP/Y4hH1qW2/R70nqBZqaaR3h6HF3JOHa6L9oBy +c8FfCa/jcDQ34rzxyktgsp7qdR+LRZgYrdeJeQG13T9Ex/NiUFKj5Cm/mBts +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 +oEG4L+yjV7mqDf7/3/M/D83v8lEuzP0/QMwvsQ== + + "]]}}, {}, {{{}, {}, {}, {}}, {}}}, + AxesOrigin->{0, 0}, + CoordinatesToolOptions:>{"DisplayFunction" -> ({ + Sqrt[Part[#, 1]^2 + Part[#, 2]^2], + Mod[ + ArcTan[ + Part[#, 1], + Part[#, 2]], 2 Pi]}& ), "CopiedValueFunction" -> ({ + Sqrt[Part[#, 1]^2 + Part[#, 2]^2], + Mod[ + ArcTan[ + Part[#, 1], + Part[#, 2]], 2 Pi]}& )}, + DisplayFunction:>Identity, + PlotRange->{{Automatic, Automatic}, {Automatic, Automatic}}, + PlotRangeClipping->True, + PlotRangePadding->Scaled[0.02]]], "Output", + CellChangeTimes->{{3.620489657702744*^9, 3.620489739957882*^9}, { + 3.620489770653817*^9, 3.620489782707429*^9}, 3.620489827142384*^9, { + 3.620489873668777*^9, 3.62048991191786*^9}, 3.620489953790297*^9, { + 3.620490009760477*^9, 3.620490015672822*^9}, {3.620490085688377*^9, + 3.620490102224215*^9}, 3.620490177264339*^9, 3.620490224928536*^9, { + 3.620490300042884*^9, 3.620490445981697*^9}, 3.620490506115926*^9, { + 3.620490639133857*^9, 3.620490700389542*^9}, 3.6204907632928457`*^9, { + 3.6204908794932337`*^9, 3.6204908942148542`*^9}, {3.6204909338818073`*^9, + 3.620490947909124*^9}, {3.6204910090289288`*^9, 3.620491017640053*^9}, + 3.62049105095186*^9}, + ImageCache->GraphicsData["CompressedBitmap", "\<\ +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 +jTav0CumLbU1h9KhpgpVqep+WuSGeiAdaIbRMLMTUwBl/ePWbneVgfWwcmfK +J+6Oplo8YgXqgcHhgO3B8vixfmAPaWVv24ZqRdqBVbR0tPADW/OocRO59WqL +rx9YDarh2BTz+Cq9albQCtELNtAGN9hu1M19X5fqhvkvciyMeR9LY+El8q// +Z7ZV6tuko+plN+95I9NRwTKHn0qPCtr90qXujqP9qB6U2f3J7o9azpT4VXux +MZs6WuO6nzE7Lsd3+BIEFpmaVkDubFfdNjTKbgAb7SRYlrLXjpgxe1V0f6lu +VzTZySG7I5Cpb69G9trLXm3t1cNeH9nre3vNs9cmomaBN8HS2DSAnN1fKgdQ +sOU8Ro9hAZhGTP2SadZOu8QpKcUMCnazjy5yeqaAAoMNLhQNChw70MjtHUd5 +UO4JTDd/PplZs8gMH05mzBgyo7s9bzZVrljEXilseW2NGdrbmP3/DH5Dqmav +c+z1lr2WmnrOo1nJ4bELxLu9DrXX+fZ6wl5T7NUkDBgaQQdLPCSY3W0qhaUL +3sa++w19YzbT5h15LIstH37Yyo1TxmxFOX3f1YlvEfOQx9hwrAIrY4YrCS4k +e8eRfszeJ1TLLFhA5ocfyPTpQ6ZrVzI33WQndEdrbW9FpnJlMtWq2eFUsj+o +ba8W9rrfTvTgsWZI64bgCRFvdY350y71iycaK9UxlJb26muv1XbWjGP97ezn +KfZ6wF6f2etve7FgghaFHfYGu1tvQ9tUCpO/K+1qnqPnnMgTIMD5WAGyp9u/ +vbi317YBO98H72xYEbKVQquH+mDV2CM8ENcEqbppE5mpU8ncfTeZY44hs/32 +ZGrX9oMvuMm2HLm3/cF99nrZXpPIjcuq7ebIuYea+S2iFt7QmD6WH7ZaB3l1 +jWOMEndzLWOn1ApDe02x10x7/WNpXW5fYf/WeAaZuv9a7EvJaiJkF5tfSNuG +hVaBqI57TLFpZj+vtlcfv44aBxg30Sa372MjtZtgIcBYzXIpkJ1JM80ODA+2 +AngRuu8YYYTS/8UNzqQUGKHZ7757uoagjMKjbO/wzpHg+ikxc+eS+fBDMnfc +YVntSM8/lR18VjoW2xsttFZsG7PWco8fi1X07HW0eXGARefggGI1s9ZqYqdP +2M/KI8tGK+3ffoLWYa+r7XW6vQ6w1372qg6tFW/Yyk3WwQeTueEGMjfeSGbA +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 +v92IXwGZkTrZ\ +\>"]] +}, Open ]] +}, +WindowSize->{740, 867}, +WindowMargins->{{146, Automatic}, {Automatic, 27}}, +FrontEndVersion->"8.0 for Linux x86 (64-bit) (October 10, 2011)", +StyleDefinitions->"Default.nb" +] +(* End of Notebook Content *) + +(* Internal cache information *) +(*CellTagsOutline +CellTagsIndex->{} +*) +(*CellTagsIndex +CellTagsIndex->{} +*) +(*NotebookFileOutline +Notebook[{ +Cell[CellGroupData[{ +Cell[579, 22, 601, 16, 29, "Input"], +Cell[1183, 40, 417, 12, 45, "Output"] +}, Open ]], +Cell[CellGroupData[{ +Cell[1637, 57, 1948, 46, 84, "Input"], +Cell[3588, 105, 138924, 2293, 327, 96939, 1604, "CachedBoxData", "BoxData", \ +"Output"] +}, Open ]] +} +] +*) + +(* End of internal cache information *) + diff --git a/src/musredit_qt6/musredit/icons/document-new-dark.svg b/src/musredit_qt6/musredit/icons/document-new-dark.svg new file mode 100644 index 00000000..f56bdeb8 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/document-new-dark.svg @@ -0,0 +1,14 @@ + + + + + + diff --git a/src/musredit_qt6/musredit/icons/document-new-plain.svg b/src/musredit_qt6/musredit/icons/document-new-plain.svg new file mode 100644 index 00000000..1327e7fd --- /dev/null +++ b/src/musredit_qt6/musredit/icons/document-new-plain.svg @@ -0,0 +1,75 @@ + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/document-open-dark.svg b/src/musredit_qt6/musredit/icons/document-open-dark.svg new file mode 100644 index 00000000..ef9cbb30 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/document-open-dark.svg @@ -0,0 +1,14 @@ + + + + + + diff --git a/src/musredit_qt6/musredit/icons/document-open-plain.svg b/src/musredit_qt6/musredit/icons/document-open-plain.svg new file mode 100644 index 00000000..bcd7478d --- /dev/null +++ b/src/musredit_qt6/musredit/icons/document-open-plain.svg @@ -0,0 +1,75 @@ + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/document-print-dark.svg b/src/musredit_qt6/musredit/icons/document-print-dark.svg new file mode 100644 index 00000000..6eb876ee --- /dev/null +++ b/src/musredit_qt6/musredit/icons/document-print-dark.svg @@ -0,0 +1,14 @@ + + + + + + diff --git a/src/musredit_qt6/musredit/icons/document-print-plain.svg b/src/musredit_qt6/musredit/icons/document-print-plain.svg new file mode 100644 index 00000000..41c4fcff --- /dev/null +++ b/src/musredit_qt6/musredit/icons/document-print-plain.svg @@ -0,0 +1,74 @@ + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/document-save-dark.svg b/src/musredit_qt6/musredit/icons/document-save-dark.svg new file mode 100644 index 00000000..3df75d57 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/document-save-dark.svg @@ -0,0 +1,14 @@ + + + + + + diff --git a/src/musredit_qt6/musredit/icons/document-save-plain.svg b/src/musredit_qt6/musredit/icons/document-save-plain.svg new file mode 100644 index 00000000..01669b54 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/document-save-plain.svg @@ -0,0 +1,95 @@ + + + I REALLY hate this icon + + + + + + + image/svg+xml + + I REALLY hate this icon + Migh as well use Tango... for crying out loud. This damn icon has to die, but no because obviously we're still using floppies therefore it is still relevant in 2014. + English + + + + + + + + Uri Herrera + + + November 20th 2014 + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/edit-copy-dark.svg b/src/musredit_qt6/musredit/icons/edit-copy-dark.svg new file mode 100644 index 00000000..6de6a598 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/edit-copy-dark.svg @@ -0,0 +1,14 @@ + + + + + + diff --git a/src/musredit_qt6/musredit/icons/edit-copy-plain.svg b/src/musredit_qt6/musredit/icons/edit-copy-plain.svg new file mode 100644 index 00000000..af0fe5fc --- /dev/null +++ b/src/musredit_qt6/musredit/icons/edit-copy-plain.svg @@ -0,0 +1,74 @@ + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/edit-cut-dark.svg b/src/musredit_qt6/musredit/icons/edit-cut-dark.svg new file mode 100644 index 00000000..99ab04ef --- /dev/null +++ b/src/musredit_qt6/musredit/icons/edit-cut-dark.svg @@ -0,0 +1,14 @@ + + + + + + diff --git a/src/musredit_qt6/musredit/icons/edit-cut-plain.svg b/src/musredit_qt6/musredit/icons/edit-cut-plain.svg new file mode 100644 index 00000000..1f9c5024 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/edit-cut-plain.svg @@ -0,0 +1,104 @@ + + + I hate this icon + + + + + + + image/svg+xml + + I hate this icon + October 19th 2014 + + + Uri Herrera + + + + + + + + English + An icon I absolutely don't like, and that represents exactly the kind of things why I choose CC licenses. + + + Everyone + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/edit-find-dark.svg b/src/musredit_qt6/musredit/icons/edit-find-dark.svg new file mode 100644 index 00000000..fb62e414 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/edit-find-dark.svg @@ -0,0 +1,14 @@ + + + + + + diff --git a/src/musredit_qt6/musredit/icons/edit-find-plain.svg b/src/musredit_qt6/musredit/icons/edit-find-plain.svg new file mode 100644 index 00000000..7098f1c9 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/edit-find-plain.svg @@ -0,0 +1,79 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/edit-paste-dark.svg b/src/musredit_qt6/musredit/icons/edit-paste-dark.svg new file mode 100644 index 00000000..ba4f3cb5 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/edit-paste-dark.svg @@ -0,0 +1,14 @@ + + + + + + diff --git a/src/musredit_qt6/musredit/icons/edit-paste-plain.svg b/src/musredit_qt6/musredit/icons/edit-paste-plain.svg new file mode 100644 index 00000000..4f5e81dd --- /dev/null +++ b/src/musredit_qt6/musredit/icons/edit-paste-plain.svg @@ -0,0 +1,74 @@ + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/edit-redo-dark.svg b/src/musredit_qt6/musredit/icons/edit-redo-dark.svg new file mode 100644 index 00000000..19d34158 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/edit-redo-dark.svg @@ -0,0 +1,14 @@ + + + + + + diff --git a/src/musredit_qt6/musredit/icons/edit-redo-plain.svg b/src/musredit_qt6/musredit/icons/edit-redo-plain.svg new file mode 100644 index 00000000..d2d70ab8 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/edit-redo-plain.svg @@ -0,0 +1,75 @@ + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/edit-undo-dark.svg b/src/musredit_qt6/musredit/icons/edit-undo-dark.svg new file mode 100644 index 00000000..7ab68cf0 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/edit-undo-dark.svg @@ -0,0 +1,14 @@ + + + + + + diff --git a/src/musredit_qt6/musredit/icons/edit-undo-plain.svg b/src/musredit_qt6/musredit/icons/edit-undo-plain.svg new file mode 100644 index 00000000..4169593c --- /dev/null +++ b/src/musredit_qt6/musredit/icons/edit-undo-plain.svg @@ -0,0 +1,75 @@ + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/go-next-use-dark.svg b/src/musredit_qt6/musredit/icons/go-next-use-dark.svg new file mode 100644 index 00000000..6c188cf0 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/go-next-use-dark.svg @@ -0,0 +1,14 @@ + + + + + + diff --git a/src/musredit_qt6/musredit/icons/go-next-use-plain.svg b/src/musredit_qt6/musredit/icons/go-next-use-plain.svg new file mode 100644 index 00000000..4bbeff5c --- /dev/null +++ b/src/musredit_qt6/musredit/icons/go-next-use-plain.svg @@ -0,0 +1,74 @@ + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/go-previous-use-dark.svg b/src/musredit_qt6/musredit/icons/go-previous-use-dark.svg new file mode 100644 index 00000000..01ef7277 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/go-previous-use-dark.svg @@ -0,0 +1,14 @@ + + + + + + diff --git a/src/musredit_qt6/musredit/icons/go-previous-use-plain.svg b/src/musredit_qt6/musredit/icons/go-previous-use-plain.svg new file mode 100644 index 00000000..06c4b0c5 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/go-previous-use-plain.svg @@ -0,0 +1,73 @@ + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/inkscape/document-new.svg b/src/musredit_qt6/musredit/icons/inkscape/document-new.svg new file mode 100644 index 00000000..2a46e85e --- /dev/null +++ b/src/musredit_qt6/musredit/icons/inkscape/document-new.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/inkscape/document-open.svg b/src/musredit_qt6/musredit/icons/inkscape/document-open.svg new file mode 100644 index 00000000..58101a55 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/inkscape/document-open.svg @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/inkscape/document-print.svg b/src/musredit_qt6/musredit/icons/inkscape/document-print.svg new file mode 100644 index 00000000..de757e13 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/inkscape/document-print.svg @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/inkscape/document-save.svg b/src/musredit_qt6/musredit/icons/inkscape/document-save.svg new file mode 100644 index 00000000..a725304a --- /dev/null +++ b/src/musredit_qt6/musredit/icons/inkscape/document-save.svg @@ -0,0 +1,83 @@ + + + + I REALLY hate this icon + + + + + + + + + + + + + + + + + + image/svg+xml + + I REALLY hate this icon + Migh as well use Tango... for crying out loud. This damn icon has to die, but no because obviously we're still using floppies therefore it is still relevant in 2014. + English + + + + + + + + Uri Herrera + + + November 20th 2014 + + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/inkscape/edit-copy.svg b/src/musredit_qt6/musredit/icons/inkscape/edit-copy.svg new file mode 100644 index 00000000..6edb0571 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/inkscape/edit-copy.svg @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/inkscape/edit-cut.svg b/src/musredit_qt6/musredit/icons/inkscape/edit-cut.svg new file mode 100644 index 00000000..1f77c268 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/inkscape/edit-cut.svg @@ -0,0 +1,84 @@ + + + + I hate this icon + + + + + + + + + + + + + + + + + + image/svg+xml + + I hate this icon + October 19th 2014 + + + Uri Herrera + + + + + + + + English + An icon I absolutely don't like, and that represents exactly the kind of things why I choose CC licenses. + + + Everyone + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/inkscape/edit-find.svg b/src/musredit_qt6/musredit/icons/inkscape/edit-find.svg new file mode 100644 index 00000000..7694d71d --- /dev/null +++ b/src/musredit_qt6/musredit/icons/inkscape/edit-find.svg @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/inkscape/edit-paste.svg b/src/musredit_qt6/musredit/icons/inkscape/edit-paste.svg new file mode 100644 index 00000000..49233e35 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/inkscape/edit-paste.svg @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/inkscape/edit-redo.svg b/src/musredit_qt6/musredit/icons/inkscape/edit-redo.svg new file mode 100644 index 00000000..8f221de0 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/inkscape/edit-redo.svg @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/inkscape/edit-undo.svg b/src/musredit_qt6/musredit/icons/inkscape/edit-undo.svg new file mode 100644 index 00000000..67add4f4 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/inkscape/edit-undo.svg @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/inkscape/go-next-use.svg b/src/musredit_qt6/musredit/icons/inkscape/go-next-use.svg new file mode 100644 index 00000000..04c85bd1 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/inkscape/go-next-use.svg @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/inkscape/go-previous-use.svg b/src/musredit_qt6/musredit/icons/inkscape/go-previous-use.svg new file mode 100644 index 00000000..15facb2f --- /dev/null +++ b/src/musredit_qt6/musredit/icons/inkscape/go-previous-use.svg @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/inkscape/msr2data.svg b/src/musredit_qt6/musredit/icons/inkscape/msr2data.svg new file mode 100644 index 00000000..9f4cab35 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/inkscape/msr2data.svg @@ -0,0 +1,256 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/inkscape/musrAsym.svg b/src/musredit_qt6/musredit/icons/inkscape/musrAsym.svg new file mode 100644 index 00000000..dedda475 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/inkscape/musrAsym.svg @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + ASYM + + + diff --git a/src/musredit_qt6/musredit/icons/inkscape/musrFT.svg b/src/musredit_qt6/musredit/icons/inkscape/musrFT.svg new file mode 100644 index 00000000..98515d4d --- /dev/null +++ b/src/musredit_qt6/musredit/icons/inkscape/musrFT.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/inkscape/musrSingleHisto.svg b/src/musredit_qt6/musredit/icons/inkscape/musrSingleHisto.svg new file mode 100644 index 00000000..9ea2dd3a --- /dev/null +++ b/src/musredit_qt6/musredit/icons/inkscape/musrSingleHisto.svg @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + HISTO + + + diff --git a/src/musredit_qt6/musredit/icons/inkscape/musrchisq.svg b/src/musredit_qt6/musredit/icons/inkscape/musrchisq.svg new file mode 100644 index 00000000..b0a982fc --- /dev/null +++ b/src/musredit_qt6/musredit/icons/inkscape/musrchisq.svg @@ -0,0 +1,170 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + χ2 + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/inkscape/musrdump.svg b/src/musredit_qt6/musredit/icons/inkscape/musrdump.svg new file mode 100644 index 00000000..c13a8e1f --- /dev/null +++ b/src/musredit_qt6/musredit/icons/inkscape/musrdump.svg @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + DUMP + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/inkscape/musrfit.svg b/src/musredit_qt6/musredit/icons/inkscape/musrfit.svg new file mode 100644 index 00000000..05704d7c --- /dev/null +++ b/src/musredit_qt6/musredit/icons/inkscape/musrfit.svg @@ -0,0 +1,186 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/inkscape/musrprefs.svg b/src/musredit_qt6/musredit/icons/inkscape/musrprefs.svg new file mode 100644 index 00000000..e4d7b3b2 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/inkscape/musrprefs.svg @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + PREFS + + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/inkscape/musrswap.svg b/src/musredit_qt6/musredit/icons/inkscape/musrswap.svg new file mode 100644 index 00000000..c92078f3 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/inkscape/musrswap.svg @@ -0,0 +1,201 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + MLOG + MSR + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/inkscape/musrt0.svg b/src/musredit_qt6/musredit/icons/inkscape/musrt0.svg new file mode 100644 index 00000000..83a2d02f --- /dev/null +++ b/src/musredit_qt6/musredit/icons/inkscape/musrt0.svg @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + T0 + + diff --git a/src/musredit_qt6/musredit/icons/inkscape/musrview.svg b/src/musredit_qt6/musredit/icons/inkscape/musrview.svg new file mode 100644 index 00000000..dea64857 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/inkscape/musrview.svg @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/inkscape/view-refresh.svg b/src/musredit_qt6/musredit/icons/inkscape/view-refresh.svg new file mode 100644 index 00000000..2e3d287e --- /dev/null +++ b/src/musredit_qt6/musredit/icons/inkscape/view-refresh.svg @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/msr2data-dark.svg b/src/musredit_qt6/musredit/icons/msr2data-dark.svg new file mode 100644 index 00000000..87af256a --- /dev/null +++ b/src/musredit_qt6/musredit/icons/msr2data-dark.svg @@ -0,0 +1,265 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/msr2data-plain.svg b/src/musredit_qt6/musredit/icons/msr2data-plain.svg new file mode 100644 index 00000000..6efadaf6 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/msr2data-plain.svg @@ -0,0 +1,256 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/mupp-dark.svg b/src/musredit_qt6/musredit/icons/mupp-dark.svg new file mode 100644 index 00000000..b6e3033a --- /dev/null +++ b/src/musredit_qt6/musredit/icons/mupp-dark.svg @@ -0,0 +1,199 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + P + + + diff --git a/src/musredit_qt6/musredit/icons/mupp-plain.svg b/src/musredit_qt6/musredit/icons/mupp-plain.svg new file mode 100644 index 00000000..eb0b1186 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/mupp-plain.svg @@ -0,0 +1,199 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + P + + + diff --git a/src/musredit_qt6/musredit/icons/musrAsym-plain.svg b/src/musredit_qt6/musredit/icons/musrAsym-plain.svg new file mode 100644 index 00000000..b723be47 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/musrAsym-plain.svg @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + ASYM + + + diff --git a/src/musredit_qt6/musredit/icons/musrFT-dark.svg b/src/musredit_qt6/musredit/icons/musrFT-dark.svg new file mode 100644 index 00000000..55763817 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/musrFT-dark.svg @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/musrFT-plain.svg b/src/musredit_qt6/musredit/icons/musrFT-plain.svg new file mode 100644 index 00000000..e9289a3a --- /dev/null +++ b/src/musredit_qt6/musredit/icons/musrFT-plain.svg @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/musrSingleHisto-plain.svg b/src/musredit_qt6/musredit/icons/musrSingleHisto-plain.svg new file mode 100644 index 00000000..86c2b153 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/musrSingleHisto-plain.svg @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + HISTO + + + diff --git a/src/musredit_qt6/musredit/icons/musrStep-32x32-dark.svg b/src/musredit_qt6/musredit/icons/musrStep-32x32-dark.svg new file mode 100644 index 00000000..fec88e9f --- /dev/null +++ b/src/musredit_qt6/musredit/icons/musrStep-32x32-dark.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/musrStep-32x32.svg b/src/musredit_qt6/musredit/icons/musrStep-32x32.svg new file mode 100644 index 00000000..176bb47e --- /dev/null +++ b/src/musredit_qt6/musredit/icons/musrStep-32x32.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/musrWiz-32x32-dark.svg b/src/musredit_qt6/musredit/icons/musrWiz-32x32-dark.svg new file mode 100644 index 00000000..9f6d2e8e --- /dev/null +++ b/src/musredit_qt6/musredit/icons/musrWiz-32x32-dark.svg @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/musrWiz-32x32.svg b/src/musredit_qt6/musredit/icons/musrWiz-32x32.svg new file mode 100644 index 00000000..1b3cafe5 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/musrWiz-32x32.svg @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/musrchisq-dark.svg b/src/musredit_qt6/musredit/icons/musrchisq-dark.svg new file mode 100644 index 00000000..2086780e --- /dev/null +++ b/src/musredit_qt6/musredit/icons/musrchisq-dark.svg @@ -0,0 +1,153 @@ + + + + + + + + image/svg+xml + + + + + + χ2 + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/musrchisq-plain.svg b/src/musredit_qt6/musredit/icons/musrchisq-plain.svg new file mode 100644 index 00000000..93f6576c --- /dev/null +++ b/src/musredit_qt6/musredit/icons/musrchisq-plain.svg @@ -0,0 +1,127 @@ + + + + + + + image/svg+xml + + + + + + + χ2 + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/musrdump-dark.svg b/src/musredit_qt6/musredit/icons/musrdump-dark.svg new file mode 100644 index 00000000..13d8cf23 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/musrdump-dark.svg @@ -0,0 +1,182 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + DUMP + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/musrdump-plain.svg b/src/musredit_qt6/musredit/icons/musrdump-plain.svg new file mode 100644 index 00000000..f81adb2f --- /dev/null +++ b/src/musredit_qt6/musredit/icons/musrdump-plain.svg @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + DUMP + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/musredit.icns b/src/musredit_qt6/musredit/icons/musredit.icns new file mode 100644 index 00000000..ee2fe513 Binary files /dev/null and b/src/musredit_qt6/musredit/icons/musredit.icns differ diff --git a/src/musredit_qt6/musredit/icons/musredit.ico b/src/musredit_qt6/musredit/icons/musredit.ico new file mode 100644 index 00000000..1fd7720d Binary files /dev/null and b/src/musredit_qt6/musredit/icons/musredit.ico differ diff --git a/src/musredit_qt6/musredit/icons/musrfit-16x16.gif b/src/musredit_qt6/musredit/icons/musrfit-16x16.gif new file mode 100644 index 00000000..14aeef69 Binary files /dev/null and b/src/musredit_qt6/musredit/icons/musrfit-16x16.gif differ diff --git a/src/musredit_qt6/musredit/icons/musrfit-16x16.ico b/src/musredit_qt6/musredit/icons/musrfit-16x16.ico new file mode 100644 index 00000000..247a09df Binary files /dev/null and b/src/musredit_qt6/musredit/icons/musrfit-16x16.ico differ diff --git a/src/musredit_qt6/musredit/icons/musrfit-16x16.png b/src/musredit_qt6/musredit/icons/musrfit-16x16.png new file mode 100644 index 00000000..076937f1 Binary files /dev/null and b/src/musredit_qt6/musredit/icons/musrfit-16x16.png differ diff --git a/src/musredit_qt6/musredit/icons/musrfit-16x16.xpm b/src/musredit_qt6/musredit/icons/musrfit-16x16.xpm new file mode 100644 index 00000000..7826f514 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/musrfit-16x16.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * musrfit_16x16_xpm[] = { +"16 16 3 1", +" c None", +". c #FF0000", +"+ c #000000", +" ... ", +" +... . ", +" .+ ...+. ", +" ... . ... ", +" ... ... ", +" ... ... ", +"+ . .+ ", +" .+ ", +" . ", +" ... ", +"+++ + +++ ... ", +"+ + + ...+ ", +"+++ + + . + ", +"+ + + ...+", +"+ + + ... ", +" ... "}; diff --git a/src/musredit_qt6/musredit/icons/musrfit-dark.svg b/src/musredit_qt6/musredit/icons/musrfit-dark.svg new file mode 100644 index 00000000..45a532c6 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/musrfit-dark.svg @@ -0,0 +1,190 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/musrfit-help-dark.svg b/src/musredit_qt6/musredit/icons/musrfit-help-dark.svg new file mode 100644 index 00000000..de27d7cd --- /dev/null +++ b/src/musredit_qt6/musredit/icons/musrfit-help-dark.svg @@ -0,0 +1,171 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ? + + diff --git a/src/musredit_qt6/musredit/icons/musrfit-help-plain.svg b/src/musredit_qt6/musredit/icons/musrfit-help-plain.svg new file mode 100644 index 00000000..75338437 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/musrfit-help-plain.svg @@ -0,0 +1,171 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ? + + diff --git a/src/musredit_qt6/musredit/icons/musrfit-plain.svg b/src/musredit_qt6/musredit/icons/musrfit-plain.svg new file mode 100644 index 00000000..48931d3f --- /dev/null +++ b/src/musredit_qt6/musredit/icons/musrfit-plain.svg @@ -0,0 +1,186 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/musrfit.gif b/src/musredit_qt6/musredit/icons/musrfit.gif new file mode 100644 index 00000000..c4a7bbc5 Binary files /dev/null and b/src/musredit_qt6/musredit/icons/musrfit.gif differ diff --git a/src/musredit_qt6/musredit/icons/musrprefs-dark.svg b/src/musredit_qt6/musredit/icons/musrprefs-dark.svg new file mode 100644 index 00000000..8687353f --- /dev/null +++ b/src/musredit_qt6/musredit/icons/musrprefs-dark.svg @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + PREFS + + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/musrprefs-plain.svg b/src/musredit_qt6/musredit/icons/musrprefs-plain.svg new file mode 100644 index 00000000..7230817b --- /dev/null +++ b/src/musredit_qt6/musredit/icons/musrprefs-plain.svg @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + PREFS + + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/musrswap-dark.svg b/src/musredit_qt6/musredit/icons/musrswap-dark.svg new file mode 100644 index 00000000..79151fc6 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/musrswap-dark.svg @@ -0,0 +1,206 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + MLOG + MSR + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/musrswap-plain.svg b/src/musredit_qt6/musredit/icons/musrswap-plain.svg new file mode 100644 index 00000000..31cd08e3 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/musrswap-plain.svg @@ -0,0 +1,201 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + MLOG + MSR + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/musrt0-dark.svg b/src/musredit_qt6/musredit/icons/musrt0-dark.svg new file mode 100644 index 00000000..3630dd7f --- /dev/null +++ b/src/musredit_qt6/musredit/icons/musrt0-dark.svg @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + T0 + diff --git a/src/musredit_qt6/musredit/icons/musrt0-plain.svg b/src/musredit_qt6/musredit/icons/musrt0-plain.svg new file mode 100644 index 00000000..28da0830 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/musrt0-plain.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + T0 + + diff --git a/src/musredit_qt6/musredit/icons/musrview-dark.svg b/src/musredit_qt6/musredit/icons/musrview-dark.svg new file mode 100644 index 00000000..1831940f --- /dev/null +++ b/src/musredit_qt6/musredit/icons/musrview-dark.svg @@ -0,0 +1,173 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/musrview-plain.svg b/src/musredit_qt6/musredit/icons/musrview-plain.svg new file mode 100644 index 00000000..36edb07f --- /dev/null +++ b/src/musredit_qt6/musredit/icons/musrview-plain.svg @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/icons/view-refresh-dark.svg b/src/musredit_qt6/musredit/icons/view-refresh-dark.svg new file mode 100644 index 00000000..0b66cbef --- /dev/null +++ b/src/musredit_qt6/musredit/icons/view-refresh-dark.svg @@ -0,0 +1,17 @@ + + + + + + diff --git a/src/musredit_qt6/musredit/icons/view-refresh-plain.svg b/src/musredit_qt6/musredit/icons/view-refresh-plain.svg new file mode 100644 index 00000000..c78579d9 --- /dev/null +++ b/src/musredit_qt6/musredit/icons/view-refresh-plain.svg @@ -0,0 +1,91 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/musredit_qt6/musredit/latex_images/abragam.png b/src/musredit_qt6/musredit/latex_images/abragam.png new file mode 100644 index 00000000..d3c11151 Binary files /dev/null and b/src/musredit_qt6/musredit/latex_images/abragam.png differ diff --git a/src/musredit_qt6/musredit/latex_images/abragam.tex b/src/musredit_qt6/musredit/latex_images/abragam.tex new file mode 100644 index 00000000..372a9a38 --- /dev/null +++ b/src/musredit_qt6/musredit/latex_images/abragam.tex @@ -0,0 +1,9 @@ +\documentclass[12pt]{article} +\pagestyle{empty} +\begin{document} + +\begin{displaymath} +\exp\left[ -(\sigma/\gamma)^2 \left( e^{-\gamma t} - 1 + \gamma t\right) \right] +\end{displaymath} + +\end{document} \ No newline at end of file diff --git a/src/musredit_qt6/musredit/latex_images/asymmetry.png b/src/musredit_qt6/musredit/latex_images/asymmetry.png new file mode 100644 index 00000000..8d54c017 Binary files /dev/null and b/src/musredit_qt6/musredit/latex_images/asymmetry.png differ diff --git a/src/musredit_qt6/musredit/latex_images/asymmetry.tex b/src/musredit_qt6/musredit/latex_images/asymmetry.tex new file mode 100644 index 00000000..f21bd2aa --- /dev/null +++ b/src/musredit_qt6/musredit/latex_images/asymmetry.tex @@ -0,0 +1,9 @@ +\documentclass[12pt]{article} +\pagestyle{empty} +\begin{document} + +\begin{displaymath} +A +\end{displaymath} + +\end{document} \ No newline at end of file diff --git a/src/musredit_qt6/musredit/latex_images/bessel.png b/src/musredit_qt6/musredit/latex_images/bessel.png new file mode 100644 index 00000000..d0801169 Binary files /dev/null and b/src/musredit_qt6/musredit/latex_images/bessel.png differ diff --git a/src/musredit_qt6/musredit/latex_images/bessel.tex b/src/musredit_qt6/musredit/latex_images/bessel.tex new file mode 100644 index 00000000..0b372d7b --- /dev/null +++ b/src/musredit_qt6/musredit/latex_images/bessel.tex @@ -0,0 +1,9 @@ +\documentclass[12pt]{article} +\pagestyle{empty} +\begin{document} + +\begin{displaymath} +j_0(2\pi\nu t + \phi \pi/180) +\end{displaymath} + +\end{document} \ No newline at end of file diff --git a/src/musredit_qt6/musredit/latex_images/combiLGKT.png b/src/musredit_qt6/musredit/latex_images/combiLGKT.png new file mode 100644 index 00000000..01734338 Binary files /dev/null and b/src/musredit_qt6/musredit/latex_images/combiLGKT.png differ diff --git a/src/musredit_qt6/musredit/latex_images/combiLGKT.tex b/src/musredit_qt6/musredit/latex_images/combiLGKT.tex new file mode 100644 index 00000000..49213056 --- /dev/null +++ b/src/musredit_qt6/musredit/latex_images/combiLGKT.tex @@ -0,0 +1,9 @@ +\documentclass[12pt]{article} +\pagestyle{empty} +\begin{document} + +\begin{displaymath} +1/3 \left[ 1 + 2\, \left\{ 1 - (\sigma t)^2 - \lambda t\right\}\right]\, e^{-(\sigma t)^2/2 - \lambda t} +\end{displaymath} + +\end{document} \ No newline at end of file diff --git a/src/musredit_qt6/musredit/latex_images/generalExp.png b/src/musredit_qt6/musredit/latex_images/generalExp.png new file mode 100644 index 00000000..6cdc0248 Binary files /dev/null and b/src/musredit_qt6/musredit/latex_images/generalExp.png differ diff --git a/src/musredit_qt6/musredit/latex_images/generalExp.tex b/src/musredit_qt6/musredit/latex_images/generalExp.tex new file mode 100644 index 00000000..d99ea317 --- /dev/null +++ b/src/musredit_qt6/musredit/latex_images/generalExp.tex @@ -0,0 +1,9 @@ +\documentclass[12pt]{article} +\pagestyle{empty} +\begin{document} + +\begin{displaymath} +\exp\left[-(\lambda t)^\beta\right] +\end{displaymath} + +\end{document} \ No newline at end of file diff --git a/src/musredit_qt6/musredit/latex_images/internalBessel.png b/src/musredit_qt6/musredit/latex_images/internalBessel.png new file mode 100644 index 00000000..0220ead7 Binary files /dev/null and b/src/musredit_qt6/musredit/latex_images/internalBessel.png differ diff --git a/src/musredit_qt6/musredit/latex_images/internalBessel.tex b/src/musredit_qt6/musredit/latex_images/internalBessel.tex new file mode 100644 index 00000000..934d2b17 --- /dev/null +++ b/src/musredit_qt6/musredit/latex_images/internalBessel.tex @@ -0,0 +1,9 @@ +\documentclass[12pt]{article} +\pagestyle{empty} +\begin{document} + +\begin{displaymath} +\alpha j_0\left(2\pi\nu t + \phi\pi/180\right) e^{-\lambda_{\rm T} t} + (1-\alpha) e^{-\lambda_{\rm L} t} +\end{displaymath} + +\end{document} \ No newline at end of file diff --git a/src/musredit_qt6/musredit/latex_images/internalField.png b/src/musredit_qt6/musredit/latex_images/internalField.png new file mode 100644 index 00000000..a75823cf Binary files /dev/null and b/src/musredit_qt6/musredit/latex_images/internalField.png differ diff --git a/src/musredit_qt6/musredit/latex_images/internalField.tex b/src/musredit_qt6/musredit/latex_images/internalField.tex new file mode 100644 index 00000000..57606995 --- /dev/null +++ b/src/musredit_qt6/musredit/latex_images/internalField.tex @@ -0,0 +1,20 @@ +\documentclass[12pt]{article} +\pagestyle{empty} +\begin{document} + +% internal field, delta-B +\begin{displaymath} +\alpha \cos\left(2\pi\nu t + \phi\pi/180\right) e^{-\lambda_{\rm T} t} + (1-\alpha) e^{-\lambda_{\rm L} t} +\end{displaymath} + +% internal field, Gaussian broadened +\begin{displaymath} +\alpha \left[\cos(2\pi\nu t) -\frac{\sigma^2 t}{2\pi\nu}\sin(2\pi\nu t)\right] e^{-(\sigma t)^2/2} + (1-\alpha) e^{-(\lambda t)^\beta} +\end{displaymath} + +% internal field, Lorentzian broadened +\begin{displaymath} +\alpha \left[\cos(2\pi\nu t) -\frac{a}{2\pi\nu}\sin(2\pi\nu t)\right] e^{-a t} + (1-\alpha) e^{-\lambda t} +\end{displaymath} + +\end{document} \ No newline at end of file diff --git a/src/musredit_qt6/musredit/latex_images/internalFieldGK.png b/src/musredit_qt6/musredit/latex_images/internalFieldGK.png new file mode 100644 index 00000000..3a8462e2 Binary files /dev/null and b/src/musredit_qt6/musredit/latex_images/internalFieldGK.png differ diff --git a/src/musredit_qt6/musredit/latex_images/internalFieldLL.png b/src/musredit_qt6/musredit/latex_images/internalFieldLL.png new file mode 100644 index 00000000..72bff3e0 Binary files /dev/null and b/src/musredit_qt6/musredit/latex_images/internalFieldLL.png differ diff --git a/src/musredit_qt6/musredit/latex_images/polynom.png b/src/musredit_qt6/musredit/latex_images/polynom.png new file mode 100644 index 00000000..ae2c018e Binary files /dev/null and b/src/musredit_qt6/musredit/latex_images/polynom.png differ diff --git a/src/musredit_qt6/musredit/latex_images/polynom.tex b/src/musredit_qt6/musredit/latex_images/polynom.tex new file mode 100644 index 00000000..cfcdf4b0 --- /dev/null +++ b/src/musredit_qt6/musredit/latex_images/polynom.tex @@ -0,0 +1,9 @@ +\documentclass[12pt]{article} +\pagestyle{empty} +\begin{document} + +\begin{displaymath} +\sum_{k=0}^n a_k (t-t_0)^k +\end{displaymath} + +\end{document} \ No newline at end of file diff --git a/src/musredit_qt6/musredit/latex_images/simpleExp.png b/src/musredit_qt6/musredit/latex_images/simpleExp.png new file mode 100644 index 00000000..e033d578 Binary files /dev/null and b/src/musredit_qt6/musredit/latex_images/simpleExp.png differ diff --git a/src/musredit_qt6/musredit/latex_images/simpleExp.tex b/src/musredit_qt6/musredit/latex_images/simpleExp.tex new file mode 100644 index 00000000..86049aa1 --- /dev/null +++ b/src/musredit_qt6/musredit/latex_images/simpleExp.tex @@ -0,0 +1,9 @@ +\documentclass[12pt]{article} +\pagestyle{empty} +\begin{document} + +\begin{displaymath} +\exp(-\lambda t) +\end{displaymath} + +\end{document} \ No newline at end of file diff --git a/src/musredit_qt6/musredit/latex_images/simpleGauss.png b/src/musredit_qt6/musredit/latex_images/simpleGauss.png new file mode 100644 index 00000000..a5b8ed8c Binary files /dev/null and b/src/musredit_qt6/musredit/latex_images/simpleGauss.png differ diff --git a/src/musredit_qt6/musredit/latex_images/simpleGauss.tex b/src/musredit_qt6/musredit/latex_images/simpleGauss.tex new file mode 100644 index 00000000..e8f20339 --- /dev/null +++ b/src/musredit_qt6/musredit/latex_images/simpleGauss.tex @@ -0,0 +1,9 @@ +\documentclass[12pt]{article} +\pagestyle{empty} +\begin{document} + +\begin{displaymath} +\exp\left[-1/2(\sigma t)^2\right] +\end{displaymath} + +\end{document} \ No newline at end of file diff --git a/src/musredit_qt6/musredit/latex_images/statExpKT.png b/src/musredit_qt6/musredit/latex_images/statExpKT.png new file mode 100644 index 00000000..60e13e78 Binary files /dev/null and b/src/musredit_qt6/musredit/latex_images/statExpKT.png differ diff --git a/src/musredit_qt6/musredit/latex_images/statExpKT.tex b/src/musredit_qt6/musredit/latex_images/statExpKT.tex new file mode 100644 index 00000000..32a8e61f --- /dev/null +++ b/src/musredit_qt6/musredit/latex_images/statExpKT.tex @@ -0,0 +1,9 @@ +\documentclass[12pt]{article} +\pagestyle{empty} +\begin{document} + +\begin{displaymath} +1/3 \left[ 1 + 2\, \left\{ 1 - \lambda t \right\}\right]\, e^{-\lambda t} +\end{displaymath} + +\end{document} \ No newline at end of file diff --git a/src/musredit_qt6/musredit/latex_images/statGssKT.png b/src/musredit_qt6/musredit/latex_images/statGssKT.png new file mode 100644 index 00000000..e28023b5 Binary files /dev/null and b/src/musredit_qt6/musredit/latex_images/statGssKT.png differ diff --git a/src/musredit_qt6/musredit/latex_images/statGssKT.tex b/src/musredit_qt6/musredit/latex_images/statGssKT.tex new file mode 100644 index 00000000..4852ffb7 --- /dev/null +++ b/src/musredit_qt6/musredit/latex_images/statGssKT.tex @@ -0,0 +1,9 @@ +\documentclass[12pt]{article} +\pagestyle{empty} +\begin{document} + +\begin{displaymath} +1/3 \left[ 1 + 2\, \left\{ 1 - (\sigma t)^2 \right\}\right]\, e^{-(\sigma t)^2/2}~ +\end{displaymath} + +\end{document} \ No newline at end of file diff --git a/src/musredit_qt6/musredit/latex_images/textogif b/src/musredit_qt6/musredit/latex_images/textogif new file mode 100644 index 00000000..f5d98b2f --- /dev/null +++ b/src/musredit_qt6/musredit/latex_images/textogif @@ -0,0 +1,233 @@ +#! /usr/bin/perl +# +# T E X T O G I F +# +# by John Walker +# http://www.fourmilab.ch/ +# + $version = '1.1 (2003-11-07)'; +# +# +# Converts a LaTeX file containing equations(s) into a GIF file for +# embedding into an HTML document. The black and white image of the +# equation is created at high resolution and then resampled to the +# target resolution to antialias what would otherwise be jagged +# edges. +# +# Online documentation with sample output is available on the Web +# at http://www.fourmilab.ch/webtools/textogif/ +# +# Write your equation (or anything else you can typeset with LaTeX) +# in a file like: +# +# \documentclass[12pt]{article} +# \pagestyle{empty} +# \begin{document} +# +# \begin{displaymath} +# \bf % Compiled formulae often look better in boldface +# \int H(x,x')\psi(x')dx' = -\frac{\hbar2}{2m}\frac{d2}{dx2} +# \psi(x)+V(x)\psi(x) +# \end{displaymath} +# +# \end{document} +# +# The "\pagestyle{empty}" is required to avoid generating a huge +# image with a page number at the bottom. +# +# Then (assuming you have all the software described below installed +# properly), you can simply say: +# +# textogif [options] filename ... +# +# to compile filename.tex to filename.gif, an interlaced, +# transparent background GIF file ready to use an an inline image. +# You can specify the base name, for example, "schrod", rather than +# the full name of the TeX file ("schrod.tex"). TeX requires the +# input file to have an extension of ".tex". The command line +# options are described in the help text at the end of this program +# and in the "Default Configuration" section below. +# +# A sample IMG tag, including the image width and height is printed +# on standard error, for example: +# +# +# +# Required Software +# +# This script requires the following software to be installed +# in the standard manner. Version numbers are those used in the +# development and testing of the script. +# +# Perl 5.8.0 (anything later than 4.036 should work) +# TeX 3.14159 (Web2C 7.3.1) +# LaTeX2e <2000/06/01> +# dvips dvipsk 5.86 +# Ghostscript 6.52 (2001-10-20) +# Netpbm 9.24 +# +# +# Default Configuration +# +# The following settings are the defaults used if the -dpi and +# -res options are not specified on the command line. +# +# The parameter $dpi controls how large the equation will appear +# with respect to other inline images and the surrounding text. +# The parameter is expressed in "dots per inch" in the PostScript +# sense. Unfortunately, since there's no standard text size in +# Web browsers (and most allow the user to change fonts and +# point sizes), there's no "right" value for this setting. The +# default of 150 seems about right for most documents. A setting +# of 75 generates equations at half the normal size, while 300 +# doubles the size of equations. The setting of $dpi can always be +# overridden by specifying the "-dpi" command line option. +# + $dpi = 150; +# +# The parameter $res specifies the oversampling as the ratio +# of the final image size to the initial black and white image. +# Smaller values produce smoothing with more levels of grey but +# require (much) more memory and intermediate file space to create +# the image. If you run out of memory or disc space with the +# default value of 0.5, try changing it to 0.75. A $res setting of +# 1.0 disables antialiasing entirely. The setting of $res can +# always be overridden by specifying the "res" command line option. +# + $res = 0.5; +# +# The $background parameter supplies a command, which may be +# void, to be inserted in the image processing pipeline to +# adjust the original black-on-white image so that its background +# agrees with that of the document in which it is to be inserted. +# For a document with the default grey background used by Mosaic +# and old versions of Netscape, use: +# +# $background = "ppmdim 0.7 |"; $transparent = "b2/b2/b2"; +# +# If your document uses a white background, the void specification: +# +# $background = ""; $transparent = "ff/ff/ff"; +# +# should be used. For colour or pattern backgrounds, you'll have +# to hack the code. The reason for adjusting the background is to +# ensure that when the image is resampled and then output with a +# transparent background the edges of the characters will fade +# smoothly into the page background. Otherwise you'll get a +# distracting "halo" around each character. You can override this +# default specification with the -grey command line option. +# + $background = ""; $transparent = "ff/ff/ff"; +# +# Image generation and decoding commands for GIF and PNG output. +# + $cmdGIF = 'ppmtogif'; + $cmdGIFdecode = 'giftopnm'; + $cmdPNG = 'pnmtopng'; + $cmdPNGdecode = 'pngtopnm'; +# +# Default image creation modes +# + $imageCmd = $cmdGIF; + $imageCmdD = $cmdGIFdecode; + $imageExt = 'gif'; + + # + # Command line option processing + # + while ($ARGV[0] =~ m/^-/) { + $_ = shift(@ARGV); + s/^--/-/; # Allow GNU-style -- options + if (m/^-d/) { # -dpi nnn + $dpi = shift(@ARGV); + } elsif (m/^-gi/) { # -gif + $imageCmd = $cmdGIF; + $imageCmdD = $cmdGIFdecode; + $imageExt = 'gif'; + } elsif (m/^-gr/) { # -grey n + $grey = shift(@ARGV); + $background = "ppmdim $grey | "; + $greylev = int(255 * $grey); + $transparent = sprintf("%02x/%02x/%02x", $greylev, $greylev, $greylev); + } elsif (m/^-h/) { # -help + &help(); + exit(0); + } elsif (m/^-p/) { # -png + $imageCmd = $cmdPNG; + $imageCmdD = $cmdPNGdecode; + $imageExt = 'png'; + } elsif (m/^-r/) { # -res nnn + $res = shift(@ARGV); + } elsif (m/^-v/) { # -version + print("Version $version\n"); + exit(0); + } + } + # + # Main file processing loop + # + foreach $f (@ARGV) { + $f =~ s/(.*)\.tex$/$1/; + &syscmd("echo x | latex $f \n"); + &syscmd("dvips -f $f >_temp_$$.ps\n"); + + # Assemble and execute the command pipeline which generates the image. + + # Start by invoking Ghostscript with the pbmraw output device and + # output file set to standard output ("-") and the requested resolution. + # The -q (Quiet) option is required; otherwise Ghostscript will send + # processing information to standard output and corrupt transmission + # of the bitmap to the next component in the pipeline. + $cmd = "echo quit | gs -q -dNOPAUSE -r" . int($dpi / $res). "x". int($dpi / $res) . + " -sOutputFile=- -sDEVICE=pbmraw _temp_$$.ps | " . + + # Next we crop white space surrounding the generated text, promote + # the monochrome bitmap to a grey scale image with 8 bits per pixel, + # apply whatever background adjustment transform is requested, and + # scale the image to the desired size. + "pnmcrop -white | pnmdepth 255 | $background pnmscale " . + $res . " | " . + + # Finally, convert the image to the desired output format and write + # the output file. + "$imageCmd -interlace -transparent rgb:$transparent >$f.$imageExt"; + &syscmd($cmd); + + # Sweep up debris left around by the various intermediate steps + &syscmd("rm $f.dvi $f.aux $f.log _temp_$$.ps"); + + # Print the reference to include this figure, including width and height, + # to standard error. + $r = `$imageCmdD $f.$imageExt | pnmfile`; + $r =~ m/(\d+) by (\d+)/; + print(STDERR "\n"); + } + + # Echo and execute a system command + + sub syscmd { + local ($cmd) = @_; + + print(STDERR "$cmd\n"); + system($cmd) == 0 || die("Error processing command:\n\t$cmd\n\t"); + } + + # Print help text + + sub help { + print <<"EOD" +usage: textogif [ options ] texfile... + Options: + -dpi n Set rendering dots per inch to n (default 150) + -gif Generate GIF image (default) + -grey Grey scale background level: 0 = black, 1 = white (default) + -help Print this message + -png Generate PNG image + -res n Set oversampling ratio, smaller = finer (default 0.5) + -version Print version number +For documentation and the latest version of this program +please visit the Web page: + http://www.fourmilab.ch/webtools/textogif/ +EOD +; + } diff --git a/src/musredit_qt6/musredit/latex_images/tfCos.png b/src/musredit_qt6/musredit/latex_images/tfCos.png new file mode 100644 index 00000000..eb925afb Binary files /dev/null and b/src/musredit_qt6/musredit/latex_images/tfCos.png differ diff --git a/src/musredit_qt6/musredit/latex_images/tfCos.tex b/src/musredit_qt6/musredit/latex_images/tfCos.tex new file mode 100644 index 00000000..eff39d22 --- /dev/null +++ b/src/musredit_qt6/musredit/latex_images/tfCos.tex @@ -0,0 +1,9 @@ +\documentclass[12pt]{article} +\pagestyle{empty} +\begin{document} + +\begin{displaymath} +\cos\left(2\pi\nu t + \phi\pi/180\right) +\end{displaymath} + +\end{document} \ No newline at end of file diff --git a/src/musredit_qt6/musredit/main.cpp b/src/musredit_qt6/musredit/main.cpp new file mode 100644 index 00000000..76dfe392 --- /dev/null +++ b/src/musredit_qt6/musredit/main.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** + + main.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2010-2019 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 "git-revision.h" +#include "PTextEdit.h" +#include "PFitOutputHandler.h" + +/** + *

musredit is a simple editor based interface to the musrfit programs. It is based on Qt 4.6 + * of Digia (http://qt.digia.com and http://qt-project.org/). + * + *

musredit is free software liensenced under GPL 2 or later (for detail license informations see + * http://www.gnu.org/licenses). + */ +int main( int argc, char ** argv ) +{ + Q_INIT_RESOURCE(musredit); + + if (argc == 2) { + if (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")) { + std::cout << std::endl << "usage: musredit [] | -h, --help | -v, --version"; + std::cout << std::endl << std::endl; + return 0; + } else if (!strcmp(argv[1], "--version") || !strcmp(argv[1], "-v")) { + std::cout << std::endl << "musredit git-branch: " << GIT_BRANCH << ", git-rev: " << GIT_CURRENT_SHA1; + std::cout << std::endl << std::endl; + return 0; + } + } + + QApplication a( argc, argv ); + + PTextEdit *mw = new PTextEdit(); + mw->setWindowTitle( "MusrFit Editor" ); + mw->resize( 800, 800 ); + mw->show(); + + a.connect( &a, SIGNAL( lastWindowClosed() ), &a, SLOT( quit() ) ); + a.connect( &a, SIGNAL( aboutToQuit() ), mw, SLOT( aboutToQuit() ) ); + return a.exec(); +} diff --git a/src/musredit_qt6/musredit/musredit.dox b/src/musredit_qt6/musredit/musredit.dox new file mode 100644 index 00000000..064af8ee --- /dev/null +++ b/src/musredit_qt6/musredit/musredit.dox @@ -0,0 +1,21 @@ +/********************************************************************************************* + + name: musredit.dox + + created by: Andreas Suter, 2015/10/26 + + content: Description of musredit. + +**********************************************************************************************/ + +/** + +\mainpage musredit + +

musredit is a simple editor based interface to the musrfit programs. It is based on Qt 5.5 +of The Qt Company (http://www.qt.io). + +

musredit is free software liensenced under GPL 2 or later (for detail license informations see +http://www.gnu.org/licenses). + +*/ diff --git a/src/musredit_qt6/musredit/musredit.h b/src/musredit_qt6/musredit/musredit.h new file mode 100644 index 00000000..8cdbb2f1 --- /dev/null +++ b/src/musredit_qt6/musredit/musredit.h @@ -0,0 +1,81 @@ +/**************************************************************************** + + musredit.h + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + +*****************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2010-2019 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. * + ***************************************************************************/ + +#ifndef _MUSREDIT_H_ +#define _MUSREDIT_H_ + +#include + +#define MAX_RECENT_FILES 5 + +//------------------------------------------------------------------------------------------------- +/** + *

This structure is used in conjunction to msr2data. It stores the necessary + * parameters to handle msr2data. For a detailed description of the meaning of these + * parameters see msr2data --help and the online documentation. + */ +typedef struct { + QString runList; ///< list of run numbers (usage 3 of msr2data) + QString runListFileName; ///< run list filename (usage 4 of msr2data) + QString msrFileExtension; ///< msr filename extension, e.g. '0100_h13.msr' -> '_h13' + int templateRunNo; ///< fit template run number + QString paramList; ///< parameter list to be exported. + QString dbOutputFileName; ///< output file name for the generated (trumf-like) db-file. + bool writeDbHeader; ///< flag indicating if a db header shall be generated (== !noheader in msr2data) + bool ignoreDataHeaderInfo; ///< flag indicating if data header info (like temp.) shall be ignored (== nosummary in msr2data) + bool keepMinuit2Output; ///< flag indicating if the minuit2 output shall be kept ('-k' in msr2data) + bool writeColumnData; ///< flag indicating if instead of a db-file a column data ascii file shall be written ('data' in msr2data) + bool recreateDbFile; ///< flag: true = recreate db-file, false = append to present db-file + bool chainFit; ///< flag: true = chain fit, i.e. the template for a fit is the preceeding run. false = the template is always the source for the new msr-file + bool openFilesAfterFitting; ///< flag: true = open msr-file after fit in musredit. false = do not open msr-file after fit. + bool titleFromDataFile; ///< flag indicating if the title for the msr-file shall be extracted from the data-file ('-t' in msr2data) + bool estimateN0; ///< flag indicating if the N0 shall be estimated for single histogram fitting + bool perRunBlockChisq; ///< flag indicating if per-run-block-chisq shall be dumped into the msr-file + bool createMsrFileOnly; ///< flag: true = just create the msr-files without any fitting ('msr-