BornAgain  1.19.79
Simulate and fit neutron and x-ray scattering at grazing incidence
FitParameterModel.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file GUI/Model/Model/FitParameterModel.cpp
6 //! @brief Implements class FitParameterAbsModel
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2021
11 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
12 //
13 // ************************************************************************************************
14 
23 #include "GUI/Util/Error.h"
24 #include <QColor>
25 #include <QMimeData>
26 
27 #include <boost/polymorphic_cast.hpp>
28 
29 using boost::polymorphic_downcast;
30 
31 #include <optional>
32 
34  : QAbstractItemModel(parent)
35  , m_parameterContainer(fitParContainer)
36 {
37  addColumn(COL_NAME, "Name", "Name of fit parameter");
38  addColumn(COL_TYPE, "Type", "Fit parameter limits type");
39  addColumn(COL_VALUE, "Value", "Starting value of fit parameter");
40  addColumn(COL_MIN, "Min", "Lower bound on fit parameter value");
41  addColumn(COL_MAX, "Max", "Upper bound on fit parameter value");
42 
43  connectModel(fitParContainer->model());
44 
46  [this](SessionItem* parentItem) {
47  if (parentItem != m_parameterContainer) {
48  throw Error("FitParameterModel::FitParameterModel() -> Error. "
49  "Wrong item reported.");
50  }
51  m_parameterContainer = nullptr;
52  },
53  this);
54 }
55 
57 {
60 }
61 
62 Qt::ItemFlags FitParameterModel::flags(const QModelIndex& index) const
63 {
65  return Qt::NoItemFlags;
66 
67  Qt::ItemFlags result = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
68  if (SessionItem* item = itemForIndex(index)) {
69  if (item->isEditable() && index.column() != COL_NAME)
70  result |= Qt::ItemIsEditable;
71  if (item->parentItem()->hasModelType<FitParameterLinkItem>() && index.column() == COL_NAME)
72  result |= Qt::ItemIsDragEnabled;
73  const bool allow_one_fit_parameter_to_have_more_than_one_link = true;
74  if (allow_one_fit_parameter_to_have_more_than_one_link) {
75  // drop is allowed to fit parameter container, and, to FitParameterItem itself.
76  // (i.e. we can have more than one link in single FitParameterItem)
77  if (item->hasModelType<FitParameterItem>()
79  result |= Qt::ItemIsDropEnabled;
80  }
81  } else {
82  // drop is allowed only to fit parameter container
83  // (i.e. only one link is allowed in FitParameterItem)
84  if (item->hasModelType<FitParameterContainerItem>())
85  result |= Qt::ItemIsDropEnabled;
86  }
87  }
88  return result;
89 }
90 
91 QModelIndex FitParameterModel::index(int row, int column, const QModelIndex& parent) const
92 {
93  if (!m_parameterContainer || row < 0 || column < 0 || column >= columnCount(QModelIndex())
94  || (parent.isValid() && parent.column() != COL_NAME))
95  return QModelIndex();
96 
97  SessionItem* parent_item = itemForIndex(parent);
98  ASSERT(parent_item);
99 
100  if (parent_item->hasModelType<FitParameterContainerItem>()) {
101  QVector<FitParameterItem*> fitParamItems =
102  polymorphic_downcast<FitParameterContainerItem*>(parent_item)->fitParameterItems();
103  if (row < fitParamItems.size()) {
104  FitParameterItem* fitParItem = fitParamItems[row];
105  SessionItem* itemToPack = nullptr;
106  switch (column) {
107  case COL_NAME:
108  itemToPack = fitParItem;
109  break;
110  case COL_TYPE:
111  itemToPack = fitParItem->typeItem();
112  break;
113  case COL_VALUE:
114  itemToPack = fitParItem->startValueItem();
115  break;
116  case COL_MIN:
117  itemToPack = fitParItem->minimumItem();
118  break;
119  case COL_MAX:
120  itemToPack = fitParItem->maximumItem();
121  break;
122  default:
123  itemToPack = nullptr;
124  }
125  return createIndex(row, column, itemToPack);
126  }
127  } else if (parent_item->hasModelType<FitParameterItem>() && column == COL_NAME) {
128  QVector<FitParameterLinkItem*> links =
129  polymorphic_downcast<FitParameterItem*>(parent_item)->linkItems();
130  if (row < links.size()) {
131  if (FitParameterLinkItem* linkItem = links.at(row))
132  return createIndex(row, column, linkItem->linkItem());
133  }
134  }
135  return QModelIndex();
136 }
137 
138 QModelIndex FitParameterModel::parent(const QModelIndex& child) const
139 {
141  return QModelIndex();
142 
143  if (!child.isValid())
144  return QModelIndex();
145 
146  if (SessionItem* child_item = itemForIndex(child)) {
147  if (SessionItem* parent_item = child_item->parentItem()) {
148  if (!isValidSourceItem(parent_item))
149  return QModelIndex();
150  if (parent_item->hasModelType<FitParameterLinkItem>()) {
151  SessionItem* fitPar = parent_item->parentItem();
152  if (!isValidSourceItem(fitPar))
153  return QModelIndex();
154  return createIndex(fitPar->parentRow(), 0, fitPar);
155  }
156  }
157  }
158  return QModelIndex();
159 }
160 
161 int FitParameterModel::rowCount(const QModelIndex& parent) const
162 {
164  return 0;
165 
166  if (parent.isValid() && parent.column() != COL_NAME)
167  return 0;
168 
169  SessionItem* parent_item = itemForIndex(parent);
170  if (parent_item != m_parameterContainer && !isValidSourceItem(parent_item))
171  return 0;
172 
173  if (parent_item->hasModelType<FitParameterContainerItem>())
174  return parent_item->numberOfChildren();
175  if (parent_item->hasModelType<FitParameterItem>())
176  return polymorphic_downcast<FitParameterItem*>(parent_item)->linkItems().size();
177  return 0;
178 }
179 
180 int FitParameterModel::columnCount(const QModelIndex& parent) const
181 {
183  return 0;
184 
185  if (parent.isValid() && parent.column() != COL_NAME)
186  return 0;
187 
188  if (!parent.isValid())
189  return NUM_COLUMNS;
190 
191  if (parent.isValid()) {
192  if (SessionItem* parentItem = itemForIndex(parent)) {
193  if (parentItem->hasModelType<FitParameterItem>())
194  return !polymorphic_downcast<FitParameterItem*>(parentItem)->linkItems().empty();
195  }
196  }
197  return 0;
198 }
199 
200 QVariant FitParameterModel::data(const QModelIndex& index, int role) const
201 {
203  return QVariant();
204 
205  if (!index.isValid() || index.column() < 0 || index.column() >= NUM_COLUMNS)
206  return QVariant();
207 
208  if (SessionItem* item = itemForIndex(index)) {
209  if (role == Qt::DisplayRole || role == Qt::EditRole) {
210  if (item->hasModelType<FitParameterItem>())
211  return item->displayName();
212  if (const auto* linkItem = dynamic_cast<FitParameterLinkItem*>(item->parentItem()))
213  return linkItem->title();
214  return item->value();
215  }
216  if (role == Qt::ForegroundRole && !item->isEditable())
217  return QVariant(QColor(Qt::gray));
218  if (role == Qt::ToolTipRole && item->hasModelType<FitParameterLinkItem>())
219  return item->value();
220  }
221  return QVariant();
222 }
223 
224 bool FitParameterModel::setData(const QModelIndex& index, const QVariant& value, int role)
225 {
227  return false;
228 
229  if (!index.isValid())
230  return false;
231  if (SessionItem* item = itemForIndex(index)) {
232  if (role == Qt::EditRole) {
233  item->setValue(value);
234  emit dataChanged(index, index);
235  return true;
236  }
237  }
238  return false;
239 }
240 
241 QStringList FitParameterModel::mimeTypes() const
242 {
243  QStringList types;
245  return types;
246 }
247 
248 QMimeData* FitParameterModel::mimeData(const QModelIndexList& indexes) const
249 {
250  auto* mimeData = new QMimeData();
251  QModelIndex index = indexes.first();
252  if (index.isValid()) {
253  if (SessionItem* item = itemForIndex(index)) {
254  QString path = item->value().toString();
255  auto* parameterItem = FitParameterHelper::getParameterItem(m_parameterContainer, path);
256  QByteArray data;
257  data.setNum(reinterpret_cast<qlonglong>(parameterItem));
259  }
260  }
261  return mimeData;
262 }
263 
264 bool FitParameterModel::canDropMimeData(const QMimeData* data, Qt::DropAction action, int row,
265  int column, const QModelIndex& parent) const
266 {
267  Q_UNUSED(data);
268  Q_UNUSED(action);
269  Q_UNUSED(row);
270  bool drop_is_possible(false);
271  if (parent.isValid())
272  drop_is_possible = true;
273  if (!parent.isValid() && row == -1 && column == -1)
274  drop_is_possible = true;
275  return drop_is_possible;
276 }
277 
278 bool FitParameterModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row,
279  int column, const QModelIndex& parent)
280 {
281  Q_UNUSED(action);
282  Q_UNUSED(row);
283  Q_UNUSED(column);
284 
285  if (parent.isValid()) {
286  if (SessionItem* fitParItem = itemForIndex(parent)) {
287  ASSERT(fitParItem->hasModelType<FitParameterItem>());
288  ParameterItem* parItem = reinterpret_cast<ParameterItem*>(
289  data->data(GUI::Session::XML::LinkMimeType).toULongLong());
290  ASSERT(parItem);
291  m_parameterContainer->addToFitParameter(parItem, fitParItem->displayName());
292  }
293  } else {
294  ParameterItem* parItem = reinterpret_cast<ParameterItem*>(
295  data->data(GUI::Session::XML::LinkMimeType).toULongLong());
296  ASSERT(parItem);
298  }
299  return true;
300 }
301 
302 QVariant FitParameterModel::headerData(int section, Qt::Orientation orientation, int role) const
303 {
304  if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
305  return m_columnNames.value(section);
306  if (role == Qt::ToolTipRole)
307  return m_columnToolTips.value(section);
308  return QVariant();
309 }
310 
311 void FitParameterModel::onSourceDataChanged(const QModelIndex& topLeft,
312  const QModelIndex& bottomRight,
313  const QVector<int>& roles)
314 {
315  Q_UNUSED(bottomRight);
316 
317  auto* sourceModel = qobject_cast<JobModel*>(sender());
318  ASSERT(sourceModel);
319  SessionItem* sourceItem = sourceModel->itemForIndex(topLeft);
320 
321  QModelIndex itemIndex = indexOfItem(sourceItem);
322 
323  if (itemIndex.isValid())
324  emit dataChanged(itemIndex, itemIndex, roles);
325 }
326 
327 void FitParameterModel::onSourceRowsRemoved(const QModelIndex& parent, int first, int last)
328 {
329  Q_UNUSED(parent);
330  Q_UNUSED(first);
331  Q_UNUSED(last);
332  beginResetModel();
333  endResetModel();
334 }
335 
337 {
339  return;
340  beginResetModel();
341  endResetModel();
342 }
343 
344 void FitParameterModel::connectModel(QAbstractItemModel* sourceModel, bool isConnect) const
345 {
346  ASSERT(sourceModel);
347  if (isConnect) {
348  connect(sourceModel, &QAbstractItemModel::dataChanged, this,
350  connect(sourceModel, &QAbstractItemModel::rowsRemoved, this,
352  connect(sourceModel, &QAbstractItemModel::modelAboutToBeReset, this,
354  } else {
355  disconnect(sourceModel, &QAbstractItemModel::dataChanged, this,
357  disconnect(sourceModel, &QAbstractItemModel::rowsRemoved, this,
359  disconnect(sourceModel, &QAbstractItemModel::modelAboutToBeReset, this,
361  }
362 }
363 
365  const QString& tooltip)
366 {
367  m_columnNames[id] = name;
368  m_columnToolTips[id] = tooltip;
369 }
370 
372 {
374  return QModelIndex();
375 
376  if (SessionItem* parent_item = item->parentItem()) {
377  if (parent_item->hasModelType<FitParameterContainerItem>()) {
378  if (item->hasModelType<FitParameterItem>())
379  return createIndex(item->parentRow(), 0, item);
380  } else if (parent_item->hasModelType<FitParameterItem>()) {
381  auto* fitParam = polymorphic_downcast<FitParameterItem*>(parent_item);
382  std::optional<int> col;
383  if (item == fitParam->typeItem())
384  col = COL_TYPE;
385  else if (item == fitParam->startValueItem())
386  col = COL_VALUE;
387  else if (item == fitParam->minimumItem())
388  col = COL_MIN;
389  else if (item == fitParam->maximumItem())
390  col = COL_MAX;
391  if (col)
392  return createIndex(parent_item->parentRow(), col.value(), item);
393  } else if (parent_item->hasModelType<FitParameterLinkItem>()) {
394  QVector<FitParameterLinkItem*> links =
395  polymorphic_downcast<FitParameterItem*>(parent_item->parentItem())->linkItems();
396  int index = links.indexOf(polymorphic_downcast<FitParameterLinkItem*>(parent_item));
397  return createIndex(index, 0, item);
398  }
399  }
400  return QModelIndex();
401 }
402 
403 SessionItem* FitParameterModel::itemForIndex(const QModelIndex& index) const
404 {
406  return nullptr;
407 
408  if (index.isValid()) {
409  auto* item = static_cast<SessionItem*>(index.internalPointer());
410  if (item) {
411  if (!isValidSourceItem(item))
412  return nullptr;
413  return item;
414  }
415  }
416  return m_parameterContainer;
417 }
418 
420 {
421  ASSERT(m_parameterContainer);
422  return m_parameterContainer->model();
423 }
424 
425 //! Returns true if given item still exists in source model
427 {
428  if (item == m_parameterContainer)
429  return true;
430  if (sourceModel()
432  return true;
433  return false;
434 }
Defines error class.
Defines class FitParameterContainerItem.
Defines namespace FitParameterHelper.
Defines class FitParameterItem.
Defines class FitParameterLinkItem.
Defines class FitParameterModel.
Defines class JobModel.
Defines namespace GUI::Model::Path.
Defines reader and writer classes for SessionModel.
The FitParameterContainerItem class is a collection of all defined fit parameters in JobItem.
void createFitParameter(ParameterItem *parameterItem)
Creates fit parameter from given ParameterItem, sets starting value to the value of ParameterItem,...
void addToFitParameter(ParameterItem *parameterItem, const QString &fitParName)
Adds given parameterItem to the existing fit parameter with display name fitParName....
FitParameterItems is a collection of items to define fit parameters in GUI.
SessionItem * minimumItem() const
SessionItem * maximumItem() const
SessionItem * typeItem() const
SessionItem * startValueItem() const
The FitParameterLinkItem class holds a link to ParameterItem in tuning tree.
int columnCount(const QModelIndex &parent) const override
Qt::ItemFlags flags(const QModelIndex &index) const override
int rowCount(const QModelIndex &parent) const override
QModelIndex indexOfItem(SessionItem *item) const
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
void onSourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector< int > &roles)
SessionItem * itemForIndex(const QModelIndex &index) const
bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const override
SessionModel * sourceModel() const
FitParameterModel(FitParameterContainerItem *fitParContainer, QObject *parent=nullptr)
QMap< int, QString > m_columnToolTips
bool setData(const QModelIndex &index, const QVariant &value, int role) override
~FitParameterModel() override
QModelIndex parent(const QModelIndex &child) const override
QStringList mimeTypes() const override
QModelIndex index(int row, int column, const QModelIndex &parent) const override
void addColumn(EColumn id, const QString &name, const QString &tooltip)
FitParameterContainerItem * m_parameterContainer
void connectModel(QAbstractItemModel *sourceModel, bool isConnect=true) const
QMimeData * mimeData(const QModelIndexList &indexes) const override
void onSourceRowsRemoved(const QModelIndex &parent, int first, int last)
QMap< int, QString > m_columnNames
bool isValidSourceItem(SessionItem *item) const
Returns true if given item still exists in source model.
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
void unsubscribe(const void *caller)
Cancels all subscriptions of given caller.
Definition: ModelMapper.cpp:78
void setOnItemDestroy(std::function< void(SessionItem *)> f, const void *caller=nullptr)
Definition: ModelMapper.cpp:67
The ParameterItem class represent a tuning value in a parameter tuning tree.
Base class for a GUI data item.
Definition: SessionItem.h:204
int numberOfChildren() const
Returns total number of children.
Definition: SessionItem.cpp:88
bool hasModelType() const
Definition: SessionItem.h:421
ModelMapper * mapper()
Returns the current model mapper of this item. Creates new one if necessary.
SessionModel * model() const
Returns model of this item.
Definition: SessionItem.cpp:60
SessionItem * parentItem() const
Returns parent of this item.
Definition: SessionItem.cpp:67
int parentRow()
Returns the index of the given item within its parent. Returns -1 when no parent is set.
QModelIndex index() const
Returns model index of this item.
Definition: SessionItem.cpp:74
Base class for a GUI data collection. A collection is e.g. all real data (RealDataModel)....
Definition: SessionModel.h:42
SessionItem * itemForIndex(const QModelIndex &index) const
ParameterItem * getParameterItem(FitParameterContainerItem *container, const QString &link)
Returns ParameterItem corresponding to given link.
bool isValidItem(SessionModel *model, SessionItem *item, const QModelIndex &parent)
Iterates through all the model and returns true if item is found. This is to.
Definition: ModelPath.cpp:20
QString const & name(EShape k)
Definition: particles.cpp:20
constexpr auto LinkMimeType
Definition: SessionXML.h:31