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/CoreCmdApps.cmake b/CMake/BuildConfigurations/CoreCmdApps.cmake new file mode 100644 index 0000000000..09a25933dd --- /dev/null +++ b/CMake/BuildConfigurations/CoreCmdApps.cmake @@ -0,0 +1,7 @@ +include(${CMAKE_CURRENT_LIST_DIR}/Minimal.cmake) + +set(MITK_WHITELIST "CoreCmdApps" CACHE STRING "" FORCE) + +if(NOT MITK_USE_SUPERBUILD) + set(BUILD_CoreCmdApps ON CACHE BOOL "" FORCE) +endif() 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/BuildConfigurations/Minimal.cmake b/CMake/BuildConfigurations/Minimal.cmake new file mode 100644 index 0000000000..91873eef15 --- /dev/null +++ b/CMake/BuildConfigurations/Minimal.cmake @@ -0,0 +1,5 @@ +set(BUILD_TESTING OFF CACHE BOOL "" FORCE) + +set(MITK_USE_BLUEBERRY OFF CACHE BOOL "" FORCE) +set(MITK_USE_CTK OFF CACHE BOOL "" FORCE) +set(MITK_USE_Qt5 OFF CACHE BOOL "" FORCE) diff --git a/CMake/FixMacOSInstaller.cmake b/CMake/FixMacOSInstaller.cmake index bc3ebc5f69..c60ca34ebd 100644 --- a/CMake/FixMacOSInstaller.cmake +++ b/CMake/FixMacOSInstaller.cmake @@ -1,52 +1,41 @@ set(bundle_path "${CMAKE_INSTALL_PREFIX}/${_bundle_dest_dir}/../..") get_filename_component(bundle_path ${bundle_path} REALPATH) ############################# # (1) Fix Qt-related issues # ############################# # Compile list of Qt frameworks in bundle unset(qt_frameworks) file(GLOB qt_framework_paths "${bundle_path}/Contents/Frameworks/Qt*.framework") foreach(qt_framework_path ${qt_framework_paths}) get_filename_component(qt_framework ${qt_framework_path} NAME_WE) list(APPEND qt_frameworks ${qt_framework}) endforeach() # For each Qt framework, change the style of dependencies to other # Qt frameworks from @executable_path to @rpath. The install name tool # only changes existing dependencies. foreach(qt_framework ${qt_frameworks}) set(in "${bundle_path}/Contents/Frameworks/${qt_framework}.framework/Versions/5/${qt_framework}") foreach(other_qt_framework ${qt_frameworks}) set(from "@executable_path/../Frameworks/${other_qt_framework}.framework/Versions/5/${other_qt_framework}") set(to "@rpath/${other_qt_framework}.framework/Versions/5/${other_qt_framework}") execute_process(COMMAND install_name_tool -change ${from} ${to} ${in}) endforeach() endforeach() # Do the same for QtWebEngineProcess set(qtwebengineprocess_path "${bundle_path}/Contents/Frameworks/QtWebEngineCore.framework/Helpers/QtWebEngineProcess.app/Contents/MacOS/QtWebEngineProcess") foreach(qt_framework ${qt_frameworks}) set(from "@executable_path/../Frameworks/${qt_framework}.framework/Versions/5/${qt_framework}") set(to "@rpath/${qt_framework}.framework/Versions/5/${qt_framework}") execute_process(COMMAND install_name_tool -change ${from} ${to} ${qtwebengineprocess_path}) endforeach() # Add corresponding rpath entries to the actual application and QtWebEngineProcess. # The install name tool returns an error if an entry is already present. get_filename_component(app ${bundle_path} NAME_WE) set(app_path "${bundle_path}/Contents/MacOS/${app}") execute_process(COMMAND install_name_tool -add_rpath "@executable_path/../Frameworks" ${app_path} ERROR_QUIET) execute_process(COMMAND install_name_tool -add_rpath "@executable_path/../../../../.." ${qtwebengineprocess_path} ERROR_QUIET) - -################################################## -# (2) Fix hard dependencies to auto-load modules # -################################################## - -# Create symlinks to auto-load modules in MitkCore directory -file(GLOB autoload_module_paths "${bundle_path}/Contents/MacOS/MitkCore/*.dylib") -foreach(autoload_module_path ${autoload_module_paths}) - get_filename_component(autoload_module ${autoload_module_path} NAME) - execute_process(COMMAND ln -s MitkCore/${autoload_module} WORKING_DIRECTORY "${bundle_path}/Contents/MacOS") -endforeach() diff --git a/CMake/Whitelists/CoreCmdApps.cmake b/CMake/Whitelists/CoreCmdApps.cmake new file mode 100644 index 0000000000..ccc34d77f7 --- /dev/null +++ b/CMake/Whitelists/CoreCmdApps.cmake @@ -0,0 +1,25 @@ +include(${CMAKE_CURRENT_LIST_DIR}/Minimal.cmake) + +list(APPEND enabled_modules + AlgorithmsExt + Annotation + CommandLine + ContourModel + CoreCmdApps + DataTypesExt + DICOMPM + DICOMPMIO + DICOMQI + DICOMReader + DICOMReaderServices + DicomRT + DicomRTIO + DICOMSegIO + ModelFit + Multilabel + MultilabelIO + LegacyGL + SceneSerialization + SceneSerializationBase +) + 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/CMake/Whitelists/Minimal.cmake b/CMake/Whitelists/Minimal.cmake index 6bfa892451..d3725a79a3 100644 --- a/CMake/Whitelists/Minimal.cmake +++ b/CMake/Whitelists/Minimal.cmake @@ -1,8 +1,7 @@ set(enabled_modules Core CppMicroServices ) set(enabled_plugins - "" -) \ No newline at end of file +) diff --git a/CMake/mitkFunctionCreateCommandLineApp.cmake b/CMake/mitkFunctionCreateCommandLineApp.cmake index 5c7d442fdd..139d6d53ef 100644 --- a/CMake/mitkFunctionCreateCommandLineApp.cmake +++ b/CMake/mitkFunctionCreateCommandLineApp.cmake @@ -1,99 +1,55 @@ #! #! Create a Command Line App. #! #! \brief This function will create a command line executable and the scripts required to run it #! #! \param NAME (required) Name of the command line app #! \param DEPENDS (optional) Required MITK modules beyond MitkCommandLine #! \param PACKAGE_DEPENDS (optional) list of "packages" this command line app depends on (e.g. ITK, VTK, etc.) #! \param CPP_FILES (optional) list of cpp files, if it is not given NAME.cpp is assumed #! #! Assuming that there exists a file called MyApp.cpp, an example call looks like: #! \code #! mitkFunctionCreateCommandLineApp( #! NAME MyApp #! DEPENDS MitkCore MitkPlanarFigure #! PACKAGE_DEPENDS ITK VTK #! ) #! \endcode #! function(mitkFunctionCreateCommandLineApp) set(_function_params NAME # Name of the command line app ) set(_function_multiparams DEPENDS # list of modules this command line app depends on PACKAGE_DEPENDS # list of "packages" this command line app depends on (e.g. ITK, VTK, etc.) CPP_FILES # (optional) list of cpp files, if it is not given NAME.cpp is assumed ) set(_function_options WARNINGS_NO_ERRORS ) cmake_parse_arguments(CMDAPP "${_function_options}" "${_function_params}" "${_function_multiparams}" ${ARGN}) if(NOT CMDAPP_NAME) message(FATAL_ERROR "NAME argument cannot be empty.") endif() if(NOT CMDAPP_CPP_FILES) set(CMDAPP_CPP_FILES ${CMDAPP_NAME}.cpp) endif() if(CMDAPP_WARNINGS_NO_ERRORS) LIST(APPEND _CMDAPP_OPTIONS WARNINGS_NO_ERRORS) endif() mitk_create_executable(${CMDAPP_NAME} DEPENDS MitkCommandLine ${CMDAPP_DEPENDS} PACKAGE_DEPENDS ${CMDAPP_PACKAGE_DEPENDS} CPP_FILES ${CMDAPP_CPP_FILES} ${_CMDAPP_OPTIONS} ) - MITK_INSTALL_TARGETS(EXECUTABLES ${EXECUTABLE_TARGET} ) - - if(EXECUTABLE_IS_ENABLED) - - # On Linux, create a shell script to start a relocatable application - if(UNIX AND NOT APPLE) - install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) - endif() - - get_target_property(_is_bundle ${EXECUTABLE_TARGET} MACOSX_BUNDLE) - - if(APPLE) - if(_is_bundle) - set(_target_locations ${EXECUTABLE_TARGET}.app) - set(${_target_locations}_qt_plugins_install_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) - set(_bundle_dest_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) - set(_qt_plugins_for_current_bundle ${EXECUTABLE_TARGET}.app/Contents/MacOS) - set(_qt_conf_install_dirs ${EXECUTABLE_TARGET}.app/Contents/Resources) - install(TARGETS ${EXECUTABLE_TARGET} BUNDLE DESTINATION . ) - else() - if(NOT MACOSX_BUNDLE_NAMES) - set(_qt_conf_install_dirs bin) - set(_target_locations bin/${EXECUTABLE_TARGET}) - set(${_target_locations}_qt_plugins_install_dir bin) - install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) - else() - foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) - list(APPEND _qt_conf_install_dirs ${bundle_name}.app/Contents/Resources) - set(_current_target_location ${bundle_name}.app/Contents/MacOS/${EXECUTABLE_TARGET}) - list(APPEND _target_locations ${_current_target_location}) - set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) - message( " set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) ") - - install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION ${bundle_name}.app/Contents/MacOS/) - endforeach() - endif() - endif() - else() - set(_target_locations bin/${EXECUTABLE_TARGET}${CMAKE_EXECUTABLE_SUFFIX}) - set(${_target_locations}_qt_plugins_install_dir bin) - set(_qt_conf_install_dirs bin) - install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) - endif() - endif() endfunction() diff --git a/CMake/mitkInstallRules.cmake b/CMake/mitkInstallRules.cmake index 0b02b0bc21..ec850c1efc 100644 --- a/CMake/mitkInstallRules.cmake +++ b/CMake/mitkInstallRules.cmake @@ -1,109 +1,152 @@ # Install MITK icon and logo MITK_INSTALL(FILES "${MITK_SOURCE_DIR}/mitk.ico" "${MITK_SOURCE_DIR}/mitk.bmp") # Helper vars if(WIN32) set(_prefix "") set(_ext ".dll") elseif(UNIX) set(_prefix "lib") if(APPLE) set(_ext ".dylib") else() set(_ext ".so") endif() endif() +# Install MITK executables including auto-load modules + +get_property(_mitk_executable_targets GLOBAL PROPERTY MITK_EXECUTABLE_TARGETS) +if(_mitk_executable_targets) + get_property(_mitk_module_targets GLOBAL PROPERTY MITK_MODULE_TARGETS) + foreach(_mitk_module_target ${_mitk_module_targets}) + if(TARGET ${_mitk_module_target}) + get_target_property(_mitk_autoload_targets ${_mitk_module_target} MITK_AUTOLOAD_TARGETS) + if (_mitk_autoload_targets) + foreach(_mitk_autoload_target ${_mitk_autoload_targets}) + get_target_property(_mitk_autoload_directory ${_mitk_autoload_target} MITK_AUTOLOAD_DIRECTORY) + if (_mitk_autoload_directory) + if(WIN32) + get_target_property(_target_location ${_mitk_autoload_target} RUNTIME_OUTPUT_DIRECTORY) + else() + get_target_property(_target_location ${_mitk_autoload_target} LIBRARY_OUTPUT_DIRECTORY) + endif() + if(NOT CMAKE_CFG_INTDIR STREQUAL ".") + set(_target_location "${_target_location}/Release") + endif() + set(_mitk_autoload_target_filename "${_prefix}${_mitk_autoload_target}${_ext}") + set(_mitk_autoload_target_filepath "${_target_location}/${_mitk_autoload_target_filename}") + set(_install_DESTINATION "${_mitk_autoload_directory}") + MITK_INSTALL(FILES ${_mitk_autoload_target_filepath}) + if(UNIX AND NOT APPLE) + install(CODE "file(RPATH_REMOVE FILE \"\${CMAKE_INSTALL_PREFIX}/bin/${_mitk_autoload_directory}/${_mitk_autoload_target_filename}\")") + endif() + endif() + endforeach() + endif() + endif() + endforeach() + + set(_install_DESTINATION "") + + foreach(_mitk_executable_target ${_mitk_executable_targets}) + MITK_INSTALL_TARGETS(EXECUTABLES ${_mitk_executable_target} GLOB_PLUGINS) + if(UNIX AND NOT APPLE) + install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${_mitk_executable_target}.sh) + endif() + endforeach() +endif() + # Install PythonQt if(MITK_USE_Python3 AND PythonQt_DIR) set(_python_qt_lib "${PythonQt_DIR}/") if(WIN32) set(_python_qt_lib "${_python_qt_lib}bin") else() set(_python_qt_lib "${_python_qt_lib}lib") endif() set(_python_qt_lib "${_python_qt_lib}/${_prefix}PythonQt${_ext}") MITK_INSTALL(FILES ${_python_qt_lib}) endif() # Install Qt plugins if(MITK_USE_Qt5) get_property(_qmake_location TARGET ${Qt5Core_QMAKE_EXECUTABLE} PROPERTY IMPORT_LOCATION) get_filename_component(_qmake_path ${_qmake_location} DIRECTORY) set(_install_DESTINATION "plugins/sqldrivers") MITK_INSTALL(FILES "${_qmake_path}/../plugins/sqldrivers/${_prefix}qsqlite${_ext}") set(_install_DESTINATION "plugins/imageformats") MITK_INSTALL(FILES "${_qmake_path}/../plugins/imageformats/${_prefix}qsvg${_ext}") set(_install_DESTINATION "plugins/iconengines") MITK_INSTALL(FILES "${_qmake_path}/../plugins/iconengines/${_prefix}qsvgicon${_ext}") # Install platform-specific Qt plugins set(_install_DESTINATION "plugins/platforms") if(WIN32) MITK_INSTALL(FILES "${_qmake_path}/../plugins/platforms/qwindows.dll") elseif(APPLE) MITK_INSTALL(FILES "${_qmake_path}/../plugins/platforms/libqcocoa.dylib") elseif(UNIX) MITK_INSTALL(FILES "${_qmake_path}/../plugins/platforms/libqxcb.so") set(_install_DESTINATION "plugins/xcbglintegrations") MITK_INSTALL(FILES "${_qmake_path}/../plugins/xcbglintegrations/libqxcb-glx-integration.so") endif() # Install platform-specific Qt styles set(_install_DESTINATION "plugins/styles") if(WIN32) MITK_INSTALL(FILES "${_qmake_path}/../plugins/styles/qwindowsvistastyle.dll") elseif(APPLE) MITK_INSTALL(FILES "${_qmake_path}/../plugins/styles/libqmacstyle.dylib") endif() # Install Qt WebEngine if(APPLE) set(_install_DESTINATION "../Frameworks/QtWebEngineCore.framework") get_filename_component(_real_path "${_qmake_path}/../lib/QtWebEngineCore.framework/Helpers" REALPATH) MITK_INSTALL(DIRECTORY ${_real_path} USE_SOURCE_PERMISSIONS) # Translations are included in the Resources directory of # QtWebEngineCore.framework and are installed by default. else() set(_install_DESTINATION "") if(WIN32) MITK_INSTALL(PROGRAMS "${_qmake_path}/QtWebEngineProcess.exe") elseif(UNIX) MITK_INSTALL(PROGRAMS "${_qmake_path}/../libexec/QtWebEngineProcess") endif() MITK_INSTALL(DIRECTORY "${_qmake_path}/../resources") set(_install_DESTINATION "translations") MITK_INSTALL(DIRECTORY "${_qmake_path}/../translations/qtwebengine_locales") endif() endif() set(_install_DESTINATION "") # Install MatchPoint binaries that are not auto-detected if(MITK_USE_MatchPoint) MITK_INSTALL(DIRECTORY "${MITK_EXTERNAL_PROJECT_PREFIX}/bin/" FILES_MATCHING PATTERN "MapUtilities*") MITK_INSTALL(DIRECTORY "${MITK_EXTERNAL_PROJECT_PREFIX}/bin/" FILES_MATCHING PATTERN "MapAlgorithms*") endif() # IMPORTANT: Restore default install destination! Do not edit this file beyond this line! set(_install_DESTINATION "") diff --git a/CMake/mitkMacroCreateExecutable.cmake b/CMake/mitkMacroCreateExecutable.cmake index b5138cddc0..6f3a3048b0 100644 --- a/CMake/mitkMacroCreateExecutable.cmake +++ b/CMake/mitkMacroCreateExecutable.cmake @@ -1,111 +1,112 @@ ################################################################## # # MITK_CREATE_EXECUTABLE # #! Creates an executable with MITK dependencies and batch files #! for proper application start-up. #! #! USAGE: #! #! \code #! MITK_CREATE_EXECUTABLE( [] #! [DEPENDS ] #! [PACKAGE_DEPENDS ] #! [INCLUDE_DIRS ] #! [TARGET_DEPENDS #! [WARNINGS_NO_ERRORS] #! \endcode #! #! \param EXECUTABLE_NAME The name for the new executable target ################################################################## macro(mitk_create_executable) set(_macro_params VERSION # version number, e.g. "1.2.0" FILES_CMAKE # file name of a CMake file setting source list variables # (defaults to files.cmake) DESCRIPTION # a description for the executable ) set(_macro_multiparams SUBPROJECTS # list of CDash labels INCLUDE_DIRS # additional include dirs DEPENDS # list of modules this module depends on PACKAGE_DEPENDS # list of "packages" this module depends on (e.g. Qt, VTK, etc.) TARGET_DEPENDS # list of CMake targets this executable should depend on ADDITIONAL_LIBS # list of additional libraries linked to this executable CPP_FILES # (optional) list of cpp files ) set(_macro_options NO_INIT # do not create CppMicroServices initialization code NO_FEATURE_INFO # do not create a feature info by calling add_feature_info() NO_BATCH_FILE # do not create batch files on Windows WARNINGS_NO_ERRORS # do not treat compiler warnings as errors ) cmake_parse_arguments(EXEC "${_macro_options}" "${_macro_params}" "${_macro_multiparams}" ${ARGN}) set(_EXEC_OPTIONS EXECUTABLE) if(EXEC_NO_INIT) list(APPEND _EXEC_OPTIONS NO_INIT) endif() if(EXEC_WARNINGS_NO_ERRORS) list(APPEND _EXEC_OPTIONS WARNINGS_NO_ERRORS) endif() if(EXEC_NO_FEATURE_INFO) list(APPEND _EXEC_OPTIONS NO_FEATURE_INFO) endif() mitk_create_module(${EXEC_UNPARSED_ARGUMENTS} SUBPROJECTS ${EXEC_SUBPROJECTS} VERSION ${EXEC_VERSION} INCLUDE_DIRS ${EXEC_INCLUDE_DIRS} DEPENDS ${EXEC_DEPENDS} PACKAGE_DEPENDS ${EXEC_PACKAGE_DEPENDS} TARGET_DEPENDS ${EXEC_TARGET_DEPENDS} ADDITIONAL_LIBS ${EXEC_ADDITIONAL_LIBS} FILES_CMAKE ${EXEC_FILES_CMAKE} CPP_FILES ${EXEC_CPP_FILES} DESCRIPTION "${DESCRIPTION}" ${_EXEC_OPTIONS} ) set(EXECUTABLE_IS_ENABLED ${MODULE_IS_ENABLED}) set(EXECUTABLE_TARGET ${MODULE_TARGET}) - if(MODULE_IS_ENABLED) + if(EXECUTABLE_IS_ENABLED) + set_property(GLOBAL APPEND PROPERTY MITK_EXECUTABLE_TARGETS ${EXECUTABLE_TARGET}) # Add meta dependencies (e.g. on auto-load modules from depending modules) if(TARGET ${CMAKE_PROJECT_NAME}-autoload) add_dependencies(${MODULE_TARGET} ${CMAKE_PROJECT_NAME}-autoload) endif() # Create batch and VS user files for Windows platforms include(mitkFunctionCreateWindowsBatchScript) if(WIN32) set(_batch_file_in "${CMAKE_CURRENT_SOURCE_DIR}/${MODULE_TARGET}.bat.in") if(NOT EXISTS "${_batch_file_in}") set(_batch_file_in "${MITK_CMAKE_DIR}/StartApp.bat.in") endif() if(CMAKE_RUNTIME_OUTPUT_DIRECTORY) set(_batch_file_out_dir "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") else() set(_batch_file_out_dir "${CMAKE_CURRENT_BINARY_DIR}") endif() if(NOT EXEC_NO_BATCH_FILE) if(NOT EXEC_NAME) set(EXEC_NAME ${MODULE_TARGET}) endif() foreach(BUILD_TYPE debug release) mitkFunctionCreateWindowsBatchScript( ${_batch_file_in} ${_batch_file_out_dir}/${MODULE_TARGET}_${BUILD_TYPE}.bat ${BUILD_TYPE} ) endforeach() endif() mitkFunctionConfigureVisualStudioUserProjectFile( NAME ${MODULE_TARGET} ) endif() endif() endmacro() diff --git a/CMake/mitkMacroInstallHelperApp.cmake b/CMake/mitkMacroInstallHelperApp.cmake index f72bf92379..ddfe252c9c 100644 --- a/CMake/mitkMacroInstallHelperApp.cmake +++ b/CMake/mitkMacroInstallHelperApp.cmake @@ -1,109 +1,74 @@ #! MITK specific cross plattform install macro #! #! Usage: MITK_INSTALL_HELPER_APP(target1 [target2] ....) #! macro(MITK_INSTALL_HELPER_APP) cmake_parse_arguments(_install "GLOB_PLUGINS" "" "TARGETS;EXECUTABLES;PLUGINS;LIBRARY_DIRS" ${ARGN}) list(APPEND _install_TARGETS ${_install_DEFAULT_ARGS}) # TODO: how to supply to correct intermediate directory?? # CMAKE_CFG_INTDIR is not expanded to actual values inside the install(CODE "...") macro ... set(intermediate_dir .) if(WIN32) set(intermediate_dir Release) endif() mitkFunctionGetLibrarySearchPaths(DIRS ${intermediate_dir}) if(APPLE) list(APPEND DIRS "/usr/lib") endif(APPLE) - if(QT_LIBRARY_DIR MATCHES "^(/lib|/lib32|/lib64|/usr/lib|/usr/lib32|/usr/lib64|/usr/X11R6)(/.*)?$") - set(_qt_is_system_qt 1) - endif() - foreach(_target ${_install_EXECUTABLES}) - - set(_qt_plugins_install_dirs "") set(_qt_conf_install_dirs "") set(_target_locations "") get_filename_component(_target_name ${_target} NAME) if(APPLE) if(NOT MACOSX_BUNDLE_NAMES) set(_qt_conf_install_dirs bin) set(_target_locations bin/${_target_name}) - set(${_target_locations}_qt_plugins_install_dir bin) install(PROGRAMS ${_target} DESTINATION bin) else() foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) list(APPEND _qt_conf_install_dirs ${bundle_name}.app/Contents/Resources) set(_current_target_location ${bundle_name}.app/Contents/MacOS/${_target_name}) list(APPEND _target_locations ${_current_target_location}) - set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) - install(PROGRAMS ${_target} DESTINATION ${bundle_name}.app/Contents/MacOS/) endforeach() endif(NOT MACOSX_BUNDLE_NAMES) else() set(_target_location bin/${_target_name}) - set(${_target_location}_qt_plugins_install_dir bin) set(_qt_conf_install_dirs bin) install(PROGRAMS ${_target} DESTINATION bin) if(UNIX AND NOT WIN32) # Remove the rpath from helper applications. We assume that all dependencies # are installed into the same location as the helper application. install(CODE "file(RPATH_REMOVE FILE \"\${CMAKE_INSTALL_PREFIX}/${_target_location}\")") endif() endif() foreach(_target_location ${_target_locations}) - if(NOT _qt_is_system_qt) - if(QT_PLUGINS_DIR) - if(WIN32) - install(DIRECTORY "${QT_PLUGINS_DIR}" - DESTINATION ${${_target_location}_qt_plugins_install_dir} - CONFIGURATIONS Release - FILES_MATCHING REGEX "[^4d]4?${CMAKE_SHARED_LIBRARY_SUFFIX}" - ) - - install(DIRECTORY "${QT_PLUGINS_DIR}" - DESTINATION ${${_target_location}_qt_plugins_install_dir} - CONFIGURATIONS Debug - FILES_MATCHING REGEX "d4?${CMAKE_SHARED_LIBRARY_SUFFIX}" - ) - else(WIN32) - # install everything, see bug 7143 - install(DIRECTORY "${QT_PLUGINS_DIR}" - DESTINATION ${${_target_location}_qt_plugins_install_dir} - FILES_MATCHING REGEX "${CMAKE_SHARED_LIBRARY_SUFFIX}" - ) - - endif(WIN32) - endif() - endif() _fixup_target() endforeach(_target_location) - if(NOT _qt_is_system_qt) - #-------------------------------------------------------------------------------- - # install a qt.conf file - # this inserts some cmake code into the install script to write the file + #-------------------------------------------------------------------------------- + # install a qt.conf file + # this inserts some cmake code into the install script to write the file + if(MITK_USE_Qt5) set(_qt_conf_plugin_install_prefix .) if(APPLE) set(_qt_conf_plugin_install_prefix ./MacOS) endif() foreach(_qt_conf_install_dir ${_qt_conf_install_dirs}) install(CODE "file(WRITE \"\${CMAKE_INSTALL_PREFIX}/${_qt_conf_install_dir}/qt.conf\" \" [Paths] Prefix=${_qt_conf_plugin_install_prefix} \")") endforeach() endif() - endforeach() endmacro(MITK_INSTALL_HELPER_APP) diff --git a/CMake/mitkMacroInstallTargets.cmake b/CMake/mitkMacroInstallTargets.cmake index dbe1367269..68ffe8bcba 100644 --- a/CMake/mitkMacroInstallTargets.cmake +++ b/CMake/mitkMacroInstallTargets.cmake @@ -1,113 +1,71 @@ # # MITK specific cross plattform install macro # # Usage: MITK_INSTALL_TARGETS(target1 [target2] ....) # macro(MITK_INSTALL_TARGETS) cmake_parse_arguments(_install "GLOB_PLUGINS" "" "TARGETS;EXECUTABLES;PLUGINS;LIBRARY_DIRS" ${ARGN}) list(APPEND _install_TARGETS ${_install_DEFAULT_ARGS}) # TODO: how to supply the correct intermediate directory?? # CMAKE_CFG_INTDIR is not expanded to actual values inside the install(CODE "...") macro ... set(intermediate_dir .) if(WIN32) set(intermediate_dir Release) endif() - if(QT_LIBRARY_DIR MATCHES "^(/lib|/lib32|/lib64|/usr/lib|/usr/lib32|/usr/lib64|/usr/X11R6)(/.*)?$") - set(_qt_is_system_qt 1) - endif() - foreach(_target ${_install_EXECUTABLES}) - get_target_property(_is_bundle ${_target} MACOSX_BUNDLE) - set(_qt_plugins_install_dirs "") set(_qt_conf_install_dirs "") set(_target_locations "") if(APPLE) if(_is_bundle) set(_target_locations ${_target}.app) set(${_target_locations}_qt_plugins_install_dir ${_target}.app/Contents/MacOS) set(_bundle_dest_dir ${_target}.app/Contents/MacOS) - set(_qt_plugins_for_current_bundle ${_target}.app/Contents/MacOS) set(_qt_conf_install_dirs ${_target}.app/Contents/Resources) install(TARGETS ${_target} BUNDLE DESTINATION . ) else() if(NOT MACOSX_BUNDLE_NAMES) set(_qt_conf_install_dirs bin) set(_target_locations bin/${_target}) - set(${_target_locations}_qt_plugins_install_dir bin) install(TARGETS ${_target} RUNTIME DESTINATION bin) else() foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) list(APPEND _qt_conf_install_dirs ${bundle_name}.app/Contents/Resources) set(_current_target_location ${bundle_name}.app/Contents/MacOS/${_target}) list(APPEND _target_locations ${_current_target_location}) - set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) - message( " set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) ") - install(TARGETS ${_target} RUNTIME DESTINATION ${bundle_name}.app/Contents/MacOS/) endforeach() endif() endif() else() set(_target_locations bin/${_target}${CMAKE_EXECUTABLE_SUFFIX}) - set(${_target_locations}_qt_plugins_install_dir bin) set(_qt_conf_install_dirs bin) install(TARGETS ${_target} RUNTIME DESTINATION bin) endif() foreach(_target_location ${_target_locations}) - if(NOT _qt_is_system_qt) - - if(QT_PLUGINS_DIR) - if(WIN32) - install(DIRECTORY "${QT_PLUGINS_DIR}" - DESTINATION ${${_target_location}_qt_plugins_install_dir} - CONFIGURATIONS Release - FILES_MATCHING REGEX "[^4d]4?${CMAKE_SHARED_LIBRARY_SUFFIX}" - ) - - install(DIRECTORY "${QT_PLUGINS_DIR}" - DESTINATION ${${_target_location}_qt_plugins_install_dir} - CONFIGURATIONS Debug - FILES_MATCHING REGEX "d4?${CMAKE_SHARED_LIBRARY_SUFFIX}" - ) - else(WIN32) - # install everything, see bug 7143 - install(DIRECTORY "${QT_PLUGINS_DIR}" - DESTINATION ${${_target_location}_qt_plugins_install_dir} - FILES_MATCHING REGEX "${CMAKE_SHARED_LIBRARY_SUFFIX}" - ) - - endif(WIN32) - - endif() - endif() _fixup_target() endforeach() - if(NOT _qt_is_system_qt) - - #-------------------------------------------------------------------------------- - # install a qt.conf file - # this inserts some cmake code into the install script to write the file + #-------------------------------------------------------------------------------- + # install a qt.conf file + # this inserts some cmake code into the install script to write the file + if(MITK_USE_Qt5) set(_qt_conf_plugin_install_prefix .) if(APPLE) set(_qt_conf_plugin_install_prefix ./MacOS) endif() foreach(_qt_conf_install_dir ${_qt_conf_install_dirs}) install(CODE "file(WRITE \"\${CMAKE_INSTALL_PREFIX}/${_qt_conf_install_dir}/qt.conf\" \" -[Paths] -Prefix=${_qt_conf_plugin_install_prefix} -\")") + [Paths] + Prefix=${_qt_conf_plugin_install_prefix} + \")") endforeach() - endif() - endforeach() - endmacro() diff --git a/CMake/mitkSetupCPack.cmake b/CMake/mitkSetupCPack.cmake index 4a415bbe5d..e7643b2ee7 100644 --- a/CMake/mitkSetupCPack.cmake +++ b/CMake/mitkSetupCPack.cmake @@ -1,143 +1,143 @@ # # First, set the generator variable # if(NOT CPACK_GENERATOR) if(WIN32) find_program(NSIS_MAKENSIS NAMES makensis PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS] DOC "Where is makensis.exe located" ) if(NOT NSIS_MAKENSIS) set(CPACK_GENERATOR ZIP) else() set(CPACK_GENERATOR "NSIS;ZIP") endif(NOT NSIS_MAKENSIS) else() if(APPLE) set(CPACK_GENERATOR DragNDrop) else() set(CPACK_GENERATOR TGZ) endif() endif() endif(NOT CPACK_GENERATOR) # Set Redistributable information for windows if(${CMAKE_SYSTEM_NAME} MATCHES Windows) include(mitkFunctionGetMSVCVersion) mitkFunctionGetMSVCVersion() set(CPACK_VISUAL_STUDIO_VERSION_MAJOR "${VISUAL_STUDIO_VERSION_MAJOR}") set(CPACK_VISUAL_STUDIO_PRODUCT_NAME "${VISUAL_STUDIO_PRODUCT_NAME}") set(CPACK_LIBRARY_ARCHITECTURE "${CMAKE_LIBRARY_ARCHITECTURE}") # Visual Studio 2017 already comes with redistributable installers. # Try to find the right one. set(vswhere "$ENV{PROGRAMFILES\(X86\)}\\Microsoft Visual Studio\\Installer\\vswhere.exe") if(EXISTS ${vswhere}) execute_process(COMMAND ${vswhere} -latest -property installationPath OUTPUT_VARIABLE installationPath OUTPUT_STRIP_TRAILING_WHITESPACE) file(TO_CMAKE_PATH "${installationPath}" installationPath) set(redistPath "${installationPath}/VC/Redist/MSVC") file(GLOB redistPath "${installationPath}/VC/Redist/MSVC/*") list(LENGTH redistPath length) if(length EQUAL 1) if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(redistPath "${redistPath}/vc_redist.x64.exe") else() set(redistPath "${redistPath}/vc_redist.x86.exe") endif() if(EXISTS ${redistPath}) set(CMAKE_${CPACK_VISUAL_STUDIO_PRODUCT_NAME}_REDISTRIBUTABLE ${redistPath} CACHE FILEPATH "Path to the appropriate Microsoft Visual Studio Redistributable") endif() endif() endif() if(NOT DEFINED CMAKE_${CPACK_VISUAL_STUDIO_PRODUCT_NAME}_REDISTRIBUTABLE) set(CMAKE_${CPACK_VISUAL_STUDIO_PRODUCT_NAME}_REDISTRIBUTABLE "" CACHE FILEPATH "Path to the appropriate Microsoft Visual Studio Redistributable") endif() endif() if(EXISTS ${CMAKE_${CPACK_VISUAL_STUDIO_PRODUCT_NAME}_REDISTRIBUTABLE} ) install(PROGRAMS ${CMAKE_${CPACK_VISUAL_STUDIO_PRODUCT_NAME}_REDISTRIBUTABLE} DESTINATION thirdpartyinstallers) get_filename_component(CPACK_REDISTRIBUTABLE_FILE_NAME ${CMAKE_${CPACK_VISUAL_STUDIO_PRODUCT_NAME}_REDISTRIBUTABLE} NAME ) endif() # On windows set default install directory appropriately for 32 and 64 bit # installers if not already set if(WIN32 AND NOT CPACK_NSIS_INSTALL_ROOT) if(CMAKE_CL_64) set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64") else() set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES") endif() endif() # By default, do not warn when built on machines using only VS Express if(NOT DEFINED CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS) set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS ON) endif() # include required mfc libraries include(InstallRequiredSystemLibraries) set(CPACK_PACKAGE_NAME "MITK") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "The Medical Imaging Interaction Toolkit") set(CPACK_PACKAGE_VENDOR "German Cancer Research Center (DKFZ)") set(CPACK_PACKAGE_DESCRIPTION_FILE "${MITK_SOURCE_DIR}/LICENSE") set(CPACK_RESOURCE_FILE_LICENSE "${MITK_SOURCE_DIR}/LICENSE") set(CPACK_PACKAGE_VERSION_MAJOR ${MITK_REVISION_DESC}) -string(REPLACE " [local changes]" "-local_changes" CPACK_PACKAGE_VERSION_MAJOR ${CPACK_PACKAGE_VERSION_MAJOR}) +string(REPLACE " [local changes]" "-local_changes" CPACK_PACKAGE_VERSION_MAJOR "${CPACK_PACKAGE_VERSION_MAJOR}") # tell cpack to strip all debug symbols from all files set(CPACK_STRIP_FILES ON) # set version if(NOT CPACK_PACKAGE_VERSION_MAJOR) set(CPACK_PACKAGE_VERSION_MAJOR ${MITK_VERSION_MAJOR}) set(CPACK_PACKAGE_VERSION_MINOR ${MITK_VERSION_MINOR}) set(CPACK_PACKAGE_VERSION_PATCH ${MITK_VERSION_PATCH}) set(CPACK_PACKAGE_VERSION "${MITK_VERSION_MAJOR}.${MITK_VERSION_MINOR}.${MITK_VERSION_PATCH}") else() set(CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}) endif() # determine possible system specific extension set(CPACK_PACKAGE_ARCH "unkown-architecture") if(${CMAKE_SYSTEM_NAME} MATCHES Windows) if(CMAKE_CL_64) set(CPACK_PACKAGE_ARCH "windows-x86_64") elseif(WIN32) set(CPACK_PACKAGE_ARCH "windows-x86") endif() endif() if(${CMAKE_SYSTEM_NAME} MATCHES Linux) if(${CMAKE_SYSTEM_PROCESSOR} MATCHES i686) set(CPACK_PACKAGE_ARCH "linux-x86") elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES x86_64) if(${CMAKE_CXX_FLAGS} MATCHES " -m32 ") set(CPACK_PACKAGE_ARCH "linux-x86") else() set(CPACK_PACKAGE_ARCH "linux-x86_64") endif() else() set(CPACK_PACKAGE_ARCH "linux") endif() endif() if(${CMAKE_SYSTEM_NAME} MATCHES Darwin) set(CPACK_PACKAGE_ARCH "macos-x86_64") endif() set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CPACK_PACKAGE_ARCH}") diff --git a/CMakeLists.txt b/CMakeLists.txt index dc145cb1c2..5001d8ce9e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,1470 +1,1470 @@ set(MITK_CMAKE_MINIMUM_REQUIRED_VERSION 3.14.5) cmake_minimum_required(VERSION ${MITK_CMAKE_MINIMUM_REQUIRED_VERSION}) #----------------------------------------------------------------------------- # See https://cmake.org/cmake/help/v3.14/manual/cmake-policies.7.html for details #----------------------------------------------------------------------------- set(project_policies ) foreach(policy ${project_policies}) if(POLICY ${policy}) cmake_policy(SET ${policy} NEW) endif() endforeach() #----------------------------------------------------------------------------- # Superbuild Option - Enabled by default #----------------------------------------------------------------------------- option(MITK_USE_SUPERBUILD "Build MITK and the projects it depends on via SuperBuild.cmake." ON) if(MITK_USE_SUPERBUILD) project(MITK-superbuild) set(MITK_SOURCE_DIR ${PROJECT_SOURCE_DIR}) set(MITK_BINARY_DIR ${PROJECT_BINARY_DIR}) else() project(MITK VERSION 2018.04.99) include_directories(SYSTEM ${MITK_SUPERBUILD_BINARY_DIR}) endif() #----------------------------------------------------------------------------- # MITK Extension Feature #----------------------------------------------------------------------------- set(MITK_EXTENSION_DIRS "" CACHE STRING "") set(MITK_DIR_PLUS_EXTENSION_DIRS ${MITK_SOURCE_DIR} ${MITK_EXTENSION_DIRS}) #----------------------------------------------------------------------------- # Update CMake module path #----------------------------------------------------------------------------- set(MITK_CMAKE_DIR ${MITK_SOURCE_DIR}/CMake) set(CMAKE_MODULE_PATH ${MITK_CMAKE_DIR}) foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) set(MITK_CMAKE_EXTENSION_DIR ${MITK_EXTENSION_DIR}/CMake) get_filename_component(MITK_CMAKE_EXTENSION_DIR ${MITK_CMAKE_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_CMAKE_EXTENSION_DIR}) list(APPEND CMAKE_MODULE_PATH ${MITK_CMAKE_EXTENSION_DIR}) endif() endforeach() #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- # Standard CMake macros include(FeatureSummary) include(CTestUseLaunchers) include(CMakeParseArguments) include(FindPackageHandleStandardArgs) # MITK macros include(mitkFunctionGetGccVersion) include(mitkFunctionCheckCompilerFlags) include(mitkFunctionSuppressWarnings) # includes several functions include(mitkMacroEmptyExternalProject) include(mitkFunctionGenerateProjectXml) include(mitkFunctionEnableBuildConfiguration) include(mitkFunctionWhitelists) include(mitkFunctionAddExternalProject) include(mitkFunctionAddLibrarySearchPaths) SUPPRESS_VC_DEPRECATED_WARNINGS() #----------------------------------------------------------------------------- # Set a default build type if none was specified #----------------------------------------------------------------------------- if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to 'Debug' as none was specified.") set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() #----------------------------------------------------------------------------- # Check miminum macOS version #----------------------------------------------------------------------------- # The minimum supported macOS version is 10.13. If you use a version less than 10.13, there is no guarantee that the build still works. if(APPLE) exec_program(sw_vers ARGS -productVersion OUTPUT_VARIABLE macos_version) if (macos_version VERSION_LESS "10.13") message(WARNING "Detected macOS version \"${macos_version}\" is not supported anymore. Minimum required macOS version is at least 10.13.") endif() if (CMAKE_OSX_DEPLOYMENT_TARGET AND CMAKE_OSX_DEPLOYMENT_TARGET VERSION_LESS 10.13) message(WARNING "Detected macOS deployment target \"${CMAKE_OSX_DEPLOYMENT_TARGET}\" is not supported anymore. Minimum required macOS version is at least 10.13.") endif() endif() #----------------------------------------------------------------------------- # Check miminum compiler versions #----------------------------------------------------------------------------- if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") # require at least gcc 4.9 as provided by ppa:ubuntu-toolchain-r/test for Ubuntu 14.04 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9) message(FATAL_ERROR "GCC version must be at least 4.9 If you are using Ubuntu 14.04, you can easily install gcc and g++ 4.9 (or any later version available) in addition to your version ${CMAKE_CXX_COMPILER_VERSION}: sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt-get update sudo apt-get install gcc-4.9 g++-4.9 Make sure to explicitly specify these compilers when configuring MITK: CMAKE_C_COMPILER:FILEPATH=/usr/bin/gcc-4.9 CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/g++-4.9 For more information on the proposed PPA see the Toolchain Updates section of https://wiki.ubuntu.com/ToolChain.") endif() elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") # require at least clang 3.4 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4) message(FATAL_ERROR "Clang version must be at least 3.4") endif() elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") # require at least clang 5.0 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) message(FATAL_ERROR "Apple Clang version must be at least 5.0") endif() elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") # require at least Visual Studio 2017 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.10) message(FATAL_ERROR "Microsoft Visual Studio 2017 or newer required") endif() else() message(WARNING "You are using an unsupported compiler! Compilation has only been tested with Clang (Linux or Apple), GCC and MSVC.") endif() if(CMAKE_COMPILER_IS_GNUCXX) mitkFunctionGetGccVersion(${CMAKE_CXX_COMPILER} GCC_VERSION) else() set(GCC_VERSION 0) endif() set(MITK_CXX_STANDARD 14) set(CMAKE_CXX_EXTENSIONS 0) set(CMAKE_CXX_STANDARD ${MITK_CXX_STANDARD}) set(CMAKE_CXX_STANDARD_REQUIRED 1) # This is necessary to avoid problems with compile feature checks. # CMAKE_CXX_STANDARD seems to only set the -std=c++14 flag for targets. # However, compile flag checks also need to be done with -std=c++14. # The MITK_CXX14_FLAG variable is also used for external projects # build during the MITK super-build. mitkFunctionCheckCompilerFlags("-std=c++14" MITK_CXX14_FLAG) #----------------------------------------------------------------------------- # Warn if source or build path is too long #----------------------------------------------------------------------------- if(WIN32) set(_src_dir_length_max 50) set(_bin_dir_length_max 50) if(MITK_USE_SUPERBUILD) set(_src_dir_length_max 34) # _src_dir_length_max - strlen(ep/src/ITK-build) set(_bin_dir_length_max 40) # _bin_dir_length_max - strlen(MITK-build) endif() string(LENGTH "${MITK_SOURCE_DIR}" _src_n) string(LENGTH "${MITK_BINARY_DIR}" _bin_n) # The warnings should be converted to errors if(_src_n GREATER _src_dir_length_max) message(WARNING "MITK source code directory path length is too long (${_src_n} > ${_src_dir_length_max})." "Please move the MITK source code directory to a directory with a shorter path." ) endif() if(_bin_n GREATER _bin_dir_length_max) message(WARNING "MITK build directory path length is too long (${_bin_n} > ${_bin_dir_length_max})." "Please move the MITK build directory to a directory with a shorter path." ) endif() endif() #----------------------------------------------------------------------------- # Additional MITK Options (also shown during superbuild) #----------------------------------------------------------------------------- # ----------------------------------------- # General build options option(BUILD_SHARED_LIBS "Build MITK with shared libraries" ON) option(WITH_COVERAGE "Enable/Disable coverage" OFF) option(BUILD_TESTING "Test the project" ON) option(MITK_FAST_TESTING "Disable long-running tests like packaging" OFF) option(MITK_XVFB_TESTING "Execute test drivers through xvfb-run" OFF) option(MITK_BUILD_ALL_APPS "Build all MITK applications" OFF) option(MITK_BUILD_EXAMPLES "Build the MITK Examples" OFF) option(MITK_ENABLE_PIC_READER "Enable support for reading the DKFZ pic file format." ON) mark_as_advanced( MITK_XVFB_TESTING MITK_FAST_TESTING MITK_BUILD_ALL_APPS MITK_ENABLE_PIC_READER ) # ----------------------------------------- # Other options set(MITK_CUSTOM_REVISION_DESC "" CACHE STRING "Override MITK revision description") mark_as_advanced(MITK_CUSTOM_REVISION_DESC) +#----------------------------------------------------------------------------- +# Build configurations +#----------------------------------------------------------------------------- + +set(_buildConfigs "Custom") + +file(GLOB _buildConfigFiles CMake/BuildConfigurations/*.cmake) + +foreach(_buildConfigFile ${_buildConfigFiles}) + get_filename_component(_buildConfigFile ${_buildConfigFile} NAME_WE) + list(APPEND _buildConfigs ${_buildConfigFile}) +endforeach() + +foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) + file(GLOB _extBuildConfigFiles ${MITK_EXTENSION_DIR}/CMake/BuildConfigurations/*.cmake) + + foreach(_extBuildConfigFile ${_extBuildConfigFiles}) + get_filename_component(_extBuildConfigFile ${_extBuildConfigFile} NAME_WE) + list(APPEND _buildConfigs ${_extBuildConfigFile}) + endforeach() + + list(REMOVE_DUPLICATES _buildConfigs) +endforeach() + +set(MITK_BUILD_CONFIGURATION "Custom" CACHE STRING "Use pre-defined MITK configurations") +set_property(CACHE MITK_BUILD_CONFIGURATION PROPERTY STRINGS ${_buildConfigs}) + +mitkFunctionEnableBuildConfiguration() + +mitkFunctionCreateWhitelistPaths(MITK) +mitkFunctionFindWhitelists(MITK) + # ----------------------------------------- # Qt version related variables option(MITK_USE_Qt5 "Use Qt 5 library" ON) if(MITK_USE_Qt5) set(MITK_QT5_MINIMUM_VERSION 5.12) set(MITK_QT5_COMPONENTS Concurrent OpenGL PrintSupport Script Sql Svg Widgets Xml XmlPatterns WebEngineWidgets UiTools Help LinguistTools) if(APPLE) list(APPEND MITK_QT5_COMPONENTS DBus) elseif(UNIX) list(APPEND MITK_QT5_COMPONENTS X11Extras) endif() # Hint at default install locations of Qt if(NOT Qt5_DIR) if(MSVC) set(_dir_candidates "C:/Qt") if(CMAKE_GENERATOR MATCHES "^Visual Studio [0-9]+ ([0-9]+)") set(_compilers "msvc${CMAKE_MATCH_1}") elseif(CMAKE_GENERATOR MATCHES "Ninja") include(mitkFunctionGetMSVCVersion) mitkFunctionGetMSVCVersion() if(VISUAL_STUDIO_PRODUCT_NAME MATCHES "^Visual Studio ([0-9]+)") set(_compilers "msvc${CMAKE_MATCH_1}") endif() endif() if(_compilers MATCHES "[0-9]+") if (CMAKE_MATCH_0 EQUAL 2019) list(APPEND _compilers "msvc2017") # Binary compatible to 2019 endif() endif() else() set(_dir_candidates ~/Qt) if(APPLE) set(_compilers clang) else() list(APPEND _dir_candidates /opt/Qt) set(_compilers gcc) endif() endif() if(CMAKE_SIZEOF_VOID_P EQUAL 8) foreach(_compiler ${_compilers}) list(APPEND _compilers64 "${_compiler}_64") endforeach() set(_compilers ${_compilers64}) endif() foreach(_dir_candidate ${_dir_candidates}) get_filename_component(_dir_candidate ${_dir_candidate} REALPATH) foreach(_compiler ${_compilers}) set(_glob_expression "${_dir_candidate}/5.*/${_compiler}") file(GLOB _hints ${_glob_expression}) list(SORT _hints) list(APPEND MITK_QT5_HINTS ${_hints}) endforeach() endforeach() endif() find_package(Qt5 ${MITK_QT5_MINIMUM_VERSION} COMPONENTS ${MITK_QT5_COMPONENTS} REQUIRED HINTS ${MITK_QT5_HINTS}) if(${Qt5_VERSION} VERSION_GREATER_EQUAL 5.13) message(FATAL_ERROR "Qt version ${Qt5_VERSION_MAJOR}.${Qt5_VERSION_MINOR} is not yet supported. We recommend using the latest long-term support version 5.12.x.") endif() endif() set_property(GLOBAL PROPERTY MITK_EXTERNAL_PROJECTS "") include(CMakeExternals/ExternalProjectList.cmake) foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) set(MITK_CMAKE_EXTERNALS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/CMakeExternals) get_filename_component(MITK_CMAKE_EXTERNALS_EXTENSION_DIR ${MITK_CMAKE_EXTERNALS_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_CMAKE_EXTERNALS_EXTENSION_DIR}/ExternalProjectList.cmake) include(${MITK_CMAKE_EXTERNALS_EXTENSION_DIR}/ExternalProjectList.cmake) endif() endforeach() # ----------------------------------------- # Other MITK_USE_* options not related to # external projects build via the # MITK superbuild option(MITK_USE_BLUEBERRY "Build the BlueBerry platform" ON) option(MITK_USE_OpenCL "Use OpenCL GPU-Computing library" OFF) option(MITK_USE_OpenMP "Use OpenMP" OFF) option(MITK_USE_Python3 "Use Python 3" OFF) -#----------------------------------------------------------------------------- -# Build configurations -#----------------------------------------------------------------------------- - -set(_buildConfigs "Custom") - -file(GLOB _buildConfigFiles CMake/BuildConfigurations/*.cmake) - -foreach(_buildConfigFile ${_buildConfigFiles}) - get_filename_component(_buildConfigFile ${_buildConfigFile} NAME_WE) - list(APPEND _buildConfigs ${_buildConfigFile}) -endforeach() - -foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) - file(GLOB _extBuildConfigFiles ${MITK_EXTENSION_DIR}/CMake/BuildConfigurations/*.cmake) - - foreach(_extBuildConfigFile ${_extBuildConfigFiles}) - get_filename_component(_extBuildConfigFile ${_extBuildConfigFile} NAME_WE) - list(APPEND _buildConfigs ${_extBuildConfigFile}) - endforeach() - - list(REMOVE_DUPLICATES _buildConfigs) -endforeach() - -set(MITK_BUILD_CONFIGURATION "Custom" CACHE STRING "Use pre-defined MITK configurations") -set_property(CACHE MITK_BUILD_CONFIGURATION PROPERTY STRINGS ${_buildConfigs}) - -mitkFunctionEnableBuildConfiguration() - -mitkFunctionCreateWhitelistPaths(MITK) -mitkFunctionFindWhitelists(MITK) - # ----------------------------------------- # Custom dependency logic option(MITK_USE_SYSTEM_Boost "Use the system Boost" OFF) set(MITK_USE_Boost_LIBRARIES "" CACHE STRING "A semi-colon separated list of required Boost libraries") if(MITK_USE_cpprestsdk) find_package(OpenSSL QUIET) if(NOT OpenSSL_FOUND) set(openssl_message "Could not find OpenSSL (dependency of C++ REST SDK).\n") if(UNIX) if(APPLE) set(openssl_message "${openssl_message}Please install it using your favorite package management " "system (i.e. Homebrew or MacPorts).\n") else() set(openssl_message "${openssl_message}Please install the dev package of OpenSSL (i.e. libssl-dev).\n") endif() else() set(openssl_message "${openssl_message}Please install Win32 OpenSSL:\n" " https://slproweb.com/products/Win32OpenSSL.html\n") endif() set(openssl_message "${openssl_message}If it still cannot be found, you can hint CMake to find OpenSSL by " "adding/setting the OPENSSL_ROOT_DIR variable to the root directory of an " "OpenSSL installation. Make sure to clear variables of partly found " "versions of OpenSSL before, or they will be mixed up.") message(FATAL_ERROR ${openssl_message}) endif() list(APPEND MITK_USE_Boost_LIBRARIES date_time regex system) if(UNIX) list(APPEND MITK_USE_Boost_LIBRARIES atomic chrono filesystem random thread) endif() list(REMOVE_DUPLICATES MITK_USE_Boost_LIBRARIES) set(MITK_USE_Boost_LIBRARIES ${MITK_USE_Boost_LIBRARIES} CACHE STRING "A semi-colon separated list of required Boost libraries" FORCE) endif() if(MITK_USE_Python3) set(MITK_USE_ZLIB ON CACHE BOOL "" FORCE) if(APPLE AND CMAKE_FRAMEWORK_PATH AND CMAKE_FRAMEWORK_PATH MATCHES "python3\\.?([0-9]+)") find_package(Python3 3.${CMAKE_MATCH_1} EXACT REQUIRED COMPONENTS Interpreter Development NumPy) else() find_package(Python3 REQUIRED COMPONENTS Interpreter Development NumPy) endif() if(WIN32) string(REPLACE "\\" "/" Python3_STDARCH "${Python3_STDARCH}") string(REPLACE "\\" "/" Python3_STDLIB "${Python3_STDLIB}") string(REPLACE "\\" "/" Python3_SITELIB "${Python3_SITELIB}") endif() endif() if(BUILD_TESTING AND NOT MITK_USE_CppUnit) message("> Forcing MITK_USE_CppUnit to ON because BUILD_TESTING=ON") set(MITK_USE_CppUnit ON CACHE BOOL "Use CppUnit for unit tests" FORCE) endif() if(MITK_USE_BLUEBERRY) option(MITK_BUILD_ALL_PLUGINS "Build all MITK plugins" OFF) mark_as_advanced(MITK_BUILD_ALL_PLUGINS) if(NOT MITK_USE_CTK) message("> Forcing MITK_USE_CTK to ON because of MITK_USE_BLUEBERRY") set(MITK_USE_CTK ON CACHE BOOL "Use CTK in MITK" FORCE) endif() endif() #----------------------------------------------------------------------------- # Pixel type multiplexing #----------------------------------------------------------------------------- # Customize the default pixel types for multiplex macros set(MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES "int, unsigned int, short, unsigned short, char, unsigned char" CACHE STRING "List of integral pixel types used in AccessByItk and InstantiateAccessFunction macros") set(MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES "double, float" CACHE STRING "List of floating pixel types used in AccessByItk and InstantiateAccessFunction macros") set(MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES "itk::RGBPixel, itk::RGBAPixel" CACHE STRING "List of composite pixel types used in AccessByItk and InstantiateAccessFunction macros") set(MITK_ACCESSBYITK_DIMENSIONS "2,3" CACHE STRING "List of dimensions used in AccessByItk and InstantiateAccessFunction macros") mark_as_advanced(MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES MITK_ACCESSBYITK_DIMENSIONS ) # consistency checks if(NOT MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES) set(MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES "int, unsigned int, short, unsigned short, char, unsigned char" CACHE STRING "List of integral pixel types used in AccessByItk and InstantiateAccessFunction macros" FORCE) endif() if(NOT MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES) set(MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES "double, float" CACHE STRING "List of floating pixel types used in AccessByItk and InstantiateAccessFunction macros" FORCE) endif() if(NOT MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES) set(MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES "itk::RGBPixel, itk::RGBAPixel" CACHE STRING "List of composite pixel types used in AccessByItk and InstantiateAccessFunction macros" FORCE) endif() if(NOT MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES) string(REPLACE "," ";" _integral_types ${MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES}) string(REPLACE "," ";" _floating_types ${MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES}) foreach(_scalar_type ${_integral_types} ${_floating_types}) set(MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES "${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES}itk::VariableLengthVector<${_scalar_type}>,") endforeach() string(LENGTH "${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES}" _length) math(EXPR _length "${_length} - 1") string(SUBSTRING "${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES}" 0 ${_length} MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES) set(MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES ${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES} CACHE STRING "List of vector pixel types used in AccessByItk and InstantiateAccessFunction macros for itk::VectorImage types" FORCE) endif() if(NOT MITK_ACCESSBYITK_DIMENSIONS) set(MITK_ACCESSBYITK_DIMENSIONS "2,3" CACHE STRING "List of dimensions used in AccessByItk and InstantiateAccessFunction macros") endif() #----------------------------------------------------------------------------- # Project.xml #----------------------------------------------------------------------------- # A list of topologically ordered targets set(CTEST_PROJECT_SUBPROJECTS) list(APPEND CTEST_PROJECT_SUBPROJECTS MITK-Core MITK-CoreUI MITK-IGT MITK-ToF MITK-Modules # all modules not contained in a specific subproject MITK-Plugins # all plugins not contained in a specific subproject MITK-Examples Unlabeled # special "subproject" catching all unlabeled targets and tests ) foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) set(MITK_CMAKE_EXTENSION_DIR ${MITK_EXTENSION_DIR}/CMake) get_filename_component(MITK_CMAKE_EXTENSION_DIR ${MITK_CMAKE_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_CMAKE_EXTENSION_DIR}/CTestSubprojectList.cmake) set(MITK_CTEST_SUBPROJECTS "") include(${MITK_CMAKE_EXTENSION_DIR}/CTestSubprojectList.cmake) if(MITK_CTEST_SUBPROJECTS) list(APPEND CTEST_PROJECT_SUBPROJECTS ${MITK_CTEST_SUBPROJECTS}) endif() endif() endforeach() # Configure CTestConfigSubProject.cmake that could be used by CTest scripts configure_file(${MITK_SOURCE_DIR}/CTestConfigSubProject.cmake.in ${MITK_BINARY_DIR}/CTestConfigSubProject.cmake) if(CTEST_PROJECT_ADDITIONAL_TARGETS) # those targets will be executed at the end of the ctest driver script # and they also get their own subproject label set(subproject_list "${CTEST_PROJECT_SUBPROJECTS};${CTEST_PROJECT_ADDITIONAL_TARGETS}") else() set(subproject_list "${CTEST_PROJECT_SUBPROJECTS}") endif() # Generate Project.xml file expected by the CTest driver script mitkFunctionGenerateProjectXml(${MITK_BINARY_DIR} MITK "${subproject_list}" ${MITK_USE_SUPERBUILD}) #----------------------------------------------------------------------------- # Superbuild script #----------------------------------------------------------------------------- if(MITK_USE_SUPERBUILD) include("${CMAKE_CURRENT_SOURCE_DIR}/SuperBuild.cmake") # Print configuration summary message("\n\n") feature_summary( DESCRIPTION "------- FEATURE SUMMARY FOR ${PROJECT_NAME} -------" WHAT ALL) return() endif() #***************************************************************************** #**************************** END OF SUPERBUILD **************************** #***************************************************************************** #----------------------------------------------------------------------------- # Organize MITK targets in folders #----------------------------------------------------------------------------- set_property(GLOBAL PROPERTY USE_FOLDERS ON) set(MITK_ROOT_FOLDER "MITK" CACHE STRING "") mark_as_advanced(MITK_ROOT_FOLDER) #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- include(WriteBasicConfigVersionFile) include(CheckCXXSourceCompiles) include(GenerateExportHeader) include(mitkFunctionAddCustomModuleTest) include(mitkFunctionCheckModuleDependencies) include(mitkFunctionCompileSnippets) include(mitkFunctionConfigureVisualStudioUserProjectFile) include(mitkFunctionConvertXPSchema) include(mitkFunctionCreateBlueBerryApplication) include(mitkFunctionCreateCommandLineApp) include(mitkFunctionCreateModule) include(mitkFunctionCreatePlugin) include(mitkFunctionCreateProvisioningFile) include(mitkFunctionGetLibrarySearchPaths) include(mitkFunctionGetVersion) include(mitkFunctionGetVersionDescription) include(mitkFunctionInstallAutoLoadModules) include(mitkFunctionInstallCTKPlugin) include(mitkFunctionInstallProvisioningFiles) include(mitkFunctionInstallThirdPartyCTKPlugins) include(mitkFunctionOrganizeSources) include(mitkFunctionUseModules) if( ${MITK_USE_MatchPoint} ) include(mitkFunctionCreateMatchPointDeployedAlgorithm) endif() include(mitkMacroConfigureItkPixelTypes) include(mitkMacroCreateExecutable) include(mitkMacroCreateModuleTests) include(mitkMacroGenerateToolsLibrary) include(mitkMacroGetLinuxDistribution) include(mitkMacroGetPMDPlatformString) include(mitkMacroInstall) include(mitkMacroInstallHelperApp) include(mitkMacroInstallTargets) include(mitkMacroMultiplexPicType) # Deprecated include(mitkMacroCreateCTKPlugin) #----------------------------------------------------------------------------- # Global CMake variables #----------------------------------------------------------------------------- # Required and enabled C++14 features for all MITK code. # These are added as PUBLIC compile features to all MITK modules. set(MITK_CXX_FEATURES cxx_auto_type cxx_decltype cxx_enum_forward_declarations cxx_extended_friend_declarations cxx_extern_templates cxx_final cxx_lambdas cxx_local_type_template_args cxx_long_long_type cxx_nullptr cxx_override cxx_range_for cxx_right_angle_brackets cxx_rvalue_references cxx_static_assert cxx_strong_enums cxx_template_template_parameters cxx_trailing_return_types cxx_variadic_macros ) if(NOT DEFINED CMAKE_DEBUG_POSTFIX) # We can't do this yet because the CTK Plugin Framework # cannot cope with a postfix yet. #set(CMAKE_DEBUG_POSTFIX d) endif() #----------------------------------------------------------------------------- # Output directories. #----------------------------------------------------------------------------- set(_default_LIBRARY_output_dir lib) set(_default_RUNTIME_output_dir bin) set(_default_ARCHIVE_output_dir lib) foreach(type LIBRARY RUNTIME ARCHIVE) # Make sure the directory exists if(MITK_CMAKE_${type}_OUTPUT_DIRECTORY AND NOT EXISTS ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}) message("Creating directory MITK_CMAKE_${type}_OUTPUT_DIRECTORY: ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}") file(MAKE_DIRECTORY "${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}") endif() if(MITK_CMAKE_${type}_OUTPUT_DIRECTORY) set(CMAKE_${type}_OUTPUT_DIRECTORY ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}) else() set(CMAKE_${type}_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/${_default_${type}_output_dir}) set(MITK_CMAKE_${type}_OUTPUT_DIRECTORY ${CMAKE_${type}_OUTPUT_DIRECTORY}) endif() set(CMAKE_${type}_OUTPUT_DIRECTORY ${CMAKE_${type}_OUTPUT_DIRECTORY} CACHE INTERNAL "Output directory for ${type} files.") mark_as_advanced(CMAKE_${type}_OUTPUT_DIRECTORY) endforeach() #----------------------------------------------------------------------------- # Set MITK specific options and variables (NOT available during superbuild) #----------------------------------------------------------------------------- # Look for optional Doxygen package find_package(Doxygen) option(BLUEBERRY_DEBUG_SMARTPOINTER "Enable code for debugging smart pointers" OFF) mark_as_advanced(BLUEBERRY_DEBUG_SMARTPOINTER) # Ask the user to show the console window for applications option(MITK_SHOW_CONSOLE_WINDOW "Use this to enable or disable the console window when starting MITK GUI Applications" ON) mark_as_advanced(MITK_SHOW_CONSOLE_WINDOW) # TODO: check if necessary option(USE_ITKZLIB "Use the ITK zlib for pic compression." ON) mark_as_advanced(USE_ITKZLIB) if(NOT MITK_FAST_TESTING) if(DEFINED MITK_CTEST_SCRIPT_MODE AND (MITK_CTEST_SCRIPT_MODE STREQUAL "continuous" OR MITK_CTEST_SCRIPT_MODE STREQUAL "experimental") ) set(MITK_FAST_TESTING ON) endif() endif() if(NOT UNIX) set(MITK_WIN32_FORCE_STATIC "STATIC" CACHE INTERNAL "Use this variable to always build static libraries on non-unix platforms") endif() if(MITK_BUILD_ALL_PLUGINS) set(MITK_BUILD_ALL_PLUGINS_OPTION "FORCE_BUILD_ALL") endif() # Configure pixel types used for ITK image access multiplexing mitkMacroConfigureItkPixelTypes() # Configure module naming conventions set(MITK_MODULE_NAME_REGEX_MATCH "^[A-Z].*$") set(MITK_MODULE_NAME_REGEX_NOT_MATCH "^[Mm][Ii][Tt][Kk].*$") set(MITK_DEFAULT_MODULE_NAME_PREFIX "Mitk") set(MITK_MODULE_NAME_PREFIX ${MITK_DEFAULT_MODULE_NAME_PREFIX}) set(MITK_MODULE_NAME_DEFAULTS_TO_DIRECTORY_NAME 1) #----------------------------------------------------------------------------- # Get MITK version info #----------------------------------------------------------------------------- mitkFunctionGetVersion(${MITK_SOURCE_DIR} MITK) mitkFunctionGetVersionDescription(${MITK_SOURCE_DIR} MITK) # MITK_VERSION set(MITK_VERSION_STRING "${MITK_VERSION_MAJOR}.${MITK_VERSION_MINOR}.${MITK_VERSION_PATCH}") if(MITK_VERSION_PATCH STREQUAL "99") set(MITK_VERSION_STRING "${MITK_VERSION_STRING}-${MITK_REVISION_SHORTID}") endif() #----------------------------------------------------------------------------- # Installation preparation # # These should be set before any MITK install macros are used #----------------------------------------------------------------------------- # on macOS all BlueBerry plugins get copied into every # application bundle (.app directory) specified here if(MITK_USE_BLUEBERRY AND APPLE) foreach(MITK_EXTENSION_DIR ${MITK_DIR_PLUS_EXTENSION_DIRS}) set(MITK_APPLICATIONS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/Applications) get_filename_component(MITK_APPLICATIONS_EXTENSION_DIR ${MITK_APPLICATIONS_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_APPLICATIONS_EXTENSION_DIR}/AppList.cmake) set(MITK_APPS "") include(${MITK_APPLICATIONS_EXTENSION_DIR}/AppList.cmake) foreach(mitk_app ${MITK_APPS}) # extract option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 1 option_name) list(GET target_info_list 0 app_name) # check if the application is enabled if(${option_name} OR MITK_BUILD_ALL_APPS) set(MACOSX_BUNDLE_NAMES ${MACOSX_BUNDLE_NAMES} Mitk${app_name}) endif() endforeach() endif() endforeach() endif() #----------------------------------------------------------------------------- # Set coverage Flags #----------------------------------------------------------------------------- if(WITH_COVERAGE) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(coverage_flags "-g -fprofile-arcs -ftest-coverage -O0 -DNDEBUG") set(COVERAGE_CXX_FLAGS ${coverage_flags}) set(COVERAGE_C_FLAGS ${coverage_flags}) endif() endif() #----------------------------------------------------------------------------- # MITK C/CXX Flags #----------------------------------------------------------------------------- set(MITK_C_FLAGS "${COVERAGE_C_FLAGS}") set(MITK_C_FLAGS_DEBUG ) set(MITK_C_FLAGS_RELEASE ) set(MITK_CXX_FLAGS "${COVERAGE_CXX_FLAGS} ${MITK_CXX14_FLAG}") set(MITK_CXX_FLAGS_DEBUG ) set(MITK_CXX_FLAGS_RELEASE ) set(MITK_EXE_LINKER_FLAGS ) set(MITK_SHARED_LINKER_FLAGS ) if(WIN32) set(MITK_CXX_FLAGS "${MITK_CXX_FLAGS} -DPOCO_NO_UNWINDOWS -DWIN32_LEAN_AND_MEAN -DNOMINMAX") mitkFunctionCheckCompilerFlags("/wd4005" MITK_CXX_FLAGS) # warning C4005: macro redefinition mitkFunctionCheckCompilerFlags("/wd4231" MITK_CXX_FLAGS) # warning C4231: nonstandard extension used : 'extern' before template explicit instantiation # the following line should be removed after fixing bug 17637 mitkFunctionCheckCompilerFlags("/wd4316" MITK_CXX_FLAGS) # warning C4316: object alignment on heap mitkFunctionCheckCompilerFlags("/wd4180" MITK_CXX_FLAGS) # warning C4180: qualifier applied to function type has no meaning mitkFunctionCheckCompilerFlags("/wd4251" MITK_CXX_FLAGS) # warning C4251: 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2' endif() if(APPLE) set(MITK_CXX_FLAGS "${MITK_CXX_FLAGS} -DGL_SILENCE_DEPRECATION") # Apple deprecated OpenGL in macOS 10.14 endif() if(NOT MSVC_VERSION) foreach(_flag -Wall -Wextra -Wpointer-arith -Winvalid-pch -Wcast-align -Wwrite-strings -Wno-error=gnu -Wno-error=unknown-pragmas # The strict-overflow warning is generated by ITK template code -Wno-error=strict-overflow -Woverloaded-virtual -Wstrict-null-sentinel #-Wold-style-cast #-Wsign-promo -Wno-error=deprecated-copy -Wno-array-bounds -fdiagnostics-show-option ) mitkFunctionCheckCAndCXXCompilerFlags(${_flag} MITK_C_FLAGS MITK_CXX_FLAGS) endforeach() endif() if(CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE) mitkFunctionCheckCompilerFlags("-Wl,--no-undefined" MITK_SHARED_LINKER_FLAGS) mitkFunctionCheckCompilerFlags("-Wl,--as-needed" MITK_SHARED_LINKER_FLAGS) endif() if(CMAKE_COMPILER_IS_GNUCXX) mitkFunctionCheckCAndCXXCompilerFlags("-fstack-protector-all" MITK_C_FLAGS MITK_CXX_FLAGS) set(MITK_CXX_FLAGS_RELEASE "-U_FORTIFY_SOURCES -D_FORTIFY_SOURCE=2 ${MITK_CXX_FLAGS_RELEASE}") endif() set(MITK_MODULE_LINKER_FLAGS ${MITK_SHARED_LINKER_FLAGS}) set(MITK_EXE_LINKER_FLAGS ${MITK_SHARED_LINKER_FLAGS}) #----------------------------------------------------------------------------- # MITK Packages #----------------------------------------------------------------------------- set(MITK_MODULES_PACKAGE_DEPENDS_DIR ${MITK_SOURCE_DIR}/CMake/PackageDepends) set(MODULES_PACKAGE_DEPENDS_DIRS ${MITK_MODULES_PACKAGE_DEPENDS_DIR}) foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) set(MITK_PACKAGE_DEPENDS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/CMake/PackageDepends) get_filename_component(MITK_PACKAGE_DEPENDS_EXTENSION_DIR ${MITK_PACKAGE_DEPENDS_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_PACKAGE_DEPENDS_EXTENSION_DIR}) list(APPEND MODULES_PACKAGE_DEPENDS_DIRS ${MITK_PACKAGE_DEPENDS_EXTENSION_DIR}) endif() endforeach() if(NOT MITK_USE_SYSTEM_Boost) set(Boost_NO_SYSTEM_PATHS 1) endif() set(Boost_USE_MULTITHREADED 1) set(Boost_USE_STATIC_LIBS 0) set(Boost_USE_STATIC_RUNTIME 0) set(Boost_ADDITIONAL_VERSIONS 1.68 1.68.0) # We need this later for a DCMTK workaround set(_dcmtk_dir_orig ${DCMTK_DIR}) # This property is populated at the top half of this file get_property(MITK_EXTERNAL_PROJECTS GLOBAL PROPERTY MITK_EXTERNAL_PROJECTS) foreach(ep ${MITK_EXTERNAL_PROJECTS}) get_property(_package GLOBAL PROPERTY MITK_${ep}_PACKAGE) get_property(_components GLOBAL PROPERTY MITK_${ep}_COMPONENTS) if(MITK_USE_${ep} AND _package) if(_components) find_package(${_package} COMPONENTS ${_components} REQUIRED CONFIG) else() # Prefer config mode first because it finds external # Config.cmake files pointed at by _DIR variables. # Otherwise, existing Find.cmake files could fail. if(DEFINED ${_package}_DIR) #we store the information because it will be overwritten by find_package #and would get lost for all EPs that use on Find.cmake instead of config #files. set(_temp_EP_${_package}_dir ${${_package}_DIR}) endif(DEFINED ${_package}_DIR) find_package(${_package} QUIET CONFIG) string(TOUPPER "${_package}" _package_uc) if(NOT (${_package}_FOUND OR ${_package_uc}_FOUND)) if(DEFINED _temp_EP_${_package}_dir) set(${_package}_DIR ${_temp_EP_${_package}_dir} CACHE PATH "externaly set dir of the package ${_package}" FORCE) endif(DEFINED _temp_EP_${_package}_dir) find_package(${_package} REQUIRED) endif() endif() endif() endforeach() # Ensure that the MITK CMake module path comes first set(CMAKE_MODULE_PATH ${MITK_CMAKE_DIR} ${CMAKE_MODULE_PATH} ) if(MITK_USE_DCMTK) # Due to the preferred CONFIG mode in find_package calls above, # the DCMTKConfig.cmake file is read, which does not provide useful # package information. We explictly need MODULE mode to find DCMTK. if(${_dcmtk_dir_orig} MATCHES "${MITK_EXTERNAL_PROJECT_PREFIX}.*") # Help our FindDCMTK.cmake script find our super-build DCMTK set(DCMTK_DIR ${MITK_EXTERNAL_PROJECT_PREFIX}) else() # Use the original value set(DCMTK_DIR ${_dcmtk_dir_orig}) endif() find_package(DCMTK REQUIRED MODULE) endif() if(MITK_USE_DCMQI) # Due to the preferred CONFIG mode in find_package calls above, # the DCMQIConfig.cmake file is read, which does not provide useful # package information. We explictly need MODULE mode to find DCMQI. # Help our FindDCMQI.cmake script find our super-build DCMQI set(DCMQI_DIR ${MITK_EXTERNAL_PROJECT_PREFIX}) find_package(DCMQI REQUIRED) endif() link_directories(${Boost_LIBRARY_DIRS}) if(MITK_USE_OpenIGTLink) link_directories(${OpenIGTLink_LIBRARY_DIRS}) endif() if(MITK_USE_OpenCL) find_package(OpenCL REQUIRED) endif() if(MITK_USE_OpenMP) find_package(OpenMP REQUIRED COMPONENTS CXX) else() find_package(OpenMP QUIET COMPONENTS CXX) if(OpenMP_FOUND) set(MITK_USE_OpenMP ON CACHE BOOL "" FORCE) elseif(APPLE AND OpenMP_libomp_LIBRARY AND NOT OpenMP_CXX_LIB_NAMES) set(OpenMP_CXX_LIB_NAMES libomp CACHE STRING "" FORCE) get_filename_component(openmp_lib_dir "${OpenMP_libomp_LIBRARY}" DIRECTORY) set(openmp_include_dir "${openmp_lib_dir}/../include") if(EXISTS "${openmp_include_dir}") get_filename_component(openmp_include_dir "${openmp_include_dir}" REALPATH) set(OpenMP_CXX_FLAGS "-Xpreprocessor -fopenmp -I${openmp_include_dir}" CACHE STRING "" FORCE) find_package(OpenMP QUIET COMPONENTS CXX) if(OpenMP_FOUND) set(MITK_USE_OpenMP ON CACHE BOOL "" FORCE) endif() endif() endif() endif() # Qt support if(MITK_USE_Qt5) find_package(Qt5Core ${MITK_QT5_MINIMUM_VERSION} REQUIRED) # at least Core required get_target_property(_qmake_exec Qt5::qmake LOCATION) execute_process(COMMAND ${_qmake_exec} -query QT_INSTALL_BINS RESULT_VARIABLE _result OUTPUT_VARIABLE QT_BINARY_DIR ERROR_VARIABLE _error ) string(STRIP "${QT_BINARY_DIR}" QT_BINARY_DIR) if(_result OR NOT EXISTS "${QT_BINARY_DIR}") message(FATAL_ERROR "Could not determine Qt binary directory: ${_result} ${QT_BINARY_DIR} ${_error}") endif() find_program(QT_HELPGENERATOR_EXECUTABLE NAMES qhelpgenerator qhelpgenerator-qt5 qhelpgenerator5 PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) find_program(QT_COLLECTIONGENERATOR_EXECUTABLE NAMES qcollectiongenerator qcollectiongenerator-qt5 qcollectiongenerator5 PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) find_program(QT_ASSISTANT_EXECUTABLE NAMES assistant assistant-qt5 assistant5 PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) find_program(QT_XMLPATTERNS_EXECUTABLE NAMES xmlpatterns PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) mark_as_advanced(QT_HELPGENERATOR_EXECUTABLE QT_COLLECTIONGENERATOR_EXECUTABLE QT_ASSISTANT_EXECUTABLE QT_XMLPATTERNS_EXECUTABLE ) if(MITK_USE_BLUEBERRY) option(BLUEBERRY_USE_QT_HELP "Enable support for integrating plugin documentation into Qt Help" ${DOXYGEN_FOUND}) mark_as_advanced(BLUEBERRY_USE_QT_HELP) # Sanity checks for in-application BlueBerry plug-in help generation if(BLUEBERRY_USE_QT_HELP) set(_force_blueberry_use_qt_help_to_off 0) if(NOT DOXYGEN_FOUND) message("> Forcing BLUEBERRY_USE_QT_HELP to OFF because Doxygen was not found.") set(_force_blueberry_use_qt_help_to_off 1) endif() if(DOXYGEN_FOUND AND DOXYGEN_VERSION VERSION_LESS 1.8.7) message("> Forcing BLUEBERRY_USE_QT_HELP to OFF because Doxygen version 1.8.7 or newer not found.") set(_force_blueberry_use_qt_help_to_off 1) endif() if(NOT QT_HELPGENERATOR_EXECUTABLE) message("> Forcing BLUEBERRY_USE_QT_HELP to OFF because QT_HELPGENERATOR_EXECUTABLE is empty.") set(_force_blueberry_use_qt_help_to_off 1) endif() if(NOT MITK_USE_Qt5) message("> Forcing BLUEBERRY_USE_QT_HELP to OFF because MITK_USE_Qt5 is OFF.") set(_force_blueberry_use_qt_help_to_off 1) endif() if(NOT QT_XMLPATTERNS_EXECUTABLE) message("You have enabled Qt Help support, but QT_XMLPATTERNS_EXECUTABLE is empty") set(_force_blueberry_use_qt_help_to_off 1) endif() if(_force_blueberry_use_qt_help_to_off) set(BLUEBERRY_USE_QT_HELP OFF CACHE BOOL "Enable support for integrating plugin documentation into Qt Help" FORCE) endif() endif() if(BLUEBERRY_QT_HELP_REQUIRED AND NOT BLUEBERRY_USE_QT_HELP) message(FATAL_ERROR "BLUEBERRY_USE_QT_HELP is required to be set to ON") endif() endif() endif() #----------------------------------------------------------------------------- # Testing #----------------------------------------------------------------------------- if(BUILD_TESTING) enable_testing() include(CTest) mark_as_advanced(TCL_TCLSH DART_ROOT) # Setup file for setting custom ctest vars configure_file( CMake/CTestCustom.cmake.in ${MITK_BINARY_DIR}/CTestCustom.cmake @ONLY ) # Initial cache for ProjectTemplate and PluginGenerator tests configure_file( CMake/mitkTestInitialCache.txt.in ${MITK_BINARY_DIR}/mitkTestInitialCache.txt @ONLY ) # Configuration for the CMake-generated test driver set(CMAKE_TESTDRIVER_EXTRA_INCLUDES "#include ") set(CMAKE_TESTDRIVER_BEFORE_TESTMAIN " try {") set(CMAKE_TESTDRIVER_AFTER_TESTMAIN " } catch ( const std::exception & excp ) { fprintf(stderr,\"%s\\n\",excp.what()); return EXIT_FAILURE; } catch( ... ) { printf(\"Exception caught in the test driver\\n\"); return EXIT_FAILURE; } ") set(MITK_TEST_OUTPUT_DIR "${MITK_BINARY_DIR}/test_output") if(NOT EXISTS ${MITK_TEST_OUTPUT_DIR}) file(MAKE_DIRECTORY ${MITK_TEST_OUTPUT_DIR}) endif() # Test the package target include(mitkPackageTest) endif() configure_file(mitkTestingConfig.h.in ${MITK_BINARY_DIR}/mitkTestingConfig.h) #----------------------------------------------------------------------------- # MITK_SUPERBUILD_BINARY_DIR #----------------------------------------------------------------------------- # If MITK_SUPERBUILD_BINARY_DIR isn't defined, it means MITK is *NOT* build using Superbuild. # In that specific case, MITK_SUPERBUILD_BINARY_DIR should default to MITK_BINARY_DIR if(NOT DEFINED MITK_SUPERBUILD_BINARY_DIR) set(MITK_SUPERBUILD_BINARY_DIR ${MITK_BINARY_DIR}) endif() #----------------------------------------------------------------------------- # Set C/CXX and linker flags for MITK code #----------------------------------------------------------------------------- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MITK_CXX_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${MITK_CXX_FLAGS_DEBUG}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${MITK_CXX_FLAGS_RELEASE}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${MITK_C_FLAGS}") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${MITK_C_FLAGS_DEBUG}") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${MITK_C_FLAGS_RELEASE}") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MITK_EXE_LINKER_FLAGS}") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${MITK_SHARED_LINKER_FLAGS}") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${MITK_MODULE_LINKER_FLAGS}") #----------------------------------------------------------------------------- # Add custom targets representing CDash subprojects #----------------------------------------------------------------------------- foreach(subproject ${CTEST_PROJECT_SUBPROJECTS}) if(NOT TARGET ${subproject} AND NOT subproject MATCHES "Unlabeled") add_custom_target(${subproject}) set_property(TARGET ${subproject} PROPERTY FOLDER "${MITK_ROOT_FOLDER}/CTestSubprojects") endif() endforeach() #----------------------------------------------------------------------------- # Add subdirectories #----------------------------------------------------------------------------- add_subdirectory(Utilities) add_subdirectory(Modules) include("${CMAKE_CURRENT_SOURCE_DIR}/Modules/ModuleList.cmake") mitkFunctionWhitelistModules(MITK MITK_MODULES) set(MITK_ROOT_FOLDER_BACKUP "${MITK_ROOT_FOLDER}") foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) get_filename_component(MITK_ROOT_FOLDER ${MITK_EXTENSION_DIR} NAME) set(MITK_MODULES_EXTENSION_DIR ${MITK_EXTENSION_DIR}/Modules) get_filename_component(MITK_MODULES_EXTENSION_DIR ${MITK_MODULES_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_MODULES_EXTENSION_DIR}/ModuleList.cmake) set(MITK_MODULES "") include(${MITK_MODULES_EXTENSION_DIR}/ModuleList.cmake) foreach(mitk_module ${MITK_MODULES}) add_subdirectory(${MITK_MODULES_EXTENSION_DIR}/${mitk_module} Modules/${mitk_module}) endforeach() endif() set(MITK_MODULE_NAME_PREFIX ${MITK_DEFAULT_MODULE_NAME_PREFIX}) endforeach() set(MITK_ROOT_FOLDER "${MITK_ROOT_FOLDER_BACKUP}") add_subdirectory(Wrapping) if(MITK_USE_BLUEBERRY) set(BLUEBERRY_XPDOC_OUTPUT_DIR "${MITK_DOXYGEN_OUTPUT_DIR}/html/extension-points/html/") execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${BLUEBERRY_XPDOC_OUTPUT_DIR}) include("${CMAKE_CURRENT_SOURCE_DIR}/Plugins/PluginList.cmake") mitkFunctionWhitelistPlugins(MITK MITK_PLUGINS) set(mitk_plugins_fullpath "") foreach(mitk_plugin ${MITK_PLUGINS}) list(APPEND mitk_plugins_fullpath Plugins/${mitk_plugin}) endforeach() set(MITK_PLUGIN_REGEX_LIST "") foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) set(MITK_PLUGINS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/Plugins) get_filename_component(MITK_PLUGINS_EXTENSION_DIR ${MITK_PLUGINS_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_PLUGINS_EXTENSION_DIR}/PluginList.cmake) set(MITK_PLUGINS "") include(${MITK_PLUGINS_EXTENSION_DIR}/PluginList.cmake) foreach(mitk_plugin ${MITK_PLUGINS}) list(APPEND mitk_plugins_fullpath ${MITK_PLUGINS_EXTENSION_DIR}/${mitk_plugin}) endforeach() endif() endforeach() if(EXISTS ${MITK_PRIVATE_MODULES}/PluginList.cmake) include(${MITK_PRIVATE_MODULES}/PluginList.cmake) foreach(mitk_plugin ${MITK_PRIVATE_PLUGINS}) list(APPEND mitk_plugins_fullpath ${MITK_PRIVATE_MODULES}/${mitk_plugin}) endforeach() endif() if(MITK_BUILD_EXAMPLES) include("${CMAKE_CURRENT_SOURCE_DIR}/Examples/Plugins/PluginList.cmake") set(mitk_example_plugins_fullpath ) foreach(mitk_example_plugin ${MITK_EXAMPLE_PLUGINS}) list(APPEND mitk_example_plugins_fullpath Examples/Plugins/${mitk_example_plugin}) list(APPEND mitk_plugins_fullpath Examples/Plugins/${mitk_example_plugin}) endforeach() endif() # Specify which plug-ins belong to this project macro(GetMyTargetLibraries all_target_libraries varname) set(re_ctkplugin_mitk "^org_mitk_[a-zA-Z0-9_]+$") set(re_ctkplugin_bb "^org_blueberry_[a-zA-Z0-9_]+$") set(_tmp_list) list(APPEND _tmp_list ${all_target_libraries}) ctkMacroListFilter(_tmp_list re_ctkplugin_mitk re_ctkplugin_bb MITK_PLUGIN_REGEX_LIST OUTPUT_VARIABLE ${varname}) endmacro() # Get infos about application directories and build options set(mitk_apps_fullpath "") foreach(MITK_EXTENSION_DIR ${MITK_DIR_PLUS_EXTENSION_DIRS}) set(MITK_APPLICATIONS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/Applications) get_filename_component(MITK_APPLICATIONS_EXTENSION_DIR ${MITK_APPLICATIONS_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_APPLICATIONS_EXTENSION_DIR}/AppList.cmake) set(MITK_APPS "") include(${MITK_APPLICATIONS_EXTENSION_DIR}/AppList.cmake) foreach(mitk_app ${MITK_APPS}) # extract option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 0 directory_name) list(GET target_info_list 1 option_name) if(${option_name}) list(APPEND mitk_apps_fullpath "${MITK_APPLICATIONS_EXTENSION_DIR}/${directory_name}^^${option_name}") endif() endforeach() endif() endforeach() if (mitk_plugins_fullpath) ctkMacroSetupPlugins(${mitk_plugins_fullpath} BUILD_OPTION_PREFIX MITK_BUILD_ APPS ${mitk_apps_fullpath} BUILD_ALL ${MITK_BUILD_ALL_PLUGINS} COMPACT_OPTIONS) endif() set(MITK_PLUGIN_USE_FILE "${MITK_BINARY_DIR}/MitkPluginUseFile.cmake") if(${PROJECT_NAME}_PLUGIN_LIBRARIES) ctkFunctionGeneratePluginUseFile(${MITK_PLUGIN_USE_FILE}) else() file(REMOVE ${MITK_PLUGIN_USE_FILE}) set(MITK_PLUGIN_USE_FILE ) endif() endif() #----------------------------------------------------------------------------- # Documentation #----------------------------------------------------------------------------- if(DOXYGEN_FOUND) add_subdirectory(Documentation) endif() #----------------------------------------------------------------------------- # Installation #----------------------------------------------------------------------------- # set MITK cpack variables # These are the default variables, which can be overwritten ( see below ) include(mitkSetupCPack) set(use_default_config ON) set(ALL_MITK_APPS "") set(activated_apps_no 0) foreach(MITK_EXTENSION_DIR ${MITK_DIR_PLUS_EXTENSION_DIRS}) set(MITK_APPLICATIONS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/Applications) get_filename_component(MITK_APPLICATIONS_EXTENSION_DIR ${MITK_APPLICATIONS_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_APPLICATIONS_EXTENSION_DIR}/AppList.cmake) set(MITK_APPS "") include(${MITK_APPLICATIONS_EXTENSION_DIR}/AppList.cmake) foreach(mitk_app ${MITK_APPS}) string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 0 directory_name) list(GET target_info_list 1 option_name) list(GET target_info_list 2 executable_name) list(APPEND ALL_MITK_APPS "${MITK_EXTENSION_DIR}/Applications/${directory_name}^^${option_name}^^${executable_name}") if(${option_name} OR MITK_BUILD_ALL_APPS) MATH(EXPR activated_apps_no "${activated_apps_no} + 1") endif() endforeach() endif() endforeach() list(LENGTH ALL_MITK_APPS app_count) if(app_count EQUAL 1 AND (activated_apps_no EQUAL 1 OR MITK_BUILD_ALL_APPS)) # Corner case if there is only one app in total set(use_project_cpack ON) elseif(activated_apps_no EQUAL 1 AND NOT MITK_BUILD_ALL_APPS) # Only one app is enabled (no "build all" flag set) set(use_project_cpack ON) else() # Less or more then one app is enabled set(use_project_cpack OFF) endif() foreach(mitk_app ${ALL_MITK_APPS}) # extract target_dir and option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 0 target_dir) list(GET target_info_list 1 option_name) list(GET target_info_list 2 executable_name) # check if the application is enabled if(${option_name} OR MITK_BUILD_ALL_APPS) # check whether application specific configuration files will be used if(use_project_cpack) # use files if they exist if(EXISTS "${target_dir}/CPackOptions.cmake") include("${target_dir}/CPackOptions.cmake") endif() if(EXISTS "${target_dir}/CPackConfig.cmake.in") set(CPACK_PROJECT_CONFIG_FILE "${target_dir}/CPackConfig.cmake") configure_file(${target_dir}/CPackConfig.cmake.in ${CPACK_PROJECT_CONFIG_FILE} @ONLY) set(use_default_config OFF) endif() endif() # add link to the list list(APPEND CPACK_CREATE_DESKTOP_LINKS "${executable_name}") endif() endforeach() # if no application specific configuration file was used, use default if(use_default_config) configure_file(${MITK_SOURCE_DIR}/MITKCPackOptions.cmake.in ${MITK_BINARY_DIR}/MITKCPackOptions.cmake @ONLY) set(CPACK_PROJECT_CONFIG_FILE "${MITK_BINARY_DIR}/MITKCPackOptions.cmake") endif() # include CPack model once all variables are set include(CPack) # Additional installation rules include(mitkInstallRules) #----------------------------------------------------------------------------- # Last configuration steps #----------------------------------------------------------------------------- # ---------------- Export targets ----------------- set(MITK_EXPORTS_FILE "${MITK_BINARY_DIR}/MitkExports.cmake") file(REMOVE ${MITK_EXPORTS_FILE}) set(targets_to_export) get_property(module_targets GLOBAL PROPERTY MITK_MODULE_TARGETS) if(module_targets) list(APPEND targets_to_export ${module_targets}) endif() if(MITK_USE_BLUEBERRY) if(MITK_PLUGIN_LIBRARIES) list(APPEND targets_to_export ${MITK_PLUGIN_LIBRARIES}) endif() endif() export(TARGETS ${targets_to_export} APPEND FILE ${MITK_EXPORTS_FILE}) set(MITK_EXPORTED_TARGET_PROPERTIES ) foreach(target_to_export ${targets_to_export}) get_target_property(autoload_targets ${target_to_export} MITK_AUTOLOAD_TARGETS) if(autoload_targets) set(MITK_EXPORTED_TARGET_PROPERTIES "${MITK_EXPORTED_TARGET_PROPERTIES} set_target_properties(${target_to_export} PROPERTIES MITK_AUTOLOAD_TARGETS \"${autoload_targets}\")") endif() get_target_property(autoload_dir ${target_to_export} MITK_AUTOLOAD_DIRECTORY) if(autoload_dir) set(MITK_EXPORTED_TARGET_PROPERTIES "${MITK_EXPORTED_TARGET_PROPERTIES} set_target_properties(${target_to_export} PROPERTIES MITK_AUTOLOAD_DIRECTORY \"${autoload_dir}\")") endif() get_target_property(deprecated_module ${target_to_export} MITK_MODULE_DEPRECATED_SINCE) if(deprecated_module) set(MITK_EXPORTED_TARGET_PROPERTIES "${MITK_EXPORTED_TARGET_PROPERTIES} set_target_properties(${target_to_export} PROPERTIES MITK_MODULE_DEPRECATED_SINCE \"${deprecated_module}\")") endif() endforeach() # ---------------- External projects ----------------- get_property(MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS_CONFIG GLOBAL PROPERTY MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS) set(MITK_CONFIG_EXTERNAL_PROJECTS ) #string(REPLACE "^^" ";" _mitk_external_projects ${MITK_EXTERNAL_PROJECTS}) foreach(ep ${MITK_EXTERNAL_PROJECTS}) get_property(_components GLOBAL PROPERTY MITK_${ep}_COMPONENTS) set(MITK_CONFIG_EXTERNAL_PROJECTS "${MITK_CONFIG_EXTERNAL_PROJECTS} set(MITK_USE_${ep} ${MITK_USE_${ep}}) set(MITK_${ep}_DIR \"${${ep}_DIR}\") set(MITK_${ep}_COMPONENTS ${_components}) ") endforeach() foreach(ep ${MITK_EXTERNAL_PROJECTS}) get_property(_package GLOBAL PROPERTY MITK_${ep}_PACKAGE) get_property(_components GLOBAL PROPERTY MITK_${ep}_COMPONENTS) if(_components) set(_components_arg COMPONENTS \${_components}) else() set(_components_arg) endif() if(_package) set(MITK_CONFIG_EXTERNAL_PROJECTS "${MITK_CONFIG_EXTERNAL_PROJECTS} if(MITK_USE_${ep}) set(${ep}_DIR \${MITK_${ep}_DIR}) if(MITK_${ep}_COMPONENTS) mitkMacroFindDependency(${_package} COMPONENTS \${MITK_${ep}_COMPONENTS}) else() mitkMacroFindDependency(${_package}) endif() endif()") endif() endforeach() # ---------------- Tools ----------------- configure_file(${MITK_SOURCE_DIR}/CMake/ToolExtensionITKFactory.cpp.in ${MITK_BINARY_DIR}/ToolExtensionITKFactory.cpp.in COPYONLY) configure_file(${MITK_SOURCE_DIR}/CMake/ToolExtensionITKFactoryLoader.cpp.in ${MITK_BINARY_DIR}/ToolExtensionITKFactoryLoader.cpp.in COPYONLY) configure_file(${MITK_SOURCE_DIR}/CMake/ToolGUIExtensionITKFactory.cpp.in ${MITK_BINARY_DIR}/ToolGUIExtensionITKFactory.cpp.in COPYONLY) # ---------------- Configure files ----------------- configure_file(mitkVersion.h.in ${MITK_BINARY_DIR}/mitkVersion.h) configure_file(mitkConfig.h.in ${MITK_BINARY_DIR}/mitkConfig.h) set(IPFUNC_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/ipFunc) set(UTILITIES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities) configure_file(mitkConfig.h.in ${MITK_BINARY_DIR}/mitkConfig.h) configure_file(MITKConfig.cmake.in ${MITK_BINARY_DIR}/MITKConfig.cmake @ONLY) write_basic_config_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake VERSION ${MITK_VERSION_STRING} COMPATIBILITY AnyNewerVersion) #----------------------------------------------------------------------------- # MITK Applications #----------------------------------------------------------------------------- # This must come after MITKConfig.h was generated, since applications # might do a find_package(MITK REQUIRED). add_subdirectory(Applications) if(MSVC AND TARGET MitkWorkbench) set_directory_properties(PROPERTIES VS_STARTUP_PROJECT MitkWorkbench) endif() foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) set(MITK_APPLICATIONS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/Applications) get_filename_component(MITK_APPLICATIONS_EXTENSION_DIR ${MITK_APPLICATIONS_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_APPLICATIONS_EXTENSION_DIR}/CMakeLists.txt) add_subdirectory(${MITK_APPLICATIONS_EXTENSION_DIR} Applications) endif() endforeach() #----------------------------------------------------------------------------- # MITK Examples #----------------------------------------------------------------------------- if(MITK_BUILD_EXAMPLES) # This must come after MITKConfig.h was generated, since applications # might do a find_package(MITK REQUIRED). add_subdirectory(Examples) endif() #----------------------------------------------------------------------------- # Print configuration summary #----------------------------------------------------------------------------- message("\n\n") feature_summary( DESCRIPTION "------- FEATURE SUMMARY FOR ${PROJECT_NAME} -------" WHAT ALL ) 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/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/SupportedPlatforms.md b/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/SupportedPlatforms.md index c3af74ee21..af2c0f8000 100644 --- a/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/SupportedPlatforms.md +++ b/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/SupportedPlatforms.md @@ -1,48 +1,48 @@ Supported Platforms {#SupportedPlatformsPage} =================== MITK is a cross-platform framework that is available for the following platforms: - Windows - Linux - macOS Supported Platforms Details --------------------------- The MITK team provides support for the most frequently used platforms and continuously runs testing procedures to ensure compatibility. Due to the large amount of possible combinations of operating systems and compiler versions, we divide platform support into two test categories: Tier 1 and Tier 2. Although MITK may be built on a broader range of platform-compiler combinations, only a subset of these are actively supported by the MITK development team. Tier 1 Platforms ---------------- All Tier 1 platforms are continuously tested by our unit test suite and other internal testing procedures. Errors or bugs discovered in these platforms are prioritized and corrected as soon as possible. | Platform | Compilers | ----------------------------------- | -------------------------------------------------- -| Microsoft Windows 10 (x64) | Visual Studio 2017 (latest update) -| Linux Ubuntu 18.04 (x64) | GCC 7.3 -| Linux Ubuntu 16.04 (x64) | GCC 5.4 +| Microsoft Windows 10 (x64) | Visual Studio 2019 (latest update) +| Linux Ubuntu 18.04 (x64) | Default GCC version +| Linux Ubuntu 16.04 (x64) | Default GCC version Tier 2 Platforms ---------------- Tier 2 platforms may or may not be tested on a regular basis. Some Tier 2 platforms are used by individual members of the MITK development team on a daily basis and some only receive occasional testing. While we strive to support these platforms, MITK users should note that errors may be present in released versions as well as in the current master branch. | Platform | Compilers | ----------------------------------- | -------------------------------------------------- -| Microsoft Windows 7 (x64) | Visual Studio 2017 (latest update) -| Apple macOS 10.14 "Mojave" | Apple LLVM 10.0 -| Apple macOS 10.13 "High Sierra" | Apple LLVM 10.0 +| Microsoft Windows 10 (x64) | Visual Studio 2017 (latest update) +| Apple macOS 10.15 "Catalina" | Default Apple Clang version +| Apple macOS 10.14 "Mojave" | Default Apple Clang version All platforms not listed above are not officially supported by the MITK team. However, we will happily accept contributions to improve support for other platforms. diff --git a/Modules/BasicImageProcessing/MiniApps/CMakeLists.txt b/Modules/BasicImageProcessing/MiniApps/CMakeLists.txt index c4254f4df3..e0aba755f2 100644 --- a/Modules/BasicImageProcessing/MiniApps/CMakeLists.txt +++ b/Modules/BasicImageProcessing/MiniApps/CMakeLists.txt @@ -1,99 +1,14 @@ option(BUILD_BasicImageProcessingMiniApps "Build commandline tools for Basic Image Processing" OFF) if(BUILD_BasicImageProcessingMiniApps OR MITK_BUILD_ALL_APPS) - - - include_directories( - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR} - ) - - # list of miniapps - # if an app requires additional dependencies - # they are added after a "^^" and separated by "_" - set( basicImageProcessingMiniApps - FileConverter^^MitkCore - ImageTypeConverter^^MitkCore - RectifyImage^^MitkCore - SingleImageArithmetic^^MitkCore_MitkBasicImageProcessing - TwoImageArithmetic^^MitkCore_MitkBasicImageProcessing - ImageAndValueArithmetic^^MitkCore_MitkBasicImageProcessing - MaskRangeBasedFiltering^^MitkCore_MitkBasicImageProcessing - MaskOutlierFiltering^^MitkCore_MitkBasicImageProcessing - ResampleImage^^MitkCore_MitkBasicImageProcessing - ResampleMask^^MitkCore_MitkBasicImageProcessing - LaplacianOfGaussian^^MitkCore_MitkBasicImageProcessing - MultiResolutionPyramid^^MitkCore_MitkBasicImageProcessing - ForwardWavelet^^MitkCore_MitkBasicImageProcessing - ) - - foreach(basicImageProcessingMiniApp ${basicImageProcessingMiniApps}) - # extract mini app name and dependencies - string(REPLACE "^^" "\\;" miniapp_info ${basicImageProcessingMiniApp}) - set(miniapp_info_list ${miniapp_info}) - list(GET miniapp_info_list 0 appname) - list(GET miniapp_info_list 1 raw_dependencies) - string(REPLACE "_" "\\;" dependencies "${raw_dependencies}") - set(dependencies_list ${dependencies}) - - mitk_create_executable(${appname} - DEPENDS MitkCore MitkCommandLine ${dependencies_list} - PACKAGE_DEPENDS ITK - CPP_FILES ${appname}.cpp - ) - # CPP_FILES ${appname}.cpp mitkCommandLineParser.cpp - - if(EXECUTABLE_IS_ENABLED) - - # On Linux, create a shell script to start a relocatable application - if(UNIX AND NOT APPLE) - install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) - endif() - - get_target_property(_is_bundle ${EXECUTABLE_TARGET} MACOSX_BUNDLE) - - if(APPLE) - if(_is_bundle) - set(_target_locations ${EXECUTABLE_TARGET}.app) - set(${_target_locations}_qt_plugins_install_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) - set(_bundle_dest_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) - set(_qt_plugins_for_current_bundle ${EXECUTABLE_TARGET}.app/Contents/MacOS) - set(_qt_conf_install_dirs ${EXECUTABLE_TARGET}.app/Contents/Resources) - install(TARGETS ${EXECUTABLE_TARGET} BUNDLE DESTINATION . ) - else() - if(NOT MACOSX_BUNDLE_NAMES) - set(_qt_conf_install_dirs bin) - set(_target_locations bin/${EXECUTABLE_TARGET}) - set(${_target_locations}_qt_plugins_install_dir bin) - install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) - else() - foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) - list(APPEND _qt_conf_install_dirs ${bundle_name}.app/Contents/Resources) - set(_current_target_location ${bundle_name}.app/Contents/MacOS/${EXECUTABLE_TARGET}) - list(APPEND _target_locations ${_current_target_location}) - set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) - message( " set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) ") - - install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION ${bundle_name}.app/Contents/MacOS/) - endforeach() - endif() - endif() - else() - set(_target_locations bin/${EXECUTABLE_TARGET}${CMAKE_EXECUTABLE_SUFFIX}) - set(${_target_locations}_qt_plugins_install_dir bin) - set(_qt_conf_install_dirs bin) - install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) - endif() - endif() - endforeach() - - # On Linux, create a shell script to start a relocatable application - if(UNIX AND NOT APPLE) - install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) - endif() - - if(EXECUTABLE_IS_ENABLED) - MITK_INSTALL_TARGETS(EXECUTABLES ${EXECUTABLE_TARGET}) - endif() - + mitkFunctionCreateCommandLineApp(NAME SingleImageArithmetic DEPENDS MitkBasicImageProcessing) + mitkFunctionCreateCommandLineApp(NAME TwoImageArithmetic DEPENDS MitkBasicImageProcessing) + mitkFunctionCreateCommandLineApp(NAME ImageAndValueArithmetic DEPENDS MitkBasicImageProcessing) + mitkFunctionCreateCommandLineApp(NAME MaskRangeBasedFiltering DEPENDS MitkBasicImageProcessing) + mitkFunctionCreateCommandLineApp(NAME MaskOutlierFiltering DEPENDS MitkBasicImageProcessing) + mitkFunctionCreateCommandLineApp(NAME ResampleImage DEPENDS MitkBasicImageProcessing) + mitkFunctionCreateCommandLineApp(NAME ResampleMask DEPENDS MitkBasicImageProcessing) + mitkFunctionCreateCommandLineApp(NAME LaplacianOfGaussian DEPENDS MitkBasicImageProcessing) + mitkFunctionCreateCommandLineApp(NAME MultiResolutionPyramid DEPENDS MitkBasicImageProcessing) + mitkFunctionCreateCommandLineApp(NAME ForwardWavelet DEPENDS MitkBasicImageProcessing) endif() diff --git a/Modules/Chart/include/QmitkChartData.h b/Modules/Chart/include/QmitkChartData.h index ba2890b056..9f6349e3f5 100644 --- a/Modules/Chart/include/QmitkChartData.h +++ b/Modules/Chart/include/QmitkChartData.h @@ -1,160 +1,192 @@ /*============================================================================ 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 QmitkC3Data_h #define QmitkC3Data_h #include #include +#include +#include +#include +#include +#include +#include /** \brief This class holds the relevant properties for the chart generation with C3 such as labels and diagram type. * It is derived from QObject, because we need Q_PROPERTIES to send Data via QWebChannel to JavaScript. * \sa The actual data for the chart generation is in QmitkC3xyData! */ class QmitkChartData : public QObject { Q_OBJECT Q_PROPERTY(QVariant m_xAxisLabel READ GetXAxisLabel WRITE SetXAxisLabel NOTIFY SignalXAxisLabelChanged); Q_PROPERTY(QVariant m_yAxisLabel READ GetYAxisLabel WRITE SetYAxisLabel NOTIFY SignalYAxisLabelChanged); Q_PROPERTY(QVariant m_chartTitle READ GetTitle WRITE SetTitle NOTIFY SignalTitleChanged); Q_PROPERTY(QVariant m_themeName READ GetThemeName WRITE SetThemeName NOTIFY SignalThemeNameChanged); Q_PROPERTY(QVariant m_LegendPosition READ GetLegendPosition WRITE SetLegendPosition NOTIFY SignalLegendPositionChanged); Q_PROPERTY(QVariant m_ShowLegend READ GetShowLegend WRITE SetShowLegend NOTIFY SignalShowLegendChanged); Q_PROPERTY(QVariant m_ShowErrorBars READ GetShowErrorBars WRITE SetShowErrorBars NOTIFY SignalShowErrorBarsChanged); Q_PROPERTY(QVariant m_YAxisScale READ GetYAxisScale WRITE SetYAxisScale NOTIFY SignalYAxisScaleChanged); Q_PROPERTY(QVariant m_ShowSubchart READ GetShowSubchart WRITE SetShowSubchart NOTIFY SignalShowSubchartChanged); Q_PROPERTY(QVariant m_UsePercentageInPieChart READ GetUsePercentageInPieChart WRITE SetUsePercentageInPieChart NOTIFY SignalUsePercentageInPieChartChanged); Q_PROPERTY(QVariant m_DataPointSize READ GetDataPointSize WRITE SetDataPointSize NOTIFY SignalDataPointSizeChanged); Q_PROPERTY(QVariant m_StackedData READ GetStackedData WRITE SetStackedData NOTIFY SignalStackedDataChanged); Q_PROPERTY(QVariant m_MinValueXView READ GetMinValueXView WRITE SetMinValueXView NOTIFY SignalMinValueXViewChanged); Q_PROPERTY(QVariant m_MaxValueXView READ GetMaxValueXView WRITE SetMaxValueXView NOTIFY SignalMaxValueXViewChanged); Q_PROPERTY(QVariant m_MinValueYView READ GetMinValueYView WRITE SetMinValueYView NOTIFY SignalMinValueYViewChanged); Q_PROPERTY(QVariant m_MaxValueYView READ GetMaxValueYView WRITE SetMaxValueYView NOTIFY SignalMaxValueYViewChanged); public: QmitkChartData(); void SetAppearance(bool showSubChart = true, bool usePercentageInPieChart = false); Q_INVOKABLE QVariant GetXAxisLabel() const { return m_xAxisLabel; }; Q_INVOKABLE void SetXAxisLabel(const QVariant& label) { m_xAxisLabel = label; emit SignalXAxisLabelChanged(label); }; Q_INVOKABLE QVariant GetYAxisLabel() const { return m_yAxisLabel; }; Q_INVOKABLE void SetYAxisLabel(const QVariant& label) { m_yAxisLabel = label; emit SignalYAxisLabelChanged(label); }; Q_INVOKABLE QVariant GetTitle() const { return m_chartTitle; }; Q_INVOKABLE void SetTitle(const QVariant& title) { m_chartTitle = title; emit SignalTitleChanged(title); }; Q_INVOKABLE QVariant GetThemeName() const { return m_themeName; }; Q_INVOKABLE void SetThemeName(const QVariant &themeName) { m_themeName = themeName; emit SignalThemeNameChanged(themeName); }; Q_INVOKABLE QVariant GetLegendPosition() const { return m_LegendPosition; }; Q_INVOKABLE void SetLegendPosition(const QVariant& legendPosition) { m_LegendPosition = legendPosition; emit SignalLegendPositionChanged(legendPosition); }; Q_INVOKABLE QVariant GetShowLegend() const { return m_ShowLegend; }; Q_INVOKABLE void SetShowLegend(const QVariant& show) { m_ShowLegend = show; emit SignalShowLegendChanged(show); }; Q_INVOKABLE QVariant GetShowErrorBars() const { return m_ShowErrorBars; }; Q_INVOKABLE void SetShowErrorBars(const QVariant &show) { m_ShowErrorBars = show; emit SignalShowErrorBarsChanged(show); }; Q_INVOKABLE QVariant GetYAxisScale() const { return m_YAxisScale; }; Q_INVOKABLE void SetYAxisScale(const QVariant& YAxisScale) { m_YAxisScale = YAxisScale; emit SignalYAxisScaleChanged(YAxisScale); }; Q_INVOKABLE QVariant GetShowSubchart() const { return m_ShowSubchart; }; Q_INVOKABLE void SetShowSubchart(const QVariant& showSubchart) { m_ShowSubchart = showSubchart; emit SignalShowSubchartChanged(showSubchart); }; Q_INVOKABLE QVariant GetUsePercentageInPieChart() const { return m_UsePercentageInPieChart; }; Q_INVOKABLE void SetUsePercentageInPieChart(const QVariant& usePercentageInPieChart) { m_UsePercentageInPieChart = usePercentageInPieChart; emit SignalUsePercentageInPieChartChanged(usePercentageInPieChart); }; Q_INVOKABLE QVariant GetDataPointSize() const { return m_DataPointSize; }; Q_INVOKABLE void SetDataPointSize(const QVariant& showDataPoints) { m_DataPointSize = showDataPoints; emit SignalDataPointSizeChanged(showDataPoints); }; Q_INVOKABLE QVariant GetStackedData() const { return m_StackedData; }; Q_INVOKABLE void SetStackedData(const QVariant& stackedData) { m_StackedData = stackedData; emit SignalStackedDataChanged(m_StackedData); }; Q_INVOKABLE QVariant GetMinValueXView() const { return m_MinValueXView; }; Q_INVOKABLE void SetMinValueXView(const QVariant &minValueXView) { m_MinValueXView = minValueXView; emit SignalMinValueXViewChanged(m_MinValueXView); }; Q_INVOKABLE QVariant GetMaxValueXView() const { return m_MaxValueXView; }; Q_INVOKABLE void SetMaxValueXView(const QVariant &maxValueXView) { m_MaxValueXView = maxValueXView; emit SignalMaxValueXViewChanged(m_MaxValueXView); }; Q_INVOKABLE QVariant GetMinValueYView() const { return m_MinValueYView; }; Q_INVOKABLE void SetMinValueYView(const QVariant &minValueYView) { m_MinValueYView = minValueYView; emit SignalMinValueYViewChanged(m_MinValueYView); }; Q_INVOKABLE QVariant GetMaxValueYView() const { return m_MaxValueYView; }; Q_INVOKABLE void SetMaxValueYView(const QVariant &maxValueYView) { m_MaxValueYView = maxValueYView; emit SignalMaxValueYViewChanged(m_MaxValueYView); }; + void EmitSignalImageUrl() + { + emit SignalImageUrl(); + }; + signals: void SignalYAxisLabelChanged(const QVariant label); void SignalXAxisLabelChanged(const QVariant label); void SignalLegendPositionChanged(const QVariant legendPosition); void SignalShowLegendChanged(const QVariant show); void SignalShowErrorBarsChanged(const QVariant show); void SignalYAxisScaleChanged(const QVariant YAxisScale); void SignalTitleChanged(const QVariant title); void SignalThemeNameChanged(const QVariant themeName); void SignalShowSubchartChanged(const QVariant showSubchart); void SignalUsePercentageInPieChartChanged(const QVariant usePercentageInPieChart); void SignalDataPointSizeChanged(const QVariant showDataPoints); void SignalStackedDataChanged(const QVariant stackedData); void SignalMinValueXViewChanged(const QVariant minValueXView); void SignalMaxValueXViewChanged(const QVariant maxValueXView); void SignalMinValueYViewChanged(const QVariant minValueYView); void SignalMaxValueYViewChanged(const QVariant maxValueYView); + void SignalImageUrl(); + +public slots: + void slotImageUrl(const QString &datafromjs) + { + QString ds = QUrl::fromPercentEncoding(datafromjs.toLatin1()); + + QString filename = QFileDialog::getSaveFileName( + 0, + tr("Save Plot"), + "my_plot.svg", + tr("Scalable Vector Graphics (*.svg)") ); + if (filename.isEmpty()) + return; + + std::string out_image = ds.toStdString(); + boost::algorithm::replace_first(out_image, "data:image/svg+xml,", ""); + std::ofstream outfile(filename.toStdString()); + outfile.write(out_image.c_str(), out_image.size()); + outfile.close(); + } private: QVariant m_xAxisLabel; QVariant m_yAxisLabel; QVariant m_chartTitle; QVariant m_themeName = "dark"; QVariant m_ShowLegend = true; QVariant m_ShowErrorBars; QVariant m_LegendPosition = "topRight"; QVariant m_ShowSubchart; QVariant m_YAxisScale; QVariant m_UsePercentageInPieChart; QVariant m_numberDatasets; QVariant m_DataPointSize = 0; QVariant m_StackedData; QVariant m_MinValueXView; QVariant m_MaxValueXView; QVariant m_MinValueYView; QVariant m_MaxValueYView; }; #endif //QmitkC3Data_h diff --git a/Modules/Chart/include/QmitkChartWidget.h b/Modules/Chart/include/QmitkChartWidget.h index 7d44a723b4..b26aea11ea 100644 --- a/Modules/Chart/include/QmitkChartWidget.h +++ b/Modules/Chart/include/QmitkChartWidget.h @@ -1,333 +1,357 @@ /*============================================================================ 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 QmitkC3jsWidget_h #define QmitkC3jsWidget_h #include #include #include #include class QmitkChartxyData; /*! \brief QmitkChartWidget is a widget to display various charts based on the javascript chart library plotly. * \details Data is added via AddData1D() or AddData2D().\n * There can be multiple charts (of different types with different properties) created by calling AddData1D or AddData2D multiple times.\n\n * The following chart types are supported: * * line chart * * bar chart * * spline chart * * pie chart * * scatter chart * * area chart * * area spline chart. * * Technical details: The javascript code is embedded in a QWebEngineView. The actual js code is implemented in resource\Chart.js. * \sa https://plot.ly/javascript/ for further information about the used javaScript library. * \ingroup Modules/Chart */ class MITKCHART_EXPORT QmitkChartWidget : public QWidget { Q_OBJECT public: /*! * \brief enum of diagram types. */ enum class ChartType { bar, /*!< bar chart, see https://plot.ly/javascript/bar-charts/ */ line, /*!< line chart, see https://plot.ly/javascript/line-charts/ */ spline, /*!< spline chart (smoothed line chart), see https://plot.ly/~jduelfer/23/spline/#/ */ pie, /*!< pie chart, see https://plot.ly/javascript/pie-charts/ */ area, /*!< area chart, see https://plot.ly/javascript/filled-area-plots/ */ area_spline, /*!< area-spline chart, similar to https://plot.ly/~jduelfer/23/spline/#/ */ scatter /*!< scatter chart, see https://plot.ly/javascript/line-and-scatter/ */ }; /*! * \brief enum of chart style (modifies background and line color). */ enum class ColorTheme { darkstyle, /*!< background color: dark gray, foreground color: white*/ lightstyle /*!< background color: white, foreground color: black */ }; enum class LineStyle { solid, dashed }; + enum class MarkerSymbol { + circle, + diamond, + cross, + square, + pentagon, + star, + x, + diamond_tall, + star_diamond, + star_triangle_up, + star_triangle_down, + asterisk, + cross_thin, + x_thin + }; enum class ChartColor { red, orange, yellow, green, blue, purple, brown, magenta, tan, cyan, olive, maroon, navy, aquamarine, turqouise, silver, lime, teal, indigo, violet, pink, black, white, grey }; enum class AxisScale { linear, log }; /*! * \brief enum of legend position. * See https://plot.ly/javascript/legend/ */ enum class LegendPosition { bottomMiddle, bottomRight, topRight, topLeft, middleRight }; explicit QmitkChartWidget(QWidget* parent = nullptr); //for UnitTests explicit QmitkChartWidget(QWidget *parent, bool unitTest); ~QmitkChartWidget() override; /*! * \brief Adds 1D data to the widget * \details internally, the list is converted to a map with increasing integers keys starting at 0. * \param label the name of the data that is also used as identifier. * \param chartType the chart type that should be used for this data entry * \note the data can be cleared with ClearDiagram() * \note If the label name already exists, the name is replaced with a unique one by concatenating numbers to it. * \warning Pie chart is significantly different than the other chart types. Here, the data given by AddData1D is summed. Each entry represents a different category. */ void AddData1D(const std::vector& data1D, const std::string& label, ChartType chartType = ChartType::bar); /*! * \brief Updates data of an existing label * \param data1D the 1D data , \sa AddData1D * \param label the (existing) label * \note if the label does not exist, nothing happens */ void UpdateData1D(const std::vector &data1D, const std::string &label); /*! * \sa UpdateData1D * \sa AddData2D */ void UpdateData2D(const std::map &data2D, const std::string &label); /*! * \brief Adds 2D data to the widget. Call repeatedly for displaying multiple charts. * \details each entry represents a data point: key: value --> x-value: y-value. * \param label the name of the data that is also used as identifier. * \param chartType the chart type that should be used for this data entry * \note the data can be cleared with ClearDiagram() * \note If the label name already exists, the name is replaced with a unique one by concatenating numbers to it. * \warning Pie chart is significantly different than the other chart types. Here, the data given by AddData1D is summed. Each entry represents a different category. */ void UpdateChartExampleData(const std::map& data2D, const std::string& label, const std::string& type, const std::string& color, const std::string& lineStyle, const std::string& pieLabelsData = 0); void AddData2D(const std::map &data2D, const std::string &label, ChartType chartType = ChartType::bar); //Add Function for the ChartExample void AddChartExampleData(const std::map& data2D, const std::string& label, const std::string& type, const std::string& color, const std::string& style, const std::string& pieLabelsData = 0); /*! * \brief Removes data from the widget, works for 1D and 2D Data * \param label the name of the data that is also used as identifier. * \note All data can be cleared with ClearDiagram() * \throws Invalid Argument Exception when the label cannot be found */ void RemoveData(const std::string& label); void UpdateLabel(const std::string& existingLabel, const std::string& newLabel); QmitkChartxyData *GetDataElementByLabel(const std::string& label) const; /*! * \brief Sets the color of one data entry (identifier is previously assigned label) * \details the color name can be "red" or a hex number (#FF0000). * \warning Either define all data entries with a color or no data entry. If a mixed approach is used, * plotly choses the color of the data entry (that could be the same as a user defined color). * \note If an unknown label is given, nothing happens. * \sa https://www.w3schools.com/cssref/css_colors.asp */ void SetColor(const std::string& label, const std::string& colorName); /*! * \brief Sets the line style of one data entry (identifier is previously assigned label) * \details two line styles are possible: LineStyle::solid and LineStyle::dashed. * The default line style is solid. * \note If an unknown label is given, nothing happens. * \warning only sets the line style if the current chart type is ChartType::line. * However, the line style remains also if the chart changes (e.g. new chart type) */ void SetLineStyle(const std::string& label, LineStyle style); + /*! + * \brief Sets the marker style of one data entry (identifier is previously assigned label) + * \note If an unknown label is given, nothing happens. + */ + void SetMarkerSymbol(const std::string &label, MarkerSymbol symbol); + /*! * \brief Sets the axis scale to either linear (default) or logarithmic. * \sa https://plot.ly/javascript/log-plot/ */ void SetYAxisScale(AxisScale scale); void SetXAxisLabel(const std::string& label); void SetYAxisLabel(const std::string& label); /*! * \brief Sets labels for pie chart data. * \note in AddData1D, the label still has to be given that acts as a unique id. However, the label is omitted then. */ void SetPieLabels(const std::vector &pieLabels, const std::string &label); /*! * \brief Sets a title for the chart. */ void SetTitle(const std::string &title); /*! * \brief Sets the chart type for a data entry * \details for available types, see ChartType * \note If an unknown label is given, nothing happens. * \warning Pie chart is significantly different than the other chart types. Here, the data given by AddData1D is summed. Each entry represents a different category. * \sa DiagramType for available types */ void SetChartType(const std::string& label, ChartType type); /*! * \brief Sets error bars for data in x direction * \note If only error plus is provided, the error bars are symmetrical * \param label the name of the data that is also used as identifier. * \param errorPlus the error in positive direction * \param errorMinus the error in negative direction. Same as error plus if omitted */ void SetXErrorBars(const std::string &label, const std::vector &errorPlus, const std::vector& errorMinus = std::vector()); /*! * \brief Sets error bars for data in y direction * \details for parameters, see SetXErrorBars * \note If only error plus is provided, the error bars are symmetrical */ void SetYErrorBars(const std::string &label, const std::vector &errorPlus, const std::vector &errorMinus = std::vector()); /*! * \brief Sets the legend position. * \details Default position is bottom. * \sa LegendPosition for available types */ void SetLegendPosition(LegendPosition position); void SetShowLegend(bool show); void SetStackedData(bool stacked); /*! * \brief Displays the chart in the widget * \param showSubChart if a subchart is displayed inside the widget or not. * \note if no data has been provided, (\sa AddData1D AddData2D), an empty chart is displayed. */ void Show(bool showSubChart=false); /*! * \brief Either displays the dataPoints or not * \param showDataPoints if dataPoints are displayed inside the widget or not. * \details: example for not showing points: https://plot.ly/javascript/line-charts/#styling-line-plot * example for showing the points: https://plot.ly/javascript/pointcloud/ */ void SetShowDataPoints(bool showDataPoints); /*! * \brief Clears all data inside and resets the widget. */ void Clear(); /*! * \brief Sets the theme of the widget. * \details default is dark theme as in MITK. * \warning has to be called before Show() or Reload() to work */ void SetTheme(ColorTheme themeEnabled); /*! * \brief Sets whether the subchart shall be shown. * \details Changes the state of the current chart object. * \note Needs to be reloaded with Reload() to display changes. */ void SetShowSubchart(bool showSubChart); /*! * \brief Sets whether the error bars shall be shown. * \details Changes the state of the current chart object. * \note Needs to be reloaded with Reload() to display changes. * \param showErrorBars if error bars are displayed or not. */ void SetShowErrorBars(bool showErrorBars); /*! * \brief Sets the min and max x values of the chart * \details Zooms in to view the values between minValue and maxValue in x direction */ void SetMinMaxValueXView(double minValueX,double maxValueX); /*! * \brief Sets the min and max y values of the chart * \details Zooms in to view the values between minValue and maxValue in y direction */ void SetMinMaxValueYView(double minValueY, double maxValueY); /*! * \brief Reloads the chart in the widget * \details reloading may be needed to display added data in an existing chart */ void Reload(); QSize sizeHint() const override; + void SavePlotAsImage(); + public slots: void OnLoadFinished(bool isLoadSuccessful); void OnPageSuccessfullyLoaded(); signals: void PageSuccessfullyLoaded(); private: /*! source: https://stackoverflow.com/questions/29383/converting-bool-to-text-in-c*/ std::string convertBooleanValue(bool value) const; class Impl; std::unique_ptr m_Impl; }; #endif diff --git a/Modules/Chart/include/QmitkChartxyData.h b/Modules/Chart/include/QmitkChartxyData.h index e934b9510a..30f71d94fc 100644 --- a/Modules/Chart/include/QmitkChartxyData.h +++ b/Modules/Chart/include/QmitkChartxyData.h @@ -1,161 +1,171 @@ /*============================================================================ 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 QmitkC3xyData_h #define QmitkC3xyData_h #include /** /brief This class holds the actual data for the chart generation with C3. * data can be loaded in constructor directly or with SetData * It is derived from QObject, because we need Q_PROPERTIES to send Data via QWebChannel to JavaScript. */ class QmitkChartxyData : public QObject { Q_OBJECT Q_PROPERTY(QVariant m_LabelCount READ GetLabelCount CONSTANT); Q_PROPERTY(QList m_YData READ GetYData WRITE SetYData NOTIFY SignalDataChanged); Q_PROPERTY(QList m_XData READ GetXData WRITE SetXData NOTIFY SignalDataChanged); Q_PROPERTY( QList m_XErrorDataPlus READ GetXErrorDataPlus WRITE SetXErrorDataPlus NOTIFY SignalErrorDataChanged); Q_PROPERTY( QList m_XErrorDataMinus READ GetXErrorDataMinus WRITE SetXErrorDataMinus NOTIFY SignalErrorDataChanged); Q_PROPERTY( QList m_YErrorDataPlus READ GetYErrorDataPlus WRITE SetYErrorDataPlus NOTIFY SignalErrorDataChanged); Q_PROPERTY( QList m_YErrorDataMinus READ GetYErrorDataMinus WRITE SetYErrorDataMinus NOTIFY SignalErrorDataChanged); Q_PROPERTY( QList m_PieLabels READ GetPieLabels WRITE SetPieLabels NOTIFY SignalPieLabelsChanged); Q_PROPERTY(QVariant m_ChartType READ GetChartType WRITE SetChartType NOTIFY SignalDiagramTypeChanged); Q_PROPERTY(QVariant m_Color READ GetColor WRITE SetColor NOTIFY SignalColorChanged); Q_PROPERTY(QVariant m_Label READ GetLabel WRITE SetLabel NOTIFY SignalLabelChanged); Q_PROPERTY(QVariant m_LineStyleName READ GetLineStyle WRITE SetLineStyle NOTIFY SignalLineStyleChanged); + Q_PROPERTY(QVariant m_MarkerSymbolName READ GetMarkerSymbol WRITE SetMarkerSymbol NOTIFY SignalMarkerSymbolChanged); public: explicit QmitkChartxyData(const QMap &data, const QVariant &label, const QVariant &diagramType, const QVariant &position); // Constructor for Data2D (x:y=1:2, 2:6, 3:7) void SetData(const QMap &data); Q_INVOKABLE QVariant GetLabelCount() const { return m_LabelCount; } Q_INVOKABLE QList GetYData() const { return m_YData; }; Q_INVOKABLE void SetYData(const QList &yData) { m_YData = yData; emit SignalDataChanged(yData); }; Q_INVOKABLE QList GetXData() const { return m_XData; }; Q_INVOKABLE void SetXData(const QList &xData) { m_XData = xData; emit SignalDataChanged(xData); }; Q_INVOKABLE QList GetXErrorDataPlus() const { return m_XErrorDataPlus; }; Q_INVOKABLE void SetXErrorDataPlus(const QList &errorData) { m_XErrorDataPlus = errorData; emit SignalErrorDataChanged(errorData); }; Q_INVOKABLE QList GetXErrorDataMinus() const { return m_XErrorDataMinus; }; Q_INVOKABLE void SetXErrorDataMinus(const QList &errorData) { m_XErrorDataMinus = errorData; emit SignalErrorDataChanged(errorData); }; Q_INVOKABLE QList GetYErrorDataPlus() const { return m_YErrorDataPlus; }; Q_INVOKABLE void SetYErrorDataPlus(const QList &errorData) { m_YErrorDataPlus = errorData; emit SignalErrorDataChanged(errorData); }; Q_INVOKABLE QList GetYErrorDataMinus() const { return m_YErrorDataMinus; }; Q_INVOKABLE void SetYErrorDataMinus(const QList &errorData) { m_YErrorDataMinus = errorData; emit SignalErrorDataChanged(errorData); }; Q_INVOKABLE QVariant GetChartType() const { return m_ChartType; }; Q_INVOKABLE void SetChartType(const QVariant &chartType) { m_ChartType = chartType; emit SignalDiagramTypeChanged(chartType); }; Q_INVOKABLE QVariant GetLabel() const { return m_Label; }; Q_INVOKABLE void SetLabel(const QVariant &label) { m_Label = label; emit SignalLabelChanged(label); }; Q_INVOKABLE QList GetPieLabels() const { return m_PieLabels; }; Q_INVOKABLE void SetPieLabels(const QList &pieLabels) { m_PieLabels = pieLabels; }; Q_INVOKABLE QVariant GetColor() const { return m_Color; }; Q_INVOKABLE void SetColor(const QVariant &color) { m_Color = color; emit SignalColorChanged(color); }; + Q_INVOKABLE QVariant GetMarkerSymbol() const { return m_MarkerSymbolName; }; + Q_INVOKABLE void SetMarkerSymbol(const QVariant &markerSymbol) + { + m_MarkerSymbolName = markerSymbol; + emit SignalMarkerSymbolChanged(markerSymbol); + }; + Q_INVOKABLE QVariant GetLineStyle() const { return m_LineStyleName; }; Q_INVOKABLE void SetLineStyle(const QVariant &lineStyle) { m_LineStyleName = lineStyle; emit SignalLineStyleChanged(lineStyle); }; /** * \brief Clears the Data. * * This function clears the data (including error data). */ void ClearData(); QmitkChartxyData() {} signals: void SignalDataChanged(const QList data); void SignalErrorDataChanged(const QList errorData); void SignalDiagramTypeChanged(const QVariant diagramType); void SignalColorChanged(const QVariant color); void SignalLabelChanged(const QVariant label); void SignalPieLabelsChanged(const QList pieLabels); void SignalLineStyleChanged(const QVariant lineStyle); + void SignalMarkerSymbolChanged(const QVariant lineStyle); private: /** js needs to know which label position in the list QmitkChartWidget::Impl::m_C3xyData it has for updating the values*/ const QVariant m_LabelCount; QList m_YData; QList m_XData; QList m_XErrorDataPlus; QList m_XErrorDataMinus; QList m_YErrorDataPlus; QList m_YErrorDataMinus; QVariant m_Label; QList m_PieLabels; QVariant m_ChartType; QVariant m_Color; QVariant m_LineStyleName; + QVariant m_MarkerSymbolName; }; #endif // QmitkC3xyData_h diff --git a/Modules/Chart/resource/Chart.js b/Modules/Chart/resource/Chart.js index 78ae2adf06..2fe861932e 100644 --- a/Modules/Chart/resource/Chart.js +++ b/Modules/Chart/resource/Chart.js @@ -1,611 +1,628 @@ document.body.style.backgroundColor = 'rgb(240, 240, 240)'; const minHeight = 255; var chart; var xErrorValuesPlus=[]; var xErrorValuesMinus=[]; var yErrorValuesPlus=[]; var yErrorValuesMinus=[]; var xValues=[]; var yValues=[]; var dataLabels=[]; var pieDataLabels=[]; var xs = {}; var minValueX; var maxValueX; var minValueY; var maxValueY; var dataColors = {}; var chartTypes = {}; var lineStyle = {}; var backgroundColor = '#f0f0f0'; var foregroundColor = 'black'; var dataProperties = {}; var chartData = null; // Important loading function. This will be executed at first in this whole script. // Fetching data from QWebChannel and storing them for display purposes. window.onload = function() { initHeight(); - /** - * Adds handler for Qt signal emitted from QmitkChartxyData. - * Changes for single traces like value changes in a line plot are handled here. - */ - function handleDataChangeEvents(registeredChannelObject) - { - let position = registeredChannelObject.m_LabelCount; - registeredChannelObject.SignalDiagramTypeChanged.connect(function(newValue){ - let updateDiagramType = generateTraceByChartType(newValue); - Plotly.restyle('chart', updateDiagramType, position); - }); - - registeredChannelObject.SignalLineStyleChanged.connect(function(newValue){ - var dashValue; - if (newValue == "dashed"){ - dashValue = "dot"; - } - else { - dashValue = "solid"; - } - updateDash = { - line : { - "dash" : dashValue - } - } - - Plotly.restyle('chart', updateDash, position); - }); - - registeredChannelObject.SignalColorChanged.connect(function(newValue){ - var updateColor={ - marker:{ - "color" : newValue - }, - line:{ - "color" : newValue - } - } - Plotly.restyle('chart', updateColor, position); - }); - - registeredChannelObject.SignalDataChanged.connect(function(newValue){ - console.log("data changed for label " + registeredChannelObject.m_Label); - - let xDataTemp = registeredChannelObject.m_XData; - let yDataTemp = registeredChannelObject.m_YData; - - let trace = generateTraceByChartType(registeredChannelObject.m_ChartType); - - trace["x"] = [xDataTemp]; - trace["y"] = [yDataTemp]; - trace["name"] = registeredChannelObject.m_Label; - - Plotly.restyle('chart', trace, position); - }); - - registeredChannelObject.SignalLabelChanged.connect(function(newValue){ - let trace = { - name: newValue - }; - Plotly.restyle('chart', trace, position); - }); - } - - /** - * Adds handler for Qt signal emitted from QmitkChartData. - * Changes for the whole chart like title are handled here. - */ - function handleChartChangeEvents(registeredChannelObject) - { - registeredChannelObject.SignalXAxisLabelChanged.connect(function(newValue){ - var layout = { - xaxis: { - title: { - text: newValue - }, - color: foregroundColor - } - } - Plotly.relayout('chart', layout); - }); - - registeredChannelObject.SignalYAxisLabelChanged.connect(function(newValue){ - var layout = { - yaxis: { - title: { - text: newValue - }, - color: foregroundColor - } - } - Plotly.relayout('chart', layout); - }); - - registeredChannelObject.SignalTitleChanged.connect(function(newValue){ - var layout = { - title: { - text:newValue, - font: { - color: foregroundColor - } - } - } - Plotly.relayout('chart', layout); - }); - - registeredChannelObject.SignalLegendPositionChanged.connect(function(newValue){ - let legendPosition = generateLegendPosition(chartData.m_LegendPosition); - var layout = { - legend: legendPosition - } - Plotly.relayout('chart', layout); - }); - - registeredChannelObject.SignalYAxisScaleChanged.connect(function(newValue){ - var layout = { - yaxis : { - type : newValue - } - }; - Plotly.relayout('chart', layout); - }); - - registeredChannelObject.SignalShowLegendChanged.connect(function(newValue){ - var layout = { - showlegend : newValue - }; - Plotly.relayout('chart', layout); - }); - - registeredChannelObject.SignalShowSubchartChanged.connect(function(newValue){ - var layout = { - xaxis : {} - }; - if (newValue){ - layout.xaxis.rangeslider = {}; // adds range slider below x axis - } - Plotly.relayout('chart', layout); - }); - - } + /** + * Adds handler for Qt signal emitted from QmitkChartxyData. + * Changes for single traces like value changes in a line plot are handled here. + */ + function handleDataChangeEvents(registeredChannelObject) + { + let position = registeredChannelObject.m_LabelCount; + registeredChannelObject.SignalDiagramTypeChanged.connect(function(newValue){ + let updateDiagramType = generateTraceByChartType(newValue); + Plotly.restyle('chart', updateDiagramType, position); + }); + + registeredChannelObject.SignalLineStyleChanged.connect(function(newValue){ + var dashValue; + if (newValue == "dashed"){ + dashValue = "dot"; + } + else { + dashValue = "solid"; + } + updateDash = { + line : { + "dash" : dashValue + } + } + + Plotly.restyle('chart', updateDash, position); + }); + + registeredChannelObject.SignalColorChanged.connect(function(newValue){ + var updateColor={ + marker:{ + "color" : newValue + }, + line:{ + "color" : newValue + } + } + Plotly.restyle('chart', updateColor, position); + }); + + registeredChannelObject.SignalDataChanged.connect(function(newValue){ + let xDataTemp = registeredChannelObject.m_XData; + let yDataTemp = registeredChannelObject.m_YData; + + let trace = generateTraceByChartType(registeredChannelObject.m_ChartType); + + if (dataProperties[registeredChannelObject.m_Label]["style"] == "dashed"){ + trace["line"]["dash"] = "dot" + } + + trace["x"] = [xDataTemp]; + trace["y"] = [yDataTemp]; + trace["name"] = registeredChannelObject.m_Label; + + Plotly.restyle('chart', trace, position); + }); + + registeredChannelObject.SignalLabelChanged.connect(function(newValue){ + let trace = { + name: newValue + }; + Plotly.restyle('chart', trace, position); + }); + } + + /** + * Adds handler for Qt signal emitted from QmitkChartData. + * Changes for the whole chart like title are handled here. + */ + function handleChartChangeEvents(registeredChannelObject) + { + registeredChannelObject.SignalImageUrl.connect(function() { + Plotly.toImage('chart', {format: 'svg', width: 800, height: 500, filename: 'test_plot'}).then(function(result) { + registeredChannelObject.slotImageUrl(result); + }); + }); + + registeredChannelObject.SignalXAxisLabelChanged.connect(function(newValue){ + var layout = { + xaxis: { + title: { + text: newValue + }, + color: foregroundColor + } + } + Plotly.relayout('chart', layout); + }); + + registeredChannelObject.SignalYAxisLabelChanged.connect(function(newValue){ + var layout = { + yaxis: { + title: { + text: newValue + }, + color: foregroundColor + } + } + Plotly.relayout('chart', layout); + }); + + registeredChannelObject.SignalTitleChanged.connect(function(newValue){ + var layout = { + title: { + text:newValue, + font: { + color: foregroundColor + } + } + } + Plotly.relayout('chart', layout); + }); + + registeredChannelObject.SignalLegendPositionChanged.connect(function(newValue){ + let legendPosition = generateLegendPosition(chartData.m_LegendPosition); + var layout = { + legend: legendPosition + } + Plotly.relayout('chart', layout); + }); + + registeredChannelObject.SignalYAxisScaleChanged.connect(function(newValue){ + var layout = { + yaxis : { + type : newValue + } + }; + Plotly.relayout('chart', layout); + }); + + registeredChannelObject.SignalShowLegendChanged.connect(function(newValue){ + var layout = { + showlegend : newValue + }; + Plotly.relayout('chart', layout); + }); + + registeredChannelObject.SignalShowSubchartChanged.connect(function(newValue){ + var layout = { + xaxis : {} + }; + if (newValue){ + layout.xaxis.rangeslider = {}; // adds range slider below x axis + } + Plotly.relayout('chart', layout); + }); + } new QWebChannel(qt.webChannelTransport, function(channel) { chartData = channel.objects.chartData; - handleChartChangeEvents(chartData); - + handleChartChangeEvents(chartData); + let count = 0; for(let propertyName in channel.objects) { if (propertyName != 'chartData') { - let chartXYData = channel.objects[propertyName]; - handleDataChangeEvents(chartXYData); + let chartXYData = channel.objects[propertyName]; + handleDataChangeEvents(chartXYData); let xDataTemp = chartXYData.m_XData; let yDataTemp = chartXYData.m_YData; let xErrorsTempPlus = chartXYData.m_XErrorDataPlus; - let pieDataLabelsTemp = chartXYData.m_PieLabels; + let pieDataLabelsTemp = chartXYData.m_PieLabels; let xErrorsTempMinus = chartXYData.m_XErrorDataMinus; let yErrorsTempPlus = chartXYData.m_YErrorDataPlus; let yErrorsTempMinus = chartXYData.m_YErrorDataMinus; let dataLabel = chartXYData.m_Label; dataLabels.push(dataLabel); console.log("loading datalabel: "+dataLabel); //add label to x array xDataTemp.unshift('x'+count.toString()) xs[dataLabel] = 'x' + count.toString() xDataTemp.push(null); //append null value, to make sure the last tick on x-axis is displayed correctly yDataTemp.unshift(dataLabel) yDataTemp.push(null); //append null value, to make sure the last tick on y-axis is displayed correctly xValues[count] = xDataTemp yValues[count] = yDataTemp xErrorValuesPlus[count] = xErrorsTempPlus; xErrorValuesMinus[count] = xErrorsTempMinus; yErrorValuesPlus[count] = yErrorsTempPlus; yErrorValuesMinus[count] = yErrorsTempMinus; - pieDataLabels[count] = pieDataLabelsTemp; + pieDataLabels[count] = pieDataLabelsTemp; var tempLineStyle = ''; if (chartXYData.m_LineStyleName == "solid") { tempLineStyle = '' } else { tempLineStyle = "dashed" } dataProperties[dataLabel] = { - "color" : chartXYData.m_Color, - "chartType": chartXYData.m_ChartType, - "style": tempLineStyle + "color" : chartXYData.m_Color, + "chartType": chartXYData.m_ChartType, + "style": tempLineStyle, + "symbol": chartXYData.m_MarkerSymbolName } count++; } } - var theme = chartData.m_themeName; - minValueX = chartData.m_MinValueXView; - minValueY = chartData.m_MinValueYView; - maxValueX = chartData.m_MaxValueXView; - maxValueY = chartData.m_MaxValueYView; + var theme = chartData.m_themeName; + minValueX = chartData.m_MinValueXView; + minValueY = chartData.m_MinValueYView; + maxValueX = chartData.m_MaxValueXView; + maxValueY = chartData.m_MaxValueYView; - setThemeColors(theme); + setThemeColors(theme); generateChart(chartData); }); } /** * Inits the height of the chart element to 90% of the full window height. */ function initHeight() { var size = window.innerHeight-(window.innerHeight/100*5); //subtract 10% of height to hide vertical scrool bar let chart = document.getElementById("chart"); chart.style.height = `${size}px`; } function getPlotlyChartType(inputType){ let plotlyType = inputType; if (inputType == "line"){ plotlyType = "scatter"; } else if (inputType == "scatter"){ plotlyType = "scatterOnly" } return plotlyType; } /** * Generate error bars object * * @param {array} errors - contains error bar values * @return error bar object */ function generateErrorBars(errors, visible){ - let errorObject = { - type: 'data', - array: errors, - visible: visible - } + let errorObject = { + type: 'data', + array: errors, + visible: visible + } - return errorObject; + return errorObject; } /** * Generate legend position object * * @param legendPosition the string of the legendPosition enum from QmitkChartWidget * @return legend position object */ function generateLegendPosition(legendPosition){ if (legendPosition == "bottomMiddle"){ - var legendX = 0.5; - var legendY = -0.75; + var legendX = 0.5; + var legendY = -0.75; } else if (legendPosition == "bottomRight"){ - var legendX = 1; - var legendY = 0; + var legendX = 1; + var legendY = 0; } else if (legendPosition == "topRight"){ - var legendX = 1; - var legendY = 1; + var legendX = 1; + var legendY = 1; } else if (legendPosition == "topLeft"){ - var legendX = 0; - var legendY = 1; + var legendX = 0; + var legendY = 1; } else if (legendPosition == "middleRight"){ - var legendX = 1; - var legendY = 0.5; + var legendX = 1; + var legendY = 0.5; } - let legendPositionObject = { - x: legendX, - y: legendY, - font : { - color: foregroundColor - } - } + let legendPositionObject = { + x: legendX, + y: legendY, + font : { + color: foregroundColor + } + } - return legendPositionObject; + return legendPositionObject; } function generateErrorBarsAsymmetric(errorsPlus, errorsMinus, visible){ - let errorObject = generateErrorBars(errorsPlus, visible); - errorObject["arrayminus"] = errorsMinus; - errorObject["symmetric"] = false; + let errorObject = generateErrorBars(errorsPlus, visible); + errorObject["arrayminus"] = errorsMinus; + errorObject["symmetric"] = false; - return errorObject; + return errorObject; } function generateStackPlotData(){ let data = []; for (let index = 0; index < dataLabels.length; index++){ - let inputType = dataProperties[dataLabels[index]]["chartType"]; + let inputType = dataProperties[dataLabels[index]]["chartType"]; let chartType = getPlotlyChartType(inputType); let trace = { x: xValues[index].slice(1), y: yValues[index].slice(1), stackgroup: 'one', name: dataLabels[index], - type: chartType, - marker:{ - color: dataProperties[dataLabels[index]]["color"] - } + type: chartType, + marker:{ + color: dataProperties[dataLabels[index]]["color"] + } }; data.push(trace); } return data; } function generateTraceByChartType(chartType){ - let plotlyChartType = getPlotlyChartType(chartType); + let plotlyChartType = getPlotlyChartType(chartType); - let trace = { - type: plotlyChartType, - }; - trace["line"] = {} - if (plotlyChartType == "area"){ - trace["fill"] = 'tozeroy' - } else if (plotlyChartType == "spline"){ - trace["line"]["shape"] = 'spline' - } else if (plotlyChartType == "scatterOnly"){ - trace["mode"] = 'markers'; - } else if (plotlyChartType == "area-spline"){ - trace["fill"] = 'tozeroy' - trace["line"]["shape"] = 'spline' - } + let trace = { + type: plotlyChartType, + }; + + trace["mode"] = 'lines'; + if (chartData.m_DataPointSize > 0) + trace["mode"] = 'lines+markers'; - return trace; + trace["line"] = {} + if (plotlyChartType == "area") + { + trace["fill"] = 'tozeroy' + } + else if (plotlyChartType == "spline") + { + trace["line"]["shape"] = 'spline' + } + else if (plotlyChartType == "scatterOnly") + { + trace["mode"] = 'markers'; + } + else if (plotlyChartType == "area-spline") + { + trace["fill"] = 'tozeroy' + trace["line"]["shape"] = 'spline' + } + + return trace; } function generatePlotData(){ let data = []; for (let index = 0; index < dataLabels.length; index++){ - let trace = generateTraceByChartType(dataProperties[dataLabels[index]]["chartType"]); - - trace["x"] = xValues[index].slice(1); - trace["y"] = yValues[index].slice(1); - trace["name"] = dataLabels[index]; - if (dataProperties[dataLabels[index]]["chartType"]=="pie"){ - trace["values"] = yValues[index].slice(1); - if (typeof pieDataLabels[index] !== 'undefined' && pieDataLabels[index].length > 0){ - trace["labels"] = pieDataLabels[index]; - } - } - - if(typeof xErrorValuesPlus[index] !== 'undefined'){ - if(typeof xErrorValuesMinus[index] !== 'undefined' && xErrorValuesMinus[index].length > 0) - { - trace["error_x"] = generateErrorBarsAsymmetric(xErrorValuesPlus[index], xErrorValuesMinus[index], chartData.m_ShowErrorBars); - }else{ - trace["error_x"] = generateErrorBars(xErrorValuesPlus[index], chartData.m_ShowErrorBars); - } - } - - if(typeof yErrorValuesPlus[index] !== 'undefined'){ - if(typeof yErrorValuesMinus[index] !== 'undefined' && yErrorValuesMinus[index].length > 0) - { - trace["error_y"] = generateErrorBarsAsymmetric(yErrorValuesPlus[index], yErrorValuesMinus[index], chartData.m_ShowErrorBars); - }else{ - trace["error_y"] = generateErrorBars(yErrorValuesPlus[index], chartData.m_ShowErrorBars); - } - } + let trace = generateTraceByChartType(dataProperties[dataLabels[index]]["chartType"]); + + trace["x"] = xValues[index].slice(1); + trace["y"] = yValues[index].slice(1); + trace["name"] = dataLabels[index]; + if (dataProperties[dataLabels[index]]["chartType"]=="pie"){ + trace["values"] = yValues[index].slice(1); + if (typeof pieDataLabels[index] !== 'undefined' && pieDataLabels[index].length > 0){ + trace["labels"] = pieDataLabels[index]; + } + } + + if(typeof xErrorValuesPlus[index] !== 'undefined'){ + if(typeof xErrorValuesMinus[index] !== 'undefined' && xErrorValuesMinus[index].length > 0) + { + trace["error_x"] = generateErrorBarsAsymmetric(xErrorValuesPlus[index], xErrorValuesMinus[index], chartData.m_ShowErrorBars); + }else{ + trace["error_x"] = generateErrorBars(xErrorValuesPlus[index], chartData.m_ShowErrorBars); + } + } + + if(typeof yErrorValuesPlus[index] !== 'undefined'){ + if(typeof yErrorValuesMinus[index] !== 'undefined' && yErrorValuesMinus[index].length > 0) + { + trace["error_y"] = generateErrorBarsAsymmetric(yErrorValuesPlus[index], yErrorValuesMinus[index], chartData.m_ShowErrorBars); + }else{ + trace["error_y"] = generateErrorBars(yErrorValuesPlus[index], chartData.m_ShowErrorBars); + } + } // ===================== CHART TYPE OPTIONS HANDLING =========== - trace["line"]["color"] = dataProperties[dataLabels[index]]["color"] + trace["line"]["color"] = dataProperties[dataLabels[index]]["color"] // handle marker visibility/size/color - trace["marker"] = {size: chartData.m_DataPointSize, color: dataProperties[dataLabels[index]]["color"]} - if (chartData.m_DataPointSize == 0){ - trace["mode"] = "lines"; - } + trace["marker"] = {size: 6.5, line: {width: 1, color: dataProperties[dataLabels[index]]["color"]}, color: dataProperties[dataLabels[index]]["color"], symbol: dataProperties[dataLabels[index]]["symbol"]} if (dataProperties[dataLabels[index]]["style"] == "dashed"){ trace["line"]["dash"] = "dot" } data.push(trace) } return data; } /** * Here, the chart magic takes place. Plot.ly is called. * * @param {object} chartData - containing the options for plotting, not the actual values */ function generateChart(chartData) { console.log("generate chart"); - if (chartData == undefined) - { - chartData = {} - } + if (chartData == undefined) + { + chartData = {} + } - if (dataLabels == undefined) - { + if (dataLabels == undefined) + { dataLabels = [] - } + } //=============================== DATA ======================== var data = []; if (chartData.m_StackedData){ data = generateStackPlotData(); } else { data = generatePlotData(); } //=============================== STYLE ======================== let marginTop = chartData.m_chartTitle == undefined ? 10 : 50; let legendPosition = generateLegendPosition(chartData.m_LegendPosition); var layout = { - paper_bgcolor : backgroundColor, - plot_bgcolor : backgroundColor, + paper_bgcolor : backgroundColor, + plot_bgcolor : backgroundColor, title: { - text:chartData.m_chartTitle, - font: { - color: foregroundColor - } - }, + text:chartData.m_chartTitle, + font: { + color: foregroundColor + } + }, xaxis: { title: { - text: chartData.m_xAxisLabel - }, - color: foregroundColor + text: chartData.m_xAxisLabel + }, + color: foregroundColor }, yaxis: { title: { - text:chartData.m_yAxisLabel - }, - color: foregroundColor + text:chartData.m_yAxisLabel + }, + color: foregroundColor }, margin: { l: 50, r: 10, b: 40, t: marginTop, pad: 4 }, - showlegend: chartData.m_ShowLegend, - legend: legendPosition + showlegend: chartData.m_ShowLegend, + legend: legendPosition }; if (chartData.m_StackedData){ - layout["barmode"] = 'stack'; + layout["barmode"] = 'stack'; } if (chartData.m_YAxisScale){ - layout.yaxis["type"] = "log" + layout.yaxis["type"] = "log" } if (chartData.m_ShowSubchart){ layout.xaxis.rangeslider = {}; // adds range slider below x axis } - Plotly.plot('chart', data, layout, {displayModeBar: false, responsive: true}); + Plotly.react('chart', data, layout, {displayModeBar: false, responsive: true}); -if (minValueX !== null && maxValueX !== null){ - UpdateMinMaxValueXView(minValueX, maxValueX); -} + if (minValueX !== null && maxValueX !== null){ + UpdateMinMaxValueXView(minValueX, maxValueX); + } if (minValueY !== null && maxValueY !== null){ - UpdateMinMaxValueYView(minValueY, maxValueY); -} + UpdateMinMaxValueYView(minValueY, maxValueY); + } } /** * Change theme of chart. * * @param {string} color - dark or not dark */ function changeTheme(color) { - setThemeColors(color); -link = document.getElementsByTagName("link")[0]; + setThemeColors(color); + link = document.getElementsByTagName("link")[0]; if (color == 'dark') { link.href = "Chart_dark.css"; } else { link.href = "Chart.css"; } }; /** * Reload the chart with the given arguments. * * This method is called by C++. Changes on signature with caution. */ function Reload(){ console.log("Reload chart"); generateChart(chartData); } function SetShowSubchart(showSubchart) { - chartData.m_ShowSubchart = showSubchart; + chartData.m_ShowSubchart = showSubchart; } function setThemeColors(theme){ - if (theme == 'dark'){ - backgroundColor = '#2d2d30'; - foregroundColor = 'white'; - } - else { - backgroundColor = '#f0f0f0'; - foregroundColor = 'black'; - } + if (theme == 'dark'){ + backgroundColor = '#2d2d30'; + foregroundColor = 'white'; + } + else { + backgroundColor = '#f0f0f0'; + foregroundColor = 'black'; + } } function SetStackDataString(stackDataString) { chartData.m_StackedData = stackDataString; } function SetShowErrorBars(showErrorBars) { chartData.m_ShowErrorBars = showErrorBars; } /** * Zooms to the given x-axis min and max values. */ function UpdateMinMaxValueXView(minValueX, maxValueX) { //y-Axis can't be adapted for now. See https://github.com/plotly/plotly.js/issues/1876 let chart = document.getElementById("chart"); let update = { - xaxis:{ - range:[minValueX, maxValueX] - } - }; + xaxis:{ + range:[minValueX, maxValueX] + } + }; Plotly.relayout(chart, update); } /** * Zooms to the given y-axis min and max values. */ function UpdateMinMaxValueYView(minValueY, maxValueY) { //x-Axis can't be adapted for now. See https://github.com/plotly/plotly.js/issues/1876 let chart = document.getElementById("chart"); let update = { - yaxis:{ - range:[minValueY, maxValueY] - } - }; + yaxis:{ + range:[minValueY, maxValueY] + } + }; Plotly.relayout(chart, update); } /** * Transforms the view to another chart type. * * This method is called by C++. Changes on signature with caution. * @param {string} transformTo - 'line' or 'bar' */ function transformView(transformTo) { console.log("transform view"); console.log(transformTo); dataProperties[dataLabels[0]]["chartType"] = transformTo; // preserve chartType for later updates let plotlyType = getPlotlyChartType(transformTo); let chart = document.getElementById("chart"); let update = {type : plotlyType}; Plotly.restyle(chart, update, 0); // updates the given plotly trace at index 0 with an update object built of a standard trace object }; diff --git a/Modules/Chart/src/QmitkChartWidget.cpp b/Modules/Chart/src/QmitkChartWidget.cpp index 6e18aa5e02..3955aa3f2b 100644 --- a/Modules/Chart/src/QmitkChartWidget.cpp +++ b/Modules/Chart/src/QmitkChartWidget.cpp @@ -1,915 +1,954 @@ /*============================================================================ 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 #include "mitkExceptionMacro.h" #include #include class CustomPage : public QWebEnginePage { public: CustomPage(QObject *parent = nullptr) : QWebEnginePage(parent) {} virtual void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel /*level*/, const QString &message, int lineNumber, const QString & /*sourceID*/) override { MITK_INFO << "JS > " << lineNumber << ": " << message.toStdString(); } }; class QmitkChartWidget::Impl final { public: explicit Impl(QWidget *parent); ~Impl(); Impl(const Impl &) = delete; Impl &operator=(const Impl &) = delete; void AddData1D(const std::vector &data1D, const std::string &label, QmitkChartWidget::ChartType chartType); void AddData2D(const std::map &data2D, const std::string &label, QmitkChartWidget::ChartType chartType); void AddChartExampleData(const std::map& data2D, const std::string& label, const std::string& type, const std::string& color, const std::string& style, const std::string& pieLabelsData = 0); void UpdateData1D(const std::vector &data1D, const std::string &label); void UpdateData2D(const std::map &data2D, const std::string &label); void UpdateChartExampleData(const std::map& data2D, const std::string& label, const std::string& type, const std::string& color, const std::string& lineStyle, const std::string& pieLabelsData = 0); void RemoveData(const std::string &label); void UpdateLabel(const std::string &existingLabel, const std::string &newLabel); QmitkChartxyData* GetDataElementByLabel(const std::string& label) const; void ClearData(); void SetColor(const std::string &label, const std::string &colorName); + void SetLineStyle(const std::string &label, LineStyle style); + void SetMarkerSymbol(const std::string &label, MarkerSymbol symbol); + void SetYAxisScale(AxisScale scale); void SetXAxisLabel(const std::string &label); void SetYAxisLabel(const std::string &label); void SetPieLabels(const std::vector &pieLabels, const std::string &label); void SetTitle(const std::string &title); void SetXErrorBars(const std::string &label, const std::vector &errorPlus, const std::vector &errorMinus = std::vector()); void SetYErrorBars(const std::string &label, const std::vector &errorPlus, const std::vector &errorMinus = std::vector()); std::string GetThemeName() const; void SetThemeName(ColorTheme style); void SetLegendPosition(LegendPosition position); void Show(bool showSubChart); void SetShowLegend(bool show); void SetShowErrorBars(bool show); void SetStackedData(bool stacked); void SetShowDataPoints(bool showDataPoints = false); void SetShowSubchart(bool showSubChart); void SetChartType(const std::string &label, QmitkChartWidget::ChartType chartType); void SetMinMaxValueXView(double minValueX, double maxValueX); void SetMinMaxValueYView(double minValueY, double maxValueY); QList ConvertErrorVectorToQList(const std::vector &error); QList ConvertVectorToQList(const std::vector &vec); std::string ConvertChartTypeToString(QmitkChartWidget::ChartType chartType) const; void ClearJavaScriptChart(); void InitializeJavaScriptChart(); void CallJavaScriptFuntion(const QString &command); QSize sizeHint() const; + void GetImageUrl(); + private: using ChartxyDataVector = std::vector>; std::string GetUniqueLabelName(const QList &labelList, const std::string &label) const; QList GetDataLabels(const ChartxyDataVector &c3xyData) const; QWebChannel *m_WebChannel; QWebEngineView *m_WebEngineView; QmitkChartData m_C3Data; ChartxyDataVector m_C3xyData; std::map m_ChartTypeToName; std::map m_ChartColorToName; std::map m_ColorThemeToName; std::map m_LegendPositionToName; std::map m_LineStyleToName; + std::map m_MarkerSymbolToName; std::map m_AxisScaleToName; }; QmitkChartWidget::Impl::Impl(QWidget *parent) : m_WebChannel(new QWebChannel(parent)), m_WebEngineView(new QWebEngineView(parent)) { // disable context menu for QWebEngineView m_WebEngineView->setContextMenuPolicy(Qt::NoContextMenu); m_WebEngineView->setPage(new CustomPage()); // Set the webengineview to an initial empty page. The actual chart will be loaded once the data is calculated. m_WebEngineView->load(QUrl(QStringLiteral("qrc:///Chart/empty.html"))); m_WebEngineView->page()->setWebChannel(m_WebChannel); m_WebEngineView->settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, false); connect(m_WebEngineView, SIGNAL(loadFinished(bool)), parent, SLOT(OnLoadFinished(bool))); auto layout = new QGridLayout(parent); layout->setMargin(0); layout->addWidget(m_WebEngineView); m_ChartTypeToName.emplace(ChartType::bar, "bar"); m_ChartTypeToName.emplace(ChartType::line, "line"); m_ChartTypeToName.emplace(ChartType::spline, "spline"); m_ChartTypeToName.emplace(ChartType::pie, "pie"); m_ChartTypeToName.emplace(ChartType::area, "area"); m_ChartTypeToName.emplace(ChartType::area_spline, "area-spline"); m_ChartTypeToName.emplace(ChartType::scatter, "scatter"); m_ChartColorToName.emplace(ChartColor::red, "red"); m_ChartColorToName.emplace(ChartColor::orange, "orange"); m_ChartColorToName.emplace(ChartColor::yellow, "yellow"); m_ChartColorToName.emplace(ChartColor::green, "green"); m_ChartColorToName.emplace(ChartColor::blue, "blue"); m_ChartColorToName.emplace(ChartColor::purple, "purple"); m_ChartColorToName.emplace(ChartColor::brown, "brown"); m_ChartColorToName.emplace(ChartColor::magenta, "magenta"); m_ChartColorToName.emplace(ChartColor::tan, "tan"); m_ChartColorToName.emplace(ChartColor::cyan, "cyan"); m_ChartColorToName.emplace(ChartColor::olive, "olive"); m_ChartColorToName.emplace(ChartColor::maroon, "maroon"); m_ChartColorToName.emplace(ChartColor::navy, "navy"); m_ChartColorToName.emplace(ChartColor::aquamarine, "aquamarine"); m_ChartColorToName.emplace(ChartColor::turqouise, "turqouise"); m_ChartColorToName.emplace(ChartColor::silver, "silver"); m_ChartColorToName.emplace(ChartColor::lime, "lime"); m_ChartColorToName.emplace(ChartColor::teal, "teal"); m_ChartColorToName.emplace(ChartColor::indigo, "indigo"); m_ChartColorToName.emplace(ChartColor::violet, "violet"); m_ChartColorToName.emplace(ChartColor::pink, "pink"); m_ChartColorToName.emplace(ChartColor::black, "black"); m_ChartColorToName.emplace(ChartColor::white, "white"); m_ChartColorToName.emplace(ChartColor::grey, "grey"); m_LegendPositionToName.emplace(LegendPosition::bottomMiddle, "bottomMiddle"); m_LegendPositionToName.emplace(LegendPosition::bottomRight, "bottomRight"); m_LegendPositionToName.emplace(LegendPosition::topRight, "topRight"); m_LegendPositionToName.emplace(LegendPosition::topLeft, "topLeft"); m_LegendPositionToName.emplace(LegendPosition::middleRight, "middleRight"); m_LineStyleToName.emplace(LineStyle::solid, "solid"); m_LineStyleToName.emplace(LineStyle::dashed, "dashed"); + m_MarkerSymbolToName.emplace(MarkerSymbol::circle, "circle"); + m_MarkerSymbolToName.emplace(MarkerSymbol::cross, "cross"); + m_MarkerSymbolToName.emplace(MarkerSymbol::diamond, "diamond"); + m_MarkerSymbolToName.emplace(MarkerSymbol::pentagon, "pentagon"); + m_MarkerSymbolToName.emplace(MarkerSymbol::square, "square"); + m_MarkerSymbolToName.emplace(MarkerSymbol::star, "star"); + m_MarkerSymbolToName.emplace(MarkerSymbol::x, "x"); + + m_MarkerSymbolToName.emplace(MarkerSymbol::diamond_tall, "diamond-tall"); + m_MarkerSymbolToName.emplace(MarkerSymbol::star_diamond, "star-diamond"); + m_MarkerSymbolToName.emplace(MarkerSymbol::star_triangle_up, "star-triangle-up"); + m_MarkerSymbolToName.emplace(MarkerSymbol::star_triangle_down, "star-triangle-down"); + m_MarkerSymbolToName.emplace(MarkerSymbol::asterisk, "asterisk"); + m_MarkerSymbolToName.emplace(MarkerSymbol::cross_thin, "cross-thin"); + m_MarkerSymbolToName.emplace(MarkerSymbol::x_thin, "x-thin"); + m_AxisScaleToName.emplace(AxisScale::linear, ""); m_AxisScaleToName.emplace(AxisScale::log, "log"); m_ColorThemeToName.emplace(ColorTheme::lightstyle, "light"); m_ColorThemeToName.emplace(ColorTheme::darkstyle, "dark"); } QmitkChartWidget::Impl::~Impl() {} std::string QmitkChartWidget::Impl::GetThemeName() const { return m_C3Data.GetThemeName().toString().toStdString(); } std::string CheckForCorrectHex(const std::string &colorName) { std::regex rgx("([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})"); std::smatch match; if (!colorName.empty() && colorName.at(0) != '#' && std::regex_search(colorName.begin(), colorName.end(), match, rgx)) { return "#" + colorName; } else { return colorName; } } +void QmitkChartWidget::Impl::GetImageUrl() +{ + m_C3Data.EmitSignalImageUrl(); +} + void QmitkChartWidget::Impl::AddData1D(const std::vector &data1D, const std::string &label, QmitkChartWidget::ChartType type) { std::map transformedData2D; unsigned int count = 0; // transform the 1D data to 2D data for (const auto &ele : data1D) { transformedData2D[count] = ele; count++; } AddData2D(transformedData2D, label, type); } void QmitkChartWidget::Impl::AddData2D(const std::map &data2D, const std::string &label, QmitkChartWidget::ChartType type) { QMap data2DConverted; for (const auto &aValue : data2D) { data2DConverted.insert(aValue.first, aValue.second); } const std::string chartTypeName(m_ChartTypeToName.at(type)); auto definedLabels = GetDataLabels(m_C3xyData); auto uniqueLabel = GetUniqueLabelName(definedLabels, label); - if (type == ChartType::scatter) - { - SetShowDataPoints(true); - MITK_INFO << "Enabling data points for all because of scatter plot"; - } + unsigned int sizeOfC3xyData = static_cast(m_C3xyData.size()); m_C3xyData.push_back(std::make_unique(data2DConverted, QVariant(QString::fromStdString(uniqueLabel)), QVariant(QString::fromStdString(chartTypeName)), QVariant(sizeOfC3xyData))); } void QmitkChartWidget::Impl::AddChartExampleData(const std::map& data2D, const std::string& label, const std::string& type, const std::string& color, const std::string& lineStyle, const std::string& pieLabelsData) { QMap data2DConverted; for (const auto& aValue : data2D) { data2DConverted.insert(aValue.first, aValue.second); } auto definedLabels = GetDataLabels(m_C3xyData); auto uniqueLabel = GetUniqueLabelName(definedLabels, label); if (type == "scatter") { SetShowDataPoints(true); MITK_INFO << "Enabling data points for all because of scatter plot"; } unsigned int sizeOfC3xyData = static_cast(m_C3xyData.size()); std::unique_ptr chartData = std::make_unique( data2DConverted, QVariant(QString::fromStdString(uniqueLabel)), QVariant(QString::fromStdString(type)), QVariant(sizeOfC3xyData)); chartData->SetColor(QVariant(QString::fromStdString(color))); chartData->SetLineStyle(QVariant(QString::fromStdString(lineStyle))); if (pieLabelsData != "") { std::string pieLabelsDataWorkingString = pieLabelsData; QList pieLabelsDataList; while (pieLabelsDataWorkingString.size() != 0) { QVariant oneElement = QString::fromStdString(pieLabelsDataWorkingString.substr(0, pieLabelsDataWorkingString.find(";"))); pieLabelsDataList.push_back(oneElement); if (pieLabelsDataWorkingString.find(";") != std::string::npos) { pieLabelsDataWorkingString.erase(0, pieLabelsDataWorkingString.find(";") + 1); } else { pieLabelsDataWorkingString.erase(pieLabelsDataWorkingString.begin(), pieLabelsDataWorkingString.end()); } } chartData->SetPieLabels(pieLabelsDataList); } m_C3xyData.push_back(std::move(chartData)); } void QmitkChartWidget::Impl::UpdateData1D(const std::vector &data1D, const std::string &label) { std::map transformedData2D; unsigned int count = 0; // transform the 1D data to 2D data for (const auto &ele : data1D) { transformedData2D[count] = ele; count++; } UpdateData2D(transformedData2D, label); } void QmitkChartWidget::Impl::UpdateData2D(const std::map &data2D, const std::string &label) { auto element = GetDataElementByLabel(label); if (element) { QMap data2DConverted; for (const auto &aValue : data2D) { data2DConverted.insert(aValue.first, aValue.second); } element->SetData(data2DConverted); } } void QmitkChartWidget::Impl::UpdateChartExampleData(const std::map& data2D, const std::string& label, const std::string& type, const std::string& color, const std::string& lineStyle, const std::string& pieLabelsData) { UpdateData2D(data2D, label); auto element = GetDataElementByLabel(label); if (element) { element->SetChartType(QString::fromStdString(type)); element->SetColor(QString::fromStdString(color)); element->SetLineStyle(QString::fromStdString(lineStyle)); if (pieLabelsData != "") { std::string pieLabelsDataWorkingString = pieLabelsData; QList pieLabelsDataList; while (pieLabelsDataWorkingString.size() != 0) { QVariant oneElement = QString::fromStdString(pieLabelsDataWorkingString.substr(0, pieLabelsDataWorkingString.find(";"))); pieLabelsDataList.push_back(oneElement); if (pieLabelsDataWorkingString.find(";") != std::string::npos) { pieLabelsDataWorkingString.erase(0, pieLabelsDataWorkingString.find(";") + 1); } else { pieLabelsDataWorkingString.erase(pieLabelsDataWorkingString.begin(), pieLabelsDataWorkingString.end()); } } element->SetPieLabels(pieLabelsDataList); } } } void QmitkChartWidget::Impl::RemoveData(const std::string &label) { for (ChartxyDataVector::iterator iter = m_C3xyData.begin(); iter != m_C3xyData.end(); ++iter) { if ((*iter)->GetLabel().toString().toStdString() == label) { m_C3xyData.erase(iter); return; } } throw std::invalid_argument("Cannot Remove Data because the label does not exist."); } void QmitkChartWidget::Impl::ClearData() { for (auto &xyData : m_C3xyData) { m_WebChannel->deregisterObject(xyData.get()); } m_C3xyData.clear(); } void QmitkChartWidget::Impl::UpdateLabel(const std::string &existingLabel, const std::string &newLabel) { auto element = GetDataElementByLabel(existingLabel); if (element) { auto definedLabels = GetDataLabels(m_C3xyData); auto uniqueLabel = GetUniqueLabelName(definedLabels, newLabel); element->SetLabel(QString::fromStdString(uniqueLabel)); } } void QmitkChartWidget::Impl::SetColor(const std::string &label, const std::string &colorName) { auto element = GetDataElementByLabel(label); if (element) { auto colorChecked = CheckForCorrectHex(colorName); element->SetColor(QVariant(QString::fromStdString(colorChecked))); } } void QmitkChartWidget::Impl::SetLineStyle(const std::string &label, LineStyle style) { auto element = GetDataElementByLabel(label); const std::string lineStyleName(m_LineStyleToName.at(style)); element->SetLineStyle(QVariant(QString::fromStdString(lineStyleName))); } +void QmitkChartWidget::Impl::SetMarkerSymbol(const std::string &label, MarkerSymbol symbol) +{ + auto element = GetDataElementByLabel(label); + const std::string markerSymbolName(m_MarkerSymbolToName.at(symbol)); + element->SetMarkerSymbol(QVariant(QString::fromStdString(markerSymbolName))); +} + void QmitkChartWidget::Impl::SetYAxisScale(AxisScale scale) { const std::string axisScaleName(m_AxisScaleToName.at(scale)); m_C3Data.SetYAxisScale(QString::fromStdString(axisScaleName)); } QmitkChartxyData *QmitkChartWidget::Impl::GetDataElementByLabel(const std::string &label) const { for (const auto &qmitkChartxyData : m_C3xyData) { if (qmitkChartxyData->GetLabel().toString() == label.c_str()) { return qmitkChartxyData.get(); } } - MITK_WARN << "label " << label << " not found in QmitkChartWidget"; return nullptr; } QList QmitkChartWidget::Impl::GetDataLabels(const ChartxyDataVector &c3xyData) const { QList dataLabels; for (auto element = c3xyData.begin(); element != c3xyData.end(); ++element) { dataLabels.push_back((*element)->GetLabel()); } return dataLabels; } void QmitkChartWidget::Impl::SetXAxisLabel(const std::string &label) { m_C3Data.SetXAxisLabel(QString::fromStdString(label)); } void QmitkChartWidget::Impl::SetYAxisLabel(const std::string &label) { m_C3Data.SetYAxisLabel(QString::fromStdString(label)); } void QmitkChartWidget::Impl::SetPieLabels(const std::vector &pieLabels, const std::string &label) { auto element = GetDataElementByLabel(label); if (element) { if (element->GetChartType() == QVariant("pie")) { auto dataY = element->GetYData(); element->SetPieLabels(ConvertVectorToQList(pieLabels)); if (static_cast(dataY.size()) != pieLabels.size()) { MITK_INFO << "data has " << dataY.size() << " entries whereas pie labels have " << pieLabels.size() << " entries. Unnamed pie labels automatically get a numerical label."; } } else { MITK_INFO << "label" << label << "has chart type " << element->GetChartType().toString().toStdString() << ", but pie is required"; } } } void QmitkChartWidget::Impl::SetTitle(const std::string &title) { m_C3Data.SetTitle(QString::fromStdString(title)); } void QmitkChartWidget::Impl::SetThemeName(QmitkChartWidget::ColorTheme style) { const std::string themeName(m_ColorThemeToName.at(style)); m_C3Data.SetThemeName(QString::fromStdString(themeName)); } void QmitkChartWidget::Impl::SetLegendPosition(QmitkChartWidget::LegendPosition legendPosition) { const std::string legendPositionName(m_LegendPositionToName.at(legendPosition)); m_C3Data.SetLegendPosition(QString::fromStdString(legendPositionName)); } void QmitkChartWidget::Impl::Show(bool showSubChart) { if (m_C3xyData.empty()) { MITK_WARN << "no data available for display in chart"; } else { m_C3Data.SetAppearance(showSubChart, m_C3xyData.front()->GetChartType() == QVariant("pie")); } InitializeJavaScriptChart(); } void QmitkChartWidget::Impl::SetShowLegend(bool show) { m_C3Data.SetShowLegend(show); } void QmitkChartWidget::Impl::SetStackedData(bool stacked) { m_C3Data.SetStackedData(stacked); } void QmitkChartWidget::Impl::SetShowErrorBars(bool show) { m_C3Data.SetShowErrorBars(show); } void QmitkChartWidget::Impl::SetShowDataPoints(bool showDataPoints) { if (showDataPoints == true) { m_C3Data.SetDataPointSize(6.5); } else { m_C3Data.SetDataPointSize(0); } } void QmitkChartWidget::Impl::SetShowSubchart(bool showSubChart) { m_C3Data.SetShowSubchart(showSubChart); } void QmitkChartWidget::Impl::SetChartType(const std::string &label, QmitkChartWidget::ChartType chartType) { auto element = GetDataElementByLabel(label); if (element) { if (chartType == ChartType::scatter) { SetShowDataPoints(true); MITK_INFO << "Enabling data points for all because of scatter plot"; } const std::string chartTypeName(m_ChartTypeToName.at(chartType)); element->SetChartType(QVariant(QString::fromStdString(chartTypeName))); } } void QmitkChartWidget::Impl::SetMinMaxValueXView(double minValueX, double maxValueX) { m_C3Data.SetMinValueXView(minValueX); m_C3Data.SetMaxValueXView(maxValueX); } void QmitkChartWidget::Impl::SetMinMaxValueYView(double minValueY, double maxValueY) { m_C3Data.SetMinValueYView(minValueY); m_C3Data.SetMaxValueYView(maxValueY); } QList QmitkChartWidget::Impl::ConvertErrorVectorToQList(const std::vector &error) { QList errorConverted; for (const auto &aValue : error) { errorConverted.append(aValue); } return errorConverted; } QList QmitkChartWidget::Impl::ConvertVectorToQList(const std::vector &vec) { QList vecConverted; for (const auto &aValue : vec) { vecConverted.append(QString::fromStdString(aValue)); } return vecConverted; } void QmitkChartWidget::Impl::SetXErrorBars(const std::string &label, const std::vector &errorPlus, const std::vector &errorMinus) { auto element = GetDataElementByLabel(label); if (element) { auto errorConvertedPlus = ConvertErrorVectorToQList(errorPlus); auto errorConvertedMinus = ConvertErrorVectorToQList(errorMinus); element->SetXErrorDataPlus(errorConvertedPlus); element->SetXErrorDataMinus(errorConvertedMinus); } } void QmitkChartWidget::Impl::SetYErrorBars(const std::string &label, const std::vector &errorPlus, const std::vector &errorMinus) { auto element = GetDataElementByLabel(label); if (element) { auto errorConvertedPlus = ConvertErrorVectorToQList(errorPlus); auto errorConvertedMinus = ConvertErrorVectorToQList(errorMinus); element->SetYErrorDataPlus(errorConvertedPlus); element->SetYErrorDataMinus(errorConvertedMinus); } } std::string QmitkChartWidget::Impl::ConvertChartTypeToString(QmitkChartWidget::ChartType chartType) const { return m_ChartTypeToName.at(chartType); } QSize QmitkChartWidget::Impl::sizeHint() const { return QSize(400, 300); } void QmitkChartWidget::Impl::CallJavaScriptFuntion(const QString &command) { m_WebEngineView->page()->runJavaScript(command); } void QmitkChartWidget::Impl::ClearJavaScriptChart() { m_WebEngineView->load(QUrl(QStringLiteral("qrc:///Chart/empty.html"))); } void QmitkChartWidget::Impl::InitializeJavaScriptChart() { auto alreadyRegisteredObjects = m_WebChannel->registeredObjects(); auto alreadyRegisteredObjectsValues = alreadyRegisteredObjects.values(); // only register objects that have not been registered yet if (alreadyRegisteredObjectsValues.indexOf(&m_C3Data) == -1) { m_WebChannel->registerObject(QStringLiteral("chartData"), &m_C3Data); } unsigned count = 0; for (auto &xyData : m_C3xyData) { // only register objects that have not been registered yet if (alreadyRegisteredObjectsValues.indexOf(xyData.get()) == -1) { QString variableName = "xyData" + QString::number(count); m_WebChannel->registerObject(variableName, xyData.get()); } count++; } m_WebEngineView->load(QUrl(QStringLiteral("qrc:///Chart/QmitkChartWidget.html"))); } std::string QmitkChartWidget::Impl::GetUniqueLabelName(const QList &labelList, const std::string &label) const { QString currentLabel = QString::fromStdString(label); int counter = 0; while (labelList.contains(currentLabel)) { currentLabel = QString::fromStdString(label + std::to_string(counter)); counter++; } return currentLabel.toStdString(); } QmitkChartWidget::QmitkChartWidget(QWidget *parent) : QWidget(parent), m_Impl(new Impl(this)) { connect(this, &QmitkChartWidget::PageSuccessfullyLoaded, this, &QmitkChartWidget::OnPageSuccessfullyLoaded); } QmitkChartWidget::~QmitkChartWidget() {} void QmitkChartWidget::SetColor(const std::string &label, const std::string &colorName) { m_Impl->SetColor(label, colorName); } void QmitkChartWidget::SetLineStyle(const std::string &label, LineStyle style) { m_Impl->SetLineStyle(label, style); } +void QmitkChartWidget::SetMarkerSymbol(const std::string &label, MarkerSymbol symbol) +{ + m_Impl->SetMarkerSymbol(label, symbol); +} + void QmitkChartWidget::SetYAxisScale(AxisScale scale) { m_Impl->SetYAxisScale(scale); } void QmitkChartWidget::AddData1D(const std::vector &data1D, const std::string &label, ChartType type) { m_Impl->AddData1D(data1D, label, type); } void QmitkChartWidget::AddData2D(const std::map& data2D, const std::string& label, ChartType type) { m_Impl->AddData2D(data2D, label, type); } void QmitkChartWidget::AddChartExampleData(const std::map& data2D, const std::string& label, const std::string& type, const std::string& color, const std::string& lineStyle, const std::string& pieLabelsData) { m_Impl->AddChartExampleData(data2D, label, type, color, lineStyle, pieLabelsData); } void QmitkChartWidget::UpdateData1D(const std::vector &data1D, const std::string &label) { m_Impl->UpdateData1D(data1D, label); } void QmitkChartWidget::UpdateData2D(const std::map &data2D, const std::string &label) { m_Impl->UpdateData2D(data2D, label); } void QmitkChartWidget::UpdateChartExampleData(const std::map& data2D, const std::string& label, const std::string& type, const std::string& color, const std::string& lineStyle, const std::string& pieLabelsData) { m_Impl->UpdateChartExampleData(data2D, label, type, color, lineStyle, pieLabelsData); } void QmitkChartWidget::RemoveData(const std::string &label) { m_Impl->RemoveData(label); } void QmitkChartWidget::UpdateLabel(const std::string &existingLabel, const std::string &newLabel) { m_Impl->UpdateLabel(existingLabel, newLabel); } QmitkChartxyData* QmitkChartWidget::GetDataElementByLabel(const std::string& label) const { return m_Impl->GetDataElementByLabel(label); } void QmitkChartWidget::SetXAxisLabel(const std::string &label) { m_Impl->SetXAxisLabel(label); } void QmitkChartWidget::SetYAxisLabel(const std::string &label) { m_Impl->SetYAxisLabel(label); } void QmitkChartWidget::SetPieLabels(const std::vector &pieLabels, const std::string &label) { m_Impl->SetPieLabels(pieLabels, label); } void QmitkChartWidget::SetTitle(const std::string &title) { m_Impl->SetTitle(title); } void QmitkChartWidget::SetShowDataPoints(bool showDataPoints) { m_Impl->SetShowDataPoints(showDataPoints); } void QmitkChartWidget::SetChartType(const std::string &label, ChartType type) { m_Impl->SetChartType(label, type); } void QmitkChartWidget::SetXErrorBars(const std::string &label, const std::vector &errorPlus, const std::vector &errorMinus) { m_Impl->SetXErrorBars(label, errorPlus, errorMinus); } void QmitkChartWidget::SetYErrorBars(const std::string &label, const std::vector &errorPlus, const std::vector &errorMinus) { m_Impl->SetYErrorBars(label, errorPlus, errorMinus); } void QmitkChartWidget::SetLegendPosition(LegendPosition position) { m_Impl->SetLegendPosition(position); } void QmitkChartWidget::SetShowLegend(bool show) { m_Impl->SetShowLegend(show); } void QmitkChartWidget::SetStackedData(bool stacked) { m_Impl->SetStackedData(stacked); } void QmitkChartWidget::Show(bool showSubChart) { m_Impl->Show(showSubChart); } void QmitkChartWidget::Clear() { m_Impl->ClearData(); m_Impl->ClearJavaScriptChart(); } void QmitkChartWidget::OnLoadFinished(bool isLoadSuccessful) { if (isLoadSuccessful) { emit PageSuccessfullyLoaded(); } } void QmitkChartWidget::OnPageSuccessfullyLoaded() { auto themeName = m_Impl->GetThemeName(); QString command; if (themeName == "dark") { command = QString("changeTheme('dark')"); } else { command = QString("changeTheme('light')"); } m_Impl->CallJavaScriptFuntion(command); } void QmitkChartWidget::SetTheme(ColorTheme themeEnabled) { m_Impl->SetThemeName(themeEnabled); } void QmitkChartWidget::SetShowSubchart(bool showSubChart) { m_Impl->SetShowSubchart(showSubChart); } void QmitkChartWidget::SetShowErrorBars(bool showErrorBars) { m_Impl->SetShowErrorBars(showErrorBars); } void QmitkChartWidget::SetMinMaxValueXView(double minValueX, double maxValueX) { m_Impl->SetMinMaxValueXView(minValueX, maxValueX); } void QmitkChartWidget::SetMinMaxValueYView(double minValueY, double maxValueY) { m_Impl->SetMinMaxValueYView(minValueY, maxValueY); } void QmitkChartWidget::Reload() { const QString command = QString("Reload()"); m_Impl->CallJavaScriptFuntion(command); } QSize QmitkChartWidget::sizeHint() const { return m_Impl->sizeHint(); } + +void QmitkChartWidget::SavePlotAsImage() +{ + m_Impl->GetImageUrl(); +} diff --git a/Modules/Core/CMakeLists.txt b/Modules/Core/CMakeLists.txt index 7dd2c80b0e..bae8a92060 100644 --- a/Modules/Core/CMakeLists.txt +++ b/Modules/Core/CMakeLists.txt @@ -1,65 +1,66 @@ set(TOOL_CPPS "") # temporary suppress warnings in the following files until image accessors are fully integrated. set_source_files_properties( src/DataManagement/mitkImage.cpp COMPILE_FLAGS -DMITK_NO_DEPRECATED_WARNINGS ) set_source_files_properties( src/Controllers/mitkSliceNavigationController.cpp COMPILE_FLAGS -DMITK_NO_DEPRECATED_WARNINGS ) MITK_CREATE_MODULE( INCLUDE_DIRS PUBLIC ${MITK_BINARY_DIR} PRIVATE src/Algorithms src/Controllers src/DataManagement src/Interactions src/IO src/Rendering ${OPENGL_INCLUDE_DIR} DEPENDS PUBLIC mbilog CppMicroServices PACKAGE_DEPENDS PRIVATE tinyxml OpenGL PUBLIC ITK|ITKTransform+ITKImageGrid+ITKImageFeature+ITKIOImageBase+ITKIOHDF5+ITKIOLSM+ITKIOMRC+ITKIOBioRad+ITKIOGE+ITKIOStimulate+ITKIOBruker+ITKIOMINC # We privately use/link all ITK modules in order to support all IO, Transform, etc. # factories from ITK which are registered "automatically" via a factory manager. PRIVATE ITK PUBLIC VTK|vtkFiltersTexture+vtkFiltersParallel+vtkImagingStencil+vtkImagingMath+vtkInteractionStyle+vtkRenderingOpenGL2+vtkRenderingContextOpenGL2+vtkRenderingVolumeOpenGL2+vtkRenderingFreeType+vtkRenderingLabel+vtkInteractionWidgets+vtkIOGeometry+vtkIOXML PUBLIC Boost|boost SUBPROJECTS MITK-Core # Do not automatically create CppMicroServices initialization code. # Because the VTK 6 "auto-init" functionality injects file-local static # initialization code in every cpp file which includes a VTK header, # static initialization order becomes an issue again. For the Mitk # core library, we need to ensure that the VTK static initialization stuff # happens before the CppMicroServices initialization, since the latter # might already use VTK code which needs to access VTK object factories. # Hence, CppMicroServices initialization code is placed manually within # the mitkCoreActivator.cpp file. NO_INIT ) if(NOT TARGET ${MODULE_TARGET}) message(SEND_ERROR "Core target ${MODULE_TARGET} does not exist") endif() function(_itk_create_factory_register_manager) # In MITK_ITK_Config.cmake, we do *not* include ITK_USE_FILE, which # prevents multiple registrations/unregistrations of ITK IO factories # during library loading/unloading (of MITK libraries). However, we need # "one" place where the IO factories are registered at # least once. This could be the application executable, but every executable would # need to take care of that itself. Instead, we allow the auto registration in the # Mitk Core library. set(NO_DIRECTORY_SCOPED_ITK_COMPILE_DEFINITION 1) find_package(ITK) include(${ITK_USE_FILE}) if(NOT ITK_NO_IO_FACTORY_REGISTER_MANAGER) # We manually add the define which will be of target scope. MITK # patches ITK_USE_FILE to remove the directory scoped compile # definition since it would be propagated to other targets in the # same directory scope but these targets might want to *not* # use the ITK factory manager stuff. target_compile_definitions(${MODULE_TARGET} PRIVATE ITK_IO_FACTORY_REGISTER_MANAGER) endif() endfunction() _itk_create_factory_register_manager() if(MSVC_IDE OR MSVC_VERSION) target_link_libraries(${MODULE_TARGET} PRIVATE psapi.lib) endif() -add_subdirectory(TestingHelper) - -add_subdirectory(test) +if(BUILD_TESTING) + add_subdirectory(TestingHelper) + add_subdirectory(test) +endif() diff --git a/Modules/CoreCmdApps/CMakeLists.txt b/Modules/CoreCmdApps/CMakeLists.txt new file mode 100644 index 0000000000..12d751c887 --- /dev/null +++ b/Modules/CoreCmdApps/CMakeLists.txt @@ -0,0 +1,7 @@ +option(BUILD_CoreCmdApps "Build command-line apps of the MitkCore module" OFF) + +if(BUILD_CoreCmdApps OR MITK_BUILD_ALL_APPS) + mitkFunctionCreateCommandLineApp(NAME FileConverter) + mitkFunctionCreateCommandLineApp(NAME ImageTypeConverter) + mitkFunctionCreateCommandLineApp(NAME RectifyImage) +endif() diff --git a/Modules/BasicImageProcessing/MiniApps/FileConverter.cpp b/Modules/CoreCmdApps/FileConverter.cpp similarity index 100% rename from Modules/BasicImageProcessing/MiniApps/FileConverter.cpp rename to Modules/CoreCmdApps/FileConverter.cpp diff --git a/Modules/BasicImageProcessing/MiniApps/ImageTypeConverter.cpp b/Modules/CoreCmdApps/ImageTypeConverter.cpp similarity index 100% rename from Modules/BasicImageProcessing/MiniApps/ImageTypeConverter.cpp rename to Modules/CoreCmdApps/ImageTypeConverter.cpp diff --git a/Modules/BasicImageProcessing/MiniApps/RectifyImage.cpp b/Modules/CoreCmdApps/RectifyImage.cpp similarity index 100% rename from Modules/BasicImageProcessing/MiniApps/RectifyImage.cpp rename to Modules/CoreCmdApps/RectifyImage.cpp diff --git a/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsTreeModel.cpp b/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsTreeModel.cpp index fb201ae56c..033598353c 100644 --- a/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsTreeModel.cpp +++ b/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsTreeModel.cpp @@ -1,381 +1,383 @@ /*============================================================================ 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 "QmitkImageStatisticsTreeModel.h" #include "QmitkImageStatisticsTreeItem.h" #include "itkMutexLockHolder.h" #include "mitkImageStatisticsContainerManager.h" #include "mitkProportionalTimeGeometry.h" #include "mitkStatisticsToImageRelationRule.h" #include "mitkStatisticsToMaskRelationRule.h" QmitkImageStatisticsTreeModel::QmitkImageStatisticsTreeModel(QObject *parent) : QmitkAbstractDataStorageModel(parent) { m_RootItem = new QmitkImageStatisticsTreeItem(); } QmitkImageStatisticsTreeModel ::~QmitkImageStatisticsTreeModel() { // set data storage to nullptr so that the event listener gets removed this->SetDataStorage(nullptr); delete m_RootItem; }; void QmitkImageStatisticsTreeModel::DataStorageChanged() { emit beginResetModel(); UpdateByDataStorage(); emit endResetModel(); emit modelChanged(); } void QmitkImageStatisticsTreeModel::NodePredicateChanged() { emit beginResetModel(); UpdateByDataStorage(); emit endResetModel(); emit modelChanged(); } int QmitkImageStatisticsTreeModel::columnCount(const QModelIndex& /*parent*/) const { int columns = m_StatisticNames.size() + 1; return columns; } int QmitkImageStatisticsTreeModel::rowCount(const QModelIndex &parent) const { QmitkImageStatisticsTreeItem *parentItem; if (parent.column() > 0) return 0; if (!parent.isValid()) parentItem = m_RootItem; else parentItem = static_cast(parent.internalPointer()); return parentItem->childCount(); } QVariant QmitkImageStatisticsTreeModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (role != Qt::DisplayRole) return QVariant(); QmitkImageStatisticsTreeItem *item = static_cast(index.internalPointer()); return item->data(index.column()); } QModelIndex QmitkImageStatisticsTreeModel::index(int row, int column, const QModelIndex &parent) const { if (!hasIndex(row, column, parent)) return QModelIndex(); QmitkImageStatisticsTreeItem *parentItem; if (!parent.isValid()) parentItem = m_RootItem; else parentItem = static_cast(parent.internalPointer()); QmitkImageStatisticsTreeItem *childItem = parentItem->child(row); if (childItem) return createIndex(row, column, childItem); else return QModelIndex(); } QModelIndex QmitkImageStatisticsTreeModel::parent(const QModelIndex &child) const { if (!child.isValid()) return QModelIndex(); QmitkImageStatisticsTreeItem *childItem = static_cast(child.internalPointer()); QmitkImageStatisticsTreeItem *parentItem = childItem->parentItem(); if (parentItem == m_RootItem) return QModelIndex(); return createIndex(parentItem->row(), 0, parentItem); } Qt::ItemFlags QmitkImageStatisticsTreeModel::flags(const QModelIndex &index) const { if (!index.isValid()) return nullptr; return QAbstractItemModel::flags(index); } QVariant QmitkImageStatisticsTreeModel::headerData(int section, Qt::Orientation orientation, int role) const { if ((Qt::DisplayRole == role) && (Qt::Horizontal == orientation)) { if (section == 0) { return m_HeaderFirstColumn; } else { return QVariant(m_StatisticNames.at(section - 1).c_str()); } } return QVariant(); } void QmitkImageStatisticsTreeModel::SetImageNodes(const std::vector &nodes) { std::vector> tempNodes; for (const auto &node : nodes) { auto data = node->GetData(); if (data) { auto timeSteps = data->GetTimeSteps(); for (unsigned int i = 0; i < timeSteps; i++) { tempNodes.push_back(std::make_pair(node, i)); } } } emit beginResetModel(); m_TimeStepResolvedImageNodes = std::move(tempNodes); m_ImageNodes = nodes; UpdateByDataStorage(); emit endResetModel(); emit modelChanged(); } void QmitkImageStatisticsTreeModel::SetMaskNodes(const std::vector &nodes) { std::vector> tempNodes; for (const auto &node : nodes) { auto data = node->GetData(); if (data) { auto timeSteps = data->GetTimeSteps(); // special case: apply one mask to each timestep of an 4D image if (timeSteps == 1 && m_TimeStepResolvedImageNodes.size() > 1) { timeSteps = m_TimeStepResolvedImageNodes.size(); } for (unsigned int i = 0; i < timeSteps; i++) { tempNodes.push_back(std::make_pair(node, i)); } } } emit beginResetModel(); m_TimeStepResolvedMaskNodes = std::move(tempNodes); m_MaskNodes = nodes; UpdateByDataStorage(); emit endResetModel(); emit modelChanged(); } void QmitkImageStatisticsTreeModel::Clear() { emit beginResetModel(); m_Statistics.clear(); m_ImageNodes.clear(); m_TimeStepResolvedImageNodes.clear(); m_MaskNodes.clear(); m_StatisticNames.clear(); emit endResetModel(); emit modelChanged(); } void QmitkImageStatisticsTreeModel::UpdateByDataStorage() { StatisticsContainerVector newStatistics; auto datamanager = m_DataStorage.Lock(); if (datamanager.IsNotNull()) { for (const auto &image : m_ImageNodes) { if (m_MaskNodes.empty()) { auto stats = mitk::ImageStatisticsContainerManager::GetImageStatistics(datamanager, image->GetData()); if (stats.IsNotNull()) { newStatistics.emplace_back(stats); } } else { for (const auto &mask : m_MaskNodes) { auto stats = mitk::ImageStatisticsContainerManager::GetImageStatistics(datamanager, image->GetData(), mask->GetData()); if (stats.IsNotNull()) { newStatistics.emplace_back(stats); } } } } if (!newStatistics.empty()) { emit dataAvailable(); } } { itk::MutexLockHolder locked(m_Mutex); m_Statistics = newStatistics; } m_StatisticNames = mitk::GetAllStatisticNames(m_Statistics); BuildHierarchicalModel(); } void QmitkImageStatisticsTreeModel::BuildHierarchicalModel() { // reset old model delete m_RootItem; m_RootItem = new QmitkImageStatisticsTreeItem(); bool hasMask = false; bool hasMultipleTimesteps = false; - std::map dataNodeToTreeItem; + std::map dataNodeToTreeItem; for (auto statistic : m_Statistics) { // get the connected image data node/mask data node auto imageRule = mitk::StatisticsToImageRelationRule::New(); auto imageOfStatisticsPredicate = imageRule->GetDestinationsDetector(statistic); - auto imageCandidates = this->GetDataStorage()->GetSubset(imageOfStatisticsPredicate); + auto imageFinding = std::find_if(m_ImageNodes.begin(), m_ImageNodes.end(), [&imageOfStatisticsPredicate](const mitk::DataNode::ConstPointer& testNode) { return imageOfStatisticsPredicate->CheckNode(testNode); }); auto maskRule = mitk::StatisticsToMaskRelationRule::New(); auto maskOfStatisticsPredicate = maskRule->GetDestinationsDetector(statistic); - auto maskCandidates = this->GetDataStorage()->GetSubset(maskOfStatisticsPredicate); + auto maskFinding = std::find_if(m_MaskNodes.begin(), m_MaskNodes.end(), [&maskOfStatisticsPredicate](const mitk::DataNode::ConstPointer& testNode) { return maskOfStatisticsPredicate->CheckNode(testNode); }); - if (imageCandidates->empty()) + if (imageFinding == m_ImageNodes.end()) { mitkThrow() << "no image found connected to statistic" << statistic << " Aborting."; } - auto image = imageCandidates->front(); + + auto& image = *imageFinding; + // image: 1. hierarchy level - QmitkImageStatisticsTreeItem *imageItem; + QmitkImageStatisticsTreeItem *imageItem = nullptr; auto search = dataNodeToTreeItem.find(image); // the tree item was created previously if (search != dataNodeToTreeItem.end()) { imageItem = search->second; } // create the tree item else { QString imageLabel = QString::fromStdString(image->GetName()); - if (statistic->GetTimeSteps() == 1 && maskCandidates->empty()) + if (statistic->GetTimeSteps() == 1 && maskFinding == m_MaskNodes.end()) { auto statisticsObject = statistic->GetStatisticsForTimeStep(0); imageItem = new QmitkImageStatisticsTreeItem(statisticsObject, m_StatisticNames, imageLabel, m_RootItem); } else { imageItem = new QmitkImageStatisticsTreeItem(m_StatisticNames, imageLabel, m_RootItem); } m_RootItem->appendChild(imageItem); dataNodeToTreeItem.emplace(image, imageItem); } // mask: 2. hierarchy level (optional, only if mask exists) - QmitkImageStatisticsTreeItem *lastParent; - if (!maskCandidates->empty()) + QmitkImageStatisticsTreeItem *lastParent = nullptr; + if (maskFinding != m_MaskNodes.end()) { - auto mask = maskCandidates->front(); + auto& mask = *maskFinding; QString maskLabel = QString::fromStdString(mask->GetName()); QmitkImageStatisticsTreeItem *maskItem; // add statistical values directly in this hierarchy level if (statistic->GetTimeSteps() == 1) { auto statisticsObject = statistic->GetStatisticsForTimeStep(0); maskItem = new QmitkImageStatisticsTreeItem(statisticsObject, m_StatisticNames, maskLabel, imageItem); } else { maskItem = new QmitkImageStatisticsTreeItem(m_StatisticNames, maskLabel, imageItem); } imageItem->appendChild(maskItem); lastParent = maskItem; hasMask = true; } else { lastParent = imageItem; } // 3. hierarchy level (optional, only if >1 timestep) if (statistic->GetTimeSteps() > 1) { for (unsigned int i = 0; i < statistic->GetTimeSteps(); i++) { QString timeStepLabel = "[" + QString::number(i) + "] " + QString::number(statistic->GetTimeGeometry()->TimeStepToTimePoint(i)) + " ms"; if (statistic->TimeStepExists(i)) { auto statisticsItem = new QmitkImageStatisticsTreeItem( statistic->GetStatisticsForTimeStep(i), m_StatisticNames, timeStepLabel, lastParent); lastParent->appendChild(statisticsItem); } } hasMultipleTimesteps = true; } } QString headerString = "Images"; if (hasMask) { headerString += "/Masks"; } if (hasMultipleTimesteps) { headerString += "/Timesteps"; } m_HeaderFirstColumn = headerString; } void QmitkImageStatisticsTreeModel::NodeRemoved(const mitk::DataNode *) { emit beginResetModel(); UpdateByDataStorage(); emit endResetModel(); emit modelChanged(); } void QmitkImageStatisticsTreeModel::NodeAdded(const mitk::DataNode *) { emit beginResetModel(); UpdateByDataStorage(); emit endResetModel(); emit modelChanged(); } void QmitkImageStatisticsTreeModel::NodeChanged(const mitk::DataNode *) { emit beginResetModel(); UpdateByDataStorage(); emit endResetModel(); emit modelChanged(); } diff --git a/Modules/ModuleList.cmake b/Modules/ModuleList.cmake index 4daa70f838..d65ee8faa4 100644 --- a/Modules/ModuleList.cmake +++ b/Modules/ModuleList.cmake @@ -1,85 +1,86 @@ # The entries in the mitk_modules list must be # ordered according to their dependencies. set(MITK_MODULES Core CommandLine + CoreCmdApps AppUtil LegacyIO DataTypesExt Annotation LegacyGL AlgorithmsExt MapperExt DICOMReader DICOMReaderServices DICOMQI DICOMTesting SceneSerializationBase PlanarFigure ImageDenoising ImageExtraction SceneSerialization Gizmo GraphAlgorithms Multilabel Chart ImageStatistics ContourModel SurfaceInterpolation Segmentation QtWidgets QtWidgetsExt ImageStatisticsUI SegmentationUI MatchPointRegistration MatchPointRegistrationUI Classification OpenIGTLink IGTBase IGT CameraCalibration OpenCL OpenCVVideoSupport QtOverlays ToFHardware ToFProcessing ToFUI PhotoacousticsHardware PhotoacousticsAlgorithms PhotoacousticsLib US USUI DicomUI Remeshing Python QtPython Persistence OpenIGTLinkUI IGTUI DicomRT RTUI IOExt XNAT TubeGraph BiophotonicsHardware BoundingShape RenderWindowManager RenderWindowManagerUI SemanticRelations SemanticRelationsUI CEST BasicImageProcessing ModelFit ModelFitUI Pharmacokinetics PharmacokineticsUI DICOMPM REST RESTService DICOMweb ) if(MITK_ENABLE_PIC_READER) list(APPEND MITK_MODULES IpPicSupportIO) endif() diff --git a/Modules/QtWidgets/files.cmake b/Modules/QtWidgets/files.cmake index 73069607e5..8352fe4632 100644 --- a/Modules/QtWidgets/files.cmake +++ b/Modules/QtWidgets/files.cmake @@ -1,137 +1,139 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES QmitkAbstractDataStorageModel.cpp QmitkAbstractMultiWidget.cpp QmitkAbstractNodeSelectionWidget.cpp QmitkApplicationCursor.cpp QmitkDataStorageComboBox.cpp QmitkDataStorageDefaultListModel.cpp QmitkDataStorageHistoryModel.cpp QmitkDataStorageListModel.cpp QmitkDataStorageTableModel.cpp QmitkDataStorageSimpleTreeModel.cpp QmitkDataStorageTreeModel.cpp QmitkDataStorageTreeModelInternalItem.cpp QmitkDnDDataNodeWidget.cpp QmitkFileReaderOptionsDialog.cpp QmitkFileReaderWriterOptionsWidget.cpp QmitkFileWriterOptionsDialog.cpp QmitkInteractionSchemeToolBar.cpp QmitkIOUtil.cpp QmitkLevelWindowPresetDefinitionDialog.cpp QmitkLevelWindowRangeChangeDialog.cpp QmitkLevelWindowWidgetContextMenu.cpp QmitkLevelWindowWidget.cpp QmitkLineEditLevelWindowWidget.cpp QmitkMemoryUsageIndicatorView.cpp QmitkMouseModeSwitcher.cpp QmitkMimeTypes.cpp QmitkMultiWidgetConfigurationToolBar.cpp QmitkMultiWidgetLayoutManager.cpp QmitkMultiWidgetLayoutSelectionWidget.cpp QmitkNodeDescriptor.cpp QmitkColoredNodeDescriptor.cpp QmitkNodeDescriptorManager.cpp QmitkProgressBar.cpp QmitkPropertiesTableEditor.cpp QmitkPropertiesTableModel.cpp QmitkPropertyDelegate.cpp QmitkRegisterClasses.cpp QmitkRenderingManager.cpp QmitkRenderingManagerFactory.cpp QmitkRenderWindow.cpp QmitkRenderWindowMenu.cpp QmitkRenderWindowWidget.cpp QmitkServiceListWidget.cpp QmitkSliderLevelWindowWidget.cpp QmitkStdMultiWidget.cpp QmitkMxNMultiWidget.cpp QmitkDataStorageComboBoxWithSelectNone.cpp QmitkDataStorageFilterProxyModel.cpp QmitkPropertyItem.cpp QmitkPropertyItemDelegate.cpp QmitkPropertyItemModel.cpp QmitkStyleManager.cpp QmitkAbstractDataStorageInspector.cpp QmitkDataStorageFavoriteNodesInspector.cpp QmitkDataStorageListInspector.cpp QmitkDataStorageTreeInspector.cpp QmitkDataStorageSelectionHistoryInspector.cpp QmitkModelViewSelectionConnector.cpp mitkIDataStorageInspectorProvider.cpp mitkQtWidgetsActivator.cpp mitkDataStorageInspectorGenerator.cpp QmitkOverlayWidget.cpp + QmitkSimpleTextOverlayWidget.cpp QmitkNodeDetailsDialog.cpp ) set(MOC_H_FILES include/QmitkAbstractDataStorageModel.h include/QmitkAbstractMultiWidget.h include/QmitkAbstractNodeSelectionWidget.h include/QmitkDataStorageComboBox.h include/QmitkDataStorageTableModel.h include/QmitkDataStorageTreeModel.h include/QmitkDataStorageSimpleTreeModel.h include/QmitkDataStorageDefaultListModel.h include/QmitkDnDDataNodeWidget.h include/QmitkFileReaderOptionsDialog.h include/QmitkFileReaderWriterOptionsWidget.h include/QmitkFileWriterOptionsDialog.h include/QmitkInteractionSchemeToolBar.h include/QmitkLevelWindowPresetDefinitionDialog.h include/QmitkLevelWindowRangeChangeDialog.h include/QmitkLevelWindowWidgetContextMenu.h include/QmitkLevelWindowWidget.h include/QmitkLineEditLevelWindowWidget.h include/QmitkMemoryUsageIndicatorView.h include/QmitkMouseModeSwitcher.h include/QmitkMultiWidgetConfigurationToolBar.h include/QmitkMultiWidgetLayoutManager.h include/QmitkMultiWidgetLayoutSelectionWidget.h include/QmitkNodeDescriptor.h include/QmitkColoredNodeDescriptor.h include/QmitkNodeDescriptorManager.h include/QmitkProgressBar.h include/QmitkPropertiesTableEditor.h include/QmitkPropertyDelegate.h include/QmitkRenderingManager.h include/QmitkRenderWindow.h include/QmitkRenderWindowMenu.h include/QmitkRenderWindowWidget.h include/QmitkServiceListWidget.h include/QmitkSliderLevelWindowWidget.h include/QmitkStdMultiWidget.h include/QmitkMxNMultiWidget.h include/QmitkDataStorageComboBoxWithSelectNone.h include/QmitkPropertyItemDelegate.h include/QmitkPropertyItemModel.h include/QmitkAbstractDataStorageInspector.h include/QmitkDataStorageFavoriteNodesInspector.h include/QmitkDataStorageListInspector.h include/QmitkDataStorageTreeInspector.h include/QmitkDataStorageHistoryModel.h include/QmitkDataStorageSelectionHistoryInspector.h include/QmitkModelViewSelectionConnector.h include/QmitkOverlayWidget.h + include/QmitkSimpleTextOverlayWidget.h include/QmitkNodeDetailsDialog.h ) set(UI_FILES src/QmitkFileReaderOptionsDialog.ui src/QmitkFileWriterOptionsDialog.ui src/QmitkLevelWindowPresetDefinition.ui src/QmitkLevelWindowWidget.ui src/QmitkLevelWindowRangeChange.ui src/QmitkMemoryUsageIndicator.ui src/QmitkMultiWidgetLayoutSelectionWidget.ui src/QmitkServiceListWidgetControls.ui src/QmitkDataStorageListInspector.ui src/QmitkDataStorageTreeInspector.ui src/QmitkDataStorageSelectionHistoryInspector.ui ) set(QRC_FILES resource/Qmitk.qrc ) diff --git a/Modules/QtWidgets/include/QmitkDataStorageFavoriteNodesInspector.h b/Modules/QtWidgets/include/QmitkDataStorageFavoriteNodesInspector.h index 45312b974e..7153e02a75 100644 --- a/Modules/QtWidgets/include/QmitkDataStorageFavoriteNodesInspector.h +++ b/Modules/QtWidgets/include/QmitkDataStorageFavoriteNodesInspector.h @@ -1,53 +1,58 @@ /*============================================================================ 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 QMITKDATASTORAGEFAVORITENODESINSPECTOR_H #define QMITKDATASTORAGEFAVORITENODESINSPECTOR_H #include #include #include "mitkNodePredicateProperty.h" +#include "QmitkSimpleTextOverlayWidget.h" /* * @brief This is an inspector that offers a simple list view on favorite nodes of a data storage. */ class MITKQTWIDGETS_EXPORT QmitkDataStorageFavoriteNodesInspector : public QmitkDataStorageListInspector { Q_OBJECT public: QmitkDataStorageFavoriteNodesInspector(QWidget* parent = nullptr); /** * @brief Overrides the corresponding function of QmitkAbstractDataStorageInspector: * The custom favorite nodes predicate is added to the parameter predicate * which results in a combined node predicate that always filters nodes according * to their favorite-property-state. * * @param nodePredicate A pointer to a node predicate. */ void SetNodePredicate(const mitk::NodePredicateBase* nodePredicate) override; + constexpr static const char* INSPECTOR_ID() + { + return "org.mitk.QmitkDataStorageFavoriteNodesInspector"; + }; + protected Q_SLOTS: void OnFavoriteNodesButtonClicked(); private: mitk::NodePredicateProperty::Pointer m_FavoriteNodeSelectionPredicate; - }; #endif // QMITKDATASTORAGEFAVORITENODESINSPECTOR_H diff --git a/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.h b/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.h index 44c32549e4..52d55d3d52 100644 --- a/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.h +++ b/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.h @@ -1,78 +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. ============================================================================*/ #ifndef __QMITK_DATA_STORAGE_INSPECTOR_PROVIDER_BASE_H #define __QMITK_DATA_STORAGE_INSPECTOR_PROVIDER_BASE_H #include // Microservices #include #include #include // MITK #include /** * @brief Base class for DataStorage inspector provider. * * This class is the default implementation for a inspector provider. You can template it with * the respective inspector class to directly use it. */ template class QmitkDataStorageInspectorProviderBase : public mitk::IDataStorageInspectorProvider { public: QmitkAbstractDataStorageInspector* CreateInspector() const override; - std::string GetInspectorID() const override; + using InspectorIDType = mitk::IDataStorageInspectorProvider::InspectorIDType; + + InspectorIDType GetInspectorID() const override; std::string GetInspectorDisplayName() const override; std::string GetInspectorDescription() const override; + QIcon GetInspectorIcon() const override; us::ServiceRegistration RegisterService( us::ModuleContext *context = us::GetModuleContext()); void UnregisterService(); QmitkDataStorageInspectorProviderBase(const std::string& id); - QmitkDataStorageInspectorProviderBase(const std::string& id, const std::string& displayName, const std::string& desc= "" ); + QmitkDataStorageInspectorProviderBase(const std::string& id, const std::string& displayName, const std::string& desc = "", const std::string& pathToIconSVG = ""); ~QmitkDataStorageInspectorProviderBase() override; protected: QmitkDataStorageInspectorProviderBase(const QmitkDataStorageInspectorProviderBase &other); QmitkDataStorageInspectorProviderBase &operator=(const QmitkDataStorageInspectorProviderBase &other) = delete; virtual us::ServiceProperties GetServiceProperties() const; /** * \brief Set the service ranking for this file reader. * * Default is zero and should only be chosen differently for a reason. * The ranking is used to determine which provider to use if several * equivalent providers have been found. * It may be used to replace a default provider from MITK in your own project. */ void SetRanking(int ranking); int GetRanking() const; private: class Impl; std::unique_ptr d; }; #ifndef ITK_MANUAL_INSTANTIATION #include "QmitkDataStorageInspectorProviderBase.tpp" #endif #endif /* __QMITK_DATA_STORAGE_INSPECTOR_PROVIDER_BASE_H */ diff --git a/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.tpp b/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.tpp index ed49cd2311..686f1c3d16 100644 --- a/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.tpp +++ b/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.tpp @@ -1,145 +1,166 @@ /*============================================================================ 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 - template - class QmitkDataStorageInspectorProviderBase::Impl - { - public: - Impl(const std::string& id, const std::string& displayName, const std::string& desc) : m_Ranking(0), m_ID(id), m_DisplayName(displayName), m_Desc(desc) - { - }; - - Impl(const Impl &other) = default; - - void SetRanking(int ranking) - { - m_Ranking = ranking; - }; - - int GetRanking() const - { - return m_Ranking; - }; - - us::ServiceRegistration m_Reg; - int m_Ranking; - std::string m_ID; - std::string m_DisplayName; - std::string m_Desc; - }; - - template - QmitkDataStorageInspectorProviderBase::QmitkDataStorageInspectorProviderBase(const std::string& id) : QmitkDataStorageInspectorProviderBase(id, id) - { - } - - template - QmitkDataStorageInspectorProviderBase::QmitkDataStorageInspectorProviderBase(const std::string& id, const std::string& displayName, const std::string& desc) - { - d.reset(new Impl(id, displayName, desc)); - RegisterService(); - } - - template - QmitkDataStorageInspectorProviderBase::~QmitkDataStorageInspectorProviderBase() - { - UnregisterService(); - } +#include - template - QmitkDataStorageInspectorProviderBase::QmitkDataStorageInspectorProviderBase(const QmitkDataStorageInspectorProviderBase &other) : IDataStorageInspectorProvider(), d(new Impl(*other.d.get())) - { - } +#include - template - QmitkAbstractDataStorageInspector* - QmitkDataStorageInspectorProviderBase::CreateInspector() const +template +class QmitkDataStorageInspectorProviderBase::Impl +{ +public: + Impl(const std::string& id, const std::string& displayName, const std::string& desc, const QByteArray& svg) : m_Ranking(0), m_ID(id), m_DisplayName(displayName), m_Desc(desc), m_SVG(svg) { - return new TInspector; }; - template - std::string - QmitkDataStorageInspectorProviderBase::GetInspectorID() const - { - return d->m_ID; - }; + Impl(const Impl &other) = default; - template - std::string - QmitkDataStorageInspectorProviderBase::GetInspectorDisplayName() const + void SetRanking(int ranking) { - return d->m_DisplayName; + m_Ranking = ranking; }; - template - std::string - QmitkDataStorageInspectorProviderBase::GetInspectorDescription() const + int GetRanking() const { - return d->m_Desc; + return m_Ranking; }; - template - us::ServiceRegistration - QmitkDataStorageInspectorProviderBase::RegisterService(us::ModuleContext *context) + us::ServiceRegistration m_Reg; + int m_Ranking; + std::string m_ID; + std::string m_DisplayName; + std::string m_Desc; + QByteArray m_SVG; +}; + +template +QmitkDataStorageInspectorProviderBase::QmitkDataStorageInspectorProviderBase(const std::string& id) : QmitkDataStorageInspectorProviderBase(id, id) +{ +} + +template +QmitkDataStorageInspectorProviderBase::QmitkDataStorageInspectorProviderBase(const std::string& id, const std::string& displayName, const std::string& desc, const std::string& pathToIconSVG) +{ + QByteArray svg; + + if (!pathToIconSVG.empty()) { - if (d->m_Reg) - return d->m_Reg; - - if (context == nullptr) - { - context = us::GetModuleContext(); - } + QFile iconFile(QString::fromStdString(pathToIconSVG)); + if (iconFile.open(QIODevice::ReadOnly)) + svg = iconFile.readAll(); + } - us::ServiceProperties props = this->GetServiceProperties(); - d->m_Reg = context->RegisterService(this, props); + d.reset(new Impl(id, displayName, desc, svg)); + RegisterService(); +} + +template +QmitkDataStorageInspectorProviderBase::~QmitkDataStorageInspectorProviderBase() +{ + UnregisterService(); +} + +template +QmitkDataStorageInspectorProviderBase::QmitkDataStorageInspectorProviderBase(const QmitkDataStorageInspectorProviderBase &other) : IDataStorageInspectorProvider(), d(new Impl(*other.d.get())) +{ +} + +template +QmitkAbstractDataStorageInspector* + QmitkDataStorageInspectorProviderBase::CreateInspector() const +{ + return new TInspector; +} + +template +typename QmitkDataStorageInspectorProviderBase::InspectorIDType + QmitkDataStorageInspectorProviderBase::GetInspectorID() const +{ + return d->m_ID; +} + +template +std::string + QmitkDataStorageInspectorProviderBase::GetInspectorDisplayName() const +{ + return d->m_DisplayName; +} + +template +std::string + QmitkDataStorageInspectorProviderBase::GetInspectorDescription() const +{ + return d->m_Desc; +} + +template +QIcon + QmitkDataStorageInspectorProviderBase::GetInspectorIcon() const +{ + return QmitkStyleManager::ThemeIcon(d->m_SVG); +} + +template +us::ServiceRegistration + QmitkDataStorageInspectorProviderBase::RegisterService(us::ModuleContext *context) +{ + if (d->m_Reg) return d->m_Reg; - } - template - void - QmitkDataStorageInspectorProviderBase::UnregisterService() + if (context == nullptr) { - try - { - d->m_Reg.Unregister(); - } - catch (const std::exception &) - { - } + context = us::GetModuleContext(); } - template - us::ServiceProperties - QmitkDataStorageInspectorProviderBase::GetServiceProperties() const - { - us::ServiceProperties result; + us::ServiceProperties props = this->GetServiceProperties(); + d->m_Reg = context->RegisterService(this, props); + return d->m_Reg; +} - result[IDataStorageInspectorProvider::PROP_INSPECTOR_ID()] = this->d->m_ID; - result[us::ServiceConstants::SERVICE_RANKING()] = this->GetRanking(); - return result; +template +void + QmitkDataStorageInspectorProviderBase::UnregisterService() +{ + try + { + d->m_Reg.Unregister(); } - - template - void - QmitkDataStorageInspectorProviderBase::SetRanking(int ranking) { d->SetRanking(ranking); } - - template - int - QmitkDataStorageInspectorProviderBase::GetRanking() const { return d->GetRanking(); } + catch (const std::exception &) + { + } +} + +template +us::ServiceProperties +QmitkDataStorageInspectorProviderBase::GetServiceProperties() const +{ + us::ServiceProperties result; + + result[IDataStorageInspectorProvider::PROP_INSPECTOR_ID()] = this->d->m_ID; + result[us::ServiceConstants::SERVICE_RANKING()] = this->GetRanking(); + return result; +} + +template +void +QmitkDataStorageInspectorProviderBase::SetRanking(int ranking) { d->SetRanking(ranking); } + +template +int +QmitkDataStorageInspectorProviderBase::GetRanking() const { return d->GetRanking(); } diff --git a/Modules/QtWidgets/include/QmitkDataStorageListInspector.h b/Modules/QtWidgets/include/QmitkDataStorageListInspector.h index 1b87d0ff3c..082ef54ba4 100644 --- a/Modules/QtWidgets/include/QmitkDataStorageListInspector.h +++ b/Modules/QtWidgets/include/QmitkDataStorageListInspector.h @@ -1,46 +1,48 @@ /*============================================================================ 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 QMITKDATASTORAGELISTINSPECTOR_H #define QMITKDATASTORAGELISTINSPECTOR_H #include -#include -#include +#include "QmitkAbstractDataStorageInspector.h" +#include "QmitkSimpleTextOverlayWidget.h" #include "ui_QmitkDataStorageListInspector.h" /* * @brief This is an inspector that offers a simple list view on a data storage. */ class MITKQTWIDGETS_EXPORT QmitkDataStorageListInspector : public QmitkAbstractDataStorageInspector { Q_OBJECT public: QmitkDataStorageListInspector(QWidget* parent = nullptr); QAbstractItemView* GetView() override; const QAbstractItemView* GetView() const override; void SetSelectionMode(SelectionMode mode) override; SelectionMode GetSelectionMode() const override; protected: void Initialize() override; + void OnModelReset(); QmitkAbstractDataStorageModel* m_StorageModel; Ui_QmitkDataStorageListInspector m_Controls; + QmitkSimpleTextOverlayWidget* m_Overlay; }; #endif // QMITKDATASTORAGELISTINSPECTOR_H diff --git a/Modules/QtWidgets/include/QmitkDataStorageSelectionHistoryInspector.h b/Modules/QtWidgets/include/QmitkDataStorageSelectionHistoryInspector.h index 80ba29e334..c03c22a3c4 100644 --- a/Modules/QtWidgets/include/QmitkDataStorageSelectionHistoryInspector.h +++ b/Modules/QtWidgets/include/QmitkDataStorageSelectionHistoryInspector.h @@ -1,49 +1,56 @@ /*============================================================================ 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 QMITKDATASTORAGESELECTIONHISTORYINSPECTOR_H #define QMITKDATASTORAGESELECTIONHISTORYINSPECTOR_H #include -#include +#include "QmitkAbstractDataStorageInspector.h" #include +#include "QmitkSimpleTextOverlayWidget.h" #include "ui_QmitkDataStorageSelectionHistoryInspector.h" /* * @brief This is an inspector that offers a simple list view on the last selected nodes (in chronologic order) in a data storage. */ class MITKQTWIDGETS_EXPORT QmitkDataStorageSelectionHistoryInspector : public QmitkAbstractDataStorageInspector { Q_OBJECT public: QmitkDataStorageSelectionHistoryInspector(QWidget* parent = nullptr); QAbstractItemView* GetView() override; const QAbstractItemView* GetView() const override; void SetSelectionMode(SelectionMode mode) override; SelectionMode GetSelectionMode() const override; static void AddNodeToHistory(mitk::DataNode* node); static void ResetHistory(); + constexpr static const char* INSPECTOR_ID() + { + return "org.mitk.QmitkDataStorageSelectionHistoryInspector"; + }; + protected: void Initialize() override; QmitkAbstractDataStorageModel* m_StorageModel; Ui_QmitkDataStorageSelectionHistoryInspector m_Controls; + QmitkSimpleTextOverlayWidget* m_Overlay; }; #endif // QMITKDATASTORAGESELECTIONHISTORYINSPECTOR_H diff --git a/Modules/QtWidgets/include/QmitkDataStorageTreeInspector.h b/Modules/QtWidgets/include/QmitkDataStorageTreeInspector.h index b999ba6310..46442b55f7 100644 --- a/Modules/QtWidgets/include/QmitkDataStorageTreeInspector.h +++ b/Modules/QtWidgets/include/QmitkDataStorageTreeInspector.h @@ -1,48 +1,51 @@ /*============================================================================ 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 QMITKDATASTORAGETREEINSPECTOR_H #define QMITKDATASTORAGETREEINSPECTOR_H #include #include +#include "QmitkSimpleTextOverlayWidget.h" #include #include "ui_QmitkDataStorageTreeInspector.h" /* * @brief This is an inspector that offers a simple tree view on a data storage. * Something like the "data manager plugin", but in simple/light (with less functionality) * It uses the QmitkDataStorageSimpleTreeModel. */ class MITKQTWIDGETS_EXPORT QmitkDataStorageTreeInspector : public QmitkAbstractDataStorageInspector { Q_OBJECT public: QmitkDataStorageTreeInspector(QWidget* parent = nullptr); QAbstractItemView* GetView() override; const QAbstractItemView* GetView() const override; void SetSelectionMode(SelectionMode mode) override; SelectionMode GetSelectionMode() const override; protected: void Initialize() override; + void OnModelReset(); QmitkAbstractDataStorageModel* m_StorageModel; Ui_QmitkDataStorageTreeInspector m_Controls; + QmitkSimpleTextOverlayWidget* m_Overlay; }; #endif // QMITKDATASTORAGETREEINSPECTOR_H diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkSimpleTextOverlayWidget.h b/Modules/QtWidgets/include/QmitkSimpleTextOverlayWidget.h similarity index 89% rename from Plugins/org.mitk.gui.qt.common/src/QmitkSimpleTextOverlayWidget.h rename to Modules/QtWidgets/include/QmitkSimpleTextOverlayWidget.h index d7ae90f67a..dd3d46b952 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkSimpleTextOverlayWidget.h +++ b/Modules/QtWidgets/include/QmitkSimpleTextOverlayWidget.h @@ -1,41 +1,41 @@ /*============================================================================ 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 QMITK_SIMPLE_TEXT_OVERLAY_WIDGET_H #define QMITK_SIMPLE_TEXT_OVERLAY_WIDGET_H #include "QmitkOverlayWidget.h" -#include "org_mitk_gui_qt_common_Export.h" +#include /** Simple overlay that renders a passed string. You may pass an html string that will be rendered accordingly respecting the current application style sheet.*/ -class MITK_QT_COMMON QmitkSimpleTextOverlayWidget : public QmitkOverlayWidget +class MITKQTWIDGETS_EXPORT QmitkSimpleTextOverlayWidget : public QmitkOverlayWidget { Q_OBJECT Q_PROPERTY(QString overlayText READ GetOverlayText WRITE SetOverlayText) public: explicit QmitkSimpleTextOverlayWidget(QWidget* parent = nullptr); ~QmitkSimpleTextOverlayWidget() override; QString GetOverlayText() const; void SetOverlayText(const QString& text); protected: void paintEvent(QPaintEvent* event) override; private: QString m_Text; }; #endif diff --git a/Modules/QtWidgets/include/mitkDataStorageInspectorGenerator.h b/Modules/QtWidgets/include/mitkDataStorageInspectorGenerator.h index 4356c46e22..f6500115a7 100644 --- a/Modules/QtWidgets/include/mitkDataStorageInspectorGenerator.h +++ b/Modules/QtWidgets/include/mitkDataStorageInspectorGenerator.h @@ -1,41 +1,41 @@ /*============================================================================ 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 mitkDataStorageInspectorGenerator_H #define mitkDataStorageInspectorGenerator_H #include "mitkIDataStorageInspectorProvider.h" #include namespace mitk { - /** Convinvience class to get all or specific DataStorageInspectorProvider. */ + /** Convenience class to get all or specific DataStorageInspectorProvider. */ class MITKQTWIDGETS_EXPORT DataStorageInspectorGenerator { public: - using IDType = std::string; + using IDType = mitk::IDataStorageInspectorProvider::InspectorIDType; using ProviderMapType = std::map; static ProviderMapType GetProviders(); static mitk::IDataStorageInspectorProvider *GetProvider(const IDType &id); protected: DataStorageInspectorGenerator(); virtual ~DataStorageInspectorGenerator(); DataStorageInspectorGenerator(const DataStorageInspectorGenerator &source) = delete; DataStorageInspectorGenerator& operator=(const DataStorageInspectorGenerator &) = delete; }; } #endif diff --git a/Modules/QtWidgets/include/mitkIDataStorageInspectorProvider.h b/Modules/QtWidgets/include/mitkIDataStorageInspectorProvider.h index 9a0f1ab9ae..220558b73e 100644 --- a/Modules/QtWidgets/include/mitkIDataStorageInspectorProvider.h +++ b/Modules/QtWidgets/include/mitkIDataStorageInspectorProvider.h @@ -1,67 +1,73 @@ /*============================================================================ 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 __I_DATA_STORAGE_INSPECTOR_PROVIDER_H #define __I_DATA_STORAGE_INSPECTOR_PROVIDER_H #include #include +#include + class QmitkAbstractDataStorageInspector; namespace mitk { /** * \ingroup MicroServices_Interfaces * * \brief The common interface for all DataStorage inspector providers. * * Implementations of this interface must be registered as a service * to make themselves available via the service registry. * * It is recommended to derive new implementations from QmitkDataStorageInspectorProviderBase * which provide correct service registration semantics. * * \sa QmitkDataStorageInspectorProviderBase */ struct MITKQTWIDGETS_EXPORT IDataStorageInspectorProvider { virtual ~IDataStorageInspectorProvider(); /** * \brief returns an inspector instance represented by the provider. */ virtual QmitkAbstractDataStorageInspector* CreateInspector() const = 0; + using InspectorIDType = std::string; /** Return the uniqe ID for the inspector type provided.*/ - virtual std::string GetInspectorID() const = 0; + virtual InspectorIDType GetInspectorID() const = 0; /** Return the display name (e.g. used in the UI) for the inspector type provided.*/ virtual std::string GetInspectorDisplayName() const = 0; /** Returns a description of the inspector type provided.*/ virtual std::string GetInspectorDescription() const = 0; + /** Returns the svg data of the icon of the inspector. Empty array indicates that no icon is defined. + @remark It is passed as svg file content and not as icon directly to allow later styling*/ + virtual QIcon GetInspectorIcon() const = 0; /** * @brief Service property name for the inspector ID. * * The property value must be of type \c std::string. * * @return The property name. */ static std::string PROP_INSPECTOR_ID(); }; } // namespace mitk MITK_DECLARE_SERVICE_INTERFACE(mitk::IDataStorageInspectorProvider, "org.mitk.IDataStorageInspectorProvider") #endif /* __I_DATA_STORAGE_INSPECTOR_PROVIDER_H */ diff --git a/Modules/QtWidgets/resource/Qmitk.qrc b/Modules/QtWidgets/resource/Qmitk.qrc index e650d857e8..4f12f499d8 100644 --- a/Modules/QtWidgets/resource/Qmitk.qrc +++ b/Modules/QtWidgets/resource/Qmitk.qrc @@ -1,20 +1,26 @@ Binaerbilder_48.png Images_48.png PointSet_48.png Segmentation_48.png Surface_48.png mm_pointer.png mm_scroll.png mm_zoom.png mm_contrast.png mm_pan.png LabelSetImage_48.png mwLayout.png mwSynchronized.png mwDesynchronized.png mwMITK.png mwPACS.png - + star-solid.svg + history-solid.svg + tree_inspector.svg + list-solid.svg + favorite_add.svg + favorite_remove.svg + diff --git a/Modules/QtWidgets/resource/favorite_add.svg b/Modules/QtWidgets/resource/favorite_add.svg new file mode 100644 index 0000000000..6240713584 --- /dev/null +++ b/Modules/QtWidgets/resource/favorite_add.svg @@ -0,0 +1,39 @@ + + diff --git a/Modules/QtWidgets/resource/favorite_remove.svg b/Modules/QtWidgets/resource/favorite_remove.svg new file mode 100644 index 0000000000..c05b9c255e --- /dev/null +++ b/Modules/QtWidgets/resource/favorite_remove.svg @@ -0,0 +1,42 @@ + + diff --git a/Modules/QtWidgets/resource/history-solid.svg b/Modules/QtWidgets/resource/history-solid.svg new file mode 100644 index 0000000000..625e17a3ef --- /dev/null +++ b/Modules/QtWidgets/resource/history-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Modules/QtWidgets/resource/icon-license.txt b/Modules/QtWidgets/resource/icon-license.txt new file mode 100644 index 0000000000..662c801d5f --- /dev/null +++ b/Modules/QtWidgets/resource/icon-license.txt @@ -0,0 +1,6 @@ +See [Font Awsome 4] in Licenses/ICONS.md for: +- history-solid.svg based on Font Awsome's history-solid.svg +- list-solid.svg based on Font Awsome's list-solid.svg +- star-solid.svg based on Font Awsome's star-solid.svg +- favorite_add.svg based on Font Awsome's star-solid.svg +- favorite_remove.svg based on Font Awsome's star-solid.svg diff --git a/Modules/QtWidgets/resource/list-solid.svg b/Modules/QtWidgets/resource/list-solid.svg new file mode 100644 index 0000000000..f66f89c243 --- /dev/null +++ b/Modules/QtWidgets/resource/list-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Modules/QtWidgets/resource/star-solid.svg b/Modules/QtWidgets/resource/star-solid.svg new file mode 100644 index 0000000000..9ca5eb51ae --- /dev/null +++ b/Modules/QtWidgets/resource/star-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Modules/QtWidgets/resource/tree_inspector.svg b/Modules/QtWidgets/resource/tree_inspector.svg new file mode 100644 index 0000000000..82a332cdab --- /dev/null +++ b/Modules/QtWidgets/resource/tree_inspector.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + diff --git a/Modules/QtWidgets/src/QmitkDataStorageFavoriteNodesInspector.cpp b/Modules/QtWidgets/src/QmitkDataStorageFavoriteNodesInspector.cpp index 489263a5a1..f64a2a8146 100644 --- a/Modules/QtWidgets/src/QmitkDataStorageFavoriteNodesInspector.cpp +++ b/Modules/QtWidgets/src/QmitkDataStorageFavoriteNodesInspector.cpp @@ -1,50 +1,55 @@ /*============================================================================ 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 "QmitkDataStorageDefaultListModel.h" #include "mitkNodePredicateAnd.h" #include "QPushButton" +#include "QmitkStyleManager.h" QmitkDataStorageFavoriteNodesInspector::QmitkDataStorageFavoriteNodesInspector(QWidget* parent/* = nullptr*/) : QmitkDataStorageListInspector(parent) { - auto favoriteNodesButton = new QPushButton("Remove selection from favorites", parent); + auto favoriteNodesButton = new QPushButton(parent); QmitkDataStorageListInspector::m_Controls.verticalLayout->addWidget(favoriteNodesButton, 0, Qt::AlignRight); + favoriteNodesButton->setIcon(QmitkStyleManager::ThemeIcon(QStringLiteral(":/Qmitk/favorite_remove.svg"))); + favoriteNodesButton->setIconSize(QSize(24, 24)); + favoriteNodesButton->setToolTip("Remove selected nodes as favorite"); + m_FavoriteNodeSelectionPredicate = mitk::NodePredicateProperty::New("org.mitk.selection.favorite", mitk::BoolProperty::New(true)); m_NodePredicate = m_FavoriteNodeSelectionPredicate; connect(favoriteNodesButton, &QPushButton::clicked, this, &QmitkDataStorageFavoriteNodesInspector::OnFavoriteNodesButtonClicked); } void QmitkDataStorageFavoriteNodesInspector::SetNodePredicate(const mitk::NodePredicateBase* nodePredicate) { mitk::NodePredicateAnd::Pointer combinedPredicate = mitk::NodePredicateAnd::New(); combinedPredicate->AddPredicate(m_FavoriteNodeSelectionPredicate); combinedPredicate->AddPredicate(nodePredicate); QmitkDataStorageListInspector::SetNodePredicate(combinedPredicate); } void QmitkDataStorageFavoriteNodesInspector::OnFavoriteNodesButtonClicked() { auto selectedNodes = GetSelectedNodes(); for (auto node : selectedNodes) { node->SetBoolProperty("org.mitk.selection.favorite", false); } } diff --git a/Modules/QtWidgets/src/QmitkDataStorageListInspector.cpp b/Modules/QtWidgets/src/QmitkDataStorageListInspector.cpp index dff7f3b3c9..5b8da1aa36 100644 --- a/Modules/QtWidgets/src/QmitkDataStorageListInspector.cpp +++ b/Modules/QtWidgets/src/QmitkDataStorageListInspector.cpp @@ -1,57 +1,68 @@ /*============================================================================ 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 QmitkDataStorageListInspector::QmitkDataStorageListInspector(QWidget* parent/* = nullptr*/) : QmitkAbstractDataStorageInspector(parent) { m_Controls.setupUi(this); m_Controls.view->setSelectionMode(QAbstractItemView::ExtendedSelection); m_Controls.view->setSelectionBehavior(QAbstractItemView::SelectRows); m_Controls.view->setAlternatingRowColors(true); + m_Overlay = new QmitkSimpleTextOverlayWidget(this); + m_Overlay->setVisible(false); + m_Overlay->SetOverlayText(QStringLiteral("

No suitable data available in data storage.

")); + m_StorageModel = new QmitkDataStorageDefaultListModel(this); m_Controls.view->setModel(m_StorageModel); + + connect(m_StorageModel, &QAbstractItemModel::modelReset, this, &QmitkDataStorageListInspector::OnModelReset); } QAbstractItemView* QmitkDataStorageListInspector::GetView() { return m_Controls.view; } const QAbstractItemView* QmitkDataStorageListInspector::GetView() const { return m_Controls.view; } void QmitkDataStorageListInspector::Initialize() { m_StorageModel->SetDataStorage(m_DataStorage.Lock()); m_StorageModel->SetNodePredicate(m_NodePredicate); m_Connector->SetView(m_Controls.view); } void QmitkDataStorageListInspector::SetSelectionMode(SelectionMode mode) { m_Controls.view->setSelectionMode(mode); } QmitkDataStorageListInspector::SelectionMode QmitkDataStorageListInspector::GetSelectionMode() const { return m_Controls.view->selectionMode(); } + +void QmitkDataStorageListInspector::OnModelReset() +{ + m_Overlay->setVisible(m_StorageModel->rowCount() == 0); +} diff --git a/Modules/QtWidgets/src/QmitkDataStorageSelectionHistoryInspector.cpp b/Modules/QtWidgets/src/QmitkDataStorageSelectionHistoryInspector.cpp index a9fe9b5722..ef35513131 100644 --- a/Modules/QtWidgets/src/QmitkDataStorageSelectionHistoryInspector.cpp +++ b/Modules/QtWidgets/src/QmitkDataStorageSelectionHistoryInspector.cpp @@ -1,67 +1,73 @@ /*============================================================================ 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 "QmitkDataStorageHistoryModel.h" QmitkDataStorageSelectionHistoryInspector::QmitkDataStorageSelectionHistoryInspector(QWidget* parent/* = nullptr*/) : QmitkAbstractDataStorageInspector(parent) { m_Controls.setupUi(this); m_Controls.view->setSelectionMode(QAbstractItemView::ExtendedSelection); m_Controls.view->setSelectionBehavior(QAbstractItemView::SelectRows); m_Controls.view->setAlternatingRowColors(true); + m_Overlay = new QmitkSimpleTextOverlayWidget(this); + m_Overlay->setVisible(false); + m_Overlay->SetOverlayText(QStringLiteral("

No history available yet.

")); + m_StorageModel = new QmitkDataStorageHistoryModel(this); m_Controls.view->setModel(m_StorageModel); } QAbstractItemView* QmitkDataStorageSelectionHistoryInspector::GetView() { return m_Controls.view; } const QAbstractItemView* QmitkDataStorageSelectionHistoryInspector::GetView() const { return m_Controls.view; } void QmitkDataStorageSelectionHistoryInspector::Initialize() { m_StorageModel->SetDataStorage(m_DataStorage.Lock()); m_StorageModel->SetNodePredicate(m_NodePredicate); m_Connector->SetView(m_Controls.view); + + m_Overlay->setVisible(m_StorageModel->rowCount() == 0); } void QmitkDataStorageSelectionHistoryInspector::SetSelectionMode(SelectionMode mode) { m_Controls.view->setSelectionMode(mode); } QmitkDataStorageSelectionHistoryInspector::SelectionMode QmitkDataStorageSelectionHistoryInspector::GetSelectionMode() const { return m_Controls.view->selectionMode(); } void QmitkDataStorageSelectionHistoryInspector::AddNodeToHistory(mitk::DataNode* node) { QmitkDataStorageHistoryModel::AddNodeToHistory(node); } void QmitkDataStorageSelectionHistoryInspector::ResetHistory() { QmitkDataStorageHistoryModel::ResetHistory(); } diff --git a/Modules/QtWidgets/src/QmitkDataStorageSimpleTreeModel.cpp b/Modules/QtWidgets/src/QmitkDataStorageSimpleTreeModel.cpp index f75cfbd875..5f7b269025 100644 --- a/Modules/QtWidgets/src/QmitkDataStorageSimpleTreeModel.cpp +++ b/Modules/QtWidgets/src/QmitkDataStorageSimpleTreeModel.cpp @@ -1,366 +1,370 @@ /*============================================================================ 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 // qt widgets module #include "QmitkCustomVariants.h" #include "QmitkEnums.h" QmitkDataStorageSimpleTreeModel::QmitkDataStorageSimpleTreeModel(QObject *parent) : QmitkAbstractDataStorageModel(parent), m_Root(nullptr) { ResetTree(); } QmitkDataStorageSimpleTreeModel::~QmitkDataStorageSimpleTreeModel() { m_Root->Delete(); m_Root = nullptr; }; void QmitkDataStorageSimpleTreeModel::ResetTree() { mitk::DataNode::Pointer rootDataNode = mitk::DataNode::New(); rootDataNode->SetName("Data Storage"); m_Root = new TreeItem(rootDataNode, nullptr); } void QmitkDataStorageSimpleTreeModel::DataStorageChanged() { if (m_Root) { m_Root->Delete(); } + beginResetModel(); ResetTree(); UpdateModelData(); + endResetModel(); } void QmitkDataStorageSimpleTreeModel::NodePredicateChanged() { + beginResetModel(); ResetTree(); UpdateModelData(); + endResetModel(); } void QmitkDataStorageSimpleTreeModel::NodeAdded(const mitk::DataNode *node) { if (node == nullptr || m_DataStorage.IsExpired() || !m_DataStorage.Lock()->Exists(node) || m_Root->Find(node) != nullptr) return; this->AddNodeInternal(node); } void QmitkDataStorageSimpleTreeModel::NodeChanged(const mitk::DataNode *node) { TreeItem *treeItem = m_Root->Find(node); if (treeItem) { TreeItem *parentTreeItem = treeItem->GetParent(); // as the root node should not be removed one should always have a parent item if (!parentTreeItem) return; QModelIndex index = this->createIndex(treeItem->GetIndex(), 0, treeItem); // now emit the dataChanged signal emit dataChanged(index, index); } } void QmitkDataStorageSimpleTreeModel::NodeRemoved(const mitk::DataNode *node) { if (node == nullptr || !m_Root) return; TreeItem *treeItem = m_Root->Find(node); if (!treeItem) return; // return because there is no treeitem containing this node TreeItem *parentTreeItem = treeItem->GetParent(); QModelIndex parentIndex = this->IndexFromTreeItem(parentTreeItem); // emit beginRemoveRows event (QModelIndex is empty because we dont have a tree model) this->beginRemoveRows(parentIndex, treeItem->GetIndex(), treeItem->GetIndex()); // remove node std::vector children = treeItem->GetChildren(); m_TreeItems.remove(treeItem); delete treeItem; //delete in tree if (!children.empty()) { //if not empty we have to rebuild the whole representation, //because the children could be now top level, or at another //source/parent. this->UpdateModelData(); } } QModelIndex QmitkDataStorageSimpleTreeModel::index(int row, int column, const QModelIndex &parent) const { TreeItem *parentItem; if (!parent.isValid() || parent.model() != this) parentItem = m_Root; else parentItem = static_cast(parent.internalPointer()); if (parentItem) { TreeItem *childItem = parentItem->GetChild(row); if (childItem) return createIndex(row, column, childItem); } return QModelIndex(); } QModelIndex QmitkDataStorageSimpleTreeModel::parent(const QModelIndex &child) const { if (!child.isValid() || !m_Root || child.model() != this) return QModelIndex(); TreeItem *childItem = this->TreeItemFromIndex(child); if (!childItem) return QModelIndex(); TreeItem *parentItem = childItem->GetParent(); if (parentItem == m_Root) return QModelIndex(); return this->createIndex(parentItem->GetIndex(), 0, parentItem); } QmitkDataStorageSimpleTreeModel::TreeItem *QmitkDataStorageSimpleTreeModel::TreeItemFromIndex( const QModelIndex &index) const { if (index.isValid() && index.model() == this) { auto item = static_cast(index.internalPointer()); auto finding = std::find(std::begin(m_TreeItems), std::end(m_TreeItems), item); if (finding == std::end(m_TreeItems)) { return nullptr; } return item; } else return m_Root; } int QmitkDataStorageSimpleTreeModel::rowCount(const QModelIndex &parent) const { TreeItem *parentTreeItem = this->TreeItemFromIndex(parent); if (parentTreeItem) return parentTreeItem->GetChildCount(); else return 0; } int QmitkDataStorageSimpleTreeModel::columnCount(const QModelIndex &/*parent*/) const { return 1; } QVariant QmitkDataStorageSimpleTreeModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || index.model() != this) { return QVariant(); } auto treeItem = this->TreeItemFromIndex(index); if (!treeItem) return QVariant(); mitk::DataNode *dataNode = treeItem->GetDataNode(); QString nodeName = QString::fromStdString(dataNode->GetName()); if (nodeName.isEmpty()) { nodeName = "unnamed"; } if (role == Qt::DisplayRole) return nodeName; else if (role == Qt::ToolTipRole) return nodeName; else if (role == Qt::DecorationRole) { QmitkNodeDescriptor *nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(dataNode); return nodeDescriptor->GetIcon(dataNode); } else if (role == QmitkDataNodeRole) { return QVariant::fromValue(mitk::DataNode::Pointer(dataNode)); } else if (role == QmitkDataNodeRawPointerRole) { return QVariant::fromValue(dataNode); } return QVariant(); } bool QmitkDataStorageSimpleTreeModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!index.isValid() || index.model() != this) return false; auto treeItem = this->TreeItemFromIndex(index); if (!treeItem) return false; mitk::DataNode *dataNode = treeItem->GetDataNode(); if (!dataNode) return false; if (role == Qt::EditRole && !value.toString().isEmpty()) { dataNode->SetName(value.toString().toStdString().c_str()); } else if (role == Qt::CheckStateRole) { // Please note: value.toInt() returns 2, independentely from the actual checkstate of the index element. // Therefore the checkstate is being estimated again here. QVariant qcheckstate = index.data(Qt::CheckStateRole); int checkstate = qcheckstate.toInt(); bool isVisible = bool(checkstate); dataNode->SetVisibility(!isVisible); } // inform listeners about changes emit dataChanged(index, index); return true; } QVariant QmitkDataStorageSimpleTreeModel::headerData(int /*section*/, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole && m_Root) return QString::fromStdString(m_Root->GetDataNode()->GetName()); return QVariant(); } Qt::ItemFlags QmitkDataStorageSimpleTreeModel::flags(const QModelIndex &index) const { if (index.isValid() && index.model() == this) { auto treeItem = this->TreeItemFromIndex(index); if (!treeItem) return Qt::NoItemFlags; const auto dataNode = treeItem->GetDataNode(); if (m_NodePredicate.IsNull() || m_NodePredicate->CheckNode(dataNode)) { return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable; } else { return Qt::NoItemFlags; } } return Qt::NoItemFlags; } mitk::DataNode *QmitkDataStorageSimpleTreeModel::GetParentNode(const mitk::DataNode *node) const { mitk::DataNode *dataNode = nullptr; mitk::DataStorage::SetOfObjects::ConstPointer _Sources = m_DataStorage.Lock()->GetSources(node); if (_Sources->Size() > 0) dataNode = _Sources->front(); return dataNode; } void QmitkDataStorageSimpleTreeModel::AddNodeInternal(const mitk::DataNode *node) { if (node == nullptr || m_DataStorage.IsExpired() || !m_DataStorage.Lock()->Exists(node) || m_Root->Find(node) != nullptr) return; // find out if we have a root node TreeItem *parentTreeItem = m_Root; QModelIndex index; mitk::DataNode *parentDataNode = this->GetParentNode(node); if (parentDataNode) // no top level data node { parentTreeItem = m_Root->Find(parentDataNode); // find the corresponding tree item if (!parentTreeItem) { this->NodeAdded(parentDataNode); parentTreeItem = m_Root->Find(parentDataNode); if (!parentTreeItem) return; } // get the index of this parent with the help of the grand parent index = this->createIndex(parentTreeItem->GetIndex(), 0, parentTreeItem); } int firstRowWithASiblingBelow = 0; int nodeLayer = -1; node->GetIntProperty("layer", nodeLayer); for (TreeItem *siblingTreeItem : parentTreeItem->GetChildren()) { int siblingLayer = -1; if (mitk::DataNode *siblingNode = siblingTreeItem->GetDataNode()) { siblingNode->GetIntProperty("layer", siblingLayer); } if (nodeLayer > siblingLayer) { break; } ++firstRowWithASiblingBelow; } beginInsertRows(index, firstRowWithASiblingBelow, firstRowWithASiblingBelow); auto newNode = new TreeItem(const_cast(node)); parentTreeItem->InsertChild(newNode, firstRowWithASiblingBelow); m_TreeItems.push_back(newNode); endInsertRows(); } QModelIndex QmitkDataStorageSimpleTreeModel::IndexFromTreeItem(TreeItem *item) const { if (item == m_Root) return QModelIndex(); else return this->createIndex(item->GetIndex(), 0, item); } void QmitkDataStorageSimpleTreeModel::UpdateModelData() { if (!m_DataStorage.IsExpired()) { auto nodeset = m_DataStorage.Lock()->GetAll(); if (m_NodePredicate != nullptr) { nodeset = m_DataStorage.Lock()->GetSubset(m_NodePredicate); } for (const auto& node : *nodeset) { this->AddNodeInternal(node); } } } diff --git a/Modules/QtWidgets/src/QmitkDataStorageTreeInspector.cpp b/Modules/QtWidgets/src/QmitkDataStorageTreeInspector.cpp index 7afc8d39da..f1d7d95eab 100644 --- a/Modules/QtWidgets/src/QmitkDataStorageTreeInspector.cpp +++ b/Modules/QtWidgets/src/QmitkDataStorageTreeInspector.cpp @@ -1,61 +1,72 @@ /*============================================================================ 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 QmitkDataStorageTreeInspector::QmitkDataStorageTreeInspector(QWidget* parent/* = nullptr*/) : QmitkAbstractDataStorageInspector(parent) { m_Controls.setupUi(this); m_Controls.view->setSelectionMode(QAbstractItemView::ExtendedSelection); m_Controls.view->setSelectionBehavior(QAbstractItemView::SelectRows); m_Controls.view->setAlternatingRowColors(true); m_Controls.view->setHeaderHidden(true); m_Controls.view->setTextElideMode(Qt::ElideMiddle); + m_Overlay = new QmitkSimpleTextOverlayWidget(this); + m_Overlay->setVisible(false); + m_Overlay->SetOverlayText(QStringLiteral("

No suitable data available in data storage.

")); + m_StorageModel = new QmitkDataStorageSimpleTreeModel(this); m_Controls.view->setModel(m_StorageModel); + + connect(m_StorageModel, &QAbstractItemModel::modelReset, this, &QmitkDataStorageTreeInspector::OnModelReset); } QAbstractItemView* QmitkDataStorageTreeInspector::GetView() { return m_Controls.view; } const QAbstractItemView* QmitkDataStorageTreeInspector::GetView() const { return m_Controls.view; } void QmitkDataStorageTreeInspector::Initialize() { m_StorageModel->SetDataStorage(m_DataStorage.Lock()); m_StorageModel->SetNodePredicate(m_NodePredicate); m_Connector->SetView(m_Controls.view); m_Controls.view->expandAll(); } void QmitkDataStorageTreeInspector::SetSelectionMode(SelectionMode mode) { m_Controls.view->setSelectionMode(mode); } QmitkDataStorageTreeInspector::SelectionMode QmitkDataStorageTreeInspector::GetSelectionMode() const { return m_Controls.view->selectionMode(); } + +void QmitkDataStorageTreeInspector::OnModelReset() +{ + m_Overlay->setVisible(!m_StorageModel->hasChildren()); +} diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkSimpleTextOverlayWidget.cpp b/Modules/QtWidgets/src/QmitkSimpleTextOverlayWidget.cpp similarity index 73% rename from Plugins/org.mitk.gui.qt.common/src/QmitkSimpleTextOverlayWidget.cpp rename to Modules/QtWidgets/src/QmitkSimpleTextOverlayWidget.cpp index c8832a3fa5..4c21847399 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkSimpleTextOverlayWidget.cpp +++ b/Modules/QtWidgets/src/QmitkSimpleTextOverlayWidget.cpp @@ -1,72 +1,62 @@ /*============================================================================ 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 "QmitkSimpleTextOverlayWidget.h" -#include -#include - #include "QTextDocument" #include "QPainter" +#include "QApplication" QmitkSimpleTextOverlayWidget::QmitkSimpleTextOverlayWidget(QWidget* parent) : QmitkOverlayWidget(parent) { } QmitkSimpleTextOverlayWidget::~QmitkSimpleTextOverlayWidget() { } QString QmitkSimpleTextOverlayWidget::GetOverlayText() const { return m_Text; } void QmitkSimpleTextOverlayWidget::SetOverlayText(const QString& text) { m_Text = text; this->update(); } void QmitkSimpleTextOverlayWidget::paintEvent(QPaintEvent* p) { QmitkOverlayWidget::paintEvent(p); - QString stylesheet; - - ctkPluginContext* context = berry::WorkbenchPlugin::GetDefault()->GetPluginContext(); - ctkServiceReference styleManagerRef = context->getServiceReference(); - if (styleManagerRef) - { - auto styleManager = context->getService(styleManagerRef); - stylesheet = styleManager->GetStylesheet(); - } + auto styleSheet = qApp->styleSheet(); QPainter painter(this); QTextDocument td(this); - td.setDefaultStyleSheet(stylesheet); + td.setDefaultStyleSheet(styleSheet); auto widgetSize = this->size(); td.setTextWidth(widgetSize.width()-20.); QPoint origin = QPoint(10, 5); td.setHtml(m_Text); auto textSize = td.size(); origin.setX((widgetSize.width() - textSize.width()) / 2.); origin.setY((widgetSize.height() - textSize.height()) / 2.); painter.translate(origin); td.drawContents(&painter); } diff --git a/Modules/QtWidgets/src/mitkQtWidgetsActivator.cpp b/Modules/QtWidgets/src/mitkQtWidgetsActivator.cpp index deaf7af8b7..5496077667 100644 --- a/Modules/QtWidgets/src/mitkQtWidgetsActivator.cpp +++ b/Modules/QtWidgets/src/mitkQtWidgetsActivator.cpp @@ -1,38 +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 "mitkQtWidgetsActivator.h" // Micro Services #include #include // Qmitk #include "QmitkDataStorageInspectorProviderBase.h" #include "QmitkDataStorageListInspector.h" #include "QmitkDataStorageTreeInspector.h" #include "QmitkDataStorageSelectionHistoryInspector.h" #include "QmitkDataStorageFavoriteNodesInspector.h" void MitkQtWidgetsActivator::Load(us::ModuleContext * /*context*/) { - m_TreeInspector.reset(new QmitkDataStorageInspectorProviderBase("org.mitk.QmitkDataStorageListInspector", "Simple list", "Displays the filtered content of the data storage in a simple list.")); - m_ListInspector.reset(new QmitkDataStorageInspectorProviderBase("org.mitk.QmitkDataStorageTreeInspector", "Rendering tree", "Displays the filtered content of the data storage as the current rendering tree. \n(Equals the old data manager view)")); - m_HistoryInspector.reset(new QmitkDataStorageInspectorProviderBase("org.mitk.QmitkDataStorageSelectionHistoryInspector", "Selection history", "Displays the filtered history of all node selections in this application session. \nThe nodes are sorted from new to old selections.\nOnly nodes that are still in the data storage will be displayed.")); - m_FavoriteNodesInspector.reset(new QmitkDataStorageInspectorProviderBase("org.mitk.QmitkDataStorageFavoriteNodesInspector", "Favorite nodes list", "Displays the favorite nodes of the data storage in a simple list.")); + Q_INIT_RESOURCE(Qmitk); + m_TreeInspector.reset(new QmitkDataStorageInspectorProviderBase("org.mitk.QmitkDataStorageListInspector", "Simple list", "Displays the filtered content of the data storage in a simple list.", ":/Qmitk/list-solid.svg")); + m_ListInspector.reset(new QmitkDataStorageInspectorProviderBase("org.mitk.QmitkDataStorageTreeInspector", "Rendering tree", "Displays the filtered content of the data storage as the current rendering tree. \n(Equals the old data manager view)", ":/Qmitk/tree_inspector.svg")); + m_HistoryInspector.reset(new QmitkDataStorageInspectorProviderBase(QmitkDataStorageSelectionHistoryInspector::INSPECTOR_ID(), "Selection history", "Displays the filtered history of all node selections in this application session. \nThe nodes are sorted from new to old selections.\nOnly nodes that are still in the data storage will be displayed.", ":/Qmitk/history-solid.svg")); + m_FavoriteNodesInspector.reset(new QmitkDataStorageInspectorProviderBase(QmitkDataStorageFavoriteNodesInspector::INSPECTOR_ID(), "Favorite nodes list", "Displays the favorite nodes of the data storage in a simple list.",":/Qmitk/star-solid.svg")); } void MitkQtWidgetsActivator::Unload(us::ModuleContext *) { } US_EXPORT_MODULE_ACTIVATOR(MitkQtWidgetsActivator) 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.common/files.cmake b/Plugins/org.mitk.gui.qt.common/files.cmake index b9621a8d79..bb57973a0e 100755 --- a/Plugins/org.mitk.gui.qt.common/files.cmake +++ b/Plugins/org.mitk.gui.qt.common/files.cmake @@ -1,69 +1,67 @@ set(SRC_CPP_FILES QmitkAbstractMultiWidgetEditor.cpp QmitkAbstractRenderEditor.cpp QmitkAbstractView.cpp QmitkDataNodeSelectionProvider.cpp QmitkDnDFrameWidget.cpp QmitkSelectionServiceConnector.cpp QmitkSliceNavigationListener.cpp QmitkSingleNodeSelectionWidget.cpp QmitkNodeSelectionDialog.cpp QmitkMultiNodeSelectionWidget.cpp QmitkMultiWidgetDecorationManager.cpp QmitkNodeSelectionPreferenceHelper.cpp QmitkNodeSelectionButton.cpp - QmitkSimpleTextOverlayWidget.cpp ) set(INTERNAL_CPP_FILES QmitkCommonActivator.cpp QmitkDataNodeItemModel.cpp QmitkDataNodeSelection.cpp QmitkViewCoordinator.cpp QmitkNodeSelectionConstants.cpp QmitkNodeSelectionPreferencePage.cpp QmitkNodeSelectionListItemWidget.cpp ) set(UI_FILES src/QmitkSingleNodeSelectionWidget.ui src/QmitkMultiNodeSelectionWidget.ui src/QmitkNodeSelectionDialog.ui src/internal/QmitkNodeSelectionPreferencePage.ui src/internal/QmitkNodeSelectionListItemWidget.ui ) set(MOC_H_FILES src/QmitkAbstractMultiWidgetEditor.h src/QmitkAbstractRenderEditor.h src/QmitkDnDFrameWidget.h src/QmitkSelectionServiceConnector.h src/QmitkSliceNavigationListener.h src/QmitkSingleNodeSelectionWidget.h src/QmitkNodeSelectionDialog.h src/QmitkMultiNodeSelectionWidget.h src/QmitkNodeSelectionButton.h - src/QmitkSimpleTextOverlayWidget.h src/internal/QmitkCommonActivator.h src/internal/QmitkNodeSelectionPreferencePage.h src/internal/QmitkNodeSelectionListItemWidget.h ) set(CACHED_RESOURCE_FILES plugin.xml resources/times.svg ) set(QRC_FILES resources/common.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.common/resources/icon-license.txt b/Plugins/org.mitk.gui.qt.common/resources/icon-license.txt new file mode 100644 index 0000000000..167ecb6def --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/resources/icon-license.txt @@ -0,0 +1,2 @@ +See [Font Awsome 4] in Licenses/ICONS.md for: +- times.svg \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.cpp index 2d38f08346..3bbff7435a 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.cpp +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.cpp @@ -1,224 +1,255 @@ /*============================================================================ 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 "QmitkNodeSelectionDialog.h" +#include + #include #include #include +#include QmitkNodeSelectionDialog::QmitkNodeSelectionDialog(QWidget* parent, QString title, QString hint) : QDialog(parent), m_NodePredicate(nullptr), m_SelectOnlyVisibleNodes(false), m_SelectedNodes(NodeList()), m_SelectionMode(QAbstractItemView::SingleSelection) { m_Controls.setupUi(this); m_CheckFunction = [](const NodeList &) { return ""; }; auto providers = mitk::DataStorageInspectorGenerator::GetProviders(); auto visibleProviders = mitk::GetVisibleDataStorageInspectors(); - auto favoriteID = mitk::GetFavoriteDataStorageInspector(); + auto preferredID = mitk::GetPreferredDataStorageInspector(); if (visibleProviders.empty()) { MITK_DEBUG << "No presets for visible node selection inspectors available. Use fallback (show all available inspectors)"; unsigned int order = 0; for (auto proIter : providers) { visibleProviders.insert(std::make_pair(order, proIter.first)); ++order; } } - int favIndex = 0; - bool favoriteFound = false; + int preferredIndex = 0; + bool preferredFound = false; for (auto proIter : visibleProviders) { auto finding = providers.find(proIter.second); if (finding != providers.end()) { - auto inspector = finding->second->CreateInspector(); - QString name = QString::fromStdString(finding->second->GetInspectorDisplayName()); - QString desc = QString::fromStdString(finding->second->GetInspectorDescription()); - AddPanel(inspector, name, desc); - - favoriteFound = favoriteFound || proIter.second == favoriteID; - if (!favoriteFound) + if (finding->second->GetInspectorID() != QmitkDataStorageFavoriteNodesInspector::INSPECTOR_ID() && finding->second->GetInspectorID() != QmitkDataStorageSelectionHistoryInspector::INSPECTOR_ID()) { - ++favIndex; + auto provider = finding->second; + this->AddPanel(provider, preferredID, preferredFound, preferredIndex); } } else { MITK_DEBUG << "No provider registered for inspector that is defined as visible in the preferences. Illegal inspector ID: " << proIter.second; } } - m_Controls.tabWidget->setCurrentIndex(favIndex); + if (mitk::GetShowFavoritesInspector()) + { + auto favoritesPorvider = mitk::DataStorageInspectorGenerator::GetProvider(QmitkDataStorageFavoriteNodesInspector::INSPECTOR_ID()); + if (favoritesPorvider != nullptr) + { + this->AddPanel(favoritesPorvider, preferredID, preferredFound, preferredIndex); + } + } + + if (mitk::GetShowHistoryInspector()) + { + auto historyPorvider = mitk::DataStorageInspectorGenerator::GetProvider(QmitkDataStorageSelectionHistoryInspector::INSPECTOR_ID()); + if (historyPorvider != nullptr) + { + this->AddPanel(historyPorvider, preferredID, preferredFound, preferredIndex); + } + } + + m_Controls.tabWidget->setCurrentIndex(preferredIndex); this->setWindowTitle(title); this->setToolTip(hint); m_Controls.hint->setText(hint); m_Controls.hint->setVisible(!hint.isEmpty()); m_Controls.error->setVisible(false); + m_Controls.btnAddToFav->setIcon(berry::QtStyleManager::ThemeIcon(QStringLiteral(":/Qmitk/favorite_add.svg"))); - m_FavoriteNodesButton = new QPushButton("Add to favorites"); - m_Controls.buttonBox->addButton(m_FavoriteNodesButton, QDialogButtonBox::ActionRole); - - connect(m_FavoriteNodesButton, &QPushButton::clicked, this, &QmitkNodeSelectionDialog::OnFavoriteNodesButtonClicked); - connect(m_Controls.buttonBox, SIGNAL(accepted()), this, SLOT(OnOK())); - connect(m_Controls.buttonBox, SIGNAL(rejected()), this, SLOT(OnCancel())); + connect(m_Controls.btnAddToFav, &QPushButton::clicked, this, &QmitkNodeSelectionDialog::OnFavoriteNodesButtonClicked); + connect(m_Controls.buttonBox, &QDialogButtonBox::accepted, this, &QmitkNodeSelectionDialog::OnOK); + connect(m_Controls.buttonBox, &QDialogButtonBox::rejected, this, &QmitkNodeSelectionDialog::OnCancel); } void QmitkNodeSelectionDialog::SetDataStorage(mitk::DataStorage* dataStorage) { if (m_DataStorage != dataStorage) { m_DataStorage = dataStorage; if (!m_DataStorage.IsExpired()) { for (auto panel : m_Panels) { panel->SetDataStorage(dataStorage); } } } } void QmitkNodeSelectionDialog::SetNodePredicate(const mitk::NodePredicateBase* nodePredicate) { if (m_NodePredicate != nodePredicate) { m_NodePredicate = nodePredicate; for (auto panel : m_Panels) { panel->SetNodePredicate(m_NodePredicate); } } } const mitk::NodePredicateBase* QmitkNodeSelectionDialog::GetNodePredicate() const { return m_NodePredicate; } QmitkNodeSelectionDialog::NodeList QmitkNodeSelectionDialog::GetSelectedNodes() const { return m_SelectedNodes; } void QmitkNodeSelectionDialog::SetSelectionCheckFunction(const SelectionCheckFunctionType &checkFunction) { m_CheckFunction = checkFunction; auto checkResponse = m_CheckFunction(m_SelectedNodes); m_Controls.error->setText(QString::fromStdString(checkResponse)); m_Controls.error->setVisible(!checkResponse.empty()); m_Controls.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(checkResponse.empty()); } bool QmitkNodeSelectionDialog::GetSelectOnlyVisibleNodes() const { return m_SelectOnlyVisibleNodes; } void QmitkNodeSelectionDialog::SetSelectionMode(SelectionMode mode) { m_SelectionMode = mode; for (auto panel : m_Panels) { panel->SetSelectionMode(mode); } } QmitkNodeSelectionDialog::SelectionMode QmitkNodeSelectionDialog::GetSelectionMode() const { return m_SelectionMode; } void QmitkNodeSelectionDialog::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) { if (m_SelectOnlyVisibleNodes != selectOnlyVisibleNodes) { m_SelectOnlyVisibleNodes = selectOnlyVisibleNodes; for (auto panel : m_Panels) { panel->SetSelectOnlyVisibleNodes(m_SelectOnlyVisibleNodes); } } } void QmitkNodeSelectionDialog::SetCurrentSelection(NodeList selectedNodes) { m_SelectedNodes = selectedNodes; auto checkResponse = m_CheckFunction(m_SelectedNodes); m_Controls.error->setText(QString::fromStdString(checkResponse)); m_Controls.error->setVisible(!checkResponse.empty()); m_Controls.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(checkResponse.empty()); for (auto panel : m_Panels) { panel->SetCurrentSelection(selectedNodes); } } void QmitkNodeSelectionDialog::OnSelectionChanged(NodeList selectedNodes) { SetCurrentSelection(selectedNodes); emit CurrentSelectionChanged(selectedNodes); } void QmitkNodeSelectionDialog::OnFavoriteNodesButtonClicked() { for (auto node : m_SelectedNodes) { node->SetBoolProperty("org.mitk.selection.favorite", true); } } void QmitkNodeSelectionDialog::OnOK() { for (auto node : m_SelectedNodes) { QmitkDataStorageSelectionHistoryInspector::AddNodeToHistory(node); } this->accept(); } void QmitkNodeSelectionDialog::OnCancel() { this->reject(); } -void QmitkNodeSelectionDialog::AddPanel(QmitkAbstractDataStorageInspector* view, QString name, QString desc) +void QmitkNodeSelectionDialog::AddPanel(const mitk::IDataStorageInspectorProvider * provider, const mitk::IDataStorageInspectorProvider::InspectorIDType& preferredID, bool &preferredFound, int &preferredIndex) { - view->setParent(this); - view->SetSelectionMode(m_SelectionMode); + auto inspector = provider->CreateInspector(); + QString name = QString::fromStdString(provider->GetInspectorDisplayName()); + QString desc = QString::fromStdString(provider->GetInspectorDescription()); + + inspector->setParent(this); + inspector->SetSelectionMode(m_SelectionMode); auto tabPanel = new QWidget(); tabPanel->setObjectName(QString("tab_") + name); tabPanel->setToolTip(desc); - m_Controls.tabWidget->insertTab(m_Controls.tabWidget->count(), tabPanel, name); auto verticalLayout = new QVBoxLayout(tabPanel); verticalLayout->setSpacing(0); verticalLayout->setContentsMargins(0, 0, 0, 0); - verticalLayout->addWidget(view); + verticalLayout->addWidget(inspector); + + auto panelPos = m_Controls.tabWidget->insertTab(m_Controls.tabWidget->count(), tabPanel, name); + + auto icon = provider->GetInspectorIcon(); + if (!icon.isNull()) + { + m_Controls.tabWidget->setTabIcon(panelPos, icon); + } + + m_Panels.push_back(inspector); + connect(inspector, &QmitkAbstractDataStorageInspector::CurrentSelectionChanged, this, &QmitkNodeSelectionDialog::OnSelectionChanged); - m_Panels.push_back(view); - connect(view, &QmitkAbstractDataStorageInspector::CurrentSelectionChanged, this, &QmitkNodeSelectionDialog::OnSelectionChanged); + preferredFound = preferredFound || provider->GetInspectorID() == preferredID; + if (!preferredFound) + { + ++preferredIndex; + } } diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.h b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.h index 3ba21e481f..c529aae35b 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.h +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.h @@ -1,139 +1,141 @@ /*============================================================================ 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 QMITK_NODE_SELECTION_DIALOG_H #define QMITK_NODE_SELECTION_DIALOG_H #include #include #include +#include "mitkIDataStorageInspectorProvider.h" #include #include "org_mitk_gui_qt_common_Export.h" #include "ui_QmitkNodeSelectionDialog.h" #include #include /** * \class QmitkNodeSelectionDialog * \brief Widget that allows to show and edit the content of an mitk::IsoDoseLevel instance. */ class MITK_QT_COMMON QmitkNodeSelectionDialog : public QDialog { Q_OBJECT public: explicit QmitkNodeSelectionDialog(QWidget* parent = nullptr, QString caption = "", QString hint = ""); /** * @brief Sets the data storage that will be used /monitored by widget. * * @param dataStorage A pointer to the data storage to set. */ void SetDataStorage(mitk::DataStorage* dataStorage); /** * @brief Sets the node predicate and updates the widget, according to the node predicate. * * @param nodePredicate A pointer to node predicate. */ virtual void SetNodePredicate(const mitk::NodePredicateBase* nodePredicate); const mitk::NodePredicateBase* GetNodePredicate() const; using NodeList = QList; NodeList GetSelectedNodes() const; /** * @brief Helper function that is used to check the given selection for consistency. * Returning an empty string assumes that everything is alright and the selection is valid. * If the string is not empty, the content of the string will be used as error message. */ using SelectionCheckFunctionType = std::function; /** * @brief A selection check function can be set. If set the dialog uses this function to check the made/set selection. * If the selection is valid, everything is fine. * If the selection is indicated as invalid, the dialog will display the selection check function error message. */ void SetSelectionCheckFunction(const SelectionCheckFunctionType &checkFunction); bool GetSelectOnlyVisibleNodes() const; using SelectionMode = QAbstractItemView::SelectionMode; void SetSelectionMode(SelectionMode mode); SelectionMode GetSelectionMode() const; Q_SIGNALS: /* * @brief A signal that will be emitted if the selected node has changed. * * @param nodes A list of data nodes that are newly selected. */ void CurrentSelectionChanged(NodeList nodes); public Q_SLOTS: /* * @brief Change the selection modus of the item view's selection model. * * If true, an incoming selection will be filtered (reduced) to only those nodes that are visible by the current view. * An outgoing selection can then at most contain the filtered nodes. * If false, the incoming non-visible selection will be stored and later added to the outgoing selection, * to include the original selection that could not be modified. * The part of the original selection, that is non-visible are the nodes that are not * * @param selectOnlyVisibleNodes The bool value to define the selection modus. */ void SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes); /* * @brief Transform a list of data nodes into a model selection and set this as a new selection of the * selection model of the private member item view. * * The function filters the given list of nodes according to the 'm_SelectOnlyVisibleNodes' member variable. If * necessary, the non-visible nodes are stored. This is done if 'm_SelectOnlyVisibleNodes' is false: In this case * the selection may be filtered and only a subset of the selected nodes may be visible and therefore (de-)selectable * in the data storage viewer. By storing the non-visible nodes it is possible to send the new, modified selection * but also include the selected nodes from the original selection that could not be modified (see 'SetSelectOnlyVisibleNodes'). * * @param nodes A list of data nodes that should be newly selected. */ void SetCurrentSelection(NodeList selectedNodes); protected Q_SLOTS: void OnSelectionChanged(NodeList selectedNodes); void OnFavoriteNodesButtonClicked(); void OnOK(); void OnCancel(); protected: - void AddPanel(QmitkAbstractDataStorageInspector* view, QString name, QString desc); + + void AddPanel(const mitk::IDataStorageInspectorProvider* provider, const mitk::IDataStorageInspectorProvider::InspectorIDType &preferredID, bool &preferredFound, int &preferredIndex); mitk::WeakPointer m_DataStorage; mitk::NodePredicateBase::ConstPointer m_NodePredicate; bool m_SelectOnlyVisibleNodes; NodeList m_SelectedNodes; SelectionCheckFunctionType m_CheckFunction; SelectionMode m_SelectionMode; using PanelVectorType = std::vector; PanelVectorType m_Panels; QPushButton* m_FavoriteNodesButton; Ui_QmitkNodeSelectionDialog m_Controls; }; #endif // QMITK_NODE_SELECTION_DIALOG_H diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.ui b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.ui index c874083509..2237bc6a63 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.ui +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.ui @@ -1,108 +1,128 @@ QmitkNodeSelectionDialog 0 0 - 596 - 539 + 800 + 600 Dialog true true 5 0 0 0 0 6 6 6 QFrame::NoFrame Info text ... Qt::RichText true -1 + + + 24 + 24 + + + + + + + + Add the current selection to the favorites. + + + Add to favorites + + + 6 0 6 6 error text - - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionPreferenceHelper.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionPreferenceHelper.cpp index 442e8f9a37..24c157539b 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionPreferenceHelper.cpp +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionPreferenceHelper.cpp @@ -1,119 +1,161 @@ /*============================================================================ 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 "QmitkNodeSelectionPreferenceHelper.h" #include #include #include #include #include #include "mitkExceptionMacro.h" void mitk::PutVisibleDataStorageInspectors(const VisibleDataStorageInspectorMapType &inspectors) { berry::IPreferencesService *prefService = berry::Platform::GetPreferencesService(); berry::IPreferences::Pointer prefNode = prefService->GetSystemPreferences()->Node(mitk::NodeSelectionConstants::ROOT_PREFERENCE_NODE_ID.c_str()); berry::IPreferences::Pointer visNode = prefNode->Node(mitk::NodeSelectionConstants::VISIBLE_INSPECTORS_NODE_ID.c_str()); visNode->RemoveNode(); prefNode->Flush(); // new empty preset node visNode = prefNode->Node(mitk::NodeSelectionConstants::VISIBLE_INSPECTORS_NODE_ID.c_str()); // store map in new node for (const auto &inspector : inspectors) { std::ostringstream sstr; sstr << inspector.first; berry::IPreferences::Pointer aNode = visNode->Node(QString::fromStdString(sstr.str())); aNode->Put(mitk::NodeSelectionConstants::VISIBLE_INSPECTOR_ID.c_str(), inspector.second.c_str()); aNode->Flush(); } visNode->Flush(); } mitk::VisibleDataStorageInspectorMapType mitk::GetVisibleDataStorageInspectors() { berry::IPreferencesService *prefService = berry::Platform::GetPreferencesService(); berry::IPreferences::Pointer prefNode = prefService->GetSystemPreferences()->Node(mitk::NodeSelectionConstants::ROOT_PREFERENCE_NODE_ID.c_str()); berry::IPreferences::Pointer visNode = prefNode->Node(mitk::NodeSelectionConstants::VISIBLE_INSPECTORS_NODE_ID.c_str()); typedef QStringList NamesType; NamesType names = visNode->ChildrenNames(); VisibleDataStorageInspectorMapType visMap; if (!names.empty()) { for (NamesType::const_iterator pos = names.begin(); pos != names.end(); ++pos) { berry::IPreferences::Pointer aNode = visNode->Node(*pos); if (aNode.IsNull()) { mitkThrow() << "Error in preference interface. Cannot find preset node under given name. Name: " << (*pos).toStdString(); } std::istringstream isstr(pos->toStdString()); unsigned int order = 0; isstr >> order; auto id = aNode->Get(mitk::NodeSelectionConstants::VISIBLE_INSPECTOR_ID.c_str(), ""); if (id.isEmpty()) { mitkThrow() << "Error in preference interface. ID of visible inspector is not set. Inspector position: " << order; } visMap.insert(std::make_pair(order, id.toStdString())); } } return visMap; } -mitk::DataStorageInspectorIDType mitk::GetFavoriteDataStorageInspector() +mitk::DataStorageInspectorIDType mitk::GetPreferredDataStorageInspector() { berry::IPreferencesService *prefService = berry::Platform::GetPreferencesService(); berry::IPreferences::Pointer prefNode = prefService->GetSystemPreferences()->Node(mitk::NodeSelectionConstants::ROOT_PREFERENCE_NODE_ID.c_str()); - auto id = prefNode->Get(mitk::NodeSelectionConstants::FAVORITE_INSPECTOR_ID.c_str(), ""); + auto id = prefNode->Get(mitk::NodeSelectionConstants::PREFERRED_INSPECTOR_ID.c_str(), ""); mitk::DataStorageInspectorIDType result = id.toStdString(); return result; } -void mitk::PutFavoriteDataStorageInspector(const DataStorageInspectorIDType &id) +void mitk::PutPreferredDataStorageInspector(const DataStorageInspectorIDType &id) { berry::IPreferencesService *prefService = berry::Platform::GetPreferencesService(); berry::IPreferences::Pointer prefNode = prefService->GetSystemPreferences()->Node(mitk::NodeSelectionConstants::ROOT_PREFERENCE_NODE_ID.c_str()); - prefNode->Put(mitk::NodeSelectionConstants::FAVORITE_INSPECTOR_ID.c_str(), id.c_str()); + prefNode->Put(mitk::NodeSelectionConstants::PREFERRED_INSPECTOR_ID.c_str(), id.c_str()); prefNode->Flush(); } + +void mitk::PutShowFavoritesInspector(bool show) +{ + berry::IPreferencesService *prefService = berry::Platform::GetPreferencesService(); + + berry::IPreferences::Pointer prefNode = + prefService->GetSystemPreferences()->Node(mitk::NodeSelectionConstants::ROOT_PREFERENCE_NODE_ID.c_str()); + + prefNode->PutBool(mitk::NodeSelectionConstants::SHOW_FAVORITE_INSPECTOR.c_str(), show); + prefNode->Flush(); +} + +bool mitk::GetShowFavoritesInspector() +{ + berry::IPreferencesService *prefService = berry::Platform::GetPreferencesService(); + + berry::IPreferences::Pointer prefNode = + prefService->GetSystemPreferences()->Node(mitk::NodeSelectionConstants::ROOT_PREFERENCE_NODE_ID.c_str()); + + return prefNode->GetBool(mitk::NodeSelectionConstants::SHOW_FAVORITE_INSPECTOR.c_str(), true); +} + +void mitk::PutShowHistoryInspector(bool show) +{ + berry::IPreferencesService *prefService = berry::Platform::GetPreferencesService(); + + berry::IPreferences::Pointer prefNode = + prefService->GetSystemPreferences()->Node(mitk::NodeSelectionConstants::ROOT_PREFERENCE_NODE_ID.c_str()); + + prefNode->PutBool(mitk::NodeSelectionConstants::SHOW_HISTORY_INSPECTOR.c_str(), show); + prefNode->Flush(); +} + +bool mitk::GetShowHistoryInspector() +{ + berry::IPreferencesService *prefService = berry::Platform::GetPreferencesService(); + + berry::IPreferences::Pointer prefNode = + prefService->GetSystemPreferences()->Node(mitk::NodeSelectionConstants::ROOT_PREFERENCE_NODE_ID.c_str()); + + return prefNode->GetBool(mitk::NodeSelectionConstants::SHOW_HISTORY_INSPECTOR.c_str(), true); +} diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionPreferenceHelper.h b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionPreferenceHelper.h index ecfdc573f0..477493c03e 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionPreferenceHelper.h +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionPreferenceHelper.h @@ -1,40 +1,55 @@ /*============================================================================ 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 __QMITK_NODE_SELECTION_PREFERENCE_HELPER_H #define __QMITK_NODE_SELECTION_PREFERENCE_HELPER_H #include #include namespace mitk { using DataStorageInspectorIDType = std::string; + /** map containing the IDs of all inspectors that should be visible. The map key is the order of appearance + of the respective inspector.*/ using VisibleDataStorageInspectorMapType = std::map; /** Stores the given ID as favorite inspector.*/ - void PutFavoriteDataStorageInspector(const DataStorageInspectorIDType& id); + void PutPreferredDataStorageInspector(const DataStorageInspectorIDType& id); /** Gets the ID of the current favorite data storage inspector. * If empty string is returned, no favorite is set.*/ - DataStorageInspectorIDType GetFavoriteDataStorageInspector(); + DataStorageInspectorIDType GetPreferredDataStorageInspector(); /** Stores the given map of visible inspectors.*/ void PutVisibleDataStorageInspectors(const VisibleDataStorageInspectorMapType& inspectors); /** Gets the map of current visible inspectors.*/ VisibleDataStorageInspectorMapType GetVisibleDataStorageInspectors(); + + + /** Stores the given show state of the favorite inspector.*/ + void PutShowFavoritesInspector(bool show); + + /** Indicates if the favorites inspector should be shown. */ + bool GetShowFavoritesInspector(); + + /** Stores the given show state of the history inspector.*/ + void PutShowHistoryInspector(bool show); + + /** Indicates if the history inspector should be shown. */ + bool GetShowHistoryInspector(); } #endif diff --git a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.cpp b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.cpp index 4692c11a9e..4ab85ab5e1 100644 --- a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.cpp +++ b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.cpp @@ -1,18 +1,20 @@ /*============================================================================ 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 "QmitkNodeSelectionConstants.h" const std::string mitk::NodeSelectionConstants::ROOT_PREFERENCE_NODE_ID = "/NODESELECTION/UI"; const std::string mitk::NodeSelectionConstants::VISIBLE_INSPECTORS_NODE_ID = "visibleInspectors"; -const std::string mitk::NodeSelectionConstants::FAVORITE_INSPECTOR_ID = "inspectorID"; +const std::string mitk::NodeSelectionConstants::PREFERRED_INSPECTOR_ID = "inspectorID"; const std::string mitk::NodeSelectionConstants::VISIBLE_INSPECTOR_ID = "inspectorID"; +const std::string mitk::NodeSelectionConstants::SHOW_FAVORITE_INSPECTOR = "showFavoriteInspector"; +const std::string mitk::NodeSelectionConstants::SHOW_HISTORY_INSPECTOR = "showHistoryInspector"; diff --git a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.h b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.h index 61196de261..7aa5326fd1 100644 --- a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.h +++ b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.h @@ -1,38 +1,42 @@ /*============================================================================ 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 _QMITK_NODE_SELECTION_CONSTANTS_H_ #define _QMITK_NODE_SELECTION_CONSTANTS_H_ #include #include "org_mitk_gui_qt_common_Export.h" namespace mitk { struct MITK_QT_COMMON NodeSelectionConstants { /** ID/Path of main preference node for node selections. */ static const std::string ROOT_PREFERENCE_NODE_ID; /** ID of main preference node where all visible inspectors are stored (e.g. ROOT_PREFERENCE_NODE_ID+"/"+VISIBLE_INSPECTORS_NODE_ID+"/[orderering #]"). The sub node naming encodes the ordering number of the visible inspector.*/ static const std::string VISIBLE_INSPECTORS_NODE_ID; - /** ID for the value that stores the favorite inspector ID in the root preference node.*/ - static const std::string FAVORITE_INSPECTOR_ID; + /** ID for the value that stores the preferred inspector ID in the root preference node.*/ + static const std::string PREFERRED_INSPECTOR_ID; /** ID for the value that stores the inspector ID in the preference node.*/ static const std::string VISIBLE_INSPECTOR_ID; + /** ID for the value that stores if the favorite inspector should be visible.*/ + static const std::string SHOW_FAVORITE_INSPECTOR; + /** ID for the value that stores if the history inspector should be visible.*/ + static const std::string SHOW_HISTORY_INSPECTOR; }; } #endif diff --git a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.cpp b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.cpp index 3223a49e83..be25ed2846 100644 --- a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.cpp +++ b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.cpp @@ -1,194 +1,221 @@ /*============================================================================ 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 "QmitkNodeSelectionPreferencePage.h" #include "QmitkNodeSelectionPreferenceHelper.h" +#include +#include + //----------------------------------------------------------------------------- QmitkNodeSelectionPreferencePage::QmitkNodeSelectionPreferencePage() : m_MainControl(nullptr), m_Controls(nullptr) { } //----------------------------------------------------------------------------- QmitkNodeSelectionPreferencePage::~QmitkNodeSelectionPreferencePage() { delete m_Controls; } //----------------------------------------------------------------------------- void QmitkNodeSelectionPreferencePage::Init(berry::IWorkbench::Pointer ) { } //----------------------------------------------------------------------------- void QmitkNodeSelectionPreferencePage::CreateQtControl(QWidget* parent) { m_MainControl = new QWidget(parent); m_Controls = new Ui::QmitkNodeSelectionPreferencePage; m_Controls->setupUi( m_MainControl ); - connect(m_Controls->comboFavorite, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateWidgets())); + connect(m_Controls->comboPreferred, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateWidgets())); connect(m_Controls->btnUp, SIGNAL(clicked(bool)), this, SLOT(MoveUp())); connect(m_Controls->btnDown, SIGNAL(clicked(bool)), this, SLOT(MoveDown())); - connect(m_Controls->listInspectors, SIGNAL(itemSelectionChanged()), this, SLOT(UpdateWidgets())); + connect(m_Controls->listInspectors, &QListWidget::itemSelectionChanged, this, &QmitkNodeSelectionPreferencePage::UpdateWidgets); this->Update(); } //----------------------------------------------------------------------------- QWidget* QmitkNodeSelectionPreferencePage::GetQtControl() const { return m_MainControl; } //----------------------------------------------------------------------------- bool QmitkNodeSelectionPreferencePage::PerformOk() { //store favorite - auto id = m_Controls->comboFavorite->currentData().toString(); - mitk::PutFavoriteDataStorageInspector(id.toStdString()); + auto id = m_Controls->comboPreferred->currentData().toString(); + mitk::PutPreferredDataStorageInspector(id.toStdString()); //store visible mitk::VisibleDataStorageInspectorMapType visibles; unsigned int visiblePos = 0; for (int i = 0; i < m_Controls->listInspectors->count(); ++i) { auto item = m_Controls->listInspectors->item(i); if (item->checkState() == Qt::Checked) { visibles.insert(std::make_pair(visiblePos++, item->data(Qt::UserRole).toString().toStdString())); } } mitk::PutVisibleDataStorageInspectors(visibles); + mitk::PutShowFavoritesInspector(m_Controls->checkShowFav->isChecked()); + mitk::PutShowHistoryInspector(m_Controls->checkShowHistory->isChecked()); return true; } //----------------------------------------------------------------------------- void QmitkNodeSelectionPreferencePage::PerformCancel() { } //----------------------------------------------------------------------------- void QmitkNodeSelectionPreferencePage::Update() { m_Providers = mitk::DataStorageInspectorGenerator::GetProviders(); auto visibleProviders = mitk::GetVisibleDataStorageInspectors(); auto allProviders = mitk::DataStorageInspectorGenerator::GetProviders(); - auto favorite = mitk::GetFavoriteDataStorageInspector(); + auto favorite = mitk::GetPreferredDataStorageInspector(); auto finding = m_Providers.find(favorite); if (finding == m_Providers.cend()) { favorite = m_Providers.begin()->first; } //fill favorite combo int index = 0; int currentIndex = 0; - m_Controls->comboFavorite->clear(); + m_Controls->comboPreferred->clear(); for (auto iter : m_Providers) { - m_Controls->comboFavorite->addItem(QString::fromStdString(iter.second->GetInspectorDisplayName()),QVariant::fromValue(QString::fromStdString(iter.first))); + m_Controls->comboPreferred->addItem(QString::fromStdString(iter.second->GetInspectorDisplayName()),QVariant::fromValue(QString::fromStdString(iter.first))); if (iter.first == favorite) { currentIndex = index; }; ++index; } - m_Controls->comboFavorite->setCurrentIndex(currentIndex); + m_Controls->comboPreferred->setCurrentIndex(currentIndex); //fill inspector list m_Controls->listInspectors->clear(); for (const auto iter : allProviders) { - auto currentID = iter.first; - QListWidgetItem* item = new QListWidgetItem; - item->setText(QString::fromStdString(iter.second->GetInspectorDisplayName())); - item->setData(Qt::UserRole, QVariant::fromValue(QString::fromStdString(currentID))); - item->setToolTip(QString::fromStdString(iter.second->GetInspectorDescription())); - - auto finding = std::find_if(visibleProviders.cbegin(), visibleProviders.cend(), [¤tID](auto v) {return v.second == currentID; }); - if (finding == visibleProviders.cend()) - { - item->setCheckState(Qt::Unchecked); - m_Controls->listInspectors->addItem(item); - } - else + if (iter.first != QmitkDataStorageFavoriteNodesInspector::INSPECTOR_ID() && iter.first != QmitkDataStorageSelectionHistoryInspector::INSPECTOR_ID()) { - item->setCheckState(Qt::Checked); - m_Controls->listInspectors->insertItem(finding->first, item); + auto currentID = iter.first; + QListWidgetItem* item = new QListWidgetItem; + item->setText(QString::fromStdString(iter.second->GetInspectorDisplayName())); + item->setData(Qt::UserRole, QVariant::fromValue(QString::fromStdString(currentID))); + item->setToolTip(QString::fromStdString(iter.second->GetInspectorDescription())); + + auto finding = std::find_if(visibleProviders.cbegin(), visibleProviders.cend(), [¤tID](auto v) {return v.second == currentID; }); + if (finding == visibleProviders.cend()) + { + item->setCheckState(Qt::Unchecked); + m_Controls->listInspectors->addItem(item); + } + else + { + item->setCheckState(Qt::Checked); + m_Controls->listInspectors->insertItem(finding->first, item); + } } } + m_Controls->checkShowFav->setChecked(mitk::GetShowFavoritesInspector()); + m_Controls->checkShowHistory->setChecked(mitk::GetShowHistoryInspector()); + this->UpdateWidgets(); } void QmitkNodeSelectionPreferencePage::UpdateWidgets() { int currentIndex = m_Controls->listInspectors->currentRow(); m_Controls->btnUp->setEnabled(!m_Controls->listInspectors->selectedItems().empty() && currentIndex > 0); m_Controls->btnDown->setEnabled(!m_Controls->listInspectors->selectedItems().empty() && currentIndex + 1 < m_Controls->listInspectors->count()); for (int i = 0; i < m_Controls->listInspectors->count(); ++i) { auto item = m_Controls->listInspectors->item(i); - if (item->data(Qt::UserRole).toString() == m_Controls->comboFavorite->currentData().toString()) + if (item->data(Qt::UserRole).toString() == m_Controls->comboPreferred->currentData().toString()) { - //favorites are always visible. + //preferred inspector is always visible. item->setCheckState(Qt::Checked); item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled); } else { item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsUserCheckable); } } -}; + + auto isFavSelected = + QmitkDataStorageFavoriteNodesInspector::INSPECTOR_ID() == m_Controls->comboPreferred->currentData().toString(); + if (isFavSelected) + { + m_Controls->checkShowFav->setChecked(true); + } + m_Controls->checkShowFav->setEnabled(!isFavSelected); + + auto isHistorySelected = + QmitkDataStorageSelectionHistoryInspector::INSPECTOR_ID() == m_Controls->comboPreferred->currentData().toString(); + if (isHistorySelected) + { + m_Controls->checkShowHistory->setChecked(true); + } + m_Controls->checkShowHistory->setEnabled(!isHistorySelected); +} void QmitkNodeSelectionPreferencePage::MoveDown() { int currentIndex = m_Controls->listInspectors->currentRow(); if (currentIndex+1 < m_Controls->listInspectors->count()) { QListWidgetItem *currentItem = m_Controls->listInspectors->takeItem(currentIndex); m_Controls->listInspectors->insertItem(currentIndex + 1, currentItem); m_Controls->listInspectors->setCurrentRow(currentIndex + 1); } this->UpdateWidgets(); -}; +} void QmitkNodeSelectionPreferencePage::MoveUp() { int currentIndex = m_Controls->listInspectors->currentRow(); if (currentIndex > 0) { QListWidgetItem *currentItem = m_Controls->listInspectors->takeItem(currentIndex); m_Controls->listInspectors->insertItem(currentIndex - 1, currentItem); m_Controls->listInspectors->setCurrentRow(currentIndex - 1); } this->UpdateWidgets(); -}; +} diff --git a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.ui b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.ui index c88f7330f2..1599ef75ad 100644 --- a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.ui +++ b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.ui @@ -1,145 +1,165 @@ QmitkNodeSelectionPreferencePage 0 0 715 713 Form Up Down - - - - Favorite inspector: - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - + - <html><head/><body><p>The favorite inspector is always visible.</p><p>Additionally the favorite inspector has always the focus when opening a node selection dialoge.</p></body></html> + <html><head/><body><p>The preferred inspector is always visible.</p><p>Additionally the preferred inspector has always the focus when opening a node selection dialoge.</p></body></html> Neues Element 2 - + <html><head/><body><p><span style=" font-weight:600;">Instruction:</span><br/>Only checked inspectors will be shown in node selection dialogs.<br/>You may change the order in the inspector list, to change the order of the tabs in the node selection dialog.</p></body></html> true Inspector visiblitiy and order: 16777215 16777215 List of all available inspectors. Checked inspectores will be display TreeInspector ffffff Checked List Checked + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Preferred inspector: + + + + + + + Show favorites inspector + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + Show history inspector + + + true + + + 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; +}; diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp index 415d586d47..02089e0da9 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp @@ -1,941 +1,925 @@ /*============================================================================ 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 "mitkProperties.h" #include "mitkSegTool2D.h" #include "mitkStatusBar.h" #include "QmitkNewSegmentationDialog.h" #include #include #include #include "QmitkSegmentationView.h" #include #include "mitkVtkResliceInterpolationProperty.h" #include "mitkApplicationCursor.h" #include "mitkSegmentationObjectFactory.h" #include "mitkPluginActivator.h" #include "mitkCameraController.h" #include "mitkLabelSetImage.h" #include "mitkImageTimeSelector.h" #include "mitkNodePredicateFunction.h" #include #include "usModuleResource.h" #include "usModuleResourceStream.h" //micro service to get the ToolManager instance #include "mitkToolManagerProvider.h" #include #include const std::string QmitkSegmentationView::VIEW_ID = "org.mitk.views.segmentation"; QmitkSegmentationView::QmitkSegmentationView() : m_Parent(nullptr) , m_Controls(nullptr) , m_RenderWindowPart(nullptr) , m_MouseCursorSet(false) , m_DataSelectionChanged(false) { mitk::TNodePredicateDataType::Pointer isImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateDataType::Pointer isDwi = mitk::NodePredicateDataType::New("DiffusionImage"); mitk::NodePredicateDataType::Pointer isDti = mitk::NodePredicateDataType::New("TensorImage"); mitk::NodePredicateDataType::Pointer isOdf = mitk::NodePredicateDataType::New("OdfImage"); auto isSegment = mitk::NodePredicateDataType::New("Segment"); mitk::NodePredicateOr::Pointer validImages = mitk::NodePredicateOr::New(); validImages->AddPredicate(mitk::NodePredicateAnd::New(isImage, mitk::NodePredicateNot::New(isSegment))); validImages->AddPredicate(isDwi); validImages->AddPredicate(isDti); validImages->AddPredicate(isOdf); m_IsNotAHelperObject = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true))); m_IsOfTypeImagePredicate = mitk::NodePredicateAnd::New(validImages, m_IsNotAHelperObject); mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateNot::Pointer isNotBinaryPredicate = mitk::NodePredicateNot::New(isBinaryPredicate); mitk::NodePredicateAnd::Pointer isABinaryImagePredicate = mitk::NodePredicateAnd::New(m_IsOfTypeImagePredicate, isBinaryPredicate); mitk::NodePredicateAnd::Pointer isNotABinaryImagePredicate = mitk::NodePredicateAnd::New(m_IsOfTypeImagePredicate, isNotBinaryPredicate); m_IsASegmentationImagePredicate = mitk::NodePredicateOr::New(isABinaryImagePredicate, mitk::TNodePredicateDataType::New()); m_IsAPatientImagePredicate = mitk::NodePredicateAnd::New(isNotABinaryImagePredicate, mitk::NodePredicateNot::New(mitk::TNodePredicateDataType::New())); } QmitkSegmentationView::~QmitkSegmentationView() { if (m_Controls) { SetToolSelectionBoxesEnabled(false); // deactivate all tools mitk::ToolManagerProvider::GetInstance()->GetToolManager()->ActivateTool(-1); // removing all observers for (NodeTagMapType::iterator dataIter = m_WorkingDataObserverTags.begin(); dataIter != m_WorkingDataObserverTags.end(); ++dataIter) { (*dataIter).first->GetProperty("visible")->RemoveObserver((*dataIter).second); } m_WorkingDataObserverTags.clear(); mitk::RenderingManager::GetInstance()->RemoveObserver(m_RenderingManagerObserverTag); ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); service->RemoveAllPlanePositions(); context->ungetService(ppmRef); SetToolManagerSelection(nullptr, nullptr); } delete m_Controls; } void QmitkSegmentationView::NewNodeObjectsGenerated(mitk::ToolManager::DataVectorType* nodes) { if (!nodes) return; mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); if (!toolManager) return; for (mitk::ToolManager::DataVectorType::iterator iter = nodes->begin(); iter != nodes->end(); ++iter) { this->FireNodeSelected( *iter ); // only last iteration meaningful, multiple generated objects are not taken into account here } } -void QmitkSegmentationView::Visible() -{ -} - -void QmitkSegmentationView::Hidden() -{ -} - -void QmitkSegmentationView::Activated() -{ -} - -void QmitkSegmentationView::Deactivated() -{ -} - void QmitkSegmentationView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { if (m_RenderWindowPart != renderWindowPart) { m_RenderWindowPart = renderWindowPart; } if (m_Parent) { m_Parent->setEnabled(true); } // tell the interpolation about tool manager, data storage and render window part if (m_Controls) { mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); m_Controls->m_SlicesInterpolator->SetDataStorage(this->GetDataStorage()); QList controllers; controllers.push_back(renderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()); controllers.push_back(renderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()); controllers.push_back(renderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()); m_Controls->m_SlicesInterpolator->Initialize(toolManager, controllers); } } void QmitkSegmentationView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* /*renderWindowPart*/) { m_RenderWindowPart = nullptr; if (m_Parent) { m_Parent->setEnabled(false); } } void QmitkSegmentationView::OnPreferencesChanged(const berry::IBerryPreferences* prefs) { if (m_Controls != nullptr) { bool slimView = prefs->GetBool("slim view", false); m_Controls->m_ManualToolSelectionBox2D->SetShowNames(!slimView); m_Controls->m_ManualToolSelectionBox3D->SetShowNames(!slimView); m_Controls->btnNewSegmentation->setToolButtonStyle(slimView ? Qt::ToolButtonIconOnly : Qt::ToolButtonTextOnly); } auto autoSelectionEnabled = prefs->GetBool("auto selection", true); m_Controls->patImageSelector->SetAutoSelectNewNodes(autoSelectionEnabled); m_Controls->segImageSelector->SetAutoSelectNewNodes(autoSelectionEnabled); this->ForceDisplayPreferencesUponAllImages(); } void QmitkSegmentationView::CreateNewSegmentation() { mitk::DataNode::Pointer node = mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetReferenceData(0); if (node.IsNotNull()) { mitk::Image::ConstPointer image = dynamic_cast(node->GetData()); if (image.IsNotNull()) { if (image->GetDimension() > 1) { // ask about the name and organ type of the new segmentation QmitkNewSegmentationDialog* dialog = new QmitkNewSegmentationDialog(m_Parent); // needs a QWidget as parent, "this" is not QWidget QStringList organColors = mitk::OrganNamesHandling::GetDefaultOrganColorString();; dialog->SetSuggestionList(organColors); int dialogReturnValue = dialog->exec(); if (dialogReturnValue == QDialog::Rejected) { // user clicked cancel or pressed Esc or something similar return; } if (image->GetDimension() > 3) { auto result = QMessageBox::question(m_Parent, tr("Generate a static mask?"),tr("The selected image has multiple time steps. You can either generate a simple/static masks resembling the geometry of the first timestep of the image. Or you can generate a dynamic mask that equals the selected image in geometry and number of timesteps; thus a dynamic mask can change over time (e.g. according to the image)."), tr("Yes, generate a static mask"), tr("No, generate a dynamic mask"), QString(), 0,0); if (result == 0) { auto selector = mitk::ImageTimeSelector::New(); selector->SetInput(image); selector->SetTimeNr(0); selector->Update(); const auto refTimeGeometry = image->GetTimeGeometry(); auto newTimeGeometry = mitk::ProportionalTimeGeometry::New(); newTimeGeometry->SetFirstTimePoint(refTimeGeometry->GetMinimumTimePoint()); newTimeGeometry->SetStepDuration(refTimeGeometry->GetMaximumTimePoint() - refTimeGeometry->GetMinimumTimePoint()); mitk::Image::Pointer newImage = selector->GetOutput(); newTimeGeometry->SetTimeStepGeometry(image->GetGeometry(), 0); newImage->SetTimeGeometry(newTimeGeometry); image = newImage; } } // ask the user about an organ type and name, add this information to the image's (!) propertylist // create a new image of the same dimensions and smallest possible pixel type mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); mitk::Tool* firstTool = toolManager->GetToolById(0); if (firstTool) { try { std::string newNodeName = dialog->GetSegmentationName().toStdString(); if (newNodeName.empty()) { newNodeName = "no_name"; } mitk::DataNode::Pointer emptySegmentation = firstTool->CreateEmptySegmentationNode(image, newNodeName, dialog->GetColor()); // initialize showVolume to false to prevent recalculating the volume while working on the segmentation emptySegmentation->SetProperty("showVolume", mitk::BoolProperty::New(false)); if (!emptySegmentation) { return; // could be aborted by user } mitk::OrganNamesHandling::UpdateOrganList(organColors, dialog->GetSegmentationName(), dialog->GetColor()); // escape ';' here (replace by '\;'), see longer comment above QString stringForStorage = organColors.replaceInStrings(";", "\\;").join(";"); MITK_DEBUG << "Will store: " << stringForStorage; this->GetPreferences()->Put("Organ-Color-List", stringForStorage); this->GetPreferences()->Flush(); if (mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetWorkingData(0)) { mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetWorkingData(0)->SetSelected(false); } emptySegmentation->SetSelected(true); this->GetDataStorage()->Add(emptySegmentation, node); // add as a child, because the segmentation "derives" from the original m_Controls->segImageSelector->SetCurrentSelectedNode(emptySegmentation); mitk::RenderingManager::GetInstance()->InitializeViews(emptySegmentation->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); } catch (const std::bad_alloc&) { QMessageBox::warning(nullptr, tr("Create new segmentation"), tr("Could not allocate memory for new segmentation")); } } } else { QMessageBox::information(nullptr, tr("Segmentation"), tr("Segmentation is currently not supported for 2D images")); } } } else { MITK_ERROR << "'Create new segmentation' button should never be clickable unless a patient image is selected..."; } } void QmitkSegmentationView::OnVisiblePropertyChanged() { this->CheckRenderingState(); } void QmitkSegmentationView::NodeAdded(const mitk::DataNode *node) { if (!m_IsASegmentationImagePredicate->CheckNode(node)) { return; } itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::OnVisiblePropertyChanged); m_WorkingDataObserverTags.insert(std::pair(const_cast(node), node->GetProperty("visible")->AddObserver(itk::ModifiedEvent(), command))); ApplyDisplayOptions(const_cast(node)); } void QmitkSegmentationView::NodeRemoved(const mitk::DataNode* node) { if (m_IsASegmentationImagePredicate->CheckNode(node)) { //First of all remove all possible contour markers of the segmentation mitk::DataStorage::SetOfObjects::ConstPointer allContourMarkers = this->GetDataStorage()->GetDerivations(node, mitk::NodePredicateProperty::New("isContourMarker", mitk::BoolProperty::New(true))); ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); for (mitk::DataStorage::SetOfObjects::ConstIterator it = allContourMarkers->Begin(); it != allContourMarkers->End(); ++it) { std::string nodeName = node->GetName(); unsigned int t = nodeName.find_last_of(" "); unsigned int id = atof(nodeName.substr(t + 1).c_str()) - 1; service->RemovePlanePosition(id); this->GetDataStorage()->Remove(it->Value()); } context->ungetService(ppmRef); service = nullptr; if ((mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetWorkingData(0) == node) && m_Controls->patImageSelector->GetSelectedNode().IsNotNull()) { this->SetToolManagerSelection(mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetReferenceData(0), nullptr); this->UpdateWarningLabel(tr("Select or create a segmentation")); } mitk::Image* image = dynamic_cast(node->GetData()); mitk::SurfaceInterpolationController::GetInstance()->RemoveInterpolationSession(image); } mitk::DataNode* tempNode = const_cast(node); //Remove observer if one was registered auto finding = m_WorkingDataObserverTags.find(tempNode); if (finding != m_WorkingDataObserverTags.end()) { node->GetProperty("visible")->RemoveObserver(m_WorkingDataObserverTags[tempNode]); m_WorkingDataObserverTags.erase(tempNode); } } void QmitkSegmentationView::OnPatientSelectionChanged(QList nodes) { if(! nodes.empty()) { this->UpdateWarningLabel(""); auto node = nodes.first(); auto geometryCheck = [node](const mitk::DataNode * segNode) { return QmitkSegmentationView::CheckForSameGeometry(segNode, node); }; mitk::NodePredicateFunction::Pointer hasCorrectGeo = mitk::NodePredicateFunction::New(geometryCheck); auto segPredicate = mitk::NodePredicateAnd::New(m_IsASegmentationImagePredicate.GetPointer(), hasCorrectGeo.GetPointer()); m_Controls->segImageSelector->SetNodePredicate(segPredicate); mitk::DataNode* segNode = m_Controls->segImageSelector->GetSelectedNode(); this->SetToolManagerSelection(node, segNode); if (segNode) { - //Doing this we can assure that the segmenation is always visible if the segmentation and the patient image are + //Doing this we can assure that the segmentation is always visible if the segmentation and the patient image are //loaded separately int layer(10); node->GetIntProperty("layer", layer); layer++; segNode->SetProperty("layer", mitk::IntProperty::New(layer)); this->CheckRenderingState(); } else { this->SetToolSelectionBoxesEnabled( false ); this->UpdateWarningLabel(tr("Select or create a segmentation")); } } else { m_Controls->segImageSelector->SetNodePredicate(m_IsASegmentationImagePredicate); this->UpdateWarningLabel(tr("Please select an image!")); this->SetToolSelectionBoxesEnabled( false ); } } void QmitkSegmentationView::OnSegmentationSelectionChanged(QList nodes) { if (nodes.empty()) { this->UpdateWarningLabel(tr("Select or create a segmentation")); this->SetToolSelectionBoxesEnabled( false ); return; } auto refNode = m_Controls->patImageSelector->GetSelectedNode(); auto segNode = nodes.front(); if (!refNode) { this->UpdateWarningLabel(tr("Please select the matching patient image!")); this->SetToolSelectionBoxesEnabled(false); this->SetToolManagerSelection(nullptr, segNode); return; } this->CheckRenderingState(); if ( m_Controls->lblSegmentationWarnings->isVisible()) // "this->CheckRenderingState()" caused a warning. we do not need to go any further return; this->SetToolManagerSelection(refNode, segNode); if (segNode) { //Doing this we can assure that the segmenation is always visible if the segmentation and the patient image are //loaded separately int layer(10); refNode->GetIntProperty("layer", layer); layer++; segNode->SetProperty("layer", mitk::IntProperty::New(layer)); } else { this->SetToolSelectionBoxesEnabled(false); this->UpdateWarningLabel(tr("Select or create a segmentation")); } mitk::IRenderWindowPart* renderWindowPart = this->GetRenderWindowPart(); if (!renderWindowPart || !segNode->IsVisible(renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer())) { this->UpdateWarningLabel(tr("The selected segmentation is currently not visible!")); this->SetToolSelectionBoxesEnabled( false ); } } void QmitkSegmentationView::OnShowMarkerNodes (bool state) { mitk::SegTool2D::Pointer manualSegmentationTool; unsigned int numberOfExistingTools = mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetTools().size(); for(unsigned int i = 0; i < numberOfExistingTools; i++) { manualSegmentationTool = dynamic_cast(mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetToolById(i)); if (manualSegmentationTool) { if(state == true) { manualSegmentationTool->SetShowMarkerNodes( true ); } else { manualSegmentationTool->SetShowMarkerNodes( false ); } } } } void QmitkSegmentationView::OnContourMarkerSelected(const mitk::DataNode *node) { QmitkRenderWindow* selectedRenderWindow = nullptr; QmitkRenderWindow* axialRenderWindow = GetRenderWindowPart(mitk::WorkbenchUtil::OPEN)->GetQmitkRenderWindow("axial"); QmitkRenderWindow* sagittalRenderWindow = GetRenderWindowPart(mitk::WorkbenchUtil::OPEN)->GetQmitkRenderWindow("sagittal"); QmitkRenderWindow* coronalRenderWindow = GetRenderWindowPart(mitk::WorkbenchUtil::OPEN)->GetQmitkRenderWindow("coronal"); QmitkRenderWindow* _3DRenderWindow = GetRenderWindowPart(mitk::WorkbenchUtil::OPEN)->GetQmitkRenderWindow("3d"); bool PlanarFigureInitializedWindow = false; // find initialized renderwindow if (node->GetBoolProperty("PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, axialRenderWindow->GetRenderer())) { selectedRenderWindow = axialRenderWindow; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, sagittalRenderWindow->GetRenderer())) { selectedRenderWindow = sagittalRenderWindow; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, coronalRenderWindow->GetRenderer())) { selectedRenderWindow = coronalRenderWindow; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, _3DRenderWindow->GetRenderer())) { selectedRenderWindow = _3DRenderWindow; } // make node visible if (selectedRenderWindow) { std::string nodeName = node->GetName(); unsigned int t = nodeName.find_last_of(" "); unsigned int id = atof(nodeName.substr(t+1).c_str())-1; { ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); selectedRenderWindow->GetSliceNavigationController()->ExecuteOperation(service->GetPlanePosition(id)); context->ungetService(ppmRef); } selectedRenderWindow->GetRenderer()->GetCameraController()->Fit(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkSegmentationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList &nodes) { if (nodes.size() != 0) { std::string markerName = "Position"; unsigned int numberOfNodes = nodes.size(); std::string nodeName = nodes.at(0)->GetName(); if ((numberOfNodes == 1) && (nodeName.find(markerName) == 0)) { this->OnContourMarkerSelected(nodes.at(0)); return; } } } void QmitkSegmentationView::OnTabWidgetChanged(int id) { //always disable tools on tab changed mitk::ToolManagerProvider::GetInstance()->GetToolManager()->ActivateTool(-1); //2D Tab ID = 0 //3D Tab ID = 1 if (id == 0) { //Hide 3D selection box, show 2D selection box m_Controls->m_ManualToolSelectionBox3D->hide(); m_Controls->m_ManualToolSelectionBox2D->show(); //Deactivate possible active tool //TODO Remove possible visible interpolations -> Maybe changes in SlicesInterpolator } else { //Hide 3D selection box, show 2D selection box m_Controls->m_ManualToolSelectionBox2D->hide(); m_Controls->m_ManualToolSelectionBox3D->show(); //Deactivate possible active tool } } void QmitkSegmentationView::SetToolManagerSelection(mitk::DataNode* referenceData, mitk::DataNode* workingData) { // called as a result of new BlueBerry selections // tells the ToolManager for manual segmentation about new selections // updates GUI information about what the user should select mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); toolManager->SetReferenceData(const_cast(referenceData)); toolManager->SetWorkingData(const_cast(workingData)); m_Controls->btnNewSegmentation->setEnabled(referenceData != nullptr); } void QmitkSegmentationView::ForceDisplayPreferencesUponAllImages() { if (!m_Parent) { return; } // check all images and segmentations in DataStorage: // (items in brackets are implicitly done by previous steps) // 1. // if a reference image is selected, // show the reference image // and hide all other images (orignal and segmentation), // (and hide all segmentations of the other original images) // and show all the reference's segmentations // if no reference image is selected, do do nothing // // 2. // if a segmentation is selected, // show it // (and hide all all its siblings (childs of the same parent, incl, nullptr parent)) // if no segmentation is selected, do nothing if (!m_Controls) { return; // might happen on initialization (preferences loaded) } mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); mitk::DataNode::Pointer referenceData = toolManager->GetReferenceData(0); mitk::DataNode::Pointer workingData = toolManager->GetWorkingData(0); // 1. if (referenceData.IsNotNull()) { // iterate all images mitk::DataStorage::SetOfObjects::ConstPointer allImages = this->GetDataStorage()->GetSubset(m_IsASegmentationImagePredicate); for ( mitk::DataStorage::SetOfObjects::const_iterator iter = allImages->begin(); iter != allImages->end(); ++iter) { mitk::DataNode* node = *iter; // apply display preferences ApplyDisplayOptions(node); // set visibility node->SetVisibility(node == referenceData); } } // 2. if (workingData.IsNotNull()) workingData->SetVisibility(true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSegmentationView::ApplyDisplayOptions(mitk::DataNode* node) { if (!node) { return; } mitk::BoolProperty::Pointer drawOutline = mitk::BoolProperty::New(GetPreferences()->GetBool("draw outline", true)); mitk::BoolProperty::Pointer volumeRendering = mitk::BoolProperty::New(GetPreferences()->GetBool("volume rendering", false)); mitk::LabelSetImage* labelSetImage = dynamic_cast(node->GetData()); if (nullptr != labelSetImage) { // node is actually a multi label segmentation, // but its outline property can be set in the 'single label' segmentation preference page as well node->SetProperty("labelset.contour.active", drawOutline); //node->SetProperty("opacity", mitk::FloatProperty::New(drawOutline->GetValue() ? 1.0f : 0.3f)); node->SetProperty("volumerendering", volumeRendering); // force render window update to show outline node->GetData()->Modified(); } else { // node is a 'single label' segmentation bool isBinary = false; node->GetBoolProperty("binary", isBinary); if (isBinary) { node->SetProperty("outline binary", drawOutline); node->SetProperty("outline width", mitk::FloatProperty::New(2.0)); //node->SetProperty("opacity", mitk::FloatProperty::New(drawOutline->GetValue() ? 1.0f : 0.3f)); node->SetProperty("volumerendering", volumeRendering); // force render window update to show outline node->GetData()->Modified(); } } } void QmitkSegmentationView::CheckRenderingState() { mitk::IRenderWindowPart* renderWindowPart = this->GetRenderWindowPart(); mitk::DataNode* workingNode = m_Controls->segImageSelector->GetSelectedNode(); if (!workingNode) { this->SetToolSelectionBoxesEnabled(false); this->UpdateWarningLabel(tr("Select or create a segmentation")); return; } bool selectedNodeIsVisible = renderWindowPart && workingNode->IsVisible(renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer()); if (!selectedNodeIsVisible) { this->SetToolSelectionBoxesEnabled(false); this->UpdateWarningLabel(tr("The selected segmentation is currently not visible!")); return; } /* * Here we check whether the geometry of the selected segmentation image if aligned with the worldgeometry * At the moment it is not supported to use a geometry different from the selected image for reslicing. * For further information see Bug 16063 */ const mitk::BaseGeometry* worldGeo = this->GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetSliceNavigationController()->GetCurrentGeometry3D(); if (workingNode && worldGeo) { const mitk::BaseGeometry* workingNodeGeo = workingNode->GetData()->GetGeometry(); const mitk::BaseGeometry* worldGeo = this->GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetSliceNavigationController()->GetCurrentGeometry3D(); if (mitk::Equal(*workingNodeGeo->GetBoundingBox(), *worldGeo->GetBoundingBox(), mitk::eps, true)) { this->SetToolManagerSelection(m_Controls->patImageSelector->GetSelectedNode(), workingNode); this->SetToolSelectionBoxesEnabled(true); this->UpdateWarningLabel(""); return; } } this->SetToolManagerSelection(m_Controls->patImageSelector->GetSelectedNode(), nullptr); this->SetToolSelectionBoxesEnabled(false); this->UpdateWarningLabel(tr("Please perform a reinit on the segmentation image!")); } bool QmitkSegmentationView::CheckForSameGeometry(const mitk::DataNode *node1, const mitk::DataNode *node2) { bool isSameGeometry(true); mitk::Image* image1 = dynamic_cast(node1->GetData()); mitk::Image* image2 = dynamic_cast(node2->GetData()); if (image1 && image2) { mitk::BaseGeometry* geo1 = image1->GetGeometry(); mitk::BaseGeometry* geo2 = image2->GetGeometry(); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetOrigin(), geo2->GetOrigin()); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetExtent(0), geo2->GetExtent(0)); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetExtent(1), geo2->GetExtent(1)); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetExtent(2), geo2->GetExtent(2)); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetSpacing(), geo2->GetSpacing()); isSameGeometry = isSameGeometry && mitk::MatrixEqualElementWise(geo1->GetIndexToWorldTransform()->GetMatrix(), geo2->GetIndexToWorldTransform()->GetMatrix()); return isSameGeometry; } else { return false; } } void QmitkSegmentationView::UpdateWarningLabel(QString text) { if (text.size() == 0) m_Controls->lblSegmentationWarnings->hide(); else m_Controls->lblSegmentationWarnings->show(); m_Controls->lblSegmentationWarnings->setText("" + text + ""); } void QmitkSegmentationView::CreateQtPartControl(QWidget* parent) { // setup the basic GUI of this view m_Parent = parent; m_Controls = new Ui::QmitkSegmentationControls; m_Controls->setupUi(parent); m_Controls->patImageSelector->SetDataStorage(GetDataStorage()); m_Controls->patImageSelector->SetNodePredicate(m_IsAPatientImagePredicate); m_Controls->patImageSelector->SetSelectionIsOptional(false); m_Controls->patImageSelector->SetInvalidInfo("Select an image."); m_Controls->patImageSelector->SetPopUpTitel("Select an image."); m_Controls->patImageSelector->SetPopUpHint("Select an image that should be used to define the geometry and bounds of the segmentation."); UpdateWarningLabel(tr("Please select an image")); if (m_Controls->patImageSelector->GetSelectedNode().IsNotNull()) { UpdateWarningLabel(tr("Select or create a new segmentation")); } m_Controls->segImageSelector->SetDataStorage(GetDataStorage()); m_Controls->segImageSelector->SetNodePredicate(m_IsASegmentationImagePredicate); m_Controls->segImageSelector->SetSelectionIsOptional(false); m_Controls->segImageSelector->SetInvalidInfo("Select a segmentation."); m_Controls->segImageSelector->SetPopUpTitel("Select a segmentation."); m_Controls->segImageSelector->SetPopUpHint("Select a segmentation that should be modified. Only segmentation with the same geometry and within the bounds of the reference image are selected."); if (m_Controls->segImageSelector->GetSelectedNode().IsNotNull()) { UpdateWarningLabel(""); } mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); assert(toolManager); toolManager->SetDataStorage(*(GetDataStorage())); toolManager->InitializeTools(); QString segTools2D = tr("Add Subtract Correction Paint Wipe 'Region Growing' Fill Erase 'Live Wire' '2D Fast Marching'"); QString segTools3D = tr("Threshold 'UL Threshold' Otsu 'Fast Marching 3D' 'Region Growing 3D' Watershed Picking"); std::regex extSegTool2DRegEx("SegTool2D$"); std::regex extSegTool3DRegEx("SegTool3D$"); auto tools = toolManager->GetTools(); for (const auto &tool : tools) { if (std::regex_search(tool->GetNameOfClass(), extSegTool2DRegEx)) { segTools2D.append(QString(" '%1'").arg(tool->GetName())); } else if (std::regex_search(tool->GetNameOfClass(), extSegTool3DRegEx)) { segTools3D.append(QString(" '%1'").arg(tool->GetName())); } } // all part of open source MITK m_Controls->m_ManualToolSelectionBox2D->setEnabled(true); m_Controls->m_ManualToolSelectionBox2D->SetGenerateAccelerators(true); - m_Controls->m_ManualToolSelectionBox2D->SetToolGUIArea( m_Controls->m_ManualToolGUIContainer2D ); + m_Controls->m_ManualToolSelectionBox2D->SetToolGUIArea(m_Controls->m_ManualToolGUIContainer2D); m_Controls->m_ManualToolSelectionBox2D->SetDisplayedToolGroups(segTools2D.toStdString()); m_Controls->m_ManualToolSelectionBox2D->SetLayoutColumns(3); - m_Controls->m_ManualToolSelectionBox2D->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible ); - connect( m_Controls->m_ManualToolSelectionBox2D, SIGNAL(ToolSelected(int)), this, SLOT(OnManualTool2DSelected(int)) ); + m_Controls->m_ManualToolSelectionBox2D->SetEnabledMode(QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); + connect(m_Controls->m_ManualToolSelectionBox2D, &QmitkToolSelectionBox::ToolSelected, this, &QmitkSegmentationView::OnManualTool2DSelected); //setup 3D Tools m_Controls->m_ManualToolSelectionBox3D->setEnabled(true); m_Controls->m_ManualToolSelectionBox3D->SetGenerateAccelerators(true); - m_Controls->m_ManualToolSelectionBox3D->SetToolGUIArea( m_Controls->m_ManualToolGUIContainer3D ); + m_Controls->m_ManualToolSelectionBox3D->SetToolGUIArea(m_Controls->m_ManualToolGUIContainer3D); //specify tools to be added to 3D Tool area m_Controls->m_ManualToolSelectionBox3D->SetDisplayedToolGroups(segTools3D.toStdString()); m_Controls->m_ManualToolSelectionBox3D->SetLayoutColumns(3); - m_Controls->m_ManualToolSelectionBox3D->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible ); + m_Controls->m_ManualToolSelectionBox3D->SetEnabledMode(QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); //Hide 3D selection box, show 2D selection box m_Controls->m_ManualToolSelectionBox3D->hide(); m_Controls->m_ManualToolSelectionBox2D->show(); // update the list of segmentations toolManager->NewNodeObjectsGenerated += mitk::MessageDelegate1(this, &QmitkSegmentationView::NewNodeObjectsGenerated); // create signal/slot connections - connect(m_Controls->patImageSelector, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(OnPatientSelectionChanged(QList))); - connect(m_Controls->segImageSelector, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(OnSegmentationSelectionChanged(QList))); + connect(m_Controls->patImageSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkSegmentationView::OnPatientSelectionChanged); + connect(m_Controls->segImageSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkSegmentationView::OnSegmentationSelectionChanged); - connect(m_Controls->btnNewSegmentation, SIGNAL(clicked()), this, SLOT(CreateNewSegmentation())); - connect(m_Controls->tabWidgetSegmentationTools, SIGNAL(currentChanged(int)), this, SLOT(OnTabWidgetChanged(int))); - connect(m_Controls->m_SlicesInterpolator, SIGNAL(SignalShowMarkerNodes(bool)), this, SLOT(OnShowMarkerNodes(bool))); + connect(m_Controls->btnNewSegmentation, &QToolButton::clicked, this, &QmitkSegmentationView::CreateNewSegmentation); + connect(m_Controls->tabWidgetSegmentationTools, &QTabWidget::currentChanged, this, &QmitkSegmentationView::OnTabWidgetChanged); + connect(m_Controls->m_SlicesInterpolator, &QmitkSlicesInterpolator::SignalShowMarkerNodes, this, &QmitkSegmentationView::OnShowMarkerNodes); // set callback function for already existing nodes (images & segmentations) mitk::DataStorage::SetOfObjects::ConstPointer allImages = GetDataStorage()->GetSubset(m_IsOfTypeImagePredicate); for (mitk::DataStorage::SetOfObjects::const_iterator iter = allImages->begin(); iter != allImages->end(); ++iter) { mitk::DataNode* node = *iter; itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::OnVisiblePropertyChanged); m_WorkingDataObserverTags.insert(std::pair(node, node->GetProperty("visible")->AddObserver(itk::ModifiedEvent(), command))); } itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::CheckRenderingState); m_RenderingManagerObserverTag = mitk::RenderingManager::GetInstance()->AddObserver(mitk::RenderingManagerViewsInitializedEvent(), command); SetToolManagerSelection(m_Controls->patImageSelector->GetSelectedNode(), m_Controls->segImageSelector->GetSelectedNode()); m_RenderWindowPart = GetRenderWindowPart(); if (m_RenderWindowPart) { RenderWindowPartActivated(m_RenderWindowPart); } //Should be done last, if everything else is configured because it triggers the autoselection of data. m_Controls->patImageSelector->SetAutoSelectNewNodes(true); m_Controls->segImageSelector->SetAutoSelectNewNodes(true); } void QmitkSegmentationView::SetFocus() { m_Controls->btnNewSegmentation->setFocus(); } void QmitkSegmentationView::OnManualTool2DSelected(int id) { if (id >= 0) { std::string text = "Active Tool: \""; mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); text += toolManager->GetToolById(id)->GetName(); text += "\""; mitk::StatusBar::GetInstance()->DisplayText(text.c_str()); us::ModuleResource resource = toolManager->GetToolById(id)->GetCursorIconResource(); this->SetMouseCursor(resource, 0, 0); } else { this->ResetMouseCursor(); mitk::StatusBar::GetInstance()->DisplayText(""); } } void QmitkSegmentationView::ResetMouseCursor() { if ( m_MouseCursorSet ) { mitk::ApplicationCursor::GetInstance()->PopCursor(); m_MouseCursorSet = false; } } void QmitkSegmentationView::SetMouseCursor( const us::ModuleResource& resource, int hotspotX, int hotspotY ) { // Remove previously set mouse cursor if (m_MouseCursorSet) this->ResetMouseCursor(); if (resource) { us::ModuleResourceStream cursor(resource, std::ios::binary); mitk::ApplicationCursor::GetInstance()->PushCursor(cursor, hotspotX, hotspotY); m_MouseCursorSet = true; } } void QmitkSegmentationView::SetToolSelectionBoxesEnabled(bool status) { if (status) { m_Controls->m_ManualToolSelectionBox2D->RecreateButtons(); m_Controls->m_ManualToolSelectionBox3D->RecreateButtons(); } m_Controls->m_ManualToolSelectionBox2D->setEnabled(status); m_Controls->m_ManualToolSelectionBox3D->setEnabled(status); m_Controls->m_SlicesInterpolator->setEnabled(status); } diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h index b1e7ee3a0f..0fb6d60c43 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h @@ -1,143 +1,135 @@ /*============================================================================ 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 QMITKSEGMENTATIONVIEW_H #define QMITKSEGMENTATIONVIEW_H #include #include #include #include #include "ui_QmitkSegmentationControls.h" class QmitkRenderWindow; /** -* \ingroup ToolManagerEtAl -* \ingroup org_mitk_gui_qt_segmentation_internal -* \warning Implementation of this class is split up into two .cpp files to make things more compact. Check both this file and QmitkSegmentationOrganNamesHandling.cpp +* @brief +* +* */ -class QmitkSegmentationView : public QmitkAbstractView, public mitk::ILifecycleAwarePart, public mitk::IRenderWindowPartListener +class QmitkSegmentationView : public QmitkAbstractView, public mitk::IRenderWindowPartListener { Q_OBJECT public: QmitkSegmentationView(); ~QmitkSegmentationView() override; typedef std::map NodeTagMapType; void NewNodeObjectsGenerated(mitk::ToolManager::DataVectorType*); - void Activated() override; - void Deactivated() override; - void Visible() override; - void Hidden() override; - - /// - /// Sets the focus to an internal widget. - /// void SetFocus() override; void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) override; void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) override; // BlueBerry's notification about preference changes (e.g. from a dialog) void OnPreferencesChanged(const berry::IBerryPreferences* prefs) override; // observer to mitk::RenderingManager's RenderingManagerViewsInitializedEvent event void CheckRenderingState(); static const std::string VIEW_ID; protected slots: void OnPatientSelectionChanged(QList nodes); void OnSegmentationSelectionChanged(QList nodes); // reaction to the button "New segmentation" void CreateNewSegmentation(); void OnManualTool2DSelected(int id); void OnVisiblePropertyChanged(); void OnShowMarkerNodes(bool); void OnTabWidgetChanged(int); protected: // a type for handling lists of DataNodes typedef std::vector NodeList; // GUI setup void CreateQtPartControl(QWidget* parent) override; // propagate BlueBerry selection to ToolManager for manual segmentation void SetToolManagerSelection(mitk::DataNode* referenceData, mitk::DataNode* workingData); // make sure all images/segmentations look as selected by the users in this view's preferences void ForceDisplayPreferencesUponAllImages(); // decorates a DataNode according to the user preference settings void ApplyDisplayOptions(mitk::DataNode* node); void ResetMouseCursor(); void SetMouseCursor(const us::ModuleResource&, int hotspotX, int hotspotY); void SetToolSelectionBoxesEnabled(bool); // If a contourmarker is selected, the plane in the related widget will be reoriented according to the marker`s geometry void OnContourMarkerSelected(const mitk::DataNode* node); void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList &nodes) override; void NodeRemoved(const mitk::DataNode* node) override; void NodeAdded(const mitk::DataNode *node) override; static bool CheckForSameGeometry(const mitk::DataNode*, const mitk::DataNode*); void UpdateWarningLabel(QString text/*, bool overwriteExistingText = true*/); // the Qt parent of our GUI (NOT of this object) QWidget* m_Parent; // our GUI Ui::QmitkSegmentationControls* m_Controls; mitk::IRenderWindowPart* m_RenderWindowPart; unsigned long m_VisibilityChangedObserverTag; bool m_MouseCursorSet; bool m_DataSelectionChanged; NodeTagMapType m_WorkingDataObserverTags; unsigned int m_RenderingManagerObserverTag; mitk::NodePredicateNot::Pointer m_IsNotAHelperObject; mitk::NodePredicateAnd::Pointer m_IsOfTypeImagePredicate; mitk::NodePredicateOr::Pointer m_IsASegmentationImagePredicate; mitk::NodePredicateAnd::Pointer m_IsAPatientImagePredicate; }; #endif // QMITKSEGMENTATIONVIEW_H