diff --git a/GUI/coregui/Models/ApplicationModels.cpp b/GUI/coregui/Models/ApplicationModels.cpp index 2761f266e0ae55a08b2ae691453f2abf14d186db..8351249695df5018414f3fcb7a4869c01aa24799 100644 --- a/GUI/coregui/Models/ApplicationModels.cpp +++ b/GUI/coregui/Models/ApplicationModels.cpp @@ -180,7 +180,7 @@ void ApplicationModels::createTestSample() void ApplicationModels::createTestJob() { SimulationOptionsItem *optionsItem = m_documentModel->getSimulationOptionsItem(); -// optionsItem->setRunPolicy(Constants::JOB_RUN_IN_BACKGROUND); + optionsItem->setRunPolicy(Constants::JOB_RUN_IN_BACKGROUND); JobItem *jobItem = m_jobModel->addJob( m_sampleModel->getMultiLayerItem(), diff --git a/GUI/coregui/Models/FilterPropertyProxy.cpp b/GUI/coregui/Models/FilterPropertyProxy.cpp index 0de2cfb68a98c11d5745cc08ecdb79040dc4b00f..b28e9bc13517b8fa9a0c0ec1e3088820db1403d8 100644 --- a/GUI/coregui/Models/FilterPropertyProxy.cpp +++ b/GUI/coregui/Models/FilterPropertyProxy.cpp @@ -25,7 +25,8 @@ int FilterPropertyProxy::columnCount(const QModelIndex &parent) const QModelIndex FilterPropertyProxy::toSourceIndex(QModelIndex index) { - FilterPropertyProxy *proxy = dynamic_cast<FilterPropertyProxy*>(const_cast<QAbstractItemModel*>(index.model())); + FilterPropertyProxy *proxy + = dynamic_cast<FilterPropertyProxy *>(const_cast<QAbstractItemModel *>(index.model())); if (proxy) return proxy->mapToSource(index); return index; @@ -37,8 +38,9 @@ bool FilterPropertyProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sou if (!sourceParent.isValid()) return true; const QString modelType = index.data(SessionModel::ModelTypeRole).toString(); - if (modelType == Constants::PropertyType || modelType == Constants::GroupItemType || modelType == Constants::VectorType) + if (modelType == Constants::PropertyType || modelType == Constants::GroupItemType + || modelType == Constants::VectorType) return false; - return true;//!sourceModel()->data(index, Qt::DisplayRole).isValid(); + return true; //! sourceModel()->data(index, Qt::DisplayRole).isValid(); } diff --git a/GUI/coregui/Models/FilterPropertyProxy.h b/GUI/coregui/Models/FilterPropertyProxy.h index bcda16559fa07a4cb0307e1b1fc89b9feb3a5838..3013dbbc20fa344efacaebc1180bd265247e5d47 100644 --- a/GUI/coregui/Models/FilterPropertyProxy.h +++ b/GUI/coregui/Models/FilterPropertyProxy.h @@ -20,6 +20,11 @@ #include <QSortFilterProxyModel> +//! +//! \brief The FilterPropertyProxy class filters out all PropertyItem's and similar from +//! SessionModel to have only top level items +//! + class BA_CORE_API_ FilterPropertyProxy : public QSortFilterProxyModel { Q_OBJECT diff --git a/GUI/coregui/Models/FitModelHelper.cpp b/GUI/coregui/Models/FitModelHelper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..55fabf56da747a955f0f5c0d6de3cf05e2dbb037 --- /dev/null +++ b/GUI/coregui/Models/FitModelHelper.cpp @@ -0,0 +1,132 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Models/FitModelHelper.cpp +//! @brief Implements class FitModelHelper +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2016 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov +//! @authors Walter Van Herck, Joachim Wuttke +// +// ************************************************************************** // + +#include "FitModelHelper.h" +#include "JobItem.h" +#include "FitParameterItems.h" +#include "JobModel.h" +#include "ParameterTreeItems.h" +#include "ModelPath.h" + +//! Creates fit parameter from given ParameterItem, sets starting value to the value +//! of ParameterItem, copies link. + +void FitModelHelper::createFitParameter(FitParameterContainerItem *container, + ParameterItem *parameterItem) +{ + Q_ASSERT(container); + Q_ASSERT(parameterItem); + + removeFromFitParameters(container, parameterItem); + + FitParameterItem *fitPar = dynamic_cast<FitParameterItem *>( + container->model()->insertNewItem(Constants::FitParameterType, container->index())); + Q_ASSERT(fitPar); + fitPar->setDisplayName(QStringLiteral("par")); + SessionItem *link + = fitPar->model()->insertNewItem(Constants::FitParameterLinkType, fitPar->index()); + fitPar->setItemValue(FitParameterItem::P_START_VALUE, parameterItem->value()); + link->setItemValue(FitParameterLinkItem::P_LINK, getParameterItemPath(parameterItem)); + + fitPar->initMinMaxValues(parameterItem->getLinkedItem()->limits()); +} + +//! Removes link to given parameterItem from fit parameters + +void FitModelHelper::removeFromFitParameters(FitParameterContainerItem *container, + ParameterItem *parameterItem) +{ + FitParameterItem *fitParItem = getFitParameterItem(container, parameterItem); + + if (fitParItem) { + foreach (SessionItem *linkItem, fitParItem->getItems(FitParameterItem::T_LINK)) { + if (getParameterItemPath(parameterItem) + == linkItem->getItemValue(FitParameterLinkItem::P_LINK)) { + fitParItem->model()->removeRow(linkItem->index().row(), linkItem->index().parent()); + break; + } + } + } +} + +//! Adds given parameterItem to the existing fit parameter with display name fitParName. +//! If parameterItem is already linked with another fitParameter, it will be relinked + +void FitModelHelper::addToFitParameter(FitParameterContainerItem *container, + ParameterItem *parameterItem, const QString &fitParName) +{ + Q_ASSERT(container); + + removeFromFitParameters(container, parameterItem); + foreach (SessionItem *fitPar, + container->getItems(FitParameterContainerItem::T_FIT_PARAMETERS)) { + if (fitPar->displayName() == fitParName) { + SessionItem *link + = fitPar->model()->insertNewItem(Constants::FitParameterLinkType, fitPar->index()); + link->setItemValue(FitParameterLinkItem::P_LINK, getParameterItemPath(parameterItem)); + break; + } + } +} + +//! Returns fFitParameterItem corresponding to given ParameterItem + +FitParameterItem *FitModelHelper::getFitParameterItem(FitParameterContainerItem *container, + ParameterItem *parameterItem) +{ + Q_ASSERT(container); + return container->getFitParameterItem(getParameterItemPath(parameterItem)); +} + +//! Returns list of fit parameter display names + +QStringList FitModelHelper::getFitParameterNames(FitParameterContainerItem *container) +{ + Q_ASSERT(container); + QStringList result; + foreach (SessionItem *item, container->getItems(FitParameterContainerItem::T_FIT_PARAMETERS)) { + result.append(item->displayName()); + } + return result; +} + +//! return path to given item in the ParameterTreeContainer + +QString FitModelHelper::getParameterItemPath(ParameterItem *parameterItem) +{ + QString result = ModelPath::getPathFromIndex(parameterItem->index()); + QString containerPrefix = Constants::ParameterContainerType + "/"; + int containerEnd = result.indexOf(containerPrefix) + containerPrefix.size(); + result = result.mid(containerEnd); + return result; +} + +//! Returns ParameterItem corresponding to given link. +//! Link is relative to ParameterContainerItem, so first we have to find it + +ParameterItem *FitModelHelper::getParameterItem(FitParameterContainerItem *container, + const QString &link) +{ + SessionItem *cur = container; + while (cur && cur->modelType() != Constants::JobItemType) { + cur = cur->parent(); + } + Q_ASSERT(cur->modelType() == Constants::JobItemType); + JobItem *jobItem = dynamic_cast<JobItem *>(cur); + Q_ASSERT(jobItem); + return dynamic_cast<ParameterItem *>( + ModelPath::getItemFromPath(link, jobItem->parameterContainerItem())); +} diff --git a/GUI/coregui/Models/FitModelHelper.h b/GUI/coregui/Models/FitModelHelper.h new file mode 100644 index 0000000000000000000000000000000000000000..ecdb5eff61469a9ef95f9f9d9b2e1deae2acc8a5 --- /dev/null +++ b/GUI/coregui/Models/FitModelHelper.h @@ -0,0 +1,48 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Models/FitModelHelper.h +//! @brief Declares class FitModelHelper +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2016 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov +//! @authors Walter Van Herck, Joachim Wuttke +// +// ************************************************************************** // + +#ifndef FITMODELHELPER_H +#define FITMODELHELPER_H + +#include "WinDllMacros.h" +#include "SessionModel.h" +#include <QMap> + +class ParameterItem; +class FitParameterItem; +class FitParameterContainerItem; +class JobItem; + +//! The FitModelHelper class contains set of convenience static methods to handle various fitting +//! items in given JobItem + +class BA_CORE_API_ FitModelHelper : public SessionModel +{ +public: + static void createFitParameter(FitParameterContainerItem *container, ParameterItem *parameterItem); + + static void removeFromFitParameters(FitParameterContainerItem *container, ParameterItem *parameterItem); + static void addToFitParameter(FitParameterContainerItem *container, ParameterItem *parameterItem, const QString &fitParName); + + static FitParameterItem *getFitParameterItem(FitParameterContainerItem *container, ParameterItem *parameterItem); + + static QStringList getFitParameterNames(FitParameterContainerItem *container); + static QString getParameterItemPath(ParameterItem *parameterItem); + static ParameterItem *getParameterItem(FitParameterContainerItem *container, const QString &link); + +}; + +#endif diff --git a/GUI/coregui/Models/FitParameterAbsModel.cpp b/GUI/coregui/Models/FitParameterAbsModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..86e97614a8b32e7114f6b32a1e39fda4241b867b --- /dev/null +++ b/GUI/coregui/Models/FitParameterAbsModel.cpp @@ -0,0 +1,400 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Models/FitParameterAbsModel.cpp +//! @brief Implements class FitParameterAbsModel +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2016 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov +//! @authors Walter Van Herck, Joachim Wuttke +// +// ************************************************************************** // + +#include "FitParameterAbsModel.h" +#include "SessionItem.h" +#include "FitParameterItems.h" +#include "SessionModel.h" +#include "JobModel.h" +#include "FitModelHelper.h" +#include "ParameterTreeItems.h" +#include "GUIHelpers.h" +#include "ModelPath.h" +#include <QColor> +#include <QMimeData> +#include <QDebug> + + +FitParameterProxyModel::FitParameterProxyModel(FitParameterContainerItem *fitParContainer, QObject *parent) + : QAbstractItemModel(parent) + , m_root_item(fitParContainer) +{ + addColumn(PAR_NAME, QStringLiteral("Name"), QStringLiteral("Name of fit parameter")); + addColumn(PAR_TYPE, FitParameterItem::P_TYPE, QStringLiteral("Fit parameter limits type")); + addColumn(PAR_VALUE, FitParameterItem::P_START_VALUE, QStringLiteral("Starting value of fit parameter")); + addColumn(PAR_MIN, FitParameterItem::P_MIN, QStringLiteral("Lower bound on fit parameter value")); + addColumn(PAR_MAX, FitParameterItem::P_MAX, QStringLiteral("Upper bound on fit parameter value")); + + connectModel(fitParContainer->model()); + + m_root_item->mapper()->setOnItemDestroy( + [this](SessionItem *parent) { + Q_ASSERT(parent == m_root_item); + m_root_item = 0; + }); +} + +Qt::ItemFlags FitParameterProxyModel::flags(const QModelIndex &index) const +{ + if(!m_root_item) return Qt::NoItemFlags; + + Qt::ItemFlags returnVal = Qt::ItemIsEnabled | Qt::ItemIsSelectable; + if(SessionItem *item = itemForIndex(index)) { + if(item->isEditable() && index.column() != 0) returnVal |= Qt::ItemIsEditable; + if(item->parent()->modelType() == Constants::FitParameterLinkType && index.column() == 0) { + returnVal |= Qt::ItemIsDragEnabled; + } + if(item->modelType() == Constants::FitParameterType || item->modelType() == Constants::FitParameterContainerType) { + returnVal |= Qt::ItemIsDropEnabled; + } + + } + + return returnVal; +} + +QModelIndex FitParameterProxyModel::index(int row, int column, const QModelIndex &parent) const +{ + if (!m_root_item || row < 0 || column < 0 || column >= columnCount(QModelIndex()) + || (parent.isValid() && parent.column() != 0)) + return QModelIndex(); + + SessionItem *parent_item = itemForIndex(parent); +// if(!isValidSourceItem(parent_item)) return QModelIndex(); + Q_ASSERT(parent_item); + + if(parent_item->modelType() == Constants::FitParameterContainerType) { + if (SessionItem *fitParItem = parent_item->childAt(row)) { + SessionItem *itemToPack = fitParItem; + if(column != 0) { + itemToPack = fitParItem->getItem(m_columnNames.value(column)); + } + return createIndex(row, column, itemToPack); + } + } + + else if(parent_item->modelType() == Constants::FitParameterType && column == 0) { + QVector<SessionItem *> links = parent_item->getItems(FitParameterItem::T_LINK); + if(row < links.size()) { + if(SessionItem *linkItem = links.at(row)) { + return createIndex(row, column, linkItem->getItem(FitParameterLinkItem::P_LINK)); + } + } + } + + return QModelIndex(); +} + +QModelIndex FitParameterProxyModel::parent(const QModelIndex &child) const +{ + if(!m_root_item) + return QModelIndex(); + + if (!child.isValid()) + return QModelIndex(); + + if (SessionItem *child_item = itemForIndex(child)) { + if (SessionItem *parent_item = child_item->parent()) { + + if(!isValidSourceItem(parent_item)) return QModelIndex(); + + if(parent_item->modelType()==Constants::FitParameterLinkType) { + SessionItem *fitPar = parent_item->parent(); + + if(!isValidSourceItem(fitPar)) return QModelIndex(); + + return createIndex(fitPar->parentRow(), 0, fitPar); + } + } + + } + + return QModelIndex(); +} + +int FitParameterProxyModel::rowCount(const QModelIndex &parent) const +{ + if(!m_root_item) return 0; + + if (parent.isValid() && parent.column() != 0) + return 0; + + SessionItem *parent_item = itemForIndex(parent); + if(parent_item!=m_root_item && !isValidSourceItem(parent_item)) return 0; + + if(parent_item->modelType() == Constants::FitParameterContainerType) { + return parent_item->rowCount(); + } + + else if(parent_item->modelType() == Constants::FitParameterType) { + return parent_item->getItems(FitParameterItem::T_LINK).size(); + } + + return 0; +} + +int FitParameterProxyModel::columnCount(const QModelIndex &parent) const +{ + if(!m_root_item) return 0; + + if (parent.isValid() && parent.column() != 0) + return 0; + + if(!parent.isValid()) + return MAX_COLUMNS; + + if(parent.isValid()) { + if(SessionItem *parentItem = itemForIndex(parent)) { + if(parentItem->modelType() == Constants::FitParameterType) { + return (parentItem->getItems(FitParameterItem::T_LINK).size() ? 1 : 0); + } + } + + } + + return 0; +} + +QVariant FitParameterProxyModel::data(const QModelIndex &index, int role) const +{ + if(!m_root_item) return QVariant(); + + if ( !index.isValid() || index.column() < 0 || index.column() >= MAX_COLUMNS) + return QVariant(); + + if (SessionItem *item = itemForIndex(index)) { + if (role == Qt::DisplayRole || role == Qt::EditRole) { + if(item->modelType() == Constants::FitParameterType) { + return item->displayName(); + } else { + return item->value(); + } + } + if(role == Qt::TextColorRole && !item->isEditable()) { + return QVariant(QColor(Qt::gray)); + } + } + + return QVariant(); +} + +bool FitParameterProxyModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if(!m_root_item) return false; + + if (!index.isValid()) + return false; + if (SessionItem *item = itemForIndex(index)) { + if (role == Qt::EditRole) { + item->setValue(value); + emit dataChanged(index, index); + return true; + } + } + return false; +} + +QStringList FitParameterProxyModel::mimeTypes() const +{ + QStringList types; + types << SessionXML::LinkMimeType; + return types; +} + +QMimeData *FitParameterProxyModel::mimeData(const QModelIndexList &indexes) const +{ + QMimeData *mimeData = new QMimeData(); + QModelIndex index = indexes.first(); + if (index.isValid()) { + if(SessionItem *item = itemForIndex(index)) { + QString path = item->value().toString(); + mimeData->setData(SessionXML::LinkMimeType, path.toLatin1()); + } + } + return mimeData; +} + +bool FitParameterProxyModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const +{ + Q_UNUSED(data); + Q_UNUSED(action); + Q_UNUSED(row); + bool drop_is_possible(false); + if(parent.isValid()) drop_is_possible = true; + if(!parent.isValid() && row==-1 && column == -1) drop_is_possible = true; + return drop_is_possible; +} + +bool FitParameterProxyModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, + int column, const QModelIndex &parent) +{ + Q_UNUSED(action); + Q_UNUSED(row); + Q_UNUSED(column); + + if (parent.isValid()) { + if (SessionItem *fitParItem = itemForIndex(parent)) { + Q_ASSERT(fitParItem->modelType() == Constants::FitParameterType); + ParameterItem *parItem = FitModelHelper::getParameterItem( + m_root_item, QString::fromLatin1(data->data(SessionXML::LinkMimeType))); + Q_ASSERT(parItem); + FitModelHelper::addToFitParameter(m_root_item, parItem, fitParItem->displayName()); + } + + } else { + ParameterItem *parItem = FitModelHelper::getParameterItem( + m_root_item, QString::fromLatin1(data->data(SessionXML::LinkMimeType))); + Q_ASSERT(parItem); + FitModelHelper::createFitParameter(m_root_item, parItem); + } + + return true; +} + +QVariant FitParameterProxyModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { + return m_columnNames.value(section); + } + else if(role == Qt::ToolTipRole) { + return m_columnToolTips.value(section); + } + return QVariant(); +} + +void FitParameterProxyModel::onSourceDataChanged(const QModelIndex &topLeft, + const QModelIndex &bottomRight, + const QVector<int> &roles) +{ + Q_UNUSED(bottomRight); + + JobModel *sourceModel = qobject_cast<JobModel *>(sender()); + Q_ASSERT(sourceModel); + SessionItem *sourceItem = sourceModel->itemForIndex(topLeft); + + QModelIndex itemIndex = indexOfItem(sourceItem); + + if (itemIndex.isValid()) + emit dataChanged(itemIndex, itemIndex, roles); +} + +void FitParameterProxyModel::onSourceRowsRemoved(const QModelIndex &parent, int first, int last) +{ + Q_UNUSED(parent); + Q_UNUSED(first); + Q_UNUSED(last); + beginResetModel(); + endResetModel(); +} + +void FitParameterProxyModel::onSourceAboutToBeReset() +{ + if(!m_root_item) return; + beginResetModel(); + endResetModel(); +} + +void FitParameterProxyModel::connectModel(QAbstractItemModel *sourceModel, bool isConnect) +{ + Q_ASSERT(sourceModel); + if(isConnect) { + connect(sourceModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)), + this, SLOT(onSourceDataChanged(QModelIndex,QModelIndex,QVector<int>))); + connect(sourceModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), + this, SLOT(onSourceRowsRemoved(QModelIndex,int,int))); + connect(sourceModel, SIGNAL(modelAboutToBeReset()), this, SLOT(onSourceAboutToBeReset())); + + } + + else { + disconnect(sourceModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)), + this, SLOT(onSourceDataChanged(QModelIndex,QModelIndex,QVector<int>))); + disconnect(sourceModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), + this, SLOT(onSourceRowsRemoved(QModelIndex,int,int))); + disconnect(sourceModel, SIGNAL(modelAboutToBeReset()), this, SLOT(onSourceAboutToBeReset())); + } +} + +void FitParameterProxyModel::addColumn(FitParameterProxyModel::EColumn id, const QString &name, + const QString &tooltip) +{ + m_columnNames[id] = name; + m_columnToolTips[id] = tooltip; +} + +QModelIndex FitParameterProxyModel::indexOfItem(SessionItem *item) const +{ + if(!m_root_item) return QModelIndex(); + + if(SessionItem *parent_item = item->parent()) { + if(parent_item->modelType() == Constants::FitParameterContainerType) { + if(item->modelType() == Constants::FitParameterType) { + return createIndex(item->parentRow(), 0, item); + } + } + + else if(parent_item->modelType() == Constants::FitParameterType) { + + QString tag = parent_item->tagFromItem(item); + int col = m_columnNames.key(tag, -1); + if(col > 0) { + return createIndex(parent_item->parentRow(), col, item); + } + } + + else if(parent_item->modelType() == Constants::FitParameterLinkType) { + QVector<SessionItem *> links = parent_item->parent()->getItems(FitParameterItem::T_LINK); + return createIndex(links.indexOf(parent_item), 0, item); + } + + } + + return QModelIndex(); +} + +SessionItem *FitParameterProxyModel::itemForIndex(const QModelIndex &index) const +{ + if(!m_root_item) return 0; + + if (index.isValid()) { + SessionItem *item = static_cast<SessionItem *>(index.internalPointer()); + if(item) { + if(!isValidSourceItem(item)) { + return 0; +// throw GUIHelpers::Error("FitParameterAbsModel::itemForIndex -> Error! Attempt to " +// "use destroyed item."); + } + + return item; + } + } + return m_root_item; +} + +SessionModel *FitParameterProxyModel::sourceModel() const +{ + Q_ASSERT(m_root_item); + return m_root_item->model(); +} + +//! Returns true if given item still exists in source model +bool FitParameterProxyModel::isValidSourceItem(SessionItem *item) const +{ + if(item == m_root_item) return true; + if(sourceModel() && ModelPath::isValidItem(sourceModel(), item, m_root_item->index())) + return true; + return false; +} diff --git a/GUI/coregui/Models/FitParameterAbsModel.h b/GUI/coregui/Models/FitParameterAbsModel.h new file mode 100644 index 0000000000000000000000000000000000000000..16ebc34d2672672f374b9563e786aedc10a21e59 --- /dev/null +++ b/GUI/coregui/Models/FitParameterAbsModel.h @@ -0,0 +1,95 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Models/FitParameterProxyModel.h +//! @brief Declares class FitParameterProxyModel +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2016 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov +//! @authors Walter Van Herck, Joachim Wuttke +// +// ************************************************************************** // + +#ifndef FITPARAMETERABSMODEL_H +#define FITPARAMETERABSMODEL_H + +#include "WinDllMacros.h" +#include <QAbstractItemModel> + +class SessionModel; +class FitParameterContainerItem; +class SessionItem; + +//! The FitParameterProxyModel adopt original JobModel to show items from FitParameterContainer +//! in 5 column tree view. +//! (It's not a true proxy model, it + +class BA_CORE_API_ FitParameterProxyModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + + explicit FitParameterProxyModel(FitParameterContainerItem *fitParContainer, QObject *parent = 0); + + enum EColumn {PAR_NAME, PAR_TYPE, PAR_VALUE, PAR_MIN, PAR_MAX, MAX_COLUMNS}; + + Qt::ItemFlags flags(const QModelIndex & index) const Q_DECL_OVERRIDE; + QModelIndex index(int row, int column, const QModelIndex &parent) const; + QModelIndex parent(const QModelIndex &child) const; + int rowCount(const QModelIndex &parent) const; + int columnCount(const QModelIndex &parent) const; + 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; + Qt::DropActions supportedDragActions() const; + Qt::DropActions supportedDropActions() const; + QMimeData *mimeData(const QModelIndexList &indexes) const; + 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) Q_DECL_OVERRIDE; + + + QVariant headerData(int section, Qt::Orientation orientation, int role) const Q_DECL_OVERRIDE; + + + QModelIndex indexOfItem(SessionItem *item) const; + SessionItem *itemForIndex(const QModelIndex &index) const; + + SessionModel *sourceModel() const; + + bool isValidSourceItem(SessionItem *item) const; + +private slots: + void onSourceDataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight, + const QVector<int> & roles); + void onSourceRowsRemoved(const QModelIndex & parent, int first, int last); + void onSourceAboutToBeReset(); + +private: + void connectModel(QAbstractItemModel *sourceModel, bool isConnect = true); + void addColumn(EColumn id, const QString &name, const QString &tooltip); + + FitParameterContainerItem *m_root_item; + QMap<int, QString> m_columnNames; + QMap<int, QString> m_columnToolTips; +}; + +inline Qt::DropActions FitParameterProxyModel::supportedDragActions() const +{ + return Qt::MoveAction | Qt::CopyAction; +} + +inline Qt::DropActions FitParameterProxyModel::supportedDropActions() const +{ + return Qt::MoveAction | Qt::CopyAction; +} + + +#endif diff --git a/GUI/coregui/Models/FitParameterItems.cpp b/GUI/coregui/Models/FitParameterItems.cpp index ebd48eac8dd08fdb5ec9221d61ef5d5090f1d868..b2dfb7e48041a9473a41fcf5755ade64b3ec06aa 100644 --- a/GUI/coregui/Models/FitParameterItems.cpp +++ b/GUI/coregui/Models/FitParameterItems.cpp @@ -18,8 +18,30 @@ #include "ComboProperty.h" #include "ModelPath.h" #include "SessionModel.h" +#include "FitModelHelper.h" +#include "ParameterTreeItems.h" +#include "AttLimits.h" #include <QDebug> +namespace +{ + +QStringList getFitParTypeTooltips() +{ + QStringList result; + result.append(QStringLiteral("Fixed at given value")); + result.append(QStringLiteral("Limited in the range [min, max]")); + result.append(QStringLiteral("Limited at lower bound [min, inf]")); + result.append(QStringLiteral("Limited at upper bound [-inf, max]")); + result.append(QStringLiteral("No limits imposed to parameter value")); + return result; +} + +const double range_factor = 0.5; + +} + + // ---------------------------------------------------------------------------- const QString FitParameterLinkItem::P_LINK = "Link"; @@ -34,8 +56,8 @@ FitParameterLinkItem::FitParameterLinkItem() // ---------------------------------------------------------------------------- -const QString FitParameterItem::P_USE = "Use"; -const QString FitParameterItem::P_START_VALUE = "Starting Value"; +const QString FitParameterItem::P_TYPE = "Type"; +const QString FitParameterItem::P_START_VALUE = "Value"; const QString FitParameterItem::P_MIN = "Min"; const QString FitParameterItem::P_MAX = "Max"; const QString FitParameterItem::T_LINK = "Link tag"; @@ -43,12 +65,94 @@ const QString FitParameterItem::T_LINK = "Link tag"; FitParameterItem::FitParameterItem() : SessionItem(Constants::FitParameterType) { - addProperty(P_USE, true); + ComboProperty partype; + partype << Constants::FITPAR_FIXED << Constants::FITPAR_LIMITED + << Constants::FITPAR_LOWERLIMITED + << Constants::FITPAR_UPPERLIMITED << Constants::FITPAR_FREE; + partype.setValue(Constants::FITPAR_LIMITED); + partype.setToolTips(getFitParTypeTooltips()); + + addProperty(P_TYPE, partype.getVariant()); addProperty(P_START_VALUE, 0.0); addProperty(P_MIN, 0.0); - addProperty(P_MAX, 0.0); + addProperty(P_MAX, 0.0)->setEnabled(false); registerTag(T_LINK, 0, -1, QStringList() << Constants::FitParameterLinkType); setDefaultTag(T_LINK); + + mapper()->setOnPropertyChange( + [this](const QString &name) { + if(name == P_TYPE) + onTypeChange(); + }); + + onTypeChange(); +} + +//! Inits P_MIN and P_MAX taking into account current value and external limits + +void FitParameterItem::initMinMaxValues(const AttLimits &limits) +{ + double value = getItemValue(P_START_VALUE).toDouble(); + + double dr(0); + if(value == 0.0) { + dr = 1.0*range_factor; + } else { + dr = std::abs(value)*range_factor; + } + + ComboProperty partype = getItemValue(P_TYPE).value<ComboProperty>(); + if(partype.getValue() == Constants::FITPAR_LIMITED) { + double min = value - dr; + double max = value + dr; + if(limits.hasLowerLimit() && min <limits.getLowerLimit()) min = limits.getLowerLimit(); + if(limits.hasUpperLimit() && max >limits.getUpperLimit()) max = limits.getUpperLimit(); + setItemValue(P_MIN, min); + setItemValue(P_MAX, max); + } +} + +//! Enables/disables min, max properties on FitParameterItem's type + +void FitParameterItem::onTypeChange() +{ + ComboProperty partype = getItemValue(P_TYPE).value<ComboProperty>(); + if(partype.getValue() == Constants::FITPAR_FIXED) { + setLimitEnabled(P_MIN, false); + setLimitEnabled(P_MAX, false); + } + + else if(partype.getValue() == Constants::FITPAR_LIMITED) { + setLimitEnabled(P_MIN, true); + setLimitEnabled(P_MAX, true); + } + + else if(partype.getValue() == Constants::FITPAR_LOWERLIMITED) { + setLimitEnabled(P_MIN, true); + setLimitEnabled(P_MAX, false); + } + + else if(partype.getValue() == Constants::FITPAR_UPPERLIMITED) { + setLimitEnabled(P_MIN, false); + setLimitEnabled(P_MAX, true); + } + + else if(partype.getValue() == Constants::FITPAR_FREE) { + setLimitEnabled(P_MIN, false); + setLimitEnabled(P_MAX, false); + } +} + +//! Set limit property with given name to the enabled state + +void FitParameterItem::setLimitEnabled(const QString &name, bool enabled) +{ + if(isTag(name)) { + SessionItem *propertyItem = getItem(name); + Q_ASSERT(propertyItem); + propertyItem->setEnabled(enabled); + propertyItem->setEditable(enabled); + } } // ---------------------------------------------------------------------------- @@ -74,3 +178,8 @@ FitParameterItem *FitParameterContainerItem::getFitParameterItem(const QString & } return nullptr; } + +bool FitParameterContainerItem::isEmpty() +{ + return getItems(T_FIT_PARAMETERS).isEmpty() ? true : false; +} diff --git a/GUI/coregui/Models/FitParameterItems.h b/GUI/coregui/Models/FitParameterItems.h index a77411a83d6c9ab332880590df7f22ed39752db1..5d9ab0de7dba434efb949b02db5629ecb73af497 100644 --- a/GUI/coregui/Models/FitParameterItems.h +++ b/GUI/coregui/Models/FitParameterItems.h @@ -18,6 +18,8 @@ #include "SessionItem.h" +class AttLimits; + class BA_CORE_API_ FitParameterLinkItem : public SessionItem { @@ -31,12 +33,18 @@ class BA_CORE_API_ FitParameterItem : public SessionItem { public: - static const QString P_USE; + static const QString P_TYPE; static const QString P_START_VALUE; static const QString P_MIN; static const QString P_MAX; static const QString T_LINK; explicit FitParameterItem(); + + void initMinMaxValues(const AttLimits &limits); + +private: + void onTypeChange(); + void setLimitEnabled(const QString &name, bool enabled); }; class BA_CORE_API_ FitParameterContainerItem : public SessionItem @@ -46,6 +54,7 @@ public: static const QString T_FIT_PARAMETERS; explicit FitParameterContainerItem(); FitParameterItem *getFitParameterItem(const QString &link); + bool isEmpty(); }; #endif diff --git a/GUI/coregui/Models/FitParameterModel.cpp b/GUI/coregui/Models/FitParameterModel.cpp deleted file mode 100644 index 7f128f51df28704021d07175b43855ecd01eb349..0000000000000000000000000000000000000000 --- a/GUI/coregui/Models/FitParameterModel.cpp +++ /dev/null @@ -1,219 +0,0 @@ -// ************************************************************************** // -// -// BornAgain: simulate and fit scattering at grazing incidence -// -//! @file coregui/Models/FitParameterModel.h -//! @brief Declares class FitParameterModel -//! -//! @homepage http://www.bornagainproject.org -//! @license GNU General Public License v3 or higher (see COPYING) -//! @copyright Forschungszentrum Jülich GmbH 2016 -//! @authors Scientific Computing Group at MLZ Garching -//! @authors Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov -//! @authors Walter Van Herck, Joachim Wuttke -// -// ************************************************************************** // - -#include "FitParameterModel.h" -#include "JobModel.h" -#include "FitParameterItems.h" -#include "ParameterTreeItems.h" -#include "ModelPath.h" -#include <QDebug> - -FitParameterModel::FitParameterModel(SessionItem *fitParContainer, QObject *parent) - : SessionModel(QString("FitParameterModel"), parent) -{ - setRootItem(fitParContainer); - m_columnNames.insert(0, "Name"); - m_columnNames.insert(1, FitParameterItem::P_USE); - m_columnNames.insert(3, FitParameterItem::P_MIN); - m_columnNames.insert(2, FitParameterItem::P_START_VALUE); - m_columnNames.insert(4, FitParameterItem::P_MAX); -} - -FitParameterModel::~FitParameterModel() -{ - setRootItem(0); - qDebug() << "FitParameterModel::~FitParameterModel()"; -} - -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; -} - - -QVariant FitParameterModel::data(const QModelIndex & index, int role) const -{ - if ( !index.isValid() || index.column() < 0 || index.column() >= 5) { - return QVariant(); - } - if (SessionItem *item = itemForIndex(index)) { - if (role == Qt::DisplayRole || role == Qt::EditRole) { - if (item->parent() != itemForIndex(QModelIndex())) - { - if (index.column() == 0) { - QVector<SessionItem *> links = item->parent()->getItems(FitParameterItem::T_LINK); - - if(links.size()) { - if(SessionItem *linkItem = links.at(index.row())) { - return linkItem->getItemValue(FitParameterLinkItem::P_LINK); - } - } - } else { - return QVariant(); - } - } - if (index.column() == 0) - return item->itemName(); - else - return item->getItemValue(m_columnNames.value(index.column())); - } - } - return QVariant(); -} - -bool FitParameterModel::setData(const QModelIndex &index, const QVariant &value, int role) -{ - if (!index.isValid()) - return false; - if (SessionItem *item = itemForIndex(index)) { - if (role == Qt::EditRole && index.column() > 0 && index.column() < 5) { - item->setItemValue(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(); -} - -int FitParameterModel::rowCount(const QModelIndex &parent) const -{ -// if(!parent.isValid()) -// return 0; - -// if (parent.isValid() && parent.column() != 0) -// return 0; -// SessionItem *parent_item = itemForIndex(parent); -// return parent_item ? parent_item->rowCount() : 0; - if(SessionItem *parentItem = itemForIndex(parent)) { - if(parentItem->modelType() == Constants::FitParameterType) { - - return parentItem->getItems(FitParameterItem::T_LINK).size(); - } - } - return SessionModel::rowCount(parent); -} - -int FitParameterModel::columnCount(const QModelIndex &parent) const -{ -// if(!parent.isValid()) -// return 0; - - if (parent.isValid() && parent.column() != 0) - return 0; - return 5; - -} - -//! Creates fit parameter from given ParameterItem, sets starting value to the value -//! of ParameterItem, copy link. -void FitParameterModel::createFitParameter(ParameterItem *parameterItem) -{ - SessionItem *fitPar = getFitParContainer()->model()->insertNewItem(Constants::FitParameterType, getFitParContainer()->index()); - fitPar->setDisplayName(QStringLiteral("par")); - Q_ASSERT(fitPar); - if(parameterItem) { - fitPar->setItemValue(FitParameterItem::P_START_VALUE, parameterItem->value()); - SessionItem *link = fitPar->model()->insertNewItem(Constants::FitParameterLinkType, fitPar->index()); - link->setItemValue(FitParameterLinkItem::P_LINK, getParameterItemPath(parameterItem)); - } - emit layoutChanged(); - -} - -//! Removes link to given parameterItem from fit parameters -void FitParameterModel::removeFromFitParameters(ParameterItem *parameterItem) -{ - FitParameterItem *fitParItem = getFitParameterItem(parameterItem); - if(fitParItem) { - foreach(SessionItem *linkItem, fitParItem->getItems(FitParameterItem::T_LINK)) { - if(getParameterItemPath(parameterItem) == linkItem->getItemValue(FitParameterLinkItem::P_LINK)) { - fitParItem->model()->removeRow(linkItem->index().row(), linkItem->index().parent()); - break; - } - } - emit layoutChanged(); - } -} - -//! Adds given parameterItem to the existing fit parameter with display name fitParName. -//! If parameterItem is already linked with another fitParameter, it will be relinked -void FitParameterModel::addToFitParameter(ParameterItem *parameterItem, const QString &fitParName) -{ - removeFromFitParameters(parameterItem); - foreach(SessionItem *fitPar, getFitParContainer()->getItems(FitParameterContainerItem::T_FIT_PARAMETERS)) { - if(fitPar->displayName() == fitParName) { - SessionItem *link = fitPar->model()->insertNewItem(Constants::FitParameterLinkType, fitPar->index()); - link->setItemValue(FitParameterLinkItem::P_LINK, getParameterItemPath(parameterItem)); - emit layoutChanged(); - break; - } - } -} - -//! Returns fFitParameterItem corresponding to given ParameterItem -FitParameterItem *FitParameterModel::getFitParameterItem(ParameterItem *parameterItem) -{ - return getFitParContainer()->getFitParameterItem(getParameterItemPath(parameterItem)); -} - -FitParameterContainerItem *FitParameterModel::getFitParContainer() -{ - FitParameterContainerItem *result = dynamic_cast<FitParameterContainerItem *>(rootItem()); - Q_ASSERT(result); - return result; -} - -//! Returns list of fit parameter display names -QStringList FitParameterModel::getFitParameterNames() -{ - QStringList result; - - foreach(SessionItem *item, getFitParContainer()->getItems(FitParameterContainerItem::T_FIT_PARAMETERS)) { - result.append(item->displayName()); - } - - return result; -} - -//! return path to given item in the ParameterTreeContainer -QString FitParameterModel::getParameterItemPath(ParameterItem *parameterItem) -{ - QString result = ModelPath::getPathFromIndex(parameterItem->index()); -// int containerEnd = result.indexOf(QStringLiteral("Container/")) + 10; - QString containerPrefix = Constants::ParameterContainerType+"/"; - int containerEnd = result.indexOf(containerPrefix) + containerPrefix.size(); - result = result.mid(containerEnd); - return result; -} - diff --git a/GUI/coregui/Models/FitParameterModel.h b/GUI/coregui/Models/FitParameterModel.h deleted file mode 100644 index 5bbe3a5ab1c6d37aea5bfc6a2df1570ba3196cd8..0000000000000000000000000000000000000000 --- a/GUI/coregui/Models/FitParameterModel.h +++ /dev/null @@ -1,67 +0,0 @@ -// ************************************************************************** // -// -// BornAgain: simulate and fit scattering at grazing incidence -// -//! @file coregui/Models/FitParameterModel.h -//! @brief Declares class FitParameterModel -//! -//! @homepage http://www.bornagainproject.org -//! @license GNU General Public License v3 or higher (see COPYING) -//! @copyright Forschungszentrum Jülich GmbH 2016 -//! @authors Scientific Computing Group at MLZ Garching -//! @authors Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov -//! @authors Walter Van Herck, Joachim Wuttke -// -// ************************************************************************** // - -#ifndef FITPARAMETERMODEL_H -#define FITPARAMETERMODEL_H - -#include "WinDllMacros.h" -#include "SessionModel.h" -#include <QMap> - -class ParameterItem; -class FitParameterItem; -class FitParameterContainerItem; - -//! The FitParameterModel adopt fit parameters from FitParameterContainer to be shown -//! in 5 column tree view. It doesn't own its root item (it still belongs to the original JobModel) -//! and serves merely as a proxy model. Any changes should be done via original model -//! accessible via rootItem->model() - -class BA_CORE_API_ FitParameterModel : public SessionModel -{ - Q_OBJECT - -public: - explicit FitParameterModel(SessionItem *fitParContainer, QObject *parent = 0); - ~FitParameterModel(); - - 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; - QVariant headerData(int section, Qt::Orientation orientation, int role) const Q_DECL_OVERRIDE; - - virtual int rowCount(const QModelIndex &parent) const; - virtual int columnCount(const QModelIndex &parent) const; - - void createFitParameter(ParameterItem *parameterItem = 0); - void removeFromFitParameters(ParameterItem *parameterItem); - void addToFitParameter(ParameterItem *parameterItem, const QString &fitParName); - - FitParameterItem *getFitParameterItem(ParameterItem *parameterItem); - - FitParameterContainerItem *getFitParContainer(); - - QStringList getFitParameterNames(); - - static QString getParameterItemPath(ParameterItem *parameterItem); - -private: - QMap<int, QString> m_columnNames; -}; - - - -#endif diff --git a/GUI/coregui/Models/JobModel.cpp b/GUI/coregui/Models/JobModel.cpp index 5743f0579146e9516b4a137a85af009bf53bbff8..b7f52a159213bb3da98c58830122e8cf277d4cef 100644 --- a/GUI/coregui/Models/JobModel.cpp +++ b/GUI/coregui/Models/JobModel.cpp @@ -84,7 +84,8 @@ JobItem *JobModel::addJob(const MultiLayerItem *multiLayerItem, const Instrument jobItem->setItemName(generateJobName()); jobItem->setIdentifier(generateJobIdentifier()); - copyParameterizedItem(multiLayerItem, jobItem, JobItem::T_SAMPLE); + SessionItem *multilayer = copyParameterizedItem(multiLayerItem, jobItem, JobItem::T_SAMPLE); + multilayer->setItemName(Constants::MultiLayerType); copyParameterizedItem(instrumentItem, jobItem, JobItem::T_INSTRUMENT); copyParameterizedItem(optionItem, jobItem, JobItem::T_SIMULATION_OPTIONS); diff --git a/GUI/coregui/Models/ModelMapper.cpp b/GUI/coregui/Models/ModelMapper.cpp index 55f3da04154c17c7893c85c0f31dc189072f44b6..3150fb6bf34cdf0e8f9b761abcd834ac4116f2f8 100644 --- a/GUI/coregui/Models/ModelMapper.cpp +++ b/GUI/coregui/Models/ModelMapper.cpp @@ -72,6 +72,11 @@ void ModelMapper::setOnAnyChildChange(std::function<void (SessionItem *)> f, con m_onAnyChildChange.push_back(call_item_t(f, caller)); } +void ModelMapper::setOnItemDestroy(std::function<void (SessionItem *)> f, const void *caller) +{ + m_onItemDestroy.push_back(call_item_t(f, caller)); +} + //! Cancells all subscribtion of given caller void ModelMapper::unsubscribe(const void *caller) { @@ -82,6 +87,7 @@ void ModelMapper::unsubscribe(const void *caller) clean_container(m_onChildrenChange, caller); clean_container(m_onSiblingsChange, caller); clean_container(m_onAnyChildChange, caller); + clean_container(m_onItemDestroy, caller); } void ModelMapper::setModel(SessionModel *model) @@ -128,7 +134,7 @@ void ModelMapper::callOnValueChange() f.first(); } } - if(m_active) emit valueChange(); +// if(m_active) emit valueChange(); } void ModelMapper::callOnPropertyChange(const QString &name) @@ -138,7 +144,7 @@ void ModelMapper::callOnPropertyChange(const QString &name) f.first(name); } } - if(m_active) emit propertyChange(name); +// if(m_active) emit propertyChange(name); } void ModelMapper::callOnChildPropertyChange(SessionItem *item, const QString &name) @@ -148,7 +154,7 @@ void ModelMapper::callOnChildPropertyChange(SessionItem *item, const QString &na f.first(item, name); } } - if(m_active) emit childPropertyChange(item, name); +// if(m_active) emit childPropertyChange(item, name); } void ModelMapper::callOnParentChange(SessionItem *new_parent) @@ -158,7 +164,7 @@ void ModelMapper::callOnParentChange(SessionItem *new_parent) f.first(new_parent); } } - if(m_active) emit parentChange(new_parent); +// if(m_active) emit parentChange(new_parent); } void ModelMapper::callOnChildrenChange(SessionItem *item) @@ -168,7 +174,7 @@ void ModelMapper::callOnChildrenChange(SessionItem *item) f.first(item); } } - if(m_active) emit childrenChange(item); +// if(m_active) emit childrenChange(item); } void ModelMapper::callOnSiblingsChange() @@ -178,7 +184,7 @@ void ModelMapper::callOnSiblingsChange() f.first(); } } - if(m_active) emit siblingsChange(); +// if(m_active) emit siblingsChange(); } void ModelMapper::callOnAnyChildChange(SessionItem *item) @@ -188,7 +194,18 @@ void ModelMapper::callOnAnyChildChange(SessionItem *item) f.first(item); } } - if(m_active) emit anyChildChange(item); +// if(m_active) emit anyChildChange(item); +} + +//! Notifies subscribers if an item owning given mapper is about to be destroyed +void ModelMapper::callOnItemDestroy() +{ + if (m_active && m_onItemDestroy.size() > 0) { + for (auto f : m_onItemDestroy) { + f.first(m_item); + } + } +// if(m_active) emit itemDestroy(new_parent); } void ModelMapper::clearMapper() @@ -202,6 +219,7 @@ void ModelMapper::clearMapper() m_onChildrenChange.clear(); m_onSiblingsChange.clear(); m_onAnyChildChange.clear(); + m_onItemDestroy.clear(); } void ModelMapper::onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, diff --git a/GUI/coregui/Models/ModelMapper.h b/GUI/coregui/Models/ModelMapper.h index d685d6ed2537f3547adda028da77e2494083f876..b7a8d4e4bc4afaed556edfb3407e72e53269ef9e 100644 --- a/GUI/coregui/Models/ModelMapper.h +++ b/GUI/coregui/Models/ModelMapper.h @@ -54,8 +54,12 @@ public: void setActive(bool state) {m_active = state;} + void setOnItemDestroy(std::function<void(SessionItem*)> f, const void *caller=0); + void unsubscribe(const void *caller); + void callOnItemDestroy(); + signals: void valueChange(); void propertyChange(const QString &name); @@ -64,6 +68,7 @@ signals: void childrenChange(SessionItem *item); void siblingsChange(); void anyChildChange(SessionItem *item); + void itemDestroy(SessionItem *item); public slots: void onDataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight, @@ -108,6 +113,7 @@ private: std::vector<call_item_t> m_onChildrenChange; std::vector<call_t> m_onSiblingsChange; std::vector<call_item_t> m_onAnyChildChange; + std::vector<call_item_t> m_onItemDestroy; QModelIndex m_aboutToDelete; }; diff --git a/GUI/coregui/Models/ModelPath.cpp b/GUI/coregui/Models/ModelPath.cpp index aaf8cd281a684d7f44c8e21cb40118e7d31bdbed..84734324e919468eadb91dcc2694c1060cedf613 100644 --- a/GUI/coregui/Models/ModelPath.cpp +++ b/GUI/coregui/Models/ModelPath.cpp @@ -150,6 +150,21 @@ SessionItem *ModelPath::getItemFromPath(const QString &relPath, SessionItem *par return parent->model()->itemForIndex(ModelPath::getIndexFromPath(parent->model(), fullPath)); } +//! Iterates through all the model and returns true if item is found. This is to + +bool ModelPath::isValidItem(SessionModel *model, SessionItem *item, const QModelIndex &parent) +{ + for(int i_row=0; i_row<model->rowCount(parent); ++i_row) { + QModelIndex index = model->index(i_row, 0, parent); + SessionItem *curr = model->itemForIndex(index); + if(curr == item) return true; + + bool isvalid = isValidItem(model, item, index); + if(isvalid) return isvalid; + } + return false; +} + QStringList ModelPath::splitParameterName(const QString &par_name) { QStringList result; diff --git a/GUI/coregui/Models/ModelPath.h b/GUI/coregui/Models/ModelPath.h index d811ded3d1ba8a685ce46973f636dd2315ce1688..4b8ac90dee99c9a51eb5612dca75449cb4c933ab 100644 --- a/GUI/coregui/Models/ModelPath.h +++ b/GUI/coregui/Models/ModelPath.h @@ -51,6 +51,8 @@ public: static SessionItem *getItemFromPath(const QString &relPath, SessionItem *parent); + static bool isValidItem(SessionModel *model, SessionItem *item, const QModelIndex &parent); + private: static QStringList splitParameterName(const QString& par_name); diff --git a/GUI/coregui/Models/ParameterModelBuilder.cpp b/GUI/coregui/Models/ParameterModelBuilder.cpp index e5f05276800c6b98bebedd7bf8865341d9a8e56b..eebf20cb6dd1b5b8ba0441d411de5f4f797f1d1f 100644 --- a/GUI/coregui/Models/ParameterModelBuilder.cpp +++ b/GUI/coregui/Models/ParameterModelBuilder.cpp @@ -32,7 +32,7 @@ #include "JobItem.h" #include "ModelPath.h" #include "ParameterTreeItems.h" -#include "FitParameterModel.h" +#include "FitModelHelper.h" #include <QStandardItem> #include <QStandardItemModel> #include <QStack> @@ -55,7 +55,7 @@ void ParameterModelBuilder::createParameterTree(JobItem *item, const QString &ta #ifndef NDEBUG // Provides all items in "JobItem/Parameter Tree Container" with domain links already // at the stage of ParameterTree creation. It is necessary for validation, in Release mode - // it will lead for unnecessary larde project files. + // it will lead for unnecessary large project files. populateDomainLinks(item, tag); #endif } @@ -117,7 +117,7 @@ void ParameterModelBuilder::populateDomainLinks(JobItem *jobItem, const QString } } else { if(ParameterItem *parItem = dynamic_cast<ParameterItem *>(current)) { - QString parItemPath = FitParameterModel::getParameterItemPath(parItem); + QString parItemPath = FitModelHelper::getParameterItemPath(parItem); std::string domainPath = ModelPath::translateParameterName(jobItem->getMultiLayerItem()->parent(), parItemPath); parItem->setItemValue(ParameterItem::P_DOMAIN, QString::fromStdString(domainPath)); } diff --git a/GUI/coregui/Models/ParameterTuningModel.cpp b/GUI/coregui/Models/ParameterTuningModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b3adcac788e6fdb30110538c1ee517bcb0cc1faa --- /dev/null +++ b/GUI/coregui/Models/ParameterTuningModel.cpp @@ -0,0 +1,77 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Models/ParameterTuningModel.cpp +//! @brief Implements class ParameterTuningModel +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2016 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov +//! @authors Walter Van Herck, Joachim Wuttke +// +// ************************************************************************** // + +#include "ParameterTuningModel.h" +#include "FitParameterItems.h" +#include "SessionXML.h" +#include "FitModelHelper.h" +#include "SessionModel.h" +#include "ParameterTreeItems.h" +#include <QDebug> +#include <QMimeData> + +ParameterTuningModel::ParameterTuningModel(QObject *parent) + : FilterPropertyProxy(2, parent) +{ + +} + +Qt::ItemFlags ParameterTuningModel::flags(const QModelIndex &proxyIndex) const +{ + Qt::ItemFlags result = Qt::ItemIsSelectable | Qt::ItemIsEnabled; + + QModelIndex sourceIndex = toSourceIndex(proxyIndex); + if(sourceIndex.isValid()) { + if (sourceIndex.column() == SessionModel::ITEM_VALUE) result |= Qt::ItemIsEditable; + + const QString modelType = sourceIndex.data(SessionModel::ModelTypeRole).toString(); + if(modelType == Constants::ParameterType) { + result |= Qt::ItemIsDragEnabled; + } + } + + return result; +} + +QMimeData *ParameterTuningModel::mimeData(const QModelIndexList &proxyIndexes) const +{ + qDebug() << "ParameterTuningModel::mimeData" << proxyIndexes; + QMimeData *mimeData = new QMimeData(); + + foreach(QModelIndex proxyIndex, proxyIndexes) { + if(ParameterItem *parameterItem = getParameterItem(proxyIndex)) { + QString path = FitModelHelper::getParameterItemPath(parameterItem); + mimeData->setData(SessionXML::LinkMimeType, path.toLatin1()); + qDebug() << " FilterPropertyProxy::mimeData" << path; + break; + } + } + return mimeData; +} + +//! Returns ParameterItem from given proxy index + +ParameterItem *ParameterTuningModel::getParameterItem(const QModelIndex &proxyIndex) const +{ + SessionModel *sessionModel = dynamic_cast<SessionModel *>(sourceModel()); + Q_ASSERT(sessionModel); + + QModelIndex sourceIndex = toSourceIndex(proxyIndex); + if(sourceIndex.column() == 0) { + return dynamic_cast<ParameterItem *>(sessionModel->itemForIndex(sourceIndex)); + } + return nullptr; +} diff --git a/GUI/coregui/Models/ParameterTuningModel.h b/GUI/coregui/Models/ParameterTuningModel.h new file mode 100644 index 0000000000000000000000000000000000000000..b7a01c3f380c27279372f688f803ed5aa4a16283 --- /dev/null +++ b/GUI/coregui/Models/ParameterTuningModel.h @@ -0,0 +1,56 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Models/ParameterTuningModel.h +//! @brief Declares class ParameterTuningModel +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2016 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov +//! @authors Walter Van Herck, Joachim Wuttke +// +// ************************************************************************** // + +#ifndef PARAMETERTUNINGMODEL_H +#define PARAMETERTUNINGMODEL_H + +#include "FilterPropertyProxy.h" + +class ParameterItem; + +//! +//! \brief The ParameterTuningModel class represents parameters which can be tuned in real time +//! in ParameterTuningWidget. In the fitting activity context handles dragging of ParameterItem's +//! to the FitParametersWidget. +//! + +class BA_CORE_API_ ParameterTuningModel : public FilterPropertyProxy +{ + Q_OBJECT + +public: + ParameterTuningModel(QObject *parent = 0); + + Qt::ItemFlags flags(const QModelIndex &proxyIndex) const; + QMimeData *mimeData(const QModelIndexList &proxyIndexes) const; + Qt::DropActions supportedDragActions() const; + Qt::DropActions supportedDropActions() const; + + ParameterItem *getParameterItem(const QModelIndex &proxyIndex) const; + +}; + +inline Qt::DropActions ParameterTuningModel::supportedDragActions() const +{ + return Qt::CopyAction; +} + +inline Qt::DropActions ParameterTuningModel::supportedDropActions() const +{ + return Qt::IgnoreAction; +} + +#endif diff --git a/GUI/coregui/Models/SessionItem.cpp b/GUI/coregui/Models/SessionItem.cpp index 3b6f71c934093a6422dc7bae6642b5c128334df5..cbb32dd60e761332b7075d3ff46fcbdde47a238b 100644 --- a/GUI/coregui/Models/SessionItem.cpp +++ b/GUI/coregui/Models/SessionItem.cpp @@ -57,6 +57,9 @@ SessionItem::SessionItem(const QString &modelType) SessionItem::~SessionItem() { + if(m_mapper) + m_mapper->callOnItemDestroy(); + QVector<SessionItem*>::const_iterator it; for (it = m_children.constBegin(); it != m_children.constEnd(); ++it) { SessionItem *child = *it; diff --git a/GUI/coregui/Models/SessionModel.cpp b/GUI/coregui/Models/SessionModel.cpp index 171999d453323bf2aeb6f9c5946385d98a11254d..a23c45852faed9641436703574a77eee55cd62c7 100644 --- a/GUI/coregui/Models/SessionModel.cpp +++ b/GUI/coregui/Models/SessionModel.cpp @@ -144,8 +144,8 @@ QModelIndex SessionModel::parent(const QModelIndex &child) const if (SessionItem *parent_item = child_item->parent()) { if (parent_item == m_root_item) return QModelIndex(); - return createIndex(parent_item->parentRow(), 0, parent_item); -// } + + return createIndex(parent_item->parentRow(), 0, parent_item); } } return QModelIndex(); @@ -177,7 +177,7 @@ bool SessionModel::removeRows(int row, int count, const QModelIndex &parent) QStringList SessionModel::mimeTypes() const { - return QStringList() << SessionXML::MimeType; + return QStringList() << SessionXML::ItemMimeType; } QMimeData *SessionModel::mimeData(const QModelIndexList &indices) const @@ -189,7 +189,7 @@ QMimeData *SessionModel::mimeData(const QModelIndexList &indices) const QByteArray xml_data; QXmlStreamWriter writer(&xml_data); SessionWriter::writeItemAndChildItems(&writer, item); - mime_data->setData(SessionXML::MimeType, qCompress(xml_data, MaxCompression)); + mime_data->setData(SessionXML::ItemMimeType, qCompress(xml_data, MaxCompression)); return mime_data; } return 0; @@ -201,12 +201,12 @@ bool SessionModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, (void)row; if (action == Qt::IgnoreAction) return true; - if (action != Qt::MoveAction || column > 0 || !data || !data->hasFormat(SessionXML::MimeType)) + if (action != Qt::MoveAction || column > 0 || !data || !data->hasFormat(SessionXML::ItemMimeType)) return false; if (!parent.isValid()) return true; QVector<QString> acceptable_child_items = getAcceptableDefaultItemTypes(parent); - QByteArray xml_data = qUncompress(data->data(SessionXML::MimeType)); + QByteArray xml_data = qUncompress(data->data(SessionXML::ItemMimeType)); QXmlStreamReader reader(xml_data); while (!reader.atEnd()) { reader.readNext(); @@ -226,12 +226,12 @@ bool SessionModel::dropMimeData(const QMimeData *data, Qt::DropAction action, in { if (action == Qt::IgnoreAction) return true; - if (action != Qt::MoveAction || column > 0 || !data || !data->hasFormat(SessionXML::MimeType)) + if (action != Qt::MoveAction || column > 0 || !data || !data->hasFormat(SessionXML::ItemMimeType)) return false; if (!canDropMimeData(data, action, row, column, parent)) return false; if (SessionItem *item = itemForIndex(parent)) { - QByteArray xml_data = qUncompress(data->data(SessionXML::MimeType)); + QByteArray xml_data = qUncompress(data->data(SessionXML::ItemMimeType)); QXmlStreamReader reader(xml_data); if (row == -1) row = item->rowCount(); diff --git a/GUI/coregui/Models/SessionModelDelegate.cpp b/GUI/coregui/Models/SessionModelDelegate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..35b128d083d040198a3cc8806a030e8f9e9f1349 --- /dev/null +++ b/GUI/coregui/Models/SessionModelDelegate.cpp @@ -0,0 +1,94 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Models/SessionModelDelegate.cpp +//! @brief Implements class SessionModelDelegate +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2016 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov +//! @authors Walter Van Herck, Joachim Wuttke +// +// ************************************************************************** // + +#include "SessionModelDelegate.h" +#include "SessionModel.h" +#include "ComboProperty.h" +#include "PropertyBrowserUtils.h" +#include "ComboProperty.h" +#include <QDebug> +#include <QApplication> +#include <QPainter> + +SessionModelDelegate::SessionModelDelegate(QWidget *parent) + : QStyledItemDelegate(parent) +{ + +} + +void SessionModelDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + QVariant prop_value = index.model()->data(index, Qt::EditRole); + if(prop_value.canConvert<ComboProperty>()) { + ComboProperty property = prop_value.value<ComboProperty>(); + QStyleOptionViewItem opt = option; + initStyleOption(&opt, index); // calling original method to take into accounts colors etc + opt.text = displayText(property.getValue(), option.locale); // by overriding text with ours + const QWidget *widget = opt.widget; + QStyle *style = widget ? widget->style() : QApplication::style(); + style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, widget); + } else { + QStyledItemDelegate::paint(painter, option, index); + } + +} + +QWidget *SessionModelDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + if (index.data().canConvert<ComboProperty>()) { + ComboPropertyEdit *editor = new ComboPropertyEdit(parent); + ComboProperty combo = index.data().value<ComboProperty>(); + editor->setComboProperty(combo); + connect(editor, SIGNAL(comboPropertyChanged(const ComboProperty &)), + this, SLOT(onComboPropertyChanged(const ComboProperty &))); + return editor; + + } else { + return QStyledItemDelegate::createEditor(parent, option, index); + } + +} + +void SessionModelDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, + const QModelIndex &index) const +{ + if (index.data().canConvert<ComboProperty>()) { + ComboPropertyEdit *comboEditor = qobject_cast<ComboPropertyEdit *>(editor); + model->setData(index, comboEditor->getComboProperty().getVariant()); + } else { + QStyledItemDelegate::setModelData(editor, model, index); + } + +} + +void SessionModelDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const +{ + if (index.data().canConvert<ComboProperty>()) { + //as using custom widget, doing nothing here + } else { + QStyledItemDelegate::setEditorData(editor, index); + } +} + +void SessionModelDelegate::onComboPropertyChanged(const ComboProperty &property) +{ + ComboPropertyEdit *editor = qobject_cast<ComboPropertyEdit *>(sender()); + Q_ASSERT(editor); + emit commitData(editor); + //emit closeEditor(editor); // Qt by default leaves editor alive after editing finished +} diff --git a/GUI/coregui/Models/SessionModelDelegate.h b/GUI/coregui/Models/SessionModelDelegate.h new file mode 100644 index 0000000000000000000000000000000000000000..97146c1895212423d115b82cd6c08523f45423ba --- /dev/null +++ b/GUI/coregui/Models/SessionModelDelegate.h @@ -0,0 +1,51 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Models/SessionModelDelegate.h +//! @brief Declares class SessionModelDelegate +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2016 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov +//! @authors Walter Van Herck, Joachim Wuttke +// +// ************************************************************************** // + +#ifndef SESSIONMODELDELEGATE_H +#define SESSIONMODELDELEGATE_H + +#include "WinDllMacros.h" +#include <QStyledItemDelegate> + +class ComboProperty; + +//! The SessionModelDelegate class presents the content of SessionModel items in +//! standard QTreeView. Extents base QItemDelegate with possibility to show/edit +//! our custom QVariant's. + +class BA_CORE_API_ SessionModelDelegate : public QStyledItemDelegate +{ + Q_OBJECT +public: + SessionModelDelegate(QWidget *parent); + + void paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index ) const; + + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, + const QModelIndex &index) const; + + void setModelData(QWidget *editor, QAbstractItemModel *model, + const QModelIndex &index) const; + + void setEditorData(QWidget *editor, const QModelIndex &index) const; + +private slots: + void onComboPropertyChanged(const ComboProperty &); + +}; + +#endif diff --git a/GUI/coregui/Models/SessionXML.h b/GUI/coregui/Models/SessionXML.h index 20ab00c1e1cf58031af408c3f3edb416cd7d0bb0..f98fe0b51949179895e61280ca5af6e0286e39f5 100644 --- a/GUI/coregui/Models/SessionXML.h +++ b/GUI/coregui/Models/SessionXML.h @@ -27,7 +27,9 @@ class SessionItem; class WarningMessageService; namespace SessionXML { -const QString MimeType = "application/org.bornagainproject.xml.item.z"; +const QString ItemMimeType = "application/org.bornagainproject.xml.item.z"; +const QString LinkMimeType = "application/org.bornagainproject.fittinglink"; + const QString ModelTag("SessionModel"); const QString InstrumentModelTag("InstrumentModel"); const QString SampleModelTag("SampleModel"); diff --git a/GUI/coregui/Models/item_constants.h b/GUI/coregui/Models/item_constants.h index e5d5dbb6246cf985a01fa60d5a3d2b223788df06..a546691953659683486e326f292624a28d738636 100644 --- a/GUI/coregui/Models/item_constants.h +++ b/GUI/coregui/Models/item_constants.h @@ -217,6 +217,12 @@ const ModelType ALIGNMENT_TO_DIRECT_BEAM = "Perpendicular to direct beam"; const ModelType ALIGNMENT_TO_REFLECTED_BEAM = "Perpendicular to reflected beam"; const ModelType ALIGNMENT_TO_REFLECTED_BEAM_DPOS = "Perpendicular to reflected beam (dpos)"; +const ModelType FITPAR_FIXED = "fixed"; +const ModelType FITPAR_LIMITED = "limited"; +const ModelType FITPAR_LOWERLIMITED = "lower limited"; +const ModelType FITPAR_UPPERLIMITED = "upper limited"; +const ModelType FITPAR_FREE = "free"; + } #endif diff --git a/GUI/coregui/Views/FitWidgets/FitParameterWidget.cpp b/GUI/coregui/Views/FitWidgets/FitParameterWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7d4a8370871f09e21751d9e4ec7a89cea04457af --- /dev/null +++ b/GUI/coregui/Views/FitWidgets/FitParameterWidget.cpp @@ -0,0 +1,437 @@ +// ************************************************************************** // +// +// 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 2016 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov +//! @authors Walter Van Herck, Joachim Wuttke +// +// ************************************************************************** // + +#include "FitParameterWidget.h" +#include "JobItem.h" +#include "JobModel.h" +#include "FitSuiteItem.h" +#include "FitParameterItems.h" +#include "ParameterTuningWidget.h" +#include "FilterPropertyProxy.h" +#include "ParameterTreeItems.h" +#include "FitParameterAbsModel.h" +#include "FitModelHelper.h" +#include "SessionModelDelegate.h" +#include "CustomEventFilters.h" +#include "OverlayLabelController.h" +#include <QMenu> +#include <QSignalMapper> +#include <QTreeView> +#include <QVBoxLayout> +#include <QAction> +#include <QDebug> + +FitParameterWidget::FitParameterWidget(QWidget *parent) + : QWidget(parent) + , m_treeView(new QTreeView) + , m_jobItem(0) + , m_tuningWidget(0) + , m_createFitParAction(0) + , m_removeFromFitParAction(0) + , m_removeFitParAction(0) + , m_signalMapper(0) + , m_fitParameterModel(0) + , m_delegate(new SessionModelDelegate(this)) + , m_keyboardFilter(new DeleteEventFilter(this)) + , m_infoLabel(new OverlayLabelController(this)) +{ + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(m_treeView); + setLayout(layout); + init_actions(); + + m_treeView->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_treeView->setSelectionBehavior(QAbstractItemView::SelectRows); + m_treeView->setContextMenuPolicy(Qt::CustomContextMenu); + m_treeView->setItemDelegate(m_delegate); + m_treeView->setDragEnabled(true); + m_treeView->setDragDropMode(QAbstractItemView::DragDrop); + m_treeView->installEventFilter(m_keyboardFilter); + + connect(m_treeView, SIGNAL(customContextMenuRequested(const QPoint &)), + this, SLOT(onFitParameterTreeContextMenu(const QPoint &))); + + m_infoLabel->setArea(m_treeView); + m_infoLabel->setText(QStringLiteral("Drop parameter(s) to fit here")); +} + +void FitParameterWidget::setItem(JobItem *jobItem) +{ + if(jobItem == m_jobItem) { + return; + } + + else { + m_jobItem = jobItem; + if (!m_jobItem) return; + + init_fit_containers(); + init_fit_model(); + } +} + +//! Sets ParameterTuningWidget to be able to provide it with context menu and steer +//! it behaviour in the course of fit settings or fit runnig + +void FitParameterWidget::setParameterTuningWidget(ParameterTuningWidget *tuningWidget) +{ + if(tuningWidget == m_tuningWidget) { + return; + + } else { + if(m_tuningWidget) + disconnect(m_tuningWidget, SIGNAL(itemContextMenuRequest(QPoint)), + this, SLOT(onTuningWidgetContextMenu(QPoint))); + + m_tuningWidget = tuningWidget; + if(!m_tuningWidget) return; + + connect(m_tuningWidget, SIGNAL(itemContextMenuRequest(QPoint)), + this, SLOT(onTuningWidgetContextMenu(QPoint)), Qt::UniqueConnection); + } +} + +//! Creates context menu for ParameterTuningWidget + +void FitParameterWidget::onTuningWidgetContextMenu(const QPoint &point) +{ + QMenu menu; + initTuningWidgetContextMenu(menu); + menu.exec(point); + setActionsEnabled(true); +} + +//! Creates context menu for the tree with fit parameters + +void FitParameterWidget::onFitParameterTreeContextMenu(const QPoint &point) +{ + QMenu menu; + initFitParameterTreeContextMenu(menu); + menu.exec(m_treeView->mapToGlobal(point+ QPoint(2, 22))); + setActionsEnabled(true); +} + +void FitParameterWidget::onTuningWidgetSelectionChanged(const QItemSelection &selection) +{ + Q_UNUSED(selection); +} + +//! Propagates selection form the tree with fit parameters to the tuning widget + +void FitParameterWidget::onFitParametersSelectionChanged(const QItemSelection &selection) +{ + Q_UNUSED(selection); + qDebug() << "onFitParametersSelectionChanged ->"; + if (selection.indexes().isEmpty()) + return; + + foreach(QModelIndex index, selection.indexes()) { + m_tuningWidget->selectionModel()->clearSelection(); + SessionItem *item = m_fitParameterModel->itemForIndex(index); + if(item->parent()->modelType() == Constants::FitParameterLinkType) { + QString link = item->parent()->getItemValue(FitParameterLinkItem::P_LINK).toString(); + m_tuningWidget->makeSelected(FitModelHelper::getParameterItem(m_jobItem->fitParameterContainerItem(), link)); + } + qDebug() << "XXX index" << index << item->modelType(); + + } + +} + +//! Creates fit parameters for all selected ParameterItem's in tuning widget + +void FitParameterWidget::onCreateFitParAction() +{ + foreach(ParameterItem *item, m_tuningWidget->getSelectedParameters()) { + if(!FitModelHelper::getFitParameterItem(m_jobItem->fitParameterContainerItem(), item)) { + FitModelHelper::createFitParameter(m_jobItem->fitParameterContainerItem(), item); + } + } +} + +//! All ParameterItem's selected in tuning widget will be removed from link section of +//! corresponding fitParameterItem. + +void FitParameterWidget::onRemoveFromFitParAction() +{ + foreach(ParameterItem *item, m_tuningWidget->getSelectedParameters()) { + if(FitModelHelper::getFitParameterItem(m_jobItem->fitParameterContainerItem(), item)) { + FitModelHelper::removeFromFitParameters(m_jobItem->fitParameterContainerItem(), item); + } + } +} + +//! All selected FitParameterItem's of FitParameterItemLink's will be removed + +void FitParameterWidget::onRemoveFitParAction() +{ + FitParameterContainerItem *container = m_jobItem->fitParameterContainerItem(); + + // retrieve both, selected FitParameterItem and FitParameterItemLink + QVector<FitParameterLinkItem *> linksToRemove = selectedFitParameterLinks(); + QVector<FitParameterItem *> itemsToRemove = selectedFitParameters(); + + foreach(FitParameterLinkItem *item, linksToRemove) { + container->model()->removeRow(item->index().row(), item->index().parent()); + } + + foreach(FitParameterItem *item, itemsToRemove) { + container->model()->removeRow(item->index().row(), item->index().parent()); + } +} + +//! Add all selected parameters to fitParameter with given index + +void FitParameterWidget::onAddToFitParAction(int ipar) +{ + QStringList fitParNames + = FitModelHelper::getFitParameterNames(m_jobItem->fitParameterContainerItem()); + foreach (ParameterItem *item, m_tuningWidget->getSelectedParameters()) { + FitModelHelper::addToFitParameter(m_jobItem->fitParameterContainerItem(), item, + fitParNames.at(ipar)); + } +} + +void FitParameterWidget::onFitParameterModelChange() +{ + qDebug() << "FitParameterWidget::onFitParameterModelChange()"; + spanParameters(); + updateInfoLabel(); +} + + +//! Context menu reimplemented to suppress the default one + +void FitParameterWidget::contextMenuEvent(QContextMenuEvent *event) +{ + Q_UNUSED(event); +} + +void FitParameterWidget::init_actions() +{ + m_createFitParAction = new QAction(QStringLiteral("Create fit parameter"), this); + connect(m_createFitParAction, SIGNAL(triggered()), this, SLOT(onCreateFitParAction())); + + m_removeFromFitParAction = new QAction(QStringLiteral("Remove from fit parameters"), this); + connect(m_removeFromFitParAction, SIGNAL(triggered()), this, SLOT(onRemoveFromFitParAction())); + + m_removeFitParAction = new QAction(QStringLiteral("Remove fit parameter"), this); + connect(m_removeFitParAction, SIGNAL(triggered()), this, SLOT(onRemoveFitParAction())); + + m_signalMapper = new QSignalMapper(this); + connect(m_signalMapper, SIGNAL(mapped(int)), this, SLOT(onAddToFitParAction(int))); + + connect(m_keyboardFilter, SIGNAL(removeItem()), this, SLOT(onRemoveFitParAction())); +} + +//! Fills context menu for ParameterTuningWidget with content. + +void FitParameterWidget::initTuningWidgetContextMenu(QMenu &menu) +{ + m_removeFromFitParAction->setEnabled(canRemoveFromFitParameters()); + m_createFitParAction->setEnabled(canCreateFitParameter()); + + menu.addAction(m_createFitParAction); + QMenu *addToFitParMenu = menu.addMenu("Add to existing fit parameter"); + + QStringList fitParNames + = FitModelHelper::getFitParameterNames(m_jobItem->fitParameterContainerItem()); + if(fitParNames.isEmpty() || canCreateFitParameter()==false) { + addToFitParMenu->setEnabled(false); + } + + for(int i =0; i<fitParNames.count(); ++i) { + QAction *action = new QAction(QString("to ").append(fitParNames.at(i)), addToFitParMenu); + connect(action, SIGNAL(triggered()), m_signalMapper, SLOT(map())); + m_signalMapper->setMapping(action, i); + addToFitParMenu->addAction(action); + } + + menu.addSeparator(); + menu.addAction(m_removeFromFitParAction); +} + +//! Fills context menu for FitParameterTree with content. + +void FitParameterWidget::initFitParameterTreeContextMenu(QMenu &menu) +{ + menu.addAction(m_removeFitParAction); +} + +//! Initializes FitParameterModel and its tree. + +void FitParameterWidget::init_fit_model() +{ + m_treeView->setModel(0); + + delete m_fitParameterModel; + m_fitParameterModel = new FitParameterProxyModel(m_jobItem->fitParameterContainerItem(), + m_jobItem->fitParameterContainerItem()->model()); + m_treeView->setModel(m_fitParameterModel); + + connect(m_fitParameterModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)), + this, SLOT(onFitParameterModelChange())); + connect(m_fitParameterModel, SIGNAL(modelReset()), this, SLOT(onFitParameterModelChange())); + + onFitParameterModelChange(); + connectFitParametersSelection(true); +} + +//! Adds to JobItem all fit containers, if necessary. + +void FitParameterWidget::init_fit_containers() +{ + SessionItem *fitSuiteItem = m_jobItem->getItem(JobItem::T_FIT_SUITE); + if (!fitSuiteItem) { + fitSuiteItem = m_jobItem->model()->insertNewItem( + Constants::FitSuiteType, m_jobItem->index(), -1, JobItem::T_FIT_SUITE); + } + Q_ASSERT(fitSuiteItem); + + SessionItem *parsContainerItem = fitSuiteItem->getItem(FitSuiteItem::T_FIT_PARAMETERS); + if (!parsContainerItem) { + parsContainerItem = fitSuiteItem->model()->insertNewItem( + Constants::FitParameterContainerType, fitSuiteItem->index(), -1, + FitSuiteItem::T_FIT_PARAMETERS); + } +} + +//! Returns true if tuning widget contains selected ParameterItem's which can be used to create +//! a fit parameter (i.e. it is not linked with some fit parameter already). + +bool FitParameterWidget::canCreateFitParameter() +{ + QVector<ParameterItem *> selected = m_tuningWidget->getSelectedParameters(); + foreach(ParameterItem *item, selected) { + if(FitModelHelper::getFitParameterItem( + m_jobItem->fitParameterContainerItem(), item) == nullptr) + return true; + } + return false; +} + +//! Returns true if tuning widget contains selected ParameterItem's which can be removed from +//! fit parameters. + +bool FitParameterWidget::canRemoveFromFitParameters() +{ + QVector<ParameterItem *> selected = m_tuningWidget->getSelectedParameters(); + foreach(ParameterItem *item, selected) { + if(FitModelHelper::getFitParameterItem(m_jobItem->fitParameterContainerItem(), item)) + return true; + } + return false; +} + +//! Enables/disables all context menu actions. + +void FitParameterWidget::setActionsEnabled(bool value) +{ + m_createFitParAction->setEnabled(value); + m_removeFromFitParAction->setEnabled(value); + m_removeFitParAction->setEnabled(value); +} + +//! Returns list of FitParameterItem's currently selected in FitParameterItem tree + +QVector<FitParameterItem *> FitParameterWidget::selectedFitParameters() +{ + QVector<FitParameterItem *> result; + QModelIndexList indexes = m_treeView->selectionModel()->selectedIndexes(); + foreach(QModelIndex index, indexes) { + if(SessionItem *item = m_fitParameterModel->itemForIndex(index)) { + if(item->modelType() == Constants::FitParameterType) { + FitParameterItem *fitParItem = dynamic_cast<FitParameterItem *>(item); + Q_ASSERT(fitParItem); + result.push_back(fitParItem); + } + } + } + return result; +} + +//! Returns links of FitParameterLink's item selected in FitParameterItem tree + +QVector<FitParameterLinkItem *> FitParameterWidget::selectedFitParameterLinks() +{ + QVector<FitParameterLinkItem *> result; + QModelIndexList indexes = m_treeView->selectionModel()->selectedIndexes(); + foreach (QModelIndex index, indexes) { + if (SessionItem *item = m_fitParameterModel->itemForIndex(index)) { + if (item->parent()->modelType() == Constants::FitParameterLinkType) { + FitParameterLinkItem *fitParItem + = dynamic_cast<FitParameterLinkItem *>(item->parent()); + Q_ASSERT(fitParItem); + result.push_back(fitParItem); + } + } + } + return result; +} + +//! Makes first column in FitParameterItem's tree related to ParameterItem link occupy whole space. + +void FitParameterWidget::spanParameters() +{ + m_treeView->expandAll(); + for (int i = 0; i < m_fitParameterModel->rowCount(QModelIndex()); i++){ + QModelIndex parameter = m_fitParameterModel->index(i,0,QModelIndex()); + if (!parameter.isValid()) + break; + int childRowCount = m_fitParameterModel->rowCount(parameter); + if (childRowCount > 0){ + for (int j = 0; j < childRowCount; j++) { + m_treeView->setFirstColumnSpanned(j, parameter, true); + } + } + } +} + +//! Places overlay label on top of tree view, if there is no fit parameters +void FitParameterWidget::updateInfoLabel() +{ + Q_ASSERT(m_jobItem); + bool is_to_show_label = m_jobItem->fitParameterContainerItem()->isEmpty(); + m_infoLabel->setShown(is_to_show_label); +} + + +void FitParameterWidget::connectTuningWidgetSelection(bool active) +{ + Q_ASSERT(m_tuningWidget); + + if (active) { + connect(m_tuningWidget->selectionModel(), + SIGNAL(selectionChanged(QItemSelection,QItemSelection)), + this, SLOT(onTuningWidgetSelectionChanged(QItemSelection)), Qt::UniqueConnection); + } else { + disconnect(m_tuningWidget->selectionModel(), + SIGNAL(selectionChanged(QItemSelection,QItemSelection)), + this, SLOT(onTuningWidgetSelectionChanged(QItemSelection))); + } +} + +void FitParameterWidget::connectFitParametersSelection(bool active) { + if (active) { + connect(m_treeView->selectionModel(), + SIGNAL(selectionChanged(QItemSelection,QItemSelection)), + this, SLOT(onFitParametersSelectionChanged(QItemSelection)), Qt::UniqueConnection); + } else { + disconnect(m_treeView->selectionModel(), + SIGNAL(selectionChanged(QItemSelection,QItemSelection)), + this, SLOT(onFitParametersSelectionChanged(QItemSelection))); + } +} diff --git a/GUI/coregui/Views/FitWidgets/FitParametersWidget.h b/GUI/coregui/Views/FitWidgets/FitParameterWidget.h similarity index 57% rename from GUI/coregui/Views/FitWidgets/FitParametersWidget.h rename to GUI/coregui/Views/FitWidgets/FitParameterWidget.h index 4e7f30d6158a92ef0df391c94f081aeafccf5053..d273114c19ef033b348f7872ee1f13505a006f3f 100644 --- a/GUI/coregui/Views/FitWidgets/FitParametersWidget.h +++ b/GUI/coregui/Views/FitWidgets/FitParameterWidget.h @@ -2,8 +2,8 @@ // // BornAgain: simulate and fit scattering at grazing incidence // -//! @file coregui/Views/FitWidgets/FitParametersWidget.h -//! @brief Declares class FitParametersWidget +//! @file coregui/Views/FitWidgets/FitParameterWidget.h +//! @brief Declares class FitParameterWidget //! //! @homepage http://www.bornagainproject.org //! @license GNU General Public License v3 or higher (see COPYING) @@ -14,66 +14,88 @@ // // ************************************************************************** // -#ifndef FITPARAMETERSWIDGET_H -#define FITPARAMETERSWIDGET_H +#ifndef FITPARAMETERWIDGET_H +#define FITPARAMETERWIDGET_H #include "WinDllMacros.h" #include <QWidget> #include <memory> class JobItem; -class ModelTuningWidget; +class ParameterTuningWidget; class QTreeView; class QSignalMapper; class QAction; class QMenu; -class FitParameterModel; +class FitParameterProxyModel; class ParameterItem; +class FitParameterItem; +class FitParameterLinkItem; class QItemSelection; +class SessionModelDelegate; +class DeleteEventFilter; +class OverlayLabelController; //! The FitParametersWidget class contains a tree view to set fit parameters (fix/release, //! starting value, min/max bounds). It occupies buttom right corner of JobView. -class BA_CORE_API_ FitParametersWidget : public QWidget +class BA_CORE_API_ FitParameterWidget : public QWidget { Q_OBJECT public: - FitParametersWidget(QWidget *parent = 0); - ~FitParametersWidget(); + FitParameterWidget(QWidget *parent = 0); void setItem(JobItem *jobItem); - void setModelTuningWidget(ModelTuningWidget *tuningWidget); + void setParameterTuningWidget(ParameterTuningWidget *tuningWidget); public slots: void onTuningWidgetContextMenu(const QPoint &point); + void onFitParameterTreeContextMenu(const QPoint &point); void onTuningWidgetSelectionChanged(const QItemSelection&selection); void onFitParametersSelectionChanged(const QItemSelection &selection); private slots: void onCreateFitParAction(); void onRemoveFromFitParAction(); + void onRemoveFitParAction(); void onAddToFitParAction(int ipar); + void onFitParameterModelChange(); + +protected: + void contextMenuEvent(QContextMenuEvent *event); private: void init_actions(); void initTuningWidgetContextMenu(QMenu &menu); - void stop_tracking_job_item(); - void init_job_item(); - void spanParameters(); - bool isCreateFitParameterPossible(); + void initFitParameterTreeContextMenu(QMenu &menu); + + void init_fit_model(); + void init_fit_containers(); + + bool canCreateFitParameter(); + bool canRemoveFromFitParameters(); + void setActionsEnabled(bool value); void connectTuningWidgetSelection(bool active); void connectFitParametersSelection(bool active); - QVector<ParameterItem *> getSelectedParameters(); + QVector<FitParameterItem *> selectedFitParameters(); + QVector<FitParameterLinkItem *> selectedFitParameterLinks(); + + void spanParameters(); + void updateInfoLabel(); QTreeView *m_treeView; JobItem *m_jobItem; - ModelTuningWidget *m_tuningWidget; + ParameterTuningWidget *m_tuningWidget; QAction *m_createFitParAction; QAction *m_removeFromFitParAction; + QAction *m_removeFitParAction; QSignalMapper *m_signalMapper; - std::unique_ptr<FitParameterModel> m_fitParameterModel; + FitParameterProxyModel* m_fitParameterModel; + SessionModelDelegate *m_delegate; + DeleteEventFilter *m_keyboardFilter; + OverlayLabelController *m_infoLabel; }; #endif diff --git a/GUI/coregui/Views/FitWidgets/FitParametersWidget.cpp b/GUI/coregui/Views/FitWidgets/FitParametersWidget.cpp deleted file mode 100644 index cbca886872e83230942f0111a60c888e837adae5..0000000000000000000000000000000000000000 --- a/GUI/coregui/Views/FitWidgets/FitParametersWidget.cpp +++ /dev/null @@ -1,342 +0,0 @@ -// ************************************************************************** // -// -// BornAgain: simulate and fit scattering at grazing incidence -// -//! @file coregui/Views/FitWidgets/FitParametersWidget.cpp -//! @brief Implements class FitParametersWidget -//! -//! @homepage http://www.bornagainproject.org -//! @license GNU General Public License v3 or higher (see COPYING) -//! @copyright Forschungszentrum Jülich GmbH 2016 -//! @authors Scientific Computing Group at MLZ Garching -//! @authors Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov -//! @authors Walter Van Herck, Joachim Wuttke -// -// ************************************************************************** // - -#include "FitParametersWidget.h" -#include "JobItem.h" -#include "JobModel.h" -#include "FitSuiteItem.h" -#include "FitParameterItems.h" -#include "FitParameterModel.h" -#include "ModelTuningWidget.h" -#include "FilterPropertyProxy.h" -#include "ParameterTreeItems.h" -#include <QMenu> -#include <QSignalMapper> -#include <QTreeView> -#include <QVBoxLayout> -#include <QAction> -#include <QDebug> - -FitParametersWidget::FitParametersWidget(QWidget *parent) - : QWidget(parent) - , m_treeView(new QTreeView) - , m_jobItem(0) - , m_tuningWidget(0) - , m_createFitParAction(0) - , m_removeFromFitParAction(0) - , m_signalMapper(0) -{ - QVBoxLayout *layout = new QVBoxLayout; - layout->addWidget(m_treeView); - setLayout(layout); - init_actions(); -} - -FitParametersWidget::~FitParametersWidget() -{ - qDebug() << "FitParametersWidget::~FitParametersWidget()"; - -} - -void FitParametersWidget::setItem(JobItem *jobItem) -{ - if(jobItem == m_jobItem) { - return; - } - - else { - if(m_jobItem) - stop_tracking_job_item(); - - m_jobItem = jobItem; - if (!m_jobItem) return; - - init_job_item(); - - } -} - -//! Our FitParametersWidget will provide model tuning widget with context menu. -//! It also will take care of cross-item-selection between parameterTuningTree -//! and fitParametersTree -void FitParametersWidget::setModelTuningWidget(ModelTuningWidget *tuningWidget) -{ - if(tuningWidget == m_tuningWidget) { - return; - } - - else { - if(m_tuningWidget) { - disconnect(m_tuningWidget, - SIGNAL(itemContextMenuRequest(QPoint)), - this, - SLOT(onTuningWidgetContextMenu(QPoint))); - } - - m_tuningWidget = tuningWidget; - if(!m_tuningWidget) return; - - connect(m_tuningWidget, - SIGNAL(itemContextMenuRequest(QPoint)), - this, - SLOT(onTuningWidgetContextMenu(QPoint)), Qt::UniqueConnection); - - } - -} - -void FitParametersWidget::onTuningWidgetContextMenu(const QPoint &point) -{ - QMenu menu; - initTuningWidgetContextMenu(menu); - menu.exec(point); - setActionsEnabled(true); -} - -void FitParametersWidget::onTuningWidgetSelectionChanged(const QItemSelection &selection) -{ - Q_UNUSED(selection); -} - -void FitParametersWidget::onFitParametersSelectionChanged(const QItemSelection &selection) -{ - Q_UNUSED(selection); - qDebug() << "onFitParametersSelectionChanged ->"; -// if (selection.indexes().isEmpty()) -// return; -// QModelIndex index = selection.indexes().last(); -// qDebug() << "XXX index" << selection.indexes() << index; -// QModelIndex newSelection = QModelIndex(); -// if (index.isValid() && index.parent().isValid()) { -// SessionItem *val = m_fitParameterModel->itemForIndex(index); -//// QString link = val->getItemValue(FitParameterLinkItem::P_LINK).toString(); -// qDebug() << "XXX val" << val->modelType() << val->displayName() << val->value(); -//// 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(); - -} - -void FitParametersWidget::onCreateFitParAction() -{ - foreach(ParameterItem *item, getSelectedParameters()) { - if(!m_fitParameterModel->getFitParameterItem(item)) { - m_fitParameterModel->createFitParameter(item); - } - } - spanParameters(); -} - -void FitParametersWidget::onRemoveFromFitParAction() -{ - foreach(ParameterItem *item, getSelectedParameters()) { - if(m_fitParameterModel->getFitParameterItem(item)) { - m_fitParameterModel->removeFromFitParameters(item); - } - } -} - -//! Add all selected parameters to fitParameter with given index -void FitParametersWidget::onAddToFitParAction(int ipar) -{ - QStringList fitParNames = m_fitParameterModel->getFitParameterNames(); - foreach(ParameterItem *item, getSelectedParameters()) { - m_fitParameterModel->addToFitParameter(item, fitParNames.at(ipar)); - } - spanParameters(); -} - -void FitParametersWidget::init_actions() -{ - m_createFitParAction = new QAction(QStringLiteral("Create fit parameter"), this); - connect(m_createFitParAction, SIGNAL(triggered()), this, SLOT(onCreateFitParAction())); - - m_removeFromFitParAction = new QAction(QStringLiteral("Remove from fit parameters"), this); - connect(m_removeFromFitParAction, SIGNAL(triggered()), this, SLOT(onRemoveFromFitParAction())); - - m_signalMapper = new QSignalMapper(this); - connect(m_signalMapper, SIGNAL(mapped(int)), this, SLOT(onAddToFitParAction(int))); - -} - -void FitParametersWidget::initTuningWidgetContextMenu(QMenu &menu) -{ - Q_ASSERT(m_jobItem); - - if(isCreateFitParameterPossible()) { - m_removeFromFitParAction->setEnabled(false); - } else { - m_createFitParAction->setEnabled(false); - } - - menu.addAction(m_createFitParAction); - QMenu *addToFitParMenu = menu.addMenu("Add to existing fit parameter"); - - QStringList fitParNames = m_fitParameterModel->getFitParameterNames(); - if(fitParNames.isEmpty() || isCreateFitParameterPossible()==false) { - addToFitParMenu->setEnabled(false); - } - - for(int i =0; i<fitParNames.count(); ++i) { - QAction *action = new QAction(QString("to ").append(fitParNames.at(i)), addToFitParMenu); - connect(action, SIGNAL(triggered()), m_signalMapper, SLOT(map())); - m_signalMapper->setMapping(action, i); - addToFitParMenu->addAction(action); - } - - menu.addSeparator(); - menu.addAction(m_removeFromFitParAction); -} - -//! stop tracking job item -void FitParametersWidget::stop_tracking_job_item() -{ - Q_ASSERT(m_jobItem); - -} - -//! init job item: create fit containers if necessary, subscribes for item changing -void FitParametersWidget::init_job_item() -{ - SessionItem *fitSuiteItem = m_jobItem->getItem(JobItem::T_FIT_SUITE); - if (!fitSuiteItem) { - fitSuiteItem = m_jobItem->model()->insertNewItem( - Constants::FitSuiteType, m_jobItem->index(), -1, JobItem::T_FIT_SUITE); - } - Q_ASSERT(fitSuiteItem); - - SessionItem *parsContainerItem = fitSuiteItem->getItem(FitSuiteItem::T_FIT_PARAMETERS); - if (!parsContainerItem) { - parsContainerItem = fitSuiteItem->model()->insertNewItem( - Constants::FitParameterContainerType, fitSuiteItem->index(), -1, - FitSuiteItem::T_FIT_PARAMETERS); - } - -// SessionItem *fitPar = parsContainerItem->model()->insertNewItem(Constants::FitParameterType, -// parsContainerItem->index()); - -// Q_ASSERT(fitPar); -// SessionItem *link1 = fitPar->model()->insertNewItem(Constants::FitParameterLinkType, fitPar->index()); -// link1->setItemValue(FitParameterLinkItem::P_LINK, "abc1"); -// SessionItem *link2 = fitPar->model()->insertNewItem(Constants::FitParameterLinkType, fitPar->index()); -// link2->setItemValue(FitParameterLinkItem::P_LINK, "xyz1"); - - m_fitParameterModel.reset(new FitParameterModel(parsContainerItem)); - m_treeView->setModel(m_fitParameterModel.get()); - connectFitParametersSelection(true); - -// m_fitParameterModel->createFitParameter(); -// m_fitParameterModel->createFitParameter(); -// spanParameters(); - - -// m_treeView->setModel(parsContainerItem->model()); -// m_treeView->setRootIndex(parsContainerItem->index()); -// spanParameters(); - -} - -//! Make first column in FitParameterItem's link occupy whole space -void FitParametersWidget::spanParameters() -{ - m_treeView->expandAll(); - for (int i = 0; i < m_fitParameterModel->rowCount(QModelIndex()); i++){ - QModelIndex parameter = m_fitParameterModel->index(i,0,QModelIndex()); - if (!parameter.isValid()) - break; - int childRowCount = m_fitParameterModel->rowCount(parameter); - if (childRowCount > 0){ - for (int j = 0; j < childRowCount; j++) { - m_treeView->setFirstColumnSpanned(j, parameter, true); - } - } - } - -} - -//! Returns true if it is possible to create fit parameter. There should be some ParameterItem's -//! selected in model tuning widget and they should not be in FitParameterContainer already -bool FitParametersWidget::isCreateFitParameterPossible() -{ - QVector<ParameterItem *> selected = getSelectedParameters(); - foreach(ParameterItem *item, selected) { - if(m_fitParameterModel->getFitParameterItem(item) == nullptr) - return true; - } - return false; -} - -void FitParametersWidget::setActionsEnabled(bool value) -{ - m_createFitParAction->setEnabled(value); - m_removeFromFitParAction->setEnabled(value); -} - -//! Returns list of ParameterItem's currently selected in ModelTuningWidget -QVector<ParameterItem *> FitParametersWidget::getSelectedParameters() -{ - QVector<ParameterItem *> result; - QModelIndexList proxyIndexes = m_tuningWidget->selectionModel()->selectedIndexes(); - foreach(QModelIndex proxyIndex, proxyIndexes) { - QModelIndex index = FilterPropertyProxy::toSourceIndex(proxyIndex); - if(index.column() != 0) - continue; - - if (ParameterItem *parameterItem - = dynamic_cast<ParameterItem *>(m_jobItem->model()->itemForIndex(index))) { - result.push_back(parameterItem); - } - } - return result; -} - - -void FitParametersWidget::connectTuningWidgetSelection(bool active) -{ - Q_ASSERT(m_tuningWidget); - - if (active) { - connect(m_tuningWidget->selectionModel(), - SIGNAL(selectionChanged(QItemSelection,QItemSelection)), - this, SLOT(onTuningWidgetSelectionChanged(QItemSelection)), Qt::UniqueConnection); - } else { - disconnect(m_tuningWidget->selectionModel(), - SIGNAL(selectionChanged(QItemSelection,QItemSelection)), - this, SLOT(onTuningWidgetSelectionChanged(QItemSelection))); - } -} - -void FitParametersWidget::connectFitParametersSelection(bool active) { - if (active) { - connect(m_treeView->selectionModel(), - SIGNAL(selectionChanged(QItemSelection,QItemSelection)), - this, SLOT(onFitParametersSelectionChanged(QItemSelection)), Qt::UniqueConnection); - } else { - disconnect(m_treeView->selectionModel(), - SIGNAL(selectionChanged(QItemSelection,QItemSelection)), - this, SLOT(onFitParametersSelectionChanged(QItemSelection))); - - } -} diff --git a/GUI/coregui/Views/FitWidgets/FitSuiteWidget.cpp b/GUI/coregui/Views/FitWidgets/FitSuiteWidget.cpp index 997dafbc3c1a4143aef7af860c77ea1566889808..52822f0f3b0f87c996d075e816dd3a96fff504bf 100644 --- a/GUI/coregui/Views/FitWidgets/FitSuiteWidget.cpp +++ b/GUI/coregui/Views/FitWidgets/FitSuiteWidget.cpp @@ -19,7 +19,7 @@ #include "JobItem.h" #include "FitSuiteItem.h" #include "FitParameterItems.h" -#include "FitParametersWidget.h" +#include "FitParameterWidget.h" #include "RunFitManager.h" #include "GUIFitObserver.h" #include "DomainFittingBuilder.h" @@ -37,7 +37,7 @@ FitSuiteWidget::FitSuiteWidget(JobModel *jobModel, QWidget *parent) : QWidget(parent) , m_tabWidget(new QTabWidget) - , m_fitParametersWidget(new FitParametersWidget(this)) + , m_fitParametersWidget(new FitParameterWidget(this)) , m_minimizerSettingsWidget(new MinimizerSettingsWidget(this)) , m_fitResultsWidget(new FitResultsWidget(this)) , m_jobModel(jobModel) @@ -68,11 +68,11 @@ void FitSuiteWidget::setItem(JobItem *jobItem) m_fitParametersWidget->setItem(jobItem); } -void FitSuiteWidget::setModelTuningWidget(ModelTuningWidget *tuningWidget) +void FitSuiteWidget::setModelTuningWidget(ParameterTuningWidget *tuningWidget) { Q_ASSERT(m_fitParametersWidget); Q_ASSERT(tuningWidget); - m_fitParametersWidget->setModelTuningWidget(tuningWidget); + m_fitParametersWidget->setParameterTuningWidget(tuningWidget); } void FitSuiteWidget::onError(const QString &text) diff --git a/GUI/coregui/Views/FitWidgets/FitSuiteWidget.h b/GUI/coregui/Views/FitWidgets/FitSuiteWidget.h index 5f71e324cad44a9b077eb66203fa32e4269b4b7a..0bcbdfe86f42358fa00898a5bba95e267727d10c 100644 --- a/GUI/coregui/Views/FitWidgets/FitSuiteWidget.h +++ b/GUI/coregui/Views/FitWidgets/FitSuiteWidget.h @@ -24,10 +24,10 @@ class QTabWidget; class JobModel; class JobItem; -class FitParametersWidget; +class FitParameterWidget; class MinimizerSettingsWidget; class FitResultsWidget; -class ModelTuningWidget; +class ParameterTuningWidget; class RunFitManager; class GUIFitObserver; template <class T> class OutputData; @@ -46,7 +46,7 @@ public: ~FitSuiteWidget(); void setItem(JobItem *jobItem); - void setModelTuningWidget(ModelTuningWidget *tuningWidget); + void setModelTuningWidget(ParameterTuningWidget *tuningWidget); signals: void fittingStarted(); @@ -72,7 +72,7 @@ private: void connectSignals(); QTabWidget *m_tabWidget; - FitParametersWidget *m_fitParametersWidget; + FitParameterWidget *m_fitParametersWidget; MinimizerSettingsWidget *m_minimizerSettingsWidget; FitResultsWidget *m_fitResultsWidget; JobModel *m_jobModel; diff --git a/GUI/coregui/Views/FitWidgets/ObsoleteFitParameterWidget.cpp b/GUI/coregui/Views/FitWidgets/ObsoleteFitParameterWidget.cpp index 00786e2d35bf96488c3527ccbff179794cc0e5e7..315066c7061e36ab82673728694f6d1c0038f953 100644 --- a/GUI/coregui/Views/FitWidgets/ObsoleteFitParameterWidget.cpp +++ b/GUI/coregui/Views/FitWidgets/ObsoleteFitParameterWidget.cpp @@ -19,10 +19,10 @@ #include "ObsoleteFitParameterItems.h" #include "ObsoleteFitParameterModel.h" #include "ObsoleteFitSelectorModel.h" -#include "DeleteEventFilter.h" #include "ObsoleteMinimizerSettingsWidget.h" #include "minisplitter.h" #include "ModelPath.h" +#include "CustomEventFilters.h" #include <QVBoxLayout> #include <QTreeView> #include <QSplitter> diff --git a/GUI/coregui/Views/FitWidgets/FitTools.cpp b/GUI/coregui/Views/FitWidgets/ObsoleteFitTools.cpp similarity index 92% rename from GUI/coregui/Views/FitWidgets/FitTools.cpp rename to GUI/coregui/Views/FitWidgets/ObsoleteFitTools.cpp index 8b5b2a382e0d2059e3d3d1185f1cbd8d2ee289e5..2d3d78648985d49b02f31b73d875c6f25d2a05d5 100644 --- a/GUI/coregui/Views/FitWidgets/FitTools.cpp +++ b/GUI/coregui/Views/FitWidgets/ObsoleteFitTools.cpp @@ -14,6 +14,7 @@ // // ************************************************************************** // +#include "ObsoleteFitTools.h" #include "JobItem.h" #include "FilterPropertyProxy.h" #include "JobModel.h" @@ -31,8 +32,6 @@ #include "SessionItem.h" #include "ObsoleteRealDataWindow.h" -#include "FitTools.h" - #include <boost/scoped_ptr.hpp> #include <QHBoxLayout> #include <QLabel> @@ -45,7 +44,7 @@ #include <QStack> -FitTools::FitTools(JobModel *jobModel, QWidget *parent) +ObsoleteFitTools::ObsoleteFitTools(JobModel *jobModel, QWidget *parent) : QWidget(parent) , m_jobModel(jobModel) , m_currentJobItem(0) @@ -89,7 +88,7 @@ FitTools::FitTools(JobModel *jobModel, QWidget *parent) this->setLayout(layout); } -void FitTools::setCurrentItem(JobItem *item, QItemSelectionModel *selection) +void ObsoleteFitTools::setCurrentItem(JobItem *item, QItemSelectionModel *selection) { m_currentJobItem = item; m_selectionModel = selection; @@ -102,7 +101,7 @@ void FitTools::setCurrentItem(JobItem *item, QItemSelectionModel *selection) m_realDataWindow->setItem(dynamic_cast<IntensityDataItem*>(item->getItem(JobItem::T_REALDATA))); } -void FitTools::onStartClick() +void ObsoleteFitTools::onStartClick() { if (!m_currentJobItem) return; @@ -158,31 +157,31 @@ void FitTools::onStartClick() } } -void FitTools::onFittingStarted() +void ObsoleteFitTools::onFittingStarted() { m_startButton->setEnabled(false); m_stopButton->setEnabled(true); } -void FitTools::onFittingFinished() +void ObsoleteFitTools::onFittingFinished() { m_startButton->setEnabled(true); m_stopButton->setEnabled(false); } -void FitTools::onStopClicked() +void ObsoleteFitTools::onStopClicked() { m_manager->interruptFitting(); } -void FitTools::onError(const QString &text) +void ObsoleteFitTools::onError(const QString &text) { QMessageBox box; box.setText(text); box.exec(); } -void FitTools::onUpdatePlots(OutputData<double> *sim, OutputData<double> *) +void ObsoleteFitTools::onUpdatePlots(OutputData<double> *sim, OutputData<double> *) { // hack to preserve axis information auto data = m_currentJobItem->getIntensityDataItem()->getOutputData()->clone(); @@ -191,7 +190,7 @@ void FitTools::onUpdatePlots(OutputData<double> *sim, OutputData<double> *) m_observer->finishedPlotting(); } -void FitTools::onUpdateParameters(const QStringList ¶meters, QVector<double> values) +void ObsoleteFitTools::onUpdateParameters(const QStringList ¶meters, QVector<double> values) { // TODO update parameters SessionItem *current = m_currentJobItem->getItem(JobItem::T_PARAMETER_TREE); //this is container @@ -213,7 +212,7 @@ void FitTools::onUpdateParameters(const QStringList ¶meters, QVector<double> } } -void FitTools::onRealData() +void ObsoleteFitTools::onRealData() { m_realDataWindow->show(); } diff --git a/GUI/coregui/Views/FitWidgets/FitTools.h b/GUI/coregui/Views/FitWidgets/ObsoleteFitTools.h similarity index 86% rename from GUI/coregui/Views/FitWidgets/FitTools.h rename to GUI/coregui/Views/FitWidgets/ObsoleteFitTools.h index 92947129a3bc944f552d7816bc4729d6cd407c0a..d537d5403e103fe565d82f471f27cd010ca774ea 100644 --- a/GUI/coregui/Views/FitWidgets/FitTools.h +++ b/GUI/coregui/Views/FitWidgets/ObsoleteFitTools.h @@ -2,8 +2,8 @@ // // BornAgain: simulate and fit scattering at grazing incidence // -//! @file coregui/Views/FitWidgets/FitTools.h -//! @brief Declares class FitTools +//! @file coregui/Views/FitWidgets/ObsoleteFitTools.h +//! @brief Declares class ObsoleteFitTools //! //! @homepage http://www.bornagainproject.org //! @license GNU General Public License v3 or higher (see COPYING) @@ -14,8 +14,8 @@ // // ************************************************************************** // -#ifndef FITTOOLS_H -#define FITTOOLS_H +#ifndef OBSOLETEFITTOOLS_H +#define OBSOLETEFITTOOLS_H #include <QWidget> #include "OutputData.h" @@ -31,12 +31,12 @@ class GUIFitObserver; class QSlider; class ObsoleteRealDataWindow; -class FitTools : public QWidget +class ObsoleteFitTools : public QWidget { Q_OBJECT public: - FitTools(JobModel *jobModel, QWidget *parent = 0); + ObsoleteFitTools(JobModel *jobModel, QWidget *parent = 0); void setCurrentItem(JobItem *item, QItemSelectionModel *selection); diff --git a/GUI/coregui/Views/FitWidgets/TestFitWidgets.cpp b/GUI/coregui/Views/FitWidgets/TestFitWidgets.cpp index e66db3a7177522985022bceb01828ca6085921dc..d111b31374aef30ac1aeb4f507541cb6bddfae6a 100644 --- a/GUI/coregui/Views/FitWidgets/TestFitWidgets.cpp +++ b/GUI/coregui/Views/FitWidgets/TestFitWidgets.cpp @@ -16,23 +16,33 @@ #include "TestFitWidgets.h" #include "mainwindow.h" -#include "ModelTuningWidget.h" -#include "FitParametersWidget.h" +#include "ParameterTuningWidget.h" +#include "FitParameterWidget.h" #include "item_constants.h" #include "JobModel.h" #include "JobItem.h" +#include "FitParameterItems.h" +#include "FitSuiteItem.h" #include <QVBoxLayout> +#include <QHBoxLayout> +#include <QTreeView> TestFitWidgets::TestFitWidgets(MainWindow *mainWindow) : QWidget(mainWindow) , m_mainWindow(mainWindow) - , m_tuningWidget(new ModelTuningWidget(mainWindow->jobModel())) - , m_fitParametersWidget(new FitParametersWidget(this)) + , m_tuningWidget(new ParameterTuningWidget(mainWindow->jobModel())) + , m_fitParametersWidget(new FitParameterWidget(this)) + , m_jobTreeView(new QTreeView) , m_jobItem(0) { QHBoxLayout *hlayout = new QHBoxLayout; hlayout->addWidget(m_tuningWidget); - hlayout->addWidget(m_fitParametersWidget); + + QVBoxLayout *vlayout = new QVBoxLayout; + vlayout->addWidget(m_fitParametersWidget); + vlayout->addWidget(m_jobTreeView); + + hlayout->addLayout(vlayout); setLayout(hlayout); } @@ -43,7 +53,9 @@ void TestFitWidgets::showEvent(QShowEvent *) m_jobItem = jobItem; m_tuningWidget->setItem(jobItem); m_fitParametersWidget->setItem(jobItem); - m_fitParametersWidget->setModelTuningWidget(m_tuningWidget); + m_fitParametersWidget->setParameterTuningWidget(m_tuningWidget); + m_jobTreeView->setModel(m_mainWindow->jobModel()); + m_jobTreeView->setRootIndex(jobItem->fitSuiteItem()->index()); } } diff --git a/GUI/coregui/Views/FitWidgets/TestFitWidgets.h b/GUI/coregui/Views/FitWidgets/TestFitWidgets.h index b53f860697faba66ff124d6e88a552e69d789904..5afd670ba4b54e76df917f6f93af7ff1fdd78f49 100644 --- a/GUI/coregui/Views/FitWidgets/TestFitWidgets.h +++ b/GUI/coregui/Views/FitWidgets/TestFitWidgets.h @@ -21,9 +21,10 @@ #include <QWidget> class MainWindow; -class ModelTuningWidget; -class FitParametersWidget; +class ParameterTuningWidget; +class FitParameterWidget; class JobItem; +class QTreeView; //! TestFitWidgets is a temporary widget (created by mainwindow) //! for testing fitting related widgets. @@ -38,8 +39,9 @@ public: private: MainWindow *m_mainWindow; - ModelTuningWidget *m_tuningWidget; - FitParametersWidget *m_fitParametersWidget; + ParameterTuningWidget *m_tuningWidget; + FitParameterWidget *m_fitParametersWidget; + QTreeView *m_jobTreeView; JobItem *m_jobItem; }; diff --git a/GUI/coregui/Views/InfoWidgets/OverlayLabelController.cpp b/GUI/coregui/Views/InfoWidgets/OverlayLabelController.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5840ca7f7b946cc08453e3dab51f9e427da8562b --- /dev/null +++ b/GUI/coregui/Views/InfoWidgets/OverlayLabelController.cpp @@ -0,0 +1,75 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Views/InfoWidgets/OverlayLabelController.cpp +//! @brief Implements class OverlayLabelController +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2016 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov +//! @authors Walter Van Herck, Joachim Wuttke +// +// ************************************************************************** // + +#include "OverlayLabelController.h" +#include "OverlayLabelWidget.h" +#include <QAbstractScrollArea> +#include <QEvent> +#include <QRect> +#include <QDebug> + +OverlayLabelController::OverlayLabelController(QObject *parent) + : QObject(parent) + , m_label(0) + , m_area(0) +{ + +} + +void OverlayLabelController::setText(const QString &text) +{ + m_text = text; +} + +void OverlayLabelController::setArea(QAbstractScrollArea *area) +{ + m_area = area; + m_area->installEventFilter(this); +} + +//! Shows/removes a label from the controlled widget + +void OverlayLabelController::setShown(bool shown) +{ + if(shown) { + Q_ASSERT(m_area); + if(!m_label) { + m_label = new OverlayLabelWidget(m_area); + m_label->setText(m_text); + updateLabelGeometry(); + m_label->show(); + } + + } else { + delete m_label; + m_label = 0; + } +} + +bool OverlayLabelController::eventFilter(QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::Resize) + updateLabelGeometry(); + + return QObject::eventFilter(obj, event); +} + +void OverlayLabelController::updateLabelGeometry() +{ + if(!m_label || !m_area) return; + m_label->setRectangle(QRect(0, 0, m_area->width(), m_area->height())); + m_label->setPosition(0, 0); +} diff --git a/GUI/coregui/Views/InfoWidgets/OverlayLabelController.h b/GUI/coregui/Views/InfoWidgets/OverlayLabelController.h new file mode 100644 index 0000000000000000000000000000000000000000..45676a0eac211e3f4ce3afc24c9ba5a9a18f2811 --- /dev/null +++ b/GUI/coregui/Views/InfoWidgets/OverlayLabelController.h @@ -0,0 +1,53 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Views/InfoWidgets/OverlayLabelController.h +//! @brief Declares class OverlayLabelController +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2016 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov +//! @authors Walter Van Herck, Joachim Wuttke +// +// ************************************************************************** // + +#ifndef OVERLAYLABELCONTROLLER_H +#define OVERLAYLABELCONTROLLER_H + +#include "WinDllMacros.h" +#include <QObject> +#include <QString> + +class OverlayLabelWidget; +class QAbstractScrollArea; + +//! The OverlayLabelController class controlls appearance of InfoLabelWidget (position, show/hide) +//! on top of some scroll area. + +class BA_CORE_API_ OverlayLabelController : public QObject +{ + Q_OBJECT +public: + OverlayLabelController(QObject *parent = 0); + + void setText(const QString &text); + + void setArea(QAbstractScrollArea *area); + + void setShown(bool shown); + +protected: + bool eventFilter(QObject *obj, QEvent *event); + +private: + void updateLabelGeometry(); + + OverlayLabelWidget *m_label; + QAbstractScrollArea *m_area; + QString m_text; +}; + +#endif diff --git a/GUI/coregui/Views/InfoWidgets/OverlayLabelWidget.cpp b/GUI/coregui/Views/InfoWidgets/OverlayLabelWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6b32ec893f5b3f6fac1c82f56508977c2386d575 --- /dev/null +++ b/GUI/coregui/Views/InfoWidgets/OverlayLabelWidget.cpp @@ -0,0 +1,50 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Views/InfoWidgets/OverlayLabelWidget.cpp +//! @brief Implements class OverlayLabelWidget +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2016 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov +//! @authors Walter Van Herck, Joachim Wuttke +// +// ************************************************************************** // + +#include "OverlayLabelWidget.h" +#include "DesignerHelper.h" +#include <QPainter> +#include <QColor> +#include <QFont> + +OverlayLabelWidget::OverlayLabelWidget(QWidget *parent) + : QWidget(parent) + , m_bounding_rect(QRect(0,0,10,10)) +{ + setAttribute(Qt::WA_TransparentForMouseEvents); +} + +void OverlayLabelWidget::setRectangle(const QRect &rect) +{ + m_bounding_rect = rect; +} + +void OverlayLabelWidget::setPosition(int x, int y) +{ + setGeometry(x, y, m_bounding_rect.width(), m_bounding_rect.height()); +} + +void OverlayLabelWidget::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event); + QPainter painter(this); + painter.setBrush(QColor(Qt::lightGray)); + QFont serifFont("Monospace", DesignerHelper::getHeaderFontSize(), + QFont::Normal, true); + painter.setFont(serifFont); +// painter.drawRect(m_bounding_rect); + painter.drawText(m_bounding_rect, Qt::AlignCenter, m_text); +} diff --git a/GUI/coregui/Views/InfoWidgets/OverlayLabelWidget.h b/GUI/coregui/Views/InfoWidgets/OverlayLabelWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..11dc7169fae6b6017f48c2fac3288a401840b40d --- /dev/null +++ b/GUI/coregui/Views/InfoWidgets/OverlayLabelWidget.h @@ -0,0 +1,47 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Views/InfoWidgets/OverlayLabelWidget.h +//! @brief Declares class OverlayLabelWidget +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2016 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov +//! @authors Walter Van Herck, Joachim Wuttke +// +// ************************************************************************** // + +#ifndef OVERLAYLABELWIDGET +#define OVERLAYLABELWIDGET + +#include "WinDllMacros.h" +#include <QWidget> +#include <QString> +#include <QRect> + +//! The OverlayLabelWidget is a semi-transparent overlay label to place on top of other +//! widgets outside of any layout context. + +class BA_CORE_API_ OverlayLabelWidget : public QWidget +{ + Q_OBJECT +public: + OverlayLabelWidget(QWidget *parent = 0); + + void setRectangle(const QRect &rect); + void setPosition(int x, int y); + + void setText(const QString &text) {m_text = text;} + +protected: + void paintEvent(QPaintEvent *event); + +private: + QString m_text; + QRect m_bounding_rect; +}; + +#endif diff --git a/GUI/coregui/Views/InfoWidgets/WarningSignWidget.h b/GUI/coregui/Views/InfoWidgets/WarningSignWidget.h index 6b90edb0eac2dd7bf8f6d5a7c5d3ba88f820204b..d4dfe5845967aa5a484808c4a1114bed3d6e7c93 100644 --- a/GUI/coregui/Views/InfoWidgets/WarningSignWidget.h +++ b/GUI/coregui/Views/InfoWidgets/WarningSignWidget.h @@ -22,8 +22,6 @@ #include <QPixmap> #include <QString> -class QAbstractScrollArea; - //! The WarningSignWidget is an transparent widget with warning sign pixmap intended to be //! overlayed onto other widget at some arbitrary position. class WarningSignWidget : public QWidget diff --git a/GUI/coregui/Views/JobWidgets/JobRealTimeWidget.cpp b/GUI/coregui/Views/JobWidgets/JobRealTimeWidget.cpp index bbaf8debafba7351352d66f0677c112f5544bffb..39ee54b02b789eadde4e91537152d5bf6997cca0 100644 --- a/GUI/coregui/Views/JobWidgets/JobRealTimeWidget.cpp +++ b/GUI/coregui/Views/JobWidgets/JobRealTimeWidget.cpp @@ -18,7 +18,7 @@ #include "JobModel.h" #include "JobItem.h" #include "JobQueueData.h" -#include "ModelTuningWidget.h" +#include "ParameterTuningWidget.h" #include "JobRealTimeToolBar.h" #include "GUIHelpers.h" #include "mainwindow_constants.h" @@ -49,7 +49,7 @@ JobRealTimeWidget::JobRealTimeWidget(JobModel *jobModel, QWidget *parent) connect(m_toolBar, SIGNAL(resetParameters()), this, SLOT(onResetParameters())); } -ModelTuningWidget *JobRealTimeWidget::getTuningWidgetForItem(JobItem *jobItem) +ParameterTuningWidget *JobRealTimeWidget::getTuningWidgetForItem(JobItem *jobItem) { return m_jobItemToTuningWidget[jobItem]; } @@ -73,9 +73,9 @@ void JobRealTimeWidget::setItem(JobItem * item) if(!isVisible()) return; - ModelTuningWidget *widget = m_jobItemToTuningWidget[item]; + ParameterTuningWidget *widget = m_jobItemToTuningWidget[item]; if( !widget && isValidJobItem(item)) { - widget = new ModelTuningWidget(m_jobModel); + widget = new ParameterTuningWidget(m_jobModel); widget->setItem(item); m_stack->addWidget(widget); m_jobItemToTuningWidget[item] = widget; @@ -110,7 +110,7 @@ void JobRealTimeWidget::onJobItemFinished(const QString &identifier) void JobRealTimeWidget::onResetParameters() { - ModelTuningWidget *widget = getCurrentModelTuningWidget(); + ParameterTuningWidget *widget = getCurrentModelTuningWidget(); if(widget) widget->restoreModelsOfCurrentJobItem(); } @@ -131,9 +131,9 @@ void JobRealTimeWidget::onModelLoaded() } } -ModelTuningWidget *JobRealTimeWidget::getCurrentModelTuningWidget() +ParameterTuningWidget *JobRealTimeWidget::getCurrentModelTuningWidget() { - ModelTuningWidget *result = dynamic_cast<ModelTuningWidget *>(m_stack->currentWidget()); + ParameterTuningWidget *result = dynamic_cast<ParameterTuningWidget *>(m_stack->currentWidget()); if(result && result->isHidden()) result = 0; return result; } @@ -150,13 +150,13 @@ void JobRealTimeWidget::onJobItemDelete(JobItem *item) //qDebug() << "JobOutputDataWidget::onJobItemDelete()"; if(item == m_currentItem) m_currentItem=0; - ModelTuningWidget *widget = m_jobItemToTuningWidget[item]; + ParameterTuningWidget *widget = m_jobItemToTuningWidget[item]; if( !widget ) { // this is the case when user removes failed job which doesn't have propper widget return; } - QMap<JobItem *, ModelTuningWidget *>::iterator it = m_jobItemToTuningWidget.begin(); + QMap<JobItem *, ParameterTuningWidget *>::iterator it = m_jobItemToTuningWidget.begin(); while(it!=m_jobItemToTuningWidget.end()) { if(it.value() == widget) { it = m_jobItemToTuningWidget.erase(it); diff --git a/GUI/coregui/Views/JobWidgets/JobRealTimeWidget.h b/GUI/coregui/Views/JobWidgets/JobRealTimeWidget.h index 34d897f632250d88d4ee61d564e9479c4f7a1be2..625e249a099ad45c026a690b798f46e1ca64beb4 100644 --- a/GUI/coregui/Views/JobWidgets/JobRealTimeWidget.h +++ b/GUI/coregui/Views/JobWidgets/JobRealTimeWidget.h @@ -23,7 +23,7 @@ class JobModel; class JobItem; class QStackedWidget; -class ModelTuningWidget; +class ParameterTuningWidget; class JobRealTimeToolBar; //! The JobRealTimeWidget provides tuning of sample parameters in real time. @@ -35,7 +35,7 @@ class BA_CORE_API_ JobRealTimeWidget : public JobPresenter public: explicit JobRealTimeWidget(JobModel *jobModel, QWidget *parent = 0); - ModelTuningWidget *getTuningWidgetForItem(JobItem *jobItem); + ParameterTuningWidget *getTuningWidgetForItem(JobItem *jobItem); QSize sizeHint() const; QSize minimumSizeHint() const; @@ -49,11 +49,11 @@ public slots: void onModelLoaded(); private: - ModelTuningWidget *getCurrentModelTuningWidget(); + ParameterTuningWidget *getCurrentModelTuningWidget(); bool isValidJobItem(JobItem *item); QStackedWidget *m_stack; - QMap<JobItem *, ModelTuningWidget *> m_jobItemToTuningWidget; + QMap<JobItem *, ParameterTuningWidget *> m_jobItemToTuningWidget; JobRealTimeToolBar *m_toolBar; }; diff --git a/GUI/coregui/Views/JobWidgets/ModelTuningDelegate.cpp b/GUI/coregui/Views/JobWidgets/ParameterTuningDelegate.cpp similarity index 85% rename from GUI/coregui/Views/JobWidgets/ModelTuningDelegate.cpp rename to GUI/coregui/Views/JobWidgets/ParameterTuningDelegate.cpp index 09ae9c20b4b1bb99abc39bc2e5caf80d970cf9bc..d1b74e1a6a06f365a2b8696c08f3fef56043f71e 100644 --- a/GUI/coregui/Views/JobWidgets/ModelTuningDelegate.cpp +++ b/GUI/coregui/Views/JobWidgets/ParameterTuningDelegate.cpp @@ -2,8 +2,8 @@ // // BornAgain: simulate and fit scattering at grazing incidence // -//! @file coregui/Views/JobWidgets/ModelTuningDelegate.cpp -//! @brief Implements class ModelTuningDelegate +//! @file coregui/Views/JobWidgets/ParameterTuningDelegate.cpp +//! @brief Implements class ParameterTuningDelegate //! //! @homepage http://www.bornagainproject.org //! @license GNU General Public License v3 or higher (see COPYING) @@ -14,10 +14,10 @@ // // ************************************************************************** // -#include "ModelTuningDelegate.h" +#include "ParameterTuningDelegate.h" #include "GUIHelpers.h" #include "ParameterTreeItems.h" -#include "FilterPropertyProxy.h" +#include "ParameterTuningModel.h" #include "ModelPath.h" #include "SessionModel.h" #include <QDebug> @@ -43,7 +43,7 @@ const double maximum_doublespin_value(20000.0); //const double minimum_doublespin_value(0.0); } -ModelTuningDelegate::SliderData::SliderData() +ParameterTuningDelegate::SliderData::SliderData() : m_smin(0) , m_smax(100) , m_rmin(0.0) @@ -53,17 +53,17 @@ ModelTuningDelegate::SliderData::SliderData() } -void ModelTuningDelegate::SliderData::setRangeFactor(double range_factor) +void ParameterTuningDelegate::SliderData::setRangeFactor(double range_factor) { m_range_factor = range_factor; } -void ModelTuningDelegate::SliderData::setItemLimits(const AttLimits &item_limits) +void ParameterTuningDelegate::SliderData::setItemLimits(const AttLimits &item_limits) { m_item_limits = item_limits; } -int ModelTuningDelegate::SliderData::value_to_slider(double value) +int ParameterTuningDelegate::SliderData::value_to_slider(double value) { double dr(0); if(value == 0.0) { @@ -83,13 +83,13 @@ int ModelTuningDelegate::SliderData::value_to_slider(double value) return m_smin + (value - m_rmin)*(m_smax-m_smin)/(m_rmax-m_rmin); } -double ModelTuningDelegate::SliderData::slider_to_value(int slider) +double ParameterTuningDelegate::SliderData::slider_to_value(int slider) { return m_rmin + (slider - m_smin)*(m_rmax-m_rmin)/(m_smax - m_smin); } -ModelTuningDelegate::ModelTuningDelegate(QObject *parent) +ParameterTuningDelegate::ParameterTuningDelegate(QObject *parent) : QItemDelegate(parent) , m_valueColumn(1) , m_slider(0) @@ -100,7 +100,7 @@ ModelTuningDelegate::ModelTuningDelegate(QObject *parent) } -void ModelTuningDelegate::paint(QPainter *painter, +void ParameterTuningDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { @@ -128,7 +128,7 @@ void ModelTuningDelegate::paint(QPainter *painter, } -QWidget *ModelTuningDelegate::createEditor(QWidget *parent, +QWidget *ParameterTuningDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { @@ -137,9 +137,7 @@ QWidget *ModelTuningDelegate::createEditor(QWidget *parent, double value = index.model()->data(index, Qt::EditRole).toDouble(); - m_currentItem = static_cast<ParameterItem*>(FilterPropertyProxy::toSourceIndex(index).internalPointer()); - - + m_currentItem = static_cast<ParameterItem*>(ParameterTuningModel::toSourceIndex(index).internalPointer()); AttLimits limits = m_currentItem->getLinkedItem()->limits(); @@ -203,7 +201,7 @@ QWidget *ModelTuningDelegate::createEditor(QWidget *parent, } -void ModelTuningDelegate::updateSlider(double value) const +void ParameterTuningDelegate::updateSlider(double value) const { disconnect(m_slider, SIGNAL(valueChanged(int)),this, SLOT(sliderValueChanged(int))); @@ -213,7 +211,7 @@ void ModelTuningDelegate::updateSlider(double value) const } -void ModelTuningDelegate::sliderValueChanged(int position) +void ParameterTuningDelegate::sliderValueChanged(int position) { disconnect(m_valueBox, SIGNAL(valueChanged(double)),this, SLOT(editorValueChanged(double))); @@ -225,7 +223,7 @@ void ModelTuningDelegate::sliderValueChanged(int position) } -void ModelTuningDelegate::editorValueChanged(double value) +void ParameterTuningDelegate::editorValueChanged(double value) { qDebug() << "ModelTuningDelegate::editorValueChanged " << value; disconnect(m_slider, SIGNAL(valueChanged(int)),this, SLOT(sliderValueChanged(int))); @@ -237,7 +235,7 @@ void ModelTuningDelegate::editorValueChanged(double value) } -void ModelTuningDelegate::setEditorData(QWidget *editor, +void ParameterTuningDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { if (index.column() == m_valueColumn) { @@ -248,7 +246,7 @@ void ModelTuningDelegate::setEditorData(QWidget *editor, } -void ModelTuningDelegate::setModelData(QWidget *editor, +void ParameterTuningDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { @@ -262,7 +260,7 @@ void ModelTuningDelegate::setModelData(QWidget *editor, } -void ModelTuningDelegate::emitSignals(double value) +void ParameterTuningDelegate::emitSignals(double value) { if(m_currentItem) { m_currentItem->setValue(value); @@ -271,7 +269,7 @@ void ModelTuningDelegate::emitSignals(double value) } } -void ModelTuningDelegate::setSliderRangeFactor(double value) +void ParameterTuningDelegate::setSliderRangeFactor(double value) { m_slider_data.setRangeFactor(value); } diff --git a/GUI/coregui/Views/JobWidgets/ModelTuningDelegate.h b/GUI/coregui/Views/JobWidgets/ParameterTuningDelegate.h similarity index 89% rename from GUI/coregui/Views/JobWidgets/ModelTuningDelegate.h rename to GUI/coregui/Views/JobWidgets/ParameterTuningDelegate.h index 635b1e4163f1ab595c3fc1a7fe49fb498c85ec21..2b5ad75c0642619bfd1ce690498180d25c5170bd 100644 --- a/GUI/coregui/Views/JobWidgets/ModelTuningDelegate.h +++ b/GUI/coregui/Views/JobWidgets/ParameterTuningDelegate.h @@ -2,8 +2,8 @@ // // BornAgain: simulate and fit scattering at grazing incidence // -//! @file coregui/Views/JobWidgets/ModelTuningDelegate.h -//! @brief Declares class ModelTuningDelegate +//! @file coregui/Views/JobWidgets/ParameterTuningDelegate.h +//! @brief Declares class ParameterTuningDelegate //! //! @homepage http://www.bornagainproject.org //! @license GNU General Public License v3 or higher (see COPYING) @@ -14,8 +14,8 @@ // // ************************************************************************** // -#ifndef MODELTUNINGDELEGATE_H -#define MODELTUNINGDELEGATE_H +#ifndef PARAMETERTUNINGDELEGATE_H +#define PARAMETERTUNINGDELEGATE_H #include <QItemDelegate> #include "AttLimits.h" @@ -26,7 +26,7 @@ class QHBoxLayout; class ParameterItem; class SessionItem; -class BA_CORE_API_ ModelTuningDelegate : public QItemDelegate +class BA_CORE_API_ ParameterTuningDelegate : public QItemDelegate { Q_OBJECT @@ -47,7 +47,7 @@ public: }; - ModelTuningDelegate(QObject *parent = 0); + ParameterTuningDelegate(QObject *parent = 0); QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & /* index */) const { diff --git a/GUI/coregui/Views/JobWidgets/ModelTuningWidget.cpp b/GUI/coregui/Views/JobWidgets/ParameterTuningWidget.cpp similarity index 70% rename from GUI/coregui/Views/JobWidgets/ModelTuningWidget.cpp rename to GUI/coregui/Views/JobWidgets/ParameterTuningWidget.cpp index a3c297d0de66a8e9aa938b0c6c0e58282de7a43d..87a87861f1fca629f697d62866dca4e62f49b803 100644 --- a/GUI/coregui/Views/JobWidgets/ModelTuningWidget.cpp +++ b/GUI/coregui/Views/JobWidgets/ParameterTuningWidget.cpp @@ -2,8 +2,8 @@ // // BornAgain: simulate and fit scattering at grazing incidence // -//! @file coregui/Views/JobWidgets/ModelTuningWidget.cpp -//! @brief Implements class ModelTuningWidget +//! @file coregui/Views/JobWidgets/ParameterTuningWidget.cpp +//! @brief Implements class ParameterTuningWidget //! //! @homepage http://www.bornagainproject.org //! @license GNU General Public License v3 or higher (see COPYING) @@ -14,21 +14,21 @@ // // ************************************************************************** // -#include "ModelTuningWidget.h" +#include "ParameterTuningWidget.h" #include "JobQueueData.h" #include "JobItem.h" #include "SliderSettingsWidget.h" #include "ParameterModelBuilder.h" #include "GUIHelpers.h" -#include "ModelTuningDelegate.h" +#include "ParameterTuningDelegate.h" #include "JobModel.h" #include "SampleModel.h" #include "InstrumentModel.h" #include "IntensityDataItem.h" #include "DesignerHelper.h" #include "WarningSignWidget.h" -#include "FilterPropertyProxy.h" -#include "FitTools.h" +#include "ParameterTuningModel.h" +#include "ParameterTreeItems.h" #include <QLabel> #include <QVBoxLayout> #include <QTreeView> @@ -45,23 +45,17 @@ const int warning_sign_xpos = 38; const int warning_sign_ypos = 38; } -ModelTuningWidget::ModelTuningWidget(JobModel *jobModel, QWidget *parent) +ParameterTuningWidget::ParameterTuningWidget(JobModel *jobModel, QWidget *parent) : QWidget(parent) , m_jobModel(jobModel) , m_currentJobItem(0) - , m_sliderSettingsWidget(0) - , m_delegate(new ModelTuningDelegate) + , m_parameterTuningModel(0) + , m_sliderSettingsWidget(new SliderSettingsWidget(this)) + , m_delegate(new ParameterTuningDelegate) , m_warningSign(0) -// , m_mapper(0) - , m_fitTools(new FitTools(jobModel, parent)) { -// setMinimumSize(128, 128); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - m_sliderSettingsWidget = new SliderSettingsWidget(); - connect(m_sliderSettingsWidget, SIGNAL(sliderRangeFactorChanged(double)), this, SLOT(onSliderValueChanged(double))); - connect(m_sliderSettingsWidget, SIGNAL(lockzChanged(bool)), this, SLOT(onLockZValueChanged(bool))); - m_treeView = new QTreeView(); m_treeView->setStyleSheet( "QTreeView::branch {background: palette(base);}QTreeView::branch:has-siblings:!adjoins-item " @@ -76,29 +70,28 @@ ModelTuningWidget::ModelTuningWidget(JobModel *jobModel, QWidget *parent) m_treeView->setItemDelegate(m_delegate); m_treeView->setSelectionMode(QAbstractItemView::ExtendedSelection); - connect(m_delegate, SIGNAL(currentLinkChanged(SessionItem*)), this, SLOT(onCurrentLinkChanged(SessionItem*))); m_treeView->setContextMenuPolicy(Qt::CustomContextMenu); - connect(m_treeView, SIGNAL(customContextMenuRequested(const QPoint &)), - this, SLOT(onCustomContextMenuRequested(const QPoint &))); - + m_treeView->setDragEnabled(true); + m_treeView->setDragDropMode(QAbstractItemView::DragOnly); QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->setMargin(0); mainLayout->setSpacing(0); - - // assembling all together mainLayout->addWidget(m_sliderSettingsWidget); mainLayout->addWidget(m_treeView); - mainLayout->addWidget(m_fitTools); - setLayout(mainLayout); -} -ModelTuningWidget::~ModelTuningWidget() -{ + connect(m_sliderSettingsWidget, SIGNAL(sliderRangeFactorChanged(double)), + this, SLOT(onSliderValueChanged(double))); + connect(m_sliderSettingsWidget, SIGNAL(lockzChanged(bool)), + this, SLOT(onLockZValueChanged(bool))); + connect(m_delegate, SIGNAL(currentLinkChanged(SessionItem*)), + this, SLOT(onCurrentLinkChanged(SessionItem*))); + connect(m_treeView, SIGNAL(customContextMenuRequested(const QPoint &)), + this, SLOT(onCustomContextMenuRequested(const QPoint &))); } -void ModelTuningWidget::setItem(JobItem *item) +void ParameterTuningWidget::setItem(JobItem *item) { if (m_currentJobItem == item) { return; @@ -118,17 +111,29 @@ void ModelTuningWidget::setItem(JobItem *item) onPropertyChanged(name); }, this); - m_fitTools->setCurrentItem(m_currentJobItem, m_treeView->selectionModel()); } } -QItemSelectionModel *ModelTuningWidget::selectionModel() +QItemSelectionModel *ParameterTuningWidget::selectionModel() { Q_ASSERT(m_treeView); return m_treeView->selectionModel(); } -void ModelTuningWidget::onCurrentLinkChanged(SessionItem *item) +//! Returns list of ParameterItem's currently selected in parameter tree + +QVector<ParameterItem *> ParameterTuningWidget::getSelectedParameters() +{ + QVector<ParameterItem *> result; + QModelIndexList proxyIndexes = selectionModel()->selectedIndexes(); + foreach(QModelIndex proxyIndex, proxyIndexes) { + if(ParameterItem *parItem = m_parameterTuningModel->getParameterItem(proxyIndex)) + result.push_back(parItem); + } + return result; +} + +void ParameterTuningWidget::onCurrentLinkChanged(SessionItem *item) { qDebug() << "ModelTuningWidget::onCurrentLinkChanged"; Q_ASSERT(m_currentJobItem); @@ -144,12 +149,12 @@ void ModelTuningWidget::onCurrentLinkChanged(SessionItem *item) } } -void ModelTuningWidget::onSliderValueChanged(double value) +void ParameterTuningWidget::onSliderValueChanged(double value) { m_delegate->setSliderRangeFactor(value); } -void ModelTuningWidget::onLockZValueChanged(bool value) +void ParameterTuningWidget::onLockZValueChanged(bool value) { if(!m_currentJobItem) return; if(IntensityDataItem *intensityDataItem = m_currentJobItem->getIntensityDataItem()) { @@ -158,7 +163,7 @@ void ModelTuningWidget::onLockZValueChanged(bool value) } } -void ModelTuningWidget::updateParameterModel() +void ParameterTuningWidget::updateParameterModel() { qDebug() << "ModelTuningWidget::updateParameterModel()"; @@ -168,21 +173,24 @@ void ModelTuningWidget::updateParameterModel() throw GUIHelpers::Error("ModelTuningWidget::updateParameterModel() -> Error." "JobItem doesn't have sample or instrument model."); - FilterPropertyProxy *proxy = new FilterPropertyProxy(2, this); - proxy->setSourceModel(m_jobModel); - m_treeView->setModel(proxy); - m_treeView->setRootIndex(proxy->mapFromSource(m_currentJobItem->getItem(JobItem::T_PARAMETER_TREE)->index())); + delete m_parameterTuningModel; + m_parameterTuningModel = new ParameterTuningModel(this); + m_parameterTuningModel->setSourceModel(m_jobModel); + + m_treeView->setModel(m_parameterTuningModel); + m_treeView->setRootIndex( + m_parameterTuningModel->mapFromSource(m_currentJobItem->parameterContainerItem()->index())); if (m_treeView->columnWidth(0) < 170) m_treeView->setColumnWidth(0, 170); m_treeView->expandAll(); } -void ModelTuningWidget::onCustomContextMenuRequested(const QPoint &point) +void ParameterTuningWidget::onCustomContextMenuRequested(const QPoint &point) { emit itemContextMenuRequest(m_treeView->mapToGlobal(point+ QPoint(2, 22))); } -void ModelTuningWidget::restoreModelsOfCurrentJobItem() +void ParameterTuningWidget::restoreModelsOfCurrentJobItem() { Q_ASSERT(m_currentJobItem); @@ -190,13 +198,18 @@ void ModelTuningWidget::restoreModelsOfCurrentJobItem() return; m_jobModel->restore(m_currentJobItem); - -// updateParameterModel(); - m_jobModel->getJobQueueData()->runJob(m_currentJobItem); } -void ModelTuningWidget::resizeEvent(QResizeEvent *event) +void ParameterTuningWidget::makeSelected(ParameterItem *item) +{ + QModelIndex proxyIndex = m_parameterTuningModel->mapFromSource(item->index()); + if(proxyIndex.isValid()) { + selectionModel()->select(proxyIndex, QItemSelectionModel::Select); + } +} + +void ParameterTuningWidget::resizeEvent(QResizeEvent *event) { Q_UNUSED(event); if(m_warningSign) { @@ -208,13 +221,13 @@ void ModelTuningWidget::resizeEvent(QResizeEvent *event) } } -//! Context menu reimplemented to suppress default -void ModelTuningWidget::contextMenuEvent(QContextMenuEvent *event) +//! Context menu reimplemented to suppress the default one +void ParameterTuningWidget::contextMenuEvent(QContextMenuEvent *event) { Q_UNUSED(event); } -void ModelTuningWidget::onPropertyChanged(const QString &property_name) +void ParameterTuningWidget::onPropertyChanged(const QString &property_name) { if(property_name == JobItem::P_STATUS) { delete m_warningSign; @@ -236,7 +249,7 @@ void ModelTuningWidget::onPropertyChanged(const QString &property_name) //! Returns position for warning sign at the bottom right corner of the tree view. //! The position will be adjusted according to the visibility of scroll bars -QPoint ModelTuningWidget::getPositionForWarningSign() +QPoint ParameterTuningWidget::getPositionForWarningSign() { int x = width()-warning_sign_xpos; int y = height()-warning_sign_ypos; diff --git a/GUI/coregui/Views/JobWidgets/ModelTuningWidget.h b/GUI/coregui/Views/JobWidgets/ParameterTuningWidget.h similarity index 74% rename from GUI/coregui/Views/JobWidgets/ModelTuningWidget.h rename to GUI/coregui/Views/JobWidgets/ParameterTuningWidget.h index 98924106c3885235708b7c82795bc3fc4c3e5fad..e7046052914b07145e2e5c311dd33faae9e5b8b3 100644 --- a/GUI/coregui/Views/JobWidgets/ModelTuningWidget.h +++ b/GUI/coregui/Views/JobWidgets/ParameterTuningWidget.h @@ -2,8 +2,8 @@ // // BornAgain: simulate and fit scattering at grazing incidence // -//! @file coregui/Views/JobWidgets/ModelTuningWidget.h -//! @brief Declares class ModelTuningWidget +//! @file coregui/Views/JobWidgets/ParameterTuningWidget.h +//! @brief Declares class ParameterTuningWidget //! //! @homepage http://www.bornagainproject.org //! @license GNU General Public License v3 or higher (see COPYING) @@ -14,36 +14,36 @@ // // ************************************************************************** // -#ifndef MODELTUNINGWIDGET_H -#define MODELTUNINGWIDGET_H +#ifndef PARAMETERTUNIGWIDGET_H +#define PARAMETERTUNIGWIDGET_H #include <QWidget> #include <memory> +class JobModel; class JobItem; +class SessionItem; +class QItemSelectionModel; +class ParameterTuningDelegate; +class ParameterTuningModel; class SliderSettingsWidget; -class ModelTuningDelegate; -class JobModel; class QTreeView; -class SampleModel; -class InstrumentModel; class WarningSignWidget; -class SessionItem; -class FitTools; -class QItemSelectionModel; +class ParameterItem; -class ModelTuningWidget : public QWidget +class ParameterTuningWidget : public QWidget { Q_OBJECT public: - ModelTuningWidget(JobModel *jobModel, QWidget *parent = 0); - virtual ~ModelTuningWidget(); + ParameterTuningWidget(JobModel *jobModel, QWidget *parent = 0); void setItem(JobItem *item); QItemSelectionModel* selectionModel(); + QVector<ParameterItem *> getSelectedParameters(); + signals: void itemContextMenuRequest(const QPoint &point); @@ -52,6 +52,7 @@ public slots: void onSliderValueChanged(double value); void onLockZValueChanged(bool value); void restoreModelsOfCurrentJobItem(); + void makeSelected(ParameterItem *item); protected: void resizeEvent(QResizeEvent *event); @@ -67,11 +68,11 @@ private: JobModel *m_jobModel; JobItem *m_currentJobItem; + ParameterTuningModel *m_parameterTuningModel; SliderSettingsWidget *m_sliderSettingsWidget; QTreeView *m_treeView; - ModelTuningDelegate *m_delegate; + ParameterTuningDelegate *m_delegate; WarningSignWidget *m_warningSign; - FitTools *m_fitTools; }; #endif diff --git a/GUI/coregui/Views/SampleDesigner/DesignerHelper.cpp b/GUI/coregui/Views/SampleDesigner/DesignerHelper.cpp index 75aabf5b3509e1f6055793b876d43c67022e78c6..8585409246e9393a1d9117894e3c8b43421b15e1 100644 --- a/GUI/coregui/Views/SampleDesigner/DesignerHelper.cpp +++ b/GUI/coregui/Views/SampleDesigner/DesignerHelper.cpp @@ -213,6 +213,15 @@ QPixmap DesignerHelper::getMimePixmap(const QString &name) return pixmap; } +int DesignerHelper::getHeaderFontSize() +{ +#ifdef Q_OS_MAC + return 14; +#else + return 12; +#endif +} + QRectF DesignerHelper::getDefaultMultiLayerRect() { return QRectF(0, 0, DesignerHelper::getDefaultMultiLayerWidth(), diff --git a/GUI/coregui/Views/SampleDesigner/DesignerHelper.h b/GUI/coregui/Views/SampleDesigner/DesignerHelper.h index 3ae0547c44ba90831e71dd16733d662db03279a8..6717876fec2a2c25607f01e568e61ab76f9576b7 100644 --- a/GUI/coregui/Views/SampleDesigner/DesignerHelper.h +++ b/GUI/coregui/Views/SampleDesigner/DesignerHelper.h @@ -103,6 +103,7 @@ public: static QPixmap getMimePixmap(const QString &name); //! returns system dependent font size + static int getHeaderFontSize(); static int getSectionFontSize(); static int getLabelFontSize(); static int getPortFontSize(); diff --git a/GUI/coregui/Views/SampleDesigner/ItemTreeView.cpp b/GUI/coregui/Views/SampleDesigner/ItemTreeView.cpp index 48c590f202a9c914b8bb62f84f9d499f49d27a0d..b37b0f673dc20ee52d4ac4f20c562f561436d568 100644 --- a/GUI/coregui/Views/SampleDesigner/ItemTreeView.cpp +++ b/GUI/coregui/Views/SampleDesigner/ItemTreeView.cpp @@ -42,7 +42,7 @@ void ItemTreeView::dragMoveEvent(QDragMoveEvent *event) SessionModel *model = static_cast<SessionModel *>(this->model()); model->setDraggedItemType(QString()); QByteArray xml_data = qUncompress( - event->mimeData()->data(SessionXML::MimeType)); + event->mimeData()->data(SessionXML::ItemMimeType)); QXmlStreamReader reader(xml_data); while (!reader.atEnd()) { reader.readNext(); diff --git a/GUI/coregui/Views/SessionModelView.cpp b/GUI/coregui/Views/SessionModelView.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a155b25975073b1f67a87fd154685414dda979c4 --- /dev/null +++ b/GUI/coregui/Views/SessionModelView.cpp @@ -0,0 +1,130 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Views/SessionModelView.cpp +//! @brief Implements class SessionModelView +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2016 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov +//! @authors Walter Van Herck, Joachim Wuttke +// +// ************************************************************************** // + +#include "SessionModelView.h" +#include "mainwindow.h" +#include "ApplicationModels.h" +#include "InstrumentModel.h" +#include "SampleModel.h" +#include "MaterialModel.h" +#include "JobModel.h" +#include "SessionModelDelegate.h" +#include <QVBoxLayout> +#include <QToolBar> +#include <QTabWidget> +#include <QToolButton> +#include <QTreeView> +#include <QDebug> + + +SessionModelView::ModelTree::ModelTree(SessionModel *model, QTreeView *tree) + : m_model(model), m_tree(tree), m_is_expanded(false) +{ + Q_ASSERT(m_model); + Q_ASSERT(m_tree); + m_tree->setModel(m_model); + if(model->rowCount(QModelIndex()) > 0) { + setExpanded(true); + } +} + +void SessionModelView::ModelTree::toggleExpanded() +{ + setExpanded(!isExpanded()); +} + +void SessionModelView::ModelTree::setExpanded(bool expanded) +{ + Q_ASSERT(m_tree); + if(expanded) { + m_tree->expandAll(); + m_tree->resizeColumnToContents(0); + m_tree->resizeColumnToContents(1); + } else { + m_tree->collapseAll(); + } + m_is_expanded = expanded; +} + +void SessionModelView::ModelTree::setActive(bool is_active) +{ + if(is_active) { + if(m_tree->model()) return; + m_tree->setModel(m_model); + setExpanded(true); + } else { + if(!m_tree->model()) return; + m_tree->setModel(0); + } +} + + +SessionModelView::SessionModelView(MainWindow *mainWindow) + : QWidget(mainWindow) + , m_mainWindow(mainWindow) + , m_toolBar(new QToolBar(this)) + , m_tabs(new QTabWidget(this)) + , m_expandCollapseButton(0) + , m_delegate(new SessionModelDelegate(this)) +{ + QVBoxLayout *layout = new QVBoxLayout; + layout->setMargin(0); + layout->setSpacing(0); + + m_expandCollapseButton = new QToolButton; + m_expandCollapseButton->setText("Expand / collapse tree"); + m_expandCollapseButton->setIcon(QIcon(":/images/toolbar_expand_collapse_tree.svg")); + m_expandCollapseButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + m_expandCollapseButton->setToolTip("Click to switch between expanded/collapsed tree view"); + m_toolBar->addWidget(m_expandCollapseButton); + connect(m_expandCollapseButton, SIGNAL(clicked()), this, SLOT(onExpandCollapseTree())); + + layout->addWidget(m_toolBar); + layout->addWidget(m_tabs); + setLayout(layout); + + init_tabs(); + + //setViewActive(false); + +} + +//! Sets given view to enabled/disable state. If disabled, all trees will be disconnected from models +void SessionModelView::setViewActive(bool is_active) +{ + for(int i=0; i<m_content.size(); ++i) { + m_content[i].setActive(is_active); + } +} + +void SessionModelView::onExpandCollapseTree() +{ + m_content[m_tabs->currentIndex()].toggleExpanded(); +} + +void SessionModelView::init_tabs() +{ + m_content.clear(); + m_content.push_back(ModelTree(m_mainWindow->instrumentModel(), new QTreeView(this))); + m_content.push_back(ModelTree(m_mainWindow->sampleModel(), new QTreeView(this))); + m_content.push_back(ModelTree(m_mainWindow->materialModel(), new QTreeView(this))); + m_content.push_back(ModelTree(m_mainWindow->jobModel(), new QTreeView(this))); + for(int i=0; i<m_content.size(); ++i) { + m_tabs->addTab(m_content[i].m_tree, m_content[i].m_model->getModelTag()); + m_content[i].m_tree->setItemDelegate(m_delegate); + } +} + diff --git a/GUI/coregui/Views/SessionModelView.h b/GUI/coregui/Views/SessionModelView.h new file mode 100644 index 0000000000000000000000000000000000000000..c5f18cc77ff0e814f73760c3280670e8e12ed709 --- /dev/null +++ b/GUI/coregui/Views/SessionModelView.h @@ -0,0 +1,73 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file coregui/Views/SessionModelView.h +//! @brief Declares class SessionModelView +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2016 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov +//! @authors Walter Van Herck, Joachim Wuttke +// +// ************************************************************************** // + +#ifndef SESSIONMODELVIEW_H +#define SESSIONMODELVIEW_H + +#include "WinDllMacros.h" +#include <QWidget> +#include <QVector> + +class MainWindow; +class QToolBar; +class QTabWidget; +class QToolButton; +class SessionModel; +class QTreeView; +class SessionModelDelegate; + +//! The SessionModelView is a technical view which shows the content all current application +//! models. It appears as an additional view in the main navigation bar on the left, right +//! after the jobView (if corresponding setting of MainWindow is On). + +class BA_CORE_API_ SessionModelView : public QWidget +{ + Q_OBJECT + +public: + SessionModelView(MainWindow *mainWindow = 0); + + // keeps info about tree and it's model together + class ModelTree { + public: + ModelTree() : m_model(0), m_tree(0), m_is_expanded(false) {} + ModelTree(SessionModel *model, QTreeView *tree); + void toggleExpanded(); + void setExpanded(bool expanded); + bool isExpanded() const { return m_is_expanded;} + void setActive(bool is_active); + SessionModel *m_model; + QTreeView *m_tree; + bool m_is_expanded; + }; + + void setViewActive(bool is_active); + +private slots: + void onExpandCollapseTree(); + +private: + void init_tabs(); + + MainWindow *m_mainWindow; + QToolBar *m_toolBar; + QTabWidget *m_tabs; + QToolButton *m_expandCollapseButton; + SessionModelDelegate *m_delegate; + QVector<ModelTree> m_content; +}; + +#endif diff --git a/GUI/coregui/Views/TestView.cpp b/GUI/coregui/Views/TestView.cpp index 609571ca8db3af81bd524204a9dcdbc61105c9c8..8d3a42717561a9b7d584c2ee4f08db5659fcd3e6 100644 --- a/GUI/coregui/Views/TestView.cpp +++ b/GUI/coregui/Views/TestView.cpp @@ -37,6 +37,7 @@ #include <QPersistentModelIndex> #include "ModelMapper.h" #include "DetectorItems.h" +#include "SessionModelDelegate.h" TestView::TestView(MainWindow *mainWindow) : QWidget(mainWindow) @@ -54,9 +55,9 @@ void TestView::test_sessionModel() QVBoxLayout *layout = new QVBoxLayout; QTabWidget *tabs = new QTabWidget; - addModelToTabs(tabs, m_mainWindow->instrumentModel()); - addModelToTabs(tabs, m_mainWindow->sampleModel()); - addModelToTabs(tabs, m_mainWindow->materialModel()); +// addModelToTabs(tabs, m_mainWindow->instrumentModel()); +// addModelToTabs(tabs, m_mainWindow->sampleModel()); +// addModelToTabs(tabs, m_mainWindow->materialModel()); addModelToTabs(tabs, m_mainWindow->jobModel()); TestProxyModel *testModel = new TestProxyModel(this); @@ -91,7 +92,11 @@ void TestView::test_MaterialEditor() void TestView::addModelToTabs(QTabWidget *tabs, QAbstractItemModel *model) { QTreeView *view = new QTreeView; + SessionModelDelegate *delegate = new SessionModelDelegate(this); + view->setModel(model); + view->setItemDelegate(delegate); + view->expandAll(); view->resizeColumnToContents(0); view->resizeColumnToContents(1); diff --git a/GUI/coregui/Views/TestView.h b/GUI/coregui/Views/TestView.h index 55f5e956f7d1067542fe410d3be92d56ef767d07..9c52a1ffe61d8f9bddbc9638ea0b7b7dc25caa3b 100644 --- a/GUI/coregui/Views/TestView.h +++ b/GUI/coregui/Views/TestView.h @@ -17,13 +17,14 @@ #ifndef TESTVIEW_H #define TESTVIEW_H +#include "WinDllMacros.h" #include <QWidget> class MainWindow; class QTabWidget; class QAbstractItemModel; -class TestView : public QWidget +class BA_CORE_API_ TestView : public QWidget { Q_OBJECT public: diff --git a/GUI/coregui/coregui.qrc b/GUI/coregui/coregui.qrc index 499d2a29b5e292bfa91aad375af2bf3dceea2621..5ff9018083bfd779b9831408d339dabadb923032 100644 --- a/GUI/coregui/coregui.qrc +++ b/GUI/coregui/coregui.qrc @@ -39,5 +39,7 @@ <file>images/toolbar32dark_remove.svg</file> <file>images/statusbar_dockmenu.svg</file> <file>images/statusbar_joblist.svg</file> + <file>images/main_sessionmodel.svg</file> + <file>images/toolbar_expand_collapse_tree.svg</file> </qresource> </RCC> diff --git a/GUI/coregui/images/main_sessionmodel.svg b/GUI/coregui/images/main_sessionmodel.svg new file mode 100644 index 0000000000000000000000000000000000000000..a1e41b56de260873fd8f59f26dcf6f020c6d7ef0 --- /dev/null +++ b/GUI/coregui/images/main_sessionmodel.svg @@ -0,0 +1,323 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="48px" + height="48px" + id="svg2985" + version="1.1" + inkscape:version="0.91 r13725" + sodipodi:docname="main_sessionmodel.svg"> + <defs + id="defs2987"> + <linearGradient + id="linearGradient3765"> + <stop + style="stop-color:#c3c3c3;stop-opacity:1;" + offset="0" + id="stop3767" /> + <stop + style="stop-color:#ffffff;stop-opacity:1;" + offset="1" + id="stop3769" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3765" + id="linearGradient3771" + x1="26" + y1="43" + x2="26.111572" + y2="-4.0193973" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.90876041,0,0,1.0336717,-56.997994,-8.8095796)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3765" + id="linearGradient4505" + x1="-255.26595" + y1="-109.97279" + x2="-287.26593" + y2="-146.97279" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3765" + id="linearGradient4507" + gradientUnits="userSpaceOnUse" + x1="-255.26595" + y1="-109.97279" + x2="-287.26593" + y2="-146.97279" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3765" + id="linearGradient4509" + gradientUnits="userSpaceOnUse" + x1="-255.26595" + y1="-109.97279" + x2="-287.26593" + y2="-146.97279" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3765" + id="linearGradient4511" + gradientUnits="userSpaceOnUse" + x1="-255.26595" + y1="-109.97279" + x2="-287.26593" + y2="-146.97279" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3765" + id="linearGradient4513" + gradientUnits="userSpaceOnUse" + x1="-255.26595" + y1="-109.97279" + x2="-287.26593" + y2="-146.97279" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3765" + id="linearGradient4515" + gradientUnits="userSpaceOnUse" + x1="-255.26595" + y1="-109.97279" + x2="-287.26593" + y2="-146.97279" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3765" + id="linearGradient4517" + gradientUnits="userSpaceOnUse" + x1="-255.26595" + y1="-109.97279" + x2="-287.26593" + y2="-146.97279" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3765" + id="linearGradient4519" + gradientUnits="userSpaceOnUse" + x1="-255.26595" + y1="-109.97279" + x2="-287.26593" + y2="-146.97279" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3765" + id="linearGradient4521" + gradientUnits="userSpaceOnUse" + x1="-255.26595" + y1="-109.97279" + x2="-287.26593" + y2="-146.97279" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3765" + id="linearGradient4523" + gradientUnits="userSpaceOnUse" + x1="-255.26595" + y1="-109.97279" + x2="-287.26593" + y2="-146.97279" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3765" + id="linearGradient4525" + gradientUnits="userSpaceOnUse" + x1="-255.26595" + y1="-109.97279" + x2="-287.26593" + y2="-146.97279" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3765" + id="linearGradient4527" + gradientUnits="userSpaceOnUse" + x1="-255.26595" + y1="-109.97279" + x2="-287.26593" + y2="-146.97279" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3765" + id="linearGradient4529" + gradientUnits="userSpaceOnUse" + x1="-255.26595" + y1="-109.97279" + x2="-287.26593" + y2="-146.97279" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3765" + id="linearGradient4531" + gradientUnits="userSpaceOnUse" + x1="-255.26595" + y1="-109.97279" + x2="-287.26593" + y2="-146.97279" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3765" + id="linearGradient4533" + gradientUnits="userSpaceOnUse" + x1="-255.26595" + y1="-109.97279" + x2="-287.26593" + y2="-146.97279" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3765" + id="linearGradient4535" + gradientUnits="userSpaceOnUse" + x1="-255.26595" + y1="-109.97279" + x2="-287.26593" + y2="-146.97279" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3765" + id="linearGradient4537" + gradientUnits="userSpaceOnUse" + x1="-255.26595" + y1="-109.97279" + x2="-287.26593" + y2="-146.97279" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3765" + id="linearGradient4539" + gradientUnits="userSpaceOnUse" + x1="-255.26595" + y1="-109.97279" + x2="-287.26593" + y2="-146.97279" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3765" + id="linearGradient4541" + gradientUnits="userSpaceOnUse" + x1="-255.26595" + y1="-109.97279" + x2="-287.26593" + y2="-146.97279" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="14" + inkscape:cx="16.581924" + inkscape:cy="20.626546" + inkscape:current-layer="layer1" + showgrid="true" + inkscape:grid-bbox="true" + inkscape:document-units="px" + inkscape:window-width="2466" + inkscape:window-height="1365" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1"> + <inkscape:grid + type="xygrid" + id="grid3012" /> + </sodipodi:namedview> + <metadata + id="metadata2990"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + id="layer1" + inkscape:label="Layer 1" + inkscape:groupmode="layer"> + <path + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:Sans;-inkscape-font-specification:Sans;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient3771);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate" + d="m -48.36477,4.1113174 0,0.516836 0,26.8754646 0,0.516836 0.45438,0 27.262813,0 0.45438,0 0,-0.516836 0,-26.8754646 0,-0.516836 -0.45438,0 -27.262813,0 z" + id="rect2991" + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccccccccccccc" /> + <g + id="g4479" + transform="matrix(1.0294216,0,0,1.0294216,295.75276,151.18995)" + style="fill:url(#linearGradient4505);fill-opacity:1"> + <g + id="Settings" + style="fill:url(#linearGradient4511);fill-opacity:1"> + <g + id="g4439" + style="fill:url(#linearGradient4509);fill-opacity:1"> + <path + id="path4441" + d="m -247.27788,-125.80737 c -0.0537,-0.47795 -0.61103,-0.83711 -1.09291,-0.83711 -1.55794,0 -2.94043,-0.91478 -3.52022,-2.32953 -0.59231,-1.44903 -0.21038,-3.13892 0.95071,-4.204 0.36549,-0.33411 0.40989,-0.8934 0.10335,-1.28191 -0.79738,-1.01257 -1.70368,-1.92723 -2.69323,-2.71993 -0.38749,-0.31096 -0.95602,-0.2677 -1.29203,0.10436 -1.01333,1.12226 -2.83354,1.53936 -4.24006,0.95249 -1.4637,-0.61572 -2.38671,-2.09891 -2.29638,-3.69102 0.0297,-0.50008 -0.33576,-0.9349 -0.83432,-0.99296 -1.2699,-0.14687 -2.55092,-0.15143 -3.82461,-0.0101 -0.49288,0.0544 -0.85836,0.47896 -0.84179,0.97272 0.0554,1.57643 -0.87873,3.03368 -2.32789,3.62725 -1.38969,0.56765 -3.19712,0.15409 -4.20843,-0.95817 -0.33423,-0.36637 -0.89352,-0.41141 -1.28292,-0.10791 -1.0189,0.79941 -1.94557,1.71482 -2.75029,2.71904 -0.31387,0.39041 -0.2677,0.95628 0.10146,1.29216 1.18323,1.07152 1.56529,2.77611 0.95059,4.24184 -0.58688,1.3974 -2.03794,2.29802 -3.69912,2.29802 -0.53904,-0.0174 -0.923,0.34448 -0.98195,0.83457 -0.14954,1.27724 -0.1513,2.57863 -0.008,3.86623 0.0534,0.47997 0.62761,0.83597 1.11479,0.83597 1.48041,-0.0379 2.90173,0.87873 3.49796,2.32966 0.59434,1.44902 0.21229,3.13791 -0.95058,4.20387 -0.36371,0.33411 -0.40989,0.89252 -0.10336,1.28103 0.78992,1.00612 1.69636,1.92166 2.68945,2.72094 0.38951,0.31387 0.95627,0.26959 1.29393,-0.10247 1.01712,-1.12504 2.8372,-1.54138 4.23816,-0.95337 1.46736,0.61382 2.39038,2.09688 2.30005,3.68987 -0.0295,0.50034 0.33777,0.93592 0.83433,0.99309 0.64962,0.0758 1.30316,0.11361 1.95847,0.11361 0.62205,0 1.24421,-0.0342 1.86625,-0.10336 0.49301,-0.0544 0.85824,-0.47896 0.84166,-0.97361 -0.057,-1.57554 0.87873,-3.03278 2.32599,-3.62535 1.39905,-0.57144 3.19889,-0.1532 4.21033,0.95793 0.33613,0.3656 0.8915,0.40975 1.28304,0.10727 1.01701,-0.79751 1.94178,-1.71217 2.7503,-2.71917 0.31375,-0.38952 0.26947,-0.95628 -0.10159,-1.29203 -1.18323,-1.07153 -1.56718,-2.77636 -0.95247,-4.24108 0.57789,-1.37881 1.97504,-2.3046 3.47784,-2.3046 l 0.21025,0.006 c 0.48744,0.0396 0.93591,-0.33587 0.995,-0.83343 0.14978,-1.27837 0.15155,-2.57862 0.008,-3.86623 z m -16.86674,7.5943 c -3.12704,0 -5.67062,-2.54358 -5.67062,-5.67062 0,-3.1269 2.54358,-5.67062 5.67062,-5.67062 3.12691,0 5.67049,2.54372 5.67049,5.67062 0,3.12704 -2.54358,5.67062 -5.67049,5.67062 z" + style="clip-rule:evenodd;fill:url(#linearGradient4507);fill-opacity:1;fill-rule:evenodd" + inkscape:connector-curvature="0" /> + </g> + </g> + <g + id="g4443" + style="fill:url(#linearGradient4513);fill-opacity:1" /> + <g + id="g4445" + style="fill:url(#linearGradient4515);fill-opacity:1" /> + <g + id="g4447" + style="fill:url(#linearGradient4517);fill-opacity:1" /> + <g + id="g4449" + style="fill:url(#linearGradient4519);fill-opacity:1" /> + <g + id="g4451" + style="fill:url(#linearGradient4521);fill-opacity:1" /> + <g + id="g4453" + style="fill:url(#linearGradient4523);fill-opacity:1" /> + <g + id="g4455" + style="fill:url(#linearGradient4525);fill-opacity:1" /> + <g + id="g4457" + style="fill:url(#linearGradient4527);fill-opacity:1" /> + <g + id="g4459" + style="fill:url(#linearGradient4529);fill-opacity:1" /> + <g + id="g4461" + style="fill:url(#linearGradient4531);fill-opacity:1" /> + <g + id="g4463" + style="fill:url(#linearGradient4533);fill-opacity:1" /> + <g + id="g4465" + style="fill:url(#linearGradient4535);fill-opacity:1" /> + <g + id="g4467" + style="fill:url(#linearGradient4537);fill-opacity:1" /> + <g + id="g4469" + style="fill:url(#linearGradient4539);fill-opacity:1" /> + <g + id="g4471" + style="fill:url(#linearGradient4541);fill-opacity:1" /> + </g> + </g> +</svg> diff --git a/GUI/coregui/images/toolbar_expand_collapse_tree.svg b/GUI/coregui/images/toolbar_expand_collapse_tree.svg new file mode 100644 index 0000000000000000000000000000000000000000..c6e710a58b7c1ea061ec4b51124a8ac826df22f0 --- /dev/null +++ b/GUI/coregui/images/toolbar_expand_collapse_tree.svg @@ -0,0 +1,310 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + id="svg2985" + version="1.1" + inkscape:version="0.91 r13725" + sodipodi:docname="toolbar_expand_collapse_tree.svg"> + <defs + id="defs2987"> + <linearGradient + inkscape:collect="always" + id="linearGradient3848"> + <stop + style="stop-color:#000000;stop-opacity:1;" + offset="0" + id="stop3850" /> + <stop + style="stop-color:#000000;stop-opacity:0;" + offset="1" + id="stop3852" /> + </linearGradient> + <inkscape:path-effect + effect="spiro" + id="path-effect3833" + is_visible="true" /> + <linearGradient + id="linearGradient4619"> + <stop + style="stop-color:#c3c3c3;stop-opacity:1;" + offset="0" + id="stop4621" /> + <stop + style="stop-color:#ffffff;stop-opacity:1;" + offset="1" + id="stop4623" /> + </linearGradient> + <linearGradient + id="linearGradient4592"> + <stop + style="stop-color:#c3c3c3;stop-opacity:1;" + offset="0" + id="stop4594" /> + <stop + style="stop-color:#fafafa;stop-opacity:0.98039216;" + offset="1" + id="stop4596" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4619" + id="linearGradient4708" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(-0.90913729,12.020815)" + x1="11" + y1="12" + x2="11" + y2="6" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4619" + id="linearGradient4724" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(4.3671751,0,0,0.36023659,-29.207084,18.152322)" + x1="11" + y1="12" + x2="11" + y2="6" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4619" + id="linearGradient4767" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(3.0034693,0,0,0.6589497,-28.754255,27.735252)" + x1="11" + y1="12" + x2="11" + y2="6" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4619" + id="linearGradient3048" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.62685746,0,0,1,-8.55667,-29.093836)" + x1="22" + y1="38" + x2="22" + y2="26" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3848" + id="linearGradient3854" + x1="7.2781744" + y1="31.824934" + x2="7.1922593" + y2="42.052731" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3848" + id="linearGradient3858" + gradientUnits="userSpaceOnUse" + x1="7.2781744" + y1="31.824934" + x2="7.1922593" + y2="42.052731" + gradientTransform="matrix(0,1,-1,0,48.340927,29.754123)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4619" + id="linearGradient3412" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(3.0118872,0,0,0.6589497,-28.837626,31.725355)" + x1="11" + y1="12" + x2="11" + y2="6" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4619" + id="linearGradient3416" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.6818531,0,0,0.6589497,-11.700039,35.715457)" + x1="11" + y1="12" + x2="11" + y2="6" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4619" + id="linearGradient3420" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.6734352,0,0,0.6589497,-11.540906,39.70556)" + x1="11" + y1="12" + x2="11" + y2="6" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4619" + id="linearGradient3437" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.31814721,0,0,3.8830217,9.8874079,3.1384864)" + x1="11" + y1="12" + x2="11" + y2="6" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4619" + id="linearGradient4474" + x1="10.148653" + y1="31.140333" + x2="16.184389" + y2="37.580055" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(-0.02525381,-0.60609152)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4619" + id="linearGradient4478" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-1,-0.01639304,0,-1,27.040149,80.760186)" + x1="12.345735" + y1="33.665714" + x2="19.265354" + y2="41.97422" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="9.899495" + inkscape:cx="10.914737" + inkscape:cy="3.2232233" + inkscape:current-layer="layer1" + showgrid="true" + inkscape:grid-bbox="true" + inkscape:document-units="px" + inkscape:window-width="2466" + inkscape:window-height="1365" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:snap-global="false"> + <inkscape:grid + type="xygrid" + id="grid3012" + empspacing="5" + visible="true" + enabled="true" + snapvisiblegridlinesonly="true" /> + </sodipodi:namedview> + <metadata + id="metadata2990"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + id="layer1" + inkscape:label="Layer 1" + inkscape:groupmode="layer" + transform="translate(0,-32)"> + <path + sodipodi:nodetypes="ccccccccccccc" + inkscape:connector-curvature="0" + id="path4763" + d="m 0.99228782,33.010196 0,0.329474 0,1.3179 0,0.329474 1.50173428,0 6.0069384,0 1.5017355,0 0,-0.329474 0,-1.3179 0,-0.329474 -1.5017355,0 -6.0069384,0 z" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:Sans;-inkscape-font-specification:Sans;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient4767);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" /> + <path + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:Sans;-inkscape-font-specification:Sans;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient3412);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" + d="m 0.99228782,37.000299 0,0.329474 0,1.3179 0,0.329474 1.50594318,0 6.0237744,0 1.5059446,0 0,-0.329474 0,-1.3179 0,-0.329474 -1.5059446,0 -6.0237744,0 z" + id="path3410" + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccccccccccccc" /> + <path + sodipodi:nodetypes="ccccccccccccc" + inkscape:connector-curvature="0" + id="path3414" + d="m 4.9571365,40.990401 0,0.329474 0,1.3179 0,0.329474 0.8409264,0 3.3637061,0 0.840927,0 0,-0.329474 0,-1.3179 0,-0.329474 -0.840927,0 -3.3637061,0 z" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:Sans;-inkscape-font-specification:Sans;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient3416);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" /> + <path + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:Sans;-inkscape-font-specification:Sans;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient3420);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" + d="m 5.0328979,44.980504 0,0.329474 0,1.3179 0,0.329474 0.8367174,0 3.3468704,0 0.8367183,0 0,-0.329474 0,-1.3179 0,-0.329474 -0.8367183,0 -3.3468704,0 z" + id="path3418" + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccccccccccccc" /> + <path + sodipodi:nodetypes="ccccccccccccc" + inkscape:connector-curvature="0" + id="path3435" + d="m 13.038357,34.222379 0,1.941507 0,7.766046 0,1.941505 0.159074,0 0.636294,0 0.159074,0 0,-1.941505 0,-7.766046 0,-1.941507 -0.159074,0 -0.636294,0 z" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:Sans;-inkscape-font-specification:Sans;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient3437);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" /> + <g + id="g4359" + transform="matrix(0.04779299,0,0,0.04779299,-9.1696001,57.289298)" /> + <g + id="g4361" + transform="matrix(0.04779299,0,0,0.04779299,-9.1696001,57.289298)" /> + <g + id="g4363" + transform="matrix(0.04779299,0,0,0.04779299,-9.1696001,57.289298)" /> + <g + id="g4365" + transform="matrix(0.04779299,0,0,0.04779299,-9.1696001,57.289298)" /> + <g + id="g4367" + transform="matrix(0.04779299,0,0,0.04779299,-9.1696001,57.289298)" /> + <g + id="g4369" + transform="matrix(0.04779299,0,0,0.04779299,-9.1696001,57.289298)" /> + <g + id="g4371" + transform="matrix(0.04779299,0,0,0.04779299,-9.1696001,57.289298)" /> + <g + id="g4373" + transform="matrix(0.04779299,0,0,0.04779299,-9.1696001,57.289298)" /> + <g + id="g4375" + transform="matrix(0.04779299,0,0,0.04779299,-9.1696001,57.289298)" /> + <g + id="g4377" + transform="matrix(0.04779299,0,0,0.04779299,-9.1696001,57.289298)" /> + <g + id="g4379" + transform="matrix(0.04779299,0,0,0.04779299,-9.1696001,57.289298)" /> + <g + id="g4381" + transform="matrix(0.04779299,0,0,0.04779299,-9.1696001,57.289298)" /> + <g + id="g4383" + transform="matrix(0.04779299,0,0,0.04779299,-9.1696001,57.289298)" /> + <g + id="g4385" + transform="matrix(0.04779299,0,0,0.04779299,-9.1696001,57.289298)" /> + <g + id="g4387" + transform="matrix(0.04779299,0,0,0.04779299,-9.1696001,57.289298)" /> + <path + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#linearGradient4474);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.72582728px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + d="m 13.584121,33.028673 a 0.36294993,0.36294993 0 0 0 -0.345703,0.222656 l -1.285156,3.054687 a 0.36294993,0.36294993 0 1 0 0.667968,0.28125 l 0.921875,-2.1875 0.748047,2.128907 a 0.36353463,0.36353463 0 1 0 0.685547,-0.242188 l -1.060547,-3.013672 a 0.36294993,0.36294993 0 0 0 -0.332031,-0.24414 z" + id="path4443" + inkscape:connector-curvature="0" /> + <path + inkscape:connector-curvature="0" + id="path4476" + d="m 13.430774,46.902321 a 0.36593705,0.35998719 45.234808 0 0 0.345703,-0.216989 l 1.285156,-3.033619 a 0.36593705,0.35998719 45.234808 1 0 -0.667968,-0.2922 L 13.47179,45.5319 12.723743,43.390731 a 0.3665266,0.36056716 45.234808 0 0 -0.685547,0.23095 l 1.060547,3.031057 a 0.36593705,0.35998719 45.234808 0 0 0.332031,0.249583 z" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#linearGradient4478);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.72582728px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> + </g> +</svg> diff --git a/GUI/coregui/mainwindow/UpdateNotifier.cpp b/GUI/coregui/mainwindow/UpdateNotifier.cpp index d870c48f3bfaa051ceef6da082d51df337d92b50..f6605d8ea8e0a93aed2e6d89046098ca7c54f8d7 100644 --- a/GUI/coregui/mainwindow/UpdateNotifier.cpp +++ b/GUI/coregui/mainwindow/UpdateNotifier.cpp @@ -81,7 +81,7 @@ void UpdateNotifier::askForUpdates() QMessageBox msgBox; msgBox.setWindowTitle("Updates"); msgBox.setText("Should BornAgain check for updates automatically?\n" - "This setting can be changed later."); + "This setting can be changed later in the main window Settings menu."); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox.setDefaultButton(QMessageBox::Yes); int ret = msgBox.exec(); diff --git a/GUI/coregui/mainwindow/actionmanager.cpp b/GUI/coregui/mainwindow/actionmanager.cpp index 62d007d97843a7ba09edb954c1cb51be69581df4..d9af04489ffb7742fa85f311339036219ca7d089 100644 --- a/GUI/coregui/mainwindow/actionmanager.cpp +++ b/GUI/coregui/mainwindow/actionmanager.cpp @@ -172,14 +172,23 @@ void ActionManager::aboutToShowRecentProjects() void ActionManager::aboutToShowSettings() { - m_settingsMenu->clear(); + m_settingsMenu->clear(); QSettings settings; + settings.beginGroup(Constants::S_UPDATES); QAction *action = m_settingsMenu->addAction(tr("Check for Updates")); action->setCheckable(true); action->setChecked(settings.value(Constants::S_CHECKFORUPDATES, false).toBool()); connect(action, SIGNAL(toggled(bool)), this, SLOT(toggleCheckForUpdates(bool))); settings.endGroup(); + + settings.beginGroup(Constants::S_SESSIONMODELVIEW); + action = m_settingsMenu->addAction(tr("Model tech view")); + action->setToolTip("Additional developer's view will appear in left control tab bar"); + action->setCheckable(true); + action->setChecked(settings.value(Constants::S_VIEWISACTIVE, false).toBool()); + connect(action, SIGNAL(toggled(bool)), this, SLOT(setSessionModelViewActive(bool))); + settings.endGroup(); } void ActionManager::toggleCheckForUpdates(bool status) @@ -191,4 +200,13 @@ void ActionManager::toggleCheckForUpdates(bool status) m_mainWindow->getUpdateNotifier()->checkForUpdates(); } +void ActionManager::setSessionModelViewActive(bool status) +{ + QSettings settings; + settings.beginGroup(Constants::S_SESSIONMODELVIEW); + settings.setValue(Constants::S_VIEWISACTIVE, status); + settings.endGroup(); + m_mainWindow->onSessionModelViewActive(status); +} + diff --git a/GUI/coregui/mainwindow/actionmanager.h b/GUI/coregui/mainwindow/actionmanager.h index 9f9fb3570e0e9b4bf8aa053b0544e4889ff2707f..499db0b9238fcafd273ab81269c2ea2106565ae9 100644 --- a/GUI/coregui/mainwindow/actionmanager.h +++ b/GUI/coregui/mainwindow/actionmanager.h @@ -40,6 +40,7 @@ public slots: void aboutToShowRecentProjects(); void aboutToShowSettings(); void toggleCheckForUpdates(bool status); + void setSessionModelViewActive(bool status); private: MainWindow *m_mainWindow; diff --git a/GUI/coregui/mainwindow/mainwindow.cpp b/GUI/coregui/mainwindow/mainwindow.cpp index 93e0ab19b988c17f38ea4dc7b33b6bde9ee19f82..fd84368bf4a5d0ebdc16d23539f72ba6087067f5 100644 --- a/GUI/coregui/mainwindow/mainwindow.cpp +++ b/GUI/coregui/mainwindow/mainwindow.cpp @@ -39,6 +39,7 @@ #include "GUIHelpers.h" #include "UpdateNotifier.h" #include "TestFitWidgets.h" +#include "SessionModelView.h" #include <QApplication> #include <QStatusBar> @@ -62,6 +63,7 @@ MainWindow::MainWindow(QWidget *parent) , m_sampleView(0) , m_simulationView(0) , m_jobView(0) + , m_sessionModelView(0) , m_fitView(0) { initApplication(); @@ -169,6 +171,34 @@ void MainWindow::onAboutApplication() dialog.exec(); } +//! Inserts/removes developers SessionModelView on the left fancy tabbar. +//! This SessionModelView will be known for the tab under MAXVIEWCOUNT id (so it is last one) +void MainWindow::onSessionModelViewActive(bool isActive) +{ + qDebug() << "MainWindow::onSessionModelViewActive" << isActive; + + if(isActive) { + if(m_sessionModelView) + return; + + m_sessionModelView = new SessionModelView(this); + m_tabWidget->insertTab(MAXVIEWCOUNT, m_sessionModelView, QIcon(":/images/main_sessionmodel.svg"), "Models"); + + } else { + if(!m_sessionModelView) + return; + + if(m_tabWidget->currentIndex() == MAXVIEWCOUNT) + m_tabWidget->setCurrentIndex(WELCOME); + + m_tabWidget->removeTab(MAXVIEWCOUNT); + delete m_sessionModelView; + m_sessionModelView = 0; + m_tabWidget->update(); + } + +} + void MainWindow::closeEvent(QCloseEvent *event) { if(jobModel()->hasUnfinishedJobs()) { @@ -231,7 +261,8 @@ void MainWindow::initViews() m_simulationView = new SimulationView(this); m_jobView = new JobView(this); - TestView *testView = new TestView(this); +// TestView *testView = new TestView(this); +// m_sessionModelView = new SessionModelView(this); TestFitWidgets *testFitWidgets = new TestFitWidgets(this); //m_fitView = new FitView(this); @@ -241,11 +272,17 @@ void MainWindow::initViews() 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(FIT, m_fitView, QIcon(":/images/main_jobqueue.png"), "Fit"); - m_tabWidget->insertTab(FIT, testView, QIcon(":/images/main_jobqueue.png"), "Test"); + //m_tabWidget->insertTab(MODELVIEW, m_sessionModelView, QIcon(":/images/main_sessionmodel.svg"), "Models"); m_tabWidget->insertTab(TESTVIEW, testFitWidgets, QIcon(":/images/main_jobqueue.png"), "TestView"); m_tabWidget->setCurrentIndex(WELCOME); + // enabling technical view + QSettings settings; + settings.beginGroup(Constants::S_SESSIONMODELVIEW); + onSessionModelViewActive(settings.value(Constants::S_VIEWISACTIVE, false).toBool()); + settings.endGroup(); + setCentralWidget(m_tabWidget); } diff --git a/GUI/coregui/mainwindow/mainwindow.h b/GUI/coregui/mainwindow/mainwindow.h index 2ccf947656b881377b86e925202d9004df73a6ca..c7c3d1d08355db621653d907d4bdc1211f3360c0 100644 --- a/GUI/coregui/mainwindow/mainwindow.h +++ b/GUI/coregui/mainwindow/mainwindow.h @@ -31,6 +31,7 @@ class InstrumentView; class SampleView; class SimulationView; class JobView; +class SessionModelView; class ObsoleteFitView; class MaterialModel; @@ -52,7 +53,7 @@ class BA_CORE_API_ MainWindow : public Manhattan::FancyMainWindow Q_OBJECT public: - enum ETabViewId {WELCOME, INSTRUMENT, SAMPLE, SIMULATION, JOB, FIT, TESTVIEW}; + enum ETabViewId {WELCOME, INSTRUMENT, SAMPLE, SIMULATION, JOB, TESTVIEW, MAXVIEWCOUNT}; explicit MainWindow(QWidget *parent = 0); @@ -76,6 +77,7 @@ public slots: void openRecentProject(); void onRunSimulationShortcut(); void onAboutApplication(); + void onSessionModelViewActive(bool isActive); protected: virtual void closeEvent(QCloseEvent *event); @@ -103,6 +105,7 @@ private: SampleView *m_sampleView; SimulationView *m_simulationView; JobView *m_jobView; + SessionModelView *m_sessionModelView; ObsoleteFitView *m_fitView; }; diff --git a/GUI/coregui/mainwindow/mainwindow_constants.h b/GUI/coregui/mainwindow/mainwindow_constants.h index 9eafe88d3db6385d5dbc71869546ff9feff23f81..5cd78f1df64492005582dffd687b9f1c63658f71 100644 --- a/GUI/coregui/mainwindow/mainwindow_constants.h +++ b/GUI/coregui/mainwindow/mainwindow_constants.h @@ -34,6 +34,7 @@ const char S_MAINWINDOW[] = "MainWindow"; const char S_MASKEDITOR[] = "MaskEditor"; const char S_UPDATES[] = "Updates"; const char S_MATERIALEDITOR[] = "MaterialEditor"; +const char S_SESSIONMODELVIEW[] = "SessionModelView"; // Settings keys const char S_DEFAULTPROJECTPATH[] = "DefaultProjectPath"; @@ -42,6 +43,7 @@ const char S_WINDOWSIZE[] = "size"; const char S_WINDOWPOSITION[] = "pos"; const char S_SPLITTERSIZE[] = "SplitterSize"; const char S_CHECKFORUPDATES[] = "CheckForUpdates"; +const char S_VIEWISACTIVE[] = "ViewIsActive"; // Updates const char S_VERSION_URL[] = "http://apps.jcns.fz-juelich.de/src/BornAgain/CHANGELOG"; diff --git a/GUI/coregui/utils/CustomEventFilters.cpp b/GUI/coregui/utils/CustomEventFilters.cpp index b1f19c98001c856346bf76387f1a4c9ca62382bd..e7fd9d3bb01dd44800db66a13a492821b1f911a4 100644 --- a/GUI/coregui/utils/CustomEventFilters.cpp +++ b/GUI/coregui/utils/CustomEventFilters.cpp @@ -43,6 +43,8 @@ bool SpaceKeyEater::eventFilter(QObject *obj, QEvent *event) } } +// ---------------------------------------------------------------------------- + WheelEventEater::WheelEventEater(QObject *parent) : QObject(parent) { @@ -80,3 +82,19 @@ bool WheelEventEater::eventFilter(QObject *obj, QEvent *event) } return QObject::eventFilter(obj, event); } + +// ---------------------------------------------------------------------------- + +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/CustomEventFilters.h b/GUI/coregui/utils/CustomEventFilters.h index 99d83c3bf448ce47c0fafe223054bdc2cc96d0bd..ab61e50c64f87007df32e3ef5556b8e42daa5879 100644 --- a/GUI/coregui/utils/CustomEventFilters.h +++ b/GUI/coregui/utils/CustomEventFilters.h @@ -22,7 +22,7 @@ class QEvent; -//! Filter out space bar key events, which is special case for dialog windows +//! Filter out space bar key events, which is special case for dialog windows. class BA_CORE_API_ SpaceKeyEater : public QObject { @@ -36,8 +36,8 @@ protected: }; -//! event filter to install on combo boxes and spin boxes to not -//! to react on wheel events during scrolling of InstrumentComponentWidget +//! Event filter to install on combo boxes and spin boxes to not +//! to react on wheel events during scrolling of InstrumentComponentWidget. class BA_CORE_API_ WheelEventEater : public QObject { @@ -50,6 +50,20 @@ protected: bool eventFilter(QObject *obj, QEvent *event); }; +//! Lisens for press-del-key events + +class DeleteEventFilter : public QObject +{ + Q_OBJECT +public: + DeleteEventFilter( QObject *parent = 0 ) : QObject( parent ) {} + +protected: + bool eventFilter( QObject *dist, QEvent *event ); + +signals: + void removeItem(); +}; diff --git a/GUI/coregui/utils/DeleteEventFilter.cpp b/GUI/coregui/utils/DeleteEventFilter.cpp deleted file mode 100644 index f6a7f9d8672d91eae5d029c4d1836ca945a41089..0000000000000000000000000000000000000000 --- a/GUI/coregui/utils/DeleteEventFilter.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// ************************************************************************** // -// -// BornAgain: simulate and fit scattering at grazing incidence -// -//! @file coregui/utils/DeleteEventFilter.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 2016 -//! @authors Scientific Computing Group at MLZ Garching -//! @authors Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov -//! @authors Walter Van Herck, Joachim 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 deleted file mode 100644 index 85ff954756c5b82c8e6fd89c5ee3a547aa05e543..0000000000000000000000000000000000000000 --- a/GUI/coregui/utils/DeleteEventFilter.h +++ /dev/null @@ -1,40 +0,0 @@ -// ************************************************************************** // -// -// BornAgain: simulate and fit scattering at grazing incidence -// -//! @file coregui/utils/DeleteEventFilter.h -//! @brief Declares 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 2016 -//! @authors Scientific Computing Group at MLZ Garching -//! @authors Céline Durniak, Marina Ganeva, David Li, Gennady Pospelov -//! @authors Walter Van Herck, Joachim 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/Tests/UnitTests/GUI/TestFitParameterModel.h b/Tests/UnitTests/GUI/TestFitParameterModel.h new file mode 100644 index 0000000000000000000000000000000000000000..637fa4fbd2891f81cae1d5297b7291f8cdc96a74 --- /dev/null +++ b/Tests/UnitTests/GUI/TestFitParameterModel.h @@ -0,0 +1,244 @@ +#ifndef TESTFITPARAMETERMODEL_H +#define TESTFITPARAMETERMODEL_H + +#include <QtTest> +#include "JobModel.h" +#include "FitParameterAbsModel.h" +#include "FitParameterItems.h" +#include "FitSuiteItem.h" + +class TestFitParameterModel : public QObject { + Q_OBJECT + +private slots: + void test_InitialState(); + void test_addFitParameter(); + void test_addFitParameterAndLink(); + void test_addTwoFitParameterAndLinks(); +}; + +inline void TestFitParameterModel::test_InitialState() +{ + JobModel source; + SessionItem *fitSuiteItem = source.insertNewItem(Constants::FitSuiteType); + SessionItem *container = source.insertNewItem(Constants::FitParameterContainerType, fitSuiteItem->index(), -1, FitSuiteItem::T_FIT_PARAMETERS); + FitParameterProxyModel proxy(dynamic_cast<FitParameterContainerItem *>(container)); + + QCOMPARE(0, proxy.rowCount(QModelIndex())); + QCOMPARE((int)FitParameterProxyModel::MAX_COLUMNS, proxy.columnCount(QModelIndex())); + QCOMPARE(container, proxy.itemForIndex(QModelIndex())); +} + +inline void TestFitParameterModel::test_addFitParameter() +{ + JobModel source; + SessionItem *fitSuiteItem = source.insertNewItem(Constants::FitSuiteType); + SessionItem *container = source.insertNewItem(Constants::FitParameterContainerType, fitSuiteItem->index(), -1, FitSuiteItem::T_FIT_PARAMETERS); + FitParameterProxyModel proxy(dynamic_cast<FitParameterContainerItem *>(container)); + + // adding fit parameter + SessionItem *fitPar0 = source.insertNewItem(Constants::FitParameterType, container->index()); + fitPar0->setDisplayName(QStringLiteral("par")); + fitPar0->setItemValue(FitParameterItem::P_MIN, 1.0); + fitPar0->setItemValue(FitParameterItem::P_MAX, 2.0); + fitPar0->setItemValue(FitParameterItem::P_START_VALUE, 3.0); + + // checking index of root + QCOMPARE(1, proxy.rowCount(QModelIndex())); + QCOMPARE((int)FitParameterProxyModel::MAX_COLUMNS, proxy.columnCount(QModelIndex())); + + // accessing item at col=0 (original FitParameterItem) + QModelIndex index = proxy.index(0, 0, QModelIndex()); + QCOMPARE(index.row(), 0); + QCOMPARE(index.column(), 0); + QCOMPARE(proxy.rowCount(index), 0); + QCOMPARE(proxy.columnCount(index), 0); // non existing linkItem + + QCOMPARE(fitPar0, proxy.itemForIndex(index)); + QCOMPARE(fitPar0->displayName(), proxy.data(index).toString()); + QCOMPARE(index, proxy.indexOfItem(fitPar0)); + + // accessing item at col=2 + index = proxy.index(0, (int)FitParameterProxyModel::PAR_MIN, QModelIndex()); + QCOMPARE(index.row(), 0); + QCOMPARE(index.column(), (int)FitParameterProxyModel::PAR_MIN); + QCOMPARE(proxy.rowCount(index), 0); + QCOMPARE(proxy.columnCount(index), 0); + + QCOMPARE(fitPar0->getItem(FitParameterItem::P_MIN), proxy.itemForIndex(index)); + QCOMPARE(fitPar0->getItemValue(FitParameterItem::P_MIN).toDouble(), proxy.data(index).toDouble()); + QCOMPARE(index, proxy.indexOfItem(fitPar0->getItem(FitParameterItem::P_MIN))); + + // accessing item at col=3 + index = proxy.index(0, (int)FitParameterProxyModel::PAR_VALUE, QModelIndex()); + QCOMPARE(index.row(), 0); + QCOMPARE(index.column(), (int)FitParameterProxyModel::PAR_VALUE); + QCOMPARE(proxy.rowCount(index), 0); + QCOMPARE(proxy.columnCount(index), 0); + + QCOMPARE(fitPar0->getItem(FitParameterItem::P_START_VALUE), proxy.itemForIndex(index)); + QCOMPARE(fitPar0->getItemValue(FitParameterItem::P_START_VALUE).toDouble(), proxy.data(index).toDouble()); + QCOMPARE(index, proxy.indexOfItem(fitPar0->getItem(FitParameterItem::P_START_VALUE))); + + // accessing item at col=4 + index = proxy.index(0, (int)FitParameterProxyModel::PAR_MAX, QModelIndex()); + QCOMPARE(index.row(), 0); + QCOMPARE(index.column(), (int)FitParameterProxyModel::PAR_MAX); + QCOMPARE(proxy.rowCount(index), 0); + QCOMPARE(proxy.columnCount(index), 0); + + QCOMPARE(fitPar0->getItem(FitParameterItem::P_MAX), proxy.itemForIndex(index)); + QCOMPARE(fitPar0->getItemValue(FitParameterItem::P_MAX).toDouble(), proxy.data(index).toDouble()); + QCOMPARE(index, proxy.indexOfItem(fitPar0->getItem(FitParameterItem::P_MAX))); + + // ---------------------------------------------------- + // adding second fit parameter + // ---------------------------------------------------- + SessionItem *fitPar1 = source.insertNewItem(Constants::FitParameterType, container->index()); + fitPar0->setDisplayName(QStringLiteral("par")); + fitPar0->setItemValue(FitParameterItem::P_MIN, 10.0); + fitPar0->setItemValue(FitParameterItem::P_MAX, 20.0); + fitPar0->setItemValue(FitParameterItem::P_START_VALUE, 30.0); + + // checking index of root + QCOMPARE(2, proxy.rowCount(QModelIndex())); + QCOMPARE((int)FitParameterProxyModel::MAX_COLUMNS, proxy.columnCount(QModelIndex())); + + // accessing item at col=3 for fitPar0 + index = proxy.index(0, (int)FitParameterProxyModel::PAR_VALUE, QModelIndex()); + QCOMPARE(index.row(), 0); + QCOMPARE(index.column(), (int)FitParameterProxyModel::PAR_VALUE); + QCOMPARE(proxy.rowCount(index), 0); + QCOMPARE(proxy.columnCount(index), 0); + + QCOMPARE(fitPar0->getItem(FitParameterItem::P_START_VALUE), proxy.itemForIndex(index)); + QCOMPARE(fitPar0->getItemValue(FitParameterItem::P_START_VALUE).toDouble(), proxy.data(index).toDouble()); + QCOMPARE(index, proxy.indexOfItem(fitPar0->getItem(FitParameterItem::P_START_VALUE))); + + // accessing item at col=3 for fitPar1 + index = proxy.index(1, (int)FitParameterProxyModel::PAR_VALUE, QModelIndex()); + QCOMPARE(index.row(), 1); + QCOMPARE(index.column(), (int)FitParameterProxyModel::PAR_VALUE); + QCOMPARE(proxy.rowCount(index), 0); + QCOMPARE(proxy.columnCount(index), 0); + + QCOMPARE(fitPar1->getItem(FitParameterItem::P_START_VALUE), proxy.itemForIndex(index)); + QCOMPARE(fitPar1->getItemValue(FitParameterItem::P_START_VALUE).toDouble(), proxy.data(index).toDouble()); + QCOMPARE(index, proxy.indexOfItem(fitPar1->getItem(FitParameterItem::P_START_VALUE))); +} + +inline void TestFitParameterModel::test_addFitParameterAndLink() +{ + JobModel source; + SessionItem *fitSuiteItem = source.insertNewItem(Constants::FitSuiteType); + SessionItem *container = source.insertNewItem(Constants::FitParameterContainerType, fitSuiteItem->index(), -1, FitSuiteItem::T_FIT_PARAMETERS); + FitParameterProxyModel proxy(dynamic_cast<FitParameterContainerItem *>(container)); + + // adding fit parameter + SessionItem *fitPar0 = source.insertNewItem(Constants::FitParameterType, container->index()); + fitPar0->setDisplayName(QStringLiteral("par")); + fitPar0->setItemValue(FitParameterItem::P_MIN, 1.0); + fitPar0->setItemValue(FitParameterItem::P_MAX, 2.0); + fitPar0->setItemValue(FitParameterItem::P_START_VALUE, 3.0); + + // adding link + SessionItem *link0 = source.insertNewItem(Constants::FitParameterLinkType, fitPar0->index()); + link0->setItemValue(FitParameterLinkItem::P_LINK, "link0"); + + // checking index of root + QCOMPARE(1, proxy.rowCount(QModelIndex())); + QCOMPARE((int)FitParameterProxyModel::MAX_COLUMNS, proxy.columnCount(QModelIndex())); + + // accessing item at col=0 (original FitParameterItem) + QModelIndex index = proxy.index(0, 0, QModelIndex()); + QCOMPARE(index.row(), 0); + QCOMPARE(index.column(), 0); + QCOMPARE(proxy.rowCount(index), 1); + QCOMPARE(proxy.columnCount(index), 1); // linkItem + + // testing link0 index + QModelIndex linkIndex = proxy.index(0, 0, index); + QCOMPARE(linkIndex.row(), 0); + QCOMPARE(linkIndex.column(), 0); + QCOMPARE(linkIndex.parent(), index); + QCOMPARE(proxy.rowCount(linkIndex), 0); + QCOMPARE(proxy.columnCount(linkIndex), 0); + + QCOMPARE(proxy.parent(linkIndex), index); + QCOMPARE(proxy.itemForIndex(linkIndex), link0->getItem(FitParameterLinkItem::P_LINK)); + + QCOMPARE(link0->getItemValue(FitParameterLinkItem::P_LINK).toString(), proxy.data(linkIndex).toString()); + QCOMPARE(linkIndex, proxy.indexOfItem(link0->getItem(FitParameterLinkItem::P_LINK))); + + + // adding second link + SessionItem *link1 = source.insertNewItem(Constants::FitParameterLinkType, fitPar0->index()); + link1->setItemValue(FitParameterLinkItem::P_LINK, "link1"); + QCOMPARE(proxy.rowCount(index), 2); + QCOMPARE(proxy.columnCount(index), 1); // linkItem + + linkIndex = proxy.index(1, 0, index); + QCOMPARE(linkIndex.row(), 1); + QCOMPARE(linkIndex.column(), 0); + QCOMPARE(linkIndex.parent(), index); + QCOMPARE(proxy.rowCount(linkIndex), 0); + QCOMPARE(proxy.columnCount(linkIndex), 0); + QCOMPARE(proxy.parent(linkIndex), index); + + QCOMPARE(proxy.parent(linkIndex), index); + QCOMPARE(proxy.itemForIndex(linkIndex), link1->getItem(FitParameterLinkItem::P_LINK)); + +} + +inline void TestFitParameterModel::test_addTwoFitParameterAndLinks() +{ + JobModel source; + SessionItem *fitSuiteItem = source.insertNewItem(Constants::FitSuiteType); + SessionItem *container = source.insertNewItem(Constants::FitParameterContainerType, fitSuiteItem->index(), -1, FitSuiteItem::T_FIT_PARAMETERS); + FitParameterProxyModel proxy(dynamic_cast<FitParameterContainerItem *>(container)); + + // adding fit parameters + SessionItem *fitPar0 = source.insertNewItem(Constants::FitParameterType, container->index()); + SessionItem *link0 = source.insertNewItem(Constants::FitParameterLinkType, fitPar0->index()); + Q_UNUSED(link0); + + SessionItem *fitPar1 = source.insertNewItem(Constants::FitParameterType, container->index()); + SessionItem *link1 = source.insertNewItem(Constants::FitParameterLinkType, fitPar1->index()); + Q_UNUSED(link1); + + // checking index of root + QCOMPARE(2, proxy.rowCount(QModelIndex())); + QCOMPARE((int)FitParameterProxyModel::MAX_COLUMNS, proxy.columnCount(QModelIndex())); + + // accessing fitPar1 + QModelIndex index1 = proxy.index(1, 0, QModelIndex()); + QCOMPARE(index1.row(), 1); + QCOMPARE(index1.column(), 0); + QCOMPARE(index1.parent(), QModelIndex()); + QCOMPARE(proxy.rowCount(index1), 1); + QCOMPARE(proxy.columnCount(index1), 1); + + QCOMPARE(fitPar1, proxy.itemForIndex(index1)); + QCOMPARE(fitPar1->displayName(), proxy.data(index1).toString()); + QCOMPARE(index1, proxy.indexOfItem(fitPar1)); + + // accessing link1 + QModelIndex linkIndex1 = proxy.index(0, 0, index1); + QCOMPARE(linkIndex1.row(), 0); + QCOMPARE(linkIndex1.column(), 0); + qDebug() << "AAA" << index1 << linkIndex1; + QCOMPARE(linkIndex1.parent(), index1); + QCOMPARE(proxy.rowCount(linkIndex1), 0); + QCOMPARE(proxy.columnCount(linkIndex1), 0); + +// QCOMPARE(proxy.parent(linkIndex), index); +// QCOMPARE(proxy.itemForIndex(linkIndex), link0->getItem(FitParameterLinkItem::P_LINK)); + + +// QModelIndex linkIndex1 = proxy.index(0, 0, index1); + +} + +#endif + + diff --git a/Tests/UnitTests/GUI/TestGUI.cpp b/Tests/UnitTests/GUI/TestGUI.cpp index f6ec600751091eab3e81f28da02700660a76f2ec..f318dcd993996764bbc6d0f35fd8c146e6a4e5cf 100644 --- a/Tests/UnitTests/GUI/TestGUI.cpp +++ b/Tests/UnitTests/GUI/TestGUI.cpp @@ -15,24 +15,26 @@ #include "TestMapperForItem.h" #include "TestParticleDistributionItem.h" #include "TestGUIHelpers.h" +#include "TestFitParameterModel.h" int main(int argc, char** argv) { QCoreApplication app(argc, argv); Q_UNUSED(app); - TestFormFactorItems testFormFactorItems; - TestFTDistributionItems testFTDistributionItems; - TestParameterizedItem testParameterizedItem; - TestParticleItem testParticleItem; - TestLayerRoughnessItems testLayerRoughnessItems; - TestParaCrystalItems testParaCrystalItems; - TestSessionModel testSessionModel; - TestGUICoreObjectCorrespondence testGUICoreObjectCorrespondence; - TestSessionItem testSessionItem; - TestMapperCases testMapperCases; - TestMapperForItem testMapperForItem; - TestParticleDistributionItem testParticleDistributionItem; - TestGUIHelpers testGUIHelpers; +// TestFormFactorItems testFormFactorItems; +// TestFTDistributionItems testFTDistributionItems; +// TestParameterizedItem testParameterizedItem; +// TestParticleItem testParticleItem; +// TestLayerRoughnessItems testLayerRoughnessItems; +// TestParaCrystalItems testParaCrystalItems; +// TestSessionModel testSessionModel; +// TestGUICoreObjectCorrespondence testGUICoreObjectCorrespondence; +// TestSessionItem testSessionItem; +// TestMapperCases testMapperCases; +// TestMapperForItem testMapperForItem; +// TestParticleDistributionItem testParticleDistributionItem; +// TestGUIHelpers testGUIHelpers; + TestFitParameterModel testFitParameterModel; bool status(false); @@ -47,9 +49,11 @@ int main(int argc, char** argv) { // status |= QTest::qExec(&testSessionItem); // status |= QTest::qExec(&testMapperCases, argc, argv); // status |= QTest::qExec(&testSessionModel, argc, argv); - status |= QTest::qExec(&testMapperForItem, argc, argv); +// status |= QTest::qExec(&testMapperForItem, argc, argv); // status |= QTest::qExec(&testParticleDistributionItem, argc, argv); // status |= QTest::qExec(&testGUIHelpers, argc, argv); + status |= QTest::qExec(&testFitParameterModel, argc, argv); + return status; }