Medical Imaging Interaction Toolkit  2016.11.0
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,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
18 
19 //# Own includes
20 #include "QmitkCustomVariants.h"
21 #include "mitkColorProperty.h"
23 #include "mitkProperties.h"
24 #include "mitkRenderingManager.h"
25 #include "mitkStringProperty.h"
26 
27 //# Toolkit includes
28 #include <QBrush>
29 #include <QColor>
30 #include <QStringList>
31 #include <itkCommand.h>
32 
33 //# PUBLIC CTORS,DTOR
35  : QAbstractTableModel(parent),
36  m_PropertyList(nullptr),
37  m_BlockEvents(false),
38  m_SortDescending(false),
39  m_FilterKeyWord("")
40 {
41  this->SetPropertyList(_PropertyList);
42 }
43 
45 {
46  // remove all event listeners by setting the property list to 0
47  this->SetPropertyList(nullptr);
48 }
49 
50 //# PUBLIC GETTER
52 {
53  return m_PropertyList.GetPointer();
54 }
55 
56 Qt::ItemFlags QmitkPropertiesTableModel::flags(const QModelIndex &index) const
57 {
58  // no editing so far, return default (enabled, selectable)
59  Qt::ItemFlags flags = QAbstractItemModel::flags(index);
60 
61  if (index.column() == PROPERTY_VALUE_COLUMN)
62  {
63  // there are also read only property items -> do not allow editing them
64  if (index.data(Qt::EditRole).isValid())
65  flags |= Qt::ItemIsEditable;
66 
67  if (index.data(Qt::CheckStateRole).isValid())
68  flags |= Qt::ItemIsUserCheckable;
69  }
70 
71  return flags;
72 }
73 
74 QVariant QmitkPropertiesTableModel::headerData(int section, Qt::Orientation orientation, int role) const
75 {
76  if (role != Qt::DisplayRole)
77  return QVariant();
78 
79  if (orientation == Qt::Horizontal)
80  {
81  switch (section)
82  {
84  return tr("Name");
85 
87  return tr("Value");
88 
89  default:
90  return QVariant();
91  }
92  }
93 
94  return QVariant();
95 }
96 
97 QVariant QmitkPropertiesTableModel::data(const QModelIndex &index, int role) const
98 {
99  // empty data by default
100  QVariant data;
101 
102  if (!index.isValid() || m_SelectedProperties.empty() || index.row() > (int)(m_SelectedProperties.size() - 1))
103  return data;
104 
105  // the properties name
106  if (index.column() == PROPERTY_NAME_COLUMN)
107  {
108  if (role == Qt::DisplayRole)
109  data = QString::fromStdString(m_SelectedProperties[index.row()].first);
110  }
111  // the real properties value
112  else if (index.column() == PROPERTY_VALUE_COLUMN)
113  {
114  mitk::BaseProperty *baseProp = m_SelectedProperties[index.row()].second;
115 
116  if (const mitk::ColorProperty *colorProp = dynamic_cast<const mitk::ColorProperty *>(baseProp))
117  {
118  mitk::Color col = colorProp->GetColor();
119  QColor qcol((int)(col.GetRed() * 255), (int)(col.GetGreen() * 255), (int)(col.GetBlue() * 255));
120  if (role == Qt::DisplayRole)
121  data.setValue<QColor>(qcol);
122  else if (role == Qt::EditRole)
123  data.setValue<QColor>(qcol);
124  }
125 
126  else if (mitk::BoolProperty *boolProp = dynamic_cast<mitk::BoolProperty *>(baseProp))
127  {
128  if (role == Qt::CheckStateRole)
129  data = boolProp->GetValue() ? Qt::Checked : Qt::Unchecked;
130  }
131 
132  else if (mitk::StringProperty *stringProp = dynamic_cast<mitk::StringProperty *>(baseProp))
133  {
134  if (role == Qt::DisplayRole)
135  data.setValue<QString>(QString::fromStdString(stringProp->GetValue()));
136  else if (role == Qt::EditRole)
137  data.setValue<QString>(QString::fromStdString(stringProp->GetValue()));
138  }
139 
140  else if (mitk::IntProperty *intProp = dynamic_cast<mitk::IntProperty *>(baseProp))
141  {
142  if (role == Qt::DisplayRole)
143  data.setValue<int>(intProp->GetValue());
144  else if (role == Qt::EditRole)
145  data.setValue<int>(intProp->GetValue());
146  }
147 
148  else if (mitk::FloatProperty *floatProp = dynamic_cast<mitk::FloatProperty *>(baseProp))
149  {
150  if (role == Qt::DisplayRole)
151  data.setValue<float>(floatProp->GetValue());
152  else if (role == Qt::EditRole)
153  data.setValue<float>(floatProp->GetValue());
154  }
155 
156  else if (mitk::EnumerationProperty *enumerationProp = dynamic_cast<mitk::EnumerationProperty *>(baseProp))
157  {
158  if (role == Qt::DisplayRole)
159  data.setValue<QString>(QString::fromStdString(baseProp->GetValueAsString()));
160  else if (role == Qt::EditRole)
161  {
162  QStringList values;
163  for (auto it = enumerationProp->Begin(); it != enumerationProp->End(); it++)
164  {
165  values << QString::fromStdString(it->second);
166  }
167  data.setValue<QStringList>(values);
168  }
169  }
170 
171  else
172  {
173  if (role == Qt::DisplayRole)
174  data.setValue<QString>(QString::fromStdString(m_SelectedProperties[index.row()].second->GetValueAsString()));
175  }
176  }
177 
178  return data;
179 }
180 
181 int QmitkPropertiesTableModel::rowCount(const QModelIndex & /*parent*/) const
182 {
183  // return the number of properties in the properties list.
184  return m_SelectedProperties.size();
185 }
186 
187 int QmitkPropertiesTableModel::columnCount(const QModelIndex & /*parent*/) const
188 {
189  return 2;
190 }
191 
192 //# PUBLIC SETTER
194 {
195  // if propertylist really changed
196  if (m_PropertyList.GetPointer() != _PropertyList)
197  {
198  // Remove delete listener if there was a propertylist before
200  {
203  }
204 
205  // set new list
206  m_PropertyList = _PropertyList;
207 
209  {
212  }
213  this->Reset();
214  }
215 }
216 
217 void QmitkPropertiesTableModel::PropertyListDelete(const itk::Object * /*_PropertyList*/)
218 {
219  if (!m_BlockEvents)
220  {
221  m_BlockEvents = true;
222  this->Reset();
223  m_BlockEvents = false;
224  }
225 }
226 
227 void QmitkPropertiesTableModel::PropertyModified(const itk::Object *caller, const itk::EventObject & /*event*/)
228 {
229  if (!m_BlockEvents)
230  {
231  m_BlockEvents = true;
232  int row = this->FindProperty(dynamic_cast<const mitk::BaseProperty *>(caller));
233 
234  QModelIndex indexOfChangedProperty = index(row, 1);
235 
236  emit dataChanged(indexOfChangedProperty, indexOfChangedProperty);
237  m_BlockEvents = false;
238  }
239 }
240 
241 void QmitkPropertiesTableModel::PropertyDelete(const itk::Object *caller, const itk::EventObject & /*event*/)
242 {
243  if (!m_BlockEvents)
244  {
245  m_BlockEvents = true;
246  int row = this->FindProperty(dynamic_cast<const mitk::BaseProperty *>(caller));
247  if (row >= 0)
248  this->Reset();
249  m_BlockEvents = false;
250  }
251 }
252 
253 bool QmitkPropertiesTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
254 {
255  if (index.isValid() && !m_SelectedProperties.empty() && index.row() < (int)(m_SelectedProperties.size()) &&
256  (role == Qt::EditRole || Qt::CheckStateRole))
257  {
258  // block all events now!
259  m_BlockEvents = true;
260 
261  // the properties name
262  if (index.column() == PROPERTY_VALUE_COLUMN)
263  {
264  mitk::BaseProperty *baseProp = m_SelectedProperties[index.row()].second;
265 
266  if (mitk::ColorProperty *colorProp = dynamic_cast<mitk::ColorProperty *>(baseProp))
267  {
268  QColor qcolor = value.value<QColor>();
269  if (!qcolor.isValid())
270  return false;
271 
272  mitk::Color col = colorProp->GetColor();
273  col.SetRed(qcolor.red() / 255.0);
274  col.SetGreen(qcolor.green() / 255.0);
275  col.SetBlue(qcolor.blue() / 255.0);
276  colorProp->SetColor(col);
277  m_PropertyList->InvokeEvent(itk::ModifiedEvent());
278  m_PropertyList->Modified();
279 
281  }
282 
283  else if (mitk::BoolProperty *boolProp = dynamic_cast<mitk::BoolProperty *>(baseProp))
284  {
285  boolProp->SetValue(value.toInt() == Qt::Checked ? true : false);
286  m_PropertyList->InvokeEvent(itk::ModifiedEvent());
287  m_PropertyList->Modified();
288 
290  }
291 
292  else if (mitk::StringProperty *stringProp = dynamic_cast<mitk::StringProperty *>(baseProp))
293  {
294  stringProp->SetValue((value.value<QString>()).toStdString());
295  m_PropertyList->InvokeEvent(itk::ModifiedEvent());
296  m_PropertyList->Modified();
297 
299  }
300 
301  else if (mitk::IntProperty *intProp = dynamic_cast<mitk::IntProperty *>(baseProp))
302  {
303  int intValue = value.value<int>();
304  if (intValue != intProp->GetValue())
305  {
306  intProp->SetValue(intValue);
307  m_PropertyList->InvokeEvent(itk::ModifiedEvent());
308  m_PropertyList->Modified();
309 
311  }
312  }
313 
314  else if (mitk::FloatProperty *floatProp = dynamic_cast<mitk::FloatProperty *>(baseProp))
315  {
316  float floatValue = value.value<float>();
317  if (floatValue != floatProp->GetValue())
318  {
319  floatProp->SetValue(floatValue);
320  m_PropertyList->InvokeEvent(itk::ModifiedEvent());
321  m_PropertyList->Modified();
322 
324  }
325  }
326 
327  else if (mitk::EnumerationProperty *enumerationProp = dynamic_cast<mitk::EnumerationProperty *>(baseProp))
328  {
329  std::string activatedItem = value.value<QString>().toStdString();
330  if (activatedItem != enumerationProp->GetValueAsString())
331  {
332  if (enumerationProp->IsValidEnumerationValue(activatedItem))
333  {
334  enumerationProp->SetValue(activatedItem);
335  m_PropertyList->InvokeEvent(itk::ModifiedEvent());
336  m_PropertyList->Modified();
337 
339  }
340  }
341  }
342  }
343 
344  // property was changed by us, now we can accept property changes triggered by someone else
345  m_BlockEvents = false;
346  emit dataChanged(index, index);
347  return true;
348  }
349 
350  return false;
351 }
352 
353 void QmitkPropertiesTableModel::sort(int column, Qt::SortOrder order /*= Qt::AscendingOrder */)
354 {
355  bool sortDescending = (order == Qt::DescendingOrder) ? true : false;
356 
357  // do not sort twice !!! (dont know why, but qt calls this func twice. STUPID!)
358  if (sortDescending != m_SortDescending)
359  {
360  m_SortDescending = sortDescending;
361 
363 
366 
367  if (column == PROPERTY_VALUE_COLUMN)
369 
370  PropertyDataSetCompareFunction compareFunc(_CompareCriteria, _CompareOperator);
371  std::sort(m_SelectedProperties.begin(), m_SelectedProperties.end(), compareFunc);
372 
373  QAbstractTableModel::beginResetModel();
374  QAbstractTableModel::endResetModel();
375  }
376 }
377 
378 //# PROTECTED GETTER
380 {
381  int row = -1;
382 
383  if (_Property)
384  {
385  // search for property that changed and emit datachanged on the corresponding ModelIndex
386  std::vector<PropertyDataSet>::const_iterator propertyIterator;
387 
388  for (propertyIterator = m_SelectedProperties.begin(); propertyIterator != m_SelectedProperties.end();
389  propertyIterator++)
390  {
391  if (propertyIterator->second == _Property)
392  break;
393  }
394 
395  if (propertyIterator != m_SelectedProperties.end())
396  row = std::distance(m_SelectedProperties.begin(), propertyIterator);
397  }
398 
399  return row;
400 }
401 
402 //# PROTECTED SETTER
404 {
405  // subscribe for modified event
406  itk::MemberCommand<QmitkPropertiesTableModel>::Pointer _PropertyDataSetModifiedCommand =
408  _PropertyDataSetModifiedCommand->SetCallbackFunction(this, &QmitkPropertiesTableModel::PropertyModified);
410  _PropertyDataSet.second->AddObserver(itk::ModifiedEvent(), _PropertyDataSetModifiedCommand));
411 
412  // subscribe for delete event
413  itk::MemberCommand<QmitkPropertiesTableModel>::Pointer _PropertyDataSetDeleteCommand =
415  _PropertyDataSetDeleteCommand->SetCallbackFunction(this, &QmitkPropertiesTableModel::PropertyDelete);
417  _PropertyDataSet.second->AddObserver(itk::DeleteEvent(), _PropertyDataSetDeleteCommand));
418 
419  // add to the selection
420  m_SelectedProperties.push_back(_PropertyDataSet);
421 }
422 
424 {
425  PropertyDataSet &_PropertyDataSet = m_SelectedProperties.at(_Index);
426 
427  // remove modified event listener
428  _PropertyDataSet.second->RemoveObserver(m_PropertyModifiedObserverTags[_Index]);
430  // remove delete event listener
431  _PropertyDataSet.second->RemoveObserver(m_PropertyDeleteObserverTags[_Index]);
433  // remove from selection
434  m_SelectedProperties.erase(m_SelectedProperties.begin() + _Index);
435 }
436 
438 {
439  // remove all selected properties
440  while (!m_SelectedProperties.empty())
441  {
443  }
444 
445  std::vector<PropertyDataSet> allPredicates;
447  {
448  // first of all: collect all properties from the list
449  for (auto it = m_PropertyList->GetMap()->begin(); it != m_PropertyList->GetMap()->end(); it++)
450  {
451  allPredicates.push_back(*it); //% TODO
452  }
453  }
454  // make a subselection if a keyword is specified
455  if (!m_FilterKeyWord.empty())
456  {
457  std::vector<PropertyDataSet> subSelection;
458 
459  for (auto it = allPredicates.begin(); it != allPredicates.end(); it++)
460  {
461  // add this to the selection if it is matched by the keyword
462  if ((*it).first.find(m_FilterKeyWord) != std::string::npos)
463  subSelection.push_back((*it));
464  }
465  allPredicates.clear();
466  allPredicates = subSelection;
467  }
468 
469  PropertyDataSet tmpPropertyDataSet;
470  // add all selected now to the Model
471  for (auto it = allPredicates.begin(); it != allPredicates.end(); it++)
472  {
473  tmpPropertyDataSet = *it;
474  this->AddSelectedProperty(tmpPropertyDataSet);
475  }
476 
477  // sort the list as indicated by m_SortDescending
478  this->sort(m_SortDescending);
479 
480  // model was resetted
481  QAbstractTableModel::beginResetModel();
482  QAbstractTableModel::endResetModel();
483 }
484 
486 {
487  m_FilterKeyWord = _FilterKeyWord;
488  this->Reset();
489 }
490 
492  CompareCriteria _CompareCriteria, CompareOperator _CompareOperator)
493  : m_CompareCriteria(_CompareCriteria), m_CompareOperator(_CompareOperator)
494 {
495 }
496 
498  const PropertyDataSet &_Right) const
499 {
500  switch (m_CompareCriteria)
501  {
502  case CompareByValue:
503  if (m_CompareOperator == Less)
504  return (_Left.second->GetValueAsString() < _Right.second->GetValueAsString());
505  else
506  return (_Left.second->GetValueAsString() > _Right.second->GetValueAsString());
507  break;
508 
509  // CompareByName:
510  default:
511  if (m_CompareOperator == Less)
512  return (_Left.first < _Right.first);
513  else
514  return (_Left.first > _Right.first);
515  break;
516  }
517 }
519  const std::string &_FilterKeyWord)
520  : m_FilterKeyWord(_FilterKeyWord)
521 {
522 }
523 
525 {
526  if (m_FilterKeyWord.empty())
527  return true;
528  return (_Elem.first.find(m_FilterKeyWord) == 0);
529 }
void RemoveListener(const AbstractDelegate &delegate) const
Definition: mitkMessage.h:397
void AddListener(const AbstractDelegate &delegate) const
Definition: mitkMessage.h:378
itk::SmartPointer< Self > Pointer
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...
itkObjectEvent ObjectDelete
AddEvent is emitted when the object pointed to gets deleted.
QmitkPropertiesTableModel(QObject *parent=nullptr, mitk::PropertyList::Pointer _PropertyList=nullptr)
bool IsNotNull() const
bool operator()(const PropertyDataSet &_Left, const PropertyDataSet &_Right) const
The reimplemented compare function.
Key-value list holding instances of BaseProperty.
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...
mitk::PropertyList::Pointer GetPropertyList() const
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Overwritten from QAbstractTableModel. Returns the flags what can be done with the items (view...
ObjectType * GetPointer() const
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
Abstract base class for properties.
std::pair< std::string, mitk::BaseProperty::Pointer > PropertyDataSet
bool setData(const QModelIndex &index, const QVariant &value, int role) override
CompareCriteria
Specifies field of the property with which it will be sorted.
static RenderingManager * GetInstance()
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.
virtual std::string GetValueAsString() const
std::vector< unsigned long > m_PropertyModifiedObserverTags
Holds all tags of Modified Event Listeners. We need it to remove them again.
bool operator()(const PropertyDataSet &_Elem) const
The reimplemented compare function.
virtual ~QmitkPropertiesTableModel()
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...
virtual void PropertyListDelete(const itk::Object *_PropertyList)
Gets called when the list is about to be deleted.
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...
Property for strings.
int columnCount(const QModelIndex &parent) const override
void AddSelectedProperty(PropertyDataSet &_PropertyDataSet)
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)
const PropertyMap * GetMap() const
Qt::ItemFlags flags(const QModelIndex &index) const override
Overwritten from QAbstractTableModel. Returns the flags what can be done with the items (view...
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.