// ************************************************************************************************ // // BornAgain: simulate and fit reflection and scattering // //! @file GUI/View/FitObjective/ParameterTuningWidget.cpp //! @brief Implements class ParameterTuningWidget //! //! @homepage http://www.bornagainproject.org //! @license GNU General Public License v3 or higher (see COPYING) //! @copyright Forschungszentrum Jülich GmbH 2018 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS) // // ************************************************************************************************ #include "GUI/View/FitObjective/ParameterTuningWidget.h" #include "Base/Util/Assert.h" #include "GUI/Model/Data/IntensityDataItem.h" #include "GUI/Model/Job/ParameterTreeItems.h" #include "GUI/Model/Model/ParameterTuningModel.h" #include "GUI/Model/Project/ProjectDocument.h" #include "GUI/View/FitObjective/ParameterTuningDelegate.h" #include "GUI/View/FitObjective/SliderSettingsWidget.h" #include "GUI/View/Info/CautionSign.h" #include "GUI/View/Widget/StyledToolbar.h" #include <QAction> #include <QTreeView> #include <QVBoxLayout> ParameterTuningWidget::ParameterTuningWidget(QWidget* parent) : DataAccessWidget(parent) , m_jobModel(nullptr) , m_parameterTuningModel(nullptr) , m_sliderSettingsWidget(new SliderSettingsWidget(this)) , m_treeView(new QTreeView) , m_delegate(new ParameterTuningDelegate(this)) , m_cautionSign(new CautionSign(m_treeView)) { setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_treeView->setItemDelegate(m_delegate); m_treeView->setContextMenuPolicy(Qt::CustomContextMenu); m_treeView->setDragDropMode(QAbstractItemView::NoDragDrop); m_treeView->setAttribute(Qt::WA_MacShowFocusRect, false); auto* resetValuesAction = new QAction(QIcon(":/images/undo-variant.svg"), "Reset values", this); resetValuesAction->setToolTip("Reset parameter tree to initial values"); connect(resetValuesAction, &QAction::triggered, this, &ParameterTuningWidget::restoreModelsOfCurrentJobItem); auto* toolbar = new StyledToolbar(this); toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); toolbar->addAction(resetValuesAction); auto* mainLayout = new QVBoxLayout; mainLayout->setContentsMargins(0, 0, 0, 0); mainLayout->setSpacing(0); mainLayout->addWidget(toolbar); mainLayout->addWidget(m_sliderSettingsWidget); mainLayout->addWidget(m_treeView); setLayout(mainLayout); connect(m_sliderSettingsWidget, &SliderSettingsWidget::sliderRangeFactorChanged, this, &ParameterTuningWidget::onSliderRangeChanged); connect(m_sliderSettingsWidget, &SliderSettingsWidget::lockzChanged, this, &ParameterTuningWidget::onLockZValueChanged); connect(m_delegate, &ParameterTuningDelegate::currentLinkChanged, this, &ParameterTuningWidget::onCurrentLinkChanged); connect(m_treeView, &QTreeView::customContextMenuRequested, this, &ParameterTuningWidget::onCustomContextMenuRequested); } void ParameterTuningWidget::setJobOrRealItem(QObject* job_item) { DataAccessWidget::setJobOrRealItem(job_item); m_sliderSettingsWidget->setJobOrRealItem(job_item); updateParameterModel(); updateDragAndDropSettings(); connect(jobItem(), &JobItem::jobStatusChanged, this, [this](const JobStatus) { updateJobStatus(); }); updateJobStatus(); } void ParameterTuningWidget::setModel(QObject* jobModel) { m_jobModel = dynamic_cast<JobModel*>(jobModel); ASSERT(m_jobModel); } QItemSelectionModel* ParameterTuningWidget::selectionModel() { ASSERT(m_treeView); return m_treeView->selectionModel(); } //! Returns list of ParameterItem's currently selected in parameter tree QVector<ParameterItem*> ParameterTuningWidget::selectedParameterItems() { QVector<ParameterItem*> result; for (auto index : selectionModel()->selectedIndexes()) if (ParameterItem* parItem = m_parameterTuningModel->getParameterItem(index)) result.push_back(parItem); return result; } void ParameterTuningWidget::onCurrentLinkChanged(ParameterItem* item) { ASSERT(jobItem()); if (jobItem()->isRunning()) return; if (item) m_jobModel->runJob(jobItem()); } void ParameterTuningWidget::onSliderRangeChanged(int value) { m_delegate->setSliderRangeFactor(value); } void ParameterTuningWidget::onLockZValueChanged(bool value) { if (!jobItem()) return; if (IntensityDataItem* intensityDataItem = jobItem()->intensityDataItem()) intensityDataItem->setZaxisLocked(value); } void ParameterTuningWidget::updateParameterModel() { ASSERT(m_jobModel); if (!jobItem()) return; if (!jobItem()->sampleItem() || !jobItem()->instrumentItem()) throw std::runtime_error("JobItem is missing sample or instrument model"); delete m_parameterTuningModel; m_parameterTuningModel = new ParameterTuningModel(jobItem()->parameterContainerItem()->parameterTreeRoot(), this); m_treeView->setModel(m_parameterTuningModel); if (m_treeView->columnWidth(0) < 170) m_treeView->setColumnWidth(0, 170); m_treeView->expandAll(); } void ParameterTuningWidget::onCustomContextMenuRequested(const QPoint& point) { emit itemContextMenuRequest(m_treeView->mapToGlobal(point + QPoint(2, 22))); } void ParameterTuningWidget::restoreModelsOfCurrentJobItem() { ASSERT(m_jobModel); ASSERT(jobItem()); if (jobItem()->isRunning()) return; closeActiveEditors(); m_jobModel->restore(jobItem()); m_jobModel->runJob(jobItem()); gProjectDocument.value()->setModified(); } void ParameterTuningWidget::makeSelected(ParameterItem* item) { QModelIndex index = m_parameterTuningModel->indexForItem(item); if (index.isValid()) selectionModel()->select(index, QItemSelectionModel::Select); } void ParameterTuningWidget::contextMenuEvent(QContextMenuEvent*) { // reimplemented to suppress context menu from QMainWindow } //! Disable drag-and-drop abilities, if job is in fit running state. void ParameterTuningWidget::updateDragAndDropSettings() { ASSERT(jobItem()); if (jobItem()->status() == JobStatus::Fitting) { setTuningDelegateEnabled(false); m_treeView->setDragDropMode(QAbstractItemView::NoDragDrop); } else { setTuningDelegateEnabled(true); if (jobItem()->isValidForFitting()) m_treeView->setDragDropMode(QAbstractItemView::DragOnly); } } //! Sets delegate to enabled/disabled state. //! In 'disabled' state the delegate is in ReadOnlyMode, if it was containing already some //! editing widget, it will be forced to close. void ParameterTuningWidget::setTuningDelegateEnabled(bool enabled) { if (enabled) m_delegate->setReadOnly(false); else { m_delegate->setReadOnly(true); closeActiveEditors(); } } void ParameterTuningWidget::closeActiveEditors() { QModelIndex index = m_treeView->currentIndex(); QWidget* editor = m_treeView->indexWidget(index); if (editor) { // m_delegate->commitData(editor); m_delegate->closeEditor(editor, QAbstractItemDelegate::NoHint); } m_treeView->selectionModel()->clearSelection(); } void ParameterTuningWidget::updateJobStatus() { m_cautionSign->clear(); if (jobItem()->isFailed()) { QString message; message.append("Current parameter values cause simulation failure.\n\n"); message.append(jobItem()->comments()); m_cautionSign->setCautionMessage(message); } updateDragAndDropSettings(); }