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