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