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
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.