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