diff --git a/Plugins/org.mitk.gui.qt.cli/src/QmitkCmdLineModuleProgressWidget.cpp b/Plugins/org.mitk.gui.qt.cli/src/QmitkCmdLineModuleProgressWidget.cpp index 2e3c9408cb..689e9c97c1 100644 --- a/Plugins/org.mitk.gui.qt.cli/src/QmitkCmdLineModuleProgressWidget.cpp +++ b/Plugins/org.mitk.gui.qt.cli/src/QmitkCmdLineModuleProgressWidget.cpp @@ -1,144 +1,307 @@ /*=================================================================== 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 - #include "QmitkCmdLineModuleProgressWidget.h" #include "ui_QmitkCmdLineModuleProgressWidget.h" +// Qt +#include + +// CTK +#include +#include +#include +#include +#include + +// MITK +#include +#include +#include +#include +#include QmitkCmdLineModuleProgressWidget::QmitkCmdLineModuleProgressWidget(QWidget *parent) : QWidget(parent) , m_UI(new Ui::QmitkCmdLineModuleProgressWidget) { + qRegisterMetaType(); + qRegisterMetaType(); + m_UI->setupUi(this); m_UI->m_RemoveButton->setIcon(QApplication::style()->standardIcon(QStyle::SP_TitleBarCloseButton)); // Due to Qt bug 12152, we cannot listen to the "paused" signal because it is // not emitted directly when the QFuture is paused. Instead, it is emitted after // resuming the future, after the "resume" signal has been emitted... we use // a polling aproach instead. m_PollPauseTimer.setInterval(300); connect(&m_PollPauseTimer, SIGNAL(timeout()), SLOT(checkModulePaused())); connect(&m_FutureWatcher, SIGNAL(started()), SLOT(moduleStarted())); connect(&m_FutureWatcher, SIGNAL(canceled()), SLOT(moduleCanceled())); connect(&m_FutureWatcher, SIGNAL(finished()), SLOT(moduleFinished())); connect(&m_FutureWatcher, SIGNAL(resumed()), SLOT(moduleResumed())); connect(&m_FutureWatcher, SIGNAL(progressRangeChanged(int,int)), SLOT(moduleProgressRangeChanged(int,int))); connect(&m_FutureWatcher, SIGNAL(progressTextChanged(QString)), SLOT(moduleProgressTextChanged(QString))); connect(&m_FutureWatcher, SIGNAL(progressValueChanged(int)), SLOT(moduleProgressValueChanged(int))); connect(m_UI->m_CancelButton, SIGNAL(clicked()), &this->m_FutureWatcher, SLOT(cancel())); m_PollPauseTimer.start(); } QmitkCmdLineModuleProgressWidget::~QmitkCmdLineModuleProgressWidget() { + this->ClearUpTemporaryFiles(); delete m_UI; } -void QmitkCmdLineModuleProgressWidget::setFuture(const ctkCmdLineModuleFuture &future) -{ - m_UI->m_PauseButton->setEnabled(future.canPause()); - m_UI->m_CancelButton->setEnabled(future.canCancel()); - m_UI->m_RemoveButton->setEnabled(!future.isRunning()); - - m_FutureWatcher.setFuture(future); -} void QmitkCmdLineModuleProgressWidget::setTitle(const QString &title) { m_UI->m_ProgressTitle->setText(title); } void QmitkCmdLineModuleProgressWidget::mouseReleaseEvent(QMouseEvent*) { emit clicked(); } void QmitkCmdLineModuleProgressWidget::on_PauseButton_toggled(bool toggled) { this->m_FutureWatcher.setPaused(toggled); } void QmitkCmdLineModuleProgressWidget::on_RemoveButton_clicked() { this->deleteLater(); } void QmitkCmdLineModuleProgressWidget::moduleStarted() { this->m_UI->m_ProgressBar->setMaximum(0); } void QmitkCmdLineModuleProgressWidget::moduleCanceled() { this->m_UI->m_PauseButton->setEnabled(false); this->m_UI->m_PauseButton->setChecked(false); this->m_UI->m_CancelButton->setEnabled(false); this->m_UI->m_RemoveButton->setEnabled(true); } void QmitkCmdLineModuleProgressWidget::moduleFinished() { + QString message = "finishing."; + this->PublishMessage(message); + this->m_UI->m_PauseButton->setEnabled(false); this->m_UI->m_PauseButton->setChecked(false); this->m_UI->m_CancelButton->setEnabled(false); this->m_UI->m_RemoveButton->setEnabled(true); + + this->LoadOutputData(); + this->ClearUpTemporaryFiles(); + + message = "finished."; + this->PublishMessage(message); } void QmitkCmdLineModuleProgressWidget::checkModulePaused() { if (this->m_FutureWatcher.future().isPaused()) { if (!m_UI->m_PauseButton->isChecked()) { m_UI->m_PauseButton->setChecked(true); } } else { if (m_UI->m_PauseButton->isChecked()) { m_UI->m_PauseButton->setChecked(false); } } } void QmitkCmdLineModuleProgressWidget::moduleResumed() { this->m_UI->m_PauseButton->setChecked(false); } void QmitkCmdLineModuleProgressWidget::moduleProgressRangeChanged(int progressMin, int progressMax) { this->m_UI->m_ProgressBar->setMinimum(progressMin); this->m_UI->m_ProgressBar->setMaximum(progressMax); } void QmitkCmdLineModuleProgressWidget::moduleProgressTextChanged(const QString& progressText) { //m_UI->m_ProgressText->setText(progressText); } void QmitkCmdLineModuleProgressWidget::moduleProgressValueChanged(int progressValue) { m_UI->m_ProgressBar->setValue(progressValue); } + +//----------------------------------------------------------------------------- +void QmitkCmdLineModuleProgressWidget::PublishMessage(const QString& message) +{ + QString prefix = ""; // Can put additional prefix here if needed. + qDebug() << prefix << message; +} + + +//----------------------------------------------------------------------------- +void QmitkCmdLineModuleProgressWidget::ClearUpTemporaryFiles() +{ + QString message; + QString fileName; + + foreach (fileName, m_TemporaryFileNames) + { + QFile file(fileName); + if (file.exists()) + { + message = QObject::tr("removing %1").arg(fileName); + this->PublishMessage(message); + + bool success = file.remove(); + + message = QObject::tr("removed %1, successfully=%2").arg(fileName).arg(success); + this->PublishMessage(message); + } + } +} + + +//----------------------------------------------------------------------------- +void QmitkCmdLineModuleProgressWidget::LoadOutputData() +{ + assert(m_DataStorage); + + std::vector fileNames; + + QString fileName; + foreach (fileName, m_OutputDataToLoad) + { + QString message = QObject::tr("loading %1").arg(fileName); + this->PublishMessage(message); + + fileNames.push_back(fileName.toStdString()); + } + + if (fileNames.size() > 0) + { + int numberLoaded = mitk::IOUtil::LoadFiles(fileNames, *(m_DataStorage)); + + QString message = QObject::tr("loaded %1 files").arg(numberLoaded); + this->PublishMessage(message); + } +} + + +//----------------------------------------------------------------------------- +void QmitkCmdLineModuleProgressWidget::Run(ctkCmdLineModuleFrontend* moduleInstance) +{ + assert(m_ModuleManager); + + if (!moduleInstance) + { + qWarning() << "Invalid module instance"; + return; + } + + m_OutputDataToLoad.clear(); + ctkCmdLineModuleReference reference = moduleInstance->moduleReference(); + ctkCmdLineModuleDescription description = reference.description(); + + QString message = "Saving image data to temporary storage..."; + this->PublishMessage(message); + + // Sanity check we have actually specified some input: + QString parameterName; + QList parameters; + + // For each input image, write a temporary file as a Nifti image, + // and then save the full path name back on the parameter. + parameters = moduleInstance->parameters("image", ctkCmdLineModuleFrontend::Input); + foreach (ctkCmdLineModuleParameter parameter, parameters) + { + parameterName = parameter.name(); + + QVariant tmp = moduleInstance->value(parameterName, ctkCmdLineModuleFrontend::UserRole); + mitk::DataNode::Pointer node = tmp.value(); + + if (node.IsNotNull()) + { + mitk::Image* image = dynamic_cast(node->GetData()); + if (image != NULL) + { + QString name = QString::fromStdString(node->GetName()); + int pid = QCoreApplication::applicationPid(); + int randomInt = qrand() % 1000000; + + QString fileName = m_TemporaryDirectoryName + "/" + name + QString::number(pid) + "." + QString::number(randomInt) + ".nii"; + + message = "Saving " + fileName; + this->PublishMessage(message); + + std::string tmpFN = CommonFunctionality::SaveImage(image, fileName.toStdString().c_str()); + QString temporaryStorageFileName = QString::fromStdString(tmpFN); + + m_TemporaryFileNames.push_back(temporaryStorageFileName); + moduleInstance->setValue(parameterName, temporaryStorageFileName); + + message = "Saved " + temporaryStorageFileName; + this->PublishMessage(message); + } // end if image + } // end if node + } // end foreach input image + + // For each output image or file, store the filename, so we can auto-load it once the process finishes. + parameters = moduleInstance->parameters("image", ctkCmdLineModuleFrontend::Output); + parameters << moduleInstance->parameters("file", ctkCmdLineModuleFrontend::Output); + foreach (ctkCmdLineModuleParameter parameter, parameters) + { + parameterName = parameter.name(); + QString outputFileName = moduleInstance->value(parameterName).toString(); + + if (!outputFileName.isEmpty()) + { + m_OutputDataToLoad.push_back(outputFileName); + + message = "Command Line Module ... Registered " + outputFileName + " to auto load upon completion."; + this->PublishMessage(message); + } + } + + // Now we run stuff. + message = "starting."; + this->PublishMessage(message); + + ctkCmdLineModuleFuture future = m_ModuleManager->run(moduleInstance); + m_FutureWatcher.setFuture(future); + + m_UI->m_PauseButton->setEnabled(future.canPause()); + m_UI->m_CancelButton->setEnabled(future.canCancel()); + m_UI->m_RemoveButton->setEnabled(!future.isRunning()); +} diff --git a/Plugins/org.mitk.gui.qt.cli/src/QmitkCmdLineModuleProgressWidget.h b/Plugins/org.mitk.gui.qt.cli/src/QmitkCmdLineModuleProgressWidget.h index f767742de4..7c6bd64e1f 100644 --- a/Plugins/org.mitk.gui.qt.cli/src/QmitkCmdLineModuleProgressWidget.h +++ b/Plugins/org.mitk.gui.qt.cli/src/QmitkCmdLineModuleProgressWidget.h @@ -1,82 +1,115 @@ /*=================================================================== 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 QMITKCMDLINEMODULEPROGRESSWIDGET_H #define QMITKCMDLINEMODULEPROGRESSWIDGET_H -#include "ctkCmdLineModuleResult.h" -#include "ctkCmdLineModuleFutureWatcher.h" - #include -#include #include +#include +class ctkCmdLineModuleManager; +class ctkCmdLineModuleFrontend; class ctkCmdLineModuleFuture; namespace Ui { class QmitkCmdLineModuleProgressWidget; } +namespace mitk { +class DataStorage; +} + /** * \class QmitkCmdLineModuleProgressWidget * \brief Based on ctkCmdLineModuleExplorerProgressWidget, implements a progress widget * with console output, and space for storing the GUI widget once the module is running. */ class QmitkCmdLineModuleProgressWidget : public QWidget { Q_OBJECT public: QmitkCmdLineModuleProgressWidget(QWidget *parent = 0); ~QmitkCmdLineModuleProgressWidget(); - void setFuture(const ctkCmdLineModuleFuture& future); - + void Run(ctkCmdLineModuleFrontend* moduleInstance); void setTitle(const QString& title); Q_SIGNALS: void clicked(); protected: void mouseReleaseEvent(QMouseEvent*); private Q_SLOTS: void on_PauseButton_toggled(bool toggled); void on_RemoveButton_clicked(); void checkModulePaused(); void moduleStarted(); void moduleCanceled(); void moduleFinished(); void moduleResumed(); void moduleProgressRangeChanged(int progressMin, int progressMax); void moduleProgressTextChanged(const QString& progressText); void moduleProgressValueChanged(int progressValue); private: - Ui::QmitkCmdLineModuleProgressWidget *m_UI; + /** + * \brief Used to write output to console widget, and qDebug(). + */ + void PublishMessage(const QString& message); + + /** + * \brief Destroys any images listed in m_TemporaryFileNames. + */ + void ClearUpTemporaryFiles(); + + /** + * \brief Loads any data listed in m_OutputDataToLoad into the mitk::DataStorage. + */ + void LoadOutputData(); + + + Ui::QmitkCmdLineModuleProgressWidget *m_UI; ctkCmdLineModuleFutureWatcher m_FutureWatcher; + ctkCmdLineModuleManager* m_ModuleManager; QTimer m_PollPauseTimer; - + mitk::DataStorage* m_DataStorage; + QString m_TemporaryDirectoryName; + + /** + * \brief We store a list of temporary file names that are saved to disk before + * launching a command line app, and then must be cleared up when the command line + * app successfully finishes. + */ + QStringList m_TemporaryFileNames; + + /** + * \brief We store a list of output images, so that on successfull completion of + * a command line module, we load the output data into the mitk::DataStorage. + */ + QStringList m_OutputDataToLoad; }; #endif // QMITKCMDLINEMODULEPROGRESSWIDGET_H diff --git a/Plugins/org.mitk.gui.qt.cli/src/QmitkCmdLineModuleProgressWidget.ui b/Plugins/org.mitk.gui.qt.cli/src/QmitkCmdLineModuleProgressWidget.ui index 8dead2619a..40de4d69ab 100644 --- a/Plugins/org.mitk.gui.qt.cli/src/QmitkCmdLineModuleProgressWidget.ui +++ b/Plugins/org.mitk.gui.qt.cli/src/QmitkCmdLineModuleProgressWidget.ui @@ -1,132 +1,134 @@ QmitkCmdLineModuleProgressWidget 0 0 - 533 - 288 + 586 + 388 Form 0 0 TextLabel 0 ... :/CommandLineModulesResources/pause.png:/CommandLineModulesResources/pause.png true true ... :/CommandLineModulesResources/stop.png:/CommandLineModulesResources/stop.png true Remove true 0 0 Parameters Console + + + + + Qt::Vertical - - QSizePolicy::Expanding - 20 - 4 + 30 ctkCollapsibleGroupBox QGroupBox
ctkCollapsibleGroupBox.h
1
diff --git a/Plugins/org.mitk.gui.qt.cli/src/internal/CommandLineModulesView.cpp b/Plugins/org.mitk.gui.qt.cli/src/internal/CommandLineModulesView.cpp index 85574ff929..dbdb58b26e 100644 --- a/Plugins/org.mitk.gui.qt.cli/src/internal/CommandLineModulesView.cpp +++ b/Plugins/org.mitk.gui.qt.cli/src/internal/CommandLineModulesView.cpp @@ -1,742 +1,380 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) University College London (UCL). 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. ===================================================================*/ // Blueberry #include #include #include // Qmitk #include "CommandLineModulesView.h" #include "CommandLineModulesViewConstants.h" #include "CommandLineModulesViewControls.h" #include "CommandLineModulesPreferencesPage.h" #include "QmitkCmdLineModuleFactoryGui.h" -#include "QmitkDataStorageComboBox.h" -#include "QmitkCommonFunctionality.h" -#include "QmitkCustomVariants.h" // Qt -#include -#include #include +#include +#include #include #include -#include // CTK #include #include #include #include #include -#include -#include -#include #include -#include - -// MITK -#include +#include //----------------------------------------------------------------------------- CommandLineModulesView::CommandLineModulesView() : m_Controls(NULL) , m_Parent(NULL) , m_ModuleManager(NULL) , m_ModuleBackend(NULL) , m_ModuleFactory(NULL) , m_DirectoryWatcher(NULL) -, m_Watcher(NULL) , m_TemporaryDirectoryName("") , m_DebugOutput(false) { - qRegisterMetaType(); - qRegisterMetaType(); } //----------------------------------------------------------------------------- CommandLineModulesView::~CommandLineModulesView() { if (m_ModuleManager != NULL) { delete m_ModuleManager; } if (m_ModuleBackend != NULL) { delete m_ModuleBackend; } if (m_ModuleFactory != NULL) { delete m_ModuleFactory; } if (m_DirectoryWatcher != NULL) { delete m_DirectoryWatcher; } - - if (m_Watcher != NULL) - { - delete m_Watcher; - } - - this->ClearUpTemporaryFiles(); } //----------------------------------------------------------------------------- void CommandLineModulesView::SetFocus() { this->m_Controls->m_ComboBox->setFocus(); } //----------------------------------------------------------------------------- void CommandLineModulesView::CreateQtPartControl( QWidget *parent ) { if (!m_Controls) { m_MapTabToModuleInstance.clear(); - m_TemporaryFileNames.clear(); // We create CommandLineModulesViewControls, which derives from the Qt generated class. m_Controls = new CommandLineModulesViewControls(parent); // This must be done independent of other preferences, as we need it before // we create the ctkCmdLineModuleManager to initialise the Cache. this->RetrieveAndStoreTemporaryDirectoryPreferenceValues(); // Create the command line module infrastructure. m_ModuleBackend = new ctkCmdLineModuleBackendLocalProcess(); m_ModuleFactory = new QmitkCmdLineModuleFactoryGui(this->GetDataStorage()); m_ModuleManager = new ctkCmdLineModuleManager(ctkCmdLineModuleManager::STRICT_VALIDATION, m_TemporaryDirectoryName); m_Controls->m_ComboBox->SetManager(m_ModuleManager); m_DirectoryWatcher = new ctkCmdLineModuleDirectoryWatcher(m_ModuleManager); m_ModuleManager->registerBackend(m_ModuleBackend); + // Setup the remaining preferences. this->RetrieveAndStorePreferenceValues(); // Connect signals to slots after we have set up GUI. connect(this->m_Controls->m_RunButton, SIGNAL(pressed()), this, SLOT(OnRunPauseButtonPressed())); connect(this->m_Controls->m_RestoreDefaults, SIGNAL(pressed()), this, SLOT(OnRestoreButtonPressed())); connect(this->m_Controls->m_ComboBox, SIGNAL(actionChanged(QAction*)), this, SLOT(OnActionChanged(QAction*))); } } //----------------------------------------------------------------------------- berry::IBerryPreferences::Pointer CommandLineModulesView::RetrievePreferences() { berry::IPreferencesService::Pointer prefService = berry::Platform::GetServiceRegistry() .GetServiceById(berry::IPreferencesService::ID); assert( prefService ); std::string id = "/" + CommandLineModulesViewConstants::VIEW_ID; berry::IBerryPreferences::Pointer prefs = (prefService->GetSystemPreferences()->Node(id)) .Cast(); assert( prefs ); return prefs; } //----------------------------------------------------------------------------- void CommandLineModulesView::RetrieveAndStoreTemporaryDirectoryPreferenceValues() { berry::IBerryPreferences::Pointer prefs = this->RetrievePreferences(); QString fallbackTmpDir = QDir::tempPath(); m_TemporaryDirectoryName = QString::fromStdString( prefs->Get(CommandLineModulesViewConstants::TEMPORARY_DIRECTORY_NODE_NAME, fallbackTmpDir.toStdString())); } //----------------------------------------------------------------------------- void CommandLineModulesView::RetrieveAndStorePreferenceValues() { berry::IBerryPreferences::Pointer prefs = this->RetrievePreferences(); // Get the flag for debug output, useful when parsing all the XML. m_DebugOutput = prefs->GetBool(CommandLineModulesViewConstants::DEBUG_OUTPUT_NODE_NAME, false); m_DirectoryWatcher->setDebug(m_DebugOutput); bool loadApplicationDir = prefs->GetBool(CommandLineModulesViewConstants::LOAD_FROM_APPLICATION_DIR, false); bool loadHomeDir = prefs->GetBool(CommandLineModulesViewConstants::LOAD_FROM_HOME_DIR, false); bool loadCurrentDir = prefs->GetBool(CommandLineModulesViewConstants::LOAD_FROM_CURRENT_DIR, false); bool loadAutoLoadDir = prefs->GetBool(CommandLineModulesViewConstants::LOAD_FROM_AUTO_LOAD_DIR, false); // Get some default application paths. // Here we can use the preferences to set up the builder, ctkCmdLineModuleDefaultPathBuilder builder; builder.setLoadFromApplicationDir(loadApplicationDir); builder.setLoadFromHomeDir(loadHomeDir); builder.setLoadFromCurrentDir(loadCurrentDir); builder.setLoadFromCtkModuleLoadPath(loadAutoLoadDir); // and then we ask the builder to set up the paths. QStringList defaultPaths = builder.build(); // We get additional directory paths from preferences. QString pathString = QString::fromStdString(prefs->Get(CommandLineModulesViewConstants::MODULE_DIRECTORIES_NODE_NAME, "")); QStringList additionalPaths = pathString.split(";", QString::SkipEmptyParts); // Combine the sets of directory paths. QStringList totalPaths; totalPaths << defaultPaths; totalPaths << additionalPaths; QString additionalModulesString = QString::fromStdString(prefs->Get(CommandLineModulesViewConstants::MODULE_FILES_NODE_NAME, "")); QStringList additionalModules = additionalModulesString.split(";", QString::SkipEmptyParts); // OnPreferencesChanged can be called for each preference in a dialog box, so // when you hit "OK", it is called repeatedly, whereas we want to only call these only once. if (this->m_DirectoryWatcher->directories() != totalPaths) { m_DirectoryWatcher->setDirectories(totalPaths); } if (this->m_DirectoryWatcher->additionalModules() != additionalModules) { m_DirectoryWatcher->setAdditionalModules(additionalModules); } } //----------------------------------------------------------------------------- void CommandLineModulesView::OnPreferencesChanged(const berry::IBerryPreferences* /*prefs*/) { this->RetrieveAndStoreTemporaryDirectoryPreferenceValues(); this->RetrieveAndStorePreferenceValues(); } //----------------------------------------------------------------------------- void CommandLineModulesView::AddModuleTab(const ctkCmdLineModuleReference& moduleRef) { // We don't want to repeatedly create new tabs. If the moduleRef points to // an existing tab, make that tab the current tab. for (int i = 0; i < m_Controls->m_TabWidget->count(); i++) { if (m_Controls->m_TabWidget->tabText(i) == moduleRef.description().title()) { m_Controls->m_TabWidget->setCurrentIndex(i); return; } } // Otherwise, create a new tab. ctkCmdLineModuleFrontend* moduleInstance = m_ModuleFactory->create(moduleRef); if (!moduleInstance) return; // Build up the GUI layout programmatically (manually). QTabWidget *documentationTabWidget = new QTabWidget(); documentationTabWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); QWidget *aboutWidget = new QWidget(); QWidget *helpWidget = new QWidget(); QTextBrowser *aboutBrowser = new QTextBrowser(aboutWidget); aboutBrowser->setReadOnly(true); aboutBrowser->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); QTextBrowser *helpBrowser = new QTextBrowser(helpWidget); helpBrowser->setReadOnly(true); helpBrowser->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); QHBoxLayout *aboutLayout = new QHBoxLayout(aboutWidget); aboutLayout->addWidget(aboutBrowser); aboutLayout->setContentsMargins(0,0,0,0); aboutLayout->setSpacing(0); QHBoxLayout *helpLayout = new QHBoxLayout(helpWidget); helpLayout->addWidget(helpBrowser); helpLayout->setContentsMargins(0,0,0,0); helpLayout->setSpacing(0); documentationTabWidget->addTab(aboutWidget, "About"); documentationTabWidget->addTab(helpWidget, "Help"); QObject* guiHandle = moduleInstance->guiHandle(); QWidget* generatedGuiWidgets = qobject_cast(guiHandle); QWidget *topLevelWidget = new QWidget(); QGridLayout *topLevelLayout = new QGridLayout(topLevelWidget); topLevelLayout->setContentsMargins(0,0,0,0); topLevelLayout->setSpacing(0); topLevelLayout->addWidget(documentationTabWidget, 0, 0); topLevelLayout->setRowStretch(0, 1); topLevelLayout->addWidget(generatedGuiWidgets, 1, 0); topLevelLayout->setRowStretch(1, 10); ctkCmdLineModuleDescription description = moduleRef.description(); QString helpString = ""; if (!description.title().isEmpty()) { QString titleHtml = "

" + description.title() + "

"; helpString += titleHtml; } if (!description.description().isEmpty()) { QString descriptionHtml = "

" + description.description() + "

"; helpString += descriptionHtml; } if (!description.documentationURL().isEmpty()) { QString docUrlHtml = "

For more information please see the online documentation.

"; helpString += docUrlHtml; } QString aboutString = ""; if (!description.title().isEmpty()) { QString titleHtml = "

" + description.title() + "

"; aboutString += titleHtml; } if (!description.contributor().isEmpty()) { QString contributorHtml = "

Contributed By

" + description.contributor() + "

"; aboutString += contributorHtml; } if (!description.license().isEmpty()) { QString licenseHtml = "

License

" + description.license() + "

"; aboutString += licenseHtml; } if (!description.acknowledgements().isEmpty()) { QString acknowledgementsHtml = "

Acknowledgements

" + description.acknowledgements() + "

"; aboutString += acknowledgementsHtml; } helpBrowser->clear(); helpBrowser->setHtml(helpString); aboutBrowser->clear(); aboutBrowser->setHtml(aboutString); int tabIndex = m_Controls->m_TabWidget->addTab(topLevelWidget, moduleRef.description().title()); m_Controls->m_TabWidget->setCurrentIndex(tabIndex); m_MapTabToModuleInstance[tabIndex] = moduleInstance; } //----------------------------------------------------------------------------- ctkCmdLineModuleReference CommandLineModulesView::GetReferenceByIdentifier(QString identifier) { ctkCmdLineModuleReference result; QList references = this->m_ModuleManager->moduleReferences(); ctkCmdLineModuleReference ref; foreach(ref, references) { if (ref.description().title() == identifier) { result = ref; } } return result; } -//----------------------------------------------------------------------------- -void CommandLineModulesView::OnRunPauseButtonPressed() -{ - this->ProcessInstruction(RunPauseButton); -} - - -//----------------------------------------------------------------------------- -void CommandLineModulesView::OnStopButtonPressed() -{ - this->ProcessInstruction(StopButton); -} - - //----------------------------------------------------------------------------- void CommandLineModulesView::OnRestoreButtonPressed() { - QString message = "restoring defaults."; - this->PublishMessage(message); - ctkCmdLineModuleFrontend* moduleInstance = m_MapTabToModuleInstance[m_Controls->m_TabWidget->currentIndex()]; if (!moduleInstance) { qWarning() << "Invalid module instance"; return; } moduleInstance->resetValues(); - - message = "restored defaults."; - this->PublishMessage(message); } //----------------------------------------------------------------------------- void CommandLineModulesView::OnActionChanged(QAction* action) { ctkCmdLineModuleReference ref = this->GetReferenceByIdentifier(action->text()); if (ref) { this->AddModuleTab(ref); } } -//----------------------------------------------------------------------------- -void CommandLineModulesView::ProcessInstruction(const ProcessingInstruction& instruction) -{ - // This code places one method between OnRunButtonPressed and - // OnStopButtonPressed, and is responsible for calling - // OnRun, OnStop, OnPause, OnResume, and so could be refactored - // into a separate class for ease of unit testing. - - if (instruction == RunPauseButton) - { - if (m_Watcher == NULL) - { - // Never been run before ... so just run it. - this->Run(); - } - else - { - if (m_Watcher->isCanceled()) - { - this->Run(); - } - else if (m_Watcher->isFinished()) - { - this->Run(); - } - else if (m_Watcher->isPaused()) - { - this->Resume(); - } - else if (m_Watcher->isRunning()) - { - this->Pause(); - } - else if (m_Watcher->isStarted()) - { - this->Pause(); - } - } - } - else if (instruction == StopButton) - { - if (m_Watcher != NULL) - { - if (m_Watcher->isPaused()) - { - this->Resume(); - this->Stop(); - } - else if (m_Watcher->isRunning()) - { - this->Stop(); - } - else if (m_Watcher->isStarted()) - { - this->Stop(); - } - } - } -} - - -//----------------------------------------------------------------------------- -void CommandLineModulesView::Run() -{ - // Get hold of the command line module. - ctkCmdLineModuleFrontend* moduleInstance = m_MapTabToModuleInstance[m_Controls->m_TabWidget->currentIndex()]; - if (!moduleInstance) - { - qWarning() << "Invalid module instance"; - return; - } - - m_OutputDataToLoad.clear(); - ctkCmdLineModuleReference reference = moduleInstance->moduleReference(); - ctkCmdLineModuleDescription description = reference.description(); - - QString message = "Saving image data to temporary storage..."; - this->PublishMessage(message); - - // Sanity check we have actually specified some input: - QString parameterName; - QList parameters; - - // For each input image, write a temporary file as a Nifti image, - // and then save the full path name back on the parameter. - parameters = moduleInstance->parameters("image", ctkCmdLineModuleFrontend::Input); - foreach (ctkCmdLineModuleParameter parameter, parameters) - { - parameterName = parameter.name(); - - QVariant tmp = moduleInstance->value(parameterName, ctkCmdLineModuleFrontend::UserRole); - mitk::DataNode::Pointer node = tmp.value(); - - if (node.IsNotNull()) - { - mitk::Image* image = dynamic_cast(node->GetData()); - if (image != NULL) - { - QString name = QString::fromStdString(node->GetName()); - int pid = QCoreApplication::applicationPid(); - int randomInt = qrand() % 1000000; - - QString fileName = m_TemporaryDirectoryName + "/" + name + QString::number(pid) + "." + QString::number(randomInt) + ".nii"; - - message = "Saving " + fileName; - this->PublishMessage(message); - - std::string tmpFN = CommonFunctionality::SaveImage(image, fileName.toStdString().c_str()); - QString temporaryStorageFileName = QString::fromStdString(tmpFN); - - m_TemporaryFileNames.push_back(temporaryStorageFileName); - moduleInstance->setValue(parameterName, temporaryStorageFileName); - - message = "Saved " + temporaryStorageFileName; - this->PublishMessage(message); - } // end if image - } // end if node - } // end foreach input image - - // For each output image or file, store the filename, so we can auto-load it once the process finishes. - parameters = moduleInstance->parameters("image", ctkCmdLineModuleFrontend::Output); - parameters << moduleInstance->parameters("file", ctkCmdLineModuleFrontend::Output); - foreach (ctkCmdLineModuleParameter parameter, parameters) - { - parameterName = parameter.name(); - QString outputFileName = moduleInstance->value(parameterName).toString(); - - if (!outputFileName.isEmpty()) - { - m_OutputDataToLoad.push_back(outputFileName); - - message = "Command Line Module ... Registered " + outputFileName + " to auto load upon completion."; - this->PublishMessage(message); - } - } - - // Now we run stuff. - message = "starting."; - this->PublishMessage(message); - - if (m_Watcher != NULL) - { - QObject::disconnect(m_Watcher, 0, 0, 0); - delete m_Watcher; - } - - m_Watcher = new ctkCmdLineModuleFutureWatcher(); - QObject::connect(m_Watcher, SIGNAL(started()), this, SLOT(OnModuleStarted())); - QObject::connect(m_Watcher, SIGNAL(finished()), this, SLOT(OnModuleFinished())); - QObject::connect(m_Watcher, SIGNAL(progressValueChanged(int)), this, SLOT(OnModuleProgressValueChanged(int))); - QObject::connect(m_Watcher, SIGNAL(progressTextChanged(QString)), this, SLOT(OnModuleProgressTextChanged(QString))); - QObject::connect(m_Watcher, SIGNAL(outputDataReady()), this, SLOT(OnModuleOutputDataReady())); - QObject::connect(m_Watcher, SIGNAL(errorDataReady()), this, SLOT(OnModuleErrorDataReady())); - - ctkCmdLineModuleFuture future = m_ModuleManager->run(moduleInstance); - m_Watcher->setFuture(future); - m_Controls->Running(); -} - - -//----------------------------------------------------------------------------- -void CommandLineModulesView::Stop() -{ - QString message = "stopping."; - this->PublishMessage(message); - - this->ClearUpTemporaryFiles(); - m_TemporaryFileNames.clear(); - m_OutputDataToLoad.clear(); - - m_Watcher->cancel(); - m_Watcher->waitForFinished(); - m_Controls->Cancel(); - - message = "stopped."; - this->PublishMessage(message); -} - - -//----------------------------------------------------------------------------- -void CommandLineModulesView::Pause() -{ - QString message = "pausing."; - this->PublishMessage(message); - - m_Watcher->pause(); - m_Controls->Pause(); - - message = "paused."; - this->PublishMessage(message); -} - - -//----------------------------------------------------------------------------- -void CommandLineModulesView::Resume() -{ - QString message = "resuming."; - this->PublishMessage(message); - - m_Watcher->resume(); - m_Controls->Resume(); - - message = "resumed."; - this->PublishMessage(message); -} - - -//----------------------------------------------------------------------------- -void CommandLineModulesView::ClearUpTemporaryFiles() -{ - QString message; - QString fileName; - - foreach (fileName, m_TemporaryFileNames) - { - QFile file(fileName); - if (file.exists()) - { - message = QObject::tr("removing %1").arg(fileName); - this->PublishMessage(message); - - bool success = file.remove(); - - message = QObject::tr("removed %1, successfully=%2").arg(fileName).arg(success); - this->PublishMessage(message); - } - } -} - - -//----------------------------------------------------------------------------- -void CommandLineModulesView::LoadOutputData() -{ - std::vector fileNames; - - QString fileName; - foreach (fileName, m_OutputDataToLoad) - { - QString message = QObject::tr("loading %1").arg(fileName); - this->PublishMessage(message); - - fileNames.push_back(fileName.toStdString()); - } - - if (fileNames.size() > 0) - { - mitk::DataStorage::Pointer dataStorage = this->GetDataStorage(); - int numberLoaded = mitk::IOUtil::LoadFiles(fileNames, *(dataStorage.GetPointer())); - - QString message = QObject::tr("loaded %1 files").arg(numberLoaded); - this->PublishMessage(message); - } -} - - -//----------------------------------------------------------------------------- -void CommandLineModulesView::PublishMessage(const QString& message) -{ - QString prefix = "Command Line Module ... "; - qDebug() << prefix << message; -} - - -//----------------------------------------------------------------------------- -void CommandLineModulesView::OnModuleStarted() -{ - QString message = "started."; - this->PublishMessage(message); -} - - -//----------------------------------------------------------------------------- -void CommandLineModulesView::OnModuleProgressValueChanged(int value) -{ - QString message = QObject::tr("OnModuleProgressValueChanged int=%1.").arg(value); - this->PublishMessage(message); -} - - -//----------------------------------------------------------------------------- -void CommandLineModulesView::OnModuleProgressTextChanged(QString value) -{ - QString message = QObject::tr("OnModuleProgressValueChanged QString=%1.").arg(value); - this->PublishMessage(message); -} - - -//----------------------------------------------------------------------------- -void CommandLineModulesView::OnModuleFinished() -{ - QString message = "finishing."; - this->PublishMessage(message); - - this->LoadOutputData(); - this->ClearUpTemporaryFiles(); - - m_Controls->Finished(); - - message = "finished."; - this->PublishMessage(message); -} - - -//----------------------------------------------------------------------------- -void CommandLineModulesView::OnModuleOutputDataReady() -{ - QByteArray bytes = m_Watcher->readPendingOutputData(); - QString standardOutput(bytes.data()); - QString message = "OUTPUT:" + standardOutput; - this->PublishMessage(message); -} - - - -//----------------------------------------------------------------------------- -void CommandLineModulesView::OnModuleErrorDataReady() -{ - QByteArray bytes = m_Watcher->readPendingErrorData(); - QString standardError(bytes.data()); - QString message = "ERROR:" + standardError; - this->PublishMessage(message); -} diff --git a/Plugins/org.mitk.gui.qt.cli/src/internal/CommandLineModulesView.h b/Plugins/org.mitk.gui.qt.cli/src/internal/CommandLineModulesView.h index d048f587b2..c62144076a 100644 --- a/Plugins/org.mitk.gui.qt.cli/src/internal/CommandLineModulesView.h +++ b/Plugins/org.mitk.gui.qt.cli/src/internal/CommandLineModulesView.h @@ -1,289 +1,174 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) University College London (UCL). 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 CommandLineModulesView_h #define CommandLineModulesView_h #include #include #include #include #include #include class QmitkCmdLineModuleFactoryGui; class ctkCmdLineModuleManager; class ctkCmdLineModuleFrontend; class ctkCmdLineModuleBackendLocalProcess; class ctkCmdLineModuleDirectoryWatcher; class ctkCmdLineModuleFutureWatcher; class CommandLineModulesViewControls; class QAction; namespace berry { class IBerryPreferences; } /*! * \class CommandLineModulesView * \brief Provides basic GUI interface to the CTK command line modules. * \author Matt Clarkson (m.clarkson@ucl.ac.uk) * \ingroup org_mitk_gui_qt_cli_internal - * - * This class is a basic interface to the CTK command line modules library. - * Ideally, an MITK base application would load command line modules dynamically - * at runtime, and promote them to the main window menu bar to appear as fully - * fledged Views. However, currently this is not supported, and so this view - * provides a simplified interface, contained within one plugin in order to - * facilitate testing, debugging, and understanding of use-cases. - * * \sa QmitkAbstractView */ class CommandLineModulesView : public QmitkAbstractView { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: CommandLineModulesView(); virtual ~CommandLineModulesView(); /** * \brief Main method, called by framework to create the GUI at the right time. * \param parent The parent QWidget, as this class itself is not a QWidget subclass. */ virtual void CreateQtPartControl(QWidget *parent); /** * \brief Called by the framework to indicate that the preferences have changed. * \param prefs not used, as we call RetrievePreferenceValues(). */ void OnPreferencesChanged(const berry::IBerryPreferences* prefs); protected Q_SLOTS: /** * \brief Called when the ctkMenuComboBox has the menu selection changed, * meaning that a new GUI page be created in another tab. */ void OnActionChanged(QAction*); /** - * \brief Slot that is called when the Run button is pressed. - */ - void OnRunPauseButtonPressed(); - - /** - * \brief Slot that is called when the Stop button is pressed. - */ - void OnStopButtonPressed(); - - /** - * \brief Slot that is called when the restore defaults button is pressed. + * \brief Slot that is called when the restore defaults button is pressed, + * to reset the current GUI form to the default values. */ void OnRestoreButtonPressed(); - /** - * \brief Slot called from ctkCmdLineModuleFutureWatcher when the module has been launched. - */ - void OnModuleStarted(); - - /** - * \brief Slot called from ctkCmdLineModuleFutureWatcher when the module has finished. - */ - void OnModuleFinished(); - - /** - * \brief Slot called from ctkCmdLineModuleFutureWatcher to notify of any progress, - * currently just printing console debug messages. - */ - void OnModuleProgressValueChanged(int); - - /** - * \brief Slot called from ctkCmdLineModuleFutureWatcher to notify of any progress, - * currently just printing console debug messages. - */ - void OnModuleProgressTextChanged(QString); - - /** - * \brief Slot called from ctkCmdLineModuleFutureWatcher to notify of any standard - * output progress information. - */ - void OnModuleOutputDataReady(); - - /** - * \brief Slot called from ctkCmdLineModuleFutureWatcher to notify of any standard - * error progress information. - */ - void OnModuleErrorDataReady(); - protected: /** * \brief Called by framework to set the focus on the right widget * when this view has focus, so currently, thats the combo box. */ virtual void SetFocus(); private: - enum ProcessingInstruction { - RunPauseButton, - StopButton - }; - /** - * \brief Called on startup and by OnPreferencesChanged to load the preferences into member variables. - * - * Does not do the temporary folder. + * \brief Called on startup and by OnPreferencesChanged to load all + * preferences except the temporary folder into member variables. */ void RetrieveAndStorePreferenceValues(); /** - * \brief Called on startup and by OnPreferencesChanged to load the temporary folder preference into member variables. + * \brief Called on startup and by OnPreferencesChanged to load the temporary folder + * preference into member variable m_TemporaryDirectoryName. */ void RetrieveAndStoreTemporaryDirectoryPreferenceValues(); /** - * \brief Called to get hold of the actual prefefences node. + * \brief Called to get hold of the actual preferences node. */ berry::IBerryPreferences::Pointer RetrievePreferences(); - /** - * \brief Used to write output to console. - */ - void PublishMessage(const QString& message); - /** * \brief Search the internal datastructure (QHash) to find the reference that matches the identifier. * \param identifier The identifier used in the front end combo box widget, currently title. * \return ctkCmdLineModuleReference the reference corresponding to the identifier, or an invalid reference if non found. */ ctkCmdLineModuleReference GetReferenceByIdentifier(QString identifier); /** * \brief Adds a module to the views tabbed widget, creating a new tab each time. * \param moduleRef A ctkCmdLineModuleReference. */ void AddModuleTab(const ctkCmdLineModuleReference& moduleRef); - /** - * \brief Destroys any images listed in m_TemporaryFileNames, silently failing. - */ - void ClearUpTemporaryFiles(); - - /** - * \brief Loads any data listed in m_OutputDataToLoad into the mitk::DataStorage. - */ - void LoadOutputData(); - - /** - * \brief Called by OnRunButtonPressed() and OnStopButtonPressed() to actually decide what to run. - */ - void ProcessInstruction(const ProcessingInstruction& instruction); - - /** - * \brief Slot to launch the command line module. - */ - void Run(); - - /** - * \brief Slot to stop (kill) the command line module. - */ - void Stop(); - - /** - * \brief Slot to pause the command line module. - */ - void Pause(); - - /** - * \brief Slot to resume the command line module. - */ - void Resume(); - /** * \brief The GUI controls contain a run/stop button, and a tabbed widget, and the GUI component * for each command line module is added to the tabbed widget dynamically at run time. */ CommandLineModulesViewControls *m_Controls; /** * \brief We store the parent, passed in via CommandLineModulesView::CreateQtPartControl, as this class itself is not a QWidget. */ QWidget *m_Parent; /** * \brief The manager is responsible for loading and instantiating command line modules. */ ctkCmdLineModuleManager *m_ModuleManager; /** * \brief We are using a back-end that runs locally installed command line programs. */ ctkCmdLineModuleBackendLocalProcess *m_ModuleBackend; /** * \brief The QmitkCmdLineModuleFactoryGui builds a gui for each plugin. */ QmitkCmdLineModuleFactoryGui *m_ModuleFactory; /** * \brief The ctkCmdLineModuleDirectoryWatcher maintains the list of directories * we are using to load modules, to provide automatic updates. */ ctkCmdLineModuleDirectoryWatcher *m_DirectoryWatcher; - /** - * \brief This is the QFutureWatcher that will watch for when the process has finished, and call OnFutureFinished() slot. - */ - ctkCmdLineModuleFutureWatcher* m_Watcher; - /** * \brief We use this map to decide if we want to create more tabs or not. */ QHash m_MapTabToModuleInstance; /** * \brief We store a temporary folder name, accessible via user preferences. */ QString m_TemporaryDirectoryName; - /** - * \brief We store a list of temporary file names that are saved to disk before - * launching a command line app, and then must be cleared up when the command line - * app successfully finishes. - */ - QStringList m_TemporaryFileNames; - - /** - * \brief We store a list of output images, so that on successfull completion of - * a command line module, we load the output data into the mitk::DataStorage. - */ - QStringList m_OutputDataToLoad; - /** * \brief Member variable, taken from preference page. */ bool m_DebugOutput; - }; #endif // CommandLineModulesView_h diff --git a/Plugins/org.mitk.gui.qt.cli/src/internal/CommandLineModulesViewControls.ui b/Plugins/org.mitk.gui.qt.cli/src/internal/CommandLineModulesViewControls.ui index 3b423ffbec..6a10289091 100644 --- a/Plugins/org.mitk.gui.qt.cli/src/internal/CommandLineModulesViewControls.ui +++ b/Plugins/org.mitk.gui.qt.cli/src/internal/CommandLineModulesViewControls.ui @@ -1,143 +1,134 @@ CommandLineModulesViewControls 0 0 678 582 0 0 QmitkTemplate 0 0 choose: 0 0 restore default parameters 0 0 run the command line module Qt::Horizontal 40 20 0 0 0 0 - - - 0 0 QmitkCmdLineModuleMenuComboBox QWidget
QmitkCmdLineModuleMenuComboBox.h
1
- - QmitkCmdLineModuleProgressWidget - QWidget -
QmitkCmdLineModuleProgressWidget.h
- 1 -