BornAgain  1.19.79
Simulate and fit neutron and x-ray scattering at grazing incidence
RealDataTreeModel.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file GUI/View/Import/RealDataTreeModel.cpp
6 //! @brief Implements class RealDataTreeModel
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 
19 #include <QApplication>
20 #include <QtCore>
21 #include <QtGui>
22 
24  : QAbstractItemModel(parent)
25  , m_model(model)
26  , m_visibleRanks({1, 2})
27 {
28  for (auto rank : m_visibleRanks)
29  m_items[rank - 1] = model->realDataItems(rank);
30 
31  updateSubscriptions();
32 
33  connect(m_model, &RealDataModel::modelAboutToBeReset, this, &RealDataTreeModel::clear,
34  Qt::UniqueConnection);
35 }
36 
37 void RealDataTreeModel::setVisibleRanks(QSet<int> visibleRanks)
38 {
39  if (m_visibleRanks == visibleRanks)
40  return;
41 
42  m_visibleRanks = visibleRanks;
43 
44  beginResetModel();
45  for (auto rank : m_visibleRanks)
46  m_items[rank - 1] = m_model->realDataItems(rank);
47  endResetModel();
48 
50 }
51 
53 {
54  for (auto rank : m_visibleRanks) {
55  if (!m_items[rank - 1].isEmpty()) {
56  beginRemoveRows(indexOfHeadline(rank), 0, m_items[rank - 1].size() - 1);
57  m_items[rank - 1] = m_model->realDataItems(rank);
58  endRemoveRows();
59  }
60  }
61 
63 }
64 
66 {
67  beginResetModel();
68  m_items[0].clear();
69  m_items[1].clear();
70  endResetModel();
72 }
73 
75 {
76  QModelIndex index = indexForItem(item);
77  if (!index.isValid())
78  return;
79 
80  if (item->dataLoader())
81  item->dataLoader()->disconnect(this);
82 
83  const int rank = item->isSpecularData() ? 1 : 2;
84  if (m_visibleRanks.contains(rank)) {
85  const int rowOfItem = m_items[rank - 1].indexOf(item);
86  beginRemoveRows(indexOfHeadline(rank), rowOfItem, rowOfItem);
87  m_items[rank - 1].removeAll(item);
88  m_model->remove(item);
89  endRemoveRows();
90  }
91 }
92 
94 {
95  return insertDataItem(1);
96 }
97 
99 {
100  return insertDataItem(2);
101 }
102 
104 {
105  auto* newItem = m_model->insertDataItem(rank);
106  if (!m_visibleRanks.contains(rank))
107  return newItem;
108 
109  const int rowOfItem = m_model->realDataItems(rank).indexOf(newItem);
110  beginInsertRows(indexOfHeadline(rank), rowOfItem, rowOfItem);
111  m_items[rank - 1] = m_model->realDataItems(rank);
112  endInsertRows();
114  return newItem;
115 }
116 
118 {
119  if (!m_items[0].isEmpty() && m_visibleRanks.contains(1))
120  return m_items[0].first();
121  if (!m_items[1].isEmpty() && m_visibleRanks.contains(2))
122  return m_items[1].first();
123  return nullptr;
124 }
125 
126 QModelIndex RealDataTreeModel::indexOfHeadline(int rank) const
127 {
128  if (!m_visibleRanks.contains(rank))
129  return QModelIndex();
130 
131  if (rank == 1)
132  return createIndex(0, 0, nullptr);
133 
134  if (rank == 2) {
135  const bool has1D = m_visibleRanks.contains(1);
136  return createIndex(has1D ? 1 : 0, 0, nullptr);
137  }
138 
139  return QModelIndex();
140 }
141 
142 QModelIndex RealDataTreeModel::index(int row, int column, const QModelIndex& parent) const
143 {
144  if (!hasIndex(row, column, parent))
145  return QModelIndex();
146 
147  if (!parent.isValid())
148  return createIndex(row, column, nullptr);
149 
150  for (auto rank : m_visibleRanks)
151  if (parent == indexOfHeadline(rank))
152  return createIndex(row, column, m_items[rank - 1][row]);
153 
154  return QModelIndex();
155 }
156 
157 QModelIndex RealDataTreeModel::parent(const QModelIndex& index) const
158 {
159  if (!index.isValid())
160  return QModelIndex();
161 
162  if (index.internalPointer() == nullptr) // index is headline => no parent
163  return QModelIndex();
164 
165  if (itemForIndex(index)->isSpecularData())
166  return indexOfHeadline(1);
167 
168  return indexOfHeadline(2);
169 }
170 
171 int RealDataTreeModel::columnCount(const QModelIndex& /*parent*/) const
172 {
173  return 1;
174 }
175 
176 int RealDataTreeModel::rowCount(const QModelIndex& parent) const
177 {
178  if (!parent.isValid())
179  return m_visibleRanks.size();
180 
181  // parent is a headline
182  for (int rank : m_visibleRanks)
183  if (parent == indexOfHeadline(rank))
184  return m_items[rank - 1].size();
185 
186  return 0;
187 }
188 
189 QVariant RealDataTreeModel::data(const QModelIndex& index, int role) const
190 {
191  if (isHeadline(index)) {
192  QString title = (index == indexOfHeadline(1)) ? "1D Data" : "2D Data";
193  if (m_visibleRanks.size() < 2)
194  title = "Data";
195 
196  switch (role) {
197  case Qt::DisplayRole:
198  return title;
199 
200  case Qt::FontRole: {
201  QFont f(QApplication::font());
202  f.setPointSize(f.pointSize() * 1.5);
203  f.setBold(true);
204  return f;
205  }
206 
207  case Qt::SizeHintRole: {
208  QFont f(QApplication::font());
209  f.setPointSize(f.pointSize() * 1.5);
210  f.setBold(true);
211  QSize s = QFontMetrics(f).boundingRect(title).size();
212  return QSize(s.width() * 2, s.height() * 2);
213  }
214 
215  case Qt::TextAlignmentRole:
216  return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
217 
218  case Qt::BackgroundRole:
220 
221  case Qt::ForegroundRole:
223 
224  default:
225  return QVariant();
226  }
227  }
228 
229  auto* const item = itemForIndex(index);
230 
231  if (role == Qt::ToolTipRole)
232  return QString();
233 
234  if (role == Qt::DecorationRole) {
235  if (item->isSpecularData())
236  return item->hasImportErrors() ? QIcon(":/images/warning_16x16.png")
237  : QIcon(":/images/1D_OK.png");
238  return QIcon(":/images/2D_OK.png");
239  }
240 
241  if (role == Qt::DisplayRole) {
242  const auto numErrors =
243  (item->dataLoader() != nullptr) ? item->dataLoader()->numErrors() : 0;
244 
245  if (numErrors == 0)
246  return item->dataName();
247  if (numErrors == 1)
248  return item->dataName() + " (1 parser warning)";
249  return item->dataName() + QString(" (%1 parser warnings)").arg(numErrors);
250  }
251 
252  if (role == Qt::EditRole)
253  return item->dataName();
254 
255  return QVariant();
256 }
257 
258 Qt::ItemFlags RealDataTreeModel::flags(const QModelIndex& index) const
259 {
260  if (isHeadline(index) || !index.isValid())
261  return Qt::NoItemFlags;
262 
263  auto f = QAbstractItemModel::flags(index);
264  f |= Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled;
265 
266  if (index.column() == 0) // col 0 contains name of the data entry
267  f |= Qt::ItemIsEditable;
268 
269  return f;
270 }
271 
272 bool RealDataTreeModel::setData(const QModelIndex& index, const QVariant& value, int role)
273 {
274  if (!index.isValid())
275  return false;
276 
277  if (role == Qt::EditRole && index.column() == 0) {
278  itemForIndex(index)->setDataName(value.toString());
279  emit dataChanged(index, index);
280  return true;
281  }
282 
283  return false;
284 }
285 
286 RealDataItem* RealDataTreeModel::itemForIndex(const QModelIndex& index) const
287 {
288  if (!index.isValid())
289  return nullptr;
290 
291  return reinterpret_cast<RealDataItem*>(index.internalPointer());
292 }
293 
295 {
296  if (item == nullptr)
297  return QModelIndex();
298 
299  const int rank = item->isSpecularData() ? 1 : 2;
300  if (m_visibleRanks.contains(rank))
301  if (auto index = m_items[rank - 1].indexOf(item); index >= 0)
302  return createIndex(index, 0, item);
303 
304  return QModelIndex();
305 }
306 
307 bool RealDataTreeModel::isHeadline(const QModelIndex& index) const
308 {
309  if (!index.isValid())
310  return false;
311 
312  return index.internalPointer() == nullptr;
313 }
314 
316 {
317  for (auto* item : m_items[0])
318  connect(item, &RealDataItem::importContentsProcessed, this,
319  [=]() { onContentsProcessed(item); });
320 
321  for (auto* item : m_items[1])
322  connect(item, &RealDataItem::importContentsProcessed, this,
323  [=]() { onContentsProcessed(item); });
324 }
325 
327 {
328  QModelIndex index = indexForItem(item);
329  emit dataChanged(index, index);
330 }
ApplicationSettings * appSettings
global pointer to the instance
Defines class ApplicationSettings.
Defines class RealDataItem.
Defines class RealDataModel.
Defines class RealDataTreeModel.
const Palette & styleSheetPalette() const
Provides access to experimental data, for display and fitting. Owns an AbstractDataLoader.
Definition: RealDataItem.h:33
bool isSpecularData() const
AbstractDataLoader * dataLoader() const
void setDataName(const QString &name)
void importContentsProcessed()
The RealDataModel class is a model to store all imported RealDataItem's.
Definition: RealDataModel.h:24
QVector< RealDataItem * > realDataItems() const
RealDataItem * insertDataItem(int rank)
void remove(RealDataItem *item)
int rowCount(const QModelIndex &parent=QModelIndex()) const override
QModelIndex parent(const QModelIndex &index) const override
QModelIndex indexForItem(RealDataItem *item) const
QSet< int > m_visibleRanks
Qt::ItemFlags flags(const QModelIndex &index) const override
bool setData(const QModelIndex &index, const QVariant &value, int role) override
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
RealDataItem * insertIntensityDataItem()
bool isHeadline(const QModelIndex &index) const
RealDataModel * m_model
int columnCount(const QModelIndex &parent=QModelIndex()) const override
RealDataTreeModel(QObject *parent, RealDataModel *model)
RealDataItem * topMostItem() const
The topmost visible item. Can be null of course.
RealDataItem * insertSpecularDataItem()
RealDataItem * itemForIndex(const QModelIndex &index) const
QVector< RealDataItem * > m_items[2]
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
void onContentsProcessed(RealDataItem *item)
void removeItem(RealDataItem *item)
void setVisibleRanks(QSet< int > visibleRanks)
QModelIndex indexOfHeadline(int rank) const
RealDataItem * insertDataItem(int rank)