BornAgain  1.19.79
Simulate and fit neutron and x-ray scattering at grazing incidence
InstrumentsTreeModel.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file GUI/View/Instrument/InstrumentsTreeModel.cpp
6 //! @brief Implements class InstrumentsTreeModel
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_visibleTypes(All)
27  , m_namesAreEditable(false)
28  , m_enableEmptyHeadlines(true)
29 {
30 }
31 
33 {
34  if (b != m_enableEmptyHeadlines) {
35  beginResetModel();
37  endResetModel();
38  }
39 }
40 
42 {
43  if (m_visibleTypes.testFlag(type) != b) {
44  beginResetModel();
45  m_visibleTypes.setFlag(type, b);
46  endResetModel();
47  }
48 }
49 
51 {
52  // for (auto rank : m_visibleRanks) {
53  // if (!m_items[rank - 1].isEmpty()) {
54  // beginRemoveRows(indexOfHeadline(rank), 0, m_items[rank - 1].size() - 1);
55  // m_items[rank - 1] = m_model->InstrumentCollection(rank);
56  // endRemoveRows();
57  // }
58  // }
59  //
60  // updateSubscriptions();
61 }
62 
64 {
65  beginResetModel();
66  endResetModel();
67 }
68 
69 QList<InstrumentsTreeModel::InstrumentType> InstrumentsTreeModel::visibleTypes() const
70 {
71  QList<InstrumentsTreeModel::InstrumentType> result;
72 
73  const auto forType = [&](InstrumentType type) {
74  if (m_visibleTypes.testFlag(type)
75  && (m_enableEmptyHeadlines || !instruments(type).isEmpty()))
76  result << type;
77  };
78 
79  forType(Gisas);
80  forType(Offspec);
81  forType(Specular);
82  forType(DepthProbe);
83 
84  return result;
85 }
86 
87 QVector<InstrumentItem*> InstrumentsTreeModel::instruments(InstrumentType type) const
88 {
89  switch (type) {
90  case Gisas:
91  return m_model->instrumentItems([](const InstrumentItem* p) {
92  return dynamic_cast<const GISASInstrumentItem*>(p) != nullptr;
93  });
94  case Offspec:
95  return m_model->instrumentItems([](const InstrumentItem* p) {
96  return dynamic_cast<const OffspecInstrumentItem*>(p) != nullptr;
97  });
98  case Specular:
99  return m_model->instrumentItems([](const InstrumentItem* p) {
100  return dynamic_cast<const SpecularInstrumentItem*>(p) != nullptr;
101  });
102  case DepthProbe:
103  return m_model->instrumentItems([](const InstrumentItem* p) {
104  return dynamic_cast<const DepthProbeInstrumentItem*>(p) != nullptr;
105  });
106  default:
107  return {};
108  }
109 }
110 
112 {
113  for (auto t : visibleTypes())
114  if (auto instr = instruments(t); !instr.isEmpty())
115  return instr.first();
116 
117  return nullptr;
118 }
119 
121 {
122  int row = 0;
123  for (auto t : visibleTypes()) {
124  if (t == type)
125  return createIndex(row, 0, nullptr);
126  row++;
127  }
128 
129  return QModelIndex();
130 }
131 
132 QModelIndex InstrumentsTreeModel::index(int row, int column, const QModelIndex& parent) const
133 {
134  if (!hasIndex(row, column, parent))
135  return QModelIndex();
136 
137  if (!parent.isValid())
138  return createIndex(row, column, nullptr);
139 
140  for (auto type : visibleTypes())
141  if (parent == indexOfHeadline(type))
142  return createIndex(row, column, instruments(type)[row]);
143 
144  return QModelIndex();
145 }
146 
147 QModelIndex InstrumentsTreeModel::parent(const QModelIndex& index) const
148 {
149  if (!index.isValid())
150  return QModelIndex();
151 
152  if (index.internalPointer() == nullptr) // index is headline => no parent
153  return QModelIndex();
154 
155  auto* item = itemForIndex(index);
156  for (auto type : visibleTypes())
157  if (instruments(type).contains(item))
158  return indexOfHeadline(type);
159 
160  return QModelIndex();
161 }
162 
163 int InstrumentsTreeModel::columnCount(const QModelIndex& /*parent*/) const
164 {
165  return 1;
166 }
167 
168 int InstrumentsTreeModel::rowCount(const QModelIndex& parent) const
169 {
170  if (!parent.isValid())
171  return visibleTypes().size();
172 
173  // parent is a headline
174  for (auto type : visibleTypes())
175  if (parent == indexOfHeadline(type))
176  return instruments(type).size();
177 
178  return 0;
179 }
180 
181 QVariant InstrumentsTreeModel::data(const QModelIndex& index, int role) const
182 {
183  if (isHeadline(index)) {
184  QString title;
185  if (index == indexOfHeadline(Gisas))
186  title = "GISAS";
187  else if (index == indexOfHeadline(Offspec))
188  title = "Offspec";
189  else if (index == indexOfHeadline(Specular))
190  title = "Specular";
191  else if (index == indexOfHeadline(DepthProbe))
192  title = "DepthProbe";
193 
194  switch (role) {
195  case Qt::DisplayRole:
196  return title;
197 
198  case Qt::FontRole: {
199  QFont f(QApplication::font());
200  f.setPointSize(f.pointSize() * 1.5);
201  f.setBold(true);
202  return f;
203  }
204 
205  case Qt::SizeHintRole: {
206  QFont f(QApplication::font());
207  f.setPointSize(f.pointSize() * 1.5);
208  f.setBold(true);
209  QSize s = QFontMetrics(f).boundingRect(title).size();
210  return QSize(s.width() * 2, s.height() * 2);
211  }
212 
213  case Qt::TextAlignmentRole:
214  return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
215 
216  case Qt::BackgroundRole:
218 
219  case Qt::ForegroundRole:
221 
222  default:
223  return QVariant();
224  }
225  }
226 
227  auto* const item = itemForIndex(index);
228 
229  if (role == Qt::ToolTipRole)
230  return item->description();
231 
232  if (role == Qt::DisplayRole)
233  return item->instrumentName();
234 
235  if (role == Qt::EditRole)
236  return item->instrumentName();
237 
238  if (role == Qt::TextAlignmentRole)
239  return QVariant(Qt::AlignLeft | Qt::AlignTop);
240 
241  if (role == Qt::DecorationRole)
242  switch (instrumentType(item)) {
243  case Gisas:
244  return QIcon(":/images/gisas_instrument.svg");
245  case Offspec:
246  return QIcon(":/images/offspec_instrument.svg");
247  case Specular:
248  return QIcon(":/images/specular_instrument.svg");
249  case DepthProbe:
250  return QIcon(":/images/depth_instrument.svg");
251  default:
252  break;
253  }
254 
255  return QVariant();
256 }
257 
258 Qt::ItemFlags InstrumentsTreeModel::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 && m_namesAreEditable) // col 0 contains name of the data entry
267  f |= Qt::ItemIsEditable;
268 
269  return f;
270 }
271 
272 bool InstrumentsTreeModel::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)->setInstrumentName(value.toString());
279  emit dataChanged(index, index);
280  return true;
281  }
282 
283  if (role == Qt::ToolTipRole && index.column() == 0) {
284  itemForIndex(index)->setDescription(value.toString());
285  emit dataChanged(index, index);
286  return true;
287  }
288 
289  return false;
290 }
291 
292 InstrumentItem* InstrumentsTreeModel::itemForIndex(const QModelIndex& index) const
293 {
294  if (!index.isValid())
295  return nullptr;
296 
297  return reinterpret_cast<InstrumentItem*>(index.internalPointer());
298 }
299 
301 {
302  if (item == nullptr)
303  return QModelIndex();
304 
305  for (auto type : visibleTypes())
306  if (auto row = instruments(type).indexOf(item); row >= 0)
307  return createIndex(row, 0, item);
308 
309  return QModelIndex();
310 }
311 
313 {
314  QModelIndex index = indexForItem(item);
315  if (!index.isValid())
316  return;
317 
318  beginRemoveRows(index.parent(), index.row(), index.row());
319  m_model->removeInstrument(item);
320  endRemoveRows();
321 }
322 
323 bool InstrumentsTreeModel::isHeadline(const QModelIndex& index) const
324 {
325  if (!index.isValid())
326  return false;
327 
328  return index.internalPointer() == nullptr;
329 }
330 
332 {
333  if (item->is<GISASInstrumentItem>())
334  return Gisas;
335 
336  if (item->is<OffspecInstrumentItem>())
337  return Offspec;
338 
339  if (item->is<SpecularInstrumentItem>())
340  return Specular;
341 
342  if (item->is<DepthProbeInstrumentItem>())
343  return DepthProbe;
344 
345  ASSERT(false);
346  return None;
347 }
ApplicationSettings * appSettings
global pointer to the instance
Defines class ApplicationSettings.
Defines class InstrumentCollection.
Defines class InstrumentItem and all its children.
Defines class InstrumentsTreeModel.
const Palette & styleSheetPalette() const
QVector< InstrumentItem * > instrumentItems(const std::function< bool(const InstrumentItem *)> &accept) const
void removeInstrument(InstrumentItem *instrument)
Abstract base class for instrument-specific item classes.
bool is() const
void setDescription(const QString &description)
void setInstrumentName(const QString &instrumentName)
Qt::ItemFlags flags(const QModelIndex &index) const override
VisibleInstrumentTypes m_visibleTypes
bool setData(const QModelIndex &index, const QVariant &value, int role) override
static InstrumentType instrumentType(InstrumentItem *item)
QModelIndex parent(const QModelIndex &index) const override
QModelIndex indexForItem(InstrumentItem *item) const
InstrumentItem * topMostItem() const
The topmost visible item. Can be null of course.
InstrumentCollection * m_model
QList< InstrumentType > visibleTypes() const
int rowCount(const QModelIndex &parent=QModelIndex()) const override
QModelIndex indexOfHeadline(InstrumentType type) const
InstrumentItem * itemForIndex(const QModelIndex &index) const
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
InstrumentsTreeModel(QObject *parent, InstrumentCollection *model)
int columnCount(const QModelIndex &parent=QModelIndex()) const override
bool isHeadline(const QModelIndex &index) const
QVector< InstrumentItem * > instruments(InstrumentType type) const
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
void setTypeEnabled(InstrumentType type, bool b)
void removeItem(InstrumentItem *item)