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 8e6667d096..1a50c00ca3 100644 --- a/Plugins/org.mitk.gui.qt.cli/src/internal/CommandLineModulesView.cpp +++ b/Plugins/org.mitk.gui.qt.cli/src/internal/CommandLineModulesView.cpp @@ -1,345 +1,390 @@ /*=================================================================== 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 "QmitkCmdLineModuleGui.h" #include "QmitkCmdLineModuleProgressWidget.h" // Qt #include #include #include #include #include #include +#include // CTK #include #include #include #include #include #include #include //----------------------------------------------------------------------------- CommandLineModulesView::CommandLineModulesView() : m_Controls(NULL) , m_Parent(NULL) , m_Layout(NULL) , m_ModuleManager(NULL) , m_ModuleBackend(NULL) , m_DirectoryWatcher(NULL) , m_TemporaryDirectoryName("") , m_DebugOutput(false) { } //----------------------------------------------------------------------------- CommandLineModulesView::~CommandLineModulesView() { if (m_ModuleManager != NULL) { delete m_ModuleManager; } if (m_ModuleBackend != NULL) { delete m_ModuleBackend; } if (m_DirectoryWatcher != NULL) { delete m_DirectoryWatcher; } if (m_Layout != NULL) { delete m_Layout; } + + for (int i = 0; i < m_ListOfModules.size(); i++) + { + delete m_ListOfModules[i]; + } } //----------------------------------------------------------------------------- void CommandLineModulesView::SetFocus() { this->m_Controls->m_ComboBox->setFocus(); } //----------------------------------------------------------------------------- void CommandLineModulesView::CreateQtPartControl( QWidget *parent ) { m_Parent = parent; if (!m_Controls) { // We create CommandLineModulesViewControls, which derives from the Qt generated class. m_Controls = new CommandLineModulesViewControls(parent); // Create a layout to contain a display of QmitkCmdLineModuleProgressWidget. - m_Layout = new QVBoxLayout(m_Controls->m_GeneratedGuiWidget); + m_Layout = new QVBoxLayout(m_Controls->m_RunningWidgets); m_Layout->setContentsMargins(0,0,0,0); m_Layout->setSpacing(0); // This must be done independent of other preferences, as we need it before // we create the ctkCmdLineModuleManager to initialise the Cache. this->RetrieveAndStoreTemporaryDirectoryPreferenceValues(); this->RetrieveAndStoreValidationMode(); - qDebug() << "CommandLineModulesView: Creating ctkCmdLineModuleManager with mode=" << m_ValidationMode << ", temp directory=" << m_TemporaryDirectoryName; - // Start to create the command line module infrastructure. m_ModuleBackend = new ctkCmdLineModuleBackendLocalProcess(); m_ModuleManager = new ctkCmdLineModuleManager(m_ValidationMode, m_TemporaryDirectoryName); // Set the main object, the ctkCmdLineModuleManager onto all the objects that need it. 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(OnRunButtonPressed())); connect(this->m_Controls->m_RestoreDefaults, SIGNAL(pressed()), this, SLOT(OnRestoreButtonPressed())); connect(this->m_Controls->m_ComboBox, SIGNAL(actionChanged(QAction*)), this, SLOT(OnActionChanged(QAction*))); + connect(this->m_Controls->m_TabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(OnTabCloseRequested(int))); } } //----------------------------------------------------------------------------- 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::RetrieveAndStoreValidationMode() { berry::IBerryPreferences::Pointer prefs = this->RetrievePreferences(); int value = prefs->GetInt(CommandLineModulesViewConstants::XML_VALIDATION_MODE, 0); if (value == 0) { m_ValidationMode = ctkCmdLineModuleManager::STRICT_VALIDATION; } else if (value == 1) { m_ValidationMode = ctkCmdLineModuleManager::SKIP_VALIDATION; } else { m_ValidationMode = ctkCmdLineModuleManager::WEAK_VALIDATION; } } //----------------------------------------------------------------------------- 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->RetrieveAndStoreValidationMode(); this->RetrieveAndStorePreferenceValues(); } //----------------------------------------------------------------------------- ctkCmdLineModuleReference CommandLineModulesView::GetReferenceByFullName(QString fullName) { ctkCmdLineModuleReference result; QList references = this->m_ModuleManager->moduleReferences(); ctkCmdLineModuleReference ref; foreach(ref, references) { - QString name = ref.description().category() + "." + ref.description().title(); + QString name = ref.description().categoryDotTitle(); if (name == fullName) { result = ref; } } return result; } //----------------------------------------------------------------------------- -QmitkCmdLineModuleProgressWidget* CommandLineModulesView::GetWidget(const int& indexNumber) +void CommandLineModulesView::OnActionChanged(QAction* action) { - QmitkCmdLineModuleProgressWidget *result = NULL; + QString fullName = action->objectName(); + ctkCmdLineModuleReference ref = this->GetReferenceByFullName(fullName); - QLayoutItem *layoutItem = m_Layout->itemAt(indexNumber); - if (layoutItem != NULL) + // ref should never be invalid, as the menu was generated from each ctkCmdLineModuleReference. + // But just to be sure ... if invalid, don't do anything. + if (ref) { - QWidgetItem *widgetItem = dynamic_cast(layoutItem); - if (widgetItem != NULL) + // Check if we already have the reference. + int tabIndex = -1; + for (int i = 0; i < m_ListOfModules.size(); i++) { - result = dynamic_cast(widgetItem->widget()); + ctkCmdLineModuleReference tabsReference = m_ListOfModules[i]->moduleReference(); + if (ref.location() == tabsReference.location()) + { + tabIndex = i; + break; + } } - } - return result; + // i.e. we found a matching tab, so just switch to it. + if (tabIndex != -1) + { + m_Controls->m_TabWidget->setCurrentIndex(tabIndex); + } + else // i.e. we did not find a matching tab + { + // In this case, we need to create a new tab, and give + // it a GUI for the user to setup the parameters with. + QmitkCmdLineModuleFactoryGui factory(this->GetDataStorage()); + ctkCmdLineModuleFrontend *frontEnd = factory.create(ref); + QmitkCmdLineModuleGui *theGui = dynamic_cast(frontEnd); + + // Add to list and tab wigdget + m_ListOfModules.push_back(frontEnd); + m_Controls->m_TabWidget->addTab(theGui->getGui(), ref.description().title()); + } + } } //----------------------------------------------------------------------------- -void CommandLineModulesView::OnActionChanged(QAction* action) +void CommandLineModulesView::OnTabCloseRequested(int tabNumber) { - QString fullName = action->objectName(); - ctkCmdLineModuleReference ref = this->GetReferenceByFullName(fullName); - if (ref) - { - QmitkCmdLineModuleProgressWidget *widget = this->GetWidget(0); - if (widget == NULL - || widget->IsStarted()) - { - // Create new widget. - QmitkCmdLineModuleProgressWidget* newWidget = new QmitkCmdLineModuleProgressWidget(m_Controls->m_GeneratedGuiWidget); + ctkCmdLineModuleFrontend *frontEnd = m_ListOfModules[tabNumber]; - // Configure new widget. - newWidget->SetTemporaryDirectory(this->m_TemporaryDirectoryName); - newWidget->SetDataStorage(this->GetDataStorage()); - newWidget->SetManager(this->m_ModuleManager); - newWidget->SetModule(ref); + m_Controls->m_TabWidget->removeTab(tabNumber); + m_ListOfModules.removeAt(tabNumber); - // Add new widget to the top (nearest top of screen) of layout. - m_Layout->insertWidget(0, newWidget); - } - else - { - // If the first widget has not even started, we can simply replace the GUI, - // with the correct GUI for the newly selected command line module. + delete frontEnd; +} - // Note: At the moment, I'm getting 3 signals instead of 1 ??? - if (widget->GetFullName() != fullName) - { - widget->SetModule(ref); - } - } - } + +//----------------------------------------------------------------------------- +void CommandLineModulesView::AskUserToSelectAModule() const +{ + QMessageBox msgBox; + msgBox.setText("Please select a module!"); + msgBox.setIcon(QMessageBox::Warning); + msgBox.exec(); } //----------------------------------------------------------------------------- void CommandLineModulesView::OnRestoreButtonPressed() { - QmitkCmdLineModuleProgressWidget *widget = this->GetWidget(0); - if (widget != NULL && !widget->IsStarted()) + int tabNumber = m_Controls->m_TabWidget->currentIndex(); + if (tabNumber >= 0) { - widget->Reset(); + ctkCmdLineModuleFrontend *frontEnd = m_ListOfModules[tabNumber]; + frontEnd->resetValues(); + } + else + { + this->AskUserToSelectAModule(); } } //----------------------------------------------------------------------------- void CommandLineModulesView::OnRunButtonPressed() { - QmitkCmdLineModuleProgressWidget *widget = this->GetWidget(0); - if (widget != NULL && !widget->IsStarted()) + int tabNumber = m_Controls->m_TabWidget->currentIndex(); + if (tabNumber >= 0) { + // 1. Create a new QmitkCmdLineModuleProgressWidget to represent the running widget. + QmitkCmdLineModuleProgressWidget *widget = new QmitkCmdLineModuleProgressWidget(m_Controls->m_RunningWidgets); + widget->SetDataStorage(this->GetDataStorage()); + widget->SetManager(m_ModuleManager); + widget->SetTemporaryDirectory(m_TemporaryDirectoryName); + + // 2. Create a new front end. + QmitkCmdLineModuleFactoryGui factory(this->GetDataStorage()); + + ctkCmdLineModuleFrontend *frontEndOnCurrentTab = m_ListOfModules[tabNumber]; + QmitkCmdLineModuleGui *frontEndGuiOnCurrentTab = dynamic_cast(frontEndOnCurrentTab); + ctkCmdLineModuleReference currentTabFrontendReferences = frontEndGuiOnCurrentTab->moduleReference(); + + ctkCmdLineModuleFrontend *newFrontEnd = factory.create(currentTabFrontendReferences); + QmitkCmdLineModuleGui *newFrontEndGui = dynamic_cast(newFrontEnd); + widget->SetFrontend(newFrontEndGui); + m_Layout->insertWidget(0, widget); + + // 3. Copy parameters. This MUST come after widget->SetFrontEnd + newFrontEndGui->copyParameters(*frontEndGuiOnCurrentTab); + + // 4. GO. widget->Run(); } + else + { + this->AskUserToSelectAModule(); + } } 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 bdb38caa2c..e01f9340e3 100644 --- a/Plugins/org.mitk.gui.qt.cli/src/internal/CommandLineModulesView.h +++ b/Plugins/org.mitk.gui.qt.cli/src/internal/CommandLineModulesView.h @@ -1,185 +1,195 @@ /*=================================================================== 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 #include class ctkCmdLineModuleBackendLocalProcess; class ctkCmdLineModuleDirectoryWatcher; class CommandLineModulesViewControls; class QmitkCmdLineModuleProgressWidget; class QAction; class QVBoxLayout; 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 * \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, * and causes the corresponding GUI to be displayed. */ void OnActionChanged(QAction*); /** * \brief Slot that is called when the restore defaults button is pressed, - * to reset the current GUI form to the default values, if the XML specifies them. + * to reset the current GUI form to the default values, if the XML specifies defaults. */ void OnRestoreButtonPressed(); /** - * \brief Slot that is called when the Run button (green arrow) is pressed, - * to run the current module. + * \brief Slot that is called when the Run button is pressed to run the current module. */ void OnRunButtonPressed(); protected: /** * \brief Called by framework to set the focus on the right widget - * when this view has focus, so currently, thats the combo box. + * when this view has focus, so currently, thats the ctkMenuCombo box. */ virtual void SetFocus(); +private slots: + + /** + * \brief Called when the user clicks to close a tab, and removes the front end from m_ListOfModules + */ + void OnTabCloseRequested(int tabNumber); + private: /** * \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 variable m_TemporaryDirectoryName. */ void RetrieveAndStoreTemporaryDirectoryPreferenceValues(); /** * \brief Called on startup and by OnPreferencesChanged to set the validation mode, but will require a restart. */ void RetrieveAndStoreValidationMode(); /** * \brief Called to get hold of the actual preferences node. */ berry::IBerryPreferences::Pointer RetrievePreferences(); /** * \brief Search all modules for the one matching the given identifier. * \param fullName The "fullName" is the . from the XML. * \return ctkCmdLineModuleReference the reference corresponding to the fullName, or an invalid reference if non found. */ ctkCmdLineModuleReference GetReferenceByFullName(QString fullName); /** - * \brief Returns the QmitkCmdLineModuleProgressWidget from the layout. - * \param indexNumber the number of the widget in the layout, starting at zero. + * \brief Raises a message box asking the user to select a module first. */ - QmitkCmdLineModuleProgressWidget* GetWidget(const int& indexNumber); + void AskUserToSelectAModule() const; /** * \brief The GUI controls contain a reset and run button, and a QWidget container, and the GUI component * for each command line module is added to the QWidget 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 We keep a local layout, and arrange a display of QmitkCmdLineModuleProgressWidget, * where each QmitkCmdLineModuleProgressWidget represents a single running job. */ QVBoxLayout *m_Layout; /** * \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 ctkCmdLineModuleDirectoryWatcher maintains the list of directories * we are using to load modules, to provide automatic updates. */ ctkCmdLineModuleDirectoryWatcher *m_DirectoryWatcher; /** * \brief We store a temporary folder name, accessible via user preferences. */ QString m_TemporaryDirectoryName; /** * \brief We store the validation mode, accessisble via user preferences. */ ctkCmdLineModuleManager::ValidationMode m_ValidationMode; /** * \brief Member variable, taken from preference page. */ bool m_DebugOutput; + + /** + * \brief We keep a list of front ends to match the m_TabWidget. + */ + QList<ctkCmdLineModuleFrontend*> m_ListOfModules; }; #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 c65f4f5997..7d34e94cfd 100644 --- a/Plugins/org.mitk.gui.qt.cli/src/internal/CommandLineModulesViewControls.ui +++ b/Plugins/org.mitk.gui.qt.cli/src/internal/CommandLineModulesViewControls.ui @@ -1,129 +1,139 @@ <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>CommandLineModulesViewControls</class> <widget class="QWidget" name="CommandLineModulesViewControls"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>678</width> <height>582</height> </rect> </property> <property name="minimumSize"> <size> <width>0</width> <height>0</height> </size> </property> <property name="windowTitle"> <string>QmitkTemplate</string> </property> <layout class="QVBoxLayout" name="verticalLayout"> <item> <layout class="QHBoxLayout" name="m_HorizontalLayout"> <item> <widget class="QLabel" name="m_ChooseLabel"> <property name="sizePolicy"> <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="toolTip"> <string/> </property> <property name="text"> <string>choose:</string> </property> </widget> </item> <item> <widget class="QmitkCmdLineModuleMenuComboBox" name="m_ComboBox" native="true"/> </item> <item> <widget class="QPushButton" name="m_RestoreDefaults"> <property name="sizePolicy"> <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="toolTip"> <string>restore default parameters</string> </property> <property name="text"> <string/> </property> </widget> </item> <item> <widget class="QPushButton" name="m_RunButton"> <property name="sizePolicy"> <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="toolTip"> <string>run the command line module</string> </property> <property name="text"> <string/> </property> </widget> </item> <item> <spacer name="m_HorizontalSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>40</width> <height>20</height> </size> </property> </spacer> </item> </layout> </item> <item> - <widget class="QWidget" name="m_GeneratedGuiWidget" native="true"> + <widget class="QTabWidget" name="m_TabWidget"> + <property name="currentIndex"> + <number>-1</number> + </property> + <property name="tabsClosable"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QWidget" name="m_RunningWidgets" native="true"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> </widget> </item> <item> <spacer name="verticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>20</width> <height>250</height> </size> </property> </spacer> </item> </layout> </widget> <layoutdefault spacing="6" margin="11"/> <customwidgets> <customwidget> <class>QmitkCmdLineModuleMenuComboBox</class> <extends>QWidget</extends> <header>QmitkCmdLineModuleMenuComboBox.h</header> <container>1</container> </customwidget> </customwidgets> <resources> <include location="../../resources/CommandLineModulesResources.qrc"/> </resources> <connections/> </ui> diff --git a/Plugins/org.mitk.gui.qt.cli/src/internal/QmitkCmdLineModuleGui.cpp b/Plugins/org.mitk.gui.qt.cli/src/internal/QmitkCmdLineModuleGui.cpp index 1172ef92fa..c5bb43e4d8 100644 --- a/Plugins/org.mitk.gui.qt.cli/src/internal/QmitkCmdLineModuleGui.cpp +++ b/Plugins/org.mitk.gui.qt.cli/src/internal/QmitkCmdLineModuleGui.cpp @@ -1,103 +1,284 @@ /*=================================================================== 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. ===================================================================*/ #include "QmitkCmdLineModuleGui.h" #include "QmitkUiLoader.h" #include <QVariant> #include <QIODevice> #include <QFile> #include <QScopedPointer> +#include <QWidget> +#include <QTextBrowser> +#include <QVBoxLayout> +#include <QmitkCustomVariants.h> #include <ctkCmdLineModuleXslTransform.h> #include <ctkCmdLineModuleParameter.h> #include <ctkCmdLineModuleDescription.h> +#include <ctkCollapsibleGroupBox.h> #include "mitkDataStorage.h" //----------------------------------------------------------------------------- struct QmitkCmdLineModuleGuiPrivate { QmitkCmdLineModuleGuiPrivate(const mitk::DataStorage* dataStorage) - : m_DataStorage(dataStorage), m_Loader(NULL), m_Transform(NULL) - {} - + : m_DataStorage(dataStorage), m_Loader(NULL), m_Transform(NULL), m_TopLevelWidget(NULL) + { + } const mitk::DataStorage* m_DataStorage; mutable QScopedPointer<QUiLoader> m_Loader; mutable QScopedPointer<ctkCmdLineModuleXslTransform> m_Transform; + mutable QScopedPointer<QWidget> m_TopLevelWidget; }; //----------------------------------------------------------------------------- QmitkCmdLineModuleGui::QmitkCmdLineModuleGui(const mitk::DataStorage* dataStorage, const ctkCmdLineModuleReference& moduleRef) : ctkCmdLineModuleFrontendQtGui(moduleRef) , d(new QmitkCmdLineModuleGuiPrivate(dataStorage)) { + qRegisterMetaType<mitk::DataNode::Pointer>(); } //----------------------------------------------------------------------------- QmitkCmdLineModuleGui::~QmitkCmdLineModuleGui() { } //----------------------------------------------------------------------------- QUiLoader* QmitkCmdLineModuleGui::uiLoader() const { // Here we are creating a QUiLoader locally, so when this method // is called, it overrides the one in the base class, so the base // class one is never constructed, and this one is constructed as // a replacement. if (d->m_Loader == NULL) { d->m_Loader.reset(new QmitkUiLoader(d->m_DataStorage)); } return d->m_Loader.data(); } //----------------------------------------------------------------------------- ctkCmdLineModuleXslTransform* QmitkCmdLineModuleGui::xslTransform() const { // This is a virtual getter, overriding the one in the base class. // However, we want to use the transform in the base class, and just append to it. // So we call the base class one, modify it by adding some stuff, and then return // the pointer to the one in the base class. ctkCmdLineModuleXslTransform *transform = ctkCmdLineModuleFrontendQtGui::xslTransform(); if (transform != NULL) { transform->bindVariable("imageInputWidget", QVariant(QString("QmitkDataStorageComboBoxWithSelectNone"))); QIODevice* transformQmitkDataStorageComboBox(new QFile(":/CommandLineModulesResources/QmitkDataStorageComboBox.xsl")); if (transformQmitkDataStorageComboBox) { transform->setXslExtraTransformation(transformQmitkDataStorageComboBox); } } return transform; } //----------------------------------------------------------------------------- QVariant QmitkCmdLineModuleGui::value(const QString ¶meter, int role) const { if (role == UserRole) { ctkCmdLineModuleParameter param = this->moduleReference().description().parameter(parameter); if (param.channel() == "input" && param.tag() == "image") { - return this->customValue(parameter, "GetSelectedNode"); + return this->customValue(parameter, "SelectedNode"); } return QVariant(); } return ctkCmdLineModuleFrontendQtGui::value(parameter, role); } + + +//----------------------------------------------------------------------------- +void QmitkCmdLineModuleGui::setValue(const QString& parameter, const QVariant& value, int role) +{ + if (role == UserRole) + { + ctkCmdLineModuleParameter param = this->moduleReference().description().parameter(parameter); + if (param.channel() == "input" && param.tag() == "image") + { + this->setCustomValue(parameter, value, "SelectedNode"); + } + else + { + ctkCmdLineModuleFrontendQtGui::setValue(parameter, value, role); + } + } + else + { + ctkCmdLineModuleFrontendQtGui::setValue(parameter, value, role); + } +} + +//----------------------------------------------------------------------------- +QWidget* QmitkCmdLineModuleGui::getGui() +{ + if (!d->m_TopLevelWidget) + { + // Construct additional widgets to contain full GUI. + QWidget *aboutBoxContainerWidget = new QWidget(); + + ctkCollapsibleGroupBox *aboutBox = new ctkCollapsibleGroupBox(aboutBoxContainerWidget); + aboutBox->setTitle("About"); + + QTextBrowser *aboutBrowser = new QTextBrowser(aboutBox); + aboutBrowser->setReadOnly(true); + aboutBrowser->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + aboutBrowser->setOpenExternalLinks(true); + aboutBrowser->setOpenLinks(true); + + QVBoxLayout *aboutLayout = new QVBoxLayout(aboutBox); + aboutLayout->addWidget(aboutBrowser); + + QVBoxLayout *aboutBoxContainerWidgetLayout = new QVBoxLayout(aboutBoxContainerWidget); + aboutBoxContainerWidgetLayout->addWidget(aboutBox); + + QWidget *helpBoxContainerWidget = new QWidget(); + + ctkCollapsibleGroupBox *helpBox = new ctkCollapsibleGroupBox(); + helpBox->setTitle("Help"); + + QTextBrowser *helpBrowser = new QTextBrowser(helpBox); + helpBrowser->setReadOnly(true); + helpBrowser->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + helpBrowser->setOpenExternalLinks(true); + helpBrowser->setOpenLinks(true); + + QVBoxLayout *helpLayout = new QVBoxLayout(helpBox); + helpLayout->addWidget(helpBrowser); + + QVBoxLayout *helpBoxContainerWidgetLayout = new QVBoxLayout(helpBoxContainerWidget); + helpBoxContainerWidgetLayout->addWidget(helpBox); + + QObject* guiHandle = this->guiHandle(); + QWidget* generatedGuiWidgets = qobject_cast<QWidget*>(guiHandle); + + QWidget *topLevelWidget = new QWidget(); + + QGridLayout *topLevelLayout = new QGridLayout(topLevelWidget); + topLevelLayout->setContentsMargins(0,0,0,0); + topLevelLayout->setSpacing(0); + topLevelLayout->addWidget(aboutBoxContainerWidget, 0, 0); + topLevelLayout->addWidget(helpBoxContainerWidget, 1, 0); + topLevelLayout->addWidget(generatedGuiWidgets, 2, 0); + + ctkCmdLineModuleDescription description = this->moduleReference().description(); + + QString helpString = ""; + + if (!description.title().isEmpty()) + { + QString titleHtml = "<h1>" + description.title() + "</h1>"; + helpString += titleHtml; + } + + if (!description.description().isEmpty()) + { + QString descriptionHtml = "<p>" + description.description() + "</p>"; + helpString += descriptionHtml; + } + + if (!description.documentationURL().isEmpty()) + { + QString docUrlHtml = "<p>For more information please see <a href=\"" + description.documentationURL() + + "\">" + description.documentationURL() + "</a></p>"; + helpString += docUrlHtml; + } + + QString aboutString = ""; + + if (!description.title().isEmpty()) + { + QString titleHtml = "<h1>" + description.title() + "</h1>"; + aboutString += titleHtml; + } + + if (!description.contributor().isEmpty()) + { + QString contributorHtml = "<h2>Contributed By</h2><p>" + description.contributor() + "</p>"; + aboutString += contributorHtml; + } + + if (!description.license().isEmpty()) + { + QString licenseHtml = "<h2>License</h2><p>" + description.license() + "</p>"; + aboutString += licenseHtml; + } + + if (!description.acknowledgements().isEmpty()) + { + QString acknowledgementsHtml = "<h2>Acknowledgements</h2><p>" + description.acknowledgements() + "</p>"; + aboutString += acknowledgementsHtml; + } + + helpBrowser->clear(); + helpBrowser->setHtml(helpString); + helpBox->setCollapsed(true); + + aboutBrowser->clear(); + aboutBrowser->setHtml(aboutString); + aboutBox->setCollapsed(true); + + d->m_TopLevelWidget.reset(topLevelWidget); + } + + return d->m_TopLevelWidget.data(); +} + + +//----------------------------------------------------------------------------- +void QmitkCmdLineModuleGui::lockGui() +{ + // TODO +} + + +//----------------------------------------------------------------------------- +void QmitkCmdLineModuleGui::copyParameters(QmitkCmdLineModuleGui& another) +{ + + // This copies "display" parameter types. + // See ctkCmdLineModuleFrontend::DisplayRole + this->setValues(another.values()); + + // For custom types, we must manually copy the values. + // In our case, we copy image types manually, to pass across the mitk::DataNode pointer. + QList<ctkCmdLineModuleParameter> parameters = another.parameters("image", ctkCmdLineModuleFrontend::Input); + foreach (ctkCmdLineModuleParameter parameter, parameters) + { + QString parameterName = parameter.name(); + + QVariant tmp = another.value(parameterName, ctkCmdLineModuleFrontend::UserRole); + mitk::DataNode::Pointer node = tmp.value<mitk::DataNode::Pointer>(); + + if (node.IsNotNull()) + { + mitk::Image* image = dynamic_cast<mitk::Image*>(node->GetData()); + if (image != NULL) + { + this->setValue(parameterName, tmp, ctkCmdLineModuleFrontend::UserRole); + } + } + } +} diff --git a/Plugins/org.mitk.gui.qt.cli/src/internal/QmitkCmdLineModuleGui.h b/Plugins/org.mitk.gui.qt.cli/src/internal/QmitkCmdLineModuleGui.h index 9638fd4c19..69183d126f 100644 --- a/Plugins/org.mitk.gui.qt.cli/src/internal/QmitkCmdLineModuleGui.h +++ b/Plugins/org.mitk.gui.qt.cli/src/internal/QmitkCmdLineModuleGui.h @@ -1,86 +1,123 @@ /*=================================================================== 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 QmitkCmdLineModuleGui_h #define QmitkCmdLineModuleGui_h #include <QBuffer> #include <QUiLoader> #include <ctkCmdLineModuleReference.h> #include <ctkCmdLineModuleFrontendQtGui.h> namespace mitk { class DataStorage; } class QmitkCmdLineModuleGuiPrivate; +class QWidget; /** * \class QmitkCmdLineModuleGui * \brief Derived from ctkCmdLineModuleQtGui to implement an MITK specific command line module, * that has access to the mitk::DataStorage, and also instantiates QmitkDataStorageComboBox * for any "imageInputWidget" type, and also provides QmitkDataStorageComboBox.xsl to override * the standard CTK xslt transformation. * \author Matt Clarkson (m.clarkson@ucl.ac.uk) * \ingroup org_mitk_gui_qt_cli_internal * \sa QmitkCmdLineModuleFactoryGui * \sa ctkCmdLineModuleFrontendQtGui */ class QmitkCmdLineModuleGui : public ctkCmdLineModuleFrontendQtGui { Q_OBJECT public: QmitkCmdLineModuleGui(const mitk::DataStorage* dataStorage, const ctkCmdLineModuleReference& moduleRef); virtual ~QmitkCmdLineModuleGui(); -protected: + /** + * \brief Returns the top level widget containing the whole GUI, and + * should be used in preference to ctkCmdLineModuleFrontend::guiHandle. + */ + QWidget* getGui(); /** - * \brief Virtual getter. - * \see ctkCmdLineModuleFrontendQtGui::uiLoader() + * \brief Used to disable the editable parameters, but leave group boxes + * and collapsible items still usable. */ - virtual QUiLoader* uiLoader() const; + void lockGui(); /** - * \brief Virtual getter. - * \see ctkCmdLineModuleFrontendQtGui::xslTransform() + * \brief Copies the visible parameters from another QmitkCmdLineModuleGui; + * \param another a QmitkCmdLineModuleGui frontend. */ - virtual ctkCmdLineModuleXslTransform* xslTransform() const; + void copyParameters(QmitkCmdLineModuleGui& another); /** * \brief A custom method to enable access to a mitk::DataNode::Pointer for input images. * \param parameter The name of the parameter as specified in XML. - * \param role The role, see ctkCmdLineModuleFrontend. + * \param role The role, \see ctkCmdLineModuleFrontend. * \return QVariant * * If role==UserRole and the parameter specified by parameter name is an * input image, will return a mitk::DataNode::Pointer wrapped in a QVariant. * * If role==UserRole and the parameter specified is not an input image, * returns an Empty QVariant. * - * For any other role, calls base class. + * For any other scenario, calls base class. + * + * \sa ctkCmdLineModuleFrontend::value */ virtual QVariant value(const QString ¶meter, int role) const; + /** + * \brief A custom method to enable the setting of mitk::DataNode::Pointer for input images. + * \param parameter The name of the parameter as specified in XML. + * \param value QVariant containing a mitk::DataNode::Pointer + * \param role The role, \see ctkCmdLineModuleFrontend. + * + * If role==UserRole and the parameter specified by parameter name is an + * input image, will set the value for that parameter. + * + * + * For any other scenario, calls base class. + * + * \sa ctkCmdLineModuleFrontend::setValue + */ + virtual void setValue(const QString& parameter, const QVariant& value, int role = DisplayRole); + +protected: + + /** + * \brief Virtual getter. + * \see ctkCmdLineModuleFrontendQtGui::uiLoader() + */ + virtual QUiLoader* uiLoader() const; + + /** + * \brief Virtual getter. + * \see ctkCmdLineModuleFrontendQtGui::xslTransform() + */ + virtual ctkCmdLineModuleXslTransform* xslTransform() const; + private: QScopedPointer<QmitkCmdLineModuleGuiPrivate> d; }; // end class #endif // QmitkCmdLineModuleGui_h diff --git a/Plugins/org.mitk.gui.qt.cli/src/internal/QmitkCmdLineModuleProgressWidget.cpp b/Plugins/org.mitk.gui.qt.cli/src/internal/QmitkCmdLineModuleProgressWidget.cpp index b7a7d544fd..8ef5c92513 100644 --- a/Plugins/org.mitk.gui.qt.cli/src/internal/QmitkCmdLineModuleProgressWidget.cpp +++ b/Plugins/org.mitk.gui.qt.cli/src/internal/QmitkCmdLineModuleProgressWidget.cpp @@ -1,662 +1,512 @@ /*=================================================================== 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. ===================================================================*/ #include "QmitkCmdLineModuleProgressWidget.h" #include "ui_QmitkCmdLineModuleProgressWidget.h" // Qt #include <QFile> #include <QVBoxLayout> #include <QLayoutItem> #include <QTextBrowser> #include <QByteArray> // CTK #include <ctkCmdLineModuleFuture.h> +#include <ctkCmdLineModuleFutureWatcher.h> #include <ctkCmdLineModuleManager.h> #include <ctkCmdLineModuleFrontend.h> #include <ctkCmdLineModuleDescription.h> #include <ctkCmdLineModuleParameter.h> #include <ctkCollapsibleGroupBox.h> // MITK #include <mitkIOUtil.h> #include <mitkDataStorage.h> #include <mitkDataNode.h> #include <QmitkCommonFunctionality.h> #include <QmitkCustomVariants.h> -#include "QmitkCmdLineModuleFactoryGui.h" +#include "QmitkCmdLineModuleGui.h" //----------------------------------------------------------------------------- QmitkCmdLineModuleProgressWidget::QmitkCmdLineModuleProgressWidget(QWidget *parent) : QWidget(parent) , m_ModuleManager(NULL) , m_DataStorage(NULL) , m_TemporaryDirectoryName("") , m_UI(new Ui::QmitkCmdLineModuleProgressWidget) +, m_Layout(NULL) , m_ModuleFrontEnd(NULL) , m_FutureWatcher(NULL) { m_UI->setupUi(this); m_UI->m_RemoveButton->setIcon(QApplication::style()->standardIcon(QStyle::SP_TitleBarCloseButton)); m_Layout = new QVBoxLayout(); m_Layout->setContentsMargins(0,0,0,0); m_Layout->setSpacing(0); m_UI->m_ParametersGroupBox->setLayout(m_Layout); qRegisterMetaType<mitk::DataNode::Pointer>(); qRegisterMetaType<ctkCmdLineModuleReference>(); + connect(m_UI->m_RemoveButton, SIGNAL(clicked()), this, SLOT(OnRemoveButtonClicked())); + // 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 approach instead. - m_PollPauseTimer.setInterval(300); connect(&m_PollPauseTimer, SIGNAL(timeout()), SLOT(OnCheckModulePaused())); - - connect(m_UI->m_RemoveButton, SIGNAL(clicked()), this, SLOT(OnRemoveButtonClicked())); - + m_PollPauseTimer.setInterval(300); m_PollPauseTimer.start(); } //----------------------------------------------------------------------------- QmitkCmdLineModuleProgressWidget::~QmitkCmdLineModuleProgressWidget() { if (m_ModuleFrontEnd != NULL) { delete m_ModuleFrontEnd; } this->ClearUpTemporaryFiles(); delete m_UI; } //----------------------------------------------------------------------------- void QmitkCmdLineModuleProgressWidget::SetManager(ctkCmdLineModuleManager* manager) { this->m_ModuleManager = manager; } //----------------------------------------------------------------------------- void QmitkCmdLineModuleProgressWidget::SetDataStorage(mitk::DataStorage* dataStorage) { this->m_DataStorage = dataStorage; } //----------------------------------------------------------------------------- void QmitkCmdLineModuleProgressWidget::SetTemporaryDirectory(const QString& directoryName) { this->m_TemporaryDirectoryName = directoryName; } //----------------------------------------------------------------------------- -void QmitkCmdLineModuleProgressWidget::ShowProgressBar(bool visible) +QString QmitkCmdLineModuleProgressWidget::GetTitle() { - m_UI->m_ProgressBar->setVisible(visible); - m_UI->m_PauseButton->setVisible(visible); - m_UI->m_CancelButton->setVisible(visible); - m_UI->m_RemoveButton->setVisible(visible); -} + assert(m_ModuleFrontEnd); + ctkCmdLineModuleReference reference = m_ModuleFrontEnd->moduleReference(); + ctkCmdLineModuleDescription description = reference.description(); -//----------------------------------------------------------------------------- -void QmitkCmdLineModuleProgressWidget::ShowConsole(bool visible) -{ - m_UI->m_ConsoleGroupBox->setVisible(visible); + return description.title(); } + //----------------------------------------------------------------------------- -QString QmitkCmdLineModuleProgressWidget::GetTitle() +QString QmitkCmdLineModuleProgressWidget::GetFullName() const { assert(m_ModuleFrontEnd); ctkCmdLineModuleReference reference = m_ModuleFrontEnd->moduleReference(); ctkCmdLineModuleDescription description = reference.description(); - return description.title(); + return description.categoryDotTitle(); } +//----------------------------------------------------------------------------- +bool QmitkCmdLineModuleProgressWidget::IsStarted() const +{ + bool isStarted = false; + if (m_FutureWatcher != NULL && m_FutureWatcher->isStarted()) + { + isStarted = true; + } + return isStarted; +} + //----------------------------------------------------------------------------- void QmitkCmdLineModuleProgressWidget::OnCheckModulePaused() { if (!this->IsStarted()) { return; } 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::OnPauseButtonToggled(bool toggled) { this->m_FutureWatcher->setPaused(toggled); if (toggled) { this->m_UI->m_ProgressTitle->setText(this->GetTitle() + ": paused"); } else { this->m_UI->m_ProgressTitle->setText(this->GetTitle() + ": resumed"); } } //----------------------------------------------------------------------------- void QmitkCmdLineModuleProgressWidget::OnRemoveButtonClicked() { this->deleteLater(); } //----------------------------------------------------------------------------- void QmitkCmdLineModuleProgressWidget::OnModuleStarted() { this->m_UI->m_ProgressBar->setMaximum(0); QString message = "started."; this->PublishMessage(message); } //----------------------------------------------------------------------------- void QmitkCmdLineModuleProgressWidget::OnModuleCanceled() { QString message = "cancelling."; 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->m_UI->m_ParametersGroupBox->setCollapsed(true); this->m_UI->m_ConsoleGroupBox->setCollapsed(true); this->m_UI->m_ProgressTitle->setText(this->GetTitle() + ": cancelled"); message = "cancelled."; this->PublishMessage(message); } //----------------------------------------------------------------------------- void QmitkCmdLineModuleProgressWidget::OnModuleFinished() { 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); if (!this->m_FutureWatcher->isCanceled()) { QString message = "finishing."; this->PublishMessage(message); // If no incremental results from stdout, try getting hold of the whole buffer and printing it. if (m_OutputCount == 0) { message = "Output channel is:"; this->PublishMessage(message); this->PublishByteArray(this->m_FutureWatcher->readAllOutputData()); } // If no incremental results from stderr, try getting hold of the whole buffer and printing it. if (m_ErrorCount == 0) { message = "Error channel is:"; this->PublishMessage(message); this->PublishByteArray(this->m_FutureWatcher->readAllErrorData()); } this->m_UI->m_ProgressTitle->setText(this->GetTitle() + ": finished"); this->LoadOutputData(); this->ClearUpTemporaryFiles(); message = "finished."; this->PublishMessage(message); } } //----------------------------------------------------------------------------- void QmitkCmdLineModuleProgressWidget::OnModuleResumed() { this->m_UI->m_PauseButton->setChecked(false); } //----------------------------------------------------------------------------- void QmitkCmdLineModuleProgressWidget::OnModuleProgressRangeChanged(int progressMin, int progressMax) { this->m_UI->m_ProgressBar->setMinimum(progressMin); this->m_UI->m_ProgressBar->setMaximum(progressMax); } //----------------------------------------------------------------------------- void QmitkCmdLineModuleProgressWidget::OnModuleProgressTextChanged(const QString& progressText) { this->m_UI->m_Console->appendPlainText(progressText); } //----------------------------------------------------------------------------- void QmitkCmdLineModuleProgressWidget::OnModuleProgressValueChanged(int progressValue) { this->m_UI->m_ProgressBar->setValue(progressValue); } //----------------------------------------------------------------------------- void QmitkCmdLineModuleProgressWidget::OnOutputDataReady() { m_OutputCount++; this->PublishByteArray(this->m_FutureWatcher->readPendingOutputData()); } //----------------------------------------------------------------------------- void QmitkCmdLineModuleProgressWidget::OnErrorDataReady() { m_ErrorCount++; this->PublishByteArray(this->m_FutureWatcher->readPendingErrorData()); } //----------------------------------------------------------------------------- void QmitkCmdLineModuleProgressWidget::PublishMessage(const QString& message) { QString prefix = ""; // Can put additional prefix here if needed. QString outputMessage = prefix + message; qDebug() << outputMessage; this->m_UI->m_Console->appendPlainText(outputMessage); } //----------------------------------------------------------------------------- void QmitkCmdLineModuleProgressWidget::PublishByteArray(const QByteArray& array) { QString message = array.data(); this->PublishMessage(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<std::string> 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::SetModule(const ctkCmdLineModuleReference& reference) +void QmitkCmdLineModuleProgressWidget::SetFrontend(QmitkCmdLineModuleGui* frontEnd) { - + assert(frontEnd); assert(m_ModuleManager); assert(m_DataStorage); - // If a widget exists, make it invisible. - // This seems to cause less problems than deleting widgets on the fly. - QLayoutItem *item = m_Layout->itemAt(0); - if (item != NULL) - { - item->widget()->setVisible(false); - } - - // This method is called when the user selects a new module to display. - // Aim of this method is to create a default GUI, and attach it to this widget. - - QmitkCmdLineModuleFactoryGui factory(m_DataStorage); - m_ModuleFrontEnd = factory.create(reference); - - if (!m_ModuleFrontEnd) - { - qDebug() << "QmitkCmdLineModuleProgressWidget: Failed to SetModule() for " << reference.description().title(); - return; - } - - // Build up the GUI layout programmatically (manually). - - QWidget *aboutBoxContainerWidget = new QWidget(); - - ctkCollapsibleGroupBox *aboutBox = new ctkCollapsibleGroupBox(aboutBoxContainerWidget); - aboutBox->setTitle("About"); - - QTextBrowser *aboutBrowser = new QTextBrowser(aboutBox); - aboutBrowser->setReadOnly(true); - aboutBrowser->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); - aboutBrowser->setOpenExternalLinks(true); - aboutBrowser->setOpenLinks(true); - - QVBoxLayout *aboutLayout = new QVBoxLayout(aboutBox); - aboutLayout->addWidget(aboutBrowser); - - QVBoxLayout *aboutBoxContainerWidgetLayout = new QVBoxLayout(aboutBoxContainerWidget); - aboutBoxContainerWidgetLayout->addWidget(aboutBox); - - QWidget *helpBoxContainerWidget = new QWidget(); - - ctkCollapsibleGroupBox *helpBox = new ctkCollapsibleGroupBox(); - helpBox->setTitle("Help"); - - QTextBrowser *helpBrowser = new QTextBrowser(helpBox); - helpBrowser->setReadOnly(true); - helpBrowser->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); - helpBrowser->setOpenExternalLinks(true); - helpBrowser->setOpenLinks(true); - - QVBoxLayout *helpLayout = new QVBoxLayout(helpBox); - helpLayout->addWidget(helpBrowser); - - QVBoxLayout *helpBoxContainerWidgetLayout = new QVBoxLayout(helpBoxContainerWidget); - helpBoxContainerWidgetLayout->addWidget(helpBox); - - QObject* guiHandle = m_ModuleFrontEnd->guiHandle(); - QWidget* generatedGuiWidgets = qobject_cast<QWidget*>(guiHandle); - - QWidget *topLevelWidget = new QWidget(); - - QGridLayout *topLevelLayout = new QGridLayout(topLevelWidget); - topLevelLayout->setContentsMargins(0,0,0,0); - topLevelLayout->setSpacing(0); - topLevelLayout->addWidget(aboutBoxContainerWidget, 0, 0); - topLevelLayout->addWidget(helpBoxContainerWidget, 1, 0); - topLevelLayout->addWidget(generatedGuiWidgets, 2, 0); - - ctkCmdLineModuleDescription description = reference.description(); - - QString helpString = ""; - - if (!description.title().isEmpty()) - { - QString titleHtml = "<h1>" + description.title() + "</h1>"; - helpString += titleHtml; - } - - if (!description.description().isEmpty()) - { - QString descriptionHtml = "<p>" + description.description() + "</p>"; - helpString += descriptionHtml; - } + // We are assuming that this method is ONLY EVER CALLED ONCE. + assert(!m_ModuleFrontEnd); - if (!description.documentationURL().isEmpty()) - { - QString docUrlHtml = "<p>For more information please see <a href=\"" + description.documentationURL() - + "\">" + description.documentationURL() + "</a></p>"; - helpString += docUrlHtml; - } + // Assign the frontEnd to the member variable. + m_ModuleFrontEnd = frontEnd; - QString aboutString = ""; - - if (!description.title().isEmpty()) - { - QString titleHtml = "<h1>" + description.title() + "</h1>"; - aboutString += titleHtml; - } - - if (!description.contributor().isEmpty()) - { - QString contributorHtml = "<h2>Contributed By</h2><p>" + description.contributor() + "</p>"; - aboutString += contributorHtml; - } - - if (!description.license().isEmpty()) - { - QString licenseHtml = "<h2>License</h2><p>" + description.license() + "</p>"; - aboutString += licenseHtml; - } - - if (!description.acknowledgements().isEmpty()) - { - QString acknowledgementsHtml = "<h2>Acknowledgements</h2><p>" + description.acknowledgements() + "</p>"; - aboutString += acknowledgementsHtml; - } - - helpBrowser->clear(); - helpBrowser->setHtml(helpString); - helpBox->setCollapsed(true); - aboutBrowser->clear(); - aboutBrowser->setHtml(aboutString); - aboutBox->setCollapsed(true); - - // So, we put the new GUI into the layout. - m_Layout->insertWidget(0, topLevelWidget); + // We put the new GUI into the layout. + m_Layout->insertWidget(0, m_ModuleFrontEnd->getGui()); // And configure a few other niceties. - m_UI->m_ProgressTitle->setText(description.title()); - m_UI->m_ConsoleGroupBox->setCollapsed(true); - m_UI->m_ParametersGroupBox->setCollapsed(false); - this->ShowProgressBar(false); - this->ShowConsole(false); -} - - -//----------------------------------------------------------------------------- -QString QmitkCmdLineModuleProgressWidget::GetFullName() const -{ - assert(m_ModuleFrontEnd); - - ctkCmdLineModuleDescription description = m_ModuleFrontEnd->moduleReference().description(); - QString fullName = description.category() + "." + description.title(); - - return fullName; -} - - -//----------------------------------------------------------------------------- -bool QmitkCmdLineModuleProgressWidget::IsStarted() const -{ - bool isStarted = false; - if (m_FutureWatcher != NULL && m_FutureWatcher->isStarted()) - { - isStarted = true; - } - return isStarted; -} - - -//----------------------------------------------------------------------------- -void QmitkCmdLineModuleProgressWidget::Reset() -{ - assert(m_ModuleFrontEnd); - - m_ModuleFrontEnd->resetValues(); + m_UI->m_ProgressTitle->setText(this->GetTitle()); + m_UI->m_ConsoleGroupBox->setCollapsed(true); // We basically call SetFrontend then Run + m_UI->m_ParametersGroupBox->setCollapsed(true); // so in practice the user will only want the progress bar. } //----------------------------------------------------------------------------- void QmitkCmdLineModuleProgressWidget::Run() { assert(m_ModuleManager); + assert(m_DataStorage); assert(m_ModuleFrontEnd); m_OutputDataToLoad.clear(); ctkCmdLineModuleReference reference = m_ModuleFrontEnd->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<ctkCmdLineModuleParameter> 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 = m_ModuleFrontEnd->parameters("image", ctkCmdLineModuleFrontend::Input); foreach (ctkCmdLineModuleParameter parameter, parameters) { parameterName = parameter.name(); QVariant tmp = m_ModuleFrontEnd->value(parameterName, ctkCmdLineModuleFrontend::UserRole); mitk::DataNode::Pointer node = tmp.value<mitk::DataNode::Pointer>(); if (node.IsNotNull()) { mitk::Image* image = dynamic_cast<mitk::Image*>(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); m_ModuleFrontEnd->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 = m_ModuleFrontEnd->parameters("image", ctkCmdLineModuleFrontend::Output); parameters << m_ModuleFrontEnd->parameters("file", ctkCmdLineModuleFrontend::Output); foreach (ctkCmdLineModuleParameter parameter, parameters) { parameterName = parameter.name(); - QString outputFileName = m_ModuleFrontEnd->value(parameterName).toString(); + QString outputFileName = m_ModuleFrontEnd->value(parameterName, ctkCmdLineModuleFrontend::DisplayRole).toString(); if (!outputFileName.isEmpty()) { m_OutputDataToLoad.push_back(outputFileName); message = "Registered " + outputFileName + " to auto load upon completion."; this->PublishMessage(message); } } m_OutputCount = 0; m_ErrorCount = 0; // Now we run stuff. message = "starting."; this->PublishMessage(message); if (m_FutureWatcher == NULL) { m_FutureWatcher = new ctkCmdLineModuleFutureWatcher(); connect(m_FutureWatcher, SIGNAL(started()), SLOT(OnModuleStarted())); connect(m_FutureWatcher, SIGNAL(canceled()), SLOT(OnModuleCanceled())); connect(m_FutureWatcher, SIGNAL(finished()), SLOT(OnModuleFinished())); connect(m_FutureWatcher, SIGNAL(resumed()), SLOT(OnModuleResumed())); connect(m_FutureWatcher, SIGNAL(progressRangeChanged(int,int)), SLOT(OnModuleProgressRangeChanged(int,int))); connect(m_FutureWatcher, SIGNAL(progressTextChanged(QString)), SLOT(OnModuleProgressTextChanged(QString))); connect(m_FutureWatcher, SIGNAL(progressValueChanged(int)), SLOT(OnModuleProgressValueChanged(int))); connect(m_FutureWatcher, SIGNAL(outputDataReady()), SLOT(OnOutputDataReady())); connect(m_FutureWatcher, SIGNAL(errorDataReady()), SLOT(OnErrorDataReady())); connect(m_UI->m_CancelButton, SIGNAL(clicked()), m_FutureWatcher, SLOT(cancel())); connect(m_UI->m_PauseButton, SIGNAL(toggled(bool)), this, SLOT(OnPauseButtonToggled(bool))); } ctkCmdLineModuleFuture future = m_ModuleManager->run(m_ModuleFrontEnd); 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()); - // Configure some other niceties. - this->ShowProgressBar(true); - this->ShowConsole(true); - m_UI->m_ParametersGroupBox->setCollapsed(true); - m_UI->m_ConsoleGroupBox->setCollapsed(true); - // Lock parameters, as once the module is running the user can't change them. - m_Layout->itemAt(0)->widget()->setEnabled(false); + m_ModuleFrontEnd->lockGui(); // Give some immediate indication that we are running. m_UI->m_ProgressTitle->setText(description.title() + ": running"); } diff --git a/Plugins/org.mitk.gui.qt.cli/src/internal/QmitkCmdLineModuleProgressWidget.h b/Plugins/org.mitk.gui.qt.cli/src/internal/QmitkCmdLineModuleProgressWidget.h index bfbcbb1613..800df91be1 100644 --- a/Plugins/org.mitk.gui.qt.cli/src/internal/QmitkCmdLineModuleProgressWidget.h +++ b/Plugins/org.mitk.gui.qt.cli/src/internal/QmitkCmdLineModuleProgressWidget.h @@ -1,228 +1,209 @@ /*=================================================================== 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 QMITKCMDLINEMODULEPROGRESSWIDGET_H #define QMITKCMDLINEMODULEPROGRESSWIDGET_H #include <QWidget> #include <QTimer> -#include <ctkCmdLineModuleFutureWatcher.h> -#include <ctkCmdLineModuleReference.h> -class ctkCmdLineModuleManager; -class ctkCmdLineModuleFrontend; -class ctkCmdLineModuleFuture; -class QmitkCmdLineModuleFactoryGui; class QVBoxLayout; +class QmitkCmdLineModuleGui; +class ctkCmdLineModuleManager; +class ctkCmdLineModuleFutureWatcher; 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 widgets. * \author Matt Clarkson (m.clarkson@ucl.ac.uk) * \ingroup org_mitk_gui_qt_cli_internal * \sa ctkCmdLineModuleExplorerProgressWidget */ class QmitkCmdLineModuleProgressWidget : public QWidget { Q_OBJECT public: QmitkCmdLineModuleProgressWidget(QWidget *parent = 0); - ~QmitkCmdLineModuleProgressWidget(); + virtual ~QmitkCmdLineModuleProgressWidget(); /** * \brief Sets the manager on this object, and must be called immediately * after construction, before using the widget. */ void SetManager(ctkCmdLineModuleManager* manager); /** * \brief Sets the DataStorage on this object, and must be called immediately * after construction, before using the widget. */ void SetDataStorage(mitk::DataStorage* dataStorage); /** * \brief Sets the Temporary Directory on this widget, and must be called * immediately after construction, before using the widget. */ void SetTemporaryDirectory(const QString& directoryName); /** - * \brief Tells this widget, which module it is pertaining to, which is looked up via the ModuleManager. - * \param reference - */ - void SetModule(const ctkCmdLineModuleReference& reference); - - /** - * \brief Returns <category>.<title>, derived from the ctkCmdLineModuleReference and - * hence from the ctkCmdLineModuleDescription. - */ - QString GetFullName() const; - - /** - * \brief Called from CommandLineModulesView to see if this job has started or not, - * as it affects the decision on when to create new widgets. - */ - bool IsStarted() const; - - /** - * \brief Resets this widget to the default parameters specified in the - * command line modules XML file. + * \brief Tells this widget, which module frontend it is running + * \param frontEnd our QmitkCmdLineModuleGui class derived from ctkCmdLineModuleFrontend */ - void Reset(); + void SetFrontend(QmitkCmdLineModuleGui* frontEnd); /** * \brief Runs the module that this widget is currently referring to. */ void Run(); - /** - * \brief Shows the progress bar widgets, which can be turned off / on to save space. - */ - void ShowProgressBar(bool visible); - - /** - * \brief Shows the console widget, which can be turned off / on to save space. - */ - void ShowConsole(bool visible); - Q_SIGNALS: // These signals so that container classes such as CommandLineModuleView // can keep track of how many modules are running simultaneously. void started(); // emmitted when the module is started. void finished(); // emmitted when the module is completely finished. private Q_SLOTS: void OnCheckModulePaused(); void OnPauseButtonToggled(bool toggled); void OnRemoveButtonClicked(); void OnModuleStarted(); void OnModuleCanceled(); void OnModuleFinished(); void OnModuleResumed(); void OnModuleProgressRangeChanged(int progressMin, int progressMax); void OnModuleProgressTextChanged(const QString& progressText); void OnModuleProgressValueChanged(int progressValue); void OnOutputDataReady(); void OnErrorDataReady(); private: + /** + * \brief Simply returns true if this widget is considered as having been started. + */ + bool IsStarted() const; + /** * \brief Used to write output to the console widget, and also to qDebug(). */ void PublishMessage(const QString& message); /** * \brief Used to write output to the console widget, and also to qDebug(). */ void PublishByteArray(const QByteArray& array); /** * \brief Destroys any images listed in m_TemporaryFileNames. */ void ClearUpTemporaryFiles(); /** * \brief Loads any data listed in m_OutputDataToLoad into the m_DataStorage. */ void LoadOutputData(); /** * \brief Utility method to look up the title from the description. */ QString GetTitle(); + /** + * \brief Returns <category>.<title>, derived from the ctkCmdLineModuleReference and + * hence from the ctkCmdLineModuleDescription. + */ + QString GetFullName() const; + /** * \brief This must be injected before the Widget is used. */ ctkCmdLineModuleManager *m_ModuleManager; /** * \brief This must be injected before the Widget is used. */ mitk::DataStorage *m_DataStorage; /** * \brief This must be injected before the Widget is used. */ QString m_TemporaryDirectoryName; /** * \brief We instantiate the main widgets from this .ui file. */ Ui::QmitkCmdLineModuleProgressWidget *m_UI; /** * \brief The m_ParametersGroupBox needs a layout. */ QVBoxLayout *m_Layout; /** - * \brief The ctkCmdLineModuleFrontend is created by the QmitkCmdLineModuleFactoryGui. + * \brief The QmitkCmdLineModuleGui is created by the QmitkCmdLineModuleFactoryGui outside + * of this class and injected into this class before being run. */ - ctkCmdLineModuleFrontend *m_ModuleFrontEnd; + QmitkCmdLineModuleGui *m_ModuleFrontEnd; /** * \brief Main object to keep track of a running command line module. */ ctkCmdLineModuleFutureWatcher *m_FutureWatcher; /** * \brief Due to Qt bug 12152, we use a timer to correctly check for a paused module. */ QTimer m_PollPauseTimer; /** * \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 successful completion of * the command line module, we automatically load the output data into the mitk::DataStorage. */ QStringList m_OutputDataToLoad; /** * \brief We track how many times the OnOutputDataReady is called. */ int m_OutputCount; /** * \brief We track how many times the OnErrorDataReady is called. */ int m_ErrorCount; }; #endif // QMITKCMDLINEMODULEPROGRESSWIDGET_H