diff --git a/Modules/MitkExt/Controllers/mitkIPythonService.h b/Modules/MitkExt/Controllers/mitkIPythonService.h index a99caa5cad..8bab9408d4 100644 --- a/Modules/MitkExt/Controllers/mitkIPythonService.h +++ b/Modules/MitkExt/Controllers/mitkIPythonService.h @@ -1,135 +1,138 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkIPythonService_h #define mitkIPythonService_h // mitk #include "MitkExtExports.h" #include "mitkImage.h" //for microservices #include #include "mitkSurface.h" #include namespace mitk { /// /// describes a python variable (data container) /// \see IPythonService::GetVariableStack() /// struct PythonVariable { std::string m_Name; std::string m_Type; std::string m_Value; }; /// /// a PythonCommandObserver gets informed as soon as a python command was issued /// \see IPythonService::AddPythonCommandObserver() /// class PythonCommandObserver { public: virtual void CommandExecuted(const std::string& pythonCommand) = 0; }; /// /// The central service for issuing Python Code /// The class also enables to transfer mitk images to python as itk::Image and vice versa /// \see IPythonService::GetVariableStack() /// class MitkExt_EXPORT IPythonService { public: /// /// Constant representing a single line command /// \see IPythonService::Execute() static const int SINGLE_LINE_COMMAND = 0; /// /// Constant representing a command in which the commands are seperated by new lines, i.e. "\\n" /// \see IPythonService::Execute() static const int MULTI_LINE_COMMAND = 1; /// /// Constant representing a single line command x which is run as "eval(x)" /// \see IPythonService::Execute() static const int EVAL_COMMAND = 2; /// /// Executes a python command. /// \return A variant containing the return value as string of the python code (if any) virtual std::string Execute( const std::string& pythonCommand, int commandType = SINGLE_LINE_COMMAND ) = 0; /// /// Executes a python script. virtual void ExecuteScript( const std::string& pathToPythonScript ) = 0; /// + /// \return true if the last call to Execute...() resulted in an error, false otherwise + virtual bool PythonErrorOccured() const = 0; + /// /// \return The list of variables in the __main__ namespace virtual std::vector GetVariableStack() const = 0; /// /// adds a command observer which is informed after a command was issued with "Execute" virtual void AddPythonCommandObserver( PythonCommandObserver* observer ) = 0; /// /// removes a specific command observer virtual void RemovePythonCommandObserver( PythonCommandObserver* observer ) = 0; /// /// notify all observer. this should only be used if it can be garantueed that the /// current python interpreter instance got another command from anywhere else /// the the Execute() method of this service, e.g. the shell widget uses this function /// since it does not use Execute() virtual void NotifyObserver( const std::string& command ) = 0; /// /// \return true, if itk wrapping is available, false otherwise virtual bool IsItkPythonWrappingAvailable() = 0; /// /// copies an mitk image as itk image into the python interpreter process /// the image will be available as "varName" in python if everythin worked /// \return true if image was copied, else false virtual bool CopyToPythonAsItkImage( mitk::Image* image, const std::string& varName ) = 0; /// /// copies an itk image from the python process that is named "varName" /// \return the image or 0 if copying was not possible virtual mitk::Image::Pointer CopyItkImageFromPython( const std::string& varName ) = 0; /// /// \return true, if OpenCv wrapping is available, false otherwise virtual bool IsOpenCvPythonWrappingAvailable() = 0; /// /// \see CopyToPythonAsItkImage() virtual bool CopyToPythonAsCvImage( mitk::Image* image, const std::string& varName ) = 0; /// /// \see CopyCvImageFromPython() virtual mitk::Image::Pointer CopyCvImageFromPython( const std::string& varName ) = 0; /// /// \return true, if vtk wrapping is available, false otherwise virtual bool IsVtkPythonWrappingAvailable() = 0; /// /// \see CopyToPythonAsItkImage() virtual bool CopyToPythonAsVtkPolyData( mitk::Surface* surface, const std::string& varName ) = 0; /// /// \see CopyCvImageFromPython() virtual mitk::Surface::Pointer CopyVtkPolyDataFromPython( const std::string& varName ) = 0; /// /// nothing to do here virtual ~IPythonService(); // leer in mitkIPythonService.cpp implementieren }; } US_DECLARE_SERVICE_INTERFACE(mitk::IPythonService, "org.mitk.services.IPythonService") #endif diff --git a/Modules/Python/QmitkCtkPythonShell.cpp b/Modules/Python/QmitkCtkPythonShell.cpp index 7eb4746901..c87c39f85d 100644 --- a/Modules/Python/QmitkCtkPythonShell.cpp +++ b/Modules/Python/QmitkCtkPythonShell.cpp @@ -1,82 +1,91 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkCtkPythonShell.h" #include #include #include #include #include #include "mitkPythonService.h" #include #include #include struct QmitkCtkPythonShellData { mitk::PythonService* m_PythonService; + mitk::ServiceReference m_PythonServiceRef; }; QmitkCtkPythonShell::QmitkCtkPythonShell(QWidget* parent) : ctkPythonConsole(parent), d( new QmitkCtkPythonShellData ) { - mitk::ModuleContext* context = mitk::GetModuleContext(); - mitk::ServiceReference serviceRef = context->GetServiceReference(); - d->m_PythonService = dynamic_cast ( context->GetService(serviceRef) ); + MITK_DEBUG("QmitkCtkPythonShell") << "retrieving IPythonService"; + mitk::ModuleContext* context = mitk::GetModuleContext(); + d->m_PythonServiceRef = context->GetServiceReference(); + d->m_PythonService = dynamic_cast ( context->GetService(d->m_PythonServiceRef) ); - assert( d->m_PythonService ); - this->initialize( d->m_PythonService->GetPythonManager() ); + MITK_DEBUG("QmitkCtkPythonShell") << "checking IPythonService"; + Q_ASSERT( d->m_PythonService ); + + MITK_DEBUG("QmitkCtkPythonShell") << "initialize m_PythonService"; + this->initialize( d->m_PythonService->GetPythonManager() ); + + MITK_DEBUG("QmitkCtkPythonShell") << "m_PythonService initialized"; } QmitkCtkPythonShell::~QmitkCtkPythonShell() { - delete d; + mitk::ModuleContext* context = mitk::GetModuleContext(); + context->UngetService( d->m_PythonServiceRef ); + delete d; } void QmitkCtkPythonShell::dragEnterEvent(QDragEnterEvent *event) { event->accept(); } void QmitkCtkPythonShell::dropEvent(QDropEvent *event) { QList urls = event->mimeData()->urls(); for(int i = 0; i < urls.size(); i++) { d->m_PythonService->Execute( urls[i].toString().toStdString(), mitk::IPythonService::SINGLE_LINE_COMMAND ); } } bool QmitkCtkPythonShell::canInsertFromMimeData( const QMimeData *source ) const { return true; } void QmitkCtkPythonShell::executeCommand(const QString& command) { MITK_DEBUG("QmitkCtkPythonShell") << "executing command " << command.toStdString(); ctkPythonConsole::executeCommand(command); d->m_PythonService->NotifyObserver(command.toStdString()); } void QmitkCtkPythonShell::Paste(const QString &command) { if( this->isVisible() ) { this->exec( command ); //this->executeCommand( command ); } } diff --git a/Modules/Python/QmitkPythonSnippets.cpp b/Modules/Python/QmitkPythonSnippets.cpp index e4bb50d7af..975944557c 100644 --- a/Modules/Python/QmitkPythonSnippets.cpp +++ b/Modules/Python/QmitkPythonSnippets.cpp @@ -1,465 +1,483 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkPythonSnippets.h" #include "QmitkPythonScriptEditorHighlighter.h" #include #include #include struct QmitkPythonSnippetsData { QString m_AutoSaveFileName; QString m_SaveFileName; QAction* m_PasteSnippet; QAction* m_RemoveSnippet; QAction* m_RenameSnippet; QAction* m_AddSnippet; QAction* m_RestoreDefaultSnippets; QAction* m_LoadSnippets; QAction* m_SaveSnippets; QToolBar* m_Toolbar; QComboBox* m_Name; QTextEdit* m_Content; QGridLayout* m_Layout; QmitkPythonSnippets::QStringMap m_Snippets; }; const QString QmitkPythonSnippets::DEFAULT_SNIPPET_FILE( ":/mitkPython/PythonSnippets.xml" ); const QString QmitkPythonSnippets::SNIPPETS_ROOT_XML_ELEMENT_NAME( "PythonSnippets" ); const QString QmitkPythonSnippets::SNIPPETS_XML_ELEMENT_NAME( "PythonSnippet" ); QmitkPythonSnippets::QmitkPythonSnippets( const QString& _AutoSaveFileName, QWidget* parent ) : QWidget(parent), d(new QmitkPythonSnippetsData) { d->m_SaveFileName = QDir::currentPath(); + d->m_AutoSaveFileName = _AutoSaveFileName; + + if( !this->LoadStringMap( d->m_AutoSaveFileName, d->m_Snippets ) ) + { + this->LoadStringMap( DEFAULT_SNIPPET_FILE, d->m_Snippets ); + } d->m_PasteSnippet = new QAction(this); d->m_PasteSnippet->setObjectName(QString::fromUtf8("PasteSnippet")); QIcon icon; icon.addFile(QString::fromUtf8(":/mitkPython/edit-paste.png"), QSize(), QIcon::Normal, QIcon::Off); d->m_PasteSnippet->setIcon(icon); d->m_PasteSnippet->setToolTip("Paste snippet!"); d->m_PasteSnippet->setEnabled(false); d->m_RemoveSnippet = new QAction(this); d->m_RemoveSnippet->setObjectName(QString::fromUtf8("RemoveSnippet")); QIcon icon1; icon1.addFile(QString::fromUtf8(":/mitkPython/edit-delete.png"), QSize(), QIcon::Normal, QIcon::Off); d->m_RemoveSnippet->setIcon(icon1); d->m_RemoveSnippet->setToolTip("Remove snippet."); d->m_RemoveSnippet->setEnabled(false); d->m_RenameSnippet = new QAction(this); d->m_RenameSnippet->setObjectName(QString::fromUtf8("RenameSnippet")); QIcon icon2; icon2.addFile(QString::fromUtf8(":/mitkPython/edit-find-replace.png"), QSize(), QIcon::Normal, QIcon::Off); d->m_RenameSnippet->setIcon(icon2); d->m_RenameSnippet->setToolTip("Rename snippet."); d->m_RenameSnippet->setEnabled(false); d->m_AddSnippet = new QAction(this); d->m_AddSnippet->setObjectName(QString::fromUtf8("AddSnippet")); QIcon icon3; icon3.addFile(QString::fromUtf8(":/mitkPython/document-new.png"), QSize(), QIcon::Normal, QIcon::Off); d->m_AddSnippet->setIcon(icon3); d->m_AddSnippet->setToolTip("Add snippet."); d->m_RestoreDefaultSnippets = new QAction(this); d->m_RestoreDefaultSnippets->setObjectName(QString::fromUtf8("RestoreDefaultSnippets")); QIcon icon4; icon4.addFile(QString::fromUtf8(":/mitkPython/edit-clear.png"), QSize(), QIcon::Normal, QIcon::Off); d->m_RestoreDefaultSnippets->setIcon(icon4); d->m_RestoreDefaultSnippets->setToolTip("Restore default snippets"); d->m_LoadSnippets = new QAction(this); d->m_LoadSnippets->setToolTip("Load Snippets from disk."); d->m_LoadSnippets->setObjectName(QString::fromUtf8("LoadSnippets")); QIcon icon5; icon5.addFile(QString::fromUtf8(":/mitkPython/document-open.png"), QSize(), QIcon::Normal, QIcon::Off); d->m_LoadSnippets->setIcon(icon5); d->m_SaveSnippets = new QAction(this); d->m_SaveSnippets->setToolTip("Save Snippets to disk."); d->m_SaveSnippets->setObjectName(QString::fromUtf8("SaveSnippets")); QIcon icon6; icon6.addFile(QString::fromUtf8(":/mitkPython/document-save.png"), QSize(), QIcon::Normal, QIcon::Off); d->m_SaveSnippets->setIcon(icon6); d->m_SaveSnippets->setEnabled(false); d->m_Toolbar = new QToolBar; d->m_Toolbar->addAction( d->m_PasteSnippet ); d->m_Toolbar->addAction( d->m_AddSnippet ); d->m_Toolbar->addAction( d->m_RemoveSnippet ); d->m_Toolbar->addAction( d->m_RenameSnippet ); d->m_Toolbar->addAction( d->m_RestoreDefaultSnippets ); d->m_Toolbar->addAction( d->m_SaveSnippets ); d->m_Toolbar->addAction( d->m_LoadSnippets ); d->m_Name = new QComboBox; d->m_Name->setObjectName(QString::fromUtf8("Name")); d->m_Content = new QTextEdit(this); d->m_Content->setObjectName(QString::fromUtf8("Content")); d->m_Content->setEnabled(false); QmitkPythonScriptEditorHighlighter* highlighter = new QmitkPythonScriptEditorHighlighter( d->m_Content->document() ); d->m_Layout = new QGridLayout; d->m_Layout->addWidget( d->m_Toolbar, 0, 0, 1, 1 ); d->m_Layout->addWidget( d->m_Name, 1, 0, 1, 1 ); d->m_Layout->addWidget( d->m_Content, 2, 0, 1, 1 ); d->m_Layout->setContentsMargins(2,2,2,2); this->setLayout(d->m_Layout); QMetaObject::connectSlotsByName(this); - d->m_AutoSaveFileName = _AutoSaveFileName; - - if( !this->LoadStringMap( d->m_AutoSaveFileName, d->m_Snippets ) ) - { - this->LoadStringMap( DEFAULT_SNIPPET_FILE, d->m_Snippets ); - } - this->Update(); } QmitkPythonSnippets::~QmitkPythonSnippets() { delete d; } void QmitkPythonSnippets::on_PasteSnippet_triggered( bool ) { emit PasteCommandRequested( d->m_Content->toPlainText() ); } void QmitkPythonSnippets::on_RenameSnippet_triggered(bool) { QString oldname = d->m_Name->currentText(); QString name = oldname; bool ok = false; while( true ) { name = QInputDialog::getText(this, tr("Add new snippet"), tr("Name of snippet:"), QLineEdit::Normal, name, &ok); if (ok) { if ( d->m_Snippets.contains(name) ) { QMessageBox::warning(this, tr("Duplicate name."), tr("The entered name already exists. Enter another one or cancel the operation."), QMessageBox::Ok, QMessageBox::Ok ); } else { QString tmpSnippet = d->m_Snippets[oldname]; d->m_Snippets.remove(oldname); d->m_Snippets[name] = tmpSnippet; this->Update(name); this->SaveStringMap( d->m_AutoSaveFileName, d->m_Snippets ); break; } } else { break; } } } void QmitkPythonSnippets::on_AddSnippet_triggered(bool) { bool ok; QString name = QInputDialog::getText(this, tr("Add new snippet"), tr("Name of snippet:"), QLineEdit::Normal, "newSnippet", &ok); if (ok && !name.isEmpty()) { MITK_DEBUG("QmitkPythonSnippets") << "creating unique name for " << name.toStdString(); name = this->CreateUniqueName(name); MITK_DEBUG("QmitkPythonSnippets") << "creating snippet " << name.toStdString(); d->m_Snippets[name] = ""; this->Update(name); this->SaveStringMap( d->m_AutoSaveFileName, d->m_Snippets ); } } QString QmitkPythonSnippets::CreateUniqueName( const QString& name ) const { QString newName = name; size_t i = 2; while( d->m_Snippets.contains(name) ) { newName = name + QString("_%1").arg(i); ++i; } return newName; } void QmitkPythonSnippets::on_RemoveSnippet_triggered(bool) { QString name = d->m_Name->currentText(); QString question = QString("Really remove Snippet %1?").arg(name); int remove = QMessageBox::question( this, QString("Confirm removal"), question, QMessageBox::Yes | QMessageBox::No, QMessageBox::No ); if( remove == QMessageBox::Yes || remove == QMessageBox::Ok ) { d->m_Snippets.remove(name); this->Update(); this->SaveStringMap( d->m_AutoSaveFileName, d->m_Snippets ); } } void QmitkPythonSnippets::on_RestoreDefaultSnippets_triggered(bool) { QString question = QString("Really restore default Snippets?"); int remove = QMessageBox::question( this, QString("Confirm restoring"), question, QMessageBox::Yes | QMessageBox::No, QMessageBox::No ); if( remove == QMessageBox::Yes || remove == QMessageBox::Ok ) { this->LoadStringMap( DEFAULT_SNIPPET_FILE, d->m_Snippets ); this->Update(); this->SaveStringMap( d->m_AutoSaveFileName, d->m_Snippets ); } } void QmitkPythonSnippets::on_Name_currentIndexChanged(int i) { bool validSelection = i >= 0 ; d->m_PasteSnippet->setEnabled(validSelection); d->m_RemoveSnippet->setEnabled(validSelection); d->m_RenameSnippet->setEnabled(validSelection); d->m_Content->setEnabled(validSelection); d->m_SaveSnippets->setEnabled(validSelection); if( validSelection ) { QString name = d->m_Name->currentText(); + MITK_DEBUG("QmitkPythonSnippets") << "selected snippet " << name.toStdString(); d->m_Content->setText( d->m_Snippets[name] ); + MITK_DEBUG("QmitkPythonSnippets") << "selected snippet content " << d->m_Snippets[name].toStdString(); } } void QmitkPythonSnippets::SaveStringMap(const QString &filename, const QmitkPythonSnippets::QStringMap &map) const { MITK_DEBUG("QmitkPythonSnippets") << "saving to xml file " << filename.toStdString(); if( filename.isEmpty() ) { MITK_WARN("QmitkPythonSnippets") << "empty auto save file path given. quit."; return; } QFile file(filename); file.open(QIODevice::WriteOnly); + if( !file.isOpen() ) + { + MITK_WARN("QmitkPythonSnippets") << "could not open file " << filename.toStdString() << " for writing"; + return; + } QXmlStreamWriter xmlWriter(&file); xmlWriter.setAutoFormatting(true); xmlWriter.writeStartDocument(); xmlWriter.writeStartElement(SNIPPETS_ROOT_XML_ELEMENT_NAME); QStringMap::const_iterator it = d->m_Snippets.begin(); while( it != d->m_Snippets.end() ) { - MITK_DEBUG("QmitkPythonSnippets") << "writing item " << it.key().toStdString(); + + { + MITK_DEBUG("QmitkPythonSnippets") << "SNIPPETS_XML_ELEMENT_NAME " << SNIPPETS_XML_ELEMENT_NAME.toStdString(); + MITK_DEBUG("QmitkPythonSnippets") << "writing item " << it.key().toStdString(); + } + xmlWriter.writeStartElement(SNIPPETS_XML_ELEMENT_NAME); xmlWriter.writeAttribute( "key", it.key() ); xmlWriter.writeAttribute( "value", it.value() ); + xmlWriter.writeEndElement(); + ++it; } - xmlWriter.writeEndElement(); xmlWriter.writeEndDocument(); if( file.isOpen() ) file.close(); + { + MITK_DEBUG("QmitkPythonSnippets") << "SaveStringMap successful "; + } + } bool QmitkPythonSnippets::LoadStringMap( const QString& filename, QmitkPythonSnippets::QStringMap& oldMap ) const { MITK_DEBUG("QmitkPythonSnippets") << "loading from xml file " << filename.toStdString(); QStringMap map; QXmlStreamReader xmlReader; QFile file; QByteArray data; // resource file if( filename.startsWith(":") ) { QResource res( filename ); data = QByteArray( reinterpret_cast< const char* >( res.data() ), res.size() ); xmlReader.addData( data ); } else { file.setFileName( filename ); if (!file.open(QFile::ReadOnly | QFile::Text)) { MITK_ERROR << "Error: Cannot read file " << qPrintable(filename) << ": " << qPrintable(file.errorString()); return false; } xmlReader.setDevice(&file); } xmlReader.readNext(); while(!xmlReader.atEnd()) { xmlReader.readNext(); if(xmlReader.name() == SNIPPETS_XML_ELEMENT_NAME) { QXmlStreamAttributes attributes = xmlReader.attributes(); QString key; QString value; if(attributes.hasAttribute("key")) { key = attributes.value("key").toString(); } if(attributes.hasAttribute("value")) { value = attributes.value("value").toString(); } if( !key.isEmpty() ) { MITK_DEBUG("QmitkPythonSnippets") << "loaded snippet " << key.toStdString(); MITK_DEBUG("QmitkPythonSnippets") << "value " << value.toStdString(); map[key] = value; } } } if (xmlReader.hasError()) { MITK_ERROR << "Error: Failed to parse file " << qPrintable(filename) << ": " << qPrintable(xmlReader.errorString()); return false; } else if (file.error() != QFile::NoError) { MITK_ERROR << "Error: Cannot read file " << qPrintable(filename) << ": " << qPrintable(file.errorString()); return false; } if( file.isOpen() ) file.close(); oldMap = map; return true; } void QmitkPythonSnippets::Update(const QString &name) { d->m_Name->clear(); d->m_Content->clear(); MITK_DEBUG("QmitkPythonSnippets") << "size of snippets " << d->m_Snippets.size(); QStringMap::const_iterator it = d->m_Snippets.begin(); while( it != d->m_Snippets.end() ) { MITK_DEBUG("QmitkPythonSnippets") << "adding item " << it.key().toStdString(); d->m_Name->addItem( it.key() ); ++it; } int index = d->m_Name->findText( name ); if( index >= 0 ) { MITK_DEBUG("QmitkPythonSnippets") << "selecting index " << index; d->m_Name->setCurrentIndex(index); } } void QmitkPythonSnippets::on_Content_textChanged() { if( d->m_Content->isEnabled() ) { QString name = d->m_Name->currentText(); QString snippet = d->m_Content->toPlainText(); d->m_Snippets[name] = snippet; + this->SaveStringMap( d->m_AutoSaveFileName, d->m_Snippets ); + MITK_DEBUG("QmitkPythonSnippets") << "SaveStringMap successful"; } } void QmitkPythonSnippets::on_SaveSnippets_triggered(bool) { QString fileName = QFileDialog::getSaveFileName(this, "Save snippets", d->m_SaveFileName, "XML files (*.xml)"); if( !fileName.isEmpty() ) { d->m_SaveFileName = fileName; this->SaveStringMap( d->m_SaveFileName, d->m_Snippets ); } } void QmitkPythonSnippets::on_LoadSnippets_triggered(bool) { QString fileName = QFileDialog::getOpenFileName(this, "Load snippets", d->m_SaveFileName, "XML files (*.xml)"); if( !fileName.isEmpty() ) { d->m_SaveFileName = fileName; QString question = QString("Your current snippets will be overwritten. Proceed?"); int overwrite = QMessageBox::warning(this, QString("Confirm overwrite"), question, QMessageBox::Yes | QMessageBox::No, QMessageBox::No ); if( overwrite == QMessageBox::Yes ) { this->LoadStringMap( d->m_SaveFileName, d->m_Snippets ); this->Update( d->m_Name->currentText() ); this->SaveStringMap( d->m_AutoSaveFileName, d->m_Snippets ); } } } diff --git a/Modules/Python/QmitkPythonTextEditor.cpp b/Modules/Python/QmitkPythonTextEditor.cpp index 43d5bd8b29..bc4689a39c 100644 --- a/Modules/Python/QmitkPythonTextEditor.cpp +++ b/Modules/Python/QmitkPythonTextEditor.cpp @@ -1,180 +1,184 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkPythonTextEditor.h" #include #include #include #include #include #include #include #include #include #include "QmitkPythonScriptEditorHighlighter.h" struct QmitkPythonTextEditorData { QString m_FilePath; QAction* m_LoadScript; QAction* m_SaveScript; QAction* m_RunScript; QToolBar* m_Toolbar; QTextEdit* m_Content; QGridLayout* m_Layout; mitk::IPythonService* m_PythonService; + mitk::ServiceReference m_PythonServiceRef; QString m_FileName; }; QmitkPythonTextEditor::QmitkPythonTextEditor(QWidget *parent) :QWidget(parent), d(new QmitkPythonTextEditorData) { mitk::ModuleContext* context = mitk::GetModuleContext(); - mitk::ServiceReference serviceRef = context->GetServiceReference(); - d->m_PythonService = context->GetService(serviceRef); + d->m_PythonServiceRef = context->GetServiceReference(); + d->m_PythonService = context->GetService( d->m_PythonServiceRef ); d->m_LoadScript = new QAction(this); d->m_LoadScript->setToolTip("Load script from disk."); d->m_LoadScript->setObjectName(QString::fromUtf8("LoadScript")); QIcon icon2; icon2.addFile(QString::fromUtf8(":/mitkPython/document-open.png"), QSize(), QIcon::Normal, QIcon::Off); d->m_LoadScript->setIcon(icon2); d->m_SaveScript = new QAction(this); d->m_SaveScript->setToolTip("Save script to disk."); d->m_SaveScript->setObjectName(QString::fromUtf8("SaveScript")); QIcon icon3; icon3.addFile(QString::fromUtf8(":/mitkPython/document-save.png"), QSize(), QIcon::Normal, QIcon::Off); d->m_SaveScript->setIcon(icon3); d->m_RunScript = new QAction(this); d->m_RunScript->setToolTip("Run the current script."); d->m_RunScript->setObjectName(QString::fromUtf8("RunScript")); QIcon icon4; icon4.addFile(QString::fromUtf8(":/mitkPython/media-playback-start.png"), QSize(), QIcon::Normal, QIcon::Off); d->m_RunScript->setIcon(icon4); d->m_Toolbar = new QToolBar; d->m_Toolbar->addAction( d->m_LoadScript ); d->m_Toolbar->addAction( d->m_SaveScript ); d->m_Toolbar->addAction( d->m_RunScript ); d->m_Content = new QTextEdit(this); d->m_Content->setObjectName(QString::fromUtf8("Content")); QmitkPythonScriptEditorHighlighter* highlighter = new QmitkPythonScriptEditorHighlighter( d->m_Content->document() ); d->m_Layout = new QGridLayout; d->m_Layout->addWidget( d->m_Toolbar, 0, 0, 1, 1 ); d->m_Layout->addWidget( d->m_Content, 1, 0, 1, 1 ); d->m_Layout->setContentsMargins(2,2,2,2); this->setLayout(d->m_Layout); QMetaObject::connectSlotsByName(this); } QmitkPythonTextEditor::~QmitkPythonTextEditor() { + mitk::ModuleContext* context = mitk::GetModuleContext(); + context->UngetService( d->m_PythonServiceRef ); + delete d; } void QmitkPythonTextEditor::dragEnterEvent(QDragEnterEvent *event) { event->accept(); } void QmitkPythonTextEditor::dropEvent(QDropEvent *event) { QList urls = event->mimeData()->urls(); for(int i = 0; i < urls.size(); i++) { this->Paste( urls[i].toString() ); } } /* bool QmitkPythonTextEditor::canInsertFromMimeData( const QMimeData * ) const { return true; } */ void QmitkPythonTextEditor::Paste(const QString &command) { if( this->isVisible() ) { d->m_Content->insertPlainText(command + "\n"); } } QString QmitkPythonTextEditor::ReadFile(const QString& filename) { QFile file(filename); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { MITK_ERROR << "Could not open file " << filename; return NULL; } QByteArray total; QByteArray line; while (!file.atEnd()) { line = file.read(1024); total.append(line); } return QString(total); } void QmitkPythonTextEditor::on_SaveScript_triggered( bool ) { d->m_FileName = QFileDialog::getSaveFileName(this,tr("Save File"), d->m_FileName,tr("*.py")); if( d->m_FileName.compare("") != 0) { ofstream myfile; myfile.open(d->m_FileName.toLocal8Bit().data()); myfile << d->m_Content->toPlainText().toLocal8Bit().data(); myfile.close(); } } void QmitkPythonTextEditor::on_LoadScript_triggered( bool ) { d->m_FileName = QFileDialog::getOpenFileName( this, "Load Script", d->m_FileName, tr("*.py")); if( !d->m_FileName.isEmpty() ) { QString contents = this->ReadFile( d->m_FileName ); d->m_Content->setText(contents); } } void QmitkPythonTextEditor::on_RunScript_triggered( bool ) { if( !d->m_PythonService ) { MITK_ERROR << "Python service not available."; return; } d->m_PythonService->Execute( d->m_Content->toPlainText().toStdString(), mitk::IPythonService::MULTI_LINE_COMMAND ); } diff --git a/Modules/Python/QmitkPythonVariableStackTableModel.cpp b/Modules/Python/QmitkPythonVariableStackTableModel.cpp index a7e496ef7b..e097ddf04b 100755 --- a/Modules/Python/QmitkPythonVariableStackTableModel.cpp +++ b/Modules/Python/QmitkPythonVariableStackTableModel.cpp @@ -1,219 +1,223 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkPythonVariableStackTableModel.h" #include #include -#include #include #include #include #include const QString QmitkPythonVariableStackTableModel::MITK_IMAGE_VAR_NAME = "mitkImage"; const QString QmitkPythonVariableStackTableModel::MITK_SURFACE_VAR_NAME = "mitkSurface"; QmitkPythonVariableStackTableModel::QmitkPythonVariableStackTableModel(QObject *parent) :QAbstractTableModel(parent) { mitk::ModuleContext* context = mitk::GetModuleContext(); - mitk::ServiceReference serviceRef = context->GetServiceReference(); - m_PythonService = context->GetService(serviceRef); + m_PythonServiceRef = context->GetServiceReference(); + m_PythonService = context->GetService(m_PythonServiceRef); m_PythonService->AddPythonCommandObserver( this ); } QmitkPythonVariableStackTableModel::~QmitkPythonVariableStackTableModel() { + mitk::ModuleContext* context = mitk::GetModuleContext(); + context->UngetService( m_PythonServiceRef ); m_PythonService->RemovePythonCommandObserver( this ); } bool QmitkPythonVariableStackTableModel::dropMimeData ( const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent ) { // Early exit, returning true, but not actually doing anything (ignoring data). if (action == Qt::IgnoreAction) return true; // Note, we are returning true if we handled it, and false otherwise bool returnValue = false; if(data->hasFormat("application/x-mitk-datanodes")) { MITK_DEBUG("QmitkPythonVariableStackTableModel") << "dropped MITK DataNode"; returnValue = true; QString arg = QString(data->data("application/x-mitk-datanodes").data()); QStringList listOfDataNodeAddressPointers = arg.split(","); QStringList::iterator slIter; int i = 0; int j = 0; for (slIter = listOfDataNodeAddressPointers.begin(); slIter != listOfDataNodeAddressPointers.end(); slIter++) { long val = (*slIter).toLong(); mitk::DataNode* node = static_cast((void*)val); mitk::Image* mitkImage = dynamic_cast(node->GetData()); MITK_DEBUG("QmitkPythonVariableStackTableModel") << "mitkImage is not null " << (mitkImage != 0? "true": "false"); if( mitkImage ) { QString varName = MITK_IMAGE_VAR_NAME; if( i > 0 ) varName = QString("%1%2").arg(MITK_IMAGE_VAR_NAME).arg(i); - MITK_DEBUG("varName") << "varName" << varName.toStdString(); + MITK_DEBUG("QmitkPythonVariableStackTableModel") << "varName" << varName.toStdString(); bool exportAsCvImage = m_PythonService->IsOpenCvPythonWrappingAvailable(); if( mitkImage->GetDimension() == 2 && exportAsCvImage ) { int ret = QMessageBox::question(NULL, "Export option", "2D image detected. Export as OpenCV image to Python instead of an ITK image?", QMessageBox::Yes | QMessageBox::No, QMessageBox::No); exportAsCvImage = ret == QMessageBox::Yes; if(exportAsCvImage) { m_PythonService->CopyToPythonAsCvImage( mitkImage, MITK_IMAGE_VAR_NAME.toStdString() ); ++i; } } if( !exportAsCvImage ) { if( m_PythonService->IsItkPythonWrappingAvailable() ) { m_PythonService->CopyToPythonAsItkImage( mitkImage, MITK_IMAGE_VAR_NAME.toStdString() ); ++i; } else { MITK_ERROR << "ITK Python wrapping not available. Skipping export for image " << node->GetName(); } } } else { mitk::Surface* surface = dynamic_cast(node->GetData()); + MITK_DEBUG("QmitkPythonVariableStackTableModel") << "found surface"; if( surface ) { QString varName = MITK_SURFACE_VAR_NAME; + MITK_DEBUG("QmitkPythonVariableStackTableModel") << "varName" << varName.toStdString(); + if( j > 0 ) varName = QString("%1%2").arg(MITK_SURFACE_VAR_NAME).arg(j); MITK_DEBUG("varName") << "varName" << varName; if( m_PythonService->IsVtkPythonWrappingAvailable() ) { m_PythonService->CopyToPythonAsVtkPolyData( surface, MITK_SURFACE_VAR_NAME.toStdString() ); ++j; } else { MITK_ERROR << "VTK Python wrapping not available. Skipping export for surface " << node->GetName(); } } } } } return returnValue; } QVariant QmitkPythonVariableStackTableModel::headerData(int section, Qt::Orientation orientation, int role) const { QVariant headerData; // show only horizontal header if ( role == Qt::DisplayRole ) { if( orientation == Qt::Horizontal ) { // first column: "Attribute" if(section == 0) headerData = "Attribute"; else if(section == 1) headerData = "Value"; else if(section == 2) headerData = "Type"; } } return headerData; } Qt::ItemFlags QmitkPythonVariableStackTableModel::flags(const QModelIndex &index) const { Qt::ItemFlags flags = QAbstractItemModel::flags(index); if(index.isValid()) return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | flags; else return Qt::ItemIsDropEnabled | flags; } int QmitkPythonVariableStackTableModel::rowCount(const QModelIndex &) const { return m_VariableStack.size(); } int QmitkPythonVariableStackTableModel::columnCount(const QModelIndex &) const { return 3; } QVariant QmitkPythonVariableStackTableModel::data(const QModelIndex &index, int role) const { if (index.isValid() && !m_VariableStack.empty()) { if(role == Qt::DisplayRole) { mitk::PythonVariable item = m_VariableStack.at(index.row()); if(index.column() == 0) return QString::fromStdString(item.m_Name); if(index.column() == 1) return QString::fromStdString(item.m_Value); if(index.column() == 2) return QString::fromStdString(item.m_Type); } } return QVariant(); } QStringList QmitkPythonVariableStackTableModel::mimeTypes() const { return QAbstractTableModel::mimeTypes(); QStringList types; types << "application/x-mitk-datanodes"; types << "application/x-qabstractitemmodeldatalist"; return types; } Qt::DropActions QmitkPythonVariableStackTableModel::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } void QmitkPythonVariableStackTableModel::CommandExecuted(const std::string& pythonCommand) { MITK_DEBUG("QmitkPythonVariableStackTableModel") << "command was executed " << pythonCommand; m_VariableStack = m_PythonService->GetVariableStack(); QAbstractTableModel::reset(); } std::vector QmitkPythonVariableStackTableModel::GetVariableStack() const { return m_VariableStack; } diff --git a/Modules/Python/QmitkPythonVariableStackTableModel.h b/Modules/Python/QmitkPythonVariableStackTableModel.h index c21fac358b..ce45819723 100755 --- a/Modules/Python/QmitkPythonVariableStackTableModel.h +++ b/Modules/Python/QmitkPythonVariableStackTableModel.h @@ -1,61 +1,63 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QmitkPythonVariableStackTableModel_h #define QmitkPythonVariableStackTableModel_h #include #include #include #include "mitkIPythonService.h" #include "mitkPythonExports.h" +#include /// /// implements a table model to show the variables of the Python "__main__" dictionary /// furthermore implements dragging and dropping of datanodes (conversion from and to python) /// class MITK_PYTHON_EXPORT QmitkPythonVariableStackTableModel : public QAbstractTableModel, public mitk::PythonCommandObserver { Q_OBJECT public: static const QString MITK_IMAGE_VAR_NAME; static const QString MITK_SURFACE_VAR_NAME; QmitkPythonVariableStackTableModel(QObject *parent = 0); virtual ~QmitkPythonVariableStackTableModel(); int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; Qt::ItemFlags flags( const QModelIndex& index ) const; virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; QStringList mimeTypes() const; bool dropMimeData ( const QMimeData *, Qt::DropAction, int, int, const QModelIndex & ); Qt::DropActions supportedDropActions() const; Qt::DropActions supportedDragActions() const; void CommandExecuted(const std::string& pythonCommand); std::vector GetVariableStack() const; private: std::vector m_VariableStack; mitk::IPythonService* m_PythonService; + mitk::ServiceReference m_PythonServiceRef; }; #endif // QmitkPythonVariableStackTableModel_h diff --git a/Modules/Python/mitkPythonActivator.cpp b/Modules/Python/mitkPythonActivator.cpp index 62963304e8..d6d1e65939 100644 --- a/Modules/Python/mitkPythonActivator.cpp +++ b/Modules/Python/mitkPythonActivator.cpp @@ -1,61 +1,67 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkPythonActivator_h #define mitkPythonActivator_h // Microservices #include #include "mitkModuleContext.h" #include "mitkPythonService.h" #include namespace mitk { /// /// installs the PythonService /// runs all initial commands (setting env paths etc) /// class PythonActivator : public mitk::ModuleActivator { public: void Load(mitk::ModuleContext* context) { + MITK_DEBUG << "PythonActivator::Load"; // Registering PythonService as MicroService m_PythonService = itk::SmartPointer(new PythonService()); ServiceProperties _PythonServiceProps; _PythonServiceProps["Name"] = std::string("PythonService"); - context->RegisterService(m_PythonService, _PythonServiceProps); + m_PythonServiceRegistration = context->RegisterService(m_PythonService, _PythonServiceProps); } void Unload(mitk::ModuleContext* context) { - m_PythonService = 0; + MITK_DEBUG("PythonActivator") << "PythonActivator::Unload"; + MITK_DEBUG("PythonActivator") << "m_PythonService GetReferenceCount " << m_PythonService->GetReferenceCount(); + m_PythonServiceRegistration.Unregister(); + m_PythonService->Delete(); + MITK_DEBUG("PythonActivator") << "m_PythonService GetReferenceCount " << m_PythonService->GetReferenceCount(); } - ~PythonActivator() + virtual ~PythonActivator() { } private: itk::SmartPointer m_PythonService; + ServiceRegistration m_PythonServiceRegistration; }; } US_EXPORT_MODULE_ACTIVATOR(mitkPython, mitk::PythonActivator) #endif diff --git a/Modules/Python/mitkPythonService.cpp b/Modules/Python/mitkPythonService.cpp index ec8ccd5fa5..853fa8e819 100644 --- a/Modules/Python/mitkPythonService.cpp +++ b/Modules/Python/mitkPythonService.cpp @@ -1,451 +1,506 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPythonService.h" #include #include #include #include #include #include "PythonPath.h" const QString mitk::PythonService::m_TmpImageName("temp_mitk_image"); mitk::PythonService::PythonService() : m_ItkWrappingAvailable( true ), m_OpenCVWrappingAvailable( true ), m_VtkWrappingAvailable( true ) { + { + MITK_DEBUG << "will init python if necessary"; + } + bool pythonInitialized = static_cast( Py_IsInitialized() ); //m_PythonManager.isPythonInitialized() ); + { + MITK_DEBUG << "pythonInitialized " << pythonInitialized; + MITK_DEBUG << "m_PythonManager.isPythonInitialized() " << m_PythonManager.isPythonInitialized(); + } + + // due to strange static var behaviour on windows Py_IsInitialized() returns correct value while + // m_PythonManager.isPythonInitialized() does not because it has been constructed and destructed again if( !m_PythonManager.isPythonInitialized() ) { - //system("export LD_LIBRARY_PATH=/local/muellerm/mitk/bugsquashing/bin-debug/VTK-build/bin:$LD_LIBRARY_PATH"); + try + { + if( pythonInitialized ) + m_PythonManager.setInitializationFlags(PythonQt::RedirectStdOut|PythonQt::PythonAlreadyInitialized); + else + m_PythonManager.setInitializationFlags(PythonQt::RedirectStdOut); - MITK_DEBUG("PythonService") << "initialize python"; - m_PythonManager.setInitializationFlags(PythonQt::RedirectStdOut); - m_PythonManager.initialize(); + MITK_DEBUG("PythonService") << "initalizing python"; + m_PythonManager.initialize(); - //m_PythonManager.executeString( "print sys.path", ctkAbstractPythonManager::SingleInput ); - //MITK_DEBUG("mitk::PythonService") << "result of 'sys.path': " << result.toString().toStdString(); + MITK_DEBUG("PythonService") << "python initalized"; - m_PythonManager.executeString( "sys.path.append('/usr/share/pyshared/numpy')", ctkAbstractPythonManager::SingleInput ); - m_PythonManager.executeString( "import numpy", ctkAbstractPythonManager::SingleInput ); + QString pythonCommand(PYTHONPATH_COMMAND); + MITK_DEBUG("PythonService") << "registering python paths" << PYTHONPATH_COMMAND; + m_PythonManager.executeString( pythonCommand, ctkAbstractPythonManager::FileInput ); - QString pythonCommand(PYTHONPATH_COMMAND); - MITK_DEBUG("PythonService") << "registering python paths" << PYTHONPATH_COMMAND; - m_PythonManager.executeString( pythonCommand, ctkAbstractPythonManager::FileInput ); + /* + //system("export LD_LIBRARY_PATH=/local/muellerm/mitk/bugsquashing/bin-debug/VTK-build/bin:$LD_LIBRARY_PATH"); + //m_PythonManager.executeString( "print sys.path", ctkAbstractPythonManager::SingleInput ); + //MITK_DEBUG("mitk::PythonService") << "result of 'sys.path': " << result.toString().toStdString(); - MITK_DEBUG("mitk::PythonService") << "Trying to import ITK"; - m_PythonManager.executeString( "import itk", ctkAbstractPythonManager::SingleInput ); - m_ItkWrappingAvailable = !m_PythonManager.pythonErrorOccured(); - MITK_DEBUG("mitk::PythonService") << "m_ItkWrappingAvailable: " << (m_ItkWrappingAvailable? "yes": "no"); - if( !m_ItkWrappingAvailable ) - { - MITK_WARN << "ITK Python wrapping not available. Please check build settings or PYTHON_PATH settings."; - } + //m_PythonManager.executeString( "sys.path.append('/usr/share/pyshared/numpy')", ctkAbstractPythonManager::SingleInput ); + //m_PythonManager.executeString( "import numpy", ctkAbstractPythonManager::SingleInput ); - MITK_DEBUG("mitk::PythonService") << "Trying to import OpenCv"; - m_PythonManager.executeString( "import cv2", ctkAbstractPythonManager::SingleInput ); - m_OpenCVWrappingAvailable = !m_PythonManager.pythonErrorOccured(); - MITK_DEBUG("mitk::PythonService") << "m_OpenCVWrappingAvailable: " << (m_OpenCVWrappingAvailable? "yes": "no"); - if( !m_OpenCVWrappingAvailable ) - { - MITK_WARN << "OpenCV Python wrapping not available. Please check build settings or PYTHON_PATH settings."; - } + MITK_DEBUG("mitk::PythonService") << "Trying to import ITK"; + m_PythonManager.executeString( "import itk", ctkAbstractPythonManager::SingleInput ); + m_ItkWrappingAvailable = !m_PythonManager.pythonErrorOccured(); + MITK_DEBUG("mitk::PythonService") << "m_ItkWrappingAvailable: " << (m_ItkWrappingAvailable? "yes": "no"); + if( !m_ItkWrappingAvailable ) + { + MITK_WARN << "ITK Python wrapping not available. Please check build settings or PYTHONPATH settings."; + } - MITK_DEBUG("mitk::PythonService") << "Trying to import VTK"; - m_PythonManager.executeString( "import vtk", ctkAbstractPythonManager::SingleInput ); - m_VtkWrappingAvailable = !m_PythonManager.pythonErrorOccured(); - MITK_DEBUG("mitk::PythonService") << "m_VtkWrappingAvailable: " << (m_VtkWrappingAvailable? "yes": "no"); - if( !m_VtkWrappingAvailable ) + { + MITK_DEBUG("mitk::PythonService") << "Trying to import OpenCv"; + PyRun_SimpleString("import cv2\n"); + if (PyErr_Occurred()) + { + PyErr_Print(); + } + else + m_OpenCVWrappingAvailable = true; + + //m_PythonManager.executeString( "import cv2", ctkAbstractPythonManager::SingleInput ); + MITK_DEBUG("mitk::PythonService") << "Investigate if an error occured while importing cv2"; + //m_OpenCVWrappingAvailable = !m_PythonManager.pythonErrorOccured(); + MITK_DEBUG("mitk::PythonService") << "m_OpenCVWrappingAvailable: " << (m_OpenCVWrappingAvailable? "yes": "no"); + if( !m_OpenCVWrappingAvailable ) + { + MITK_WARN << "OpenCV Python wrapping not available. Please check build settings or PYTHONPATH settings."; + } + } + + MITK_DEBUG("mitk::PythonService") << "Trying to import VTK"; + m_PythonManager.executeString( "import vtk", ctkAbstractPythonManager::SingleInput ); + m_VtkWrappingAvailable = !m_PythonManager.pythonErrorOccured(); + MITK_DEBUG("mitk::PythonService") << "m_VtkWrappingAvailable: " << (m_VtkWrappingAvailable? "yes": "no"); + if( !m_VtkWrappingAvailable ) + { + MITK_WARN << "VTK Python wrapping not available. Please check build settings or PYTHONPATH settings."; + } + */ + } + catch (...) { - MITK_WARN << "VTK Python wrapping not available. Please check build settings or PYTHON_PATH settings."; + MITK_DEBUG("PythonService") << "exception initalizing python"; } - //m_PythonManager.executeString( "for path in sys.path:\n print path\n", ctkAbstractPythonManager::SingleInput ); - //m_PythonManager.executeString( "for k, v in os.environ.items():\n print \"%s=%s\" % (k, v)", ctkAbstractPythonManager::SingleInput ); - //m_PythonManager.executeFile("/local/muellerm/Dropbox/13-02-11-python-wrapping/interpreterInfo.py"); - } + + //m_PythonManager.executeString( "for path in sys.path:\n print path\n", ctkAbstractPythonManager::SingleInput ); + //m_PythonManager.executeString( "for k, v in os.environ.items():\n print \"%s=%s\" % (k, v)", ctkAbstractPythonManager::SingleInput ); + //m_PythonManager.executeFile("/local/muellerm/Dropbox/13-02-11-python-wrapping/interpreterInfo.py"); //std::string result = m_PythonManager.executeString( "5+5", ctkAbstractPythonManager::EvalInput ); //MITK_DEBUG("mitk::PythonService") << "result of '5+5': " << result.toString().toStdString(); } mitk::PythonService::~PythonService() { + //QVariant result = m_PythonManager.executeString( "sys.getrefcount(cv2)", ctkAbstractPythonManager::EvalInput ); + //MITK_DEBUG("mitk::PythonService") << "sys.getrefcount(cv2): " << result.toString().toStdString(); + + //m_PythonManager.executeString( "del sys.modules[\"cv2\"]", ctkAbstractPythonManager::SingleInput ); + //m_PythonManager.executeString( "del cv2", ctkAbstractPythonManager::SingleInput ); + MITK_DEBUG("mitk::PythonService") << "destructing PythonService"; } std::string mitk::PythonService::Execute(const std::string &stdpythonCommand, int commandType) { QString pythonCommand = QString::fromStdString(stdpythonCommand); { MITK_DEBUG("mitk::PythonService") << "pythonCommand = " << pythonCommand.toStdString(); MITK_DEBUG("mitk::PythonService") << "commandType = " << commandType; } QVariant result; bool commandIssued = true; if(commandType == IPythonService::SINGLE_LINE_COMMAND ) result = m_PythonManager.executeString(pythonCommand, ctkAbstractPythonManager::SingleInput ); else if(commandType == IPythonService::MULTI_LINE_COMMAND ) result = m_PythonManager.executeString(pythonCommand, ctkAbstractPythonManager::FileInput ); else if(commandType == IPythonService::EVAL_COMMAND ) result = m_PythonManager.executeString(pythonCommand, ctkAbstractPythonManager::EvalInput ); else commandIssued = false; if(commandIssued) this->NotifyObserver(pythonCommand.toStdString()); return result.toString().toStdString(); } void mitk::PythonService::ExecuteScript( const std::string& pythonScript ) { m_PythonManager.executeFile(QString::fromStdString(pythonScript)); } std::vector mitk::PythonService::GetVariableStack() const { std::vector list; PyObject* dict = PyImport_GetModuleDict(); PyObject* object = PyDict_GetItemString(dict, "__main__"); PyObject* dirMain = PyObject_Dir(object); PyObject* tempObject; if(dirMain) { std::string attr, attrValue, attrType; for(int i = 0; iob_type->tp_name; if(PyUnicode_Check(tempObject) || PyString_Check(tempObject)) attrValue = PyString_AsString(tempObject); else attrValue = ""; mitk::PythonVariable var; var.m_Name = attr; var.m_Value = attrValue; var.m_Type = attrType; list.push_back(var); } } return list; } void mitk::PythonService::AddPythonCommandObserver(mitk::PythonCommandObserver *observer) { if(!m_Observer.contains(observer)) m_Observer.append(observer); } void mitk::PythonService::RemovePythonCommandObserver(mitk::PythonCommandObserver *observer) { m_Observer.removeOne(observer); } void mitk::PythonService::NotifyObserver(const std::string &command) { MITK_DEBUG("mitk::PythonService") << "number of observer " << m_Observer.size(); for( size_t i=0; i< m_Observer.size(); ++i ) { m_Observer.at(i)->CommandExecuted(command); } } QString mitk::PythonService::GetTempImageName(const std::string& ext) const { QString tmpFolder = QDir::tempPath(); QString fileName = tmpFolder + QDir::separator() + m_TmpImageName + QString::fromStdString(ext); return fileName; } bool mitk::PythonService::CopyToPythonAsItkImage(mitk::Image *image, const std::string &stdvarName) { QString varName = QString::fromStdString( stdvarName ); // save image QString fileName = this->GetTempImageName( mitk::IOUtil::DEFAULTIMAGEEXTENSION ); fileName = QDir::fromNativeSeparators( fileName ); MITK_DEBUG("PythonService") << "Saving temporary file " << fileName.toStdString(); if( !mitk::IOUtil::SaveImage(image, fileName.toStdString()) ) { MITK_ERROR << "Temporary file could not be created."; } else { // TODO CORRECT TYPE SETUP, MAKE MITK_DEBUG("PythonService") MITK_DEBUG("PythonService") int dim = image->GetDimension(); mitk::PixelType pixelType = image->GetPixelType(); itk::ImageIOBase::IOPixelType ioPixelType = image->GetPixelType().GetPixelTypeId(); // default pixeltype: unsigned short QString type = "US"; if( ioPixelType == itk::ImageIOBase::SCALAR ) { if( pixelType.GetTypeId() == typeid(double) ) type = "D"; else if( pixelType.GetTypeId() == typeid(float) ) type = "F"; if( pixelType.GetTypeId() == typeid(long double) ) type = "LD"; else if( pixelType.GetTypeId() == typeid(short) ) type = "SS"; else if( pixelType.GetTypeId() == typeid(signed char) ) type = "SC"; else if( pixelType.GetTypeId() == typeid(signed int) ) type = "SI"; else if( pixelType.GetTypeId() == typeid(signed long) ) type = "SL"; else if( pixelType.GetTypeId() == typeid(signed short) ) type = "SS"; else if( pixelType.GetTypeId() == typeid(unsigned char) ) type = "UC"; else if( pixelType.GetTypeId() == typeid(unsigned int) ) type = "UI"; else if( pixelType.GetTypeId() == typeid(unsigned long) ) type = "UL"; else if( pixelType.GetTypeId() == typeid(unsigned short) ) type = "US"; } MITK_DEBUG("PythonService") << "Got mitk image with type " << type.toStdString() << " and dim " << dim; QString command; command.append( QString("imageType = itk.Image[itk.%1, %2]\n") .arg( type ).arg( dim ) ); command.append( QString("readerType = itk.ImageFileReader[imageType]\n") ); command.append( QString("reader = readerType.New()\n") ); command.append( QString("reader.SetFileName( \"%1\" )\n") .arg(fileName) ); command.append( QString("reader.Update()\n") ); command.append( QString("%1 = reader.GetOutput()\n").arg( varName ) ); MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); this->Execute( command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); QFile file( fileName ); MITK_DEBUG("PythonService") << "Removing file " << fileName.toStdString(); file.remove(); return true; } return false; } mitk::Image::Pointer mitk::PythonService::CopyItkImageFromPython(const std::string &stdvarName) { QString varName = QString::fromStdString( stdvarName ); mitk::Image::Pointer mitkImage; QString command; QString fileName = GetTempImageName( mitk::IOUtil::DEFAULTIMAGEEXTENSION ); fileName = QDir::fromNativeSeparators( fileName ); MITK_DEBUG("PythonService") << "Saving temporary file with python itk code " << fileName.toStdString(); command.append( QString( "writer = itk.ImageFileWriter[ %1 ].New()\n").arg( varName ) ); command.append( QString( "writer.SetFileName( \"%1\" )\n").arg(fileName) ); command.append( QString( "writer.SetInput( %1 )\n").arg(varName) ); command.append( QString( "writer.Update()\n" ) ); MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); try { MITK_DEBUG("PythonService") << "Loading temporary file " << fileName.toStdString() << " as MITK image"; mitkImage = mitk::IOUtil::LoadImage( fileName.toStdString() ); } catch(std::exception& e) { MITK_ERROR << e.what(); } QFile file(fileName); if( file.exists() ) { MITK_DEBUG("PythonService") << "Removing temporary file " << fileName.toStdString(); file.remove(); } return mitkImage; } bool mitk::PythonService::CopyToPythonAsCvImage( mitk::Image* image, const std::string& stdvarName ) { QString varName = QString::fromStdString( stdvarName ); bool convert = false; if(image->GetDimension() != 2) { MITK_ERROR << "Only 2D images allowed for OpenCV images"; return convert; } // try to save mitk image QString fileName = this->GetTempImageName( ".bmp" ); fileName = QDir::fromNativeSeparators( fileName ); MITK_DEBUG("PythonService") << "Saving temporary file " << fileName.toStdString(); if( !mitk::IOUtil::SaveImage(image, fileName.toStdString()) ) { MITK_ERROR << "Temporary file " << fileName.toStdString() << " could not be created."; return convert; } QString command; - command.append( QString("%1 = cv.LoadImage(\"%2\")\n") .arg( varName ).arg( fileName ) ); + command.append( QString("%1 = cv2.imread(\"%2\")\n") .arg( varName ).arg( fileName ) ); MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); MITK_DEBUG("PythonService") << "Removing file " << fileName.toStdString(); QFile file(fileName); file.remove(); convert = true; return convert; } mitk::Image::Pointer mitk::PythonService::CopyCvImageFromPython( const std::string& stdvarName ) { QString varName = QString::fromStdString( stdvarName ); mitk::Image::Pointer mitkImage; QString command; QString fileName = GetTempImageName( ".bmp" ); fileName = QDir::fromNativeSeparators( fileName ); MITK_DEBUG("PythonService") << "run python command to save image with opencv to " << fileName.toStdString(); - command.append( QString( "cv.SaveImage(\"%1\", %2)\n").arg( fileName ).arg( varName ) ); + command.append( QString( "cv2.imwrite(\"%1\", %2)\n").arg( fileName ).arg( varName ) ); MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); try { MITK_DEBUG("PythonService") << "Loading temporary file " << fileName.toStdString() << " as MITK image"; mitkImage = mitk::IOUtil::LoadImage( fileName.toStdString() ); } catch(std::exception& e) { MITK_ERROR << e.what(); } QFile file(fileName); if( file.exists() ) { MITK_DEBUG("PythonService") << "Removing temporary file " << fileName.toStdString(); file.remove(); } return mitkImage; } ctkAbstractPythonManager *mitk::PythonService::GetPythonManager() { return &m_PythonManager; } mitk::Surface::Pointer mitk::PythonService::CopyVtkPolyDataFromPython( const std::string& stdvarName ) { QString varName = QString::fromStdString( stdvarName ); mitk::Surface::Pointer newSurface; QString command; QString fileName = GetTempImageName( ".stl" ); fileName = QDir::fromNativeSeparators( fileName ); MITK_DEBUG("PythonService") << "run python command to save polydata with vtk to " << fileName.toStdString(); command = QString ( "vtkStlWriter = vtk.vtkSTLWriter()\n" "vtkStlWriter.SetInput(%1)\n" "vtkStlWriter.SetFileName(\"%2\")\n" "vtkStlWriter.Write()\n").arg(varName).arg(fileName); MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); try { MITK_DEBUG("PythonService") << "Loading temporary file " << fileName.toStdString() << " as MITK Surface"; newSurface = mitk::IOUtil::LoadSurface( fileName.toStdString() ); } catch(std::exception& e) { MITK_ERROR << e.what(); } QFile file(fileName); if( file.exists() ) { MITK_DEBUG("PythonService") << "Removing temporary file " << fileName.toStdString(); file.remove(); } return newSurface; } bool mitk::PythonService::CopyToPythonAsVtkPolyData( mitk::Surface* surface, const std::string& stdvarName ) { QString varName = QString::fromStdString( stdvarName ); bool convert = false; // try to save mitk image QString fileName = this->GetTempImageName( ".stl" ); fileName = QDir::fromNativeSeparators( fileName ); MITK_DEBUG("PythonService") << "Saving temporary file " << fileName.toStdString(); if( !mitk::IOUtil::SaveSurface( surface, fileName.toStdString() ) ) { MITK_ERROR << "Temporary file " << fileName.toStdString() << " could not be created."; return convert; } QString command; command.append( QString("vtkStlReader = vtk.vtkSTLReader()\n") ); command.append( QString("vtkStlReader.SetFileName(\"%1\")\n").arg( fileName ) ); command.append( QString("%1 = vtkStlReader.GetOutput()").arg( fileName ) ); MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); MITK_DEBUG("PythonService") << "Removing file " << fileName.toStdString(); QFile file(fileName); file.remove(); convert = true; return convert; } bool mitk::PythonService::IsItkPythonWrappingAvailable() { + this->Execute( "import itk", IPythonService::SINGLE_LINE_COMMAND ); + m_ItkWrappingAvailable = !this->PythonErrorOccured(); + return m_ItkWrappingAvailable; } bool mitk::PythonService::IsOpenCvPythonWrappingAvailable() { + this->Execute( "import cv2", IPythonService::SINGLE_LINE_COMMAND ); + m_OpenCVWrappingAvailable = !this->PythonErrorOccured(); + return m_OpenCVWrappingAvailable; } bool mitk::PythonService::IsVtkPythonWrappingAvailable() { + this->Execute( "import vtk", IPythonService::SINGLE_LINE_COMMAND ); + m_VtkWrappingAvailable = !this->PythonErrorOccured(); return m_VtkWrappingAvailable; } +bool mitk::PythonService::PythonErrorOccured() const +{ + return m_PythonManager.pythonErrorOccured(); +} + diff --git a/Modules/Python/mitkPythonService.h b/Modules/Python/mitkPythonService.h index a724ace3c9..6fda07058a 100644 --- a/Modules/Python/mitkPythonService.h +++ b/Modules/Python/mitkPythonService.h @@ -1,98 +1,101 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkPythonService_h #define mitkPythonService_h #include "mitkIPythonService.h" #include #include #include "mitkSurface.h" #include "mitkPythonExports.h" namespace mitk { /// /// implementation of the IPythonService using ctkabstractpythonmanager /// \see IPythonService class MITK_PYTHON_EXPORT PythonService: public itk::LightObject, public mitk::IPythonService { public: /// /// instantiate python manager here PythonService(); /// /// empty implementation... ~PythonService(); /// /// \see IPythonService::Execute() std::string Execute( const std::string& pythonCommand, int commandType = SINGLE_LINE_COMMAND ); /// /// \see IPythonService::ExecuteScript() void ExecuteScript(const std::string &pathToPythonScript); /// + /// \see IPythonService::PythonErrorOccured() + bool PythonErrorOccured() const; + /// /// \see IPythonService::GetVariableStack() std::vector GetVariableStack() const; /// /// \see IPythonService::AddPythonCommandObserver() void AddPythonCommandObserver( PythonCommandObserver* observer ); /// /// \see IPythonService::RemovePythonCommandObserver() void RemovePythonCommandObserver( PythonCommandObserver* observer ); /// /// \see IPythonService::NotifyObserver() void NotifyObserver( const std::string& command ); /// /// \see IPythonService::IsItkPythonWrappingAvailable() bool IsItkPythonWrappingAvailable(); /// /// \see IPythonService::CopyToPythonAsItkImage() bool CopyToPythonAsItkImage( mitk::Image* image, const std::string& varName ); /// /// \see IPythonService::CopyItkImageFromPython() mitk::Image::Pointer CopyItkImageFromPython( const std::string& varName ); /// /// \see IPythonService::IsOpenCvPythonWrappingAvailable() bool IsOpenCvPythonWrappingAvailable(); /// /// \see IPythonService::CopyToPythonAsCvImage() bool CopyToPythonAsCvImage( mitk::Image* image, const std::string& varName ); /// /// \see IPythonService::CopyCvImageFromPython() mitk::Image::Pointer CopyCvImageFromPython( const std::string& varName ); /// /// \see IPythonService::IsVtkPythonWrappingAvailable() bool IsVtkPythonWrappingAvailable(); /// /// \see IPythonService::CopyToPythonAsVtkPolyData() bool CopyToPythonAsVtkPolyData( mitk::Surface* surface, const std::string& varName ); /// /// \see IPythonService::CopyVtkPolyDataFromPython() mitk::Surface::Pointer CopyVtkPolyDataFromPython( const std::string& varName ); /// /// \return the ctk abstract python manager instance ctkAbstractPythonManager* GetPythonManager(); protected: QString GetTempImageName(const std::string &ext) const; private: QList m_Observer; ctkAbstractPythonManager m_PythonManager; static const QString m_TmpImageName; bool m_ItkWrappingAvailable; bool m_OpenCVWrappingAvailable; bool m_VtkWrappingAvailable; }; } #endif diff --git a/Modules/Python/resources/PythonSnippets.xml b/Modules/Python/resources/PythonSnippets.xml index 61fc3cf768..98e92ef2fa 100644 --- a/Modules/Python/resources/PythonSnippets.xml +++ b/Modules/Python/resources/PythonSnippets.xml @@ -1,4 +1,6 @@ + + diff --git a/Plugins/org.mitk.gui.qt.python/src/internal/QmitkPythonView.cpp b/Plugins/org.mitk.gui.qt.python/src/internal/QmitkPythonView.cpp index 8b7e1e5308..32b6a104bc 100644 --- a/Plugins/org.mitk.gui.qt.python/src/internal/QmitkPythonView.cpp +++ b/Plugins/org.mitk.gui.qt.python/src/internal/QmitkPythonView.cpp @@ -1,93 +1,98 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkPythonView.h" #include #include #include "mitkPluginActivator.h" #include #include #include const std::string QmitkPythonView::VIEW_ID = "org.mitk.views.python"; struct QmitkPythonViewData { // widget QmitkPythonVariableStackTableView* m_PythonVariableStackTableView; QmitkPythonSnippets* m_PythonSnippets; QmitkCtkPythonShell* m_PythonShell; QmitkPythonTextEditor* m_TextEditor; }; QmitkPythonView::QmitkPythonView() : d( new QmitkPythonViewData ) { d->m_PythonVariableStackTableView = 0; d->m_PythonShell = 0; } QmitkPythonView::~QmitkPythonView() { delete d; } void QmitkPythonView::CreateQtPartControl(QWidget* parent) { d->m_PythonVariableStackTableView = new QmitkPythonVariableStackTableView; d->m_PythonVariableStackTableView->SetDataStorage(this->GetDataStorage()); d->m_PythonVariableStackTableView->horizontalHeader()->setResizeMode(QHeaderView::Interactive); QString snippetsFilePath = mitk::PluginActivator::m_XmlFilePath; MITK_DEBUG("QmitkPythonView") << "got snippetsFilePath " << snippetsFilePath.toStdString(); d->m_PythonSnippets = new QmitkPythonSnippets(snippetsFilePath); + MITK_DEBUG("QmitkPythonView") << "initializing varStackSnippetsTab"; QTabWidget* varStackSnippetsTab = new QTabWidget; varStackSnippetsTab->addTab( d->m_PythonVariableStackTableView, "Variable Stack" ); varStackSnippetsTab->addTab( d->m_PythonSnippets, "Snippets" ); varStackSnippetsTab->setTabPosition( QTabWidget::South ); + MITK_DEBUG("QmitkPythonView") << "initializing m_PythonShell"; d->m_PythonShell = new QmitkCtkPythonShell; + MITK_DEBUG("QmitkPythonView") << "initializing m_TextEditor"; d->m_TextEditor = new QmitkPythonTextEditor; + MITK_DEBUG("QmitkPythonView") << "initializing tabWidgetConsoleEditor"; QTabWidget* tabWidgetConsoleEditor = new QTabWidget; tabWidgetConsoleEditor->addTab( d->m_PythonShell, "Console" ); tabWidgetConsoleEditor->addTab( d->m_TextEditor, "Text Editor" ); tabWidgetConsoleEditor->setTabPosition( QTabWidget::South ); QList sizes; sizes << 1 << 3; QSplitter* splitter = new QSplitter; splitter->addWidget(varStackSnippetsTab); splitter->addWidget(tabWidgetConsoleEditor); splitter->setStretchFactor ( 0, 1 ); splitter->setStretchFactor ( 1, 3 ); QGridLayout* layout = new QGridLayout; layout->addWidget( splitter, 0, 0 ); parent->setLayout(layout); + MITK_DEBUG("QmitkPythonView") << "creating connections for m_PythonSnippets"; connect( d->m_PythonSnippets, SIGNAL(PasteCommandRequested(QString)), d->m_PythonShell, SLOT(Paste(QString)) ); connect( d->m_PythonSnippets, SIGNAL(PasteCommandRequested(QString)), d->m_TextEditor, SLOT(Paste(QString)) ); } void QmitkPythonView::SetFocus() { d->m_PythonShell->setFocus(); }