Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
QmitkPreferencesDialog.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 "QmitkPreferencesDialog.h"
18 
19 #include "berryPlatform.h"
20 #include "berryPlatformUI.h"
21 #include "berryIWorkbench.h"
24 #include "berryIExtension.h"
26 #include <berryIQtPreferencePage.h>
27 
28 #include "internal/org_mitk_gui_qt_application_Activator.h"
29 
30 #include <ui_QmitkPreferencesDialog.h>
31 
32 #include <QFileDialog>
33 #include <QMessageBox>
34 #include <QPushButton>
35 
36 #include <algorithm>
37 
38 #include <mitkLogMacros.h>
39 
40 using namespace std;
41 
42 static std::vector<std::string> splitString(const std::string &s, char delim=' ')
43 {
44  std::vector < std::string > elems;
45  std::stringstream ss(s);
46  std::string item;
47  while (std::getline(ss, item, delim))
48  {
49  elems.push_back(item);
50  }
51  return elems;
52 }
53 
54 class QmitkPreferencesDialogPrivate : public Ui::QmitkPreferencesDialog
55 {
56 public:
57 
61  struct PrefPage
62  {
63  PrefPage(QString _id, QString _name, QString _category
64  , QString _className, QString _keywords, berry::IConfigurationElement::Pointer _confElem)
65  : id(_id), name(_name), category(_category), className(_className), keywords(_keywords),
66  prefPage(nullptr), confElem(_confElem), treeWidgetItem(nullptr)
67  {}
68 
69  bool operator==(const PrefPage& other)
70  { return id == other.id; }
71 
72  bool operator<(const PrefPage& other)
73  { return name < other.name; }
74 
75  QString id;
76  QString name;
77  QString category;
78  QString className;
79  QString keywords;
80  berry::IQtPreferencePage* prefPage;
82  QTreeWidgetItem* treeWidgetItem;
83  };
84 
85  QmitkPreferencesDialogPrivate()
86  : m_CurrentPage(0)
87  {
89 
90  // m_PrefPages
91  QList<berry::IConfigurationElement::Pointer> prefPages(xpService->GetConfigurationElementsFor("org.blueberry.ui.preferencePages"));
92  QList<berry::IConfigurationElement::Pointer> keywordExts(xpService->GetConfigurationElementsFor("org.blueberry.ui.keywords"));
93  QList<berry::IConfigurationElement::Pointer>::iterator prefPagesIt;
94 
95  QList<berry::IConfigurationElement::Pointer>::iterator keywordRefsIt;
96 
97  for (prefPagesIt = prefPages.begin(); prefPagesIt != prefPages.end(); ++prefPagesIt)
98  {
99  QString id = (*prefPagesIt)->GetAttribute("id");
100  QString name = (*prefPagesIt)->GetAttribute("name");
101  QString className = (*prefPagesIt)->GetAttribute("class");
102  if(!id.isEmpty() && !name.isEmpty() && !className.isEmpty())
103  {
104  QString keywordLabels;
105 
106  QString category = (*prefPagesIt)->GetAttribute("category");
107  //# collect keywords
108  QList<berry::IConfigurationElement::Pointer> keywordRefs = (*prefPagesIt)->GetChildren("keywordreference"); // get all keyword references
109  for (keywordRefsIt = keywordRefs.begin()
110  ; keywordRefsIt != keywordRefs.end(); ++keywordRefsIt) // iterate over all refs
111  {
112  QString keywordRefId = (*keywordRefsIt)->GetAttribute("id"); // get referenced id
113 
114  for (QList<berry::IConfigurationElement::Pointer>::iterator keywordExtsIt = keywordExts.begin();
115  keywordExtsIt != keywordExts.end(); ++keywordExtsIt) // iterate over all keywords
116  {
117  QString keywordId = (*keywordExtsIt)->GetAttribute("id"); // get keyword id
118  if(keywordId == keywordRefId) // if referenced id is equals the current keyword id
119  {
120  //# collect all keywords from label attribute with a tokenizer
121  QString currLabel = (*keywordExtsIt)->GetAttribute("label");
122  currLabel = currLabel.toLower();
123  if (!currLabel.isEmpty()) keywordLabels += QString(" ") + currLabel;
124 
125  //break; // break here; possibly search for other referenced keywords
126  }
127  }
128  }
129 
130  // add information as PrefPage
131  m_PrefPages.push_back(PrefPage(id, name, category, className, keywordLabels, berry::IConfigurationElement::Pointer(*prefPagesIt)));
132  }
133 
134  }
135  }
136 
140  QList<PrefPage> m_PrefPages;
141  int m_CurrentPage;
142 
143 };
144 
145 QmitkPreferencesDialog::QmitkPreferencesDialog(QWidget * parent, Qt::WindowFlags f)
146  : QDialog(parent, f), d(new QmitkPreferencesDialogPrivate)
147 {
148  d->setupUi(this);
149 
150  QObject::connect(d->m_Keyword, SIGNAL(editingFinished()), this, SLOT(OnKeywordEditingFinished()));
151  QObject::connect(d->m_Keyword, SIGNAL(textChanged(QString)), this, SLOT(OnKeywordTextChanged(QString)));
152 
153  QObject::connect(d->m_PreferencesTree, SIGNAL(itemSelectionChanged()), this, SLOT(OnPreferencesTreeItemSelectionChanged()));
154 
155  QPushButton* importButton = d->buttonBox->addButton("Import...", QDialogButtonBox::ActionRole);
156  QObject::connect(importButton, SIGNAL(clicked()), this, SLOT(OnImportButtonClicked()));
157 
158  QPushButton* exportButton = d->buttonBox->addButton("Export...", QDialogButtonBox::ActionRole);
159  QObject::connect(exportButton, SIGNAL(clicked()), this, SLOT(OnExportButtonClicked()));
160 
161  QObject::connect(this, SIGNAL(accepted()), this, SLOT(OnDialogAccepted()));
162  QObject::connect(this, SIGNAL(rejected()), this, SLOT(OnDialogRejected()));
163 
164  this->UpdateTree();
165 }
166 
168 {
169 }
170 
172 {
173  for(QList<QmitkPreferencesDialogPrivate::PrefPage>::iterator it = d->m_PrefPages.begin(); it != d->m_PrefPages.end(); ++it)
174  {
175  if(it->id == id)
176  {
177  d->m_PreferencesTree->setCurrentItem(it->treeWidgetItem);
178  break;
179  }
180  }
181 }
182 
184 {
185  int answer = QMessageBox::question(this, "Importing Preferences"
186  , "All existing preferences will be overwritten!\nAre you sure that you want to import other preferences?", QMessageBox::Yes | QMessageBox::No );
187  if(answer == QMessageBox::No)
188  return;
189 
190  try
191  {
192  berry::IBerryPreferencesService* berryPrefService =
194  if(berryPrefService != nullptr)
195  {
196  static QString importDir = "";
197  QString fileName = QFileDialog::getOpenFileName(this, tr("Choose file to import preferences"),
198  importDir, tr("XML files (*.xml)"));
199 
200  if(!fileName.isEmpty())
201  {
202  importDir = QFileInfo(fileName).absoluteDir().path();
203  berryPrefService->ImportPreferences(fileName, "");
204  berry::IQtPreferencePage* prefPage = d->m_PrefPages[d->m_CurrentPage].prefPage;
205  if(prefPage)
206  prefPage->Update();
207 
208  MITK_INFO("QmitkPreferencesDialog") << "Preferences successfully imported from " << fileName;
209  }
210  }
211  }
212  catch (Poco::Exception& pe)
213  {
214  QMessageBox::critical(this, "Error Importing", pe.message().c_str());
215  MITK_ERROR("QmitkPreferencesDialog") << pe.what();
216  }
217  catch (std::exception& e)
218  {
219  QMessageBox::critical(this, "Error Importing", e.what());
220  MITK_ERROR("QmitkPreferencesDialog") << e.what();
221  }
222 }
223 
225 {
226  try
227  {
228  berry::IBerryPreferencesService* berryPrefService =
230  if(berryPrefService != nullptr)
231  {
232  SavePreferences();
233  static QString exportDir = "";
234  QString fileName = QFileDialog::getSaveFileName(this, tr("Choose file to export preferences"),
235  exportDir, tr("XML files (*.xml)"));
236 
237  if(!fileName.isEmpty())
238  {
239  if(QFileInfo(fileName).suffix() != ".xml")
240  {
241  fileName += ".xml";
242  }
243  exportDir = QFileInfo(fileName).absoluteDir().path();
244  berryPrefService->ExportPreferences(fileName, "");
245  MITK_INFO("QmitkPreferencesDialog") << "Preferences successfully exported to " << fileName;
246  }
247  }
248  }
249  catch (Poco::Exception& pe)
250  {
251  QMessageBox::critical(this, "Error Exporting", pe.message().c_str());
252  MITK_ERROR("QmitkPreferencesDialog") << pe.what();
253  }
254  catch (std::exception& e)
255  {
256  QMessageBox::critical(this, "Error Exporting", e.what());
257  MITK_ERROR("QmitkPreferencesDialog") << e.what();
258  }
259 }
260 
262 {
263  berry::IQtPreferencePage* prefPage = nullptr;
264 
265  for(QList<QmitkPreferencesDialogPrivate::PrefPage>::iterator it = d->m_PrefPages.begin(); it != d->m_PrefPages.end(); ++it)
266  {
267  prefPage = it->prefPage;
268  if(prefPage) {
269  prefPage->PerformOk();
270  }
271  }
272 
280 }
281 
283 {
284  this->SavePreferences();
285 }
286 
288 {
289  berry::IQtPreferencePage* prefPage = d->m_PrefPages[d->m_CurrentPage].prefPage;
290  if(prefPage)
291  prefPage->PerformCancel();
292 }
293 
295 {
296  // search for text
297  this->UpdateTree();
298 }
299 
301 {
302 }
303 
304 //bool QmitkPreferencesDialog::eventFilter( QObject *obj, QEvent *event )
305 //{
306 // if(obj == d->m_Keyword)
307 // {
308 // if(event->type() == QEvent::FocusIn && d->m_Keyword->text() == "search ...")
309 // {
310 // d->m_Keyword->setText("");
311 // d->m_Keyword->setStyleSheet("color: black;");
312 // }
313 // else if(event->type() == QEvent::FocusOut && d->m_Keyword->text() == "")
314 // {
315 // d->m_Keyword->setText("search ...");
316 // d->m_Keyword->setStyleSheet("color: gray;");
317 // }
318 // }
319 // return true;
320 //}
321 
323 {
324  if(d->m_PreferencesTree == nullptr)
325  return;
326 
327  // TODO: create page and show it
328  QList<QTreeWidgetItem *> selectedItems = d->m_PreferencesTree->selectedItems();
329  if(selectedItems.size()>0)
330  {
331 
332  d->m_CurrentPage = 0;
334  for(QList<QmitkPreferencesDialogPrivate::PrefPage>::iterator it = d->m_PrefPages.begin(); it != d->m_PrefPages.end(); ++it, ++d->m_CurrentPage)
335  {
336  if(it->treeWidgetItem == selectedItems.at(0))
337  {
338  d->m_Headline->setText(it->name);
339  if(it->prefPage == nullptr)
340  {
341  berry::IPreferencePage* page = it->confElem->CreateExecutableExtension<berry::IPreferencePage>("class");
342  it->prefPage = dynamic_cast<berry::IQtPreferencePage*>(page);
343  it->prefPage->Init(berry::IWorkbench::Pointer(workbench));
344  it->prefPage->CreateQtControl(d->m_PreferencesPanel);
345  d->m_PreferencesPanel->addWidget(it->prefPage->GetQtControl());
346  }
347  d->m_PreferencesPanel->setCurrentWidget(it->prefPage->GetQtControl());
348 
349  break;
350  }
351  }
352  }
353 }
354 
356 {
357  if(d->m_PreferencesTree == nullptr)
358  return;
359 
360  d->m_PreferencesTree->sortByColumn(0, Qt::AscendingOrder);
361 
362  //m_PreferencesTree->clear();
363  QString keyword = d->m_Keyword->text().toLower();
364 
365  map<QString, QTreeWidgetItem*> items;
366  std::list< QList<QmitkPreferencesDialogPrivate::PrefPage>::iterator > deferredItems;
367 
368  for (QList<QmitkPreferencesDialogPrivate::PrefPage>::iterator it = d->m_PrefPages.begin();
369  it != d->m_PrefPages.end(); ++it)
370  {
371  if (it->treeWidgetItem == nullptr)
372  {
373  if (it->category.isEmpty())
374  {
375  it->treeWidgetItem = new QTreeWidgetItem(d->m_PreferencesTree);
376  it->treeWidgetItem->setText(0, it->name);
377  items[it->id] = it->treeWidgetItem;
378  }
379  else
380  {
381  // the parent might not be created yet
382  deferredItems.push_back(it);
383  }
384  }
385  }
386 
387  // deal with deferred items. We do not know how many levels
388  // of parents need to be created
389  auto currentItem = deferredItems.begin();
390 
391  while (currentItem != deferredItems.end())
392  {
393  auto currentItemContent = *currentItem;
394  if (items[currentItemContent->category] != nullptr)
395  {
396  currentItemContent->treeWidgetItem = new QTreeWidgetItem(items[currentItemContent->category]);
397  currentItemContent->treeWidgetItem->setText(0, currentItemContent->name);
398  items[currentItemContent->id] = currentItemContent->treeWidgetItem;
399 
400  deferredItems.erase(currentItem);
401  currentItem = deferredItems.begin();
402  }
403  else
404  {
405  ++currentItem;
406  }
407  }
408 
409  if (!deferredItems.empty())
410  {
411  MITK_ERROR << "Unknown preference category. They are added top-level.";
412 
413  for (const auto &currentItemContent : deferredItems)
414  {
415  currentItemContent->treeWidgetItem = new QTreeWidgetItem(d->m_PreferencesTree);
416  currentItemContent->treeWidgetItem->setText(0, currentItemContent->name);
417  items[currentItemContent->id] = currentItemContent->treeWidgetItem;
418  }
419  }
420 
421  //First, set all pages to hidden to avoid prolems
422  //when iterating over the child page first which contains a specific keyword
423  //and sets the parent to visible
424  //but after this the parent is searched for the keyword. However, the keyword might not be available
425  //so the parent and all of its children will be set to hidden.
426  if(!keyword.isEmpty())
427  {
428  for (QList<QmitkPreferencesDialogPrivate::PrefPage>::iterator it = d->m_PrefPages.begin();
429  it != d->m_PrefPages.end(); ++it)
430  {
431  it->treeWidgetItem->setHidden(true);
432  }
433  }
434  // we have to iterate over the list a second time, as only
435  // now all parents and items are guaranteed to be created
436  for (QList<QmitkPreferencesDialogPrivate::PrefPage>::iterator it = d->m_PrefPages.begin();
437  it != d->m_PrefPages.end(); ++it)
438  {
439  // hide treeWidgetItem if keyword not matches
440  if(!keyword.isEmpty())
441  {
442  //Split text of search box into multiple single strings
443  vector<string> keywordsAvailable = splitString(keyword.toUtf8().constData());
444  bool foundAll = true;
445 
446  //perform an AND-search
447  for(unsigned int i = 0; i < keywordsAvailable.size(); i++)
448  {
449  if (it->keywords.indexOf(QString::fromStdString(keywordsAvailable[i])) == -1)
450  {
451  foundAll = false;
452  break;
453  }
454  }
455 
456  if(foundAll)
457  {
458  //#make the whole branch visible
459  QTreeWidgetItem* treeWidgetParent = it->treeWidgetItem->parent();
460  while(treeWidgetParent!=nullptr)
461  {
462  treeWidgetParent->setHidden(false);
463  treeWidgetParent->setExpanded(true);
464  treeWidgetParent = treeWidgetParent->parent();
465  }
466 
467  it->treeWidgetItem->setHidden(false);
468  QFont f = it->treeWidgetItem->font(0);
469  f.setBold(true);
470  it->treeWidgetItem->setFont(0, f);
471  }
472  }
473  else
474  {
475  QFont f = it->treeWidgetItem->font(0);
476  f.setBold(false);
477  it->treeWidgetItem->setFont(0, f);
478  it->treeWidgetItem->setHidden(false);
479  }
480  }
481 
482  if(d->m_PrefPages.size()>0)
483  {
484  if(d->m_PrefPages.front().treeWidgetItem != nullptr)
485  d->m_PrefPages.front().treeWidgetItem->setSelected(true);
486  }
487 
488 }
QmitkPreferencesDialog(QWidget *parent=nullptr, Qt::WindowFlags f=0)
virtual void Init(IWorkbench::Pointer workbench)=0
virtual void ExportPreferences(const QString &f, const QString &name="")=0
#define MITK_INFO
Definition: mitkLogMacros.h:22
static std::vector< std::string > splitString(const std::string &s, char delim=' ')
#define MITK_ERROR
Definition: mitkLogMacros.h:24
STL namespace.
virtual void Update()=0
virtual SmartPointer< IPreferences > GetSystemPreferences()=0
virtual bool PerformOk()=0
MITKCORE_EXPORT bool operator==(const InteractionEvent &a, const InteractionEvent &b)
static IWorkbench * GetWorkbench()
virtual QList< SmartPointer< IConfigurationElement > > GetConfigurationElementsFor(const QString &extensionPointId) const =0
static IExtensionRegistry * GetExtensionRegistry()
QScopedPointer< QmitkPreferencesDialogPrivate > d
virtual void PerformCancel()=0
void SetSelectedPage(const QString &id)
virtual void ImportPreferences(const QString &f, const QString &name="")=0
void OnKeywordTextChanged(const QString &s)
static IPreferencesService * GetPreferencesService()