Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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.