Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
QmitkPropertiesTableModel.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
14 
15 //# Own includes
16 #include "QmitkCustomVariants.h"
17 #include "mitkColorProperty.h"
19 #include "mitkProperties.h"
20 #include "mitkRenderingManager.h"
21 #include "mitkStringProperty.h"
22 
23 //# Toolkit includes
24 #include <QBrush>
25 #include <QColor>
26 #include <QStringList>
27 #include <itkCommand.h>
28 
29 //# PUBLIC CTORS,DTOR
31  : QAbstractTableModel(parent),
32  m_PropertyList(nullptr),
33  m_BlockEvents(false),
34  m_SortDescending(false),
35  m_FilterKeyWord("")
36 {
37  this->SetPropertyList(_PropertyList);
38 }
39 
41 {
42  // remove all event listeners by setting the property list to 0
43  this->SetPropertyList(nullptr);
44 }
45 
46 //# PUBLIC GETTER
48 {
49  return m_PropertyList.Lock();
50 }
51 
52 Qt::ItemFlags QmitkPropertiesTableModel::flags(const QModelIndex &index) const
53 {
54  // no editing so far, return default (enabled, selectable)
55  Qt::ItemFlags flags = QAbstractItemModel::flags(index);
56 
57  if (index.column() == PROPERTY_VALUE_COLUMN)
58  {
59  // there are also read only property items -> do not allow editing them
60  if (index.data(Qt::EditRole).isValid())
61  flags |= Qt::ItemIsEditable;
62 
63  if (index.data(Qt::CheckStateRole).isValid())
64  flags |= Qt::ItemIsUserCheckable;
65  }
66 
67  return flags;
68 }
69 
70 QVariant QmitkPropertiesTableModel::headerData(int section, Qt::Orientation orientation, int role) const
71 {
72  if (role != Qt::DisplayRole)
73  return QVariant();
74 
75  if (orientation == Qt::Horizontal)
76  {
77  switch (section)
78  {
80  return tr("Name");
81 
83  return tr("Value");
84 
85  default:
86  return QVariant();
87  }
88  }
89 
90  return QVariant();
91 }
92 
93 QVariant QmitkPropertiesTableModel::data(const QModelIndex &index, int role) const
94 {
95  // empty data by default
96  QVariant data;
97 
98  if (!index.isValid() || m_SelectedProperties.empty() || index.row() > (int)(m_SelectedProperties.size() - 1))
99  return data;
100 
101  // the properties name
102  if (index.column() == PROPERTY_NAME_COLUMN)
103  {
104  if (role == Qt::DisplayRole)
105  data = QString::fromStdString(m_SelectedProperties[index.row()].first);
106  }
107  // the real properties value
108  else if (index.column() == PROPERTY_VALUE_COLUMN)
109  {
110  mitk::BaseProperty *baseProp = m_SelectedProperties[index.row()].second;
111 
112  if (const mitk::ColorProperty *colorProp = dynamic_cast<const mitk::ColorProperty *>(baseProp))
113  {
114  mitk::Color col = colorProp->GetColor();
115  QColor qcol((int)(col.GetRed() * 255), (int)(col.GetGreen() * 255), (int)(col.GetBlue() * 255));
116  if (role == Qt::DisplayRole)
117  data.setValue<QColor>(qcol);
118  else if (role == Qt::EditRole)
119  data.setValue<QColor>(qcol);
120  }
121 
122  else if (mitk::BoolProperty *boolProp = dynamic_cast<mitk::BoolProperty *>(baseProp))
123  {
124  if (role == Qt::CheckStateRole)
125  data = boolProp->GetValue() ? Qt::Checked : Qt::Unchecked;
126  }
127 
128  else if (mitk::StringProperty *stringProp = dynamic_cast<mitk::StringProperty *>(baseProp))
129  {
130  if (role == Qt::DisplayRole)
131  data.setValue<QString>(QString::fromStdString(stringProp->GetValue()));
132  else if (role == Qt::EditRole)
133  data.setValue<QString>(QString::fromStdString(stringProp->GetValue()));
134  }
135 
136  else if (mitk::IntProperty *intProp = dynamic_cast<mitk::IntProperty *>(baseProp))
137  {
138  if (role == Qt::DisplayRole)
139  data.setValue<int>(intProp->GetValue());
140  else if (role == Qt::EditRole)
141  data.setValue<int>(intProp->GetValue());
142  }
143 
144  else if (mitk::FloatProperty *floatProp = dynamic_cast<mitk::FloatProperty *>(baseProp))
145  {
146  if (role == Qt::DisplayRole)
147  data.setValue<float>(floatProp->GetValue());
148  else if (role == Qt::EditRole)
149  data.setValue<float>(floatProp->GetValue());
150  }
151 
152  else if (mitk::EnumerationProperty *enumerationProp = dynamic_cast<mitk::EnumerationProperty *>(baseProp))
153  {
154  if (role == Qt::DisplayRole)
155  data.setValue<QString>(QString::fromStdString(baseProp->GetValueAsString()));
156  else if (role == Qt::EditRole)
157  {
158  QStringList values;
159  for (auto it = enumerationProp->Begin(); it != enumerationProp->End(); it++)
160  {
161  values << QString::fromStdString(it->second);
162  }
163  data.setValue<QStringList>(values);
164  }
165  }
166 
167  else
168  {
169  if (role == Qt::DisplayRole)
170  data.setValue<QString>(QString::fromStdString(m_SelectedProperties[index.row()].second->GetValueAsString()));
171  }
172  }
173 
174  return data;
175 }
176 
177 int QmitkPropertiesTableModel::rowCount(const QModelIndex & /*parent*/) const
178 {
179  // return the number of properties in the properties list.
180  return m_SelectedProperties.size();
181 }
182 
183 int QmitkPropertiesTableModel::columnCount(const QModelIndex & /*parent*/) const
184 {
185  return 2;
186 }
187 
188 //# PUBLIC SETTER
190 {
191  // if propertylist really changed
192  if (m_PropertyList != _PropertyList)
193  {
194  // Remove delete listener if there was a propertylist before
195  if (!m_PropertyList.IsExpired())
197 
198  // set new list
199  m_PropertyList = _PropertyList;
200 
201  if (!m_PropertyList.IsExpired())
202  {
203  auto command = itk::SimpleMemberCommand<QmitkPropertiesTableModel>::New();
204  command->SetCallbackFunction(this, &QmitkPropertiesTableModel::PropertyListDelete);
205  m_PropertyListDeleteObserverTag = m_PropertyList.Lock()->AddObserver(itk::DeleteEvent(), command);
206  }
207  this->Reset();
208  }
209 }
210 
212 {
213  if (!m_BlockEvents)
214  {
215  m_BlockEvents = true;
216  this->Reset();
217  m_BlockEvents = false;
218  }
219 }
220 
221 void QmitkPropertiesTableModel::PropertyModified(const itk::Object *caller, const itk::EventObject & /*event*/)
222 {
223  if (!m_BlockEvents)
224  {
225  m_BlockEvents = true;
226  int row = this->FindProperty(dynamic_cast<const mitk::BaseProperty *>(caller));
227 
228  QModelIndex indexOfChangedProperty = index(row, 1);
229 
230  emit dataChanged(indexOfChangedProperty, indexOfChangedProperty);
231  m_BlockEvents = false;
232  }
233 }
234 
235 void QmitkPropertiesTableModel::PropertyDelete(const itk::Object *caller, const itk::EventObject & /*event*/)
236 {
237  if (!m_BlockEvents)
238  {
239  m_BlockEvents = true;
240  int row = this->FindProperty(dynamic_cast<const mitk::BaseProperty *>(caller));
241  if (row >= 0)
242  this->Reset();
243  m_BlockEvents = false;
244  }
245 }
246 
247 bool QmitkPropertiesTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
248 {
249  // TODO: check 'role' condition
250  if (index.isValid() && !m_SelectedProperties.empty() && index.row() < (int)(m_SelectedProperties.size()) &&
251  (role == Qt::EditRole || role == Qt::CheckStateRole))
252  {
253  // block all events now!
254  m_BlockEvents = true;
255 
256  auto propertyList = m_PropertyList.Lock();
257 
258  // the properties name
259  if (index.column() == PROPERTY_VALUE_COLUMN)
260  {
261  mitk::BaseProperty *baseProp = m_SelectedProperties[index.row()].second;
262 
263  if (mitk::ColorProperty *colorProp = dynamic_cast<mitk::ColorProperty *>(baseProp))
264  {
265  QColor qcolor = value.value<QColor>();
266  if (!qcolor.isValid())
267  return false;
268 
269  mitk::Color col = colorProp->GetColor();
270  col.SetRed(qcolor.red() / 255.0);
271  col.SetGreen(qcolor.green() / 255.0);
272  col.SetBlue(qcolor.blue() / 255.0);
273  colorProp->SetColor(col);
274  propertyList->InvokeEvent(itk::ModifiedEvent());
275  propertyList->Modified();
276 
278  }
279 
280  else if (mitk::BoolProperty *boolProp = dynamic_cast<mitk::BoolProperty *>(baseProp))
281  {
282  boolProp->SetValue(value.toInt() == Qt::Checked ? true : false);
283  propertyList->InvokeEvent(itk::ModifiedEvent());
284  propertyList->Modified();
285 
287  }
288 
289  else if (mitk::StringProperty *stringProp = dynamic_cast<mitk::StringProperty *>(baseProp))
290  {
291  stringProp->SetValue((value.value<QString>()).toStdString());
292  propertyList->InvokeEvent(itk::ModifiedEvent());
293  propertyList->Modified();
294 
296  }
297 
298  else if (mitk::IntProperty *intProp = dynamic_cast<mitk::IntProperty *>(baseProp))
299  {
300  int intValue = value.value<int>();
301  if (intValue != intProp->GetValue())
302  {
303  intProp->SetValue(intValue);
304  propertyList->InvokeEvent(itk::ModifiedEvent());
305  propertyList->Modified();
306 
308  }
309  }
310 
311  else if (mitk::FloatProperty *floatProp = dynamic_cast<mitk::FloatProperty *>(baseProp))
312  {
313  float floatValue = value.value<float>();
314  if (floatValue != floatProp->GetValue())
315  {
316  floatProp->SetValue(floatValue);
317  propertyList->InvokeEvent(itk::ModifiedEvent());
318  propertyList->Modified();
319 
321  }
322  }
323 
324  else if (mitk::EnumerationProperty *enumerationProp = dynamic_cast<mitk::EnumerationProperty *>(baseProp))
325  {
326  std::string activatedItem = value.value<QString>().toStdString();
327  if (activatedItem != enumerationProp->GetValueAsString())
328  {
329  if (enumerationProp->IsValidEnumerationValue(activatedItem))
330  {
331  enumerationProp->SetValue(activatedItem);
332  propertyList->InvokeEvent(itk::ModifiedEvent());
333  propertyList->Modified();
334 
336  }
337  }
338  }
339  }
340 
341  // property was changed by us, now we can accept property changes triggered by someone else
342  m_BlockEvents = false;
343  emit dataChanged(index, index);
344  return true;
345  }
346 
347  return false;
348 }
349 
350 void QmitkPropertiesTableModel::sort(int column, Qt::SortOrder order /*= Qt::AscendingOrder */)
351 {
352  bool sortDescending = (order == Qt::DescendingOrder) ? true : false;
353 
354  // do not sort twice !!! (dont know why, but qt calls this func twice. STUPID!)
355  if (sortDescending != m_SortDescending)
356  {
357  m_SortDescending = sortDescending;
358 
360 
363 
364  if (column == PROPERTY_VALUE_COLUMN)
366 
367  PropertyDataSetCompareFunction compareFunc(_CompareCriteria, _CompareOperator);
368  std::sort(m_SelectedProperties.begin(), m_SelectedProperties.end(), compareFunc);
369 
370  QAbstractTableModel::beginResetModel();
371  QAbstractTableModel::endResetModel();
372  }
373 }
374 
375 //# PROTECTED GETTER
377 {
378  int row = -1;
379 
380  if (_Property)
381  {
382  // search for property that changed and emit datachanged on the corresponding ModelIndex
383  std::vector<PropertyDataSet>::const_iterator propertyIterator;
384 
385  for (propertyIterator = m_SelectedProperties.begin(); propertyIterator != m_SelectedProperties.end();
386  propertyIterator++)
387  {
388  if (propertyIterator->second == _Property)
389  break;
390  }
391 
392  if (propertyIterator != m_SelectedProperties.end())
393  row = std::distance(m_SelectedProperties.begin(), propertyIterator);
394  }
395 
396  return row;
397 }
398 
399 //# PROTECTED SETTER
401 {
402  // subscribe for modified event
403  itk::MemberCommand<QmitkPropertiesTableModel>::Pointer _PropertyDataSetModifiedCommand =
404  itk::MemberCommand<QmitkPropertiesTableModel>::New();
405  _PropertyDataSetModifiedCommand->SetCallbackFunction(this, &QmitkPropertiesTableModel::PropertyModified);
407  _PropertyDataSet.second->AddObserver(itk::ModifiedEvent(), _PropertyDataSetModifiedCommand));
408 
409  // subscribe for delete event
410  itk::MemberCommand<QmitkPropertiesTableModel>::Pointer _PropertyDataSetDeleteCommand =
411  itk::MemberCommand<QmitkPropertiesTableModel>::New();
412  _PropertyDataSetDeleteCommand->SetCallbackFunction(this, &QmitkPropertiesTableModel::PropertyDelete);
414  _PropertyDataSet.second->AddObserver(itk::DeleteEvent(), _PropertyDataSetDeleteCommand));
415 
416  // add to the selection
417  m_SelectedProperties.push_back(_PropertyDataSet);
418 }
419 
421 {
422  PropertyDataSet &_PropertyDataSet = m_SelectedProperties.at(_Index);
423 
424  // remove modified event listener
425  _PropertyDataSet.second->RemoveObserver(m_PropertyModifiedObserverTags[_Index]);
427  // remove delete event listener
428  _PropertyDataSet.second->RemoveObserver(m_PropertyDeleteObserverTags[_Index]);
430  // remove from selection
431  m_SelectedProperties.erase(m_SelectedProperties.begin() + _Index);
432 }
433 
435 {
436  // remove all selected properties
437  while (!m_SelectedProperties.empty())
438  {
440  }
441 
442  std::vector<PropertyDataSet> allPredicates;
443  if (!m_PropertyList.IsExpired())
444  {
445  auto propertyList = m_PropertyList.Lock();
446 
447  // first of all: collect all properties from the list
448  for (auto it = propertyList->GetMap()->begin(); it != propertyList->GetMap()->end(); it++)
449  {
450  allPredicates.push_back(*it); //% TODO
451  }
452  }
453  // make a subselection if a keyword is specified
454  if (!m_FilterKeyWord.empty())
455  {
456  std::vector<PropertyDataSet> subSelection;
457 
458  for (auto it = allPredicates.begin(); it != allPredicates.end(); it++)
459  {
460  // add this to the selection if it is matched by the keyword
461  if ((*it).first.find(m_FilterKeyWord) != std::string::npos)
462  subSelection.push_back((*it));
463  }
464  allPredicates.clear();
465  allPredicates = subSelection;
466  }
467 
468  PropertyDataSet tmpPropertyDataSet;
469  // add all selected now to the Model
470  for (auto it = allPredicates.begin(); it != allPredicates.end(); it++)
471  {
472  tmpPropertyDataSet = *it;
473  this->AddSelectedProperty(tmpPropertyDataSet);
474  }
475 
476  // sort the list as indicated by m_SortDescending
477  this->sort(m_SortDescending);
478 
479  // model was resetted
480  QAbstractTableModel::beginResetModel();
481  QAbstractTableModel::endResetModel();
482 }
483 
485 {
486  m_FilterKeyWord = _FilterKeyWord;
487  this->Reset();
488 }
489 
491  CompareCriteria _CompareCriteria, CompareOperator _CompareOperator)
492  : m_CompareCriteria(_CompareCriteria), m_CompareOperator(_CompareOperator)
493 {
494 }
495 
497  const PropertyDataSet &_Right) const
498 {
499  switch (m_CompareCriteria)
500  {
501  case CompareByValue:
502  if (m_CompareOperator == Less)
503  return (_Left.second->GetValueAsString() < _Right.second->GetValueAsString());
504  else
505  return (_Left.second->GetValueAsString() > _Right.second->GetValueAsString());
506  break;
507 
508  // CompareByName:
509  default:
510  if (m_CompareOperator == Less)
511  return (_Left.first < _Right.first);
512  else
513  return (_Left.first > _Right.first);
514  break;
515  }
516 }
518  const std::string &_FilterKeyWord)
519  : m_FilterKeyWord(_FilterKeyWord)
520 {
521 }
522 
524 {
525  if (m_FilterKeyWord.empty())
526  return true;
527  return (_Elem.first.find(m_FilterKeyWord) == 0);
528 }
itk::SmartPointer< T > Lock() const
std::vector< PropertyDataSet > m_SelectedProperties
Store the properties in a vector so that they may be sorted.
signed integer value
Definition: jsoncpp.h:348
virtual void SetFilterPropertiesKeyWord(std::string _FilterKeyWord)
Set a keyword for filtering of properties. Only properties beginning with this string will be shown...
QmitkPropertiesTableModel(QObject *parent=nullptr, mitk::PropertyList::Pointer _PropertyList=nullptr)
bool operator()(const PropertyDataSet &_Elem) const
The reimplemented compare function.
Key-value list holding instances of BaseProperty.
CompareCriteria
Specifies field of the property with which it will be sorted.
virtual void PropertyModified(const itk::Object *caller, const itk::EventObject &event)
Called when a single property was changed. Send a model changed event to the Qt-outer world...
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
Overwritten from QAbstractTableModel. Returns the flags what can be done with the items (view...
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Overwritten from QAbstractTableModel. Returns the flags what can be done with the items (view...
virtual void PropertyListDelete()
Gets called when the list is about to be deleted.
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
Overwritten from QAbstractTableModel. Returns the flags what can be done with the items (view...
A struct that inherits from std::binary_function. You can use it in std::sort algorithm for sorting t...
The ColorProperty class RGB color property.
void RemoveSelectedProperty(unsigned int _Index)
mitk::WeakPointer< mitk::PropertyList > m_PropertyList
virtual std::string GetValueAsString() const
Abstract base class for properties.
std::pair< std::string, mitk::BaseProperty::Pointer > PropertyDataSet
bool setData(const QModelIndex &index, const QVariant &value, int role) override
static RenderingManager * GetInstance()
bool IsExpired() const noexcept
mitk::PropertyList::Pointer GetPropertyList() const
std::vector< unsigned long > m_PropertyModifiedObserverTags
Holds all tags of Modified Event Listeners. We need it to remove them again.
~QmitkPropertiesTableModel() override
Standard dtor. Nothing to do here.
bool m_SortDescending
The property is true when the property list is sorted in descending order.
virtual void PropertyDelete(const itk::Object *caller, const itk::EventObject &event)
Called when a single property was changed. Send a model changed event to the Qt-outer world...
void sort(int column, Qt::SortOrder order=Qt::AscendingOrder) override
Reimplemented sort function from QAbstractTableModel to enable sorting on the table.
itk::RGBPixel< float > Color
Color Standard RGB color typedef (float)
bool m_BlockEvents
Indicates if this class should neglect all incoming events because the class itself triggered the eve...
void SetPropertyList(mitk::PropertyList *_PropertyList)
PropertyDataSetCompareFunction(CompareCriteria _CompareCriteria=CompareByName, CompareOperator _CompareOperator=Less)
Creates a PropertyDataSetCompareFunction. A CompareCriteria and a CompareOperator must be given...
std::string m_FilterKeyWord
If set to any value, only properties containing the specified keyword in their name will be shown...
bool operator()(const PropertyDataSet &_Left, const PropertyDataSet &_Right) const
The reimplemented compare function.
Property for strings.
int columnCount(const QModelIndex &parent) const override
void AddSelectedProperty(PropertyDataSet &_PropertyDataSet)
int FindProperty(const mitk::BaseProperty *_Property) const
Searches for the specified property and returns the row of the element in this QTableModel. If any errors occur, the function returns -1.
std::vector< unsigned long > m_PropertyDeleteObserverTags
Holds all tags of Modified Event Listeners. We need it to remove them again.
void RequestUpdateAll(RequestType type=REQUEST_UPDATE_ALL)
Qt::ItemFlags flags(const QModelIndex &index) const override
Overwritten from QAbstractTableModel. Returns the flags what can be done with the items (view...