Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
QmitkPythonSnippets.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 "QmitkPythonSnippets.h"
19 #include <mitkCommon.h>
20 #include <memory>
21 
22 #include <QToolBar>
23 #include <QComboBox>
24 #include <QTextEdit>
25 #include <QGridLayout>
26 #include <QDir>
27 #include <QAction>
28 #include <QInputDialog>
29 #include <QLineEdit>
30 #include <QMessageBox>
31 #include <QXmlStreamWriter>
32 #include <QXmlStreamReader>
33 #include <QResource>
34 #include <QFileDialog>
35 
36 struct QmitkPythonSnippetsData
37 {
38  QString m_AutoSaveFileName;
39  QString m_SaveFileName;
40 
41  QAction* m_PasteSnippet;
42  QAction* m_RemoveSnippet;
43  QAction* m_RenameSnippet;
44  QAction* m_AddSnippet;
45  QAction* m_RestoreDefaultSnippets;
46  QAction* m_LoadSnippets;
47  QAction* m_SaveSnippets;
48 
49  QToolBar* m_Toolbar;
50 
51  QComboBox* m_Name;
52 
53  QTextEdit* m_Content;
54 
55  QGridLayout* m_Layout;
56 
58 };
59 
60 const QString QmitkPythonSnippets::DEFAULT_SNIPPET_FILE( ":/mitkPython/PythonSnippets.xml" );
61 const QString QmitkPythonSnippets::SNIPPETS_ROOT_XML_ELEMENT_NAME( "PythonSnippets" );
62 const QString QmitkPythonSnippets::SNIPPETS_XML_ELEMENT_NAME( "PythonSnippet" );
63 
64 QmitkPythonSnippets::QmitkPythonSnippets( const QString& _AutoSaveFileName, QWidget* parent )
65 : QWidget(parent), d(new QmitkPythonSnippetsData)
66 {
67  d->m_SaveFileName = QDir::currentPath();
68  d->m_AutoSaveFileName = _AutoSaveFileName;
69 
70  if( !QmitkPythonSnippets::LoadStringMap( d->m_AutoSaveFileName, d->m_Snippets ) )
71  {
73  }
74 
75  d->m_PasteSnippet = new QAction(this);
76  d->m_PasteSnippet->setObjectName(QString::fromUtf8("PasteSnippet"));
77  QIcon icon;
78  icon.addFile(QString::fromUtf8(":/mitkPython/edit-paste.png"), QSize(), QIcon::Normal, QIcon::Off);
79  d->m_PasteSnippet->setIcon(icon);
80  d->m_PasteSnippet->setToolTip("Paste snippet!");
81  d->m_PasteSnippet->setEnabled(false);
82 
83  d->m_RemoveSnippet = new QAction(this);
84  d->m_RemoveSnippet->setObjectName(QString::fromUtf8("RemoveSnippet"));
85  QIcon icon1;
86  icon1.addFile(QString::fromUtf8(":/mitkPython/edit-delete.png"), QSize(), QIcon::Normal, QIcon::Off);
87  d->m_RemoveSnippet->setIcon(icon1);
88  d->m_RemoveSnippet->setToolTip("Remove snippet.");
89  d->m_RemoveSnippet->setEnabled(false);
90 
91  d->m_RenameSnippet = new QAction(this);
92  d->m_RenameSnippet->setObjectName(QString::fromUtf8("RenameSnippet"));
93  QIcon icon2;
94  icon2.addFile(QString::fromUtf8(":/mitkPython/edit-find-replace.png"), QSize(), QIcon::Normal, QIcon::Off);
95  d->m_RenameSnippet->setIcon(icon2);
96  d->m_RenameSnippet->setToolTip("Rename snippet.");
97  d->m_RenameSnippet->setEnabled(false);
98 
99  d->m_AddSnippet = new QAction(this);
100  d->m_AddSnippet->setObjectName(QString::fromUtf8("AddSnippet"));
101  QIcon icon3;
102  icon3.addFile(QString::fromUtf8(":/mitkPython/document-new.png"), QSize(), QIcon::Normal, QIcon::Off);
103  d->m_AddSnippet->setIcon(icon3);
104  d->m_AddSnippet->setToolTip("Add snippet.");
105 
106  d->m_RestoreDefaultSnippets = new QAction(this);
107  d->m_RestoreDefaultSnippets->setObjectName(QString::fromUtf8("RestoreDefaultSnippets"));
108  QIcon icon4;
109  icon4.addFile(QString::fromUtf8(":/mitkPython/edit-clear.png"), QSize(), QIcon::Normal, QIcon::Off);
110  d->m_RestoreDefaultSnippets->setIcon(icon4);
111  d->m_RestoreDefaultSnippets->setToolTip("Restore default snippets");
112 
113  d->m_LoadSnippets = new QAction(this);
114  d->m_LoadSnippets->setToolTip("Load Snippets from disk.");
115  d->m_LoadSnippets->setObjectName(QString::fromUtf8("LoadSnippets"));
116  QIcon icon5;
117  icon5.addFile(QString::fromUtf8(":/mitkPython/document-open.png"), QSize(), QIcon::Normal, QIcon::Off);
118  d->m_LoadSnippets->setIcon(icon5);
119 
120  d->m_SaveSnippets = new QAction(this);
121  d->m_SaveSnippets->setToolTip("Save Snippets to disk.");
122  d->m_SaveSnippets->setObjectName(QString::fromUtf8("SaveSnippets"));
123  QIcon icon6;
124  icon6.addFile(QString::fromUtf8(":/mitkPython/document-save.png"), QSize(), QIcon::Normal, QIcon::Off);
125  d->m_SaveSnippets->setIcon(icon6);
126  d->m_SaveSnippets->setEnabled(false);
127 
128  d->m_Toolbar = new QToolBar;
129  d->m_Toolbar->addAction( d->m_PasteSnippet );
130  d->m_Toolbar->addAction( d->m_AddSnippet );
131  d->m_Toolbar->addAction( d->m_RemoveSnippet );
132  d->m_Toolbar->addAction( d->m_RenameSnippet );
133  d->m_Toolbar->addAction( d->m_RestoreDefaultSnippets );
134  d->m_Toolbar->addAction( d->m_SaveSnippets );
135  d->m_Toolbar->addAction( d->m_LoadSnippets );
136 
137  d->m_Name = new QComboBox;
138  d->m_Name->setObjectName(QString::fromUtf8("Name"));
139 
140  d->m_Content = new QTextEdit(this);
141  d->m_Content->setObjectName(QString::fromUtf8("Content"));
142  d->m_Content->setEnabled(false);
143 
145  new QmitkPythonScriptEditorHighlighter( d->m_Content->document() );
146 
147  d->m_Layout = new QGridLayout;
148  d->m_Layout->addWidget( d->m_Toolbar, 0, 0, 1, 1 );
149  d->m_Layout->addWidget( d->m_Name, 1, 0, 1, 1 );
150  d->m_Layout->addWidget( d->m_Content, 2, 0, 1, 1 );
151  d->m_Layout->setContentsMargins(2,2,2,2);
152 
153  this->setLayout(d->m_Layout);
154  QMetaObject::connectSlotsByName(this);
155 
156  this->Update();
157 }
158 
160 {
161  delete d;
162 }
163 
165 {
166  emit PasteCommandRequested( d->m_Content->toPlainText() );
167 }
168 
170 {
171  QString oldname = d->m_Name->currentText();
172  QString name = oldname;
173  bool ok = false;
174  while( true )
175  {
176  name = QInputDialog::getText(this,
177  tr("Add new snippet"),
178  tr("Name of snippet:"),
179  QLineEdit::Normal,
180  name,
181  &ok);
182 
183  if (ok)
184  {
185  if ( d->m_Snippets.contains(name) )
186  {
187  QMessageBox::warning(this,
188  tr("Duplicate name."),
189  tr("The entered name already exists. Enter another one or cancel the operation."),
190  QMessageBox::Ok,
191  QMessageBox::Ok );
192  }
193  else
194  {
195  QString tmpSnippet = d->m_Snippets[oldname];
196  d->m_Snippets.remove(oldname);
197  d->m_Snippets[name] = tmpSnippet;
198  this->Update(name);
199  this->SaveStringMap( d->m_AutoSaveFileName, d->m_Snippets );
200  break;
201  }
202  }
203  else
204  {
205  break;
206  }
207  }
208 }
209 
211 {
212  bool ok;
213  QString name = QInputDialog::getText(this,
214  tr("Add new snippet"),
215  tr("Name of snippet:"),
216  QLineEdit::Normal,
217  "newSnippet",
218  &ok);
219  if (ok && !name.isEmpty())
220  {
221  MITK_DEBUG("QmitkPythonSnippets") << "creating unique name for " << name.toStdString();
222  name = this->CreateUniqueName(name);
223 
224  MITK_DEBUG("QmitkPythonSnippets") << "creating snippet " << name.toStdString();
225  d->m_Snippets[name] = "";
226  this->Update(name);
227  this->SaveStringMap( d->m_AutoSaveFileName, d->m_Snippets );
228  }
229 }
230 
231 QString QmitkPythonSnippets::CreateUniqueName( const QString& name ) const
232 {
233  QString newName = name;
234  size_t i = 2;
235  while( d->m_Snippets.contains(name) )
236  {
237  newName = name + QString("_%1").arg(i);
238  ++i;
239  }
240 
241  return newName;
242 }
243 
245 {
246  QString name = d->m_Name->currentText();
247  QString question = QString("Really remove Snippet %1?").arg(name);
248  int remove = QMessageBox::question( this,
249  QString("Confirm removal"),
250  question,
251  QMessageBox::Yes | QMessageBox::No,
252  QMessageBox::No );
253 
254  if( remove == QMessageBox::Yes || remove == QMessageBox::Ok )
255  {
256  d->m_Snippets.remove(name);
257  this->Update();
258  this->SaveStringMap( d->m_AutoSaveFileName, d->m_Snippets );
259  }
260 }
261 
263 {
264  QString question = QString("Really restore default Snippets?");
265  int remove = QMessageBox::question( this,
266  QString("Confirm restoring"),
267  question,
268  QMessageBox::Yes | QMessageBox::No,
269  QMessageBox::No );
270  if( remove == QMessageBox::Yes || remove == QMessageBox::Ok )
271  {
273  this->Update();
274  this->SaveStringMap( d->m_AutoSaveFileName, d->m_Snippets );
275  }
276 }
277 
279 {
280  bool validSelection = i >= 0 ;
281 
282  d->m_PasteSnippet->setEnabled(validSelection);
283  d->m_RemoveSnippet->setEnabled(validSelection);
284  d->m_RenameSnippet->setEnabled(validSelection);
285  d->m_Content->setEnabled(validSelection);
286  d->m_SaveSnippets->setEnabled(validSelection);
287 
288  if( validSelection )
289  {
290  QString name = d->m_Name->currentText();
291  MITK_DEBUG("QmitkPythonSnippets") << "selected snippet " << name.toStdString();
292  d->m_Content->setText( d->m_Snippets[name] );
293  MITK_DEBUG("QmitkPythonSnippets") << "selected snippet content " << d->m_Snippets[name].toStdString();
294  }
295 }
296 
298 {
299  MITK_DEBUG("QmitkPythonSnippets") << "saving to xml file " << filename.toStdString();
300 
301  if( filename.isEmpty() )
302  {
303  MITK_WARN("QmitkPythonSnippets") << "empty auto save file path given. quit.";
304  return;
305  }
306 
307  QFile file(filename);
308  file.open(QIODevice::WriteOnly);
309  if( !file.isOpen() )
310  {
311  MITK_WARN("QmitkPythonSnippets") << "could not open file " << filename.toStdString() << " for writing";
312  return;
313  }
314  QXmlStreamWriter xmlWriter(&file);
315 
316  xmlWriter.setAutoFormatting(true);
317  xmlWriter.writeStartDocument();
318  xmlWriter.writeStartElement(SNIPPETS_ROOT_XML_ELEMENT_NAME);
319 
320  QStringMap::const_iterator it = d->m_Snippets.begin();
321  while( it != d->m_Snippets.end() )
322  {
323 
324  {
325  MITK_DEBUG("QmitkPythonSnippets") << "SNIPPETS_XML_ELEMENT_NAME " << SNIPPETS_XML_ELEMENT_NAME.toStdString();
326  MITK_DEBUG("QmitkPythonSnippets") << "writing item " << it.key().toStdString();
327  }
328 
329  xmlWriter.writeStartElement(SNIPPETS_XML_ELEMENT_NAME);
330 
331  xmlWriter.writeAttribute( "key", it.key() );
332  xmlWriter.writeAttribute( "value", it.value() );
333 
334  xmlWriter.writeEndElement();
335 
336  ++it;
337  }
338 
339  xmlWriter.writeEndDocument();
340  if( file.isOpen() )
341  file.close();
342 
343  {
344  MITK_DEBUG("QmitkPythonSnippets") << "SaveStringMap successful ";
345  }
346 
347 }
348 
350 {
351  MITK_DEBUG("QmitkPythonSnippets") << "loading from xml file " << filename.toStdString();
352  QStringMap map;
353 
354  QXmlStreamReader xmlReader;
355  QFile file;
356  QByteArray data;
357  // resource file
358  if( filename.startsWith(":") )
359  {
360  QResource res( filename );
361  data = QByteArray( reinterpret_cast< const char* >( res.data() ), res.size() );
362  xmlReader.addData( data );
363  }
364  else
365  {
366  file.setFileName( filename );
367  if (!file.open(QFile::ReadOnly | QFile::Text))
368  {
369  MITK_ERROR << "Error: Cannot read file " << qPrintable(filename)
370  << ": " << qPrintable(file.errorString());
371  return false;
372  }
373  xmlReader.setDevice(&file);
374  }
375 
376  xmlReader.readNext();
377 
378  while(!xmlReader.atEnd())
379  {
380  xmlReader.readNext();
381 
382  if(xmlReader.name() == SNIPPETS_XML_ELEMENT_NAME)
383  {
384  QXmlStreamAttributes attributes = xmlReader.attributes();
385  QString key;
386  QString value;
387  if(attributes.hasAttribute("key"))
388  {
389  key = attributes.value("key").toString();
390  }
391 
392  if(attributes.hasAttribute("value"))
393  {
394  value = attributes.value("value").toString();
395  }
396 
397  if( !key.isEmpty() )
398  {
399  MITK_DEBUG("QmitkPythonSnippets") << "loaded snippet " << key.toStdString();
400  MITK_DEBUG("QmitkPythonSnippets") << "value " << value.toStdString();
401  map[key] = value;
402  }
403  }
404  }
405 
406  if (xmlReader.hasError())
407  {
408  MITK_ERROR << "Error: Failed to parse file "
409  << qPrintable(filename) << ": "
410  << qPrintable(xmlReader.errorString());
411  return false;
412  }
413  else if (file.error() != QFile::NoError)
414  {
415  MITK_ERROR << "Error: Cannot read file " << qPrintable(filename)
416  << ": " << qPrintable(file.errorString());
417  return false;
418  }
419 
420  if( file.isOpen() )
421  file.close();
422 
423  oldMap = map;
424  return true;
425 }
426 
427 void QmitkPythonSnippets::Update(const QString &name)
428 {
429  d->m_Name->clear();
430  d->m_Content->clear();
431 
432  MITK_DEBUG("QmitkPythonSnippets") << "size of snippets " << d->m_Snippets.size();
433  QStringMap::const_iterator it = d->m_Snippets.begin();
434 
435  while( it != d->m_Snippets.end() )
436  {
437  MITK_DEBUG("QmitkPythonSnippets") << "adding item " << it.key().toStdString();
438  d->m_Name->addItem( it.key() );
439  ++it;
440  }
441 
442  int index = d->m_Name->findText( name );
443  if( index >= 0 )
444  {
445  MITK_DEBUG("QmitkPythonSnippets") << "selecting index " << index;
446  d->m_Name->setCurrentIndex(index);
447  }
448 
449 }
450 
452 {
453  if( d->m_Content->isEnabled() )
454  {
455  QString name = d->m_Name->currentText();
456  QString snippet = d->m_Content->toPlainText();
457  d->m_Snippets[name] = snippet;
458 
459  this->SaveStringMap( d->m_AutoSaveFileName, d->m_Snippets );
460  MITK_DEBUG("QmitkPythonSnippets") << "SaveStringMap successful";
461  }
462 }
463 
465 {
466  QString fileName = QFileDialog::getSaveFileName(this, "Save snippets", d->m_SaveFileName, "XML files (*.xml)");
467  if( !fileName.isEmpty() )
468  {
469  d->m_SaveFileName = fileName;
470  this->SaveStringMap( d->m_SaveFileName, d->m_Snippets );
471  }
472 }
473 
475 {
476  QString fileName = QFileDialog::getOpenFileName(this, "Load snippets", d->m_SaveFileName, "XML files (*.xml)");
477 
478  if( !fileName.isEmpty() )
479  {
480  d->m_SaveFileName = fileName;
481  QString question = QString("Your current snippets will be overwritten. Proceed?");
482  int overwrite = QMessageBox::warning(this,
483  QString("Confirm overwrite"),
484  question,
485  QMessageBox::Yes | QMessageBox::No,
486  QMessageBox::No );
487 
488  if( overwrite == QMessageBox::Yes )
489  {
490  this->LoadStringMap( d->m_SaveFileName, d->m_Snippets );
491  this->Update( d->m_Name->currentText() );
492  this->SaveStringMap( d->m_AutoSaveFileName, d->m_Snippets );
493  }
494  }
495 
496 }
static const QString DEFAULT_SNIPPET_FILE
QMap< QString, QString > QStringMap
typedef for string map
void SaveStringMap(const QString &filename, const QStringMap &map) const
write string map to xml file
#define MITK_ERROR
Definition: mitkLogMacros.h:24
void on_LoadSnippets_triggered(bool checked=false)
ask for file, load snippets (do not replace)
void PasteCommandRequested(const QString &command)
this class whishes to paste sth command
#define MITK_DEBUG
Definition: mitkLogMacros.h:26
void Update(const QString &name="")
void on_AddSnippet_triggered(bool checked=false)
ask for name, create snippet, call update()
static const QString SNIPPETS_ROOT_XML_ELEMENT_NAME
#define MITK_WARN
Definition: mitkLogMacros.h:23
void on_Content_textChanged()
save changed snippet
void on_SaveSnippets_triggered(bool checked=false)
ask for file, save snippets
static const std::string filename
void on_PasteSnippet_triggered(bool checked=false)
emits PasteCommandRequested signal
void on_RenameSnippet_triggered(bool checked=false)
ask for name as long as it exists, call update()
void on_RestoreDefaultSnippets_triggered(bool checked=false)
call LoadStringMap with d->m_DefaultSnippetsAutoSaveFileName
QmitkPythonSnippets(const QString &_AutoSaveFileName="", QWidget *parent=0)
static bool LoadStringMap(const QString &filename, QStringMap &oldMap)
read string map from xml file
void on_Name_currentIndexChanged(int i)
update action state (enable/disable), update text box
A script highlighter for Python Scripts.
static const QString SNIPPETS_XML_ELEMENT_NAME
virtual ~QmitkPythonSnippets()
delete d pointer
MITKMATCHPOINTREGISTRATION_EXPORT ResultImageType::Pointer map(const InputImageType *input, const RegistrationType *registration, bool throwOnOutOfInputAreaError=false, const double &paddingValue=0, const ResultImageGeometryType *resultGeometry=NULL, bool throwOnMappingError=true, const double &errorValue=0, mitk::ImageMappingInterpolator::Type interpolatorType=mitk::ImageMappingInterpolator::Linear)
void on_RemoveSnippet_triggered(bool checked=false)
remove the current snippet, call update()
QString CreateUniqueName(const QString &name) const
creates a name which does not exist in the list