Medical Imaging Interaction Toolkit  2018.4.99-3e3f1a6e
Medical Imaging Interaction Toolkit
QmitkPropertyListPopup.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 "QmitkPropertyListPopup.h"
14 #include "QmitkMaterialEditor.h"
16 
17 #include "mitkColorProperty.h"
18 #include "mitkRenderingManager.h"
19 #include "mitkStringProperty.h"
20 
21 #include <qcolordialog.h>
22 #include <qinputdialog.h>
23 #include <qmessagebox.h>
24 
25 #include <QWidgetAction>
26 #include <qmenudata.h>
27 #include <qpainter.h>
28 
30  mitk::PropertyList *list, QObject *parent, bool disableBoolProperties, bool fillMenuImmediatelty, const char *name)
31  : QObject(parent, name),
32  m_PopupMenu(new QMenu(name, dynamic_cast<QWidget *>(parent))),
33  m_PropertyList(list),
34  m_MaterialEditor(nullptr),
35  m_NameMenuAction(0),
36  m_VisibleMenuAction(0),
37  m_ColorMenuAction(0),
38  m_MaterialMenuAction(0),
39  m_OpacityMenuAction(0),
40  m_AcceptOnHide(false),
41  m_DisableBoolProperties(disableBoolProperties)
42 {
43  if (!parent)
44  {
45  std::cerr << "In " __FILE__ ", l." << __LINE__
46  << ": popup menu without parent. This tends to crash (click 'Choose color' in the material editor)."
47  << std::endl;
48  }
49 
50  if (fillMenuImmediatelty)
51  {
52  fillPopup();
53  }
54 
55  connect(m_PopupMenu, SIGNAL(aboutToHide()), this, SLOT(popupAboutToHide()));
56  connect(m_PopupMenu, SIGNAL(hovered(int)), this, SLOT(popupMenuItemHovered(int)));
57 }
58 
60 {
61  QPixmap pixmap(20, 20);
62  QPainter painter(&pixmap);
63  painter.setPen(Qt::NoPen);
64  painter.fillRect(QRect(0, 0, 20, 20), color);
65 
66  return QIcon(pixmap);
67 }
68 
70 {
71  if (m_PropertyList.IsNotNull())
72  {
73  // color
74  mitk::ColorProperty *colorProperty = dynamic_cast<mitk::ColorProperty *>(m_PropertyList->GetProperty("color"));
75  if (colorProperty)
76  {
77  mitk::Color col = colorProperty->GetColor();
78  QColor currentColor((int)(col.GetRed() * 255), (int)(col.GetGreen() * 255), (int)(col.GetBlue() * 255));
79 
80  QFont normalFont;
81  normalFont.setBold(true);
82  m_ColorMenuAction = new QAction(this->createColorIcon(currentColor), QString("Color..."), this);
83  m_ColorMenuAction->setFont(normalFont);
84  m_PopupMenu->addAction(m_ColorMenuAction);
85  m_ColorMenuAction->setEnabled(true);
86  connect(m_ColorMenuAction, SIGNAL(triggered()), this, SLOT(onColorClicked()));
87  }
88  else
89  {
90  m_ColorMenuAction = new QAction(QString("Color..."), this);
91  m_PopupMenu->addAction(m_ColorMenuAction);
92  m_ColorMenuAction->setEnabled(true);
93  }
94 
95  if (!AddMaterialPopup())
96  {
97  m_MaterialMenuAction = new QAction(QString("Material"), this);
99  m_MaterialMenuAction->setEnabled(false);
100  }
101 
102  // opacity
103  if (mitk::FloatProperty *opacityProperty =
104  dynamic_cast<mitk::FloatProperty *>(m_PropertyList->GetProperty("opacity")))
105  {
106  m_OriginalOpacity = mitk::FloatProperty::New(opacityProperty->GetValue());
107  QMenu *opacityPopup = m_PopupMenu->addMenu("Opacity");
108 
109  QmitkNumberPropertySlider *npe = new QmitkNumberPropertySlider(opacityProperty, opacityPopup);
110  npe->setShowPercent(true);
111  npe->setMinValue(0);
112  npe->setMaxValue(1);
113 
114  QWidgetAction *opacityMenuAction = new QWidgetAction(opacityPopup);
115  opacityMenuAction->setDefaultWidget(npe);
116  m_OpacityMenuAction = opacityMenuAction;
117  opacityPopup->addAction(m_OpacityMenuAction);
118  m_OpacityMenuAction->setEnabled(true);
119  }
120  else
121  {
122  m_OpacityMenuAction = new QAction(QString("Opacity"), this);
123  m_PopupMenu->addAction(m_OpacityMenuAction);
124  m_OpacityMenuAction->setEnabled(true);
125  }
126 
127  m_NameMenuAction = new QAction(QString("Name..."), this);
128  m_PopupMenu->addAction(m_NameMenuAction);
129  mitk::StringProperty *nameProperty = dynamic_cast<mitk::StringProperty *>(m_PropertyList->GetProperty("name"));
130  m_NameMenuAction->setEnabled(nameProperty != nullptr);
131  if (nameProperty)
132  {
133  connect(m_NameMenuAction, SIGNAL(triggered()), this, SLOT(onNameClicked()));
134  }
135 
136  m_VisibleMenuAction = new QAction(QString("Visibility"), this);
137  m_VisibleMenuAction->setCheckable(true);
138  m_PopupMenu->addAction(m_VisibleMenuAction);
139  mitk::BoolProperty *visibleProperty = dynamic_cast<mitk::BoolProperty *>(m_PropertyList->GetProperty("visible"));
140  m_VisibleMenuAction->setEnabled(visibleProperty != nullptr);
141  if (visibleProperty)
142  {
143  m_VisibleMenuAction->setChecked(visibleProperty->GetValue());
144  connect(m_VisibleMenuAction, SIGNAL(triggered()), this, SLOT(onVisibleClicked()));
145  }
146 
147  // other properties, "information"
149  if (map)
150  {
151  m_InfoPopup = m_PopupMenu->addMenu("Information");
152 
153  m_PopupMenu->addSeparator();
154 
155  QFont boldFont = m_PopupMenu->font();
156  boldFont.setBold(true);
157 
158  // first all bool properties
159  for (mitk::PropertyList::PropertyMap::const_iterator propertyIter = map->begin(); propertyIter != map->end();
160  ++propertyIter)
161  {
162  std::string name = propertyIter->first;
163  if (name == "visible")
164  continue; // we already display that above
165 
166  if (mitk::BoolProperty *boolProperty =
167  dynamic_cast<mitk::BoolProperty *>(propertyIter->second.first.GetPointer()))
168  {
169  // fill a vector (int -> smartpointer(boolprop)) for reacting to clicks on checked items
170  m_BoolProperties.push_back(boolProperty);
171 
172  int newID = m_PopupMenu->insertItem(QString("%1").arg(name.c_str()));
173  m_PopupMenu->setItemChecked(newID, boolProperty->GetValue());
174  m_PopupMenu->setItemParameter(newID, m_BoolProperties.size());
175  m_PopupMenu->connectItem(newID, this, SLOT(onBoolPropertyClicked(int)));
177  {
178  m_PopupMenu->setItemEnabled(newID, false);
179  }
180  }
181  }
182 
183  boldFont = m_InfoPopup->font();
184 
185  // then all non-bool properties
186  for (mitk::PropertyList::PropertyMap::const_iterator propertyIter = map->begin(); propertyIter != map->end();
187  ++propertyIter)
188  {
189  std::string name = propertyIter->first;
190  if (!dynamic_cast<mitk::BoolProperty *>(propertyIter->second.first.GetPointer()))
191  {
192  std::string value("no value");
193  mitk::BaseProperty::Pointer bp = propertyIter->second.first;
194  if (bp.IsNotNull())
195  {
196  value = bp->GetValueAsString();
197  }
198  m_InfoPopup->insertItem(QString("%1: %2").arg(name.c_str()).arg(value.c_str()));
199  }
200  }
201  }
202  }
203 }
204 
206 {
207  // normal material
208  if (mitk::MaterialProperty *materialProperty =
209  dynamic_cast<mitk::MaterialProperty *>(m_PropertyList->GetProperty("material"))) // normal "material"
210  {
211  m_OriginalMaterial = mitk::MaterialProperty::New(*materialProperty);
212  QMenu *materialPopup = new QMenu(m_PopupMenu);
213 
214  m_MaterialEditor = new QmitkMaterialEditor(m_PopupMenu);
215  m_MaterialEditor->setInline(true); // important to call this first :(
216  m_MaterialEditor->Initialize(materialProperty);
217  QWidgetAction *materialEditorMenuItem = new QWidgetAction(materialPopup);
218  materialEditorMenuItem->setDefaultWidget(m_MaterialEditor);
219  materialPopup->addAction(materialEditorMenuItem);
220  connect(m_MaterialEditor,
221  SIGNAL(ChangesAccepted(QmitkMaterialEditor *)),
222  this,
223  SLOT(MaterialEditorChangesAccepted(QmitkMaterialEditor *)));
224 
225  m_MaterialMenuAction = new QAction(QString("Material"), materialPopup);
226  materialPopup->addAction(m_OpacityMenuAction);
227  m_OpacityMenuAction->setEnabled(true);
228 
229  return true;
230  }
231 
232  return false;
233 }
234 
236 {
237  delete m_MaterialEditor;
238 }
239 
240 void QmitkPropertyListPopup::popup(const QPoint &pos, QAction *action)
241 {
242  m_PopupMenu->exec(pos, action);
243 }
244 
246 {
247  mitk::StringProperty *nameProperty = dynamic_cast<mitk::StringProperty *>(m_PropertyList->GetProperty("name"));
248  if (nameProperty)
249  {
250  bool ok;
251  QString newName = QInputDialog::getText(tr("Change object name"),
252  QString(tr("Enter a new name for \"%1\"")).arg(nameProperty->GetValue()),
253  QLineEdit::Normal,
254  QString(nameProperty->GetValue()),
255  &ok,
256  m_PopupMenu);
257  if (ok && !newName.isEmpty())
258  {
259  // user entered something and pressed OK
260  nameProperty->SetValue(newName.ascii());
261  nameProperty->Modified();
263  }
264  else if (ok)
265  {
266  // user entered nothing or pressed Cancel
267  if (QMessageBox::question(m_PopupMenu,
268  tr("Change object name"),
269  tr("Do you really want to assign an empty name to '%1'?").arg(nameProperty->GetValue()),
270  QMessageBox::Yes,
271  QMessageBox::No) == QMessageBox::Yes)
272  {
273  // ok, this user is sure, we assign "" as a name
274  nameProperty->SetValue(newName.ascii());
275  nameProperty->Modified();
277  }
278  }
279  }
280 }
281 
283 {
284  m_VisibleMenuAction->setChecked(m_VisibleMenuAction->isChecked());
285  mitk::BoolProperty *visibleProperty = dynamic_cast<mitk::BoolProperty *>(m_PropertyList->GetProperty("visible"));
286  if (visibleProperty)
287  {
288  visibleProperty->SetValue(m_VisibleMenuAction->isChecked());
289  visibleProperty->Modified(); // quite stupid that this is not done in SetValue() to inform observers
292  }
293 }
294 
296 {
297  mitk::ColorProperty *colorProperty = dynamic_cast<mitk::ColorProperty *>(m_PropertyList->GetProperty("color"));
298  if (colorProperty)
299  {
300  mitk::Color col = colorProperty->GetColor();
301  QColor result = QColorDialog::getColor(
302  QColor((int)(col.GetRed() * 255), (int)(col.GetGreen() * 255), (int)(col.GetBlue() * 255)));
303  if (result.isValid())
304  {
305  col.SetRed(result.red() / 255.0);
306  col.SetGreen(result.green() / 255.0);
307  col.SetBlue(result.blue() / 255.0);
308  colorProperty->SetColor(col);
309  colorProperty->Modified(); // quite stupid that this is not done in SetColor() to inform observers
310  }
311 
314  }
315 }
316 
318 {
319  int item =
320  m_PopupMenu->idAt(param + 6); // plus number of items before all the boolean properties (excluding separator)
321  bool on(!m_PopupMenu->isItemChecked(item));
322 
323  m_PopupMenu->setItemChecked(item, on); // toggle
324 
325  try
326  {
327  mitk::BoolProperty *boolProperty = m_BoolProperties.at(param - 1);
328  if (boolProperty)
329  {
330  boolProperty->SetValue(on);
331  boolProperty->Modified();
334  }
335  }
336  catch (...)
337  {
338  // strange
339  }
340 }
341 
343 {
344 }
345 
347 {
348  if (!m_AcceptOnHide)
349  return;
350 
351  bool changes(false);
352 
354 
355  mitk::FloatProperty *opacity = dynamic_cast<mitk::FloatProperty *>(m_PropertyList->GetProperty("opacity"));
356  if (opacity)
357  {
358  if (!(*opacity == *m_OriginalOpacity))
359  {
360  changes = true;
361  }
362  }
363 
364  if (changes)
365  {
367  }
368 }
369 
371 {
372  if (action == m_OpacityMenuAction || action == m_MaterialMenuAction)
373  {
374  m_AcceptOnHide = true;
375  }
376  else
377  {
378  m_AcceptOnHide = false;
379  }
380 }
381 
383 {
384  mitk::MaterialProperty *material = dynamic_cast<mitk::MaterialProperty *>(m_PropertyList->GetProperty("material"));
385  if (material)
386  {
387  mitk::DataNode *node = material->GetDataNode();
388  material->SetDataNode(nullptr);
389  m_OriginalMaterial->SetDataNode(nullptr);
390  if (!(*material == *m_OriginalMaterial))
391  {
392  changes = true;
393  }
394  material->SetDataNode(node);
395  }
396 }
virtual void UpdateNodeMaterialOnPopupHiding(bool &changes)
virtual const char * GetValue() const
void popupMenuItemHovered(QAction *action)
void SetColor(const mitk::Color &color)
Key-value list holding instances of BaseProperty.
virtual T GetValue() const
std::vector< mitk::BoolProperty::Pointer > m_BoolProperties
The ColorProperty class RGB color property.
std::map< std::string, BaseProperty::Pointer > PropertyMap
QmitkPropertyListPopup(mitk::PropertyList *, QObject *parent=0, bool disableBoolProperties=false, bool fillMenuImmediatelty=true, const char *name=0)
static RenderingManager * GetInstance()
const mitk::Color & GetColor() const
itk::RGBPixel< float > Color
Color Standard RGB color typedef (float)
static Pointer New()
mitk::PropertyList::Pointer m_PropertyList
virtual void MaterialEditorChangesAccepted(QmitkMaterialEditor *ed)
void popup(const QPoint &pos, QAction *action=0)
virtual void SetValue(const char *_arg)
mitk::FloatProperty::Pointer m_OriginalOpacity
QIcon createColorIcon(QColor color)
Property for strings.
virtual void SetValue(T _arg)
void RequestUpdateAll(RequestType type=REQUEST_UPDATE_ALL)
Class for nodes of the DataTree.
Definition: mitkDataNode.h:57