Medical Imaging Interaction Toolkit  2018.4.99-12ad79a3
Medical Imaging Interaction Toolkit
QmitkPropertyItemModel.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 
13 #include "QmitkPropertyItemModel.h"
14 #include "QmitkPropertyItem.h"
15 #include <QColor>
16 #include <mitkColorProperty.h>
18 #include <mitkIPropertyAliases.h>
19 #include <mitkIPropertyFilters.h>
20 #include <mitkProperties.h>
21 #include <mitkRenderingManager.h>
22 #include <mitkStringProperty.h>
23 
24 #include <usGetModuleContext.h>
25 #include <usModuleContext.h>
26 #include <usServiceReference.h>
27 
28 template <class T>
30 {
31  us::ModuleContext *context = us::GetModuleContext();
32  us::ServiceReference<T> serviceRef = context->GetServiceReference<T>();
33 
34  return serviceRef ? context->GetService<T>(serviceRef) : nullptr;
35 }
36 
37 static QColor MitkToQt(const mitk::Color &color)
38 {
39  return QColor(color.GetRed() * 255, color.GetGreen() * 255, color.GetBlue() * 255);
40 }
41 
42 static mitk::BaseProperty *GetBaseProperty(const QVariant &data)
43 {
44  return data.isValid() ? reinterpret_cast<mitk::BaseProperty *>(data.value<void *>()) : nullptr;
45 }
46 
47 static mitk::Color QtToMitk(const QColor &color)
48 {
49  mitk::Color mitkColor;
50 
51  mitkColor.SetRed(color.red() / 255.0f);
52  mitkColor.SetGreen(color.green() / 255.0f);
53  mitkColor.SetBlue(color.blue() / 255.0f);
54 
55  return mitkColor;
56 }
57 
58 class PropertyEqualTo
59 {
60 public:
61  PropertyEqualTo(const mitk::BaseProperty *property) : m_Property(property) {}
62  bool operator()(const mitk::PropertyList::PropertyMapElementType &pair) const
63  {
64  return pair.second.GetPointer() == m_Property;
65  }
66 
67 private:
68  const mitk::BaseProperty *m_Property;
69 };
70 
72  : QAbstractItemModel(parent),
73  m_ShowAliases(false),
74  m_FilterProperties(false),
75  m_PropertyAliases(nullptr),
76  m_PropertyFilters(nullptr)
77 {
78  this->CreateRootItem();
79 }
80 
82 {
83  this->SetNewPropertyList(nullptr);
84 }
85 
86 int QmitkPropertyItemModel::columnCount(const QModelIndex &parent) const
87 {
88  if (parent.isValid())
89  return static_cast<QmitkPropertyItem *>(parent.internalPointer())->GetColumnCount();
90  else
91  return m_RootItem->GetColumnCount();
92 }
93 
94 void QmitkPropertyItemModel::CreateRootItem()
95 {
96  QList<QVariant> rootData;
97  rootData << "Property"
98  << "Value";
99 
100  m_RootItem.reset(new QmitkPropertyItem(rootData));
101 
102  this->beginResetModel();
103  this->endResetModel();
104 }
105 
106 QVariant QmitkPropertyItemModel::data(const QModelIndex &index, int role) const
107 {
108  if (!index.isValid())
109  return QVariant();
110 
111  mitk::BaseProperty *property =
112  index.column() == 1 ? GetBaseProperty(static_cast<QmitkPropertyItem *>(index.internalPointer())->GetData(1)) : nullptr;
113 
114  if (role == Qt::DisplayRole)
115  {
116  if (index.column() == 0)
117  {
118  return static_cast<QmitkPropertyItem *>(index.internalPointer())->GetData(0);
119  }
120  else if (index.column() == 1 && property != nullptr)
121  {
122  if (auto colorProperty = dynamic_cast<mitk::ColorProperty *>(property))
123  return MitkToQt(colorProperty->GetValue());
124  else if (dynamic_cast<mitk::BoolProperty *>(property) == nullptr)
125  return QString::fromStdString(property->GetValueAsString());
126  }
127  }
128  else if (index.column() == 1 && property != nullptr)
129  {
130  if (role == Qt::CheckStateRole)
131  {
132  if (auto boolProperty = dynamic_cast<mitk::BoolProperty *>(property))
133  return boolProperty->GetValue() ? Qt::Checked : Qt::Unchecked;
134  }
135  else if (role == Qt::EditRole)
136  {
137  if (dynamic_cast<mitk::StringProperty *>(property) != nullptr)
138  {
139  return QString::fromStdString(property->GetValueAsString());
140  }
141  else if (auto intProperty = dynamic_cast<mitk::IntProperty *>(property))
142  {
143  return intProperty->GetValue();
144  }
145  else if (auto floatProperty = dynamic_cast<mitk::FloatProperty *>(property))
146  {
147  return floatProperty->GetValue();
148  }
149  else if (auto doubleProperty = dynamic_cast<mitk::DoubleProperty *>(property))
150  {
151  return doubleProperty->GetValue();
152  }
153  else if (auto enumProperty = dynamic_cast<mitk::EnumerationProperty *>(property))
154  {
155  QStringList values;
156 
157  for (mitk::EnumerationProperty::EnumConstIterator it = enumProperty->Begin(); it != enumProperty->End(); it++)
158  values << QString::fromStdString(it->second);
159 
160  return values;
161  }
162  else if (auto colorProperty = dynamic_cast<mitk::ColorProperty *>(property))
163  {
164  return MitkToQt(colorProperty->GetValue());
165  }
166  }
167  else if (role == mitk::PropertyRole)
168  {
169  return QVariant::fromValue<void *>(property);
170  }
171  }
172 
173  return QVariant();
174 }
175 
176 QModelIndex QmitkPropertyItemModel::FindProperty(const mitk::BaseProperty *property)
177 {
178  if (property == nullptr)
179  return QModelIndex();
180 
181  if (m_PropertyList.IsExpired())
182  return QModelIndex();
183 
184  auto propertyMap = m_PropertyList.Lock()->GetMap();
185  auto it = std::find_if(propertyMap->begin(), propertyMap->end(), PropertyEqualTo(property));
186 
187  if (it == propertyMap->end())
188  return QModelIndex();
189 
190  QString name = QString::fromStdString(it->first);
191 
192  if (!name.contains('.'))
193  {
194  QModelIndexList item = this->match(index(0, 0), Qt::DisplayRole, name, 1, Qt::MatchExactly);
195 
196  if (!item.empty())
197  return item[0];
198  }
199  else
200  {
201  QStringList names = name.split('.');
202  QModelIndexList items =
203  this->match(index(0, 0), Qt::DisplayRole, names.last(), -1, Qt::MatchRecursive | Qt::MatchExactly);
204 
205  for (auto item : items)
206  {
207  QModelIndex candidate = item;
208 
209  for (int i = names.length() - 1; i != 0; --i)
210  {
211  QModelIndex parent = item.parent();
212 
213  if (parent.parent() == QModelIndex())
214  {
215  if (parent.data() != names.first())
216  break;
217 
218  return candidate;
219  }
220 
221  if (parent.data() != names[i - 1])
222  break;
223 
224  item = parent;
225  }
226  }
227  }
228 
229  return QModelIndex();
230 }
231 
232 Qt::ItemFlags QmitkPropertyItemModel::flags(const QModelIndex &index) const
233 {
234  Qt::ItemFlags flags = QAbstractItemModel::flags(index);
235 
236  if (index.column() == 1)
237  {
238  if (index.data(Qt::EditRole).isValid())
239  flags |= Qt::ItemIsEditable;
240 
241  if (index.data(Qt::CheckStateRole).isValid())
242  flags |= Qt::ItemIsUserCheckable;
243  }
244 
245  return flags;
246 }
247 
249 {
250  return m_PropertyList.Lock().GetPointer();
251 }
252 
253 QVariant QmitkPropertyItemModel::headerData(int section, Qt::Orientation orientation, int role) const
254 {
255  if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
256  return m_RootItem->GetData(section);
257 
258  return QVariant();
259 }
260 
261 QModelIndex QmitkPropertyItemModel::index(int row, int column, const QModelIndex &parent) const
262 {
263  if (!this->hasIndex(row, column, parent))
264  return QModelIndex();
265 
266  QmitkPropertyItem *parentItem =
267  parent.isValid() ? static_cast<QmitkPropertyItem *>(parent.internalPointer()) : m_RootItem.get();
268 
269  QmitkPropertyItem *childItem = parentItem->GetChild(row);
270 
271  return childItem != nullptr ? this->createIndex(row, column, childItem) : QModelIndex();
272 }
273 
275 {
276  bool updateAliases = m_ShowAliases != (m_PropertyAliases != nullptr);
277  bool updateFilters = m_FilterProperties != (m_PropertyFilters != nullptr);
278 
279  bool resetPropertyList = false;
280 
281  if (updateAliases)
282  {
283  m_PropertyAliases = m_ShowAliases ? GetPropertyService<mitk::IPropertyAliases>() : nullptr;
284 
285  resetPropertyList = !m_PropertyList.IsExpired();
286  }
287 
288  if (updateFilters)
289  {
290  m_PropertyFilters = m_FilterProperties ? GetPropertyService<mitk::IPropertyFilters>() : nullptr;
291 
292  if (!resetPropertyList)
293  resetPropertyList = !m_PropertyList.IsExpired();
294  }
295 
296  if (resetPropertyList)
297  this->SetNewPropertyList(m_PropertyList.Lock());
298 }
299 
300 void QmitkPropertyItemModel::OnPropertyListModified()
301 {
302  this->SetNewPropertyList(m_PropertyList.Lock());
303 }
304 
305 void QmitkPropertyItemModel::OnPropertyListDeleted()
306 {
307  this->CreateRootItem();
308 }
309 
310 void QmitkPropertyItemModel::OnPropertyModified(const itk::Object *property, const itk::EventObject &)
311 {
312  QModelIndex index = this->FindProperty(static_cast<const mitk::BaseProperty *>(property));
313 
314  if (index != QModelIndex())
315  emit dataChanged(index, index);
316 }
317 
318 QModelIndex QmitkPropertyItemModel::parent(const QModelIndex &child) const
319 {
320  if (!child.isValid())
321  return QModelIndex();
322 
323  QmitkPropertyItem *parentItem = static_cast<QmitkPropertyItem *>(child.internalPointer())->GetParent();
324 
325  if (parentItem == m_RootItem.get())
326  return QModelIndex();
327 
328  return this->createIndex(parentItem->GetRow(), 0, parentItem);
329 }
330 
331 int QmitkPropertyItemModel::rowCount(const QModelIndex &parent) const
332 {
333  if (parent.column() > 0)
334  return 0;
335 
336  QmitkPropertyItem *parentItem =
337  parent.isValid() ? static_cast<QmitkPropertyItem *>(parent.internalPointer()) : m_RootItem.get();
338 
339  return parentItem->GetChildCount();
340 }
341 
342 bool QmitkPropertyItemModel::setData(const QModelIndex &index, const QVariant &value, int role)
343 {
344  if (!index.isValid() || index.column() != 1 || (role != Qt::EditRole && role != Qt::CheckStateRole))
345  return false;
346 
347  mitk::BaseProperty *property = GetBaseProperty(static_cast<QmitkPropertyItem *>(index.internalPointer())->GetData(1));
348 
349  if (property == nullptr)
350  return false;
351 
352  if (mitk::BoolProperty *boolProperty = dynamic_cast<mitk::BoolProperty *>(property))
353  {
354  boolProperty->SetValue(value.toInt() == Qt::Checked ? true : false);
355  }
356  else if (mitk::StringProperty *stringProperty = dynamic_cast<mitk::StringProperty *>(property))
357  {
358  stringProperty->SetValue(value.toString().toStdString());
359  }
360  else if (mitk::IntProperty *intProperty = dynamic_cast<mitk::IntProperty *>(property))
361  {
362  intProperty->SetValue(value.toInt());
363  }
364  else if (mitk::FloatProperty *floatProperty = dynamic_cast<mitk::FloatProperty *>(property))
365  {
366  floatProperty->SetValue(value.toFloat());
367  }
368  else if (mitk::DoubleProperty *doubleProperty = dynamic_cast<mitk::DoubleProperty *>(property))
369  {
370  doubleProperty->SetValue(value.toDouble());
371  }
372  else if (mitk::EnumerationProperty *enumProperty = dynamic_cast<mitk::EnumerationProperty *>(property))
373  {
374  std::string selection = value.toString().toStdString();
375 
376  if (selection != enumProperty->GetValueAsString() && enumProperty->IsValidEnumerationValue(selection))
377  enumProperty->SetValue(selection);
378  }
379  else if (mitk::ColorProperty *colorProperty = dynamic_cast<mitk::ColorProperty *>(property))
380  {
381  colorProperty->SetValue(QtToMitk(value.value<QColor>()));
382  }
383 
384  auto propertyList = m_PropertyList.Lock();
385 
386  propertyList->Modified();
387 
389 
390  return true;
391 }
392 
393 void QmitkPropertyItemModel::SetNewPropertyList(mitk::PropertyList *newPropertyList)
394 {
395  typedef mitk::PropertyList::PropertyMap PropertyMap;
396 
397  this->beginResetModel();
398 
399  if (!m_PropertyList.IsExpired())
400  {
401  auto propertyList = m_PropertyList.Lock();
402 
403  propertyList->RemoveObserver(m_PropertyListDeletedTag);
404  propertyList->RemoveObserver(m_PropertyListModifiedTag);
405 
406  const PropertyMap *propertyMap = m_PropertyList.Lock()->GetMap();
407 
408  for (PropertyMap::const_iterator propertyIt = propertyMap->begin(); propertyIt != propertyMap->end(); ++propertyIt)
409  {
410  std::map<std::string, unsigned long>::const_iterator tagIt = m_PropertyModifiedTags.find(propertyIt->first);
411 
412  if (tagIt != m_PropertyModifiedTags.end())
413  propertyIt->second->RemoveObserver(tagIt->second);
414 
415  tagIt = m_PropertyDeletedTags.find(propertyIt->first);
416 
417  if (tagIt != m_PropertyDeletedTags.end())
418  propertyIt->second->RemoveObserver(tagIt->second);
419  }
420 
421  m_PropertyModifiedTags.clear();
422  m_PropertyDeletedTags.clear();
423  }
424 
425  m_PropertyList = newPropertyList;
426 
427  if (!m_PropertyList.IsExpired())
428  {
429  auto onPropertyListModified = itk::SimpleMemberCommand<QmitkPropertyItemModel>::New();
430  onPropertyListModified->SetCallbackFunction(this, &QmitkPropertyItemModel::OnPropertyListModified);
431  m_PropertyListModifiedTag = m_PropertyList.Lock()->AddObserver(itk::ModifiedEvent(), onPropertyListModified);
432 
433  auto onPropertyListDeleted = itk::SimpleMemberCommand<QmitkPropertyItemModel>::New();
434  onPropertyListDeleted->SetCallbackFunction(this, &QmitkPropertyItemModel::OnPropertyListDeleted);
435  m_PropertyListDeletedTag = m_PropertyList.Lock()->AddObserver(itk::DeleteEvent(), onPropertyListDeleted);
436 
437  auto modifiedCommand = itk::MemberCommand<QmitkPropertyItemModel>::New();
438  modifiedCommand->SetCallbackFunction(this, &QmitkPropertyItemModel::OnPropertyModified);
439 
440  const PropertyMap *propertyMap = m_PropertyList.Lock()->GetMap();
441 
442  for (PropertyMap::const_iterator it = propertyMap->begin(); it != propertyMap->end(); ++it)
443  m_PropertyModifiedTags.insert(
444  std::make_pair(it->first, it->second->AddObserver(itk::ModifiedEvent(), modifiedCommand)));
445  }
446 
447  this->CreateRootItem();
448 
449  if (m_PropertyList != nullptr && !m_PropertyList.Lock()->IsEmpty())
450  {
451  mitk::PropertyList::PropertyMap filteredProperties;
452  bool filterProperties = false;
453 
454  if (m_PropertyFilters != nullptr &&
455  (m_PropertyFilters->HasFilter() || m_PropertyFilters->HasFilter(m_ClassName.toStdString())))
456  {
457  filteredProperties = m_PropertyFilters->ApplyFilter(*m_PropertyList.Lock()->GetMap(), m_ClassName.toStdString());
458  filterProperties = true;
459  }
460 
461  const mitk::PropertyList::PropertyMap *propertyMap =
462  !filterProperties ? m_PropertyList.Lock()->GetMap() : &filteredProperties;
463 
464  mitk::PropertyList::PropertyMap::const_iterator end = propertyMap->end();
465 
466  for (mitk::PropertyList::PropertyMap::const_iterator iter = propertyMap->begin(); iter != end; ++iter)
467  {
468  std::vector<std::string> aliases;
469 
470  if (m_PropertyAliases != nullptr)
471  {
472  aliases = m_PropertyAliases->GetAliases(iter->first, m_ClassName.toStdString());
473 
474  if (aliases.empty() && !m_ClassName.isEmpty())
475  aliases = m_PropertyAliases->GetAliases(iter->first);
476  }
477 
478  if (aliases.empty())
479  {
480  QList<QVariant> data;
481  data << QString::fromStdString(iter->first)
482  << QVariant::fromValue((reinterpret_cast<void *>(iter->second.GetPointer())));
483 
484  m_RootItem->AppendChild(new QmitkPropertyItem(data));
485  }
486  else
487  {
488  std::vector<std::string>::const_iterator end = aliases.end();
489  for (std::vector<std::string>::const_iterator aliasIter = aliases.begin(); aliasIter != end; ++aliasIter)
490  {
491  QList<QVariant> data;
492  data << QString::fromStdString(*aliasIter)
493  << QVariant::fromValue((reinterpret_cast<void *>(iter->second.GetPointer())));
494 
495  m_RootItem->AppendChild(new QmitkPropertyItem(data));
496  }
497  }
498  }
499  }
500 
501  this->endResetModel();
502 }
503 
504 void QmitkPropertyItemModel::SetPropertyList(mitk::PropertyList *propertyList, const QString &className)
505 {
506  if (m_PropertyList != propertyList)
507  {
508  m_ClassName = className;
509  this->SetNewPropertyList(propertyList);
510  }
511 }
512 
514 {
515  this->SetNewPropertyList(m_PropertyList.Lock());
516 }
mitk::PropertyList * GetPropertyList() const
itk::SmartPointer< T > Lock() const
int rowCount(const QModelIndex &parent=QModelIndex()) const override
std::pair< std::string, BaseProperty::Pointer > PropertyMapElementType
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
QmitkPropertyItem * GetChild(int row) const
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
virtual bool HasFilter(const std::string &className="") const =0
Check if a specific data node class name has a property filter.
virtual std::map< std::string, BaseProperty::Pointer > ApplyFilter(const std::map< std::string, BaseProperty::Pointer > &propertyMap, const std::string &className="") const =0
Apply property filter to property list.
Key-value list holding instances of BaseProperty.
QModelIndex parent(const QModelIndex &child) const override
static mitk::BaseProperty * GetBaseProperty(const QVariant &data)
virtual std::vector< std::string > GetAliases(const std::string &propertyName, const std::string &className="")=0
Get aliases for a specific property.
The ColorProperty class RGB color property.
Abstract base class for properties.
std::map< std::string, BaseProperty::Pointer > PropertyMap
static RenderingManager * GetInstance()
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
bool IsExpired() const noexcept
EnumIdsContainerType::const_iterator EnumConstIterator
int columnCount(const QModelIndex &parent=QModelIndex()) const override
itk::RGBPixel< float > Color
Color Standard RGB color typedef (float)
T * GetPropertyService()
QmitkPropertyItemModel(QObject *parent=nullptr)
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
Property for strings.
static QColor MitkToQt(const mitk::Color &color)
void SetPropertyList(mitk::PropertyList *propertyList, const QString &className="")
static ModuleContext * GetModuleContext()
Returns the module context of the calling module.
static mitk::Color QtToMitk(const QColor &color)
Qt::ItemFlags flags(const QModelIndex &index) const override
void RequestUpdateAll(RequestType type=REQUEST_UPDATE_ALL)