diff --git a/Applications/AppList.cmake b/Applications/AppList.cmake index e82b1f64b1..c063d47f6b 100644 --- a/Applications/AppList.cmake +++ b/Applications/AppList.cmake @@ -1,19 +1,21 @@ # This file is included in the top-level MITK CMakeLists.txt file to # allow early dependency checking option(MITK_BUILD_APP_Workbench "Build the MITK Workbench executable" ON) +option(MITK_BUILD_APP_FlowBench "Build the MITK FlowBench executable" OFF) # This variable is fed to ctkFunctionSetupPlugins() macro in the # top-level MITK CMakeLists.txt file. This allows to automatically # enable required plug-in runtime dependencies for applications using # the CTK DGraph executable and the ctkMacroValidateBuildOptions macro. # For this to work, directories containing executables must contain # a CMakeLists.txt file containing a "project(...)" command and a # target_libraries.cmake file setting a list named "target_libraries" # with required plug-in target names. # Format is "Directory Name^^CMake Option Name^^Executable Name (without file suffix)" set(MITK_APPS Workbench^^MITK_BUILD_APP_Workbench^^MitkWorkbench + FlowBench^^MITK_BUILD_APP_FlowBench^^MitkFlowBench ) diff --git a/Applications/FlowBench/CMakeLists.txt b/Applications/FlowBench/CMakeLists.txt new file mode 100644 index 0000000000..d3f14cafcd --- /dev/null +++ b/Applications/FlowBench/CMakeLists.txt @@ -0,0 +1,50 @@ +project(Workbench) + +# Create a cache entry for the provisioning file which is used to export +# the file name in the MITKConfig.cmake file. This will keep external projects +# which rely on this file happy. +set(MITK_FLOWBENCH_PROVISIONING_FILE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/MitkFlowBench.provisioning" CACHE INTERNAL "MitkFlowBench provisioning file" FORCE) + +# Plug-ins listed below will not be +# - added as a build-time dependency to the executable +# - listed in the provisioning file for the executable +# - installed if they are external plug-ins + +set(_exclude_plugins + org.blueberry.test + org.blueberry.uitest + org.mitk.gui.qt.coreapplication + org.mitk.gui.qt.diffusionimagingapp + org.mitk.example.gui.customviewer + org.mitk.example.gui.customviewer.views + org.mitk.example.gui.selectionservicemitk + org.mitk.example.gui.selectionservicemitk.views + org.mitk.example.gui.selectionserviceqt + org.mitk.example.gui.extensionpointcontribution + org.mitk.example.gui.extensionpointdefinition + org.mitk.example.gui.minimalapplication + org.mitk.example.gui.multipleperspectives +) + +mitkFunctionCreateBlueBerryApplication( + NAME MitkFlowBench + DESCRIPTION "MITK FlowBench" + EXCLUDE_PLUGINS ${_exclude_plugins} +) + +# Add meta dependencies (e.g. on auto-load modules from depending modules) +if(TARGET ${CMAKE_PROJECT_NAME}-autoload) + add_dependencies(MitkFlowBench ${CMAKE_PROJECT_NAME}-autoload) +endif() + +#Setting application icon for macOS systems +set_target_properties(MitkFlowBench PROPERTIES MACOSX_BUNDLE_ICON_FILE "icon.icns") + +if(APPLE) + install(FILES "icons/icon.icns" DESTINATION "MitkFlowBench.app/Contents/Resources") +endif(APPLE) + +# Add a build time dependency to legacy BlueBerry bundles. +if(MITK_MODULES_ENABLED_PLUGINS) + add_dependencies(MitkFlowBench ${MITK_MODULES_ENABLED_PLUGINS}) +endif() diff --git a/Applications/FlowBench/MitkFlowBench.cpp b/Applications/FlowBench/MitkFlowBench.cpp new file mode 100644 index 0000000000..99b0b82806 --- /dev/null +++ b/Applications/FlowBench/MitkFlowBench.cpp @@ -0,0 +1,81 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#include +#include + +#if defined __GNUC__ && !defined __clang__ +# include +# include +# include +# include +#endif + +class FlowApplication : public mitk::BaseApplication +{ +public: + static const QString ARG_OUTPUTDIR; + static const QString ARG_OUTPUTFORMAT; + + FlowApplication(int argc, char **argv) : mitk::BaseApplication(argc, argv) + { + }; + + ~FlowApplication() = default; + +protected: + /** + * Define command line arguments + * @param options + */ + void defineOptions(Poco::Util::OptionSet &options) override + { + Poco::Util::Option outputDirOption(ARG_OUTPUTDIR.toStdString(), "", "the location for storing persistent application data"); + outputDirOption.argument("").binding(ARG_OUTPUTDIR.toStdString()); + options.addOption(outputDirOption); + + Poco::Util::Option outputFormatOption(ARG_OUTPUTFORMAT.toStdString(), "", "the location for storing persistent application data"); + outputFormatOption.argument("").binding(ARG_OUTPUTFORMAT.toStdString()); + options.addOption(outputFormatOption); + + mitk::BaseApplication::defineOptions(options); + }; +}; + +const QString FlowApplication::ARG_OUTPUTDIR = "flow.outputdir"; +const QString FlowApplication::ARG_OUTPUTFORMAT = "flow.outputextension"; + +int main(int argc, char **argv) +{ + FlowApplication app(argc, argv); + + app.setSingleMode(true); + app.setApplicationName("MITK FlowBench"); + app.setOrganizationName("DKFZ"); + + // Preload the org.blueberry.core.expressions plugin to work around a bug in + // GCC that leads to undefined symbols while loading certain libraries even though + // the symbols are actually defined. +#if defined __GNUC__ && !defined __clang__ + auto library = QFileInfo(argv[0]).dir().path() + "/../lib/plugins/liborg_blueberry_core_expressions.so"; + + if (!QFileInfo(library).exists()) + library = "liborg_blueberry_core_expressions"; + + app.setPreloadLibraries(QStringList() << library); +#endif + + app.setProperty(mitk::BaseApplication::PROP_PRODUCT, "org.mitk.gui.qt.flowapplication.workbench"); + + // Run the workbench. + return app.run(); +} diff --git a/Applications/FlowBench/MitkFlowBench.ini b/Applications/FlowBench/MitkFlowBench.ini new file mode 100644 index 0000000000..ddcca0e804 --- /dev/null +++ b/Applications/FlowBench/MitkFlowBench.ini @@ -0,0 +1,4 @@ +BlueBerry.home=@BLUEBERRY_BINARY_DIR@ +BlueBerry.plugin_dirs=@MITK_MODULES_PLUGIN_OUTPUT_DIRS@ +BlueBerry.provisioning=@MITK_FLOWBENCH_PROVISIONING_FILE@ +BlueBerry.qtplugin_path=@BLUEBERRY_QTPLUGIN_PATH@ diff --git a/Applications/FlowBench/icons/icon.icns b/Applications/FlowBench/icons/icon.icns new file mode 100644 index 0000000000..5afc942282 Binary files /dev/null and b/Applications/FlowBench/icons/icon.icns differ diff --git a/Applications/FlowBench/icons/icon.ico b/Applications/FlowBench/icons/icon.ico new file mode 100644 index 0000000000..27d4c9d1b9 Binary files /dev/null and b/Applications/FlowBench/icons/icon.ico differ diff --git a/Applications/FlowBench/icons/icon.png b/Applications/FlowBench/icons/icon.png new file mode 100644 index 0000000000..b529577fab Binary files /dev/null and b/Applications/FlowBench/icons/icon.png differ diff --git a/Applications/FlowBench/icons/mitkWorkbench.rc b/Applications/FlowBench/icons/mitkWorkbench.rc new file mode 100644 index 0000000000..bb10963fb3 --- /dev/null +++ b/Applications/FlowBench/icons/mitkWorkbench.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON DISCARDABLE "icon.ico" \ No newline at end of file diff --git a/Applications/FlowBench/startMitkFlowBench.bat.in b/Applications/FlowBench/startMitkFlowBench.bat.in new file mode 100644 index 0000000000..4f36eff717 --- /dev/null +++ b/Applications/FlowBench/startMitkFlowBench.bat.in @@ -0,0 +1,2 @@ +PATH=@MITK_RUNTIME_PATH@;%PATH% +@VS_BUILD_TYPE@\MitkFlowBench.exe diff --git a/Applications/FlowBench/target_libraries.cmake b/Applications/FlowBench/target_libraries.cmake new file mode 100644 index 0000000000..554862e5c0 --- /dev/null +++ b/Applications/FlowBench/target_libraries.cmake @@ -0,0 +1,10 @@ + +# A list of plug-in targets which should be automatically enabled +# (or be available in external projects) for this application. + +set(target_libraries + org_blueberry_ui_qt + org_blueberry_ui_qt_help + org_mitk_gui_qt_flowapplication + org_mitk_gui_qt_stdmultiwidgeteditor +) diff --git a/CMake/BuildConfigurations/FlowBenchSegmentation.cmake b/CMake/BuildConfigurations/FlowBenchSegmentation.cmake new file mode 100644 index 0000000000..1bfc32cafe --- /dev/null +++ b/CMake/BuildConfigurations/FlowBenchSegmentation.cmake @@ -0,0 +1,14 @@ +set(MITK_CONFIG_PACKAGES + Qt5 + BLUEBERRY +) + +set(MITK_BUILD_APP_FlowBench ON CACHE BOOL "Build MITK FlowBench" FORCE) + +set(MITK_CONFIG_PLUGINS + org.mitk.gui.qt.stdmultiwidgeteditor + org.mitk.gui.qt.imagenavigator + org.mitk.gui.qt.properties + org.mitk.gui.qt.multilabelsegmentation + org.mitk.gui.qt.flow.segmentation +) diff --git a/CMake/BuildConfigurations/FlowBenchSegmentationRelease.cmake b/CMake/BuildConfigurations/FlowBenchSegmentationRelease.cmake new file mode 100644 index 0000000000..7dfe877a94 --- /dev/null +++ b/CMake/BuildConfigurations/FlowBenchSegmentationRelease.cmake @@ -0,0 +1,10 @@ +include(${CMAKE_CURRENT_LIST_DIR}/FlowBenchSegmentation.cmake) + +set(MITK_VTK_DEBUG_LEAKS OFF CACHE BOOL "Enable VTK Debug Leaks" FORCE) +set(MITK_BUILD_APP_Workbench OFF CACHE BOOL "Build MITK Workbench" FORCE) +set(MITK_WHITELIST "FlowBenchSegmentation" CACHE STRING "MITK FlowBench Whitelist" FORCE) + +find_package(Doxygen REQUIRED) + +# Ensure that the in-application help can be build +set(BLUEBERRY_QT_HELP_REQUIRED ON CACHE BOOL "Required Qt help documentation in plug-ins" FORCE) diff --git a/CMake/Whitelists/FlowBenchSegmentation.cmake b/CMake/Whitelists/FlowBenchSegmentation.cmake new file mode 100644 index 0000000000..41d3c61250 --- /dev/null +++ b/CMake/Whitelists/FlowBenchSegmentation.cmake @@ -0,0 +1,57 @@ +set(enabled_modules + Core + CppMicroServices + DICOMReader + DICOMPM + DataTypesExt + AlgorithmsExt + DICOMQI + Multilabel + SceneSerializationBase + DICOMPMIO + DICOMReaderServices + ContourModel + DICOMSegIO + LegacyGL + MapperExt + SceneSerialization + LegacyIO + IOExt + MultilabelIO + AppUtil + QtWidgets + QtWidgetsExt + Segmentation + SegmentationUI + PlanarFigure + Annotation + IpSegmentation + IpFunc + SurfaceInterpolation + GraphAlgorithms + ImageExtraction + ImageStatistics +) + +set(enabled_plugins +org.blueberry.core.commands +org.blueberry.core.expressions +org.blueberry.core.runtime +org.blueberry.ui.qt +org.blueberry.ui.qt.help +org.blueberry.ui.qt.log +org.mitk.core.ext +org.mitk.core.services +org.mitk.gui.common +org.mitk.gui.qt.application +org.mitk.gui.qt.common +org.mitk.gui.qt.datamanager +org.mitk.gui.qt.flow.segmentation +org.mitk.gui.qt.flowapplication +org.mitk.gui.qt.imagenavigator +org.mitk.gui.qt.multilabelsegmentation +org.mitk.gui.qt.properties +org.mitk.gui.qt.segmentation +org.mitk.gui.qt.stdmultiwidgeteditor +org.mitk.planarfigure +) diff --git a/Documentation/Doxygen/3-DeveloperManual/Application/BlueBerry/BlueBerryIntro.dox b/Documentation/Doxygen/3-DeveloperManual/Application/BlueBerry/BlueBerryIntro.dox index 7323709e08..8730cc4537 100644 --- a/Documentation/Doxygen/3-DeveloperManual/Application/BlueBerry/BlueBerryIntro.dox +++ b/Documentation/Doxygen/3-DeveloperManual/Application/BlueBerry/BlueBerryIntro.dox @@ -1,79 +1,79 @@ /** \page BlueBerryIntro BlueBerry Application Framework BlueBerry is an application framework used in MITK for creating modular and extensible end-user applications. More high-level documentation can be found below: - \subpage BlueBerryWorkbench - \ref BlueBerryExamples Please see the \ref BlueBerryExamples for code examples demonstrating different features of the application framework. The BlueBerry developer reference is available here: - \ref BlueBerryPlugins - \subpage BlueBerryExtPointsIndex \page BlueBerryWorkbench The Workbench: What are Views, Editors, Perspectives? BlueBerry makes use of the Eclipse UI guidlines which state some concepts on how to build up a GUI. The different objects of the platform UI shall be described here: \section Workbench Workbench \li root object of the platform UI \li collection of \ref WorkbenchWindow "windows" \imageMacro{workbench.jpg,"The Workbech",11.64} \section WorkbenchWindow WorkbenchWindow \li has one \ref Workbench-Page "page" -\imageMacro{workbench-window.jpg,"Worbench Windows",8.47} +\imageMacro{workbench-window.jpg,"Workbench Windows",8.47} \section WorkbenchPage Workbench Page \li denotes to the inner part of the \ref WorkbenchWindow "window", that is: everything except the title bar \li may have one menu bar, one toolbar, one shortcut bar, and one statusbar \li has one or more \ref Perspective "perspectives" \imageMacro{workbench-page.jpg,"Workbench Page",8.47} \section Perspective Perspective
  • A visual container for a set of \ref Views "views" and content \ref Editors "editors"
  • Shows \ref Views "views" and \ref Editors "editors" in a certain layout
  • Like a page within a book:
    • Only one perspective is visible at any time
    • There are several perspectives inside a \ref Workbench-Page "page"
\imageMacro{workbench-window-perspective.png,"A Perspective",11.79} \section Part Part \li every \ref Views "View" or \ref Editors "Editor" is called \b Part \subsection Editors Editors \li the StdMultiWidget is an example for an editor in our MainApp \li Contains the primary content, such as a document or image data, which users interact with \li content is the primary focus of attention and a reflection of the primary task \li primary position in the UI \li contributes commands to the workbench's main menu bar and toolbar \li shared in other perspectives \imageMacro{workbench-window-editor-area.png,"Editor Area",11.79} \subsection Views Views
  • support the primary task
    • navigate a hierarchy of information
    • open an \ref Editors "editor"
    • view/edit properties
  • The views exist wholly within the perspective (not shared, one instance at a time)
  • Every functionality is a view- it supports medical image processing
\imageMacro{workbench-window-views.png,"Views",11.79} \section ClassDiagram Summary as class diagram \imageMacro{workbench-class-diagram.jpg,"class diagram",13.74} */ diff --git a/Modules/SceneSerialization/include/mitkSceneIO.h b/Modules/SceneSerialization/include/mitkSceneIO.h index a7f8c1c457..9cdcbe8fbc 100644 --- a/Modules/SceneSerialization/include/mitkSceneIO.h +++ b/Modules/SceneSerialization/include/mitkSceneIO.h @@ -1,115 +1,134 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkSceneIO_h_included #define mitkSceneIO_h_included #include #include "mitkDataStorage.h" #include "mitkNodePredicateBase.h" #include class TiXmlElement; namespace mitk { class BaseData; class PropertyList; class MITKSCENESERIALIZATION_EXPORT SceneIO : public itk::Object { public: mitkClassMacroItkParent(SceneIO, itk::Object); itkFactorylessNewMacro(Self); itkCloneMacro(Self); typedef DataStorage::SetOfObjects FailedBaseDataListType; /** * \brief Load a scene of objects from file * \return DataStorage with all scene objects and their relations. If loading failed, query GetFailedNodes() and * GetFailedProperties() for more detail. * * Attempts to read the provided file and create objects with * parent/child relations into a DataStorage. * * \param filename full filename of the scene file * \param storage If given, this DataStorage is used instead of a newly created one * \param clearStorageFirst If set, the provided DataStorage will be cleared before populating it with the loaded * objects */ virtual DataStorage::Pointer LoadScene(const std::string &filename, DataStorage *storage = nullptr, bool clearStorageFirst = false); + /** + * \brief Load a scene of objects from directory. + * \return DataStorage with all scene objects and their relations. If loading failed, query GetFailedNodes() and + * GetFailedProperties() for more detail. + * + * Does the same like LoadScene, but assumes that the given filename is the index.xml of the scene and the working directory + * is the directory of the given filename. This function can be used to load an already unpacked scene and create objects with + * parent/child relations into a DataStorage. + * + * \param filename full filename of the scene index file + * \param storage If given, this DataStorage is used instead of a newly created one + * \param clearStorageFirst If set, the provided DataStorage will be cleared before populating it with the loaded + * objects + */ + virtual DataStorage::Pointer LoadSceneUnzipped(const std::string &indexfilename, + DataStorage *storage = nullptr, + bool clearStorageFirst = false); + + /** * \brief Save a scene of objects to file * \return True if complete success, false if any problem occurred. Note that a scene file might still be written if false is returned, it just will not contain every node/property. If writing failed, query GetFailedNodes() and GetFailedProperties() for more detail. * * Attempts to write a scene file, which contains the nodes of the * provided DataStorage, their parent/child relations, and properties. * * \param storage a DataStorage containing all nodes that should be saved * \param filename full filename of the scene file * \param predicate defining which items of the datastorage to use and which not */ virtual bool SaveScene(DataStorage::SetOfObjects::ConstPointer sceneNodes, const DataStorage *storage, const std::string &filename); /** * \brief Get a list of nodes (BaseData containers) that failed to be read/written. * * FailedBaseDataListType hold all those nodes that contain BaseData objects * which could not be read or written during the last call to LoadScene or SaveScene. */ const FailedBaseDataListType *GetFailedNodes(); /** * \brief Get a list of properties that failed to be read/written. * * Each entry corresponds to a property which could not * be (de)serialized. The properties may come from either of *
    *
  • The BaseData's PropertyList *
  • The DataNodes's PropertyList *
  • Any of a DataNodes's render window specific PropertyLists *
*/ const PropertyList *GetFailedProperties(); protected: SceneIO(); ~SceneIO() override; std::string CreateEmptyTempDirectory(); TiXmlElement *SaveBaseData(BaseData *data, const std::string &filenamehint, bool &error); TiXmlElement *SavePropertyList(PropertyList *propertyList, const std::string &filenamehint); void OnUnzipError(const void *pSender, std::pair &info); void OnUnzipOk(const void *pSender, std::pair &info); FailedBaseDataListType::Pointer m_FailedNodes; PropertyList::Pointer m_FailedProperties; std::string m_WorkingDirectory; unsigned int m_UnzipErrors; }; } #endif diff --git a/Modules/SceneSerialization/src/mitkSceneIO.cpp b/Modules/SceneSerialization/src/mitkSceneIO.cpp index c6c1c73944..55f48ecb2c 100644 --- a/Modules/SceneSerialization/src/mitkSceneIO.cpp +++ b/Modules/SceneSerialization/src/mitkSceneIO.cpp @@ -1,545 +1,577 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include #include #include #include "mitkBaseDataSerializer.h" #include "mitkPropertyListSerializer.h" #include "mitkSceneIO.h" #include "mitkSceneReader.h" #include "mitkBaseRenderer.h" #include "mitkProgressBar.h" #include "mitkRenderingManager.h" #include "mitkStandaloneDataStorage.h" #include #include #include #include #include #include #include #include "itksys/SystemTools.hxx" mitk::SceneIO::SceneIO() : m_WorkingDirectory(""), m_UnzipErrors(0) { } mitk::SceneIO::~SceneIO() { } std::string mitk::SceneIO::CreateEmptyTempDirectory() { mitk::UIDGenerator uidGen("UID_", 6); // std::string returnValue = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory() + // Poco::Path::separator() + "SceneIOTemp" + uidGen.GetUID(); std::string returnValue = Poco::Path::temp() + "SceneIOTemp" + uidGen.GetUID(); std::string uniquename = returnValue + Poco::Path::separator(); Poco::File tempdir(uniquename); try { bool existsNot = tempdir.createDirectory(); if (!existsNot) { MITK_ERROR << "Warning: Directory already exitsts: " << uniquename << " (choosing another)"; returnValue = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory() + Poco::Path::separator() + "SceneIOTempDirectory" + uidGen.GetUID(); uniquename = returnValue + Poco::Path::separator(); Poco::File tempdir2(uniquename); if (!tempdir2.createDirectory()) { MITK_ERROR << "Warning: Second directory also already exitsts: " << uniquename; } } } catch (std::exception &e) { MITK_ERROR << "Could not create temporary directory " << uniquename << ":" << e.what(); return ""; } return returnValue; } mitk::DataStorage::Pointer mitk::SceneIO::LoadScene(const std::string &filename, DataStorage *pStorage, bool clearStorageFirst) { mitk::LocaleSwitch localeSwitch("C"); // prepare data storage DataStorage::Pointer storage = pStorage; if (storage.IsNull()) { storage = StandaloneDataStorage::New().GetPointer(); } - if (clearStorageFirst) - { - try - { - storage->Remove(storage->GetAll()); - } - catch (...) - { - MITK_ERROR << "DataStorage cannot be cleared properly."; - } - } - // test input filename if (filename.empty()) { MITK_ERROR << "No filename given. Not possible to load scene."; return storage; } // test if filename can be read std::ifstream file(filename.c_str(), std::ios::binary); if (!file.good()) { MITK_ERROR << "Cannot open '" << filename << "' for reading"; return storage; } // get new temporary directory m_WorkingDirectory = CreateEmptyTempDirectory(); if (m_WorkingDirectory.empty()) { MITK_ERROR << "Could not create temporary directory. Cannot open scene files."; return storage; } // unzip all filenames contents to temp dir m_UnzipErrors = 0; Poco::Zip::Decompress unzipper(file, Poco::Path(m_WorkingDirectory)); unzipper.EError += Poco::Delegate>( this, &SceneIO::OnUnzipError); unzipper.EOk += Poco::Delegate>( this, &SceneIO::OnUnzipOk); unzipper.decompressAllFiles(); unzipper.EError -= Poco::Delegate>( this, &SceneIO::OnUnzipError); unzipper.EOk -= Poco::Delegate>( this, &SceneIO::OnUnzipOk); if (m_UnzipErrors) { MITK_ERROR << "There were " << m_UnzipErrors << " errors unzipping '" << filename << "'. Will attempt to read whatever could be unzipped."; } // transcode locale-dependent string m_WorkingDirectory = Poco::Path::transcode (m_WorkingDirectory); - // test if index.xml exists - // parse index.xml with TinyXML - TiXmlDocument document(m_WorkingDirectory + mitk::IOUtil::GetDirectorySeparator() + "index.xml"); - if (!document.LoadFile()) - { - MITK_ERROR << "Could not open/read/parse " << m_WorkingDirectory << mitk::IOUtil::GetDirectorySeparator() - << "index.xml\nTinyXML reports: " << document.ErrorDesc() << std::endl; - return storage; - } - - SceneReader::Pointer reader = SceneReader::New(); - if (!reader->LoadScene(document, m_WorkingDirectory, storage)) - { - MITK_ERROR << "There were errors while loading scene file " << filename << ". Your data may be corrupted"; - } + auto indexFile = m_WorkingDirectory + mitk::IOUtil::GetDirectorySeparator() + "index.xml"; + storage = LoadSceneUnzipped(indexFile, storage, clearStorageFirst); // delete temp directory try { Poco::File deleteDir(m_WorkingDirectory); deleteDir.remove(true); // recursive } catch (...) { MITK_ERROR << "Could not delete temporary directory " << m_WorkingDirectory; } // return new data storage, even if empty or uncomplete (return as much as possible but notify calling method) return storage; } +mitk::DataStorage::Pointer mitk::SceneIO::LoadSceneUnzipped(const std::string &indexfilename, + DataStorage *pStorage, + bool clearStorageFirst) +{ + mitk::LocaleSwitch localeSwitch("C"); + + // prepare data storage + DataStorage::Pointer storage = pStorage; + if (storage.IsNull()) + { + storage = StandaloneDataStorage::New().GetPointer(); + } + + if (clearStorageFirst) + { + try + { + storage->Remove(storage->GetAll()); + } + catch (...) + { + MITK_ERROR << "DataStorage cannot be cleared properly."; + } + } + + // test input filename + if (indexfilename.empty()) + { + MITK_ERROR << "No filename given. Not possible to load scene."; + return storage; + } + + // transcode locale-dependent string + std::string tempfilename; + std::string workingDir; + itksys::SystemTools::SplitProgramPath(indexfilename, workingDir, tempfilename); + + // test if index.xml exists + // parse index.xml with TinyXML + TiXmlDocument document(indexfilename); + if (!document.LoadFile()) + { + MITK_ERROR << "Could not open/read/parse " << workingDir << mitk::IOUtil::GetDirectorySeparator() + << "index.xml\nTinyXML reports: " << document.ErrorDesc() << std::endl; + return storage; + } + + SceneReader::Pointer reader = SceneReader::New(); + if (!reader->LoadScene(document, workingDir, storage)) + { + MITK_ERROR << "There were errors while loading scene file " << indexfilename << ". Your data may be corrupted"; + } + + // return new data storage, even if empty or uncomplete (return as much as possible but notify calling method) + return storage; +} + bool mitk::SceneIO::SaveScene(DataStorage::SetOfObjects::ConstPointer sceneNodes, const DataStorage *storage, const std::string &filename) { if (!sceneNodes) { MITK_ERROR << "No set of nodes given. Not possible to save scene."; return false; } if (!storage) { MITK_ERROR << "No data storage given. Not possible to save scene."; // \TODO: Technically, it would be possible to // save the nodes without their relation return false; } if (filename.empty()) { MITK_ERROR << "No filename given. Not possible to save scene."; return false; } mitk::LocaleSwitch localeSwitch("C"); try { m_FailedNodes = DataStorage::SetOfObjects::New(); m_FailedProperties = PropertyList::New(); // start XML DOM TiXmlDocument document; auto *decl = new TiXmlDeclaration( "1.0", "UTF-8", ""); // TODO what to write here? encoding? standalone would mean that we provide a DTD somewhere... document.LinkEndChild(decl); auto *version = new TiXmlElement("Version"); version->SetAttribute("Writer", __FILE__); version->SetAttribute("Revision", "$Revision: 17055 $"); version->SetAttribute("FileVersion", 1); document.LinkEndChild(version); // DataStorage::SetOfObjects::ConstPointer sceneNodes = storage->GetSubset( predicate ); if (sceneNodes.IsNull()) { MITK_WARN << "Saving empty scene to " << filename; } else { if (sceneNodes->size() == 0) { MITK_WARN << "Saving empty scene to " << filename; } MITK_INFO << "Storing scene with " << sceneNodes->size() << " objects to " << filename; m_WorkingDirectory = CreateEmptyTempDirectory(); if (m_WorkingDirectory.empty()) { MITK_ERROR << "Could not create temporary directory. Cannot create scene files."; return false; } ProgressBar::GetInstance()->AddStepsToDo(sceneNodes->size()); // find out about dependencies typedef std::map UIDMapType; typedef std::map> SourcesMapType; UIDMapType nodeUIDs; // for dependencies: ID of each node SourcesMapType sourceUIDs; // for dependencies: IDs of a node's parent nodes UIDGenerator nodeUIDGen("OBJECT_"); for (auto iter = sceneNodes->begin(); iter != sceneNodes->end(); ++iter) { DataNode *node = iter->GetPointer(); if (!node) continue; // unlikely event that we get a nullptr pointer as an object for saving. just ignore // generate UIDs for all source objects DataStorage::SetOfObjects::ConstPointer sourceObjects = storage->GetSources(node); for (auto sourceIter = sourceObjects->begin(); sourceIter != sourceObjects->end(); ++sourceIter) { if (std::find(sceneNodes->begin(), sceneNodes->end(), *sourceIter) == sceneNodes->end()) continue; // source is not saved, so don't generate a UID for this source // create a uid for the parent object if (nodeUIDs[*sourceIter].empty()) { nodeUIDs[*sourceIter] = nodeUIDGen.GetUID(); } // store this dependency for writing sourceUIDs[node].push_back(nodeUIDs[*sourceIter]); } if (nodeUIDs[node].empty()) { nodeUIDs[node] = nodeUIDGen.GetUID(); } } // write out objects, dependencies and properties for (auto iter = sceneNodes->begin(); iter != sceneNodes->end(); ++iter) { DataNode *node = iter->GetPointer(); if (node) { auto *nodeElement = new TiXmlElement("node"); std::string filenameHint(node->GetName()); filenameHint = itksys::SystemTools::MakeCindentifier( filenameHint.c_str()); // escape filename <-- only allow [A-Za-z0-9_], replace everything else with _ // store dependencies auto searchUIDIter = nodeUIDs.find(node); if (searchUIDIter != nodeUIDs.end()) { // store this node's ID nodeElement->SetAttribute("UID", searchUIDIter->second.c_str()); } auto searchSourcesIter = sourceUIDs.find(node); if (searchSourcesIter != sourceUIDs.end()) { // store all source IDs for (auto sourceUIDIter = searchSourcesIter->second.begin(); sourceUIDIter != searchSourcesIter->second.end(); ++sourceUIDIter) { auto *uidElement = new TiXmlElement("source"); uidElement->SetAttribute("UID", sourceUIDIter->c_str()); nodeElement->LinkEndChild(uidElement); } } // store basedata if (BaseData *data = node->GetData()) { // std::string filenameHint( node->GetName() ); bool error(false); TiXmlElement *dataElement(SaveBaseData(data, filenameHint, error)); // returns a reference to a file if (error) { m_FailedNodes->push_back(node); } // store basedata properties PropertyList *propertyList = data->GetPropertyList(); if (propertyList && !propertyList->IsEmpty()) { TiXmlElement *baseDataPropertiesElement( SavePropertyList(propertyList, filenameHint + "-data")); // returns a reference to a file dataElement->LinkEndChild(baseDataPropertiesElement); } nodeElement->LinkEndChild(dataElement); } // store all renderwindow specific propertylists mitk::DataNode::PropertyListKeyNames propertyListKeys = node->GetPropertyListNames(); for (auto renderWindowName : propertyListKeys) { PropertyList *propertyList = node->GetPropertyList(renderWindowName); if (propertyList && !propertyList->IsEmpty()) { TiXmlElement *renderWindowPropertiesElement( SavePropertyList(propertyList, filenameHint + "-" + renderWindowName)); // returns a reference to a file renderWindowPropertiesElement->SetAttribute("renderwindow", renderWindowName); nodeElement->LinkEndChild(renderWindowPropertiesElement); } } // don't forget the renderwindow independent list PropertyList *propertyList = node->GetPropertyList(); if (propertyList && !propertyList->IsEmpty()) { TiXmlElement *propertiesElement( SavePropertyList(propertyList, filenameHint + "-node")); // returns a reference to a file nodeElement->LinkEndChild(propertiesElement); } document.LinkEndChild(nodeElement); } else { MITK_WARN << "Ignoring nullptr node during scene serialization."; } ProgressBar::GetInstance()->Progress(); } // end for all nodes } // end if sceneNodes std::string defaultLocale_WorkingDirectory = Poco::Path::transcode( m_WorkingDirectory ); if (!document.SaveFile(defaultLocale_WorkingDirectory + Poco::Path::separator() + "index.xml")) { MITK_ERROR << "Could not write scene to " << defaultLocale_WorkingDirectory << Poco::Path::separator() << "index.xml" << "\nTinyXML reports '" << document.ErrorDesc() << "'"; return false; } else { try { Poco::File deleteFile(filename.c_str()); if (deleteFile.exists()) { deleteFile.remove(); } // create zip at filename std::ofstream file(filename.c_str(), std::ios::binary | std::ios::out); if (!file.good()) { MITK_ERROR << "Could not open a zip file for writing: '" << filename << "'"; return false; } else { Poco::Zip::Compress zipper(file, true); Poco::Path tmpdir(m_WorkingDirectory); zipper.addRecursive(tmpdir); zipper.close(); } try { Poco::File deleteDir(m_WorkingDirectory); deleteDir.remove(true); // recursive } catch (...) { MITK_ERROR << "Could not delete temporary directory " << m_WorkingDirectory; return false; // ok? } } catch (std::exception &e) { MITK_ERROR << "Could not create ZIP file from " << m_WorkingDirectory << "\nReason: " << e.what(); return false; } return true; } } catch (std::exception &e) { MITK_ERROR << "Caught exception during saving temporary files to disk. Error description: '" << e.what() << "'"; return false; } } TiXmlElement *mitk::SceneIO::SaveBaseData(BaseData *data, const std::string &filenamehint, bool &error) { assert(data); error = true; // find correct serializer // the serializer must // - create a file containing all information to recreate the BaseData object --> needs to know where to put this // file (and a filename?) // - TODO what to do about writers that creates one file per timestep? auto *element = new TiXmlElement("data"); element->SetAttribute("type", data->GetNameOfClass()); // construct name of serializer class std::string serializername(data->GetNameOfClass()); serializername += "Serializer"; std::list thingsThatCanSerializeThis = itk::ObjectFactoryBase::CreateAllInstance(serializername.c_str()); if (thingsThatCanSerializeThis.size() < 1) { MITK_ERROR << "No serializer found for " << data->GetNameOfClass() << ". Skipping object"; } for (auto iter = thingsThatCanSerializeThis.begin(); iter != thingsThatCanSerializeThis.end(); ++iter) { if (auto *serializer = dynamic_cast(iter->GetPointer())) { serializer->SetData(data); serializer->SetFilenameHint(filenamehint); std::string defaultLocale_WorkingDirectory = Poco::Path::transcode( m_WorkingDirectory ); serializer->SetWorkingDirectory(defaultLocale_WorkingDirectory); try { std::string writtenfilename = serializer->Serialize(); element->SetAttribute("file", writtenfilename); error = false; } catch (std::exception &e) { MITK_ERROR << "Serializer " << serializer->GetNameOfClass() << " failed: " << e.what(); } break; } } return element; } TiXmlElement *mitk::SceneIO::SavePropertyList(PropertyList *propertyList, const std::string &filenamehint) { assert(propertyList); // - TODO what to do about shared properties (same object in two lists or behind several keys)? auto *element = new TiXmlElement("properties"); // construct name of serializer class PropertyListSerializer::Pointer serializer = PropertyListSerializer::New(); serializer->SetPropertyList(propertyList); serializer->SetFilenameHint(filenamehint); std::string defaultLocale_WorkingDirectory = Poco::Path::transcode( m_WorkingDirectory ); serializer->SetWorkingDirectory(defaultLocale_WorkingDirectory); try { std::string writtenfilename = serializer->Serialize(); element->SetAttribute("file", writtenfilename); PropertyList::Pointer failedProperties = serializer->GetFailedProperties(); if (failedProperties.IsNotNull()) { // move failed properties to global list m_FailedProperties->ConcatenatePropertyList(failedProperties, true); } } catch (std::exception &e) { MITK_ERROR << "Serializer " << serializer->GetNameOfClass() << " failed: " << e.what(); } return element; } const mitk::SceneIO::FailedBaseDataListType *mitk::SceneIO::GetFailedNodes() { return m_FailedNodes.GetPointer(); } const mitk::PropertyList *mitk::SceneIO::GetFailedProperties() { return m_FailedProperties; } void mitk::SceneIO::OnUnzipError(const void * /*pSender*/, std::pair &info) { ++m_UnzipErrors; MITK_ERROR << "Error while unzipping: " << info.second; } void mitk::SceneIO::OnUnzipOk(const void * /*pSender*/, std::pair & /*info*/) { // MITK_INFO << "Unzipped ok: " << info.second.toString(); } diff --git a/Plugins/PluginList.cmake b/Plugins/PluginList.cmake index ff2ccda265..5cf41c4112 100644 --- a/Plugins/PluginList.cmake +++ b/Plugins/PluginList.cmake @@ -1,93 +1,95 @@ # Plug-ins must be ordered according to their dependencies set(MITK_PLUGINS org.blueberry.core.runtime:ON org.blueberry.core.expressions:OFF org.blueberry.core.commands:OFF org.blueberry.core.jobs:OFF org.blueberry.ui.qt:OFF org.blueberry.ui.qt.help:ON org.blueberry.ui.qt.log:ON org.blueberry.ui.qt.objectinspector:OFF org.mitk.core.services:ON org.mitk.gui.common:ON org.mitk.planarfigure:ON org.mitk.core.ext:OFF org.mitk.core.jobs:OFF org.mitk.gui.qt.application:ON org.mitk.gui.qt.ext:OFF org.mitk.gui.qt.extapplication:OFF org.mitk.gui.qt.common:ON org.mitk.gui.qt.stdmultiwidgeteditor:ON org.mitk.gui.qt.mxnmultiwidgeteditor:OFF org.mitk.gui.qt.common.legacy:OFF org.mitk.gui.qt.cmdlinemodules:OFF org.mitk.gui.qt.chartExample:OFF org.mitk.gui.qt.datamanager:ON org.mitk.gui.qt.datamanagerlight:OFF org.mitk.gui.qt.datastorageviewertest:OFF org.mitk.gui.qt.properties:ON org.mitk.gui.qt.basicimageprocessing:OFF org.mitk.gui.qt.dicom:OFF org.mitk.gui.qt.dicominspector:OFF org.mitk.gui.qt.dosevisualization:OFF org.mitk.gui.qt.geometrytools:OFF org.mitk.gui.qt.igtexamples:OFF org.mitk.gui.qt.igttracking:OFF org.mitk.gui.qt.lasercontrol:OFF org.mitk.gui.qt.openigtlink:OFF org.mitk.gui.qt.imagecropper:OFF org.mitk.gui.qt.imagenavigator:ON org.mitk.gui.qt.viewnavigator:OFF org.mitk.gui.qt.materialeditor:OFF org.mitk.gui.qt.measurementtoolbox:OFF org.mitk.gui.qt.moviemaker:OFF org.mitk.gui.qt.pointsetinteraction:OFF org.mitk.gui.qt.pointsetinteractionmultispectrum:OFF org.mitk.gui.qt.python:OFF org.mitk.gui.qt.remeshing:OFF org.mitk.gui.qt.segmentation:OFF org.mitk.gui.qt.aicpregistration:OFF org.mitk.gui.qt.renderwindowmanager:OFF org.mitk.gui.qt.semanticrelations:OFF org.mitk.gui.qt.toftutorial:OFF org.mitk.gui.qt.tofutil:OFF org.mitk.gui.qt.tubegraph:OFF org.mitk.gui.qt.ugvisualization:OFF org.mitk.gui.qt.photoacoustics.pausviewer:OFF org.mitk.gui.qt.photoacoustics.pausmotioncompensation:OFF org.mitk.gui.qt.photoacoustics.imageprocessing:OFF org.mitk.gui.qt.photoacoustics.simulation:OFF org.mitk.gui.qt.photoacoustics.spectralunmixing:OFF org.mitk.gui.qt.ultrasound:OFF org.mitk.gui.qt.volumevisualization:OFF org.mitk.gui.qt.eventrecorder:OFF org.mitk.gui.qt.xnat:OFF org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation:OFF org.mitk.gui.qt.spectrocamrecorder:OFF org.mitk.gui.qt.classificationsegmentation:OFF org.mitk.gui.qt.overlaymanager:OFF org.mitk.gui.qt.igt.app.hummelprotocolmeasurements:OFF org.mitk.gui.qt.multilabelsegmentation:OFF org.mitk.matchpoint.core.helper:OFF org.mitk.gui.qt.matchpoint.algorithm.browser:OFF org.mitk.gui.qt.matchpoint.algorithm.control:OFF org.mitk.gui.qt.matchpoint.mapper:OFF org.mitk.gui.qt.matchpoint.framereg:OFF org.mitk.gui.qt.matchpoint.visualizer:OFF org.mitk.gui.qt.matchpoint.evaluator:OFF org.mitk.gui.qt.matchpoint.manipulator:OFF org.mitk.gui.qt.preprocessing.resampling:OFF org.mitk.gui.qt.radiomics:OFF org.mitk.gui.qt.cest:OFF org.mitk.gui.qt.fit.demo:OFF org.mitk.gui.qt.fit.inspector:OFF org.mitk.gui.qt.fit.genericfitting:OFF org.mitk.gui.qt.pharmacokinetics.mri:OFF org.mitk.gui.qt.pharmacokinetics.pet:OFF org.mitk.gui.qt.pharmacokinetics.simulation:OFF org.mitk.gui.qt.pharmacokinetics.curvedescriptor:OFF org.mitk.gui.qt.pharmacokinetics.concentration.mri:OFF + org.mitk.gui.qt.flowapplication:OFF + org.mitk.gui.qt.flow.segmentation:OFF ) diff --git a/Plugins/org.blueberry.ui.qt/src/berryIEditorInput.h b/Plugins/org.blueberry.ui.qt/src/berryIEditorInput.h index 0b8009e5c8..64305a12b3 100644 --- a/Plugins/org.blueberry.ui.qt/src/berryIEditorInput.h +++ b/Plugins/org.blueberry.ui.qt/src/berryIEditorInput.h @@ -1,132 +1,132 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef BERRYIEDITORINPUT_H_ #define BERRYIEDITORINPUT_H_ #include #include #include #include namespace berry { struct IPersistableElement; /** * \ingroup org_blueberry_ui_qt * * IEditorInput is a light weight descriptor of editor input, * like a file name but more abstract. It is not a model. It is a description of * the model source for an IEditorPart. *

* Clients implementing this editor input interface must override * Object#operator==(const Object*) to answer true * for two inputs that are - * the same. The IWorbenchPage.openEditor APIs are dependent on + * the same. The IWorkbenchPage.openEditor APIs are dependent on * this to find an editor with the same input. *

*

* Clients should extend this interface to declare new types of editor inputs. *

*

* An editor input is passed to an editor via the IEditorPart.init * method. Due to the wide range of valid editor inputs, it is not possible to * define generic methods for getting and setting bytes. *

*

* Editor input must implement the IAdaptable interface; * extensions are managed by the platform's adapter manager. *

*

* Please note that it is important that the editor input be light weight. * Within the workbench, the navigation history tends to hold on to editor * inputs as a means of reconstructing the editor at a later time. The * navigation history can hold on to quite a few inputs (i.e., the default is * fifty). The actual data model should probably not be held in the input. *

* * * @see org.blueberry.ui.IEditorPart * @see org.blueberry.ui.IWorkbenchPage#openEditor(IEditorInput, String) * @see org.blueberry.ui.IWorkbenchPage#openEditor(IEditorInput, String, boolean) */ struct BERRY_UI_QT IEditorInput : public virtual Object, public virtual IAdaptable { berryObjectMacro(berry::IEditorInput); ~IEditorInput() override; /** * Returns whether the editor input exists. *

* This method is primarily used to determine if an editor input should * appear in the "File Most Recently Used" menu. An editor input will appear * in the list until the return value of exists becomes * false or it drops off the bottom of the list. * * @return true if the editor input exists; * false otherwise */ virtual bool Exists() const = 0; /** * Returns the icon for this input. * * @return the icon for this input; may be null icon if * there is no image. */ virtual QIcon GetIcon() const = 0; /** * Returns the name of this editor input for display purposes. *

* For instance, when the input is from a file, the return value would * ordinarily be just the file name. * * @return the name string; never null; */ virtual QString GetName() const = 0; /** * Returns an object that can be used to save the state of this editor * input. * * @return the persistable element, or null if this editor * input cannot be persisted */ virtual const IPersistableElement* GetPersistable() const = 0; /** * Returns the tool tip text for this editor input. This text is used to * differentiate between two input with the same name. For instance, * MyClass.java in folder X and MyClass.java in folder Y. The format of the * text varies between input types. *

* * @return the tool tip text; never null. */ virtual QString GetToolTipText() const = 0; /** * Returns true if two editor inputs are the same * */ bool operator==(const Object* o) const override = 0; }; } #endif /*BERRYIEDITORINPUT_H_*/ diff --git a/Plugins/org.mitk.gui.qt.flow.segmentation/CMakeLists.txt b/Plugins/org.mitk.gui.qt.flow.segmentation/CMakeLists.txt new file mode 100644 index 0000000000..b9e2f34736 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flow.segmentation/CMakeLists.txt @@ -0,0 +1,7 @@ +project(org_mitk_gui_qt_flow_segmentation) + +mitk_create_plugin( + EXPORT_DIRECTIVE MITK_GUI_QT_FLOW_SEGMENTATION_EXPORT + EXPORTED_INCLUDE_SUFFIXES src + MODULE_DEPENDS MitkQtWidgets MitkMultilabel +) diff --git a/Plugins/org.mitk.gui.qt.flow.segmentation/documentation/UserManual/Manual.dox b/Plugins/org.mitk.gui.qt.flow.segmentation/documentation/UserManual/Manual.dox new file mode 100644 index 0000000000..b97c29b247 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flow.segmentation/documentation/UserManual/Manual.dox @@ -0,0 +1,8 @@ +/** +\page org_mitk_gui_qt_flow_segmentation The Segmentation Flow + +The view offers a simple way to directly save the first segmentation found in the data storage. +The save location will be determined given the application argument flags (--flow.outputdir and --flow.outputextension). +If no flags where set when starting the application the current working directory and "nrrd" as extensions will be used. +*/ + diff --git a/Plugins/org.mitk.gui.qt.flow.segmentation/documentation/doxygen/modules.dox b/Plugins/org.mitk.gui.qt.flow.segmentation/documentation/doxygen/modules.dox new file mode 100644 index 0000000000..ad89625f85 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flow.segmentation/documentation/doxygen/modules.dox @@ -0,0 +1,10 @@ +/** + \defgroup org_mitk_gui_qt_flow_segmentation org.mitk.gui.qt.flow.segmentation + \ingroup MITKPlugins + + Plugin introduces the perspective QmitkFlowSegmentationPerspective that is used as org.mitk.qt.flowapplication.defaultperspective for the flow application. + (This ensures the correct views opened for direct segmentation). + Further the plugin introduces the the view "Segmentation Flow Control" that can be used to easily save the segmentations. + +*/ + diff --git a/Plugins/org.mitk.gui.qt.flow.segmentation/files.cmake b/Plugins/org.mitk.gui.qt.flow.segmentation/files.cmake new file mode 100644 index 0000000000..2d5b0a93a5 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flow.segmentation/files.cmake @@ -0,0 +1,46 @@ +set(SRC_CPP_FILES + +) + +set(INTERNAL_CPP_FILES + org_mitk_gui_qt_flow_segmentation_Activator.cpp + QmitkSegmentationFlowControlView.cpp + perspectives/QmitkFlowSegmentationPerspective.cpp +) + +set(UI_FILES + src/internal/QmitkSegmentationFlowControlView.ui +) + +set(MOC_H_FILES + src/internal/org_mitk_gui_qt_flow_segmentation_Activator.h + src/internal/QmitkSegmentationFlowControlView.h + src/internal/perspectives/QmitkFlowSegmentationPerspective.h +) + +# list of resource files which can be used by the plug-in +# system without loading the plug-ins shared library, +# for example the icon used in the menu and tabs for the +# plug-in views in the workbench +set(CACHED_RESOURCE_FILES + resources/icon.svg + plugin.xml + resources/perspectives/segmentation_icon.svg +) + +# list of Qt .qrc files which contain additional resources +# specific to this plugin +set(QRC_FILES + +) + +set(CPP_FILES ) + +foreach(file ${SRC_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/${file}) +endforeach(file ${SRC_CPP_FILES}) + +foreach(file ${INTERNAL_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/internal/${file}) +endforeach(file ${INTERNAL_CPP_FILES}) + diff --git a/Plugins/org.mitk.gui.qt.flow.segmentation/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.flow.segmentation/manifest_headers.cmake new file mode 100644 index 0000000000..724db97aef --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flow.segmentation/manifest_headers.cmake @@ -0,0 +1,5 @@ +set(Plugin-Name "Flow Segmentation Control") +set(Plugin-Version "0.1") +set(Plugin-Vendor "DKFZ, Medical Image Computing") +set(Plugin-ContactAddress "http://www.mitk.org") +set(Require-Plugin org.mitk.gui.qt.common org.mitk.gui.qt.multilabelsegmentation org.mitk.gui.qt.flowapplication) diff --git a/Plugins/org.mitk.gui.qt.flow.segmentation/plugin.xml b/Plugins/org.mitk.gui.qt.flow.segmentation/plugin.xml new file mode 100644 index 0000000000..393d53ce91 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flow.segmentation/plugin.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.flow.segmentation/resources/icon.svg b/Plugins/org.mitk.gui.qt.flow.segmentation/resources/icon.svg new file mode 100644 index 0000000000..ad0f523422 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flow.segmentation/resources/icon.svg @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.flow.segmentation/resources/perspectives/segmentation_icon.svg b/Plugins/org.mitk.gui.qt.flow.segmentation/resources/perspectives/segmentation_icon.svg new file mode 100644 index 0000000000..ad0f523422 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flow.segmentation/resources/perspectives/segmentation_icon.svg @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/QmitkSegmentationFlowControlView.cpp b/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/QmitkSegmentationFlowControlView.cpp new file mode 100644 index 0000000000..4027f2b176 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/QmitkSegmentationFlowControlView.cpp @@ -0,0 +1,126 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#include "org_mitk_gui_qt_flow_segmentation_Activator.h" + +// Blueberry +#include +#include + +#include + +//MITK +#include "mitkLabelSetImage.h" +#include "mitkNodePredicateAnd.h" +#include "mitkNodePredicateNot.h" +#include "mitkNodePredicateProperty.h" +#include "mitkNodePredicateDataType.h" +#include "mitkIOUtil.h" + +// Qmitk +#include "QmitkSegmentationFlowControlView.h" + +// Qt +#include +#include + +const std::string QmitkSegmentationFlowControlView::VIEW_ID = "org.mitk.views.flow.control"; + +QmitkSegmentationFlowControlView::QmitkSegmentationFlowControlView() + : m_Parent(nullptr) +{ + auto nodePredicate = mitk::NodePredicateAnd::New(); + nodePredicate->AddPredicate(mitk::TNodePredicateDataType::New()); + nodePredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); + m_SegmentationPredicate = nodePredicate; + + m_OutputDir = QString::fromStdString(itksys::SystemTools::GetCurrentWorkingDirectory()); + m_FileExtension = "nrrd"; +} + +void QmitkSegmentationFlowControlView::SetFocus() +{ + m_Controls.btnStoreAndAccept->setFocus(); +} + +void QmitkSegmentationFlowControlView::CreateQtPartControl(QWidget* parent) +{ + // create GUI widgets from the Qt Designer's .ui file + m_Controls.setupUi(parent); + + m_Parent = parent; + + connect(m_Controls.btnStoreAndAccept, SIGNAL(clicked()), this, SLOT(OnAcceptButtonPushed())); + + m_Controls.labelStored->setVisible(false); + UpdateControls(); + + auto arguments = QCoreApplication::arguments(); + + bool isFlagFound = false; + for (auto arg : arguments) + { + if (isFlagFound) + { + m_OutputDir = arg; + break; + } + isFlagFound = arg.startsWith("--flow.outputdir"); + } + isFlagFound = false; + for (auto arg : arguments) + { + if (isFlagFound) + { + m_FileExtension = arg; + break; + } + isFlagFound = arg.startsWith("--flow.outputextension"); + } + + m_OutputDir = QDir::fromNativeSeparators(m_OutputDir); +} + +void QmitkSegmentationFlowControlView::OnAcceptButtonPushed() +{ + auto nodes = this->GetDataStorage()->GetSubset(m_SegmentationPredicate); + + for (auto node : *nodes) + { + QString outputpath = m_OutputDir + "/" + QString::fromStdString(node->GetName()) + "." + m_FileExtension; + outputpath = QDir::toNativeSeparators(QDir::cleanPath(outputpath)); + mitk::IOUtil::Save(node->GetData(), outputpath.toStdString()); + } + + m_Controls.labelStored->setVisible(true); +} + +void QmitkSegmentationFlowControlView::UpdateControls() +{ + auto nodes = this->GetDataStorage()->GetSubset(m_SegmentationPredicate); + m_Controls.btnStoreAndAccept->setEnabled(!nodes->empty()); +}; + +void QmitkSegmentationFlowControlView::NodeAdded(const mitk::DataNode* /*node*/) +{ + UpdateControls(); +}; + +void QmitkSegmentationFlowControlView::NodeChanged(const mitk::DataNode* /*node*/) +{ + UpdateControls(); +}; + +void QmitkSegmentationFlowControlView::NodeRemoved(const mitk::DataNode* /*node*/) +{ + UpdateControls(); +}; diff --git a/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/QmitkSegmentationFlowControlView.h b/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/QmitkSegmentationFlowControlView.h new file mode 100644 index 0000000000..1d8cc9f646 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/QmitkSegmentationFlowControlView.h @@ -0,0 +1,74 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + + +#ifndef __Q_MITK_MATCHPOINT_MAPPER_H +#define __Q_MITK_MATCHPOINT_MAPPER_H + +#include +#include + +#include "mitkNodePredicateBase.h" + +#include "ui_QmitkSegmentationFlowControlView.h" + +/*! + \brief QmitkSegmentationFlowControlView + + Class that "controls" the segmentation view. It offers the possibility to accept a segmentation. + Accepting the segmentation stores the segmentation to the given working directory. + + The working directory is specified by command line arguments. If no commandline flag is set the current working directory will be used. +*/ +class QmitkSegmentationFlowControlView : 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: + + static const std::string VIEW_ID; + + /** + * Creates smartpointer typedefs + */ + berryObjectMacro(QmitkSegmentationFlowControlView) + + QmitkSegmentationFlowControlView(); + + void CreateQtPartControl(QWidget *parent) override; + +protected slots: + + void OnAcceptButtonPushed(); + +protected: + void SetFocus() override; + + void NodeAdded(const mitk::DataNode* node) override; + void NodeChanged(const mitk::DataNode* node) override; + void NodeRemoved(const mitk::DataNode* node) override; + + void UpdateControls(); + + Ui::SegmentationFlowControlView m_Controls; + +private: + QWidget *m_Parent; + mitk::NodePredicateBase::Pointer m_SegmentationPredicate; + QString m_OutputDir; + QString m_FileExtension; +}; + +#endif // MatchPoint_h + diff --git a/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/QmitkSegmentationFlowControlView.ui b/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/QmitkSegmentationFlowControlView.ui new file mode 100644 index 0000000000..05d90c45ef --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/QmitkSegmentationFlowControlView.ui @@ -0,0 +1,99 @@ + + + SegmentationFlowControlView + + + + 0 + 0 + 392 + 324 + + + + + 20 + + + 5 + + + 5 + + + 5 + + + 5 + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 50 + + + + Accept segmentation + + + + + + + <html><head/><body><p><span style=" font-size:12pt;">Segmentation stored! Flow on...</span></p></body></html> + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + 5 + + + 5 + + + true + + + true + + + true + + + diff --git a/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/org_mitk_gui_qt_flow_segmentation_Activator.cpp b/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/org_mitk_gui_qt_flow_segmentation_Activator.cpp new file mode 100644 index 0000000000..692c89b6b7 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/org_mitk_gui_qt_flow_segmentation_Activator.cpp @@ -0,0 +1,38 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + + +#include "org_mitk_gui_qt_flow_segmentation_Activator.h" + +#include "QmitkSegmentationFlowControlView.h" +#include "perspectives/QmitkFlowSegmentationPerspective.h" + +ctkPluginContext* org_mitk_gui_qt_flow_segmentation_Activator::m_Context = nullptr; + +void org_mitk_gui_qt_flow_segmentation_Activator::start(ctkPluginContext* context) +{ + BERRY_REGISTER_EXTENSION_CLASS(QmitkSegmentationFlowControlView, context) + BERRY_REGISTER_EXTENSION_CLASS(QmitkFlowSegmentationPerspective, context); + + m_Context = context; +} + +void org_mitk_gui_qt_flow_segmentation_Activator::stop(ctkPluginContext* context) +{ + Q_UNUSED(context) + m_Context = nullptr; +} + +ctkPluginContext* org_mitk_gui_qt_flow_segmentation_Activator::GetContext() +{ + return m_Context; +} diff --git a/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/org_mitk_gui_qt_flow_segmentation_Activator.h b/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/org_mitk_gui_qt_flow_segmentation_Activator.h new file mode 100644 index 0000000000..efc456eb1a --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/org_mitk_gui_qt_flow_segmentation_Activator.h @@ -0,0 +1,39 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + + +#ifndef org_mitk_gui_qt_flow_segmentation_Activator_h +#define org_mitk_gui_qt_flow_segmentation_Activator_h + +#include + +class org_mitk_gui_qt_flow_segmentation_Activator : + public QObject, public ctkPluginActivator +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_flow_segmentation") + Q_INTERFACES(ctkPluginActivator) + +public: + + void start(ctkPluginContext* context) override; + void stop(ctkPluginContext* context) override; + + static ctkPluginContext* GetContext(); + +private: + + static ctkPluginContext* m_Context; + +}; + +#endif // org_mitk_gui_qt_flow_segmentation_Activator_h diff --git a/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/perspectives/QmitkFlowSegmentationPerspective.cpp b/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/perspectives/QmitkFlowSegmentationPerspective.cpp new file mode 100644 index 0000000000..6cdfb38ae0 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/perspectives/QmitkFlowSegmentationPerspective.cpp @@ -0,0 +1,43 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#include "QmitkFlowSegmentationPerspective.h" +#include "berryIViewLayout.h" + +QmitkFlowSegmentationPerspective::QmitkFlowSegmentationPerspective() +{ +} + +void QmitkFlowSegmentationPerspective::CreateInitialLayout(berry::IPageLayout::Pointer layout) +{ + QString editorArea = layout->GetEditorArea(); + + layout->AddView("org.mitk.views.multilabelsegmentation", berry::IPageLayout::LEFT, 0.3f, editorArea); + + berry::IViewLayout::Pointer lo = layout->GetViewLayout("org.mitk.views.multilabelsegmentation"); + lo->SetCloseable(false); + + layout->AddStandaloneView("org.mitk.views.flow.control",false, berry::IPageLayout::RIGHT, 0.6f, editorArea); + lo = layout->GetViewLayout("org.mitk.views.flow.control"); + lo->SetCloseable(false); + + layout->AddView("org.mitk.views.imagenavigator", + berry::IPageLayout::TOP, 0.1f, "org.mitk.views.flow.control"); + + berry::IPlaceholderFolderLayout::Pointer bottomFolder = layout->CreatePlaceholderFolder("bottom", berry::IPageLayout::BOTTOM, 0.7f, editorArea); + bottomFolder->AddPlaceholder("org.blueberry.views.logview"); + + berry::IPlaceholderFolderLayout::Pointer rightFolder = layout->CreatePlaceholderFolder("right", berry::IPageLayout::RIGHT, 0.3f, editorArea); + rightFolder->AddPlaceholder("org.mitk.views.datamanager"); + + layout->AddPerspectiveShortcut("org.mitk.qt.flowapplication.defaultperspective"); +} diff --git a/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/perspectives/QmitkFlowSegmentationPerspective.h b/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/perspectives/QmitkFlowSegmentationPerspective.h new file mode 100644 index 0000000000..0af7d690f0 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/perspectives/QmitkFlowSegmentationPerspective.h @@ -0,0 +1,32 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + + +#ifndef QMITKFLOWSEGMENTATIONPERSPECTIVE_H_ +#define QMITKFLOWSEGMENTATIONPERSPECTIVE_H_ + +#include + +class QmitkFlowSegmentationPerspective : public QObject, public berry::IPerspectiveFactory +{ + Q_OBJECT + Q_INTERFACES(berry::IPerspectiveFactory) + +public: + + QmitkFlowSegmentationPerspective(); + + void CreateInitialLayout(berry::IPageLayout::Pointer layout) override; + +}; + +#endif /* QMITKFLOWSEGMENTATIONPERSPECTIVE_H_ */ diff --git a/Plugins/org.mitk.gui.qt.flowapplication/CMakeLists.txt b/Plugins/org.mitk.gui.qt.flowapplication/CMakeLists.txt new file mode 100644 index 0000000000..68e309ef49 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flowapplication/CMakeLists.txt @@ -0,0 +1,17 @@ +project(org_mitk_gui_qt_flowapplication) + +# see bug-19679 +set(additional_dependencies "") + +if(APPLE) + set(additional_dependencies Qt5|DBus) +endif() + + +mitk_create_plugin( + EXPORT_DIRECTIVE MITK_QT_FLOW_BENCH_APP_EXPORT + EXPORTED_INCLUDE_SUFFIXES src + MODULE_DEPENDS + PRIVATE MitkQtWidgetsExt MitkSceneSerialization MitkAppUtil + PACKAGE_DEPENDS Qt5|WebEngineWidgets ${additional_dependencies} +) diff --git a/Plugins/org.mitk.gui.qt.flowapplication/documentation/UserManual/QmitkMITKWorkbenchUserManual.dox b/Plugins/org.mitk.gui.qt.flowapplication/documentation/UserManual/QmitkMITKWorkbenchUserManual.dox new file mode 100644 index 0000000000..2c34762cb5 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flowapplication/documentation/UserManual/QmitkMITKWorkbenchUserManual.dox @@ -0,0 +1,17 @@ +/** +\page org_mitkworkbench Using The MITK Workbench + +\section QMitkMitkWorkbenchManualOverview What is the MITK Workbench + +The MITK Workbench is used by developers. As such the kind and number of views it contains is highly variable and dependent on the specific build. Typically it contains no special perspectives and whatever views the developer deemed desirable. Be aware, that it may contain views which are work in progress and may behave erratically. + +If you have been given such an executable by someone, please refer to the appropriate section of the online documentation for up to date usage information on any module. + +Nightly online documentation + + +If you are using a nightly installer, the MITK Workbench will contain nearly all views available in MITK and as such most likely will seem confusing. Again the list of modules might be a good starting point if you want to have a rough idea of what could be of interest to you. + +For a basic guide to MITK see \ref MITKUserManualPage . + +*/ diff --git a/Plugins/org.mitk.gui.qt.flowapplication/documentation/UserManual/VisualizationPerspective.dox b/Plugins/org.mitk.gui.qt.flowapplication/documentation/UserManual/VisualizationPerspective.dox new file mode 100644 index 0000000000..aa5c1ef521 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flowapplication/documentation/UserManual/VisualizationPerspective.dox @@ -0,0 +1,13 @@ +/** +\page org_mitk_gui_qt_extapplication_perspectives_visualizations The Visualization Perspective + +\imageMacro{eye.png,"The icon of the visualization perspective",1} + +This perspective bundles some views which can be used to generate expressive images for presentations or publications. + +Using \nondependentPluginLink{org_mitk_views_volumevisualization,org.mitk.gui.qt.volumevisualization, The Volume Visualization Plugin} you can display the image data as a 3D volume, where each voxel is colored depending on its value. This enables you to easily generate understandable 3D representations of your data. + +With \nondependentPluginLink{org_mitk_views_screenshotmaker,org.mitk.gui.qt.moviemaker, The Screenshot Maker Plugin} you can generate high quality screenshots of the different display windows. + +With \nondependentPluginLink{org_mitk_views_moviemaker,org.mitk.gui.qt.moviemaker, The Moviemaker Plugin} you can capture videos of your data and automatically step through slices or rotate it in the 3D window. +*/ \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.flowapplication/documentation/UserManual/eye.png b/Plugins/org.mitk.gui.qt.flowapplication/documentation/UserManual/eye.png new file mode 100644 index 0000000000..6e6e216171 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.flowapplication/documentation/UserManual/eye.png differ diff --git a/Plugins/org.mitk.gui.qt.flowapplication/documentation/doxygen/modules.dox b/Plugins/org.mitk.gui.qt.flowapplication/documentation/doxygen/modules.dox new file mode 100644 index 0000000000..4172a9d45b --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flowapplication/documentation/doxygen/modules.dox @@ -0,0 +1,16 @@ +/** + \defgroup org_mitk_gui_qt_mitkworkbench org.mitk.gui.qt.mitkworkbench + \ingroup MITKPlugins + + \brief This plug-in is responsible for initializing the MITK Workbench. + +*/ + +/** + \defgroup org_mitk_gui_qt_mitkworkbench_internal Internal + \ingroup org_mitk_gui_qt_mitkworkbench + + \brief This subcategory includes the internal classes of the org.mitk.gui.qt.mitkworkbench plugin. Other + plugins must not rely on these classes. They contain implementation details and their interface + may change at any time. We mean it. +*/ diff --git a/Plugins/org.mitk.gui.qt.flowapplication/files.cmake b/Plugins/org.mitk.gui.qt.flowapplication/files.cmake new file mode 100644 index 0000000000..56a4d17a2d --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flowapplication/files.cmake @@ -0,0 +1,42 @@ +set(SRC_CPP_FILES +) + +set(INTERNAL_CPP_FILES + QmitkFlowApplication.cpp + QmitkFlowApplicationPlugin.cpp + QmitkFlowApplicationWorkbenchAdvisor.cpp + QmitkFlowApplicationWorkbenchWindowAdvisor.cpp + QmitkExtFileSaveProjectAction.cpp +) + +set(MOC_H_FILES + src/internal/QmitkFlowApplication.h + src/internal/QmitkFlowApplicationPlugin.h + src/internal/QmitkFlowApplicationWorkbenchWindowAdvisor.h + src/internal/QmitkFlowApplicationWorkbenchWindowAdvisorHack.h + src/internal/QmitkExtFileSaveProjectAction.h +) + +set(CACHED_RESOURCE_FILES +# list of resource files which can be used by the plug-in +# system without loading the plug-ins shared library, +# for example the icon used in the menu and tabs for the +# plug-in views in the workbench + plugin.xml + resources/icon_research.xpm +) + +set(QRC_FILES +resources/QmitkFlowApplication.qrc +) + +set(CPP_FILES ) + +foreach(file ${SRC_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/${file}) +endforeach(file ${SRC_CPP_FILES}) + +foreach(file ${INTERNAL_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/internal/${file}) +endforeach(file ${INTERNAL_CPP_FILES}) + diff --git a/Plugins/org.mitk.gui.qt.flowapplication/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.flowapplication/manifest_headers.cmake new file mode 100644 index 0000000000..0892740d80 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flowapplication/manifest_headers.cmake @@ -0,0 +1,5 @@ +set(Plugin-Name "MITK Flow Application") +set(Plugin-Version "1.0.0") +set(Plugin-Vendor "DKFZ, Medical Image Computing") +set(Plugin-ContactAddress "http://www.mitk.org") +set(Require-Plugin org.mitk.core.ext org.mitk.gui.qt.application) diff --git a/Plugins/org.mitk.gui.qt.flowapplication/plugin.xml b/Plugins/org.mitk.gui.qt.flowapplication/plugin.xml new file mode 100644 index 0000000000..065ceb26fe --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flowapplication/plugin.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.flowapplication/resources/QmitkFlowApplication.qrc b/Plugins/org.mitk.gui.qt.flowapplication/resources/QmitkFlowApplication.qrc new file mode 100644 index 0000000000..4348c5cf18 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flowapplication/resources/QmitkFlowApplication.qrc @@ -0,0 +1,5 @@ + + + icon.png + + diff --git a/Plugins/org.mitk.gui.qt.flowapplication/resources/icon.png b/Plugins/org.mitk.gui.qt.flowapplication/resources/icon.png new file mode 100644 index 0000000000..91a2e7ec94 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.flowapplication/resources/icon.png differ diff --git a/Plugins/org.mitk.gui.qt.flowapplication/resources/icon_research.xpm b/Plugins/org.mitk.gui.qt.flowapplication/resources/icon_research.xpm new file mode 100644 index 0000000000..562f2cc934 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flowapplication/resources/icon_research.xpm @@ -0,0 +1,249 @@ +/* XPM */ +static char *ResearchApp___[] = { +/* columns rows colors chars-per-pixel */ +"48 48 195 2", +" c #112327", +". c #1C2325", +"X c #18282C", +"o c #002730", +"O c #062D36", +"+ c #092C34", +"@ c #032E38", +"# c #192E34", +"$ c #00353F", +"% c #0C323B", +"& c #113037", +"* c #13353C", +"= c #19353C", +"- c #17383F", +"; c #19393F", +": c #2B3637", +"> c #22383E", +", c #003441", +"< c #093741", +"1 c #003845", +"2 c #0C3A45", +"3 c #023D4B", +"4 c #0D3E49", +"5 c #143B44", +"6 c #1A3C43", +"7 c #123E49", +"8 c #0C414F", +"9 c #14414C", +"0 c #1B424C", +"q c #004354", +"w c #094451", +"e c #0E4856", +"r c #004C5E", +"t c #084858", +"y c #124451", +"u c #194651", +"i c #114956", +"p c #1B4954", +"a c #1A4E59", +"s c #1B515E", +"d c #24464F", +"f c #384244", +"g c #30484E", +"h c #214B55", +"j c #224E58", +"k c #29555F", +"l c #31575F", +"z c #3C555A", +"x c #004F62", +"c c #005165", +"v c #00596F", +"b c #135261", +"n c #185765", +"m c #185A6A", +"M c #005C73", +"N c #2A5762", +"B c #2C5E6A", +"V c #325760", +"C c #355A63", +"Z c #3F5D65", +"A c #345F69", +"S c #00637A", +"D c #2A616E", +"F c #34616B", +"G c #3B636C", +"H c #356975", +"J c #3C6A75", +"K c #306D7C", +"L c #2E707E", +"P c #3E727D", +"I c #414D4F", +"U c #4B595B", +"Y c #4F5E60", +"T c #486167", +"R c #536466", +"E c #546668", +"W c #57686A", +"Q c #446C74", +"! c #496E75", +"~ c #526E74", +"^ c #5D6E71", +"/ c #4C747C", +"( c #50767C", +") c #5C777A", +"_ c #54787F", +"` c #5D787C", +"' c #617476", +"] c #637678", +"[ c #65797C", +"{ c #687B7E", +"} c #006B84", +"| c #006E88", +" . c #00738F", +".. c #007A97", +"X. c #007B99", +"o. c #2D7281", +"O. c #2D7788", +"+. c #2B7D8F", +"@. c #357684", +"#. c #3E7280", +"$. c #387988", +"%. c #457681", +"&. c #467983", +"*. c #487983", +"=. c #407B89", +"-. c #4A7D89", +";. c #557C83", +":. c #5B7C81", +">. c #537F89", +",. c #6A7E80", +"<. c #2A8297", +"1. c #2E879C", +"2. c #0084A4", +"3. c #008BAB", +"4. c #008FB1", +"5. c #0390B3", +"6. c #0096BA", +"7. c #0099BF", +"8. c #298FA7", +"9. c #2892AB", +"0. c #279EBA", +"q. c #29A2BE", +"w. c #4C828F", +"e. c #54858F", +"r. c #5B838C", +"t. c #4F8490", +"y. c #5E8A92", +"u. c #5B8F9A", +"i. c #5E919B", +"p. c #668187", +"a. c #62838A", +"s. c #698689", +"d. c #66898E", +"f. c #72878A", +"g. c #74898D", +"h. c #648B93", +"j. c #6C8B91", +"k. c #778D90", +"l. c #788F91", +"z. c #6F9096", +"x. c #64939C", +"c. c #68939A", +"v. c #729297", +"b. c #77959A", +"n. c #7F9A9C", +"m. c #5B95A1", +"M. c #6197A4", +"N. c #699BA5", +"B. c #759CA3", +"V. c #7C9DA2", +"C. c #75A4AD", +"Z. c #7BA4AC", +"A. c #77A9B2", +"S. c #009CC1", +"D. c #00A5CC", +"F. c #00A7D0", +"G. c #00AAD3", +"H. c #26A5C3", +"J. c #26A8C7", +"K. c #26AECE", +"L. c #26B4D6", +"P. c #7CB6C2", +"I. c #819A9D", +"U. c #829DA1", +"Y. c #84A0A4", +"T. c #8BA4A6", +"R. c #89A7AC", +"E. c #8EA8AC", +"W. c #91ABAF", +"Q. c #81A8B0", +"!. c #8BADB2", +"~. c #93AEB2", +"^. c #8FB0B6", +"/. c #96B1B5", +"(. c #9BB7BC", +"). c #9AB9BD", +"_. c #8BBCC6", +"`. c #9EBFC3", +"'. c #A2BFC4", +"]. c #A3C1C5", +"[. c #A5C3C8", +"{. c #AACACE", +"}. c #B3CBCE", +"|. c #AECED3", +" X c #B1D2D6", +".X c #B4D5DA", +"XX c #B7D8DD", +"oX c #B8D9DE", +"OX c #BBDDE2", +"+X c #BFE2E7", +"@X c #C1E2E6", +"#X c #CAE3E7", +"$X c #CEE7E9", +"%X c #D1E8EA", +"&X c None", +/* pixels */ +"&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X= 6 p u ; X &X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X9 % h %.>.r.r.-.H * 7 + &X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X&X&X&X&X&X&X9 0 d.{.+XOXXX X X|.|.OXV.F 4 = &X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X&X&X&X&X; 7 j.OX XI.g.{ &X&X&X&X&X{ l./.!.B 7 &X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X&X&X&X5 j `. Xl.{ &X&X&X&X&X&X&X&X&X&X&X{ g./ 8 &X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X&X&X5 k oX~.[ &X&X&X&X&X&X&X&X&X&X&X&X&X&X&X] ( 9 &X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X&X; j |.l.&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X{ A 7 &X&X&X&X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X&X8 (.g.&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&Xa & &X&X&X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X9 ( I.&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&XF K z 4 &X&X&X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X9 (.&X&X&X&X&X&X&X&X;.*.E &X&X&X&X&X&X&X&XH 8.1.H.~ p & &X&X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X5 *.{ &X&X&X&X&X&Xr.i._.OXP.t.^ &X&X&X&XJ <.L.L.+.A &XV 3 &X&X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&Xi ) &X&X&X&X&X&Xu.z.#XU.a.&X&Xm.] &XQ O.K.L.9.H &X&X&X&X4 &X&X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X% ' &X&X&X&X&Xr.B.&X$Xc.m.&X&X&Xi.G H.L.0.K &X&X&X&X&X&Xi . &X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X9 ^ &X&X&X&X&XC.T.%X&Xx.m.&X&X&XM.@.J.L &X&X&X&X&X&X&X&Xb X &X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X s &X&X&X&X&X&XC.}.&X&Xy.x.&X&X&X&X;.Y &X&X&X&X&X&X&X&X&Xm # &X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&Xy &X&X&X&X&Xd.R.$XR.j.v.` n.&X&X&Xx.) &X&X&X&X&X&X&X&X&Xn > &X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X< &X&X&X&X&X>.!.%XV.@X+X+Xp.).&X&Xx.' &X&X&X&X&X&X&X&X&Xy R &X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X@ &X&X&X&X&X,.Q.#Xb.+X+X+X).v.&X&Xd.&X&X&X&X&X&X&X&X&X&X5 I.&X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X3 d &X&X&X&X&XA.~./.n. X+X^.U.&Xi.f.&X&X&X&X&X&X&X&X&X! i f.&X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&XO e &X&X&X&X&Xi.U.&XZ.s.p.z.&X&Xe.[ &X&X&X&X&X&X&X&X&XD C ] &X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X3 &X&X&X&X&Xa.N.W.&X&X&X&X&Xt.^ &X&X&X&X&X&X&X&X&X&X9 [.U &X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X% y &X&X&X&X&Xr.u.U.&X&X&Xw.T &X&X&X&X&X&X&X&X&X&XB l [.&X&X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X: w &X&X&X&X&X&X&X-.P =.#.^ &X&X&X&X&X&X&X&X&X&X/ 9 OX] &X&X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X&Xg w &X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&Xu V.|.&X&X&X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X&X&XV 4 &X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&Xp d.+XW &X&X&X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X&X&XU / 4 &X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&XQ u j.+Xl.&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X&X&X&XW Y.8 a &X&X&X&X&X&X&X&X&X&X&X&X&XN 0 j.@.D &X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X&X&X&X&XR .XG 5 u Q &X&X&X&X&X&X&XH j 0 p.y.4.G.G.} &X&X&X&X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X&X&X&X&X&XI (.OXV.N 7 & 6 6 ; = p C U.+X+Xo.G.G.G.G.c &X&X&X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X&X&X&X&X&X&X&XU l.OX+X+X.X.X+XOX@X@X+X X[ t G.G.G.G.F.3 &X&X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&Xf ^ U.'.OX.X'.~.,.Y &X&X&X| G.G.G.G.S., &X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X2.G.G.G.G.3.&X&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X, S.G.G.G.G. .&X&X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X3 F.G.G.G.F.M &X&X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&Xc G.G.G.G.F.q &X&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X} G.G.G.G.D.1 &X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X2.F.G.G.G.5.&X&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X$ 7.G.G.G.G.X.&X&X&X&X&X&X&X", +"&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&Xq D.G.G.G.G.S &X&X&X&X&X&X", +"&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&Xc F.G.G.G.G.r &X&X&X&X&X", +"&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X} G.G.G.G.D.3 &X&X&X&X", +"&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X2.G.G.G.G.6.1 &X&X&X", +"&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X$ 6.G.G.F.X. .&X&X&X", +"&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X3 D.4.M 6.2.1 &X&X", +"&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&Xr } G.G.F.6.o &X", +"&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&Xq G.F.F.3.&X&X", +"&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&XM 7.3.3 &X&X", +"&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X&X" +}; diff --git a/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkExtFileSaveProjectAction.cpp b/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkExtFileSaveProjectAction.cpp new file mode 100644 index 0000000000..f420a3e2e5 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkExtFileSaveProjectAction.cpp @@ -0,0 +1,177 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + + +#include "QmitkExtFileSaveProjectAction.h" + +#include "QmitkFlowApplicationPlugin.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "berryPlatform.h" + + +QmitkExtFileSaveProjectAction::QmitkExtFileSaveProjectAction(berry::IWorkbenchWindow::Pointer window) + : QAction(nullptr) + , m_Window(nullptr) +{ + this->Init(window.GetPointer()); +} + +QmitkExtFileSaveProjectAction::QmitkExtFileSaveProjectAction(berry::IWorkbenchWindow* window) + : QAction(nullptr) + , m_Window(nullptr) +{ + this->Init(window); +} + +void QmitkExtFileSaveProjectAction::Init(berry::IWorkbenchWindow* window) +{ + m_Window = window; + this->setText("&Save Project..."); + this->setToolTip("Save content of Data Manager as a .mitk project file"); + + this->connect(this, SIGNAL(triggered(bool)), this, SLOT(Run())); +} + + +void QmitkExtFileSaveProjectAction::Run() +{ + try + { + /** + * @brief stores the last path of last saved file + */ + static QString m_LastPath; + + mitk::IDataStorageReference::Pointer dsRef; + + { + ctkPluginContext* context = QmitkFlowApplicationPlugin::GetDefault()->GetPluginContext(); + mitk::IDataStorageService* dss = nullptr; + ctkServiceReference dsServiceRef = context->getServiceReference(); + if (dsServiceRef) + { + dss = context->getService(dsServiceRef); + } + + if (!dss) + { + QString msg = "IDataStorageService service not available. Unable to open files."; + MITK_WARN << msg.toStdString(); + QMessageBox::warning(QApplication::activeWindow(), "Unable to open files", msg); + return; + } + + // Get the active data storage (or the default one, if none is active) + dsRef = dss->GetDataStorage(); + context->ungetService(dsServiceRef); + } + + mitk::DataStorage::Pointer storage = dsRef->GetDataStorage(); + + QString dialogTitle = "Save MITK Scene (%1)"; + QString fileName = QFileDialog::getSaveFileName(nullptr, + dialogTitle.arg(dsRef->GetLabel()), + m_LastPath, + "MITK scene files (*.mitk)", + nullptr ); + + if (fileName.isEmpty() ) + return; + + // remember the location + m_LastPath = fileName; + + if ( fileName.right(5) != ".mitk" ) + fileName += ".mitk"; + + mitk::SceneIO::Pointer sceneIO = mitk::SceneIO::New(); + + mitk::ProgressBar::GetInstance()->AddStepsToDo(2); + + /* Build list of nodes that should be saved */ + mitk::NodePredicateNot::Pointer isNotHelperObject = + mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true))); + mitk::DataStorage::SetOfObjects::ConstPointer nodesToBeSaved = storage->GetSubset(isNotHelperObject); + + if ( !sceneIO->SaveScene( nodesToBeSaved, storage, fileName.toStdString() ) ) + { + QMessageBox::information(nullptr, + "Scene saving", + "Scene could not be written completely. Please check the log.", + QMessageBox::Ok); + + } + mitk::ProgressBar::GetInstance()->Progress(2); + + mitk::SceneIO::FailedBaseDataListType::ConstPointer failedNodes = sceneIO->GetFailedNodes(); + if (!failedNodes->empty()) + { + std::stringstream ss; + ss << "The following nodes could not be serialized:" << std::endl; + for ( mitk::SceneIO::FailedBaseDataListType::const_iterator iter = failedNodes->begin(); + iter != failedNodes->end(); + ++iter ) + { + ss << " - "; + if ( mitk::BaseData* data =(*iter)->GetData() ) + { + ss << data->GetNameOfClass(); + } + else + { + ss << "(nullptr)"; + } + + ss << " contained in node '" << (*iter)->GetName() << "'" << std::endl; + } + + MITK_WARN << ss.str(); + } + + mitk::PropertyList::ConstPointer failedProperties = sceneIO->GetFailedProperties(); + if (!failedProperties->GetMap()->empty()) + { + std::stringstream ss; + ss << "The following properties could not be serialized:" << std::endl; + const mitk::PropertyList::PropertyMap* propmap = failedProperties->GetMap(); + for ( mitk::PropertyList::PropertyMap::const_iterator iter = propmap->begin(); + iter != propmap->end(); + ++iter ) + { + ss << " - " << iter->second->GetNameOfClass() << " associated to key '" << iter->first << "'" << std::endl; + } + + MITK_WARN << ss.str(); + } + } + catch (std::exception& e) + { + MITK_ERROR << "Exception caught during scene saving: " << e.what(); + } +} diff --git a/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkExtFileSaveProjectAction.h b/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkExtFileSaveProjectAction.h new file mode 100644 index 0000000000..3514dc4c5b --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkExtFileSaveProjectAction.h @@ -0,0 +1,47 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#ifndef QmitkExtFileSaveProjectAction_H_ +#define QmitkExtFileSaveProjectAction_H_ + +#include + +#include + +#include + +namespace berry { +struct IWorkbenchWindow; +} + +class MITK_QT_FLOW_BENCH_APP_EXPORT QmitkExtFileSaveProjectAction : public QAction +{ + Q_OBJECT + +public: + + QmitkExtFileSaveProjectAction(berry::SmartPointer window); + QmitkExtFileSaveProjectAction(berry::IWorkbenchWindow* window); + +protected slots: + + void Run(); + +private: + + void Init(berry::IWorkbenchWindow* window); + + berry::IWorkbenchWindow* m_Window; +}; + + +#endif /*QmitkExtFileSaveProjectAction_H_*/ diff --git a/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplication.cpp b/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplication.cpp new file mode 100644 index 0000000000..e024bcb764 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplication.cpp @@ -0,0 +1,39 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#include "QmitkFlowApplication.h" + +#include + +#include "QmitkFlowApplicationWorkbenchAdvisor.h" + +QmitkFlowApplication::QmitkFlowApplication() +{ + +} + +QVariant QmitkFlowApplication::Start(berry::IApplicationContext* /*context*/) +{ + QScopedPointer display(berry::PlatformUI::CreateDisplay()); + + QScopedPointer wbAdvisor(new QmitkFlowApplicationWorkbenchAdvisor()); + int code = berry::PlatformUI::CreateAndRunWorkbench(display.data(), wbAdvisor.data()); + + // exit the application with an appropriate return code + return code == berry::PlatformUI::RETURN_RESTART + ? EXIT_RESTART : EXIT_OK; +} + +void QmitkFlowApplication::Stop() +{ + +} diff --git a/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplication.h b/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplication.h new file mode 100644 index 0000000000..d2e52b1acc --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplication.h @@ -0,0 +1,33 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + + +#ifndef QMITKFLOWAPPLICATIONLICATION_H_ +#define QMITKFLOWAPPLICATIONLICATION_H_ + +#include + + +class QmitkFlowApplication : public QObject, public berry::IApplication +{ + Q_OBJECT + Q_INTERFACES(berry::IApplication) + +public: + + QmitkFlowApplication(); + + QVariant Start(berry::IApplicationContext* context) override; + void Stop() override; +}; + +#endif /*QMITKFLOWAPPLICATIONLICATION_H_*/ diff --git a/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplicationPlugin.cpp b/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplicationPlugin.cpp new file mode 100644 index 0000000000..dcba3917e1 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplicationPlugin.cpp @@ -0,0 +1,203 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#include "QmitkFlowApplicationPlugin.h" +#include "QmitkFlowApplication.h" + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + + +QmitkFlowApplicationPlugin* QmitkFlowApplicationPlugin::inst = nullptr; + +QmitkFlowApplicationPlugin::QmitkFlowApplicationPlugin() +{ + inst = this; +} + +QmitkFlowApplicationPlugin::~QmitkFlowApplicationPlugin() +{ +} + +QmitkFlowApplicationPlugin* QmitkFlowApplicationPlugin::GetDefault() +{ + return inst; +} + +void QmitkFlowApplicationPlugin::start(ctkPluginContext* context) +{ + berry::AbstractUICTKPlugin::start(context); + + this->_context = context; + + QtWidgetsExtRegisterClasses(); + + BERRY_REGISTER_EXTENSION_CLASS(QmitkFlowApplication, context); + + ctkServiceReference cmRef = context->getServiceReference(); + ctkConfigurationAdmin* configAdmin = nullptr; + if (cmRef) + { + configAdmin = context->getService(cmRef); + } + + // Use the CTK Configuration Admin service to configure the BlueBerry help system + if (configAdmin) + { + ctkConfigurationPtr conf = configAdmin->getConfiguration("org.blueberry.services.help", QString()); + ctkDictionary helpProps; + helpProps.insert("homePage", "qthelp://org.mitk.gui.qt.flowapplication/bundle/index.html"); + conf->update(helpProps); + context->ungetService(cmRef); + } + else + { + MITK_WARN << "Configuration Admin service unavailable, cannot set home page url."; + } + + if (qApp->metaObject()->indexOfSignal("messageReceived(QByteArray)") > -1) + { + connect(qApp, SIGNAL(messageReceived(QByteArray)), this, SLOT(handleIPCMessage(QByteArray))); + } + + // This is a potentially long running operation. + loadDataFromDisk(berry::Platform::GetApplicationArgs(), true); +} + +void QmitkFlowApplicationPlugin::stop(ctkPluginContext* context) +{ + Q_UNUSED(context) + + this->_context = nullptr; +} + +ctkPluginContext* QmitkFlowApplicationPlugin::GetPluginContext() const +{ + return _context; +} + +void QmitkFlowApplicationPlugin::loadDataFromDisk(const QStringList &arguments, bool globalReinit) +{ + if (!arguments.empty()) + { + ctkServiceReference serviceRef = _context->getServiceReference(); + if (serviceRef) + { + mitk::IDataStorageService* dataStorageService = _context->getService(serviceRef); + mitk::DataStorage::Pointer dataStorage = dataStorageService->GetDefaultDataStorage()->GetDataStorage(); + + int argumentsAdded = 0; + for (int i = 0; i < arguments.size(); ++i) + { + if (arguments[i].startsWith("--flow.")) + { //By convention no further files are specified as soon as a flow arguments comes. + break; + } + else if (arguments[i].right(5) == ".mitk") + { + mitk::SceneIO::Pointer sceneIO = mitk::SceneIO::New(); + + bool clearDataStorageFirst(false); + mitk::ProgressBar::GetInstance()->AddStepsToDo(2); + dataStorage = sceneIO->LoadScene(arguments[i].toLocal8Bit().constData(), dataStorage, clearDataStorageFirst); + mitk::ProgressBar::GetInstance()->Progress(2); + argumentsAdded++; + } + else if (arguments[i].right(15) == ".mitksceneindex") + { + mitk::SceneIO::Pointer sceneIO = mitk::SceneIO::New(); + + bool clearDataStorageFirst(false); + mitk::ProgressBar::GetInstance()->AddStepsToDo(2); + dataStorage = sceneIO->LoadSceneUnzipped(arguments[i].toLocal8Bit().constData(), dataStorage, clearDataStorageFirst); + mitk::ProgressBar::GetInstance()->Progress(2); + argumentsAdded++; + } + else + { + try + { + const std::string path(arguments[i].toStdString()); + auto addedNodes = mitk::IOUtil::Load(path, *dataStorage); + + for (auto const node : *addedNodes) + { + node->SetIntProperty("layer", argumentsAdded); + } + + argumentsAdded++; + } + catch (...) + { + MITK_WARN << "Failed to load command line argument: " << arguments[i].toStdString(); + } + } + } // end for each command line argument + + if (argumentsAdded > 0 && globalReinit) + { + // calculate bounding geometry + mitk::RenderingManager::GetInstance()->InitializeViews(dataStorage->ComputeBoundingGeometry3D()); + } + } + else + { + MITK_ERROR << "A service reference for mitk::IDataStorageService does not exist"; + } + } +} + +void QmitkFlowApplicationPlugin::handleIPCMessage(const QByteArray& msg) +{ + QDataStream ds(msg); + QString msgType; + ds >> msgType; + + // we only handle messages containing command line arguments + if (msgType != "$cmdLineArgs") return; + + // activate the current workbench window + berry::IWorkbenchWindow::Pointer window = + berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow(); + + QMainWindow* mainWindow = + static_cast (window->GetShell()->GetControl()); + + mainWindow->setWindowState(mainWindow->windowState() & ~Qt::WindowMinimized); + mainWindow->raise(); + mainWindow->activateWindow(); + + QStringList args; + ds >> args; + + loadDataFromDisk(args, false); +} diff --git a/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplicationPlugin.h b/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplicationPlugin.h new file mode 100644 index 0000000000..b2cb08a37c --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplicationPlugin.h @@ -0,0 +1,57 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + + +#ifndef QMITKFLOWAPPLICATIONLICATIONPLUGIN_H_ +#define QMITKFLOWAPPLICATIONLICATIONPLUGIN_H_ + +#include + +#include + +class QmitkFlowApplicationPlugin : public berry::AbstractUICTKPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_flowapplication") + Q_INTERFACES(ctkPluginActivator) + +public: + + QmitkFlowApplicationPlugin(); + ~QmitkFlowApplicationPlugin() override; + + static QmitkFlowApplicationPlugin* GetDefault(); + + ctkPluginContext* GetPluginContext() const; + + void start(ctkPluginContext*) override; + void stop(ctkPluginContext* context) override; + + QString GetQtHelpCollectionFile() const; + +private: + + void loadDataFromDisk(const QStringList& args, bool globalReinit); + void startNewInstance(const QStringList& args, const QStringList &files); + +private Q_SLOTS: + + void handleIPCMessage(const QByteArray &msg); + +private: + + static QmitkFlowApplicationPlugin* inst; + + ctkPluginContext* _context; +}; + +#endif /* QMITKFLOWAPPLICATIONLICATIONPLUGIN_H_ */ diff --git a/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplicationWorkbenchAdvisor.cpp b/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplicationWorkbenchAdvisor.cpp new file mode 100644 index 0000000000..28432e595e --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplicationWorkbenchAdvisor.cpp @@ -0,0 +1,57 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + + +#include "QmitkFlowApplicationWorkbenchAdvisor.h" +#include "internal/QmitkFlowApplicationPlugin.h" + +#include "QmitkFlowApplicationWorkbenchWindowAdvisor.h" + +const QString QmitkFlowApplicationWorkbenchAdvisor::DEFAULT_PERSPECTIVE_ID = + "org.mitk.qt.flowapplication.defaultperspective"; + +void +QmitkFlowApplicationWorkbenchAdvisor::Initialize(berry::IWorkbenchConfigurer::Pointer configurer) +{ + berry::QtWorkbenchAdvisor::Initialize(configurer); + + configurer->SetSaveAndRestore(true); +} + +berry::WorkbenchWindowAdvisor* +QmitkFlowApplicationWorkbenchAdvisor::CreateWorkbenchWindowAdvisor( + berry::IWorkbenchWindowConfigurer::Pointer configurer) +{ + QmitkFlowApplicationWorkbenchWindowAdvisor* advisor = new + QmitkFlowApplicationWorkbenchWindowAdvisor(this, configurer); + + // Exclude the help perspective from org.blueberry.ui.qt.help from + // the normal perspective list. + // The perspective gets a dedicated menu entry in the help menu + QList excludePerspectives; + excludePerspectives.push_back("org.blueberry.perspectives.help"); + advisor->SetPerspectiveExcludeList(excludePerspectives); + + // Exclude some views from the normal view list + QList excludeViews; + excludeViews.push_back("org.mitk.views.modules"); + excludeViews.push_back( "org.blueberry.ui.internal.introview" ); + advisor->SetViewExcludeList(excludeViews); + + advisor->SetWindowIcon(":/org.mitk.gui.qt.flowapplication/icon.png"); + return advisor; +} + +QString QmitkFlowApplicationWorkbenchAdvisor::GetInitialWindowPerspectiveId() +{ + return DEFAULT_PERSPECTIVE_ID; +} diff --git a/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplicationWorkbenchAdvisor.h b/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplicationWorkbenchAdvisor.h new file mode 100644 index 0000000000..7f9af02ca3 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplicationWorkbenchAdvisor.h @@ -0,0 +1,34 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + + +#ifndef QMITKFLOWAPPLICATIONWORKBENCHADVISOR_H_ +#define QMITKFLOWAPPLICATIONWORKBENCHADVISOR_H_ + +#include + +class QmitkFlowApplicationWorkbenchAdvisor: public berry::QtWorkbenchAdvisor +{ +public: + + static const QString DEFAULT_PERSPECTIVE_ID; // = "org.mitk.extapp.defaultperspective" + + void Initialize(berry::IWorkbenchConfigurer::Pointer configurer) override; + + berry::WorkbenchWindowAdvisor* CreateWorkbenchWindowAdvisor( + berry::IWorkbenchWindowConfigurer::Pointer configurer) override; + + QString GetInitialWindowPerspectiveId() override; + +}; + +#endif /*QMITKFLOWAPPLICATIONWORKBENCHADVISOR_H_*/ diff --git a/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplicationWorkbenchWindowAdvisor.cpp b/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplicationWorkbenchWindowAdvisor.cpp new file mode 100644 index 0000000000..826357b8b4 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplicationWorkbenchWindowAdvisor.cpp @@ -0,0 +1,1146 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + + +#include "QmitkFlowApplicationWorkbenchWindowAdvisor.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "QmitkExtFileSaveProjectAction.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +// UGLYYY +#include "QmitkFlowApplicationWorkbenchWindowAdvisorHack.h" +#include "QmitkFlowApplicationPlugin.h" +#include "mitkUndoController.h" +#include "mitkVerboseLimitedLinearUndo.h" +#include +#include +#include +#include +#include +#include + +QmitkFlowApplicationWorkbenchWindowAdvisorHack* QmitkFlowApplicationWorkbenchWindowAdvisorHack::undohack = + new QmitkFlowApplicationWorkbenchWindowAdvisorHack(); + +QString QmitkFlowApplicationWorkbenchWindowAdvisor::QT_SETTINGS_FILENAME = "QtSettings.ini"; + +class PartListenerForTitle: public berry::IPartListener +{ +public: + + PartListenerForTitle(QmitkFlowApplicationWorkbenchWindowAdvisor* wa) + : windowAdvisor(wa) + { + } + + Events::Types GetPartEventTypes() const override + { + return Events::ACTIVATED | Events::BROUGHT_TO_TOP | Events::CLOSED + | Events::HIDDEN | Events::VISIBLE; + } + + void PartActivated(const berry::IWorkbenchPartReference::Pointer& ref) override + { + if (ref.Cast ()) + { + windowAdvisor->UpdateTitle(false); + } + } + + void PartBroughtToTop(const berry::IWorkbenchPartReference::Pointer& ref) override + { + if (ref.Cast ()) + { + windowAdvisor->UpdateTitle(false); + } + } + + void PartClosed(const berry::IWorkbenchPartReference::Pointer& /*ref*/) override + { + windowAdvisor->UpdateTitle(false); + } + + void PartHidden(const berry::IWorkbenchPartReference::Pointer& ref) override + { + if (!windowAdvisor->lastActiveEditor.Expired() && + ref->GetPart(false) == windowAdvisor->lastActiveEditor.Lock()) + { + windowAdvisor->UpdateTitle(true); + } + } + + void PartVisible(const berry::IWorkbenchPartReference::Pointer& ref) override + { + if (!windowAdvisor->lastActiveEditor.Expired() && + ref->GetPart(false) == windowAdvisor->lastActiveEditor.Lock()) + { + windowAdvisor->UpdateTitle(false); + } + } + +private: + QmitkFlowApplicationWorkbenchWindowAdvisor* windowAdvisor; +}; + +class PartListenerForImageNavigator: public berry::IPartListener +{ +public: + + PartListenerForImageNavigator(QAction* act) + : imageNavigatorAction(act) + { + } + + Events::Types GetPartEventTypes() const override + { + return Events::OPENED | Events::CLOSED | Events::HIDDEN | + Events::VISIBLE; + } + + void PartOpened(const berry::IWorkbenchPartReference::Pointer& ref) override + { + if (ref->GetId()=="org.mitk.views.imagenavigator") + { + imageNavigatorAction->setChecked(true); + } + } + + void PartClosed(const berry::IWorkbenchPartReference::Pointer& ref) override + { + if (ref->GetId()=="org.mitk.views.imagenavigator") + { + imageNavigatorAction->setChecked(false); + } + } + + void PartVisible(const berry::IWorkbenchPartReference::Pointer& ref) override + { + if (ref->GetId()=="org.mitk.views.imagenavigator") + { + imageNavigatorAction->setChecked(true); + } + } + + void PartHidden(const berry::IWorkbenchPartReference::Pointer& ref) override + { + if (ref->GetId()=="org.mitk.views.imagenavigator") + { + imageNavigatorAction->setChecked(false); + } + } + +private: + QAction* imageNavigatorAction; +}; + +class PerspectiveListenerForTitle: public berry::IPerspectiveListener +{ +public: + + PerspectiveListenerForTitle(QmitkFlowApplicationWorkbenchWindowAdvisor* wa) + : windowAdvisor(wa) + , perspectivesClosed(false) + { + } + + Events::Types GetPerspectiveEventTypes() const override + { + return Events::ACTIVATED | Events::SAVED_AS | Events::DEACTIVATED + | Events::CLOSED | Events::OPENED; + } + + void PerspectiveActivated(const berry::IWorkbenchPage::Pointer& /*page*/, + const berry::IPerspectiveDescriptor::Pointer& /*perspective*/) override + { + windowAdvisor->UpdateTitle(false); + } + + void PerspectiveSavedAs(const berry::IWorkbenchPage::Pointer& /*page*/, + const berry::IPerspectiveDescriptor::Pointer& /*oldPerspective*/, + const berry::IPerspectiveDescriptor::Pointer& /*newPerspective*/) override + { + windowAdvisor->UpdateTitle(false); + } + + void PerspectiveDeactivated(const berry::IWorkbenchPage::Pointer& /*page*/, + const berry::IPerspectiveDescriptor::Pointer& /*perspective*/) override + { + windowAdvisor->UpdateTitle(false); + } + + void PerspectiveOpened(const berry::IWorkbenchPage::Pointer& /*page*/, + const berry::IPerspectiveDescriptor::Pointer& /*perspective*/) override + { + if (perspectivesClosed) + { + QListIterator i(windowAdvisor->viewActions); + while (i.hasNext()) + { + i.next()->setEnabled(true); + } + + windowAdvisor->fileSaveProjectAction->setEnabled(true); + windowAdvisor->undoAction->setEnabled(true); + windowAdvisor->redoAction->setEnabled(true); + windowAdvisor->imageNavigatorAction->setEnabled(true); + windowAdvisor->resetPerspAction->setEnabled(true); + } + + perspectivesClosed = false; + } + + void PerspectiveClosed(const berry::IWorkbenchPage::Pointer& /*page*/, + const berry::IPerspectiveDescriptor::Pointer& /*perspective*/) override + { + berry::IWorkbenchWindow::Pointer wnd = windowAdvisor->GetWindowConfigurer()->GetWindow(); + bool allClosed = true; + if (wnd->GetActivePage()) + { + QList perspectives(wnd->GetActivePage()->GetOpenPerspectives()); + allClosed = perspectives.empty(); + } + + if (allClosed) + { + perspectivesClosed = true; + + QListIterator i(windowAdvisor->viewActions); + while (i.hasNext()) + { + i.next()->setEnabled(false); + } + + windowAdvisor->fileSaveProjectAction->setEnabled(false); + windowAdvisor->undoAction->setEnabled(false); + windowAdvisor->redoAction->setEnabled(false); + windowAdvisor->imageNavigatorAction->setEnabled(false); + windowAdvisor->resetPerspAction->setEnabled(false); + } + } + +private: + QmitkFlowApplicationWorkbenchWindowAdvisor* windowAdvisor; + bool perspectivesClosed; +}; + +class PerspectiveListenerForMenu: public berry::IPerspectiveListener +{ +public: + + PerspectiveListenerForMenu(QmitkFlowApplicationWorkbenchWindowAdvisor* wa) + : windowAdvisor(wa) + { + } + + Events::Types GetPerspectiveEventTypes() const override + { + return Events::ACTIVATED | Events::DEACTIVATED; + } + + void PerspectiveActivated(const berry::IWorkbenchPage::Pointer& /*page*/, + const berry::IPerspectiveDescriptor::Pointer& perspective) override + { + QAction* action = windowAdvisor->mapPerspIdToAction[perspective->GetId()]; + if (action) + { + action->setChecked(true); + } + } + + void PerspectiveDeactivated(const berry::IWorkbenchPage::Pointer& /*page*/, + const berry::IPerspectiveDescriptor::Pointer& perspective) override + { + QAction* action = windowAdvisor->mapPerspIdToAction[perspective->GetId()]; + if (action) + { + action->setChecked(false); + } + } + +private: + QmitkFlowApplicationWorkbenchWindowAdvisor* windowAdvisor; +}; + +QmitkFlowApplicationWorkbenchWindowAdvisor::QmitkFlowApplicationWorkbenchWindowAdvisor(berry::WorkbenchAdvisor* wbAdvisor, + berry::IWorkbenchWindowConfigurer::Pointer configurer) + : berry::WorkbenchWindowAdvisor(configurer) + , lastInput(nullptr) + , wbAdvisor(wbAdvisor) + , showViewToolbar(true) + , showVersionInfo(true) + , showMitkVersionInfo(true) + , showMemoryIndicator(true) + , dropTargetListener(new QmitkDefaultDropTargetListener) +{ + productName = QCoreApplication::applicationName(); + viewExcludeList.push_back("org.mitk.views.viewnavigatorview"); +} + +QmitkFlowApplicationWorkbenchWindowAdvisor::~QmitkFlowApplicationWorkbenchWindowAdvisor() +{ +} + +QWidget* QmitkFlowApplicationWorkbenchWindowAdvisor::CreateEmptyWindowContents(QWidget* parent) +{ + QWidget* parentWidget = static_cast(parent); + auto label = new QLabel(parentWidget); + label->setText("No perspectives are open. Open a perspective in the Window->Open Perspective menu."); + label->setContentsMargins(10,10,10,10); + label->setAlignment(Qt::AlignTop); + label->setEnabled(false); + parentWidget->layout()->addWidget(label); + return label; +} + +void QmitkFlowApplicationWorkbenchWindowAdvisor::ShowMemoryIndicator(bool show) +{ + showMemoryIndicator = show; +} + +bool QmitkFlowApplicationWorkbenchWindowAdvisor::GetShowMemoryIndicator() +{ + return showMemoryIndicator; +} + +void QmitkFlowApplicationWorkbenchWindowAdvisor::ShowViewToolbar(bool show) +{ + showViewToolbar = show; +} + +void QmitkFlowApplicationWorkbenchWindowAdvisor::ShowVersionInfo(bool show) +{ + showVersionInfo = show; +} + +void QmitkFlowApplicationWorkbenchWindowAdvisor::ShowMitkVersionInfo(bool show) +{ + showMitkVersionInfo = show; +} + +void QmitkFlowApplicationWorkbenchWindowAdvisor::SetProductName(const QString& product) +{ + productName = product; +} + +void QmitkFlowApplicationWorkbenchWindowAdvisor::SetWindowIcon(const QString& wndIcon) +{ + windowIcon = wndIcon; +} + +void QmitkFlowApplicationWorkbenchWindowAdvisor::PostWindowCreate() +{ + // very bad hack... + berry::IWorkbenchWindow::Pointer window = this->GetWindowConfigurer()->GetWindow(); + QMainWindow* mainWindow = qobject_cast (window->GetShell()->GetControl()); + + if (!windowIcon.isEmpty()) + { + mainWindow->setWindowIcon(QIcon(windowIcon)); + } + mainWindow->setContextMenuPolicy(Qt::PreventContextMenu); + + // Load icon theme + QIcon::setThemeSearchPaths(QStringList() << QStringLiteral(":/org_mitk_icons/icons/")); + QIcon::setThemeName(QStringLiteral("awesome")); + + // ==== Application menu ============================ + + QMenuBar* menuBar = mainWindow->menuBar(); + menuBar->setContextMenuPolicy(Qt::PreventContextMenu); + +#ifdef __APPLE__ + menuBar->setNativeMenuBar(true); +#else + menuBar->setNativeMenuBar(false); +#endif + + auto basePath = QStringLiteral(":/org_mitk_icons/icons/awesome/scalable/actions/"); + + fileSaveProjectAction = new QmitkExtFileSaveProjectAction(window); + fileSaveProjectAction->setIcon(berry::QtStyleManager::ThemeIcon(basePath + "document-save.svg")); + + auto perspGroup = new QActionGroup(menuBar); + std::map VDMap; + + // sort elements (converting vector to map...) + QList::const_iterator iter; + + berry::IViewRegistry* viewRegistry = + berry::PlatformUI::GetWorkbench()->GetViewRegistry(); + const QList viewDescriptors = viewRegistry->GetViews(); + + bool skip = false; + for (iter = viewDescriptors.begin(); iter != viewDescriptors.end(); ++iter) + { + // if viewExcludeList is set, it contains the id-strings of view, which + // should not appear as an menu-entry in the menu + if (viewExcludeList.size() > 0) + { + for (int i=0; iGetId()) + { + skip = true; + break; + } + } + if (skip) + { + skip = false; + continue; + } + } + + if ((*iter)->GetId() == "org.blueberry.ui.internal.introview") + continue; + if ((*iter)->GetId() == "org.mitk.views.imagenavigator") + continue; + if ((*iter)->GetId() == "org.mitk.views.viewnavigatorview") + continue; + + std::pair p((*iter)->GetLabel(), (*iter)); + VDMap.insert(p); + } + + std::map::const_iterator MapIter; + for (MapIter = VDMap.begin(); MapIter != VDMap.end(); ++MapIter) + { + berry::QtShowViewAction* viewAction = new berry::QtShowViewAction(window, (*MapIter).second); + viewActions.push_back(viewAction); + } + + QMenu* fileMenu = menuBar->addMenu("&File"); + fileMenu->setObjectName("FileMenu"); + fileMenu->addAction(fileSaveProjectAction); + fileMenu->addSeparator(); + + QAction* fileExitAction = new QmitkFileExitAction(window); + fileExitAction->setIcon(berry::QtStyleManager::ThemeIcon(basePath + "system-log-out.svg")); + fileExitAction->setShortcut(QKeySequence::Quit); + fileExitAction->setObjectName("QmitkFileExitAction"); + fileMenu->addAction(fileExitAction); + + // another bad hack to get an edit/undo menu... + QMenu* editMenu = menuBar->addMenu("&Edit"); + undoAction = editMenu->addAction(berry::QtStyleManager::ThemeIcon(basePath + "edit-undo.svg"), + "&Undo", + QmitkFlowApplicationWorkbenchWindowAdvisorHack::undohack, SLOT(onUndo()), + QKeySequence("CTRL+Z")); + undoAction->setToolTip("Undo the last action (not supported by all modules)"); + redoAction = editMenu->addAction(berry::QtStyleManager::ThemeIcon(basePath + "edit-redo.svg"), + "&Redo", + QmitkFlowApplicationWorkbenchWindowAdvisorHack::undohack, SLOT(onRedo()), + QKeySequence("CTRL+Y")); + redoAction->setToolTip("execute the last action that was undone again (not supported by all modules)"); + + // ==== Window Menu ========================== + QMenu* windowMenu = menuBar->addMenu("Window"); + + QMenu* perspMenu = windowMenu->addMenu("&Open Perspective"); + + windowMenu->addSeparator(); + resetPerspAction = windowMenu->addAction("&Reset Perspective", + QmitkFlowApplicationWorkbenchWindowAdvisorHack::undohack, SLOT(onResetPerspective())); + + windowMenu->addSeparator(); + windowMenu->addAction("&Preferences...", + QmitkFlowApplicationWorkbenchWindowAdvisorHack::undohack, SLOT(onEditPreferences()), + QKeySequence("CTRL+P")); + + // fill perspective menu + berry::IPerspectiveRegistry* perspRegistry = + window->GetWorkbench()->GetPerspectiveRegistry(); + + QList perspectives( + perspRegistry->GetPerspectives()); + + skip = false; + for (QList::iterator perspIt = + perspectives.begin(); perspIt != perspectives.end(); ++perspIt) + { + // if perspectiveExcludeList is set, it contains the id-strings of perspectives, which + // should not appear as an menu-entry in the perspective menu + if (perspectiveExcludeList.size() > 0) + { + for (int i=0; iGetId()) + { + skip = true; + break; + } + } + if (skip) + { + skip = false; + continue; + } + } + + QAction* perspAction = new berry::QtOpenPerspectiveAction(window, *perspIt, perspGroup); + mapPerspIdToAction.insert((*perspIt)->GetId(), perspAction); + } + perspMenu->addActions(perspGroup->actions()); + + // ===== Help menu ==================================== + QMenu* helpMenu = menuBar->addMenu("&Help"); + helpMenu->addAction("&Welcome",this, SLOT(onIntro())); + helpMenu->addAction("&Open Help Perspective", this, SLOT(onHelpOpenHelpPerspective())); + helpMenu->addAction("&Context Help",this, SLOT(onHelp()), QKeySequence("F1")); + helpMenu->addAction("&About",this, SLOT(onAbout())); + // ===================================================== + + + // toolbar for showing file open, undo, redo and other main actions + auto mainActionsToolBar = new QToolBar; + mainActionsToolBar->setObjectName("mainActionsToolBar"); + mainActionsToolBar->setContextMenuPolicy(Qt::PreventContextMenu); +#ifdef __APPLE__ + mainActionsToolBar->setToolButtonStyle ( Qt::ToolButtonTextUnderIcon ); +#else + mainActionsToolBar->setToolButtonStyle ( Qt::ToolButtonTextBesideIcon ); +#endif + + basePath = QStringLiteral(":/org.mitk.gui.qt.ext/"); + imageNavigatorAction = new QAction(berry::QtStyleManager::ThemeIcon(basePath + "image_navigator.svg"), "&Image Navigator", nullptr); + bool imageNavigatorViewFound = window->GetWorkbench()->GetViewRegistry()->Find("org.mitk.views.imagenavigator"); + + if (imageNavigatorViewFound) + { + QObject::connect(imageNavigatorAction, SIGNAL(triggered(bool)), QmitkFlowApplicationWorkbenchWindowAdvisorHack::undohack, SLOT(onImageNavigator())); + imageNavigatorAction->setCheckable(true); + + // add part listener for image navigator + imageNavigatorPartListener.reset(new PartListenerForImageNavigator(imageNavigatorAction)); + window->GetPartService()->AddPartListener(imageNavigatorPartListener.data()); + berry::IViewPart::Pointer imageNavigatorView = window->GetActivePage()->FindView("org.mitk.views.imagenavigator"); + imageNavigatorAction->setChecked(false); + if (imageNavigatorView) + { + bool isImageNavigatorVisible = window->GetActivePage()->IsPartVisible(imageNavigatorView); + if (isImageNavigatorVisible) + imageNavigatorAction->setChecked(true); + } + imageNavigatorAction->setToolTip("Toggle image navigator for navigating through image"); + } + + mainActionsToolBar->addAction(undoAction); + mainActionsToolBar->addAction(redoAction); + + if (imageNavigatorViewFound) + { + mainActionsToolBar->addAction(imageNavigatorAction); + } + + mainWindow->addToolBar(mainActionsToolBar); + + // ==== View Toolbar ================================== + + if (showViewToolbar) + { + auto prefService = berry::WorkbenchPlugin::GetDefault()->GetPreferencesService(); + berry::IPreferences::Pointer stylePrefs = prefService->GetSystemPreferences()->Node(berry::QtPreferences::QT_STYLES_NODE); + bool showCategoryNames = stylePrefs->GetBool(berry::QtPreferences::QT_SHOW_TOOLBAR_CATEGORY_NAMES, true); + + // Order view descriptors by category + + QMultiMap categoryViewDescriptorMap; + + for (auto labelViewDescriptorPair : VDMap) + { + auto viewDescriptor = labelViewDescriptorPair.second; + auto category = !viewDescriptor->GetCategoryPath().isEmpty() + ? viewDescriptor->GetCategoryPath().back() + : QString(); + + categoryViewDescriptorMap.insert(category, viewDescriptor); + } + + // Create a separate toolbar for each category + + for (auto category : categoryViewDescriptorMap.uniqueKeys()) + { + auto viewDescriptorsInCurrentCategory = categoryViewDescriptorMap.values(category); + QList > relevantViewDescriptors; + + for (auto viewDescriptor : viewDescriptorsInCurrentCategory) + { + if (viewDescriptor->GetId() != "org.mitk.views.flow.control") + { + relevantViewDescriptors.push_back(viewDescriptor); + } + } + + if (!relevantViewDescriptors.isEmpty()) + { + auto toolbar = new QToolBar; + toolbar->setObjectName(category + " View Toolbar"); + mainWindow->addToolBar(toolbar); + + if (showCategoryNames && !category.isEmpty()) + { + auto categoryButton = new QToolButton; + categoryButton->setToolButtonStyle(Qt::ToolButtonTextOnly); + categoryButton->setText(category); + categoryButton->setStyleSheet("background: transparent; margin: 0; padding: 0;"); + toolbar->addWidget(categoryButton); + + connect(categoryButton, &QToolButton::clicked, [toolbar]() + { + for (QWidget* widget : toolbar->findChildren()) + { + if (QStringLiteral("qt_toolbar_ext_button") == widget->objectName() && widget->isVisible()) + { + QMouseEvent pressEvent(QEvent::MouseButtonPress, QPointF(0.0f, 0.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); + QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPointF(0.0f, 0.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); + QApplication::sendEvent(widget, &pressEvent); + QApplication::sendEvent(widget, &releaseEvent); + } + } + }); + } + + for (auto viewDescriptor : relevantViewDescriptors) + { + auto viewAction = new berry::QtShowViewAction(window, viewDescriptor); + toolbar->addAction(viewAction); + } + } + } + } + + QSettings settings(GetQSettingsFile(), QSettings::IniFormat); + mainWindow->restoreState(settings.value("ToolbarPosition").toByteArray()); + + auto qStatusBar = new QStatusBar(); + + //creating a QmitkStatusBar for Output on the QStatusBar and connecting it with the MainStatusBar + auto statusBar = new QmitkStatusBar(qStatusBar); + //disabling the SizeGrip in the lower right corner + statusBar->SetSizeGripEnabled(false); + + auto progBar = new QmitkProgressBar(); + + qStatusBar->addPermanentWidget(progBar, 0); + progBar->hide(); + + mainWindow->setStatusBar(qStatusBar); + + if (showMemoryIndicator) + { + auto memoryIndicator = new QmitkMemoryUsageIndicatorView(); + qStatusBar->addPermanentWidget(memoryIndicator, 0); + } +} + +void QmitkFlowApplicationWorkbenchWindowAdvisor::PreWindowOpen() +{ + berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); + + this->HookTitleUpdateListeners(configurer); + + menuPerspectiveListener.reset(new PerspectiveListenerForMenu(this)); + configurer->GetWindow()->AddPerspectiveListener(menuPerspectiveListener.data()); + + configurer->AddEditorAreaTransfer(QStringList("text/uri-list")); + configurer->ConfigureEditorAreaDropListener(dropTargetListener.data()); +} + +void QmitkFlowApplicationWorkbenchWindowAdvisor::PostWindowOpen() +{ + berry::WorkbenchWindowAdvisor::PostWindowOpen(); + // Force Rendering Window Creation on startup. + berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); + + ctkPluginContext* context = QmitkFlowApplicationPlugin::GetDefault()->GetPluginContext(); + ctkServiceReference serviceRef = context->getServiceReference(); + if (serviceRef) + { + mitk::IDataStorageService *dsService = context->getService(serviceRef); + if (dsService) + { + mitk::IDataStorageReference::Pointer dsRef = dsService->GetDataStorage(); + mitk::DataStorageEditorInput::Pointer dsInput(new mitk::DataStorageEditorInput(dsRef)); + mitk::WorkbenchUtil::OpenEditor(configurer->GetWindow()->GetActivePage(),dsInput); + } + } +} + +void QmitkFlowApplicationWorkbenchWindowAdvisor::onIntro() +{ + QmitkFlowApplicationWorkbenchWindowAdvisorHack::undohack->onIntro(); +} + +void QmitkFlowApplicationWorkbenchWindowAdvisor::onHelp() +{ + QmitkFlowApplicationWorkbenchWindowAdvisorHack::undohack->onHelp(); +} + +void QmitkFlowApplicationWorkbenchWindowAdvisor::onHelpOpenHelpPerspective() +{ + QmitkFlowApplicationWorkbenchWindowAdvisorHack::undohack->onHelpOpenHelpPerspective(); +} + +void QmitkFlowApplicationWorkbenchWindowAdvisor::onAbout() +{ + QmitkFlowApplicationWorkbenchWindowAdvisorHack::undohack->onAbout(); +} + +void QmitkFlowApplicationWorkbenchWindowAdvisor::HookTitleUpdateListeners(berry::IWorkbenchWindowConfigurer::Pointer configurer) +{ + // hook up the listeners to update the window title + titlePartListener.reset(new PartListenerForTitle(this)); + titlePerspectiveListener.reset(new PerspectiveListenerForTitle(this)); + editorPropertyListener.reset(new berry::PropertyChangeIntAdapter< + QmitkFlowApplicationWorkbenchWindowAdvisor>(this, + &QmitkFlowApplicationWorkbenchWindowAdvisor::PropertyChange)); + + configurer->GetWindow()->AddPerspectiveListener(titlePerspectiveListener.data()); + configurer->GetWindow()->GetPartService()->AddPartListener(titlePartListener.data()); +} + +QString QmitkFlowApplicationWorkbenchWindowAdvisor::ComputeTitle() +{ + berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); + berry::IWorkbenchPage::Pointer currentPage = configurer->GetWindow()->GetActivePage(); + berry::IEditorPart::Pointer activeEditor; + if (currentPage) + { + activeEditor = lastActiveEditor.Lock(); + } + + QString title; + berry::IProduct::Pointer product = berry::Platform::GetProduct(); + if (product.IsNotNull()) + { + title = product->GetName(); + } + if (title.isEmpty()) + { + // instead of the product name, we use a custom variable for now + title = productName; + } + + if(showMitkVersionInfo) + { + QString mitkVersionInfo = MITK_REVISION_DESC; + + if(mitkVersionInfo.isEmpty()) + mitkVersionInfo = MITK_VERSION_STRING; + + title += " " + mitkVersionInfo; + } + + if (showVersionInfo) + { + // add version informatioin + QString versions = QString(" (ITK %1.%2.%3 | VTK %4.%5.%6 | Qt %7)") + .arg(ITK_VERSION_MAJOR).arg(ITK_VERSION_MINOR).arg(ITK_VERSION_PATCH) + .arg(VTK_MAJOR_VERSION).arg(VTK_MINOR_VERSION).arg(VTK_BUILD_VERSION) + .arg(QT_VERSION_STR); + + title += versions; + } + + if (currentPage) + { + if (activeEditor) + { + lastEditorTitle = activeEditor->GetTitleToolTip(); + if (!lastEditorTitle.isEmpty()) + title = lastEditorTitle + " - " + title; + } + berry::IPerspectiveDescriptor::Pointer persp = currentPage->GetPerspective(); + QString label = ""; + if (persp) + { + label = persp->GetLabel(); + } + berry::IAdaptable* input = currentPage->GetInput(); + if (input && input != wbAdvisor->GetDefaultPageInput()) + { + label = currentPage->GetLabel(); + } + if (!label.isEmpty()) + { + title = label + " - " + title; + } + } + + title += " (Not for use in diagnosis or treatment of patients)"; + + return title; +} + +void QmitkFlowApplicationWorkbenchWindowAdvisor::RecomputeTitle() +{ + berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); + QString oldTitle = configurer->GetTitle(); + QString newTitle = ComputeTitle(); + if (newTitle != oldTitle) + { + configurer->SetTitle(newTitle); + } +} + +void QmitkFlowApplicationWorkbenchWindowAdvisor::UpdateTitle(bool editorHidden) +{ + berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); + berry::IWorkbenchWindow::Pointer window = configurer->GetWindow(); + berry::IEditorPart::Pointer activeEditor; + berry::IWorkbenchPage::Pointer currentPage = window->GetActivePage(); + berry::IPerspectiveDescriptor::Pointer persp; + berry::IAdaptable* input = nullptr; + + if (currentPage) + { + activeEditor = currentPage->GetActiveEditor(); + persp = currentPage->GetPerspective(); + input = currentPage->GetInput(); + } + + if (editorHidden) + { + activeEditor = nullptr; + } + + // Nothing to do if the editor hasn't changed + if (activeEditor == lastActiveEditor.Lock() && currentPage == lastActivePage.Lock() + && persp == lastPerspective.Lock() && input == lastInput) + { + return; + } + + if (!lastActiveEditor.Expired()) + { + lastActiveEditor.Lock()->RemovePropertyListener(editorPropertyListener.data()); + } + + lastActiveEditor = activeEditor; + lastActivePage = currentPage; + lastPerspective = persp; + lastInput = input; + + if (activeEditor) + { + activeEditor->AddPropertyListener(editorPropertyListener.data()); + } + + RecomputeTitle(); +} + +void QmitkFlowApplicationWorkbenchWindowAdvisor::PropertyChange(const berry::Object::Pointer& /*source*/, int propId) +{ + if (propId == berry::IWorkbenchPartConstants::PROP_TITLE) + { + if (!lastActiveEditor.Expired()) + { + QString newTitle = lastActiveEditor.Lock()->GetPartName(); + if (lastEditorTitle != newTitle) + { + RecomputeTitle(); + } + } + } +} + +void QmitkFlowApplicationWorkbenchWindowAdvisor::SetPerspectiveExcludeList(const QList& v) +{ + this->perspectiveExcludeList = v; +} + +QList QmitkFlowApplicationWorkbenchWindowAdvisor::GetPerspectiveExcludeList() +{ + return this->perspectiveExcludeList; +} + +void QmitkFlowApplicationWorkbenchWindowAdvisor::SetViewExcludeList(const QList& v) +{ + this->viewExcludeList = v; +} + +QList QmitkFlowApplicationWorkbenchWindowAdvisor::GetViewExcludeList() +{ + return this->viewExcludeList; +} + +void QmitkFlowApplicationWorkbenchWindowAdvisor::PostWindowClose() +{ + berry::IWorkbenchWindow::Pointer window = this->GetWindowConfigurer()->GetWindow(); + QMainWindow* mainWindow = static_cast (window->GetShell()->GetControl()); + + QSettings settings(GetQSettingsFile(), QSettings::IniFormat); + settings.setValue("ToolbarPosition", mainWindow->saveState()); +} + +QString QmitkFlowApplicationWorkbenchWindowAdvisor::GetQSettingsFile() const +{ + QFileInfo settingsInfo = QmitkFlowApplicationPlugin::GetDefault()->GetPluginContext()->getDataFile(QT_SETTINGS_FILENAME); + return settingsInfo.canonicalFilePath(); +} + +//-------------------------------------------------------------------------------- +// Ugly hack from here on. Feel free to delete when command framework +// and undo buttons are done. +//-------------------------------------------------------------------------------- + +QmitkFlowApplicationWorkbenchWindowAdvisorHack::QmitkFlowApplicationWorkbenchWindowAdvisorHack() + : QObject() +{ +} + +QmitkFlowApplicationWorkbenchWindowAdvisorHack::~QmitkFlowApplicationWorkbenchWindowAdvisorHack() +{ +} + +void QmitkFlowApplicationWorkbenchWindowAdvisorHack::onUndo() +{ + mitk::UndoModel* model = mitk::UndoController::GetCurrentUndoModel(); + if (model) + { + if (mitk::VerboseLimitedLinearUndo* verboseundo = dynamic_cast(model)) + { + mitk::VerboseLimitedLinearUndo::StackDescription descriptions = verboseundo->GetUndoDescriptions(); + if (descriptions.size() >= 1) + { + MITK_INFO << "Undo " << descriptions.front().second; + } + } + model->Undo(); + } + else + { + MITK_ERROR << "No undo model instantiated"; + } +} + +void QmitkFlowApplicationWorkbenchWindowAdvisorHack::onRedo() +{ + mitk::UndoModel* model = mitk::UndoController::GetCurrentUndoModel(); + if (model) + { + if (mitk::VerboseLimitedLinearUndo* verboseundo = dynamic_cast(model)) + { + mitk::VerboseLimitedLinearUndo::StackDescription descriptions = verboseundo->GetRedoDescriptions(); + if (descriptions.size() >= 1) + { + MITK_INFO << "Redo " << descriptions.front().second; + } + } + model->Redo(); + } + else + { + MITK_ERROR << "No undo model instantiated"; + } +} + +// safe calls to the complete chain +// berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage()->FindView("org.mitk.views.imagenavigator"); +// to cover for all possible cases of closed pages etc. +static void SafeHandleNavigatorView(QString view_query_name) +{ + berry::IWorkbench* wbench = berry::PlatformUI::GetWorkbench(); + if (wbench == nullptr) + return; + + berry::IWorkbenchWindow::Pointer wbench_window = wbench->GetActiveWorkbenchWindow(); + if (wbench_window.IsNull()) + return; + + berry::IWorkbenchPage::Pointer wbench_page = wbench_window->GetActivePage(); + if (wbench_page.IsNull()) + return; + + auto wbench_view = wbench_page->FindView(view_query_name); + + if (wbench_view.IsNotNull()) + { + bool isViewVisible = wbench_page->IsPartVisible(wbench_view); + if (isViewVisible) + { + wbench_page->HideView(wbench_view); + return; + } + + } + + wbench_page->ShowView(view_query_name); +} + +void QmitkFlowApplicationWorkbenchWindowAdvisorHack::onImageNavigator() +{ + // show/hide ImageNavigatorView + SafeHandleNavigatorView("org.mitk.views.imagenavigator"); +} + +void QmitkFlowApplicationWorkbenchWindowAdvisorHack::onEditPreferences() +{ + QmitkPreferencesDialog _PreferencesDialog(QApplication::activeWindow()); + _PreferencesDialog.exec(); +} + +void QmitkFlowApplicationWorkbenchWindowAdvisorHack::onQuit() +{ + berry::PlatformUI::GetWorkbench()->Close(); +} + +void QmitkFlowApplicationWorkbenchWindowAdvisorHack::onResetPerspective() +{ + berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage()->ResetPerspective(); +} + +void QmitkFlowApplicationWorkbenchWindowAdvisorHack::onClosePerspective() +{ + berry::IWorkbenchPage::Pointer page = + berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage(); + page->ClosePerspective(page->GetPerspective(), true, true); +} + +void QmitkFlowApplicationWorkbenchWindowAdvisorHack::onIntro() +{ + bool hasIntro = + berry::PlatformUI::GetWorkbench()->GetIntroManager()->HasIntro(); + if (!hasIntro) + { + QRegExp reg("(.*)(\\n)*"); + QRegExp reg2("(\\n)*(.*)"); + QFile file(":/org.mitk.gui.qt.ext/index.html"); + file.open(QIODevice::ReadOnly | QIODevice::Text); //text file only for reading + + QString text = QString(file.readAll()); + + file.close(); + + QString title = text; + title.replace(reg, ""); + title.replace(reg2, ""); + + std::cout << title.toStdString() << std::endl; + + QMessageBox::information(nullptr, title, + text, "Close"); + } + else + { + berry::PlatformUI::GetWorkbench()->GetIntroManager()->ShowIntro( + berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow(), false); + } +} + +void QmitkFlowApplicationWorkbenchWindowAdvisorHack::onHelp() +{ + ctkPluginContext* context = QmitkFlowApplicationPlugin::GetDefault()->GetPluginContext(); + if (context == nullptr) + { + MITK_WARN << "Plugin context not set, unable to open context help"; + return; + } + + // Check if the org.blueberry.ui.qt.help plug-in is installed and started + QList > plugins = context->getPlugins(); + foreach(QSharedPointer p, plugins) + { + if (p->getSymbolicName() == "org.blueberry.ui.qt.help") + { + if (p->getState() != ctkPlugin::ACTIVE) + { + // try to activate the plug-in explicitly + try + { + p->start(ctkPlugin::START_TRANSIENT); + } + catch (const ctkPluginException& pe) + { + MITK_ERROR << "Activating org.blueberry.ui.qt.help failed: " << pe.what(); + return; + } + } + } + } + + ctkServiceReference eventAdminRef = context->getServiceReference(); + ctkEventAdmin* eventAdmin = nullptr; + if (eventAdminRef) + { + eventAdmin = context->getService(eventAdminRef); + } + if (eventAdmin == nullptr) + { + MITK_WARN << "ctkEventAdmin service not found. Unable to open context help"; + } + else + { + ctkEvent ev("org/blueberry/ui/help/CONTEXTHELP_REQUESTED"); + eventAdmin->postEvent(ev); + } +} + +void QmitkFlowApplicationWorkbenchWindowAdvisorHack::onHelpOpenHelpPerspective() +{ + berry::PlatformUI::GetWorkbench()->ShowPerspective("org.blueberry.perspectives.help", + berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()); +} + +void QmitkFlowApplicationWorkbenchWindowAdvisorHack::onAbout() +{ + auto aboutDialog = new QmitkAboutDialog(QApplication::activeWindow(), nullptr); + aboutDialog->open(); +} diff --git a/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplicationWorkbenchWindowAdvisor.h b/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplicationWorkbenchWindowAdvisor.h new file mode 100644 index 0000000000..050c4defef --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplicationWorkbenchWindowAdvisor.h @@ -0,0 +1,153 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + + +#ifndef QMITKFLOWAPPLICATIONWORKBENCHWINDOWADVISOR_H_ +#define QMITKFLOWAPPLICATIONWORKBENCHWINDOWADVISOR_H_ + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +class QAction; +class QMenu; + +class MITK_QT_FLOW_BENCH_APP_EXPORT QmitkFlowApplicationWorkbenchWindowAdvisor : public QObject, public berry::WorkbenchWindowAdvisor +{ + Q_OBJECT + +public: + + QmitkFlowApplicationWorkbenchWindowAdvisor(berry::WorkbenchAdvisor* wbAdvisor, + berry::IWorkbenchWindowConfigurer::Pointer configurer); + + ~QmitkFlowApplicationWorkbenchWindowAdvisor() override; + + QWidget* CreateEmptyWindowContents(QWidget* parent) override; + + void PostWindowCreate() override; + + void PreWindowOpen() override; + + void PostWindowOpen() override; + + void PostWindowClose() override; + + void ShowViewToolbar(bool show); + + void ShowVersionInfo(bool show); + + void ShowMitkVersionInfo(bool show); + + void ShowMemoryIndicator(bool show); + + bool GetShowMemoryIndicator(); + + //TODO should be removed when product support is here + void SetProductName(const QString& product); + void SetWindowIcon(const QString& wndIcon); + + void SetPerspectiveExcludeList(const QList &v); + QList GetPerspectiveExcludeList(); + + void SetViewExcludeList(const QList &v); + QList GetViewExcludeList(); + +protected slots: + + virtual void onIntro(); + virtual void onHelp(); + virtual void onHelpOpenHelpPerspective(); + virtual void onAbout(); + +private: + + /** + * Hooks the listeners needed on the window + * + * @param configurer + */ + void HookTitleUpdateListeners(berry::IWorkbenchWindowConfigurer::Pointer configurer); + + QString ComputeTitle(); + + void RecomputeTitle(); + + QString GetQSettingsFile() const; + + /** + * Updates the window title. Format will be: [pageInput -] + * [currentPerspective -] [editorInput -] [workspaceLocation -] productName + * @param editorHidden TODO + */ + void UpdateTitle(bool editorHidden); + + void PropertyChange(const berry::Object::Pointer& /*source*/, int propId); + + static QString QT_SETTINGS_FILENAME; + + QScopedPointer titlePartListener; + QScopedPointer titlePerspectiveListener; + QScopedPointer menuPerspectiveListener; + QScopedPointer imageNavigatorPartListener; + QScopedPointer editorPropertyListener; + friend struct berry::PropertyChangeIntAdapter; + friend class PartListenerForTitle; + friend class PerspectiveListenerForTitle; + friend class PerspectiveListenerForMenu; + friend class PartListenerForImageNavigator; + friend class PartListenerForViewNavigator; + + berry::IEditorPart::WeakPtr lastActiveEditor; + berry::IPerspectiveDescriptor::WeakPtr lastPerspective; + berry::IWorkbenchPage::WeakPtr lastActivePage; + QString lastEditorTitle; + berry::IAdaptable* lastInput; + + berry::WorkbenchAdvisor* wbAdvisor; + bool showViewToolbar; + bool showVersionInfo; + bool showMitkVersionInfo; + bool showMemoryIndicator; + QString productName; + QString windowIcon; + + // enables DnD on the editor area + QScopedPointer dropTargetListener; + + // stringlist for excluding perspectives from the perspective menu entry (e.g. Welcome Perspective) + QList perspectiveExcludeList; + + // stringlist for excluding views from the menu entry + QList viewExcludeList; + + // maps perspective ids to QAction objects + QHash mapPerspIdToAction; + + // actions which will be enabled/disabled depending on the application state + QList viewActions; + QAction* fileSaveProjectAction; + QAction* undoAction; + QAction* redoAction; + QAction* imageNavigatorAction; + QAction* resetPerspAction; +}; + +#endif /*QMITKFLOWAPPLICATIONWORKBENCHWINDOWADVISOR_H_*/ diff --git a/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplicationWorkbenchWindowAdvisorHack.h b/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplicationWorkbenchWindowAdvisorHack.h new file mode 100644 index 0000000000..3cd0d48862 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.flowapplication/src/internal/QmitkFlowApplicationWorkbenchWindowAdvisorHack.h @@ -0,0 +1,58 @@ +/*=================================================================== + +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 + +class ctkPluginContext; +class QmitkPreferencesDialog; + +/** This class is a "hack" due to the currently missing command framework. It is a direct clone of QmitkExtWorkbenchWindowAdvisorHack.*/ +class QmitkFlowApplicationWorkbenchWindowAdvisorHack : public QObject +{ + Q_OBJECT + + public slots: + + void onUndo(); + void onRedo(); + void onImageNavigator(); + void onEditPreferences(); + void onQuit(); + + void onResetPerspective(); + void onClosePerspective(); + void onIntro(); + + /** + * @brief This slot is called if the user klicks the menu item "help->context help" or presses F1. + * The help page is shown in a workbench editor. + */ + void onHelp(); + + void onHelpOpenHelpPerspective(); + + /** + * @brief This slot is called if the user clicks in help menu the about button + */ + void onAbout(); + + public: + + QmitkFlowApplicationWorkbenchWindowAdvisorHack(); + ~QmitkFlowApplicationWorkbenchWindowAdvisorHack() override; + + static QmitkFlowApplicationWorkbenchWindowAdvisorHack* undohack; +};