diff --git a/Core/Algorithms/src/ProgressHandler.cpp b/Core/Algorithms/src/ProgressHandler.cpp index 2728585b21043cd50acc0e8dd85bbb536d1f146c..69ded07d4a22150ef75bcb30158ba3dd65896261 100644 --- a/Core/Algorithms/src/ProgressHandler.cpp +++ b/Core/Algorithms/src/ProgressHandler.cpp @@ -58,10 +58,11 @@ bool ProgressHandler::update(int n) //std::cout << "ProgressHandler::update n:" << n << " m_nitems:" << m_nitems << " m_nitems_max:" << m_nitems_max << " progress:" << progress << std::endl; if(progress != m_current_progress) { m_current_progress = progress; - if(m_callback) { - continue_calculations = m_callback(m_current_progress); // report to gui - } } + if(m_callback) { + continue_calculations = m_callback(m_current_progress); // report to gui + } + return continue_calculations; } diff --git a/Fit/FitKernel/inc/FitKernel.h b/Fit/FitKernel/inc/FitKernel.h index 7d1543f41c24dd04d6341b031f441b8f887a6602..6c9fc3ee4f7234ae99efb33b279b8d6b1df611cd 100644 --- a/Fit/FitKernel/inc/FitKernel.h +++ b/Fit/FitKernel/inc/FitKernel.h @@ -27,6 +27,7 @@ #include <string> #include <boost/date_time/posix_time/posix_time.hpp> #include <boost/scoped_ptr.hpp> +#include <atomic> class GISASSimulation; class ParameterPool; @@ -100,7 +101,13 @@ class BA_CORE_API_ FitKernel void notifyObservers(); - private: + bool isInterrupted() const; + + void interruptFitting(); + + void resetInterrupt(); + +private: FitKernel& operator=(const FitKernel& ); FitKernel(const FitKernel& ); @@ -115,6 +122,7 @@ class BA_CORE_API_ FitKernel FitSuiteChiSquaredFunction m_function_chi2; FitSuiteGradientFunction m_function_gradient; bool m_is_last_iteration; + std::atomic<bool> m_is_interrupted; boost::posix_time::ptime m_start_time; boost::posix_time::ptime m_end_time; FitSuite *m_fit_suite; diff --git a/Fit/FitKernel/inc/FitSuite.h b/Fit/FitKernel/inc/FitSuite.h index 5310d3b4090dd06d7985007a71f30124886e13f8..86d5bfa236f1fa878f6d3e451170d64f1112ae79 100644 --- a/Fit/FitKernel/inc/FitSuite.h +++ b/Fit/FitKernel/inc/FitSuite.h @@ -19,6 +19,7 @@ #include "IObserver.h" #include "FitKernel.h" #include "IHistogram.h" +#include "OutputData.h" //! @class FitSuite @@ -135,6 +136,18 @@ public: //! Sets general setting of fit kernel void setOptions(const FitOptions &fit_options); + void interruptFitting(); + + void resetInterrupt(); + + bool isInterrupted(); + + const OutputData<double> *getRealOutputData(size_t i_item = 0) const; + + const OutputData<double> *getSimulationOutputData(size_t i_item = 0) const; + + const OutputData<double> *getChiSquaredOutputData(size_t i_item = 0) const; + private: FitSuite& operator=(const FitSuite& ); FitSuite(const FitSuite& ); diff --git a/Fit/FitKernel/src/FitKernel.cpp b/Fit/FitKernel/src/FitKernel.cpp index d02b73ea7ba8445b7d73fbd4a1b3901cd8177f5b..bf2ff21a6d7df80716b639bb3b2bf79fca5d7354 100644 --- a/Fit/FitKernel/src/FitKernel.cpp +++ b/Fit/FitKernel/src/FitKernel.cpp @@ -26,6 +26,7 @@ FitKernel::FitKernel(FitSuite *fit_suite) : m_minimizer(MinimizerFactory::createMinimizer("Minuit2", "Migrad")) , m_is_last_iteration(false) + , m_is_interrupted(false) , m_fit_suite(fit_suite) { m_function_chi2.init(this); @@ -45,6 +46,7 @@ void FitKernel::clear() m_fit_parameters.clear(); m_fit_strategies.clear(); m_is_last_iteration = false; + m_is_interrupted = false; } //! Adds pair of (simulation, real data) for consecutive simulation @@ -119,7 +121,9 @@ void FitKernel::minimize() m_fit_objects.setNfreeParameters((int)m_fit_parameters.getNfreeParameters()); // minimizing - m_minimizer->minimize(); + try { + m_minimizer->minimize(); + } catch (int) {} // setting found values to the parameters m_fit_parameters.setValues(m_minimizer->getValueOfVariablesAtMinimum()); @@ -165,6 +169,20 @@ size_t FitKernel::getCurrentStrategyIndex() const return m_fit_strategies.getCurrentStrategyIndex(); } +bool FitKernel::isInterrupted() const +{ + return m_is_interrupted; +} + +void FitKernel::interruptFitting() +{ + m_is_interrupted = true; +} + +void FitKernel::resetInterrupt() +{ + m_is_interrupted = false; +} // results to stdout void FitKernel::printResults() const diff --git a/Fit/FitKernel/src/FitSuite.cpp b/Fit/FitKernel/src/FitSuite.cpp index eeda74b1773dafcb4edc9aa2810c860e379557b3..39010541793c37ccae34c3d9f9ee2e98f8b9ac42 100644 --- a/Fit/FitKernel/src/FitSuite.cpp +++ b/Fit/FitKernel/src/FitSuite.cpp @@ -119,6 +119,22 @@ IHistogram *FitSuite::getChiSquaredMap(size_t i_item) const return IHistogram::createHistogram(*data); } +const OutputData<double> *FitSuite::getRealOutputData(size_t i_item) const +{ + return m_kernel->getFitObjects()->getRealData(i_item); +} + +const OutputData<double> *FitSuite::getSimulationOutputData(size_t i_item) const +{ + return m_kernel->getFitObjects()->getSimulationData(i_item); +} + +const OutputData<double> *FitSuite::getChiSquaredOutputData(size_t i_item) const +{ + return m_kernel->getFitObjects()->getChiSquaredMap(i_item); +} + + FitSuiteObjects *FitSuite::getFitObjects() { return m_kernel->getFitObjects(); @@ -159,14 +175,17 @@ double FitSuite::getChi2() const return m_kernel->getFitObjects()->getChiSquaredValue(); } -FitOptions &FitSuite::getOptions() +void FitSuite::interruptFitting() { - return m_kernel->getOptions(); + m_kernel->interruptFitting(); } -void FitSuite::setOptions(const FitOptions &fit_options) +void FitSuite::resetInterrupt() { - m_kernel->setOptions(fit_options); + m_kernel->resetInterrupt(); } - +bool FitSuite::isInterrupted() +{ + return m_kernel->isInterrupted(); +} diff --git a/Fit/FitKernel/src/FitSuiteFunctions.cpp b/Fit/FitKernel/src/FitSuiteFunctions.cpp index 08a17eb00209009470758c740818baa797f221d9..5fc4923ed6a5d35a1b140a65de972cf5e13c5558 100644 --- a/Fit/FitKernel/src/FitSuiteFunctions.cpp +++ b/Fit/FitKernel/src/FitSuiteFunctions.cpp @@ -23,6 +23,9 @@ double FitSuiteChiSquaredFunction::evaluate(const double *pars) { assert(m_fit_kernel != nullptr); + if (m_fit_kernel->isInterrupted()) + throw 0; + m_fit_kernel->getFitParameters()->setValues(pars); m_fit_kernel->getFitObjects()->runSimulations(); double chi_squared = m_fit_kernel->getFitObjects()->getChiSquaredValue(); diff --git a/Fit/PythonAPI/src/FitSuite.pypp.cpp b/Fit/PythonAPI/src/FitSuite.pypp.cpp index 3110569d09ca64b49aa2783505f578783204dd83..20780dc3bb105a576533831b951a4f86860b12e8 100644 --- a/Fit/PythonAPI/src/FitSuite.pypp.cpp +++ b/Fit/PythonAPI/src/FitSuite.pypp.cpp @@ -218,7 +218,7 @@ void register_FitSuite_class(){ , "Returns current number of minimization function calls." ); } - { //::FitSuite::getOptions + /*{ //::FitSuite::getOptions typedef ::FitOptions & ( ::FitSuite::*getOptions_function_type)( ) ; @@ -228,7 +228,7 @@ void register_FitSuite_class(){ , bp::return_value_policy< bp::reference_existing_object >() , "Returns general setting of fit kernel." ); - } + }*/ { //::FitSuite::getRealData typedef ::IHistogram * ( ::FitSuite::*getRealData_function_type)( ::std::size_t ) const; @@ -326,7 +326,7 @@ void register_FitSuite_class(){ , "Sets minimizer with given name and algorithm type @param minimizer The name of the minimizer @param algorithm Optional name of the minimizer's algorithm @param options Optional string with additional minimizer settings \n\n:Parameters:\n - 'minimizer' - The name of the minimizer\n - 'algorithm' - Optional name of the minimizer's algorithm\n - 'options' - Optional string with additional minimizer settings\n" ); } - { //::FitSuite::setOptions + /*{ //::FitSuite::setOptions typedef void ( ::FitSuite::*setOptions_function_type)( ::FitOptions const & ) ; @@ -336,7 +336,7 @@ void register_FitSuite_class(){ , ( bp::arg("fit_options") ) , "Sets general setting of fit kernel." ); - } + }*/ { //::FitSuite::setParametersFixed typedef void ( ::FitSuite::*setParametersFixed_function_type)( ::std::vector< std::string > const &,bool ) ; diff --git a/GUI/coregui/Models/FitModel.cpp b/GUI/coregui/Models/FitModel.cpp index 41b4c5188a6da5225d7c0c67c6a05e8041cf26d0..ee4d89bd68b38fbd577cf9e48609b0c9fb99374a 100644 --- a/GUI/coregui/Models/FitModel.cpp +++ b/GUI/coregui/Models/FitModel.cpp @@ -2,8 +2,8 @@ // // BornAgain: simulate and fit scattering at grazing incidence // -//! @file coregui/Models/FitModel.cpp -//! @brief Implements class FitModel +//! @file coregui/Models/NJobModel.cpp +//! @brief Implements class NJobModel //! //! @homepage http://www.bornagainproject.org //! @license GNU General Public License v3 or higher (see COPYING) @@ -14,12 +14,128 @@ // ************************************************************************** // #include "FitModel.h" +#include "SampleModel.h" +#include "InstrumentModel.h" +#include "FitParameterItems.h" +#include "ParameterizedItem.h" +#include "SessionModel.h" +#include "ComboProperty.h" +#include <QStringList> -FitModel::FitModel(QObject *parent) +FitModel::FitModel(SampleModel *samples, InstrumentModel *instruments, QObject *parent) : SessionModel(SessionXML::FitModelTag, parent) + , m_sampleModel(samples) + , m_instrumentModel(instruments) { } +FitParameterContainer *FitModel::getFitParameterContainer() { + return dynamic_cast<FitParameterContainer *> + (itemForIndex(QModelIndex())->getChildOfType(Constants::FitParameterContainerType)); +} + +FitSelectionItem *FitModel::getFitSelection() { + return dynamic_cast<FitSelectionItem *> + (itemForIndex(QModelIndex())->getChildOfType(Constants::FitSelectionType)); +} + +InputDataItem *FitModel::getInputData() { + return dynamic_cast<InputDataItem *> + (itemForIndex(QModelIndex())->getChildOfType(Constants::InputDataType)); +} + +QString FitModel::getSelectedSampleName () { + return getFitSelection()->getRegisteredProperty(FitSelectionItem::P_SAMPLE).toString(); +} + +QString FitModel::getSelectedInstrumentName(){ + return getFitSelection()->getRegisteredProperty(FitSelectionItem::P_INSTRUMENT).toString(); +} + +QStringList FitModel::getSampleNames() { + return retrieveDisplayNames(m_sampleModel, Constants::MultiLayerType); +} + +QStringList FitModel::getInstrumentNames() { + return retrieveDisplayNames(m_instrumentModel, Constants::InstrumentType); +} + +QStringList FitModel::retrieveDisplayNames(SessionModel *model, const QString &type) { + QStringList list; + for (int i_row = 0; i_row < model->rowCount(QModelIndex()); ++i_row) { + QModelIndex itemIndex = model->index(i_row, 0, QModelIndex()); + if (ParameterizedItem *item = model->itemForIndex(itemIndex)) { + if (item->modelType() == type) { + list << item->displayName(); + } + } + } + return list; +} + +QString FitModel::getSampleItemNameForDisplayName(const QString &displayName) { + if (auto *item = m_sampleModel->itemForIndex(QModelIndex())->getChildByDisplayName(displayName)) { + return item->itemName(); + } + return ""; +} + +QString FitModel::getInstrumentItemNameForDisplayName(const QString &displayName) { + if (auto *item = m_instrumentModel->itemForIndex(QModelIndex())->getChildByDisplayName(displayName)) { + return item->itemName(); + } + return ""; +} +ParameterizedItem *FitModel::getSelectedMultiLayerItem() { + ParameterizedItem *samplesRoot = m_sampleModel->itemForIndex(QModelIndex()); + return samplesRoot->getChildByDisplayName(getSelectedSampleName()); +} + +ParameterizedItem *FitModel::getSelectedInstrumentItem() { + ParameterizedItem *instrumentRoot = m_instrumentModel->itemForIndex(QModelIndex()); + return instrumentRoot->getChildByDisplayName(getSelectedInstrumentName()); +} + +void FitModel::setSelectedSample(const QString &displayName) { + ParameterizedItem *selection = getFitSelection(); + selection->setRegisteredProperty(FitSelectionItem::P_SAMPLE, displayName); +} + +void FitModel::setSelectedInstrument(const QString &displayName) { + ParameterizedItem *selection = getFitSelection(); + selection->setRegisteredProperty(FitSelectionItem::P_INSTRUMENT, displayName); +} + +MinimizerSettingsItem *FitModel::getMinimizerSettings() { + return dynamic_cast<MinimizerSettingsItem *> + (itemForIndex(QModelIndex())->getChildOfType(Constants::MinimizerSettingsType)); +} + +QString FitModel::getMinimizerAlgorithm() { + if (auto *item = getMinimizerSettings()) { + return item->getRegisteredProperty(MinimizerSettingsItem::P_ALGO).value<ComboProperty>() + .getValue(); + } +} + +QString FitModel::getInputDataPath() { + if (auto *item = getInputData()) { + return item->getRegisteredProperty(InputDataItem::P_PATH).toString(); + } + return ""; +} + +void FitModel::setInputDataPath(const QString &path) { + if (auto *item = getInputData()) { + item->setRegisteredProperty(InputDataItem::P_PATH, path); + } +} + +void FitModel::dataChangedProxy(const QModelIndex & topLeft, const QModelIndex & bottomRight, + const QVector<int> & roles) +{ + emit dataChanged(topLeft, bottomRight, roles); +} diff --git a/GUI/coregui/Models/FitModel.h b/GUI/coregui/Models/FitModel.h index c8a115f4c7ab923b0c90d97b986f311f1cfbcc9c..8cbe37f794ecd539cf14bdbcd5868195ee5585aa 100644 --- a/GUI/coregui/Models/FitModel.h +++ b/GUI/coregui/Models/FitModel.h @@ -2,8 +2,8 @@ // // BornAgain: simulate and fit scattering at grazing incidence // -//! @file coregui/Models/FitModel.h -//! @brief Defines class FitModel +//! @file coregui/Models/NJobModel.h +//! @brief Defines class NJobModel //! //! @homepage http://www.bornagainproject.org //! @license GNU General Public License v3 or higher (see COPYING) @@ -12,24 +12,85 @@ //! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke // // ************************************************************************** // - #ifndef FITMODEL_H #define FITMODEL_H - #include "SessionModel.h" +#include <QVector> + +class QModelIndex; +class SampleModel; +class InstrumentModel; +class FitParameterContainer; +class FitSelectionItem; +class SessionModel; +class MinimizerSettingsItem; +class InputDataItem; + class BA_CORE_API_ FitModel : public SessionModel { Q_OBJECT public: - explicit FitModel(QObject *parent = 0); - virtual ~FitModel(){} + //! constructs model with pointers to Sample- und InstrumentModels (read-only access) + explicit FitModel(SampleModel *samples, InstrumentModel *instruments, QObject *parent = 0); -}; + //! returns child of type FitParameterContainer + FitParameterContainer *getFitParameterContainer(); + + //! returns child fo type FitSelectionItem + FitSelectionItem *getFitSelection(); + + InputDataItem *getInputData(); + + //! returns displayName of currently selected sample, "" when nothing selected + QString getSelectedSampleName(); + + //! returns displayName of currently selected instrument + QString getSelectedInstrumentName(); + + //! returns a list of all sample displaynames + QStringList getSampleNames(); + //! returns a list of all instrument displaynames + QStringList getInstrumentNames(); + //! returning selected MultiLayerItem from SampleModel + ParameterizedItem *getSelectedMultiLayerItem(); + //! returning selected InstrumentItem from InstrumentModel + ParameterizedItem *getSelectedInstrumentItem(); + + //! set sample selection + void setSelectedSample(const QString &displayName); + + //! set instrument selection + void setSelectedInstrument(const QString &displayName); + + //! get item name when display name is known + QString getSampleItemNameForDisplayName(const QString &displayName); + QString getInstrumentItemNameForDisplayName(const QString &displayName); + + //! return minimizer settings item + MinimizerSettingsItem *getMinimizerSettings(); + + QString getMinimizerAlgorithm(); + + QString getInputDataPath(); + + void setInputDataPath(const QString &path); +public slots: + //! callback for changes made on children of root_item, propagate forward + void dataChangedProxy(const QModelIndex &topLeft, const QModelIndex &bottomRight, + const QVector<int> &roles = QVector<int> ()); + +private: + SampleModel *m_sampleModel; + InstrumentModel *m_instrumentModel; + + //! get a list of display names for given model - we use them to identify items + QStringList retrieveDisplayNames(SessionModel *model, const QString &type); +}; #endif diff --git a/GUI/coregui/Models/FitParameterItem.cpp b/GUI/coregui/Models/FitParameterItem.cpp deleted file mode 100644 index be2591a218e11c7cbe7c7279179e764b064b7e89..0000000000000000000000000000000000000000 --- a/GUI/coregui/Models/FitParameterItem.cpp +++ /dev/null @@ -1,43 +0,0 @@ -// ************************************************************************** // -// -// BornAgain: simulate and fit scattering at grazing incidence -// -//! @file coregui/Models/FitParameterItem.cpp -//! @brief Implements class FitParameterItem -//! -//! @homepage http://www.bornagainproject.org -//! @license GNU General Public License v3 or higher (see COPYING) -//! @copyright Forschungszentrum Jülich GmbH 2015 -//! @authors Scientific Computing Group at MLZ Garching -//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke -// -// ************************************************************************** // - -#include "FitParameterItem.h" - -const QString FitParameterItem::P_MIN = "Min"; -const QString FitParameterItem::P_MAX = "Max"; -const QString FitParameterItem::P_VALUE = "Value"; -const QString FitParameterItem::P_USE = "Use"; - -FitParameterItem::FitParameterItem(ParameterizedItem *parent) - : ParameterizedItem(Constants::FitParameterType, parent) -{ - registerProperty(P_NAME, Constants::FitParameterType); - registerProperty(P_MIN, 0.0); - registerProperty(P_MAX, 10.0); - registerProperty(P_VALUE, 5.0); - registerProperty(P_USE, true); -} - -void FitParameterItem::setParNames(QStringList par_names) -{ - m_par_names = par_names; -} - -QStringList FitParameterItem::getParNames() -{ - return m_par_names; -} - - diff --git a/GUI/coregui/Models/FitParameterItem.h b/GUI/coregui/Models/FitParameterItem.h deleted file mode 100644 index f1b4980cc761b5f6e2b31755af9f7c382ebae0b0..0000000000000000000000000000000000000000 --- a/GUI/coregui/Models/FitParameterItem.h +++ /dev/null @@ -1,43 +0,0 @@ -// ************************************************************************** // -// -// BornAgain: simulate and fit scattering at grazing incidence -// -//! @file coregui/Models/FitParameterItem.h -//! @brief Defines class FitParameterItem -//! -//! @homepage http://www.bornagainproject.org -//! @license GNU General Public License v3 or higher (see COPYING) -//! @copyright Forschungszentrum Jülich GmbH 2015 -//! @authors Scientific Computing Group at MLZ Garching -//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke -// -// ************************************************************************** // - -#ifndef FITPARAMETERITEM_H -#define FITPARAMETERITEM_H - -#include "ParameterizedItem.h" - - -class BA_CORE_API_ FitParameterItem : public ParameterizedItem -{ - Q_OBJECT -public: - static const QString P_MIN; - static const QString P_MAX; - static const QString P_VALUE; - static const QString P_USE; - explicit FitParameterItem(ParameterizedItem *parent=0); - virtual ~FitParameterItem(){} - - void setParNames(QStringList par_names); - QStringList getParNames(); -private: - QStringList m_par_names; -}; - - -// bool fixed, start_value, min, max, step - -#endif - diff --git a/GUI/coregui/Models/FitParameterItems.cpp b/GUI/coregui/Models/FitParameterItems.cpp new file mode 100644 index 0000000000000000000000000000000000000000..94836f3af4050892c6d144053a712470a85e0296 --- /dev/null +++ b/GUI/coregui/Models/FitParameterItems.cpp @@ -0,0 +1,80 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Models/NJobModel.cpp +//! @brief Implements class NJobModel +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2015 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke +// +// ************************************************************************** // + +#include "FitParameterItems.h" +#include "ComboProperty.h" + +FitParameterContainer::FitParameterContainer(ParameterizedItem *parent) + : ParameterizedItem(Constants::FitParameterContainerType, parent) +{ + addToValidChildren(Constants::FitParameterType); +} + + +const QString FitParameterItem::P_USE = "Use"; +const QString FitParameterItem::P_INIT = "Starting Value"; +const QString FitParameterItem::P_MIN = "Min"; +const QString FitParameterItem::P_MAX = "Max"; + +FitParameterItem::FitParameterItem(ParameterizedItem *parent) + : ParameterizedItem(Constants::FitParameterType, parent) +{ + registerProperty(P_USE, true); + registerProperty(P_INIT, 0.0); + registerProperty(P_MIN, 0.0); + registerProperty(P_MAX, 0.0); + addToValidChildren(Constants::FitParameterLinkType); +} + + + +const QString FitParameterLinkItem::P_LINK = "Link"; + +FitParameterLinkItem::FitParameterLinkItem(ParameterizedItem *parent) + : ParameterizedItem(Constants::FitParameterLinkType, parent) +{ + registerProperty(P_LINK, ""); +} + + +const QString FitSelectionItem::P_SAMPLE = "Sample"; +const QString FitSelectionItem::P_INSTRUMENT = "Instrument"; + +FitSelectionItem::FitSelectionItem(ParameterizedItem *parent) + : ParameterizedItem(Constants::FitSelectionType, parent) +{ + registerProperty(P_SAMPLE, ""); + registerProperty(P_INSTRUMENT, ""); +} + +const QString MinimizerSettingsItem::P_ALGO = "Algorithm"; + +MinimizerSettingsItem::MinimizerSettingsItem(ParameterizedItem *parent) + : ParameterizedItem(Constants::MinimizerSettingsType, parent) +{ + ComboProperty algo; + algo << "Migrad" << "Simplex" << "Combined" << "Scan" << "Fumili"; + registerProperty(P_ALGO, algo.getVariant()); +} + +const QString InputDataItem::P_PATH = "Path"; + +InputDataItem::InputDataItem(ParameterizedItem *parent) + : ParameterizedItem(Constants::InputDataType, parent) +{ + registerProperty(P_PATH, ""); +} + + diff --git a/GUI/coregui/Models/FitParameterItems.h b/GUI/coregui/Models/FitParameterItems.h new file mode 100644 index 0000000000000000000000000000000000000000..10d04df1d71bb3ce8f88cbf0359fab519e27364e --- /dev/null +++ b/GUI/coregui/Models/FitParameterItems.h @@ -0,0 +1,73 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Models/NJobModel.h +//! @brief Defines class NJobModel +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2015 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke +// +// ************************************************************************** // +#ifndef FITPARAMETERITEMS_H +#define FITPARAMETERITEMS_H + +#include "ParameterizedItem.h" + +class BA_CORE_API_ FitParameterContainer : public ParameterizedItem +{ + Q_OBJECT +public: + explicit FitParameterContainer(ParameterizedItem *parent=0); +}; + +class BA_CORE_API_ FitParameterItem : public ParameterizedItem +{ + Q_OBJECT +public: + static const QString P_USE; + static const QString P_INIT; + static const QString P_MIN; + static const QString P_MAX; + explicit FitParameterItem(ParameterizedItem *parent=0); +}; + + +class BA_CORE_API_ FitParameterLinkItem : public ParameterizedItem +{ + Q_OBJECT +public: + static const QString P_LINK; + explicit FitParameterLinkItem(ParameterizedItem *parent=0); +}; + + +class BA_CORE_API_ FitSelectionItem : public ParameterizedItem +{ + Q_OBJECT +public: + static const QString P_SAMPLE; + static const QString P_INSTRUMENT; + explicit FitSelectionItem(ParameterizedItem *parent=0); +}; + +class BA_CORE_API_ MinimizerSettingsItem : public ParameterizedItem +{ + Q_OBJECT +public: + static const QString P_ALGO; + explicit MinimizerSettingsItem(ParameterizedItem *parent=0); +}; + +class BA_CORE_API_ InputDataItem : public ParameterizedItem +{ + Q_OBJECT +public: + static const QString P_PATH; + explicit InputDataItem(ParameterizedItem *parent=0); +}; + +#endif diff --git a/GUI/coregui/Models/FitParameterModel.cpp b/GUI/coregui/Models/FitParameterModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cb8f12767abf03e3b8f81039056b9133cec49bae --- /dev/null +++ b/GUI/coregui/Models/FitParameterModel.cpp @@ -0,0 +1,169 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Models/FitModel.cpp +//! @brief Implements class FitModel +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2015 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke +// +// ************************************************************************** // + +#include "FitParameterModel.h" +#include "SessionModel.h" +#include "FitModel.h" +#include "FitParameterItems.h" +#include "FitParameterWidget.h" + +#include <QMimeData> + + + +FitParameterModel::FitParameterModel(FitModel *fitmodel, QWidget *parent) + : SessionModel("FitParameterModel", parent) + , m_columnNames(new QMap<int, QString>()) +{ + setRootItem(fitmodel->itemForIndex(QModelIndex())-> + getChildOfType(Constants::FitParameterContainerType)); + setMaxColumns(5); + m_columnNames->insert(0, FitParameterItem::P_NAME); + m_columnNames->insert(1, FitParameterItem::P_USE); + m_columnNames->insert(3, FitParameterItem::P_MIN); + m_columnNames->insert(2, FitParameterItem::P_INIT); + m_columnNames->insert(4, FitParameterItem::P_MAX); +} + +FitParameterModel::~FitParameterModel() +{ + setRootItem(0); + delete m_columnNames; +} + +ParameterizedItem *FitParameterModel::addParameter() +{ + return insertNewItem(Constants::FitParameterType, indexOfItem(itemForIndex(QModelIndex()))); +} + +QModelIndex FitParameterModel::itemForLink(const QString &link) const +{ + for (int i=0; i<rowCount(QModelIndex()); i++){ + int rowcount = rowCount(index(i,0,QModelIndex())); + for (int j = 0; j < rowcount; j++) { + QModelIndex curIndex = index(j,0,index(i,0,QModelIndex())); + QString value = itemForIndex(curIndex) + ->getRegisteredProperty(FitParameterLinkItem::P_LINK).toString(); + if (value == link) + return curIndex; + } + } + return QModelIndex(); +} + +Qt::ItemFlags FitParameterModel::flags(const QModelIndex & index) const +{ + Qt::ItemFlags returnVal = Qt::ItemIsEnabled | Qt::ItemIsSelectable; + if (index.isValid() && index.parent() == QModelIndex()) { + if (index.column() == 0) + returnVal |= Qt::ItemIsDropEnabled; + else + returnVal |= Qt::ItemIsEditable; + } else if (!index.isValid()) { + returnVal |= Qt::ItemIsDropEnabled; + } + return returnVal; +} + +QStringList FitParameterModel::mimeTypes() const +{ + QStringList types; + types << FitParameterWidget::MIME_TYPE; + return types; +} + +bool FitParameterModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, + int row, int column, const QModelIndex &parent) const +{ + Q_UNUSED(action); + Q_UNUSED(row); + Q_UNUSED(parent); + if (column > 0) + return false; + QString link = QString::fromLatin1(data->data(FitParameterWidget::MIME_TYPE)).split("#")[0]; + QModelIndex cur = itemForLink(link); + return !cur.isValid(); +} + +Qt::DropActions FitParameterModel::supportedDropActions() const +{ + return Qt::CopyAction | Qt::MoveAction; +} + +bool FitParameterModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, + int column, const QModelIndex &parent) +{ + if (action == Qt::IgnoreAction) return true; + if (column > 0) return true; + QStringList parts = QString::fromLatin1(data->data(FitParameterWidget::MIME_TYPE)) + .split("#"); + if (parts.size() != 2) return true; + QModelIndex cur = parent; + if (!parent.isValid()) { + auto newlink = addParameter(); + double value = parts[1].toDouble(); + newlink->setRegisteredProperty(FitParameterItem::P_INIT, value); + cur = indexOfItem(newlink); + } + auto link = insertNewItem(Constants::FitParameterLinkType, cur, row); + if (link) link->setRegisteredProperty(FitParameterLinkItem::P_LINK, parts[0]); + emit dataChanged(cur, cur); + return true; +} + +QVariant FitParameterModel::data(const QModelIndex & index, int role) const +{ + if ( !index.isValid() || index.column() < 0 || index.column() >= 5) { + return QVariant(); + } + if (ParameterizedItem *item = itemForIndex(index)) { + if (role == Qt::DisplayRole || role == Qt::EditRole) { + if (item->parent() != itemForIndex(QModelIndex())) + { + if (index.column() == 0) + return item->getRegisteredProperty(FitParameterLinkItem::P_LINK); + else + return QVariant(); + } + if (index.column() == 0) + return item->itemName(); + else + return item->getRegisteredProperty(m_columnNames->value(index.column())); + } + } + return QVariant(); +} + +bool FitParameterModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (!index.isValid()) + return false; + if (ParameterizedItem *item = itemForIndex(index)) { + if (role == Qt::EditRole && index.column() > 0 && index.column() < 5) { + item->setRegisteredProperty(m_columnNames->value(index.column()), value); + emit dataChanged(index, index); + return true; + } + } + return false; +} + +QVariant FitParameterModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { + return m_columnNames->value(section); + } + return QVariant(); +} diff --git a/GUI/coregui/Models/FitParameterModel.h b/GUI/coregui/Models/FitParameterModel.h new file mode 100644 index 0000000000000000000000000000000000000000..f1e30864a93d60f4468d7c27a628d6c42eee0ae3 --- /dev/null +++ b/GUI/coregui/Models/FitParameterModel.h @@ -0,0 +1,56 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Models/FitModel.h +//! @brief Defines class FitModel +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2015 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke +// +// ************************************************************************** // + +#ifndef FITPARAMETERMODEL_H +#define FITPARAMETERMODEL_H + +#include "WinDllMacros.h" +#include "SessionModel.h" +#include <QMap> + +class FitModel; +class QModelIndex; +class QParameterizedItem; + + +class BA_CORE_API_ FitParameterModel : public SessionModel +{ + Q_OBJECT + +public: + explicit FitParameterModel(FitModel *fitmodel, QWidget *parent); + ~FitParameterModel(); + QModelIndex itemForLink(const QString &link) const; + + Qt::ItemFlags flags(const QModelIndex & index) const Q_DECL_OVERRIDE; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; + bool setData(const QModelIndex &index, const QVariant &value, int role) Q_DECL_OVERRIDE; + QStringList mimeTypes() const Q_DECL_OVERRIDE; + QVariant headerData(int section, Qt::Orientation orientation, int role) const Q_DECL_OVERRIDE; + bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, + const QModelIndex &parent) const Q_DECL_OVERRIDE; + bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); + Qt::DropActions supportedDropActions() const Q_DECL_OVERRIDE; + +public slots: + ParameterizedItem *addParameter(); + +private: + QMap<int, QString> *m_columnNames; +}; + + + +#endif diff --git a/GUI/coregui/Models/FitProxyModel.cpp b/GUI/coregui/Models/FitProxyModel.cpp deleted file mode 100644 index 0bd54d2df4650127013cae7681723b5eaa742fd8..0000000000000000000000000000000000000000 --- a/GUI/coregui/Models/FitProxyModel.cpp +++ /dev/null @@ -1,228 +0,0 @@ -// ************************************************************************** // -// -// BornAgain: simulate and fit scattering at grazing incidence -// -//! @file coregui/Models/FitProxyModel.cpp -//! @brief Implements class FitProxyModel -//! -//! @homepage http://www.bornagainproject.org -//! @license GNU General Public License v3 or higher (see COPYING) -//! @copyright Forschungszentrum Jülich GmbH 2015 -//! @authors Scientific Computing Group at MLZ Garching -//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke -// -// ************************************************************************** // - -#include "FitProxyModel.h" -#include "FitModel.h" -#include "ParameterizedItem.h" -#include "FitParameterItem.h" -#include <QDebug> - - -FitProxyModel::FitProxyModel(QObject *parent) - : QAbstractItemModel(parent) -{ - -} - -void FitProxyModel::setFitModel(FitModel *fitModel) -{ - m_fitModel = fitModel; -} - -QVariant FitProxyModel::data(const QModelIndex &index, int role) const -{ - -// if(role == Qt::DisplayRole) { -// return QVariant(index.column()); -// } - -// return QVariant(); - -// if (!index.isValid() || index.column() < 0 -// || index.column() >= columnCount(index)) { - -// qDebug() << "XXXXXXXXX FitProxyModel::data index.isValid(): " << index; - -// return QVariant(); -// } - - if(!index.isValid()) - { - return QVariant(); - } - - - if(index.isValid() && !index.parent().isValid()) - { - //ParameterizedItem - if (ParameterizedItem *item = itemForIndex(index)) { - - if(role == Qt::DisplayRole || role == Qt::EditRole) { - switch (index.column()) { - case 0: return item->itemName(); - case 1: return item->getRegisteredProperty(FitParameterItem::P_USE); - case 2: return item->getRegisteredProperty(FitParameterItem::P_VALUE); - case 3: return item->getRegisteredProperty(FitParameterItem::P_MIN); - case 4: return item->getRegisteredProperty(FitParameterItem::P_MAX); - default: return QVariant(); - } - } - } - } - - if(index.isValid() && index.parent().isValid()) - { - //description - if (FitParameterItem *item = dynamic_cast<FitParameterItem *>(itemForIndex(index.parent()))) { - if(item->getParNames().size() >0) - { - return QVariant(item->getParNames().at(0)); - } - } - } - - return QVariant(); -} - -int FitProxyModel::rowCount(const QModelIndex &parentIndex) const -{ - if(parentIndex.isValid()) - { - return 0; - } - - if(parentIndex.isValid() && parentIndex.parent().isValid()) - { -// if (FitParameterItem *item = dynamic_cast<FitParameterItem *>(itemForIndex(index.parent()))) { -// return item->getParNames().size(); -// } - - return 1; - } - - - int counter = 0; - - if(m_fitModel) - { - for( int i_row = 0; i_row < m_fitModel->rowCount( parentIndex ); ++i_row) { - QModelIndex itemIndex = m_fitModel->index( i_row, 0, parentIndex ); - - if (ParameterizedItem *item = m_fitModel->itemForIndex(itemIndex)){ - Q_UNUSED(item); - counter++; - } - } - } - - return counter; -} - -int FitProxyModel::columnCount(const QModelIndex &parentIndex) const -{ - if(!parentIndex.isValid()) - { - return 5; - } - - if(parentIndex.isValid() && !parentIndex.parent().isValid()) - { - return 1; - } - - return 0; -} - -QModelIndex FitProxyModel::index(int row, int column, - const QModelIndex &parentIndex) const -{ - ParameterizedItem *parent_item = m_fitModel->itemForIndex(parentIndex); - if (ParameterizedItem *item = parent_item->childAt(row)) { - return createIndex(row, column, item); - } - return QModelIndex(); -} - -QModelIndex FitProxyModel::parent(const QModelIndex &/*child*/) const -{ - /*if (!child.isValid()) return QModelIndex(); - if (ParameterizedItem *child_item = itemForIndex(child)) { - if (ParameterizedItem *parent_item = child_item->parent()) { - - if (ParameterizedItem *grandparent_item = parent_item->parent()) - { - int row = grandparent_item->rowOfChild(parent_item); - return createIndex(row, 0, parent_item); - } - } - }*/ - return QModelIndex(); - -} - -Qt::ItemFlags FitProxyModel::flags(const QModelIndex &index) const -{ - Qt::ItemFlags result_flags = QAbstractItemModel::flags(index); - if (index.isValid()) { - result_flags |= Qt::ItemIsEnabled |Qt::ItemIsEditable; - } - else { - result_flags |= Qt::ItemIsEditable; - } - return result_flags; -} - -bool FitProxyModel::setData(const QModelIndex &index, - const QVariant &value, int role) -{ - if (!index.isValid()) return false; - - - if (ParameterizedItem *item = itemForIndex(index)) { - if (role==Qt::EditRole) { - qDebug() << "FitProxyModel::setData "; - - switch (index.column()) { - case 0: - item->setItemName(value.toString()); - break; - case 1: - item->setRegisteredProperty(FitParameterItem::P_USE, value); - break; - case 2: - item->setRegisteredProperty(FitParameterItem::P_VALUE, value); - break; - case 3: - item->setRegisteredProperty(FitParameterItem::P_MIN, value); - break; - case 4: - item->setRegisteredProperty(FitParameterItem::P_MAX, value); - break; - default: - return false; - - } - emit dataChanged(index, index); - return true; - } - } - return false; -} - -ParameterizedItem *FitProxyModel::itemForIndex(const QModelIndex &index) const -{ - if (index.isValid()) { - if (ParameterizedItem *item = static_cast<ParameterizedItem *>( - index.internalPointer())) - return item; - } - - //ParameterizedItem *item = m_fitModel->itemForIndex(index); - - return 0; -} - - - diff --git a/GUI/coregui/Models/FitProxyModel.h b/GUI/coregui/Models/FitProxyModel.h deleted file mode 100644 index 61c30c142fe46f12f08cde5958cee8ade51fc259..0000000000000000000000000000000000000000 --- a/GUI/coregui/Models/FitProxyModel.h +++ /dev/null @@ -1,57 +0,0 @@ -// ************************************************************************** // -// -// BornAgain: simulate and fit scattering at grazing incidence -// -//! @file coregui/Models/FitProxyModel.h -//! @brief Defines class FitProxyModel -//! -//! @homepage http://www.bornagainproject.org -//! @license GNU General Public License v3 or higher (see COPYING) -//! @copyright Forschungszentrum Jülich GmbH 2015 -//! @authors Scientific Computing Group at MLZ Garching -//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke -// -// ************************************************************************** // - -#ifndef FITPROXYMODEL_H -#define FITPROXYMODEL_H - - -#include <QAbstractItemModel> - -class FitModel; -class ParameterizedItem; - -class BA_CORE_API_ FitProxyModel : public QAbstractItemModel -{ - Q_OBJECT - -public: - explicit FitProxyModel(QObject *parent = 0); - virtual ~FitProxyModel(){} - - // overriden methods - virtual QVariant data(const QModelIndex &index, int role) const; - virtual int rowCount(const QModelIndex &parentIndex) const; - virtual int columnCount(const QModelIndex &parentIndex) const; - virtual QModelIndex index(int row, int column, const QModelIndex &parentIndex) const; - virtual QModelIndex parent(const QModelIndex &child) const; - virtual Qt::ItemFlags flags(const QModelIndex &index) const; - virtual bool setData(const QModelIndex &index, const QVariant &value, int role); - //end if overriden methods - - void setFitModel(FitModel *fitModel); - FitModel *getFitModel() - { return m_fitModel; } - - ParameterizedItem *itemForIndex(const QModelIndex &index) const; - -private: - FitModel *m_fitModel; - -}; - - - - -#endif diff --git a/GUI/coregui/Models/FitSelectorModel.cpp b/GUI/coregui/Models/FitSelectorModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5c053a0be6afc8657888bf80e98578faea430738 --- /dev/null +++ b/GUI/coregui/Models/FitSelectorModel.cpp @@ -0,0 +1,63 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Models/NJobModel.cpp +//! @brief Implements class NJobModel +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2015 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke +// +// ************************************************************************** // + +#include "FitSelectorModel.h" +#include "FitParameterWidget.h" +#include <QStandardItem> +#include <QMimeData> +#include <QModelIndexList> + +QMimeData *FitSelectorModel::mimeData(const QModelIndexList &indexes) const +{ + QMimeData *mimeData = new QMimeData(); + QModelIndex index = indexes.first(); + if (index.isValid()) { + QString path = getPathFromIndex(index); + path = path.append("#%1").arg(itemFromIndex(index.sibling(index.row(), 1)) + ->data(Qt::EditRole).toDouble()); + mimeData->setData(FitParameterWidget::MIME_TYPE, path.toLatin1()); + } + return mimeData; +} + +QString FitSelectorModel::getPathFromIndex(const QModelIndex &index) const +{ + if (index.isValid()) { + QStringList namePath; + QStandardItem *cur = itemFromIndex(index); + while (cur) { + namePath << cur->text(); + cur = cur->parent(); + } + std::reverse(namePath.begin(), namePath.end()); + return namePath.join("/"); + } + return QString(); +} + +QStandardItem *FitSelectorModel::getItemFromPath(const QString &path) +{ + QStringList parts = path.split("/"); + QStandardItem *t = invisibleRootItem(); + for(int i = 0; i < parts.length(); i++) { + for (int j = 0; j < t->rowCount(); j++) { + if (t->child(j,0)->text() == parts[i]) { + t = t->child(j,0); + break; + } + } + } + return t; +} diff --git a/GUI/coregui/Views/FitWidgets/RealDataWidget.h b/GUI/coregui/Models/FitSelectorModel.h similarity index 54% rename from GUI/coregui/Views/FitWidgets/RealDataWidget.h rename to GUI/coregui/Models/FitSelectorModel.h index 0fdc09feb37890070540ea99cfb05f9c1a67b1c7..ebacb274f19d1e1d46168d7d22db6d523898873a 100644 --- a/GUI/coregui/Views/FitWidgets/RealDataWidget.h +++ b/GUI/coregui/Models/FitSelectorModel.h @@ -2,8 +2,8 @@ // // BornAgain: simulate and fit scattering at grazing incidence // -//! @file coregui/Views/FitWidgets/RealDataWidget.h -//! @brief Defines class RealDataWidget +//! @file coregui/Models/NJobModel.h +//! @brief Defines class NJobModel //! //! @homepage http://www.bornagainproject.org //! @license GNU General Public License v3 or higher (see COPYING) @@ -12,19 +12,23 @@ //! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke // // ************************************************************************** // +#ifndef FITSELECTORMODEL_H +#define FITSELECTORMODEL_H -#ifndef REALDATAWIDGET_H -#define REALDATAWIDGET_H +#include "WinDllMacros.h" +#include <QStandardItemModel> -#include <QWidget> +class QMimeData; +class QStandardItem; - -class BA_CORE_API_ RealDataWidget : public QWidget +class BA_CORE_API_ FitSelectorModel : public QStandardItemModel { Q_OBJECT public: - RealDataWidget(QWidget *parent = 0); + QMimeData *mimeData(const QModelIndexList &indexes) const; + QString getPathFromIndex(const QModelIndex &index) const; + QStandardItem *getItemFromPath(const QString &path); }; #endif diff --git a/GUI/coregui/Models/ItemFactory.cpp b/GUI/coregui/Models/ItemFactory.cpp index 3717be0f25e70b8fa49ca8c20abde6db36c86ef3..076c59548c72a23b63fc10e64371cc14b6f45470 100644 --- a/GUI/coregui/Models/ItemFactory.cpp +++ b/GUI/coregui/Models/ItemFactory.cpp @@ -38,7 +38,6 @@ #include "MaterialItem.h" #include "RefractiveIndexItem.h" #include "MagneticFieldItem.h" -#include "FitParameterItem.h" #include "JobItem.h" #include "IntensityDataItem.h" #include "AxesItems.h" @@ -47,6 +46,7 @@ #include "BeamWavelengthItem.h" #include "BeamAngleItems.h" #include "MaskItems.h" +#include "FitParameterItems.h" #include <QDebug> namespace { @@ -143,8 +143,6 @@ ItemFactory::ItemMap_t initializeItemMap() { result[Constants::MagneticFieldType] = &createInstance<MagneticFieldItem>; - result[Constants::FitParameterType] = &createInstance<FitParameterItem>; - result[Constants::JobItemType] = &createInstance<JobItem>; result[Constants::IntensityDataType] = &createInstance<IntensityDataItem>; @@ -169,6 +167,13 @@ ItemFactory::ItemMap_t initializeItemMap() { result[Constants::EllipseMaskType] = &createInstance<EllipseItem>; result[Constants::MaskAllType] = &createInstance<MaskAllItem>; + result[Constants::FitParameterContainerType] = &createInstance<FitParameterContainer>; + result[Constants::FitParameterType] = &createInstance<FitParameterItem>; + result[Constants::FitParameterLinkType] = &createInstance<FitParameterLinkItem>; + result[Constants::FitSelectionType] = &createInstance<FitSelectionItem>; + result[Constants::MinimizerSettingsType] = &createInstance<MinimizerSettingsItem>; + result[Constants::InputDataType] = &createInstance<InputDataItem>; + return result; } } diff --git a/GUI/coregui/Models/ParameterModelBuilder.h b/GUI/coregui/Models/ParameterModelBuilder.h index ea1c1df416bea5ac5fc9c62f275426d9259db735..3b57158f624c6c6fc1cf6ef90fbdda0f04171fed 100644 --- a/GUI/coregui/Models/ParameterModelBuilder.h +++ b/GUI/coregui/Models/ParameterModelBuilder.h @@ -39,9 +39,10 @@ class ParameterModelBuilder public: static QStandardItemModel *createParameterModel(JobModel *jobModel, JobItem *jobItem); + static QStandardItem *iterateSessionModel(SessionModel *sampleModel, const QModelIndex &parentIndex = QModelIndex(), QStandardItem *parentItem = 0); private: - static QStandardItem *iterateSessionModel(SessionModel *sampleModel, const QModelIndex &parentIndex = QModelIndex(), QStandardItem *parentItem = 0); + static QStandardItem *iterateInstrumentModel(InstrumentModel *instrumentModel); static QStandardItem *iterateInstrumentItem(InstrumentItem *instrument); diff --git a/GUI/coregui/Models/ParameterizedItem.cpp b/GUI/coregui/Models/ParameterizedItem.cpp index 7625fbd6d2ff07260fc0587e1460216e35fd6742..2519edded23ebd481dcd8d32eb88e85c26224c59 100644 --- a/GUI/coregui/Models/ParameterizedItem.cpp +++ b/GUI/coregui/Models/ParameterizedItem.cpp @@ -37,7 +37,9 @@ ParameterizedItem::ParameterizedItem(QString model_type, ParameterizedItem *pare if (mp_parent) { mp_parent->insertChildItem(-1, this); } + registerProperty(P_PORT, -1).setHidden(); + setItemName(m_model_type); } ParameterizedItem::~ParameterizedItem() @@ -421,6 +423,20 @@ QStringList ParameterizedItem::getParameterTreeList(QString prefix) const return result; } +double ParameterizedItem::getParameterValue(const QString &name) const +{ + QString head = getFirstField(name); + auto p_child = getChildByDisplayName(head); + if (p_child) { + return p_child->getParameterValue(stripFirstField(name)); + } + if (isRegisteredProperty(head)) { + return getRegisteredProperty(head).toDouble(); + } else { + return 0.0; + } +} + std::string ParameterizedItem::translateParameterName(const QString &par_name) const { std::ostringstream result; diff --git a/GUI/coregui/Models/ParameterizedItem.h b/GUI/coregui/Models/ParameterizedItem.h index a1efb3444ee529924d5c193d425967215ee194aa..32e28d418579a5d7e7c58aa31aa77dc43f983284 100644 --- a/GUI/coregui/Models/ParameterizedItem.h +++ b/GUI/coregui/Models/ParameterizedItem.h @@ -85,6 +85,8 @@ public: //! Returns a pointer to the first child of the given type ParameterizedItem *getChildOfType(QString type) const; + ParameterizedItem* getChildByDisplayName(const QString &name) const; + //! indicates if the passed item can be set as a child item bool acceptsAsChild(const QString &child_name) const; @@ -141,6 +143,9 @@ public: //! with this node and prefixes them QStringList getParameterTreeList(QString prefix = "") const; + //! retrieve value of given parameter name + double getParameterValue(const QString &name) const; + //! translates the given parameter name to a domain parameter name //! name should start with a child/subitem name or be a direct parameter name std::string translateParameterName(const QString &par_name) const; @@ -181,8 +186,6 @@ protected: void addParameterTranslator(const IParameterTranslator &translator); - ParameterizedItem* getChildByDisplayName(const QString &name) const; - QStringList m_registered_properties; QMap<QString, PropertyAttribute> m_property_attribute; diff --git a/GUI/coregui/Models/SessionModel.cpp b/GUI/coregui/Models/SessionModel.cpp index 3b571c59073881f38417ac60048d2c694f8973dc..a5697b8731a9374fea471d97cceac59a95923b1d 100644 --- a/GUI/coregui/Models/SessionModel.cpp +++ b/GUI/coregui/Models/SessionModel.cpp @@ -41,6 +41,7 @@ const QString NON_EXISTING_SUBITEM = "NON_EXISTING_SUBITEM"; SessionModel::SessionModel(QString model_tag, QObject *parent) : QAbstractItemModel(parent), m_root_item(0), m_name("DefaultName"), m_model_tag(model_tag) + , m_maxColumns(MAX_COLUMNS) , m_iconProvider(0) , m_messageService(0) { @@ -70,7 +71,7 @@ Qt::ItemFlags SessionModel::flags(const QModelIndex &index) const QVariant SessionModel::data(const QModelIndex &index, int role) const { - if (!m_root_item || !index.isValid() || index.column() < 0 || index.column() >= MAX_COLUMNS) { + if (!m_root_item || !index.isValid() || index.column() < 0 || index.column() >= m_maxColumns) { return QVariant(); } if (ParameterizedItem *item = itemForIndex(index)) { @@ -115,12 +116,12 @@ int SessionModel::columnCount(const QModelIndex &parent) const { if (parent.isValid() && parent.column() != 0) return 0; - return MAX_COLUMNS; + return m_maxColumns; } QModelIndex SessionModel::index(int row, int column, const QModelIndex &parent) const { - if (!m_root_item || row < 0 || column < 0 || column >= MAX_COLUMNS + if (!m_root_item || row < 0 || column < 0 || column >= m_maxColumns || (parent.isValid() && parent.column() != 0)) return QModelIndex(); ParameterizedItem *parent_item = itemForIndex(parent); @@ -839,3 +840,7 @@ void SessionModel::report_error(const QString &error_type, const QString &messag throw GUIHelpers::Error(error_type + QString(" ") + message); } } + +ParameterizedItem* SessionModel::rootItem() const{ + return m_root_item; +} diff --git a/GUI/coregui/Models/SessionModel.h b/GUI/coregui/Models/SessionModel.h index e87c73899ac3ad7d8f2ac5903f4652bc09788947..22212ab4a55ff15c4eb037910d6693c4494c68cd 100644 --- a/GUI/coregui/Models/SessionModel.h +++ b/GUI/coregui/Models/SessionModel.h @@ -84,7 +84,7 @@ public: const QModelIndex &parent) const; virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); - // End overriden methods from QAbstractItemModel + // End overridden methods from QAbstractItemModel QModelIndex indexOfItem(ParameterizedItem *item) const; ParameterizedItem *insertNewItem(QString model_type, const QModelIndex &parent = QModelIndex(), @@ -104,6 +104,7 @@ public: // Sets mimedata pointer of item being dragged void setDraggedItemType(const QString &type); + // Returns root item if index is not valid ParameterizedItem *itemForIndex(const QModelIndex &index) const; void readFrom(QXmlStreamReader *reader); @@ -127,12 +128,19 @@ public: virtual void initFrom(SessionModel *model, ParameterizedItem *parent); + + public slots: void onItemPropertyChange(const QString &property_name, const QString &name = QString()); protected: + // subclasses my wish to change the column count or the root item itself + void setMaxColumns(int maxColumns) {m_maxColumns = maxColumns;} + void setRootItem(ParameterizedItem *root) {m_root_item = root;} private: + ParameterizedItem* rootItem() const; + ParameterizedItem *insertNewItem(QString model_type, ParameterizedItem *parent, int row = -1, ParameterizedItem::PortInfo::EPorts port = ParameterizedItem::PortInfo::DEFAULT); @@ -151,6 +159,7 @@ private: QString m_dragged_item_type; QString m_name; //!< model name QString m_model_tag; //!< model tag (SampleModel, InstrumentModel) + int m_maxColumns; IconProvider *m_iconProvider; WarningMessageService *m_messageService; }; diff --git a/GUI/coregui/Models/item_constants.h b/GUI/coregui/Models/item_constants.h index 887a0e5ce7e92b7b9d49de31758b90b4b4d38d83..fc825bba1730d9add0d53bb213a0678b2ae054e7 100644 --- a/GUI/coregui/Models/item_constants.h +++ b/GUI/coregui/Models/item_constants.h @@ -115,7 +115,12 @@ const ModelType RefractiveIndexType = "RefractiveIndex"; const ModelType MagneticFieldType = "MagneticField"; +const ModelType FitParameterContainerType = "FitParameterContainer"; const ModelType FitParameterType = "FitParameter"; +const ModelType FitParameterLinkType = "FitParameterLink"; +const ModelType FitSelectionType = "FitSelection"; +const ModelType MinimizerSettingsType = "Minimizer Settings"; +const ModelType InputDataType = "Input Data"; const ModelType JobItemType = "JobItem"; const ModelType IntensityDataType = "IntensityData"; diff --git a/GUI/coregui/Views/FitView.cpp b/GUI/coregui/Views/FitView.cpp index f4ff62029b4973f8f7dbe87097945835ba0c9243..98612201f309d85ba684bb4dae5fb1fe63ea68d5 100644 --- a/GUI/coregui/Views/FitView.cpp +++ b/GUI/coregui/Views/FitView.cpp @@ -14,46 +14,152 @@ // ************************************************************************** // #include "FitView.h" -#include "RealDataWidget.h" -#include "FitParameterWidget.h" #include "RunFitWidget.h" -#include "FitToolBar.h" -#include "qdebug.h" #include "mainwindow.h" -#include <QTabWidget> +#include "FitSettingsWidget.h" +#include "FitModel.h" +#include "ImportDataWidget.h" +#include "projectmanager.h" #include <QVBoxLayout> +#include <QTabWidget> +#include <QToolBar> +#include <QListWidget> +// REMARKS: -FitView::FitView(FitProxyModel *fitProxyModel, MainWindow *mainWindow) - : QWidget(mainWindow) - , m_fitProxyModel(fitProxyModel) -{ +// minimizer settings will come later - m_realDataWidget = new RealDataWidget(); - m_fitParameterWidget = new FitParameterWidget(m_fitProxyModel); - m_runFitWidget = new RunFitWidget(); +// no narrow toolbar - m_tabWidget = new QTabWidget(); - m_tabWidget->insertTab(REAL_DATA, m_realDataWidget, tr("Real Data")); - m_tabWidget->insertTab(FIT_PARAMETER, m_fitParameterWidget, tr("Fit Parameters")); - m_tabWidget->insertTab(RUN_FIT, m_runFitWidget, tr("Run Fit")); - connect(m_tabWidget, SIGNAL(currentChanged(int)), this, SLOT(onChangeTabWidget(int))); - m_toolBar = new FitToolBar(this); - QVBoxLayout *mainLayout = new QVBoxLayout; - mainLayout->setSizeConstraint(QLayout::SetNoConstraint); - mainLayout->addWidget(m_toolBar); - mainLayout->addWidget(m_tabWidget); - mainLayout->setMargin(0); - mainLayout->setSpacing(0); - setLayout(mainLayout); -} +// ------------------------------------------------------------------------------------------------ +// FIXME_DAVID +// ------------------------------------------------------------------------------------------------ + + + + +// FitParameterWidget --> Refactor ContextMenu part. m_contextMenu should not be member variable. +// * It has to be dynamically generated on right click. See MaskEditorActions::onItemContextMenuRequest +// * Think of creating separate class and isolating all actions activity there. +// See MaskEditor <--> MaskEditorActions (FitParameterWIdget <---> FitParameterWidgetActions ?) +// * Context menu should be always the same --> if given action is not available for underlying item, +// the action should be disabled. See MaskEditorActions::initItemContextMenu(QMenu &menu) +// * Use horizonal delimeter in context menu: +// > Remove parameter <---- this guy can be disabled(gray) if there is no appropriate item beneath +// > ---------------- <---- horizontal delimeter +// > Add parameter + + +// FitParameterWidget --> Add context menu to right m_selectorTreeView +// * There should be +// > create fit parameter +// > add to existing parameter --> and then dynamic menu of existing fit parameters + + + + + +// FitParameterWidget -> Refactor FitParameterWidget::buildTree and buildSelectorModel() +// Part of code should be moved into separate class with static method, similar to +// GUI/coregui/Models/ParameterModelBuilder; you can create there SelectorModelBuilder class +// which will act on QStringList (for example) and return QStandardItemModel + + +// FitParameterItem and its TreeView -> Additional functionality --> TO DISCUSS +// So we need following parameters +// Name | Use | Starting Value | Min | Max +// Could you please try to do the following: +// * Use should be QComboBox with values "free", "fixed", "limited" +// When the user selects "fixed" -> than Min,Max fields become disabled (gray and non-editable) +// When the user selects "free" -> the same +// When the user selects "limited" -> than Min,Max fields become active + +// FitParameterItem and its TreeView -> Additional functionality --> TO DISCUSS +// Please make tooltips for tree header +// "parameter name", "parameter mode: fixed, limited in the interval or free", "starting value of the parameter", "lower parameter bound", "upper parameter bound" -void FitView::onChangeTabWidget(int /*index*/) + +// ------------------------------------------------------------------------------------------------ + +// RunFitWidget --> Refactoring -> It should not act on observer, always address to FitProgressWidget +// * For example, m_interval_slider should be connected with FitProgressWidget, and not observer +// * In the method RunFitWidget::onStartClicked() something like m_fitprogress->attachFitSuite() should be used + + +// void RunFitManager::runFitting() -> Please do not use short variables FittingWorker *fw = new FittingWorker(m_fitSuite); +// Use fittingWorker for variable name + +// FitProgressWidget --> m_guifitobserver , may be it should be unique_ptr instead of shared_ptr? + +// FitProgressWidget, FitObserver --> signal refactoring, ownership --> TO DISCUSS +// > I fill myself not very comfortable with the idea of heavy OutputData's flying around, especially if they are flying separately (real data, chi_squared) +// Possible solution: +// FitObserver reports through signal: +// - There is a log String ready +// - There is data to plot ready (they seats in unique_pt, owned by FitObserver) +// --> And then FitSuite, take it out (throgh std::move, or some other trick) and permits FitObserver to conrinue + + +// RunFitWidget -> intervalSlider -> TO DISCUSS +// * I agree that slider is very nice and impressive, but +// * What if I have very fast simulation (simple model), and I want to update every 1000 iteration? +// It's not nice to have a slider up to 1000. +// * Can we replace a slider with some DropDownBox (every 1 iteration, every 5, 10 and 1000) +// Such boxes also have possibility to type inside any custom number too +// * What if I want to update plotting every 100 iterations, and output every 10. Do I need this actually? :) +// Alternatives ? + + +// ------------------------------------------------------------------------------------------------ +// ImportExperimentalData --> To discuss + + + + + +// ------------------------------------------------------------------------------------------------ + + +FitView::FitView(MainWindow *mainWindow) + : QWidget(mainWindow) + , m_tabs(new QTabWidget) + , m_importDataWidget(new ImportDataWidget(mainWindow->getFitModel(), this)) + , m_fitSettingsWidget(new FitSettingsWidget(mainWindow->getFitModel(), this)) + , m_runFitWidget(new RunFitWidget(mainWindow->getFitModel(), this)) { + QVBoxLayout *layout = new QVBoxLayout; + m_tabs->setStyleSheet("QTabBar::tab { height: 40px; }"); + m_tabs->addTab(m_importDataWidget ,QIcon(":/images/main_home.png"), "Import Experimental Data"); + m_tabs->addTab(m_fitSettingsWidget, "Fit Settings"); + m_tabs->addTab(m_runFitWidget, "Run Fit"); + layout->setMargin(0); + layout->setSpacing(0); + QToolBar *toolBar = new QToolBar(); + toolBar->addAction("Add Fit Workspace"); + toolBar->addSeparator(); + toolBar->addAction("Fit Selection"); + toolBar->addSeparator(); + QListWidget *list = new QListWidget(); + list->setMinimumSize(100, 400); + list->setMaximumWidth(128); + list->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); + m_tabs->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + QHBoxLayout *horizontalLayout = new QHBoxLayout; + horizontalLayout->addWidget(list); + horizontalLayout->addWidget(m_tabs); + layout->addWidget(toolBar); + layout->addLayout(horizontalLayout); + setLayout(layout); + + connect(mainWindow->getProjectManager(), SIGNAL(projectOpened()), + m_fitSettingsWidget, SLOT(onUpdateGUI())); + connect(mainWindow->getProjectManager(), SIGNAL(projectOpened()), + m_importDataWidget, SLOT(onUpdateGUI())); + m_tabs->setCurrentIndex(1); } diff --git a/GUI/coregui/Views/FitView.h b/GUI/coregui/Views/FitView.h index d7cb1989fa3f131a346ac961eb3743e2df0e87c2..bc775507a4e5ec8050d26e43d3b9c27c10688485 100644 --- a/GUI/coregui/Views/FitView.h +++ b/GUI/coregui/Views/FitView.h @@ -16,41 +16,29 @@ #ifndef FITVIEW_H #define FITVIEW_H -#include "FitProxyModel.h" -#include "WinDllMacros.h" +#include <WinDllMacros.h> #include <QWidget> - class MainWindow; class QTabWidget; -class RealDataWidget; -class FitParameterWidget; +class ImportDataWidget; +class FitSettingsWidget; class RunFitWidget; -class FitToolBar; class BA_CORE_API_ FitView : public QWidget { Q_OBJECT public: - enum ETabViewId { REAL_DATA, FIT_PARAMETER, RUN_FIT}; - FitView(FitProxyModel *fitProxyModel, MainWindow *mainWindow); - - -public slots: - void onChangeTabWidget(int index); + //! View containing tabs for fitting + FitView(MainWindow *window); private: - - QTabWidget *m_tabWidget; - RealDataWidget *m_realDataWidget; - FitParameterWidget *m_fitParameterWidget; + QTabWidget *m_tabs; + ImportDataWidget *m_importDataWidget; + FitSettingsWidget *m_fitSettingsWidget; RunFitWidget *m_runFitWidget; - FitToolBar *m_toolBar; - - FitProxyModel *m_fitProxyModel; }; - -#endif // SIMULATIONVIEW_H +#endif diff --git a/GUI/coregui/Views/FitWidgets/FitParameterWidget.cpp b/GUI/coregui/Views/FitWidgets/FitParameterWidget.cpp index 158c1aa006d9aec8dc24b5ae292987feac57a777..504db660fbdd480a85f638a66bec1bd67ec2eec0 100644 --- a/GUI/coregui/Views/FitWidgets/FitParameterWidget.cpp +++ b/GUI/coregui/Views/FitWidgets/FitParameterWidget.cpp @@ -14,201 +14,334 @@ // ************************************************************************** // #include "FitParameterWidget.h" -#include "FitParameterItem.h" -#include <QDebug> +#include "FitModel.h" +#include "FitParameterItems.h" +#include "FitParameterModel.h" +#include "FitSelectorModel.h" +#include "DeleteEventFilter.h" +#include "MinimizerSettingsWidget.h" +#include "minisplitter.h" #include <QVBoxLayout> - - - -FitParameterWidget::FitParameterWidget(FitProxyModel *fitProxyModel, QWidget *parent) +#include <QTreeView> +#include <QSplitter> +#include <QStringList> +#include <QStandardItemModel> +#include <QStandardItem> +#include <QModelIndex> +#include <QMenu> +#include <QAction> +#include <QItemSelection> +#include <QItemSelectionModel> + +#include <QMimeData> +#include <QDragEnterEvent> + +const QString FitParameterWidget::MIME_TYPE = "application/org.bornagainproject.fittinglink"; + +FitParameterWidget::FitParameterWidget(FitModel *fitModel, QWidget *parent) : QWidget(parent) - , m_treeView(0) - , m_fitProxyModel(fitProxyModel) + , m_fitModel(fitModel) + , m_selectorTreeView(new QTreeView()) + , m_parameterTreeview(new QTreeView()) + , m_selectorModel(nullptr) + , m_parameterModel(nullptr) + , m_contextMenu(new QMenu()) + , m_splitter(new Manhattan::MiniSplitter(this)) + , m_keyboardFilter(new DeleteEventFilter(this)) { - QColor bgColor(255,255,255,255); - QPalette palette; - palette.setColor(QPalette::Background, bgColor); - setAutoFillBackground(true); - setPalette(palette); - - - initFitModel(); - - m_fitProxyModel->setFitModel(m_fitModel); - m_fitProxyModel->setHeaderData(0, Qt::Horizontal,"Title"); - - /*if(m_fitModel) - { - ParameterizedItem *item1 = m_fitModel->insertNewItem(Constants::FitParameterType); - item1->setItemName("par1"); - item1->setRegisteredProperty(FitParameterItem::P_MIN, 1.0); - - FitParameterItem *item2 = dynamic_cast<FitParameterItem *>(m_fitModel->insertNewItem(Constants::FitParameterType)); - item2->setItemName("par2"); - -// ParameterizedItem *old_item = m_fitModel->itemForIndex(m_fitModel->index(0,0, QModelIndex())); -// qDebug() << "FitModel: " << old_item->getRegisteredProperty(FitParameterItem::P_MIN); - -// FitParameterItem *fit_item = dynamic_cast<FitParameterItem *>(m_fitModel->itemForIndex(m_fitModel->index(1,0, QModelIndex()))); -// qDebug() << "FitModel: " << fit_item->getRegisteredProperty(FitParameterItem::P_MAX); - - - - }*/ - - - m_treeView = new QTreeView(); - m_treeView->setStyleSheet("QTreeView::branch {background: palette(base);}QTreeView::branch:has-siblings:!adjoins-item {border-image: url(:/images/treeview-vline.png) 0;}QTreeView::branch:has-siblings:adjoins-item {border-image: url(:/images/treeview-branch-more.png) 0;}QTreeView::branch:!has-children:!has-siblings:adjoins-item {border-image: url(:/images/treeview-branch-end.png) 0;}QTreeView::branch:has-children:!has-siblings:closed,QTreeView::branch:closed:has-children:has-siblings {border-image: none;image: url(:/images/treeview-branch-closed.png);}QTreeView::branch:open:has-children:!has-siblings,QTreeView::branch:open:has-children:has-siblings {border-image: none;image: url(:/images/treeview-branch-open.png);}"); - - - //m_parameterModel = createParameterModel(m_fitModel); - //connect(m_parameterModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(onModelChanged(QModelIndex,QModelIndex))); - - - -// FitProxyModel *fitProxyModel = new FitProxyModel; -// qDebug() << fitProxyModel; - - - int height = this->height(); - m_treeView->setModel(m_fitProxyModel); - m_treeView->setFixedHeight(height); - m_treeView->setColumnWidth(0,170); - m_treeView->expandAll(); - + m_parameterModel = new FitParameterModel(m_fitModel, this); + + QString style( + "QTreeView::branch {background: palette(base);}QTreeView::branch:has-siblings:!adjoins-item " + "{border-image: url(:/images/treeview-vline.png) 0;}QTreeView::branch:has-siblings:" + "adjoins-item {border-image: url(:/images/treeview-branch-more.png) 0;}QTreeView::branch:" + "!has-children:!has-siblings:adjoins-item {border-image: " + "url(:/images/treeview-branch-end.png) 0;}QTreeView::branch:has-children:!has-siblings:closed" + ",QTreeView::branch:closed:has-children:has-siblings {border-image: none;image: " + "url(:/images/treeview-branch-closed.png);}QTreeView::branch:open:has-children:!has-siblings," + "QTreeView::branch:open:has-children:has-siblings {border-image: none;image: " + "url(:/images/treeview-branch-open.png);}"); + + m_selectorTreeView->setStyleSheet(style); + m_selectorTreeView->setDragEnabled(true); + m_selectorTreeView->setDragDropMode(QAbstractItemView::DragOnly); + + m_parameterTreeview->setStyleSheet(style); + m_parameterTreeview->setAcceptDrops(true); + m_parameterTreeview->setDragDropMode(QAbstractItemView::DropOnly); + m_parameterTreeview->setModel(m_parameterModel); + m_parameterTreeview->setColumnWidth(0, 300); + m_parameterTreeview->setColumnWidth(2, 120); + m_parameterTreeview->setContextMenuPolicy(Qt::CustomContextMenu); + m_parameterTreeview->installEventFilter(m_keyboardFilter); + + m_removeAction = m_contextMenu->addAction("Remove", this, SLOT(onRemoveParameter())); + m_addAction = m_contextMenu->addAction("Add Parameter", m_parameterModel, SLOT(addParameter())); + + /*QSplitter *rightWindow = new QSplitter; + rightWindow->setOrientation(Qt::Vertical); + rightWindow->addWidget(m_parameterTreeview); + m_parameterTreeview->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + auto *minimizersettings = new MinimizerSettingsWidget(m_fitModel, this); + rightWindow->addWidget(minimizersettings); + rightWindow->setSizes(QList<int>() << 3000 << 1000);*/ + + m_splitter->addWidget(m_selectorTreeView); + m_splitter->addWidget(m_parameterTreeview); + m_splitter->setSizes(QList<int>() << 10000 << 20000); QVBoxLayout *vlayout = new QVBoxLayout(this); vlayout->setMargin(0); vlayout->setSpacing(0); - vlayout->addWidget(m_treeView); - vlayout->addStretch(); + vlayout->addWidget(m_splitter); this->setLayout(vlayout); + // update selector when sample model changes - more jobs to be done here + //connect(m_sampleModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)), + // this, SLOT(updateSelector())); -// QModelIndex idx = m_parameterModel->invisibleRootItem()->index(); -// for (int i=0; i<m_parameterModel->rowCount(); i++){ -// if (m_parameterModel->item(i,0)->hasChildren()){ + connect(m_parameterModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)), + m_fitModel, SLOT(dataChangedProxy(QModelIndex,QModelIndex,QVector<int>))); -// m_treeView->setFirstColumnSpanned(0, m_parameterModel->item(i,0)->index(), true); -// m_treeView->setFirstColumnSpanned(1, m_parameterModel->item(i,0)->index(), true); -// } -// } + // setup firstcolumnspanning + connect(m_parameterModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)), + this, SLOT(spanParameters())); + // make context menu availabe + connect(m_parameterTreeview, SIGNAL(customContextMenuRequested(const QPoint &)), + this, SLOT(onCustomContextMenu(const QPoint &))); -} + // event from keyeventfilter + connect(m_keyboardFilter, SIGNAL(removeItem()), this, SLOT(removeSelectedItem())); -QStandardItemModel *FitParameterWidget::createParameterModel(FitModel *fitModel) -{ - QStandardItemModel *result(0); - result = new QStandardItemModel(); - result->setHorizontalHeaderItem( 0, new QStandardItem( "Property" ) ); - result->setHorizontalHeaderItem( 1, new QStandardItem( "Use" ) ); - result->setHorizontalHeaderItem( 2, new QStandardItem( "Value" ) ); - result->setHorizontalHeaderItem( 3, new QStandardItem( "Min" ) ); - result->setHorizontalHeaderItem( 4, new QStandardItem( "Max" ) ); - - - iterateSessionModel(fitModel, QModelIndex(), result); -// if(standardItem) -// { -// result->appendRow(standardItem); -// } - - return result; -} + // select by doubleclick + connect(m_selectorTreeView, SIGNAL(doubleClicked(QModelIndex)), + this, SLOT(onDoubleclick(QModelIndex))); -QStandardItemModel *FitParameterWidget::iterateSessionModel(FitModel *fitModel, const QModelIndex &parentIndex, QStandardItemModel *parentItem) -{ - Q_ASSERT(fitModel); - - if(!parentIndex.isValid()) { - qDebug() << "Dumping model"; - } - - - for( int i_row = 0; i_row < fitModel->rowCount( parentIndex ); ++i_row) { - QModelIndex itemIndex = fitModel->index( i_row, 0, parentIndex ); + connectParameterView(); +} - if (ParameterizedItem *item = fitModel->itemForIndex(itemIndex)){ - - - qDebug() << "FitParameterWidget::iterateSessionModel: " << item->itemName() << item->getRegisteredProperty(FitParameterItem::P_MIN)<< item->getRegisteredProperty(FitParameterItem::P_MAX); +void FitParameterWidget::updateSelector() +{ + m_parameterModel = new FitParameterModel(m_fitModel, this); + m_parameterTreeview->setModel(m_parameterModel); + connect(m_parameterModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)), + m_fitModel, SLOT(dataChangedProxy(QModelIndex,QModelIndex,QVector<int>))); + + // setup firstcolumnspanning + connect(m_parameterModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)), + this, SLOT(spanParameters())); + spanParameters(); + buildSelectorModel(); + + m_selectorTreeView->setModel(m_selectorModel); + m_selectorTreeView->expandAll(); + m_selectorTreeView->resizeColumnToContents(0); + m_selectorTreeView->setColumnWidth(0, m_selectorTreeView->columnWidth(0) * 1.2); + + connectSelectorView(); +} - insertRowIntoItem(parentItem, item->itemName(), item->getRegisteredProperty(FitParameterItem::P_VALUE), item->getRegisteredProperty(FitParameterItem::P_MIN), item->getRegisteredProperty(FitParameterItem::P_MAX), item->getRegisteredProperty(FitParameterItem::P_USE)); +void FitParameterWidget::clearParameter() { + while (m_parameterModel->rowCount(QModelIndex())) { + m_parameterModel->removeRow(0, QModelIndex()); + } +} +void FitParameterWidget::buildTree(QStandardItem *root, ParameterizedItem *top) +{ + QStringList parameterTree = top->getParameterTreeList(); + + foreach (const QString &str, parameterTree) { + QStringList parts = str.split("/"); + QStandardItem *cur = root; + for (int partIndex = 0; partIndex < parts.size(); partIndex++) { + bool insertItem = true; + + // search for existing child + for (int childIndex = 0; childIndex < cur->rowCount(); childIndex++) { + if (cur->child(childIndex, 0)->text() == parts[partIndex]) { + cur = cur->child(childIndex, 0); + insertItem = false; + break; + } + } + if (insertItem) { + QStandardItem *item = new QStandardItem(parts[partIndex]); + QStandardItem *data = new QStandardItem(); + item->setEditable(false); + data->setEditable(false); + if (partIndex == parts.size() - 1) { // arrived at the end + double value = top->getParameterValue(str); + data->setData(QVariant(value), Qt::EditRole); + } else { + item->setDragEnabled(false); + data->setDragEnabled(false); + } + cur->appendRow(QList<QStandardItem *>() << item << data); + cur = item; + } } - } +} - return parentItem; +void FitParameterWidget::buildSelectorModel() { + + m_selectorModel = new FitSelectorModel(); + m_selectorModel->setHorizontalHeaderItem(0, new QStandardItem("Property")); + m_selectorModel->setHorizontalHeaderItem(1, new QStandardItem("Value")); + QStandardItem *root = m_selectorModel->invisibleRootItem(); + + ParameterizedItem *topSample = m_fitModel->getSelectedMultiLayerItem(); + ParameterizedItem *topInst = m_fitModel->getSelectedInstrumentItem(); + if (topSample && topInst) { + QStandardItem *multilayer = new QStandardItem("MultiLayer"); + root->appendRow(multilayer); + buildTree(multilayer, topSample); + QStandardItem *instrument = new QStandardItem("Instrument"); + root->appendRow(instrument); + buildTree(instrument, topInst); + spanParameters(); + } } -void FitParameterWidget::insertRowIntoItem(QStandardItemModel *parentItem, QString title, QVariant value, QVariant min, QVariant max, QVariant isUse) +void FitParameterWidget::spanParameters() { + m_parameterTreeview->expandAll(); + for (int i = 0; i < m_parameterModel->rowCount(QModelIndex()); i++){ + QModelIndex parameter = m_parameterModel->index(i,0,QModelIndex()); + if (!parameter.isValid()) + break; + int childRowCount = m_parameterModel->rowCount(parameter); + if (childRowCount > 0){ + for (int j = 0; j < childRowCount; j++) { + m_parameterTreeview->setFirstColumnSpanned(j, parameter, true); + } + } + } +} - QStandardItem *titleItem = new QStandardItem(title); - - QStandardItem *useItem = new QStandardItem(); - useItem->setData(isUse, Qt::EditRole); - useItem->setEditable(true); +void FitParameterWidget::onCustomContextMenu(const QPoint &point) { + m_removeAction->setEnabled(false); + QModelIndex index = m_parameterTreeview->indexAt(point); + if (index.isValid()) { + ParameterizedItem *cur = m_parameterModel->itemForIndex(index); + if (cur->itemName().startsWith("FitParameter")) { + m_parameterTreeview->setCurrentIndex(index); + m_removeAction->setEnabled(true); + } + } + m_contextMenu->exec(m_parameterTreeview->mapToGlobal(point + QPoint(2, 22))); +} - QStandardItem *valueItem = new QStandardItem(); - valueItem->setData(value, Qt::EditRole); - valueItem->setEditable(true); +void FitParameterWidget::onRemoveParameter() { + QModelIndex index = m_parameterTreeview->currentIndex(); + if (index.isValid()) { + m_parameterModel->removeRow(index.row(), index.parent()); + } +} - QStandardItem *minItem = new QStandardItem(); - minItem->setData(min, Qt::EditRole); - minItem->setEditable(true); +void FitParameterWidget::onParameterSelectionChanged(const QItemSelection &selection) +{ + if (selection.indexes().isEmpty()) + return; + QModelIndex index = selection.indexes().first(); + QModelIndex newSelection = QModelIndex(); + if (index.isValid() && index.parent().isValid()) { + ParameterizedItem *val = m_fitModel->itemForIndex(index); + QString link = val->getRegisteredProperty(FitParameterLinkItem::P_LINK).toString(); + QStandardItem *t = m_selectorModel->getItemFromPath(link); + newSelection = m_selectorModel->indexFromItem(t); + } + connectSelectorView(false); + m_selectorTreeView->selectionModel() + ->select(newSelection, QItemSelectionModel::ClearAndSelect); + if (newSelection.isValid()) { + newSelection = newSelection.sibling(newSelection.row(), 1); + m_selectorTreeView->selectionModel() + ->select(newSelection, QItemSelectionModel::Select); + } + connectSelectorView(); +} - QStandardItem *maxItem = new QStandardItem(); - maxItem->setData(max, Qt::EditRole); - maxItem->setEditable(true); +void FitParameterWidget::onSelectorSelectionChanged(const QItemSelection &selection) +{ + if (selection.indexes().isEmpty()) + return; + QModelIndex index = selection.indexes().first(); + index = index.sibling(index.row(), 0); + QModelIndex newSelection = QModelIndex(); + if (index.isValid()) { + QString link = m_selectorModel->getPathFromIndex(index); + newSelection = m_parameterModel->itemForLink(link); + } + connectParameterView(false); + m_parameterTreeview->selectionModel()-> + select(newSelection, QItemSelectionModel::ClearAndSelect); + connectParameterView(); +} +void FitParameterWidget::connectSelectorView(bool active) { + if (active) { + connect(m_selectorTreeView->selectionModel(), + SIGNAL(selectionChanged(QItemSelection,QItemSelection)), + this, SLOT(onSelectorSelectionChanged(QItemSelection))); + } else { + disconnect(m_selectorTreeView->selectionModel(), + SIGNAL(selectionChanged(QItemSelection,QItemSelection)), + this, SLOT(onSelectorSelectionChanged(QItemSelection))); + } +} - QStandardItem *subItem1 = new QStandardItem("this is the description 1 this is the description 1 this is the description 1"); - QStandardItem *subItem2 = new QStandardItem("this is the description 2 this is the description 2 this is the description 2"); - titleItem->appendRow(QList<QStandardItem *>() << subItem1 << new QStandardItem << new QStandardItem <<new QStandardItem <<new QStandardItem); - titleItem->appendRow(subItem2); +void FitParameterWidget::connectParameterView(bool active) { + if (active) { + connect(m_parameterTreeview->selectionModel(), + SIGNAL(selectionChanged(QItemSelection,QItemSelection)), + this, SLOT(onParameterSelectionChanged(QItemSelection))); + } else { + disconnect(m_parameterTreeview->selectionModel(), + SIGNAL(selectionChanged(QItemSelection,QItemSelection)), + this, SLOT(onParameterSelectionChanged(QItemSelection))); + } +} - parentItem->appendRow(QList<QStandardItem *>() << titleItem << useItem << valueItem << minItem << maxItem); +void FitParameterWidget::removeEmptyParameter() { + bool finished = false; + while (!finished) { + int rowCount = m_parameterModel->rowCount(QModelIndex()); + if (rowCount == 0) + break; + for (int i=0; i<rowCount; i++) { + QModelIndex child = m_parameterModel->index(i,0,QModelIndex()); + if (child.isValid() && m_parameterModel->rowCount(child) == 0) { + m_parameterModel->removeRow(i, QModelIndex()); + break; + } + if (i + 1 == rowCount) { + finished = true; + } + } + } +} +void FitParameterWidget::removeSelectedItem() { + QModelIndex selection = m_parameterTreeview->currentIndex(); + if (selection.isValid()) { + m_parameterModel->removeRow(selection.row(), selection.parent()); + } + removeEmptyParameter(); } -void FitParameterWidget::initFitModel() -{ - m_fitModel = new FitModel; - -// ParameterizedItem *item1 = m_fitModel->insertNewItem(Constants::FitParameterType); -// item1->setItemName("Par1"); -// item1->setRegisteredProperty(FitParameterItem::P_USE, true); -// item1->setRegisteredProperty(FitParameterItem::P_VALUE, 3.0); -// item1->setRegisteredProperty(FitParameterItem::P_MIN, 1.0); -// item1->setRegisteredProperty(FitParameterItem::P_MAX, 5.0); -// //item1->setRegisteredProperty(FitParameterItem::P_NAME, tr("Par1")); - - FitParameterItem *item1 = dynamic_cast<FitParameterItem *>(m_fitModel->insertNewItem(Constants::FitParameterType)); - item1->setItemName("Par1"); - QStringList descList1; - descList1 << "This is description 1" << "This is description 2" << "This is description 3"; - item1->setParNames(descList1); - - FitParameterItem *item2 = dynamic_cast<FitParameterItem *>(m_fitModel->insertNewItem(Constants::FitParameterType)); - item2->setItemName("Par2"); - QStringList descList2; - descList2 << "This is description 1" << "This is description 2" << "This is description 3"; - item2->setParNames(descList2); - - FitParameterItem *item3 = dynamic_cast<FitParameterItem *>(m_fitModel->insertNewItem(Constants::FitParameterType)); - item3->setItemName("Par3"); - QStringList descList3; - descList3 << "This is description 1" << "This is description 2" << "This is description 3"; - item3->setParNames(descList3); - - - m_fitModel->save("fitmodel.xml"); - - //ParameterizedItem *old_item = m_fitModel->itemForIndex(m_fitModel->index(0,0, QModelIndex())); +void FitParameterWidget::onDoubleclick(const QModelIndex index) { + QModelIndex entryIndex = index.sibling(index.row(), 0); + if (m_selectorModel->itemFromIndex(entryIndex)->isDragEnabled()) { + QMimeData *data = m_selectorModel->mimeData(QModelIndexList() << entryIndex); + if (m_parameterModel->canDropMimeData(data,Qt::CopyAction,0,0,QModelIndex())) { + m_parameterModel->dropMimeData(data,Qt::CopyAction,-1,-1,QModelIndex()); + } + data->deleteLater(); + } } diff --git a/GUI/coregui/Views/FitWidgets/FitParameterWidget.h b/GUI/coregui/Views/FitWidgets/FitParameterWidget.h index 39f5d93f67f14685a595f7406b9b4c395851c835..83672f4328d489ae8cf9adc775e9a9abf4f5ecaf 100644 --- a/GUI/coregui/Views/FitWidgets/FitParameterWidget.h +++ b/GUI/coregui/Views/FitWidgets/FitParameterWidget.h @@ -16,38 +16,67 @@ #ifndef FITPARAMETERWIDGET_H #define FITPARAMETERWIDGET_H +#include "WinDllMacros.h" +#include "SessionModel.h" #include <QWidget> -#include <QTreeView> -#include <QAction> -#include <QTableWidget> - -#include "FitProxyModel.h" -#include "FitModel.h" +#include <QStandardItemModel> +#include <QAbstractItemModel> +class QTreeView; +class MainWindow; +class FitSelectorModel; +class QMenu; +class SampleModel; +class InstrumentModel; class FitModel; - - +class ParameterizedItem; +class FitParameterModel; +class QItemSelection; +class QSplitter; +class DeleteEventFilter; class BA_CORE_API_ FitParameterWidget : public QWidget { Q_OBJECT public: - FitParameterWidget(FitProxyModel *fitProxyModel, QWidget *parent = 0); + static const QString MIME_TYPE; + FitParameterWidget(FitModel *fitModel, QWidget *parent = 0); -private: - FitModel *m_fitModel; - QStandardItemModel *m_parameterModel; - QTreeView *m_treeView; - FitProxyModel *m_fitProxyModel; + void clearParameter(); +public slots: + void updateSelector(); + void spanParameters(); + void removeSelectedItem(); + void onCustomContextMenu(const QPoint &point); + void onRemoveParameter(); - QStandardItemModel *createParameterModel(FitModel *fitModel); - QStandardItemModel *iterateSessionModel(FitModel *fitModel, const QModelIndex &parentIndex = QModelIndex(), QStandardItemModel *parentItem = 0); - void insertRowIntoItem(QStandardItemModel *parentItem, QString title, QVariant value, QVariant min, QVariant max, QVariant isUse); + void onParameterSelectionChanged(const QItemSelection&selection); + void onSelectorSelectionChanged(const QItemSelection &selection); + void onDoubleclick(const QModelIndex index); - void initFitModel(); +private: + void buildSelectorModel(); + void connectSelectorView(bool active = true); + void connectParameterView(bool active = true); + void buildTree(QStandardItem *root, ParameterizedItem *top); + void removeEmptyParameter(); + + FitModel *m_fitModel; + QTreeView *m_selectorTreeView; + QTreeView *m_parameterTreeview; + FitSelectorModel *m_selectorModel; + FitParameterModel *m_parameterModel; + QMenu *m_contextMenu; + QAction *m_removeAction; + QAction *m_addAction; + QSplitter *m_splitter; + DeleteEventFilter *m_keyboardFilter; }; + + + #endif diff --git a/GUI/coregui/Views/FitWidgets/FitProgressWidget.cpp b/GUI/coregui/Views/FitWidgets/FitProgressWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b8e5d083b0fb6addfb48f81b1245137700e85450 --- /dev/null +++ b/GUI/coregui/Views/FitWidgets/FitProgressWidget.cpp @@ -0,0 +1,145 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Views/FitWidgets/RunFitWidget.h +//! @brief Defines class RunFitWidget +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2015 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke +// +// ************************************************************************** // + +#include "FitProgressWidget.h" +#include "ColorMapPlot.h" +#include "IntensityDataItem.h" +#include "GUIFitObserver.h" +#include "FitSuite.h" +#include "qcustomplot.h" +#include <QLabel> +#include <QVBoxLayout> +#include <QHBoxLayout> +#include <QPlainTextEdit> +#include <QSplitter> +#include <QScrollBar> +#include <QFont> +#include <QSlider> + +FitProgressWidget::FitProgressWidget(QWidget *parent) + : QWidget(parent) + , m_status(new QLabel(this)) + , m_realdataplot(new ColorMapPlot(this)) + , m_simulatedplot(new ColorMapPlot(this)) + , m_chi2plot(new ColorMapPlot(this)) + , m_realdata(new IntensityDataItem()) + , m_simulated(new IntensityDataItem()) + , m_chi2(new IntensityDataItem()) + , m_log(new QPlainTextEdit(this)) + , m_splitter(new QSplitter()) +{ + m_guifitobserver = boost::shared_ptr<GUIFitObserver>(new GUIFitObserver(this)); + + connect(m_guifitobserver.get(), SIGNAL(updateStatus(const QString&)), + this, SLOT(updateStatus(const QString&))); + connect(m_guifitobserver.get(), SIGNAL(updatePlots(OutputData<double>*, OutputData<double>*)), + this, SLOT(updatePlots(OutputData<double>*, OutputData<double>*))); + connect(m_guifitobserver.get(), SIGNAL(updateLog(const QString&)), + this, SLOT(updateLog(const QString&))); + connect(m_guifitobserver.get(), SIGNAL(startFitting(OutputData<double>*)), + this, SLOT(startFitting(OutputData<double>*))); + + // chi2 is the last plot to finish, so we wait for it + connect(m_chi2plot->getCustomPlot(), SIGNAL(afterReplot()), + this, SLOT(afterReplot())); + + m_realdataplot->setItem(m_realdata); + m_simulatedplot->setItem(m_simulated); + m_chi2plot->setItem(m_chi2); + m_chi2->setProperty("Gradient", "Hot"); + + QHBoxLayout *plots = new QHBoxLayout(); + plots->addWidget(m_realdataplot); + plots->addWidget(m_simulatedplot); + plots->addWidget(m_chi2plot); + QWidget *plotsWidget = new QWidget(); + plotsWidget->setLayout(plots); + + m_splitter->setOrientation(Qt::Vertical); + m_splitter->addWidget(plotsWidget); + m_splitter->addWidget(m_log); + + QVBoxLayout *layout = new QVBoxLayout(); + layout->addWidget(m_status); + layout->addWidget(m_splitter); + m_log->setReadOnly(true); + m_log->setMaximumBlockCount(100000); + QFont f("unexistent"); + f.setStyleHint(QFont::Monospace); + m_log->setFont(f); + m_status->setText(""); + setLayout(layout); +} + +void FitProgressWidget::startFitting(OutputData<double> *real) +{ + m_realdata->setOutputData(real); + m_simulated->setOutputData(real->clone()); + m_simulated->setZAxisLocked(true); + disableInteractions(); + m_log->clear(); +} + +void FitProgressWidget::connectSlider(QSlider *slider) +{ + connect(slider, SIGNAL(valueChanged(int)), + m_guifitobserver.get(), SLOT(setInterval(int))); +} + +void FitProgressWidget::setObserverToSuite(FitSuite *suite) +{ + suite->attachObserver(m_guifitobserver); +} + +void FitProgressWidget::updateStatus(const QString &text) +{ + m_status->setText(text); +} + +void FitProgressWidget::updateLog(const QString &msg) +{ + QScrollBar *scrollbar = m_log->verticalScrollBar(); + bool autoscroll = scrollbar->value() == scrollbar->maximum(); + m_log->appendPlainText(msg); + if (autoscroll) { + QTextCursor c = m_log->textCursor(); + c.movePosition(QTextCursor::End); + m_log->setTextCursor(c); + } +} + +void FitProgressWidget::updatePlots(OutputData<double> *sim, OutputData<double> *chi) +{ + m_simulated->setOutputData(sim); + m_simulated->setLowerAndUpperZ(m_realdata->getLowerZ(), m_realdata->getUpperZ()); + m_chi2->setOutputData(chi); + disableInteractions(); +} + +void FitProgressWidget::afterReplot() +{ + m_guifitobserver->finishedPlotting(); +} + +void FitProgressWidget::disableInteractions() +{ + // as ColorMapPlot enables Interactions every time, we must disenable them as well + m_realdataplot->getCustomPlot()->setInteraction(QCP::iRangeDrag, false); + m_realdataplot->getCustomPlot()->setInteraction(QCP::iRangeZoom, false); + m_simulatedplot->getCustomPlot()->setInteraction(QCP::iRangeDrag, false); + m_simulatedplot->getCustomPlot()->setInteraction(QCP::iRangeZoom, false); + m_chi2plot->getCustomPlot()->setInteraction(QCP::iRangeDrag, false); + m_chi2plot->getCustomPlot()->setInteraction(QCP::iRangeZoom, false); +} diff --git a/GUI/coregui/Views/FitWidgets/FitProgressWidget.h b/GUI/coregui/Views/FitWidgets/FitProgressWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..c20eb04b3680e137475d2de8e697cba3f8115277 --- /dev/null +++ b/GUI/coregui/Views/FitWidgets/FitProgressWidget.h @@ -0,0 +1,77 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Views/FitWidgets/RunFitWidget.h +//! @brief Defines class RunFitWidget +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2015 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke +// +// ************************************************************************** // + +#ifndef FITPROGRESSWIDGET_H +#define FITPROGRESSWIDGET_H + +#include "WinDllMacros.h" +#include "OutputData.h" +#include <boost/shared_ptr.hpp> +#include <QWidget> + +class QLabel; +class ColorMapPlot; +class IntensityDataItem; +class QPlainTextEdit; +class QSplitter; +class GUIFitObserver; +class QSlider; +class FitSuite; + +class BA_CORE_API_ FitProgressWidget : public QWidget +{ + Q_OBJECT + +public: + + FitProgressWidget(QWidget *parent = 0); + + void connectSlider(QSlider *slider); + + void setObserverToSuite(FitSuite *suite); + +public slots: + + void updateStatus(const QString &text); + + void updateLog(const QString &msg); + + void updatePlots(OutputData<double> *sim, OutputData<double> *chi); + + void startFitting(OutputData<double> *real); + + void afterReplot(); + +private: + + QLabel *m_status; + ColorMapPlot *m_realdataplot; + ColorMapPlot *m_simulatedplot; + ColorMapPlot *m_chi2plot; + IntensityDataItem *m_realdata; + IntensityDataItem *m_simulated; + IntensityDataItem *m_chi2; + QPlainTextEdit *m_log; + QSplitter *m_splitter; + boost::shared_ptr<GUIFitObserver> m_guifitobserver; + + void disableInteractions(); +}; + + + + + +#endif diff --git a/GUI/coregui/Views/FitWidgets/FitSettingsWidget.cpp b/GUI/coregui/Views/FitWidgets/FitSettingsWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bfd29c8ba46431832b2b075c34f7ded14d6f290f --- /dev/null +++ b/GUI/coregui/Views/FitWidgets/FitSettingsWidget.cpp @@ -0,0 +1,119 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Views/FitWidgets/RunFitWidget.h +//! @brief Defines class RunFitWidget +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2015 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke +// +// ************************************************************************** // + +#include "FitSettingsWidget.h" +#include "FitParameterWidget.h" +#include "FitModel.h" + +#include <QVBoxLayout> +#include <QHBoxLayout> +#include <QComboBox> +#include <QLabel> + + +FitSettingsWidget::FitSettingsWidget(FitModel *fitModel, QWidget *parent) + : QWidget(parent) + , m_fitModel(fitModel) + , m_fitParameter(new FitParameterWidget(m_fitModel, this)) + , m_sampleCombo(new QComboBox()) + , m_instrumentCombo(new QComboBox()) +{ + m_sampleCombo->setMinimumWidth(200); + m_instrumentCombo->setMinimumWidth(200); + + QVBoxLayout *mainLayout = new QVBoxLayout(); + QHBoxLayout *topLayout = new QHBoxLayout(); + topLayout->addWidget(new QLabel("Select Sample:")); + topLayout->addWidget(m_sampleCombo); + topLayout->addSpacing(30); + topLayout->addWidget(new QLabel("Select Instrument:")); + topLayout->addWidget(m_instrumentCombo); + topLayout->addStretch(); + QWidget *topWidget = new QWidget(); + topWidget->setLayout(topLayout); + topWidget->setContentsMargins(0,0,0,0); + topWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); + mainLayout->addWidget(topWidget); + mainLayout->addWidget(m_fitParameter); + m_fitParameter->setSizePolicy(QSizePolicy::MinimumExpanding, + QSizePolicy::MinimumExpanding); + connectCombos(); + setLayout(mainLayout); +} + +void FitSettingsWidget::showEvent(QShowEvent *) +{ + onUpdateGUI(); +} + +void FitSettingsWidget::onUpdateGUI() +{ + m_fitParameter->updateSelector(); + + disconnectCombos(); + m_sampleCombo->clear(); + m_instrumentCombo->clear(); + + foreach (QString v, m_fitModel->getSampleNames()) { + m_sampleCombo->addItem(m_fitModel->getSampleItemNameForDisplayName(v), + v); + } + + foreach (QString v, m_fitModel->getInstrumentNames()) { + m_instrumentCombo->addItem(m_fitModel->getInstrumentItemNameForDisplayName(v), + v); + } + m_sampleCombo->setCurrentIndex(-1); + m_instrumentCombo->setCurrentIndex(-1); + connectCombos(); + + m_instrumentCombo->setCurrentIndex(m_instrumentCombo->findData + (m_fitModel->getSelectedInstrumentName())); + m_sampleCombo->setCurrentIndex(m_sampleCombo->findData(m_fitModel->getSelectedSampleName())); +} + +void FitSettingsWidget::onSampleChanged(int index) +{ + QString data = m_sampleCombo->itemData(index).toString(); + if (data != m_fitModel->getSelectedSampleName()) { + m_fitModel->setSelectedSample(data); + m_fitParameter->updateSelector(); + // when sample changed, discard all fit parameters + m_fitParameter->clearParameter(); + } +} + +void FitSettingsWidget::onInstrumentChanged(int index) +{ + QString data = m_instrumentCombo->itemData(index).toString(); + if (data != m_fitModel->getSelectedInstrumentName()) { + m_fitModel->setSelectedInstrument(data); + m_fitParameter->updateSelector(); + // when sample changed, discard all fit parameters + m_fitParameter->clearParameter(); + } +} + +void FitSettingsWidget::connectCombos() { + connect(m_sampleCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onSampleChanged(int))); + connect(m_instrumentCombo, SIGNAL(currentIndexChanged(int)), + this, SLOT(onInstrumentChanged(int))); +} + +void FitSettingsWidget::disconnectCombos() { + disconnect(m_sampleCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onSampleChanged(int))); + disconnect(m_instrumentCombo, SIGNAL(currentIndexChanged(int)), + this, SLOT(onInstrumentChanged(int))); +} diff --git a/GUI/coregui/Views/FitWidgets/FitSettingsWidget.h b/GUI/coregui/Views/FitWidgets/FitSettingsWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..8953daa2b1e750cf4f739b8e398e14769079fb26 --- /dev/null +++ b/GUI/coregui/Views/FitWidgets/FitSettingsWidget.h @@ -0,0 +1,56 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Views/FitWidgets/RunFitWidget.h +//! @brief Defines class RunFitWidget +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2015 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke +// +// ************************************************************************** // + +#ifndef FITSETTINGSWIDGET_H +#define FITSETTINGSWIDGET_H + +#include "WinDllMacros.h" +#include <QWidget> + +class FitModel; +class FitParameterWidget; +class QComboBox; + + +class BA_CORE_API_ FitSettingsWidget : public QWidget +{ + Q_OBJECT + +public: + FitSettingsWidget(FitModel *fitModel, QWidget *parent); + + //! we update GUI when widget is shown + void showEvent(QShowEvent *); + + //! connect and disconnect signals for comboboxes + void connectCombos(); + void disconnectCombos(); + +public slots: + //! call this slot to refresh comboboxes and fitparameters + void onUpdateGUI(); + + //! slots for sample/instrument changes + void onSampleChanged(int index); + void onInstrumentChanged(int index); + +private: + FitModel *m_fitModel; + FitParameterWidget *m_fitParameter; + QComboBox *m_sampleCombo; + QComboBox *m_instrumentCombo; +}; + +#endif diff --git a/GUI/coregui/Views/FitWidgets/FitToolBar.cpp b/GUI/coregui/Views/FitWidgets/FitToolBar.cpp deleted file mode 100644 index 2cfb42679fbbdf807e4e62059e7e2184868c65d1..0000000000000000000000000000000000000000 --- a/GUI/coregui/Views/FitWidgets/FitToolBar.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// ************************************************************************** // -// -// BornAgain: simulate and fit scattering at grazing incidence -// -//! @file coregui/Views/FitWidgets/FitToolBar.cpp -//! @brief Implements class FitToolBar -//! -//! @homepage http://www.bornagainproject.org -//! @license GNU General Public License v3 or higher (see COPYING) -//! @copyright Forschungszentrum Jülich GmbH 2015 -//! @authors Scientific Computing Group at MLZ Garching -//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke -// -// ************************************************************************** // - -#include "FitToolBar.h" -#include "styledbar.h" - -#include <QIcon> -#include <QAction> -#include <QToolButton> -#include <QToolBar> -#include <QStyle> -#include <iostream> - - -FitToolBar::FitToolBar(QWidget *parent) - : QToolBar(parent) -{ - setMovable(false); - - const int size = style()->pixelMetric(QStyle::PM_SmallIconSize); - setIconSize(QSize(size, size)); - setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); - - setContentsMargins(0,0,0,0); - - this->addAction(new QAction(0)); - -} diff --git a/GUI/coregui/Views/FitWidgets/FittingWorker.cpp b/GUI/coregui/Views/FitWidgets/FittingWorker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5a1e7176b36192fbd61f141a7c69f971f97d397b --- /dev/null +++ b/GUI/coregui/Views/FitWidgets/FittingWorker.cpp @@ -0,0 +1,37 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Views/FitWidgets/FittingWorker.cpp +//! @brief Implements class FittingWorker +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2015 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke +// +// ************************************************************************** // + +#include "FittingWorker.h" +#include "FitSuite.h" + +void FittingWorker::startFit() +{ + m_fitsuite->resetInterrupt(); + emit started(); + try { + m_fitsuite->runFit(); + } catch(const std::exception& ex) { + emit error(QString::fromLatin1(ex.what())); + } + emit finished(); +} + +void FittingWorker::interruptFitting() +{ + if (m_fitsuite) { + m_fitsuite->interruptFitting(); + } +} + diff --git a/GUI/coregui/Views/FitWidgets/FittingWorker.h b/GUI/coregui/Views/FitWidgets/FittingWorker.h new file mode 100644 index 0000000000000000000000000000000000000000..a88f5b020970b8276d308502880295d47205ee47 --- /dev/null +++ b/GUI/coregui/Views/FitWidgets/FittingWorker.h @@ -0,0 +1,53 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Views/FitWidgets/FittingWorker.h +//! @brief Implements class FittingWorker +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2015 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke +// +// ************************************************************************** // + +#ifndef FITTINGWORKER_H +#define FITTINGWORKER_H + +#include "WinDllMacros.h" +#include <QObject> +#include <boost/shared_ptr.hpp> + +class FitSuite; + +class BA_CORE_API_ FittingWorker : public QObject +{ + Q_OBJECT + +public: + + FittingWorker(boost::shared_ptr<FitSuite> suite) {m_fitsuite = suite;} + +public slots: + + void startFit(); + + void interruptFitting(); + +signals: + + void started(); + + void finished(); + + void error(const QString &message); + +private: + + boost::shared_ptr<FitSuite> m_fitsuite; + +}; + +#endif diff --git a/GUI/coregui/Views/FitWidgets/GUIFitObserver.cpp b/GUI/coregui/Views/FitWidgets/GUIFitObserver.cpp new file mode 100644 index 0000000000000000000000000000000000000000..69c30e435443524dc74dc2643185b0b51983c609 --- /dev/null +++ b/GUI/coregui/Views/FitWidgets/GUIFitObserver.cpp @@ -0,0 +1,71 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Views/FitWidgets/FittingWorker.h +//! @brief Implements class FittingWorker +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2015 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke +// +// ************************************************************************** // + +#include "GUIFitObserver.h" +#include "FitSuite.h" +#include "IntensityDataItem.h" +#include <boost/scoped_ptr.hpp> + +void GUIFitObserver::update(FitSuite *subject) +{ + // discard data after interruption + if (subject->isInterrupted()) + return; + + // update log every time + std::stringstream buffer; + std::streambuf *old = std::cout.rdbuf(buffer.rdbuf()); + subject->getFitParameters()->printParameters(); + std::string text = buffer.str(); + std::cout.rdbuf(old); + + emit updateLog(QString("NCalls: %1 Chi: %2\n%3"). + arg(QString::number(subject->getNumberOfIterations()), + QString::number(subject->getChi2()), + QString::fromStdString(text))); + + if (subject->isLastIteration()) { + std::stringstream buffer; + std::streambuf *old = std::cout.rdbuf(buffer.rdbuf()); + subject->printResults(); + std::string text = buffer.str(); + emit updateLog(QString::fromStdString(text)); + std::cout.rdbuf(old); + } + + int curIteration = subject->getNumberOfIterations(); + + if (curIteration == 0) { + emit startFitting(subject->getRealOutputData()->clone()); + } + if (curIteration % m_update_interval == 0 && !m_block_update_plots) { + m_block_update_plots = true; + + emit updateStatus(QString("Iteration: %1").arg(subject->getNumberOfIterations())); + + emit updatePlots(subject->getSimulationOutputData()->clone(), + subject->getChiSquaredOutputData()->clone()); + } +} + +void GUIFitObserver::setInterval(int val) +{ + m_update_interval = val; +} + +void GUIFitObserver::finishedPlotting() +{ + m_block_update_plots = false; +} diff --git a/GUI/coregui/Views/FitWidgets/GUIFitObserver.h b/GUI/coregui/Views/FitWidgets/GUIFitObserver.h new file mode 100644 index 0000000000000000000000000000000000000000..af35a9f357118ef3fae18cd91103ef9ad405c91b --- /dev/null +++ b/GUI/coregui/Views/FitWidgets/GUIFitObserver.h @@ -0,0 +1,63 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Views/FitWidgets/FittingWorker.h +//! @brief Implements class FittingWorker +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2015 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke +// +// ************************************************************************** // + +#ifndef GUIFITOBSERVER_H +#define GUIFITOBSERVER_H + +#include "WinDllMacros.h" +#include "IFitObserver.h" +#include "OutputData.h" +#include <QObject> +#include <atomic> + +class FitSuite; +class IntensityDataItem; + +class BA_CORE_API_ GUIFitObserver : public QObject, public IFitObserver +{ + Q_OBJECT + +public: + + GUIFitObserver(QObject *parent = 0) + : QObject(parent) + , IFitObserver(1) + , m_update_interval(1) + {} + + void update(FitSuite *subject); + + void finishedPlotting(); + +public slots: + + void setInterval(int val); + +signals: + + void updateStatus(const QString &); + + void updatePlots(OutputData<double>*, OutputData<double>*); + + void updateLog(const QString &); + + void startFitting(OutputData<double>*); + +private: + std::atomic<bool> m_block_update_plots; + int m_update_interval; +}; + +#endif diff --git a/GUI/coregui/Views/FitWidgets/ImportDataWidget.cpp b/GUI/coregui/Views/FitWidgets/ImportDataWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f813fc48ddc2c35fe2635fb46974c2425b11c151 --- /dev/null +++ b/GUI/coregui/Views/FitWidgets/ImportDataWidget.cpp @@ -0,0 +1,61 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Views/FitWidgets/RunFitWidget.cpp +//! @brief Implements class RunFitWidget +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2015 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke +// +// ************************************************************************** // + +#include "ImportDataWidget.h" +#include "ColorMapPlot.h" +#include "IHistogram.h" +#include "IntensityDataIOFactory.h" +#include "IntensityDataItem.h" +#include "FitParameterItems.h" +#include "FitModel.h" +#include <QLineEdit> +#include <QVBoxLayout> + +ImportDataWidget::ImportDataWidget(FitModel *fitModel, QWidget *parent) + : QWidget(parent) + , m_line(new QLineEdit()) + , m_plot(new ColorMapPlot(this)) + , m_fitModel(fitModel) +{ + QVBoxLayout *mainLayout = new QVBoxLayout(); + mainLayout->addWidget(m_line); + mainLayout->addWidget(m_plot); + connect(m_line, SIGNAL(textChanged(QString)), this, SLOT(onTextUpdate())); + setLayout(mainLayout); +} + +void ImportDataWidget::onTextUpdate() { + QFileInfo chk(m_line->text()); + if (chk.exists() && chk.isFile()) { + try { + IHistogram *data = IntensityDataIOFactory::readIntensityData(m_line->text().toStdString()); + IntensityDataItem *item = new IntensityDataItem(); + item->setOutputData(data->createOutputData()); + m_plot->setItem(item); + m_fitModel->setInputDataPath(m_line->text()); + } catch (...) { } + } +} + +void ImportDataWidget::showEvent(QShowEvent *) +{ + onUpdateGUI(); +} + +void ImportDataWidget::onUpdateGUI() +{ + + m_line->setText(m_fitModel->getInputDataPath()); +} diff --git a/GUI/coregui/Views/FitWidgets/ImportDataWidget.h b/GUI/coregui/Views/FitWidgets/ImportDataWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..a2f76aaa8abd73cf62d0b3b40d5e7ce05b038045 --- /dev/null +++ b/GUI/coregui/Views/FitWidgets/ImportDataWidget.h @@ -0,0 +1,49 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Views/FitWidgets/RunFitWidget.h +//! @brief Defines class RunFitWidget +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2015 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke +// +// ************************************************************************** // + +#ifndef IMPORTDATAWIDGET_H +#define IMPORTDATAWIDGET_H + +#include "WinDllMacros.h" +#include <QWidget> + +class QLineEdit; +class ColorMapPlot; +class FitModel; + +class BA_CORE_API_ ImportDataWidget : public QWidget +{ + Q_OBJECT + +public: + //! TOY: loads file from path and plot data + ImportDataWidget(FitModel *fitModel, QWidget *parent = 0); + + void showEvent(QShowEvent *); + + +public slots: + //! when the text points to existing file, then plot file + void onTextUpdate(); + + void onUpdateGUI(); + +private: + QLineEdit *m_line; + ColorMapPlot *m_plot; + FitModel *m_fitModel; +}; + +#endif diff --git a/GUI/coregui/Views/FitWidgets/MinimizerSettingsWidget.cpp b/GUI/coregui/Views/FitWidgets/MinimizerSettingsWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2da6ee2d1d70a74e73f698c5cd0ab2be9accbdcc --- /dev/null +++ b/GUI/coregui/Views/FitWidgets/MinimizerSettingsWidget.cpp @@ -0,0 +1,31 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Views/FitWidgets/FitParameterWidget.cpp +//! @brief Implements class FitParameterWidget +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2015 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke +// +// ************************************************************************** // + +#include "MinimizerSettingsWidget.h" +#include "AwesomePropertyEditor.h" +#include "FitModel.h" +#include "FitParameterItems.h" +#include <QHBoxLayout> +#include <QSplitter> + +MinimizerSettingsWidget::MinimizerSettingsWidget(FitModel *fitModel, QWidget *parent) + : QWidget(parent) +{ + QHBoxLayout *layout = new QHBoxLayout; + AwesomePropertyEditor *editor = new AwesomePropertyEditor(this); + editor->setItem(fitModel->getMinimizerSettings()); + layout->addWidget(editor); + setLayout(layout); +} diff --git a/GUI/coregui/Views/FitWidgets/FitToolBar.h b/GUI/coregui/Views/FitWidgets/MinimizerSettingsWidget.h similarity index 63% rename from GUI/coregui/Views/FitWidgets/FitToolBar.h rename to GUI/coregui/Views/FitWidgets/MinimizerSettingsWidget.h index fe2e56a7ce25736cf7b04179a23cd0526b33f049..418256e78062e8cb63ca5a770c3ffa0c6a81d893 100644 --- a/GUI/coregui/Views/FitWidgets/FitToolBar.h +++ b/GUI/coregui/Views/FitWidgets/MinimizerSettingsWidget.h @@ -2,8 +2,8 @@ // // BornAgain: simulate and fit scattering at grazing incidence // -//! @file coregui/Views/FitWidgets/FitToolBar.h -//! @brief Defines class FitToolBar +//! @file coregui/Views/FitWidgets/FitParameterWidget.h +//! @brief Defines class FitParameterWidget //! //! @homepage http://www.bornagainproject.org //! @license GNU General Public License v3 or higher (see COPYING) @@ -13,25 +13,23 @@ // // ************************************************************************** // -#ifndef FITTOOLBAR_H -#define FITTOOLBAR_H +#ifndef MINIMIZERSETTTINGSWIDGET_H +#define MINIMIZERSETTTINGSWIDGET_H #include "WinDllMacros.h" -#include <QToolBar> +#include <QWidget> -class QAction; -class QToolButton; -class QToolBar; +class FitModel; - -class BA_CORE_API_ FitToolBar : public QToolBar +class BA_CORE_API_ MinimizerSettingsWidget : public QWidget { Q_OBJECT public: - explicit FitToolBar(QWidget *parent = 0); - + MinimizerSettingsWidget(FitModel *fitModel, QWidget *parent = 0); }; -#endif // SIMULATIONTOOLBAR_H + + +#endif diff --git a/GUI/coregui/Views/FitWidgets/RealDataWidget.cpp b/GUI/coregui/Views/FitWidgets/RealDataWidget.cpp deleted file mode 100644 index 93f4ab0e4ad3960a7e6b3f377be7138ac43c0bc1..0000000000000000000000000000000000000000 --- a/GUI/coregui/Views/FitWidgets/RealDataWidget.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// ************************************************************************** // -// -// BornAgain: simulate and fit scattering at grazing incidence -// -//! @file coregui/Views/FitWidgets/RealDataWidget.cpp -//! @brief Implements class RealDataWidget -//! -//! @homepage http://www.bornagainproject.org -//! @license GNU General Public License v3 or higher (see COPYING) -//! @copyright Forschungszentrum Jülich GmbH 2015 -//! @authors Scientific Computing Group at MLZ Garching -//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke -// -// ************************************************************************** // - -#include "RealDataWidget.h" -#include <QDebug> -#include <QVBoxLayout> - - - -RealDataWidget::RealDataWidget(QWidget *parent) - : QWidget(parent) -{ - - QColor bgColor(255,255,255,255); - QPalette palette; - palette.setColor(QPalette::Background, bgColor); - setAutoFillBackground(true); - setPalette(palette); - - - QVBoxLayout *vlayout = new QVBoxLayout(this); - vlayout->setMargin(0); - vlayout->setSpacing(0); - //vlayout->addWidget(m_treeView); - //vlayout->addStretch(); - this->setLayout(vlayout); - -} diff --git a/GUI/coregui/Views/FitWidgets/RunFitManager.cpp b/GUI/coregui/Views/FitWidgets/RunFitManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0af4fee77b5b8f164c58950a8524b24066cd781b --- /dev/null +++ b/GUI/coregui/Views/FitWidgets/RunFitManager.cpp @@ -0,0 +1,84 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Views/FitWidgets/RunFitManager.cpp +//! @brief Implements class RunFitManager +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2015 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke +// +// ************************************************************************** // + +#include "RunFitManager.h" +#include "FittingWorker.h" +#include "FitSuite.h" +#include <QThread> + +RunFitManager::RunFitManager(QObject *parent) + : QObject(parent) + , m_fitSuite(nullptr) + , m_is_fit_running{false} +{ +} + +void RunFitManager::setFitSuite(boost::shared_ptr<FitSuite> suite) +{ + m_fitSuite = suite; +} + +// start fitting in separate thread +void RunFitManager::runFitting() +{ + if (!m_fitSuite || m_is_fit_running) + return; + + QThread *thread = new QThread(); + FittingWorker *fw = new FittingWorker(m_fitSuite); + fw->moveToThread(thread); + + // start fitting when thread starts + connect(thread, SIGNAL(started()), fw, SLOT(startFit())); + connect(fw, SIGNAL(started()), this, SLOT(intern_workerStarted())); + + connect(this, SIGNAL(intern_interruptFittingWorker()), fw, SLOT(interruptFitting()), + Qt::DirectConnection); + + connect(fw, SIGNAL(error(QString)), this, SLOT(intern_error(QString))); + + connect(fw, SIGNAL(finished()), this, SLOT(intern_workerFinished())); + + // delete fitting worker and thread when done + connect(fw, SIGNAL(finished()), fw, SLOT(deleteLater())); + connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + + m_is_fit_running = true; + thread->start(); +} + +void RunFitManager::interruptFitting() +{ + if (m_is_fit_running) { + emit intern_interruptFittingWorker(); + } +} + +void RunFitManager::intern_workerFinished() +{ + m_is_fit_running = false; + m_fitSuite.reset(); + emit finishedFitting(); +} + +void RunFitManager::intern_workerStarted() +{ + emit startedFitting(); +} + +void RunFitManager::intern_error(const QString &mesg) +{ + emit error(mesg); +} diff --git a/GUI/coregui/Views/FitWidgets/RunFitManager.h b/GUI/coregui/Views/FitWidgets/RunFitManager.h new file mode 100644 index 0000000000000000000000000000000000000000..f602da4b6fc40f67b1bcdfce5696eb26b16640f5 --- /dev/null +++ b/GUI/coregui/Views/FitWidgets/RunFitManager.h @@ -0,0 +1,72 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Views/FitWidgets/RunFitManager.h +//! @brief Implements class RunFitManager +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2015 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke +// +// ************************************************************************** // + +#ifndef RUNFITMANAGER_H +#define RUNFITMANAGER_H + +#include "WinDllMacros.h" +#include <atomic> +#include <boost/shared_ptr.hpp> +#include <QObject> + +class FitSuite; + +class BA_CORE_API_ RunFitManager : public QObject +{ + Q_OBJECT + +public: + + RunFitManager(QObject *parent); + + void setFitSuite(boost::shared_ptr<FitSuite> suite); + + void runFitting(); + +public slots: + + void interruptFitting(); + +signals: + + void finishedFitting(); + + void startedFitting(); + + void error(const QString &message); + + +// only used by manager for communication with FittingWorker +private slots: + + void intern_workerFinished(); + + void intern_workerStarted(); + + void intern_error(const QString &mesg); + +signals: + + void intern_interruptFittingWorker(); + + +private: + + boost::shared_ptr<FitSuite> m_fitSuite; + std::atomic<bool> m_is_fit_running; + +}; + +#endif diff --git a/GUI/coregui/Views/FitWidgets/RunFitWidget.cpp b/GUI/coregui/Views/FitWidgets/RunFitWidget.cpp index 49687c66d6cb204c8da9f0112796a7aadd81f98b..56eea7ae427dd0938e1035145e772d600c754f26 100644 --- a/GUI/coregui/Views/FitWidgets/RunFitWidget.cpp +++ b/GUI/coregui/Views/FitWidgets/RunFitWidget.cpp @@ -14,27 +14,195 @@ // ************************************************************************** // #include "RunFitWidget.h" -#include <QDebug> +#include "RunFitManager.h" +#include "SampleBuilderFactory.h" +#include "SimulationRegistry.h" +#include "FitSuite.h" +#include "GUIFitObserver.h" +#include "FitProgressWidget.h" +#include "SampleModel.h" +#include "InstrumentModel.h" +#include "FitModel.h" +#include "DomainSimulationBuilder.h" +#include "FitParameterItems.h" +#include "ParameterizedItem.h" +#include "MultiLayerItem.h" +#include "InstrumentItem.h" +#include "SessionModel.h" +#include "IntensityDataIOFactory.h" +#include <QWidget> +#include <QPushButton> +#include <QSlider> +#include <QLabel> #include <QVBoxLayout> +#include <QHBoxLayout> +#include <QFileInfo> +#include <QDebug> + +RunFitWidget::RunFitWidget(FitModel *fitModel, QWidget *parent) + : QWidget(parent) + , m_start_button(new QPushButton()) + , m_stop_button(new QPushButton()) + , m_interval_label(new QLabel()) + , m_interval_slider(new QSlider()) + , m_runfitmanager(new RunFitManager(this)) + , m_fitprogress(new FitProgressWidget(this)) + , m_fitModel(fitModel) +{ + // setup ui + m_start_button->setText(tr("Start")); + m_stop_button->setText(tr("Stop")); + m_stop_button->setEnabled(false); + m_interval_slider->setOrientation(Qt::Horizontal); + m_interval_slider->setRange(1,20); + m_interval_slider->setMaximumWidth(150); + m_interval_slider->setMinimumWidth(150); + m_interval_slider->setFocusPolicy(Qt::NoFocus); + QVBoxLayout *mainLayout = new QVBoxLayout(); + QHBoxLayout *topLayout = new QHBoxLayout(); + topLayout->addWidget(m_start_button); + topLayout->addWidget(m_stop_button); + topLayout->addStretch(); + topLayout->addWidget(m_interval_label); + topLayout->addWidget(m_interval_slider); + QWidget *topWidget = new QWidget(); + topWidget->setLayout(topLayout); + mainLayout->addWidget(topWidget); + mainLayout->addWidget(m_fitprogress); + // connect everything + connect(m_start_button, SIGNAL(clicked()), this, SLOT(onStartClicked())); + connect(m_stop_button, SIGNAL(clicked()), this, SLOT(onStopClicked())); + connect(m_runfitmanager, SIGNAL(startedFitting()), this, SLOT(onFittingStarted())); + connect(m_runfitmanager, SIGNAL(finishedFitting()), this, SLOT(onFittingFinished())); + connect(m_runfitmanager, SIGNAL(error(QString)), m_fitprogress, SLOT(updateLog(QString))); -RunFitWidget::RunFitWidget(QWidget *parent) - : QWidget(parent) + connect(m_interval_slider, SIGNAL(valueChanged(int)), this, SLOT(onIntervalChanged(int))); + m_fitprogress->connectSlider(m_interval_slider); + + setLayout(mainLayout); + m_interval_slider->setValue(10); +} + +void RunFitWidget::onIntervalChanged(int value) +{ + m_interval_label->setText(QString("Update every %1th iteration").arg(value)); +} + +void RunFitWidget::onStartClicked() +{ + // used for test purposes + boost::shared_ptr<FitSuite> suite = init_test_fitsuite(); + m_fitprogress->setObserverToSuite(suite.get()); + + m_runfitmanager->setFitSuite(suite); + m_runfitmanager->runFitting(); +} + +void RunFitWidget::onStopClicked() +{ + m_runfitmanager->interruptFitting(); +} + +void RunFitWidget::onFittingStarted() +{ + m_start_button->setEnabled(false); + m_stop_button->setEnabled(true); +} + +void RunFitWidget::onFittingFinished() { + m_stop_button->setEnabled(false); + m_start_button->setEnabled(true); +} + + + +// test only +boost::shared_ptr<FitSuite> RunFitWidget::init_test_fitsuite() +{ + ParameterizedItem *multilayer = m_fitModel->getSelectedMultiLayerItem(); + ParameterizedItem *instrument = m_fitModel->getSelectedInstrumentItem(); + + DomainSimulationBuilder builder; + boost::shared_ptr<FitSuite> m_fitsuite = boost::shared_ptr<FitSuite>(new FitSuite()); + + try { + + boost::scoped_ptr<GISASSimulation> simulation(builder.getSimulation(dynamic_cast<MultiLayerItem*> + (multilayer), + dynamic_cast<InstrumentItem*> + (instrument))); + + + + QString path = m_fitModel->getInputDataPath(); + QFileInfo checkFile(path); + + OutputData<double> *data = 0; + + if (checkFile.exists() && checkFile.isFile()) { + data = IntensityDataIOFactory::readOutputData(path.toStdString()); + qDebug() << data->totalSum(); + //Q_ASSERT(0); + } else { + + simulation->runSimulation(); + data = simulation->getOutputData()->clone(); + } + + + + + + m_fitsuite->addSimulationAndRealData(*simulation.get(), *data); + + + ParameterizedItem *container = m_fitModel->getFitParameterContainer(); + - QColor bgColor(255,255,255,255); - QPalette palette; - palette.setColor(QPalette::Background, bgColor); - setAutoFillBackground(true); - setPalette(palette); + QModelIndex c_index = m_fitModel->indexOfItem(container); + for (int i = 0; i < m_fitModel->rowCount(c_index); i++) { + QModelIndex child = m_fitModel->index(i,0,c_index); + ParameterizedItem *parameter = m_fitModel->itemForIndex(child); + for (int j = 0; j < m_fitModel->rowCount(child); j++) { + ParameterizedItem *link = m_fitModel->itemForIndex(m_fitModel->index(j,0,child)); + QString value = link->getRegisteredProperty(FitParameterLinkItem::P_LINK).toString(); + value = value.replace("Position Offset/X", "PositionX"); + value = value.replace("Position Offset/Y", "PositionY"); + value = value.replace("Position Offset/Z", "PositionZ"); + value = value.replace("Rotation/ZRotation", "ZRotation"); + value = value.replace("Wavelength/DistributionNone/Value", "Wavelength"); + value = value.replace("Hurst parameter", "Hurst"); + value = value.replace("Lateral corr length", "CorrelationLength"); + value = value.replace(" ", ""); + std::string translated = "*" + value.toStdString(); + std::cout << translated; + std::cout.flush(); + double min = parameter->getRegisteredProperty(FitParameterItem::P_MIN).toDouble(); + double max = parameter->getRegisteredProperty(FitParameterItem::P_MAX).toDouble(); + double init = parameter->getRegisteredProperty(FitParameterItem::P_INIT).toDouble(); + AttLimits limits; + if (min==max && min < init) { + limits = AttLimits::lowerLimited(min); + } else if (min==max && max > init) { + limits = AttLimits::upperLimited(max); + } else if (min < init && max > init) { + limits = AttLimits::limited(min, max); + } else { + limits = AttLimits::limitless(); + } + m_fitsuite->addFitParameter(translated, init, limits); + } + } - QVBoxLayout *vlayout = new QVBoxLayout(this); - vlayout->setMargin(0); - vlayout->setSpacing(0); - //vlayout->addWidget(m_treeView); - //vlayout->addStretch(); - this->setLayout(vlayout); + m_fitsuite->setMinimizer("Minuit2", m_fitModel->getMinimizerAlgorithm().toStdString()); +} catch(const std::exception& ex) { + QString message = QString::fromLatin1(ex.what()); + m_fitprogress->updateLog(message); + } + return m_fitsuite; } diff --git a/GUI/coregui/Views/FitWidgets/RunFitWidget.h b/GUI/coregui/Views/FitWidgets/RunFitWidget.h index 730654046c53930db612fcc03791df6f43f35a42..00e4aae9505e6e28b15b1a4aa00e3e3a3c10733a 100644 --- a/GUI/coregui/Views/FitWidgets/RunFitWidget.h +++ b/GUI/coregui/Views/FitWidgets/RunFitWidget.h @@ -16,15 +16,56 @@ #ifndef RUNFITWIDGET_H #define RUNFITWIDGET_H +#include "WinDllMacros.h" #include <QWidget> +#include <boost/shared_ptr.hpp> +class QSlider; +class QLabel; +class QPushButton; +class RunFitManager; +class FitSuite; +class FitProgressWidget; +class FitModel; +class SampleModel; +class InstrumentModel; +class ParameterizedItem; +class SessionModel; class BA_CORE_API_ RunFitWidget : public QWidget { Q_OBJECT public: - RunFitWidget(QWidget *parent = 0); + + RunFitWidget(FitModel *fitModel, QWidget *parent = 0); + + // test only + boost::shared_ptr<FitSuite> init_test_fitsuite(); + +public slots: + + void onIntervalChanged(int value); + + void onStartClicked(); + + void onStopClicked(); + + void onFittingStarted(); + + void onFittingFinished(); + +private: + + QPushButton *m_start_button; + QPushButton *m_stop_button; + QLabel *m_interval_label; + QSlider *m_interval_slider; + RunFitManager *m_runfitmanager; + FitProgressWidget *m_fitprogress; + FitModel *m_fitModel; + + ParameterizedItem *getTopItemFromSelection(SessionModel *model, const QString &itemType, const QString &selectionType); }; #endif diff --git a/GUI/coregui/Views/TestView.cpp b/GUI/coregui/Views/TestView.cpp index d2a5a3e524c3acf9d699cc108a6c786941452c64..f839ed73407cec1b9f6b5f8717417e947d398bb2 100644 --- a/GUI/coregui/Views/TestView.cpp +++ b/GUI/coregui/Views/TestView.cpp @@ -14,23 +14,56 @@ // ************************************************************************** // #include "TestView.h" #include "MaskEditor.h" +#include "RunFitWidget.h" +#include "FitView.h" +#include "mainwindow.h" +#include "FitParameterWidget.h" +#include "JobModel.h" +#include <QMimeData> #include <QVBoxLayout> #include <AccordionWidget.h> #include <QLineEdit> #include <QCheckBox> +#include <QTabWidget> -TestView::TestView(QWidget *parent) + + +// FIXME_DAVID Rename Ivona's FitView into ObsoleteFitView. And use nice name FitView for own purpose. +// -- suggestion: for consistency use prefix Obsolete for all classes you are goind to throw soon +// -- you may want to add to all Ivona's classes prefix Obsolete. Don't forget about 'ifndef' header guards + +// FIXME_DAVID Move your activity from TestView to FitView. +// - FitView should contain QTabWidget with 3 tabs: +// - 1) ImportDataWidget (empty for the moment) 2) FitSettingsWidget 3) RunFitWidget + +// FIXME_DAVID FitSettingsWidget should contain +// - FitParametersWidget (for the moment), and later sample/instrument selector + MinimizerSettingsWidgert + + +TestView::TestView(MainWindow *window, QWidget *parent) : QWidget(parent) + , m_mainWindow(window) { -// MaskEditor *maskEditor = new MaskEditor(); -// QVBoxLayout *layout = new QVBoxLayout; -// layout->setMargin(0); -// layout->setSpacing(0); -// layout->addWidget(maskEditor); -// setLayout(layout); +// test_MaskEditor(); +// test_AccordionWidget(); + test_RunFitWidget(); -// maskEditor->init_test_model(); +} + +void TestView::test_MaskEditor() +{ + MaskEditor *maskEditor = new MaskEditor(); + QVBoxLayout *layout = new QVBoxLayout; + layout->setMargin(0); + layout->setSpacing(0); + layout->addWidget(maskEditor); + setLayout(layout); + maskEditor->init_test_model(); +} + +void TestView::test_AccordionWidget() +{ AccordionWidget *myAccordion = new AccordionWidget(); myAccordion->setMultiActive(true); // add the Accordion to your layout @@ -101,5 +134,24 @@ TestView::TestView(QWidget *parent) contentFrame->layout()->addWidget(cb7); } +} + +void TestView::test_RunFitWidget() +{ + // FIXME_DAVID Use consistent variable names: not 'maskEditor', but runFitWidget + + //RunFitWidget *maskEditor = new RunFitWidget(); + //FitView *fw = new FitView(m_mainWindow->getSampleModel(), m_mainWindow->getInstrumentModel()); + + //FitParameterWidget *fitting = new FitParameterWidget(m_mainWindow); + QVBoxLayout *layout = new QVBoxLayout; + QTabWidget *tabs = new QTabWidget; + //tabs->addTab(maskEditor, "Run Fit"); + //tabs->addTab(fw, "FitView by Ivonna"); + //tabs->addTab(fitting, "Test TreeView"); + layout->setMargin(0); + layout->setSpacing(0); + layout->addWidget(tabs); + setLayout(layout); } diff --git a/GUI/coregui/Views/TestView.h b/GUI/coregui/Views/TestView.h index 562ac072a9c97006f9c9f59218293592f58d95f0..eebc37c0dc61df4fe365cfb6a8db7bae6175a02c 100644 --- a/GUI/coregui/Views/TestView.h +++ b/GUI/coregui/Views/TestView.h @@ -18,12 +18,19 @@ #include <QWidget> +class MainWindow; + class TestView : public QWidget { Q_OBJECT public: - TestView(QWidget *parent = 0); + TestView(MainWindow *window, QWidget *parent = 0); +private: + void test_MaskEditor(); + void test_AccordionWidget(); + void test_RunFitWidget(); + MainWindow *m_mainWindow; }; #endif diff --git a/GUI/coregui/mainwindow/UpdateNotifier.cpp b/GUI/coregui/mainwindow/UpdateNotifier.cpp index 896d57d1959648bccd497e173029af117703335b..ada6ad2554419af207ad2e8d39d9627b0a2eaf0e 100644 --- a/GUI/coregui/mainwindow/UpdateNotifier.cpp +++ b/GUI/coregui/mainwindow/UpdateNotifier.cpp @@ -15,19 +15,15 @@ #include "UpdateNotifier.h" #include "mainwindow_constants.h" +#include "GUIHelpers.h" #include <QtNetwork> -#include <GUIHelpers.h> #include <QMessageBox> - UpdateNotifier::UpdateNotifier(QObject *parent) - : QObject(parent) - , m_networkAccessManager(new QNetworkAccessManager(parent)) + : QObject(parent), m_networkAccessManager(new QNetworkAccessManager(parent)) { - connect(m_networkAccessManager, - SIGNAL(finished(QNetworkReply*)), - this, - SLOT(replyFinished(QNetworkReply*))); + connect(m_networkAccessManager, SIGNAL(finished(QNetworkReply *)), this, + SLOT(replyFinished(QNetworkReply *))); } void UpdateNotifier::checkForUpdates() @@ -37,8 +33,7 @@ void UpdateNotifier::checkForUpdates() settings.beginGroup(Constants::S_UPDATES); if (settings.value(Constants::S_CHECKFORUPDATES).toBool()) { m_networkAccessManager->get(QNetworkRequest(QUrl(Constants::S_VERSION_URL))); - } - else + } else emit onUpdateNotification(QString("")); } } @@ -46,11 +41,9 @@ void UpdateNotifier::checkForUpdates() void UpdateNotifier::replyFinished(QNetworkReply *reply) { QString replyString; - if(reply->error() == QNetworkReply::NoError) - { - if (reply->isReadable()) - { - //Reading the first line of ChangeLog + if (reply->error() == QNetworkReply::NoError) { + if (reply->isReadable()) { + // Reading the first line of ChangeLog replyString = QString::fromUtf8(reply->readLine().data()); int versionIndex = replyString.indexOf("-") + 1; int versionIndexEnd = replyString.indexOf(",", versionIndex); @@ -58,7 +51,7 @@ void UpdateNotifier::replyFinished(QNetworkReply *reply) QString myVersion = GUIHelpers::getBornAgainVersionString(); // Testwise degrade version - //QString myVersion = QString("1.3.0"); + // QString myVersion = QString("1.3.0"); int compareResult = versionString.compare(myVersion); if (compareResult > 0) { diff --git a/GUI/coregui/mainwindow/UpdateNotifier.h b/GUI/coregui/mainwindow/UpdateNotifier.h index 05511755f2d536cfc5c3f352bb8716a3b0d4039c..fdb505ec0b254209fa854c4e8134b9f5c362b014 100644 --- a/GUI/coregui/mainwindow/UpdateNotifier.h +++ b/GUI/coregui/mainwindow/UpdateNotifier.h @@ -16,8 +16,8 @@ #ifndef UPDATENOTIFIER_H #define UPDATENOTIFIER_H -#include <QObject> #include "WinDllMacros.h" +#include <QObject> class QNetworkAccessManager; class QNetworkReply; diff --git a/GUI/coregui/mainwindow/mainwindow.cpp b/GUI/coregui/mainwindow/mainwindow.cpp index d5d871976575b8c531abeafa544269c8e6246ee8..5e58dca33cb064906d34fe76aae893b806af85fd 100644 --- a/GUI/coregui/mainwindow/mainwindow.cpp +++ b/GUI/coregui/mainwindow/mainwindow.cpp @@ -56,12 +56,12 @@ #include "SampleModel.h" #include "JobView.h" #include "aboutapplicationdialog.h" -#include "FitModel.h" -#include "FitProxyModel.h" #include "FitView.h" #include "TestView.h" #include "GUIHelpers.h" #include "UpdateNotifier.h" +#include "FitModel.h" +#include "FitParameterItems.h" #include <boost/scoped_ptr.hpp> @@ -89,9 +89,9 @@ MainWindow::MainWindow(QWidget *parent) , m_sampleModel(0) , m_instrumentModel(0) , m_materialModel(0) + , m_fitModel(0) , m_materialEditor(0) , m_toolTipDataBase(new ToolTipDataBase(this)) - , m_fitProxyModel(0) , m_updateNotifier(new UpdateNotifier(this)) { QCoreApplication::setApplicationName(QLatin1String(Constants::APPLICATION_NAME)); @@ -124,21 +124,15 @@ MainWindow::MainWindow(QWidget *parent) m_sampleView = new SampleView(m_sampleModel, m_instrumentModel); m_simulationView = new SimulationView(this); -// TestView *testView = new TestView(this); - //m_fitView = new FitView(m_fitProxyModel, this); - m_jobView = new JobView(m_jobModel, m_projectManager); - + //m_fitView = new FitView(this); m_tabWidget->insertTab(WELCOME, m_welcomeView, QIcon(":/images/main_home.png"), "Welcome"); m_tabWidget->insertTab(INSTRUMENT, m_instrumentView, QIcon(":/images/main_instrument.png"), "Instrument"); m_tabWidget->insertTab(SAMPLE, m_sampleView, QIcon(":/images/main_sample.png"), "Sample"); - //m_tabWidget->insertTab(3, m_scriptView, QIcon(":/images/mode_script.png"), "Python scripts"); m_tabWidget->insertTab(SIMULATION, m_simulationView, QIcon(":/images/main_simulation.png"), "Simulation"); m_tabWidget->insertTab(JOB, m_jobView, QIcon(":/images/main_jobqueue.png"), "Jobs"); -// m_tabWidget->insertTab(TEST_VIEW, testView, QIcon(":/images/main_simulation.png"), "Test"); - //m_tabWidget->insertTab(FitViewTab, m_fitView, QIcon(":/images/main_simulation.png"), "Fit"); - //m_tabWidget->insertTab(FIT_VIEW, new TestView(this), QIcon(":/images/main_simulation.png"), "Test"); + //m_tabWidget->insertTab(FIT, m_fitView, QIcon(":/images/main_jobqueue.png"), "Fit"); m_tabWidget->setCurrentIndex(WELCOME); @@ -158,9 +152,6 @@ MainWindow::MainWindow(QWidget *parent) m_welcomeView, SLOT(setNotificationText(const QString &))); m_projectManager->createNewProject(); - -// testGUIObjectBuilder(); - } MainWindow::~MainWindow() @@ -302,7 +293,8 @@ void MainWindow::createInstrumentModel() void MainWindow::createFitModel() { - m_fitProxyModel = new FitProxyModel; + delete m_fitModel; + m_fitModel = new FitModel(m_sampleModel, m_instrumentModel, this); } //! reset all models to initial state @@ -323,6 +315,15 @@ void MainWindow::resetModels() instrument->setItemName("Default GISAS"); m_instrumentModel->insertNewItem(Constants::DetectorType, m_instrumentModel->indexOfItem(instrument)); m_instrumentModel->insertNewItem(Constants::BeamType, m_instrumentModel->indexOfItem(instrument)); + + /*m_fitModel->clear(); + m_fitModel->insertNewItem(Constants::FitParameterContainerType, QModelIndex()); + ParameterizedItem *selection = m_fitModel->insertNewItem(Constants::FitSelectionType, QModelIndex()); + selection->setRegisteredProperty(FitSelectionItem::P_SAMPLE, "MultiLayer"); + selection->setRegisteredProperty(FitSelectionItem::P_INSTRUMENT, "Instrument0"); + m_fitModel->insertNewItem(Constants::MinimizerSettingsType, QModelIndex()); + m_fitModel->insertNewItem(Constants::InputDataType, QModelIndex());*/ + } void MainWindow::testGUIObjectBuilder() diff --git a/GUI/coregui/mainwindow/mainwindow.h b/GUI/coregui/mainwindow/mainwindow.h index bdc0bcd58d420a95b65f68a8b365ea6ff6de80a5..cfdbf9044f19a27f3aaf5e5550f4bd6e7bf6148d 100644 --- a/GUI/coregui/mainwindow/mainwindow.h +++ b/GUI/coregui/mainwindow/mainwindow.h @@ -43,18 +43,17 @@ class MaterialEditor; class ToolTipDataBase; class MaterialModel; class SampleModel; -class FitProxyModel; class FitView; class JobModel; class UpdateNotifier; - +class FitModel; class BA_CORE_API_ MainWindow : public Manhattan::FancyMainWindow { Q_OBJECT public: - enum ETabViewId { WELCOME, INSTRUMENT, SAMPLE, SIMULATION, JOB, TEST_VIEW}; + enum ETabViewId { WELCOME, INSTRUMENT, SAMPLE, SIMULATION, JOB, FIT}; explicit MainWindow(QWidget *parent = 0); virtual ~MainWindow(); @@ -63,6 +62,7 @@ public: InstrumentModel *getInstrumentModel() { return m_instrumentModel; } SampleModel *getSampleModel() { return m_sampleModel; } JobModel *getJobModel() { return m_jobModel; } + FitModel *getFitModel() { return m_fitModel; } Manhattan::ProgressBar *getProgressBar() { return m_progressBar; } ActionManager *getActionManager() { return m_actionManager; } ProjectManager *getProjectManager() { return m_projectManager; } @@ -100,9 +100,9 @@ private: SampleModel *m_sampleModel; //!< model for all samples InstrumentModel *m_instrumentModel; //!< model for all instruments MaterialModel *m_materialModel; //!< model for all materials + FitModel *m_fitModel; //!< model for fitting MaterialEditor *m_materialEditor; ToolTipDataBase *m_toolTipDataBase; - FitProxyModel *m_fitProxyModel; UpdateNotifier *m_updateNotifier; void createModels(); diff --git a/GUI/coregui/mainwindow/projectdocument.cpp b/GUI/coregui/mainwindow/projectdocument.cpp index 861683781388b08f2349470aed709f8964d648b3..e56cd02e0c5e4e474081dca90a592193eece93a6 100644 --- a/GUI/coregui/mainwindow/projectdocument.cpp +++ b/GUI/coregui/mainwindow/projectdocument.cpp @@ -18,6 +18,7 @@ #include "InstrumentModel.h" #include "JobQueueData.h" #include "JobModel.h" +#include "FitModel.h" #include "JobItem.h" #include "IntensityDataItem.h" #include "SampleModel.h" @@ -43,7 +44,7 @@ const QString XML_FORMAT_ERROR = "XML_FORMAT_ERROR"; } ProjectDocument::ProjectDocument() - : m_materialModel(0), m_instrumentModel(0), m_sampleModel(0), m_jobModel(0) + : m_materialModel(0), m_instrumentModel(0), m_sampleModel(0), m_jobModel(0), m_fitModel(0) , m_modified(false), m_documentStatus(STATUS_OK), m_messageService(0) { setObjectName("ProjectDocument"); @@ -132,6 +133,15 @@ void ProjectDocument::setJobModel(JobModel *jobModel) } } +void ProjectDocument::setFitModel(FitModel *fitModel) +{ + if (fitModel != m_fitModel) { + disconnectModel(m_fitModel); + m_fitModel = fitModel; + connectModel(m_fitModel); + } +} + bool ProjectDocument::save() { reviseOutputData(); @@ -251,6 +261,7 @@ void ProjectDocument::readFrom(QIODevice *device) disconnectModel(m_instrumentModel); disconnectModel(m_sampleModel); disconnectModel(m_jobModel); + //disconnectModel(m_fitModel); QXmlStreamReader reader(device); @@ -274,8 +285,9 @@ void ProjectDocument::readFrom(QIODevice *device) } else if (reader.name() == SessionXML::JobModelTag) { readModel(m_jobModel, &reader); - - } + } /*else if (reader.name() == SessionXML::FitModelTag) { + readModel(m_fitModel, &reader); + }*/ } } @@ -289,6 +301,7 @@ void ProjectDocument::readFrom(QIODevice *device) connectModel(m_instrumentModel); connectModel(m_sampleModel); connectModel(m_jobModel); + //connectModel(m_fitModel); } void ProjectDocument::writeTo(QIODevice *device) @@ -308,6 +321,7 @@ void ProjectDocument::writeTo(QIODevice *device) m_instrumentModel->writeTo(&writer); m_sampleModel->writeTo(&writer); m_jobModel->writeTo(&writer); + //m_fitModel->writeTo(&writer); writer.writeEndElement(); // BornAgain tag writer.writeEndDocument(); diff --git a/GUI/coregui/mainwindow/projectdocument.h b/GUI/coregui/mainwindow/projectdocument.h index 8ad115f8e0a20a0e6026c5d95a765bec60c3e9b9..7d138c4e5bf402373a2ef3268ab8039412b6074b 100644 --- a/GUI/coregui/mainwindow/projectdocument.h +++ b/GUI/coregui/mainwindow/projectdocument.h @@ -28,6 +28,7 @@ class InstrumentModel; class MaterialModel; class SampleModel; class JobModel; +class FitModel; class QXmlStreamReader; class WarningMessageService; @@ -76,6 +77,7 @@ public: void setInstrumentModel(InstrumentModel *instrumentModel); void setSampleModel(SampleModel *sampleModel); void setJobModel(JobModel *jobModel); + void setFitModel(FitModel *fitModel); bool save(); bool load(const QString &project_file_name); @@ -122,6 +124,7 @@ private: InstrumentModel *m_instrumentModel; SampleModel *m_sampleModel; JobModel *m_jobModel; + FitModel *m_fitModel; bool m_modified; EDocumentStatus m_documentStatus; WarningMessageService *m_messageService; diff --git a/GUI/coregui/mainwindow/projectmanager.cpp b/GUI/coregui/mainwindow/projectmanager.cpp index d154262e814179ae92af1c737e9a89a3fc5ee7b6..38d32bbc8847508a8e585ed0b5a9296667ff2571 100644 --- a/GUI/coregui/mainwindow/projectmanager.cpp +++ b/GUI/coregui/mainwindow/projectmanager.cpp @@ -97,6 +97,7 @@ void ProjectManager::createNewProject() m_project_document->setInstrumentModel(m_mainWindow->getInstrumentModel()); m_project_document->setSampleModel(m_mainWindow->getSampleModel()); m_project_document->setJobModel(m_mainWindow->getJobModel()); + m_project_document->setFitModel(m_mainWindow->getFitModel()); m_project_document->setMessageService(m_messageService); } @@ -208,6 +209,7 @@ void ProjectManager::openProject(QString fileName) addToRecentProjects(); } + emit projectOpened(); emit modified(); } diff --git a/GUI/coregui/mainwindow/projectmanager.h b/GUI/coregui/mainwindow/projectmanager.h index 4c74dd25348268a9aaa10c4ccc0229b1f1b5c03a..c521b6cf9a2440e39badd34732a29aac9371b5d5 100644 --- a/GUI/coregui/mainwindow/projectmanager.h +++ b/GUI/coregui/mainwindow/projectmanager.h @@ -46,6 +46,7 @@ public: signals: void modified(); + void projectOpened(); public slots: void clearRecentProjects(); diff --git a/GUI/coregui/utils/DeleteEventFilter.cpp b/GUI/coregui/utils/DeleteEventFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f351c9aa06ed52c64f2ff7fcf43f2460a2cb97d0 --- /dev/null +++ b/GUI/coregui/utils/DeleteEventFilter.cpp @@ -0,0 +1,31 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/utils/CustomEventFilters.cpp +//! @brief Defines classes releted to event filtering +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2015 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke +// +// ************************************************************************** // + +#include "DeleteEventFilter.h" +#include <QEvent> +#include <QKeyEvent> + +bool DeleteEventFilter::eventFilter( QObject *dist, QEvent *event ) +{ + Q_UNUSED(dist); + if( event->type() == QEvent::KeyPress ) + { + QKeyEvent *keyEvent = static_cast<QKeyEvent*>( event ); + if( keyEvent->key() == Qt::Key_Delete ) { + emit removeItem(); + } + } + return QObject::eventFilter(dist, event); +} diff --git a/GUI/coregui/utils/DeleteEventFilter.h b/GUI/coregui/utils/DeleteEventFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..a2941592e5ec1ef9ffe20de4155063fc449c7310 --- /dev/null +++ b/GUI/coregui/utils/DeleteEventFilter.h @@ -0,0 +1,39 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/utils/CustomEventFilters.h +//! @brief Defines classes releted to event filtering +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2015 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke +// +// ************************************************************************** // + +#ifndef DELETEEVENTFILTERS_H +#define DELETEEVENTFILTERS_H + +#include "WinDllMacros.h" +#include <QObject> + +class QEvent; + +//! Filter out space bar key events, which is special case for dialog windows + +class DeleteEventFilter : public QObject +{ + Q_OBJECT +public: + DeleteEventFilter( QObject *parent = 0 ) : QObject( parent ) {} + +protected: + bool eventFilter( QObject *dist, QEvent *event ); + +signals: + void removeItem(); +}; + +#endif diff --git a/GUI/coregui/utils/ItemIDFactory.cpp b/GUI/coregui/utils/ItemIDFactory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..81fecfeaf655f666f80945df4f0320d4d4e4da24 --- /dev/null +++ b/GUI/coregui/utils/ItemIDFactory.cpp @@ -0,0 +1,46 @@ +#include "ItemIDFactory.h" + + +ItemIDFactory& ItemIDFactory::instance() +{ + static ItemIDFactory instance; + return instance; +} + +QString ItemIDFactory::createID(ParameterizedItem *toBeInsertedItem){ + + QUuid id = QUuid::createUuid(); + QString id_String = id.toString(); + + // prevent duplicates (very improbable that this ever happens though) + while(instance().IDtoItemMap.contains(id_String)) { + id = QUuid::createUuid(); + id_String = id.toString(); + } + instance().ItemtoIDMap.insert(toBeInsertedItem, id_String); + instance().IDtoItemMap.insert(id_String, toBeInsertedItem); + + return id_String; +} + +QString ItemIDFactory::getID(ParameterizedItem *existingItem) +{ + if(instance().ItemtoIDMap.contains(existingItem)) + return instance().ItemtoIDMap.value(existingItem); + else + return QString(); +} + +ParameterizedItem* ItemIDFactory::getItem(QString existingID) +{ + if(instance().IDtoItemMap.contains(existingID)) + return instance().IDtoItemMap.value(existingID); + else + return nullptr; +} + +int ItemIDFactory::IDSize() +{ + static QUuid id = QUuid::createUuid(); + return id.toString().size(); +} diff --git a/GUI/coregui/utils/ItemIDFactory.h b/GUI/coregui/utils/ItemIDFactory.h new file mode 100644 index 0000000000000000000000000000000000000000..f259fbe48e0feb21b232c604b49215615b498091 --- /dev/null +++ b/GUI/coregui/utils/ItemIDFactory.h @@ -0,0 +1,48 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Util/ItemIDFactory.h +//! @brief Defines class ItemIDFactory +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2015 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke +// +// ************************************************************************** // +#ifndef ItemIDFactory_H +#define ItemIDFactory_H + +#include <QUuid> +#include <QMap> + +class ParameterizedItem; + +class ItemIDFactory { +public: + // delete copy/move constructor/assignment: + ItemIDFactory(const ItemIDFactory&) = delete; + ItemIDFactory(ItemIDFactory&&) = delete; + ItemIDFactory& operator=(const ItemIDFactory&) = delete; + ItemIDFactory& operator=(ItemIDFactory&&) = delete; + + static ItemIDFactory& instance(); + + static QString createID(ParameterizedItem* toBeInsertedItem); + + static QString getID(ParameterizedItem* existingItem); + + static ParameterizedItem* getItem(QString existingID); + + static int IDSize(); + +private: + ItemIDFactory() = default; + + QMap<QString, ParameterizedItem*> IDtoItemMap; + QMap<ParameterizedItem*, QString> ItemtoIDMap; +}; + +#endif