diff --git a/CMake/RunInstalledApp.sh b/CMake/RunInstalledApp.sh index db2bf6ed7f..655303864f 100644 --- a/CMake/RunInstalledApp.sh +++ b/CMake/RunInstalledApp.sh @@ -1,7 +1,7 @@ #!/bin/sh binpath=$(dirname "$(readlink -f "$0")") appname=$(basename "$0" .sh) -export LD_LIBRARY_PATH="$binpath/bin":"$binpath/bin/plugins":$LD_LIBRARY_PATH +export LD_LIBRARY_PATH="$binpath/bin":"$binpath/bin/plugins":"$LD_LIBRARY_PATH" export QT_PLUGIN_PATH="$binpath/bin":"$binpath/bin/plugins" export QT_QPA_PLATFORM=xcb "$binpath/bin/$appname" "$@" diff --git a/CMake/RunInstalledCmdLineApp.bat b/CMake/RunInstalledCmdLineApp.bat new file mode 100644 index 0000000000..9090f4aa90 --- /dev/null +++ b/CMake/RunInstalledCmdLineApp.bat @@ -0,0 +1 @@ +"%~dp0..\bin\%~n0.exe" %* diff --git a/CMake/RunInstalledApp.sh b/CMake/RunInstalledCmdLineApp.sh similarity index 53% copy from CMake/RunInstalledApp.sh copy to CMake/RunInstalledCmdLineApp.sh index db2bf6ed7f..5eadd45fb7 100644 --- a/CMake/RunInstalledApp.sh +++ b/CMake/RunInstalledCmdLineApp.sh @@ -1,7 +1,7 @@ #!/bin/sh -binpath=$(dirname "$(readlink -f "$0")") +binpath=$(dirname "$(dirname "$(readlink -f "$0")")") appname=$(basename "$0" .sh) -export LD_LIBRARY_PATH="$binpath/bin":"$binpath/bin/plugins":$LD_LIBRARY_PATH +export LD_LIBRARY_PATH="$binpath/bin":"$binpath/bin/plugins":"$LD_LIBRARY_PATH" export QT_PLUGIN_PATH="$binpath/bin":"$binpath/bin/plugins" export QT_QPA_PLATFORM=xcb "$binpath/bin/$appname" "$@" diff --git a/CMake/mitkFunctionCreateBlueBerryApplication.cmake b/CMake/mitkFunctionCreateBlueBerryApplication.cmake index f56c9fc100..176b7db466 100644 --- a/CMake/mitkFunctionCreateBlueBerryApplication.cmake +++ b/CMake/mitkFunctionCreateBlueBerryApplication.cmake @@ -1,235 +1,231 @@ #! #! Create a BlueBerry application. #! #! \brief This function will create a BlueBerry application together with all #! necessary provisioning and configuration data and install support. #! #! \param NAME (required) The name of the executable. #! \param DESCRIPTION (optional) A human-readable description of your application. #! The usage depends on the CPack generator (on Windows, this is a descriptive #! text for the created shortcuts). #! \param SOURCES (optional) A list of source files to compile into your executable. Defaults #! to .cpp. #! \param PLUGINS (optional) A list of required plug-ins. Defaults to all known plug-ins. #! \param EXCLUDE_PLUGINS (optional) A list of plug-ins which should not be used. Mainly #! useful if PLUGINS was not used. #! \param LINK_LIBRARIES A list of libraries to be linked with the executable. #! \param LIBRARY_DIRS A list of directories to pass through to MITK_INSTALL_TARGETS #! \param NO_PROVISIONING (option) Do not create provisioning files. #! \param NO_INSTALL (option) Do not install this executable #! #! Assuming that there exists a file called MyApp.cpp, an example call looks like: #! \code #! mitkFunctionCreateBlueBerryApplication( #! NAME MyApp #! DESCRIPTION "MyApp - New ways to explore medical data" #! EXCLUDE_PLUGINS org.mitk.gui.qt.extapplication #! ) #! \endcode #! function(mitkFunctionCreateBlueBerryApplication) cmake_parse_arguments(_APP "NO_PROVISIONING;NO_INSTALL" "NAME;DESCRIPTION" "SOURCES;PLUGINS;EXCLUDE_PLUGINS;LINK_LIBRARIES;LIBRARY_DIRS" ${ARGN}) if(NOT _APP_NAME) message(FATAL_ERROR "NAME argument cannot be empty.") endif() if(NOT _APP_SOURCES) set(_APP_SOURCES ${_APP_NAME}.cpp) endif() if(NOT _APP_PLUGINS) ctkFunctionGetAllPluginTargets(_APP_PLUGINS) else() set(_plugins ${_APP_PLUGINS}) set(_APP_PLUGINS) foreach(_plugin ${_plugins}) string(REPLACE "." "_" _plugin_target ${_plugin}) list(APPEND _APP_PLUGINS ${_plugin_target}) endforeach() # get all plug-in dependencies ctkFunctionGetPluginDependencies(_plugin_deps PLUGINS ${_APP_PLUGINS} ALL) # add the dependencies to the list of application plug-ins list(APPEND _APP_PLUGINS ${_plugin_deps}) endif() # ----------------------------------------------------------------------- # Set up include and link dirs for the executable # ----------------------------------------------------------------------- include_directories( ${org_blueberry_core_runtime_INCLUDE_DIRS} ) # ----------------------------------------------------------------------- # Add executable icon (Windows) # ----------------------------------------------------------------------- set(WINDOWS_ICON_RESOURCE_FILE "") if(WIN32) if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/icons/${_APP_NAME}.rc") set(WINDOWS_ICON_RESOURCE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/icons/${_APP_NAME}.rc") endif() endif() # ----------------------------------------------------------------------- # Create the executable and link libraries # ----------------------------------------------------------------------- set(_app_compile_flags ) if(WIN32) set(_app_compile_flags "${_app_compile_flags} -DWIN32_LEAN_AND_MEAN") endif() if(MITK_SHOW_CONSOLE_WINDOW) add_executable(${_APP_NAME} MACOSX_BUNDLE ${_APP_SOURCES} ${WINDOWS_ICON_RESOURCE_FILE}) else() add_executable(${_APP_NAME} MACOSX_BUNDLE WIN32 ${_APP_SOURCES} ${WINDOWS_ICON_RESOURCE_FILE}) endif() if(NOT CMAKE_CURRENT_SOURCE_DIR MATCHES "^${CMAKE_SOURCE_DIR}/.*") foreach(MITK_EXTENSION_DIR ${MITK_ABSOLUTE_EXTENSION_DIRS}) if("${CMAKE_CURRENT_SOURCE_DIR}/" MATCHES "^${MITK_EXTENSION_DIR}/.*") get_filename_component(MITK_EXTENSION_ROOT_FOLDER "${MITK_EXTENSION_DIR}" NAME) set_property(TARGET ${_APP_NAME} PROPERTY FOLDER "${MITK_EXTENSION_ROOT_FOLDER}/Applications") break() endif() endforeach() else() set_property(TARGET ${_APP_NAME} PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Applications") endif() mitk_use_modules(TARGET ${_APP_NAME} MODULES MitkAppUtil) set_target_properties(${_APP_NAME} PROPERTIES COMPILE_FLAGS "${_app_compile_flags}") target_link_libraries(${_APP_NAME} PRIVATE org_blueberry_core_runtime ${_APP_LINK_LIBRARIES}) if(WIN32) target_link_libraries(${_APP_NAME} PRIVATE ${QT_QTMAIN_LIBRARY}) endif() if(WIN32) mitk_add_manifest(${_APP_NAME}) endif() # ----------------------------------------------------------------------- # Add executable icon and bundle name (Mac) # ----------------------------------------------------------------------- if(APPLE) if( _APP_DESCRIPTION) set_target_properties(${_APP_NAME} PROPERTIES MACOSX_BUNDLE_NAME "${_APP_DESCRIPTION}") else() set_target_properties(${_APP_NAME} PROPERTIES MACOSX_BUNDLE_NAME "${_APP_NAME}") endif() set(icon_name "icon.icns") set(icon_full_path "${CMAKE_CURRENT_SOURCE_DIR}/icons/${icon_name}") if(EXISTS "${icon_full_path}") set_target_properties(${_APP_NAME} PROPERTIES MACOSX_BUNDLE_ICON_FILE "${icon_name}") file(COPY ${icon_full_path} DESTINATION "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${_APP_NAME}.app/Contents/Resources/") INSTALL (FILES ${icon_full_path} DESTINATION "${_APP_NAME}.app/Contents/Resources/") endif() endif() # ----------------------------------------------------------------------- # Set build time dependencies # ----------------------------------------------------------------------- # This ensures that all enabled plug-ins are up-to-date when the # executable is build. if(_APP_PLUGINS) ctkMacroGetAllProjectTargetLibraries("${_APP_PLUGINS}" _project_plugins) if(_APP_EXCLUDE_PLUGINS AND _project_plugins) set(_exclude_targets) foreach(_exclude_plugin ${_APP_EXCLUDE_PLUGINS}) string(REPLACE "." "_" _exclude_target ${_exclude_plugin}) list(APPEND _exclude_targets ${_exclude_target}) endforeach() list(REMOVE_ITEM _project_plugins ${_exclude_targets}) endif() if(_project_plugins) add_dependencies(${_APP_NAME} ${_project_plugins}) endif() endif() # ----------------------------------------------------------------------- # Additional files needed for the executable # ----------------------------------------------------------------------- if(NOT _APP_NO_PROVISIONING) # Create a provisioning file, listing all plug-ins set(_prov_file "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${_APP_NAME}.provisioning") mitkFunctionCreateProvisioningFile(FILE ${_prov_file} PLUGINS ${_APP_PLUGINS} EXCLUDE_PLUGINS ${_APP_EXCLUDE_PLUGINS} ) endif() # Create a .ini file for initial parameters if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${_APP_NAME}.ini") configure_file(${_APP_NAME}.ini ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${_APP_NAME}.ini) endif() # Create batch and VS user files for Windows platforms include(mitkFunctionCreateWindowsBatchScript) if(WIN32) set(template_name "start${_APP_NAME}.bat.in") if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${template_name}") foreach(BUILD_TYPE debug release) mitkFunctionCreateWindowsBatchScript(${template_name} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/start${_APP_NAME}_${BUILD_TYPE}.bat ${BUILD_TYPE}) endforeach() endif() mitkFunctionConfigureVisualStudioUserProjectFile( NAME ${_APP_NAME} ) endif(WIN32) # ----------------------------------------------------------------------- # Install support # ----------------------------------------------------------------------- if(NOT _APP_NO_INSTALL) # This installs all third-party CTK plug-ins mitkFunctionInstallThirdPartyCTKPlugins(${_APP_PLUGINS} EXCLUDE ${_APP_EXCLUDE_PLUGINS}) if(COMMAND BlueBerryApplicationInstallHook) set(_real_app_plugins ${_APP_PLUGINS}) if(_APP_EXCLUDE_PLUGINS) list(REMOVE_ITEM _real_app_plugins ${_APP_EXCLUDE_PLUGINS}) endif() BlueBerryApplicationInstallHook(APP_NAME ${_APP_NAME} PLUGINS ${_real_app_plugins}) endif() # Install the executable MITK_INSTALL_TARGETS(EXECUTABLES ${_APP_NAME} LIBRARY_DIRS ${_APP_LIBRARY_DIRS} GLOB_PLUGINS ) if(NOT _APP_NO_PROVISIONING) # Install the provisioning file mitkFunctionInstallProvisioningFiles(${_prov_file}) endif() # 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 "${_APP_NAME}.sh") elseif(WIN32) install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledWin32App.bat" DESTINATION "." RENAME "${_APP_NAME}.bat") endif() # Tell cpack the executables that you want in the start menu as links set(MITK_CPACK_PACKAGE_EXECUTABLES ${MITK_CPACK_PACKAGE_EXECUTABLES} "${_APP_NAME};${_APP_DESCRIPTION}" CACHE INTERNAL "Collecting windows shortcuts to executables") endif() endfunction() - -function(FunctionCreateBlueBerryApplication) - message(SEND_ERROR "The function FunctionCreateBlueBerryApplication was renamed to mitkFunctionCreateBlueBerryApplication in MITK 2015.05") -endfunction() diff --git a/CMake/mitkFunctionCreateCommandLineApp.cmake b/CMake/mitkFunctionCreateCommandLineApp.cmake index 949e57e848..ac4840e18a 100644 --- a/CMake/mitkFunctionCreateCommandLineApp.cmake +++ b/CMake/mitkFunctionCreateCommandLineApp.cmake @@ -1,58 +1,59 @@ #! #! 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 TARGET_DEPENDS (optional) list of additional CMake targets this command line app depends on #! \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.) TARGET_DEPENDS # list of additional CMake targets this command line app depends on 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} TARGET_DEPENDS ${TARGET_DEPENDS} CPP_FILES ${CMDAPP_CPP_FILES} ${_CMDAPP_OPTIONS} ) + set_target_properties(${EXECUTABLE_TARGET} PROPERTIES COMMAND_LINE_APP TRUE) endfunction() diff --git a/CMake/mitkFunctionCreatePlugin.cmake b/CMake/mitkFunctionCreatePlugin.cmake index 8044c5b978..4a871ce61e 100644 --- a/CMake/mitkFunctionCreatePlugin.cmake +++ b/CMake/mitkFunctionCreatePlugin.cmake @@ -1,342 +1,338 @@ #! \brief Creates a MITK CTK plugin. #! #! This function should be called from the plugins CMakeLists.txt file. #! The target name is available after the macro call as ${PLUGIN_TARGET} #! to add additional libraries in your CMakeLists.txt. Include paths and link #! libraries are set depending on the value of the Required-Plugins header #! in your manifest_headers.cmake file. #! #! This function internally calls ctkMacroBuildPlugin() and adds support #! for Qt Help files and installers. #! #! Options: #! \param TEST_PLUGIN Mark this plug-in as a testing plug-in. #! \param NO_INSTALL Don't install this plug-in. #! #! Parameters: #! #! \param EXPORT_DIRECTIVE (required) The export directive to use in the generated #! _Exports.h file. #! #! Multi-value parameters (all optional): #! #! \param EXPORTED_INCLUDE_SUFFIXES A list of sub-directories which should #! be added to the current source directory. The resulting directories #! will be available in the set of include directories of depending plug-ins. #! \param MODULE_DEPENDS (optional) A list of Modules this plug-in depends on. #! \param PACKAGE_DEPENDS (optional) A list of external packages this plug-in depends on. #! \param TARGET_DEPENDS (optional) A list of CMake targets this plug-in depends on. #! \param DOXYGEN_TAGFILES (optional) Which external tag files should be available for the plugin documentation #! \param MOC_OPTIONS (optional) Additional options to pass to the Qt MOC compiler #! \param WARNINGS_NO_ERRORS (optional) Do not handle compiler warnings as errors function(mitk_create_plugin) # options set(arg_options TEST_PLUGIN # Mark this plug-in as a testing plug-in NO_INSTALL # Don't install this plug-in WARNINGS_NO_ERRORS ) # single value arguments set(arg_single EXPORT_DIRECTIVE # (required) TODO: could be generated via CMake as it is done for MITK modules already ) # multiple value arguments set(arg_multiple EXPORTED_INCLUDE_SUFFIXES # (optional) additional public include directories MODULE_DEPENDS # (optional) PACKAGE_DEPENDS TARGET_DEPENDS DOXYGEN_TAGFILES MOC_OPTIONS SUBPROJECTS # deprecated ) cmake_parse_arguments(_PLUGIN "${arg_options}" "${arg_single}" "${arg_multiple}" ${ARGN}) if(_PLUGIN_TEST_PLUGIN) set(_PLUGIN_NO_INSTALL 1) set(is_test_plugin "TEST_PLUGIN") else() set(is_test_plugin) endif() set(_PLUGIN_MOC_OPTIONS "-DBOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED ${_PLUGIN_MOC_OPTIONS}") set(PLUGIN_TARGET ${PROJECT_NAME}) mitk_check_module_dependencies(MODULES ${_PLUGIN_MODULE_DEPENDS} PACKAGES ${_PLUGIN_PACKAGE_DEPENDS} MISSING_DEPENDENCIES_VAR _missing_deps MODULE_DEPENDENCIES_VAR _module_deps PACKAGE_DEPENDENCIES_VAR _package_deps) if(_missing_deps) if(NOT MITK_BUILD_ALL_PLUGINS) message(SEND_ERROR "${PROJECT_NAME} is missing requirements and won't be built. Missing: ${_missing_deps}") else() message(STATUS "${PROJECT_NAME} is missing requirements and won't be built. Missing: ${_missing_deps}") endif() return() endif() foreach(_module_dep ${_PLUGIN_MODULE_DEPENDS}) if(TARGET ${_module_dep}) get_target_property(AUTLOAD_DEP ${_module_dep} MITK_AUTOLOAD_DIRECTORY) if (AUTLOAD_DEP) message(SEND_ERROR "Plugin \"${PROJECT_NAME}\" has an invalid dependency on autoload module \"${_module_dep}\". Check MITK_CREATE_PLUGIN usage for \"${PROJECT_NAME}\".") endif() endif() endforeach() # -------------- All dependencies are resolved ------------------ message(STATUS "Creating CTK plugin ${PROJECT_NAME}") include(files.cmake) set(_PLUGIN_CPP_FILES ${CPP_FILES}) set(_PLUGIN_MOC_H_FILES ${MOC_H_FILES}) set(_PLUGIN_UI_FILES ${UI_FILES}) set(_PLUGIN_CACHED_RESOURCE_FILES ${CACHED_RESOURCE_FILES}) set(_PLUGIN_TRANSLATION_FILES ${TRANSLATION_FILES}) set(_PLUGIN_QRC_FILES ${QRC_FILES}) set(_PLUGIN_H_FILES ${H_FILES}) set(_PLUGIN_TXX_FILES ${TXX_FILES}) set(_PLUGIN_DOX_FILES ${DOX_FILES}) set(_PLUGIN_CMAKE_FILES ${CMAKE_FILES} files.cmake) set(_PLUGIN_FILE_DEPENDENCIES ${FILE_DEPENDENCIES}) if(CTK_PLUGINS_OUTPUT_DIR) set(_output_dir "${CTK_PLUGINS_OUTPUT_DIR}") else() set(_output_dir "") endif() # Compute the plugin dependencies ctkFunctionGetTargetLibraries(_PLUGIN_target_libraries "") #------------------------------------------------------------# #------------------ Qt Help support -------------------------# set(PLUGIN_GENERATED_QCH_FILES ) if(BLUEBERRY_USE_QT_HELP AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/documentation/UserManual") set(PLUGIN_DOXYGEN_INPUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/documentation/UserManual") set(PLUGIN_DOXYGEN_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/documentation/UserManual") # Create a list of Doxygen tag files from the plug-in dependencies set(PLUGIN_DOXYGEN_TAGFILES) foreach(_dep_target ${_PLUGIN_target_libraries}) string(REPLACE _ . _dep ${_dep_target}) get_target_property(_is_imported ${_dep_target} IMPORTED) if(_is_imported) get_target_property(_import_loc_debug ${_dep_target} IMPORTED_LOCATION_DEBUG) get_target_property(_import_loc_release ${_dep_target} IMPORTED_LOCATION_RELEASE) # There is not necessarily a debug and release build if(_import_loc_release) set(_import_loc ${_import_loc_release}) else() set(_import_loc ${_import_loc_debug}) endif() get_filename_component(_target_filename "${_import_loc}" NAME) # on windows there might be a Debug or Release subdirectory string(REGEX REPLACE "/bin/plugins/(Debug/|Release/)?${_target_filename}" "/Plugins/${_dep}/documentation/UserManual" plugin_tag_dir "${_import_loc}" ) else() set(plugin_tag_dir "${CMAKE_BINARY_DIR}/Plugins/${_dep}/documentation/UserManual") endif() set(_tag_file "${plugin_tag_dir}/${_dep_target}.tag") if(EXISTS ${_tag_file}) set(PLUGIN_DOXYGEN_TAGFILES "${PLUGIN_DOXYGEN_TAGFILES} \"${_tag_file}=qthelp://${_dep}/bundle/\"") endif() endforeach() if(_PLUGIN_DOXYGEN_TAGFILES) set(PLUGIN_DOXYGEN_TAGFILES "${PLUGIN_DOXYGEN_TAGFILES} ${_PLUGIN_DOXYGEN_TAGFILES}") endif() #message("PLUGIN_DOXYGEN_TAGFILES: ${PLUGIN_DOXYGEN_TAGFILES}") _FUNCTION_CREATE_CTK_QT_COMPRESSED_HELP(PLUGIN_GENERATED_QCH_FILES) list(APPEND _PLUGIN_CACHED_RESOURCE_FILES ${PLUGIN_GENERATED_QCH_FILES}) endif() #------------------------------------------------------------# #------------------ Create Plug-in --------------------------# mitkFunctionOrganizeSources( SOURCE ${_PLUGIN_CPP_FILES} HEADER ${_PLUGIN_H_FILES} TXX ${_PLUGIN_TXX_FILES} DOC ${_PLUGIN_DOX_FILES} UI ${_PLUGIN_UI_FILES} QRC ${_PLUGIN_QRC_FILES} ${_PLUGIN_CACHED_RESOURCE_FILES} META ${_PLUGIN_META_FILES} MOC ${MY_MOC_CPP} GEN_UI ${MY_UI_CPP} GEN_QRC ${MY_QRC_SRCS} ) ctkMacroBuildPlugin( NAME ${PLUGIN_TARGET} EXPORT_DIRECTIVE ${_PLUGIN_EXPORT_DIRECTIVE} SRCS ${_PLUGIN_CPP_FILES} ${_PLUGIN_H_FILES} ${CORRESPONDING__H_FILES} ${GLOBBED__H_FILES} MOC_SRCS ${_PLUGIN_MOC_H_FILES} MOC_OPTIONS ${_PLUGIN_MOC_OPTIONS} UI_FORMS ${_PLUGIN_UI_FILES} EXPORTED_INCLUDE_SUFFIXES ${_PLUGIN_EXPORTED_INCLUDE_SUFFIXES} RESOURCES ${_PLUGIN_QRC_FILES} TARGET_LIBRARIES ${_PLUGIN_target_libraries} CACHED_RESOURCEFILES ${_PLUGIN_CACHED_RESOURCE_FILES} TRANSLATIONS ${_PLUGIN_TRANSLATION_FILES} OUTPUT_DIR ${_output_dir} NO_INSTALL # we install the plug-in ourselves ${is_test_plugin} ) mitk_use_modules(TARGET ${PLUGIN_TARGET} MODULES ${_PLUGIN_MODULE_DEPENDS} PACKAGES ${_PLUGIN_PACKAGE_DEPENDS} ) if(_PLUGIN_TARGET_DEPENDS) target_link_libraries(${PLUGIN_TARGET} ${_PLUGIN_TARGET_DEPENDS}) endif() set_property(TARGET ${PLUGIN_TARGET} APPEND PROPERTY COMPILE_DEFINITIONS US_MODULE_NAME=${PLUGIN_TARGET}) set_property(TARGET ${PLUGIN_TARGET} PROPERTY US_MODULE_NAME ${PLUGIN_TARGET}) if(NOT CMAKE_CURRENT_SOURCE_DIR MATCHES "^${CMAKE_SOURCE_DIR}/.*") foreach(MITK_EXTENSION_DIR ${MITK_ABSOLUTE_EXTENSION_DIRS}) if("${CMAKE_CURRENT_SOURCE_DIR}/" MATCHES "^${MITK_EXTENSION_DIR}/.*") get_filename_component(MITK_EXTENSION_ROOT_FOLDER "${MITK_EXTENSION_DIR}" NAME) set_property(TARGET ${PLUGIN_TARGET} PROPERTY FOLDER "${MITK_EXTENSION_ROOT_FOLDER}/Plugins") break() endif() endforeach() else() set_property(TARGET ${PLUGIN_TARGET} PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Plugins") endif() set(plugin_c_flags) set(plugin_cxx_flags) if(NOT _PLUGIN_WARNINGS_NO_ERRORS) if(MSVC_VERSION) mitkFunctionCheckCAndCXXCompilerFlags("/WX" plugin_c_flags plugin_cxx_flags) else() mitkFunctionCheckCAndCXXCompilerFlags(-Werror plugin_c_flags plugin_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=c++0x-static-nonintegral-init" plugin_c_flags plugin_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=static-member-init" plugin_c_flags plugin_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=unknown-warning" plugin_c_flags plugin_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=gnu" plugin_c_flags plugin_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=cast-function-type" plugin_c_flags plugin_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=inconsistent-missing-override" plugin_c_flags plugin_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=deprecated-declarations" plugin_c_flags plugin_cxx_flags) endif() endif() if(plugin_c_flags) string(REPLACE " " ";" plugin_c_flags "${plugin_c_flags}") target_compile_options(${PLUGIN_TARGET} PRIVATE ${plugin_c_flags}) endif() if(plugin_cxx_flags) string(REPLACE " " ";" plugin_cxx_flags "${plugin_cxx_flags}") target_compile_options(${PLUGIN_TARGET} PRIVATE ${plugin_cxx_flags}) endif() if(_PLUGIN_TEST_PLUGIN) find_package(CppUnit REQUIRED) target_include_directories(${PLUGIN_TARGET} PRIVATE ${CppUnit_INCLUDE_DIRS}) target_link_libraries(${PLUGIN_TARGET} PRIVATE ${CppUnit_LIBRARIES}) endif() if(TARGET MitkLog) target_link_libraries(${PLUGIN_TARGET} PRIVATE MitkLog) endif() set(_PLUGIN_META_FILES "${CMAKE_CURRENT_SOURCE_DIR}/manifest_headers.cmake") if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/plugin.xml") list(APPEND _PLUGIN_META_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin.xml") endif() set(PLUGIN_TARGET ${PLUGIN_TARGET} PARENT_SCOPE) #------------------------------------------------------------# #------------------ Installer support -----------------------# if(NOT _PLUGIN_NO_INSTALL) set(install_directories "") if(NOT MACOSX_BUNDLE_NAMES) set(install_directories bin/plugins) else(NOT MACOSX_BUNDLE_NAMES) foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) list(APPEND install_directories ${bundle_name}.app/Contents/MacOS/plugins) endforeach(bundle_name) endif(NOT MACOSX_BUNDLE_NAMES) foreach(install_subdir ${install_directories}) mitkFunctionInstallCTKPlugin(TARGETS ${PLUGIN_TARGET} DESTINATION ${install_subdir}) endforeach() set(_autoload_targets ) foreach(_dependency ${_module_deps}) get_target_property(_dep_autoloads ${_dependency} MITK_AUTOLOAD_TARGETS) if (_dep_autoloads) list(APPEND _autoload_targets ${_dep_autoloads}) endif() endforeach() # The MITK_AUTOLOAD_TARGETS property is used in the mitkFunctionInstallAutoLoadModules # macro which expects a list of plug-in targets. if (_autoload_targets) list(REMOVE_DUPLICATES _autoload_targets) set_target_properties(${PLUGIN_TARGET} PROPERTIES MITK_AUTOLOAD_TARGETS "${_autoload_targets}") endif() endif() endfunction() function(_FUNCTION_CREATE_CTK_QT_COMPRESSED_HELP qch_file) set(_manifest_path "${CMAKE_CURRENT_SOURCE_DIR}/manifest_headers.cmake") if(NOT EXISTS ${_manifest_path}) message(FATAL_ERROR "${_manifest_path} not found") endif() include(${_manifest_path}) string(REPLACE "_" "." Plugin-SymbolicName "${PLUGIN_TARGET}") configure_file(${MITK_SOURCE_DIR}/Documentation/doxygen_plugin_manual.conf.in ${PLUGIN_DOXYGEN_OUTPUT_DIR}/doxygen.conf ) set(_generated_qhp_file "${PLUGIN_DOXYGEN_OUTPUT_DIR}/html/index.qhp") set(${qch_file} "${CMAKE_CURRENT_BINARY_DIR}/resources/${PLUGIN_TARGET}.qch") file(GLOB _file_dependencies "${PLUGIN_DOXYGEN_INPUT_DIR}/*") add_custom_command(OUTPUT ${${qch_file}} # Generate a Qt help project (index.qhp) with doxygen COMMAND ${DOXYGEN_EXECUTABLE} ${PLUGIN_DOXYGEN_OUTPUT_DIR}/doxygen.conf # Generate the final Qt compressed help file (.qch) COMMAND ${QT_HELPGENERATOR_EXECUTABLE} ${_generated_qhp_file} -o ${${qch_file}} DEPENDS ${PLUGIN_DOXYGEN_OUTPUT_DIR}/doxygen.conf ${_file_dependencies} ) #set_source_files_properties(${qch_file} PROPERTIES GENERATED 1) set(${qch_file} ${${qch_file}} PARENT_SCOPE) endfunction() - -function(MACRO_CREATE_MITK_CTK_PLUGIN) - message(SEND_ERROR "The function MACRO_CREATE_MITK_CTK_PLUGIN was renamed to mitk_create_plugin in MITK 2015.05.") -endfunction() diff --git a/CMake/mitkInstallRules.cmake b/CMake/mitkInstallRules.cmake index f9a4271830..2aa56b530d 100644 --- a/CMake/mitkInstallRules.cmake +++ b/CMake/mitkInstallRules.cmake @@ -1,176 +1,184 @@ # 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}) get_target_property(_no_install ${_mitk_executable_target} NO_INSTALL) if(_no_install) continue() endif() MITK_INSTALL_TARGETS(EXECUTABLES ${_mitk_executable_target} GLOB_PLUGINS) + get_target_property(_command_line_app ${_mitk_executable_target} COMMAND_LINE_APP) + if(_command_line_app) + set(_source "RunInstalledCmdLineApp") + set(_destination "apps") + else() + set(_source "RunInstalledApp") + set(_destination ".") + endif() if(UNIX AND NOT APPLE) - install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME "${_mitk_executable_target}.sh") + install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/${_source}.sh" DESTINATION "${_destination}" RENAME "${_mitk_executable_target}.sh") elseif(WIN32) get_target_property(_win32_exec ${_mitk_executable_target} WIN32_EXECUTABLE) if(_win32_exec) - install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledWin32App.bat" DESTINATION "." RENAME "${_mitk_executable_target}.bat") + install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledWin32App.bat" DESTINATION "${_destination}" RENAME "${_mitk_executable_target}.bat") else() - install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.bat" DESTINATION "." RENAME "${_mitk_executable_target}.bat") + install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/${_source}.bat" DESTINATION "${_destination}" RENAME "${_mitk_executable_target}.bat") endif() 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_Qt6) get_filename_component(_qmake_path "${QT_QMAKE_EXECUTABLE}" 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() # make sure resources and translations exist and try system location as well if(EXISTS "${_qmake_path}/../resources") MITK_INSTALL(DIRECTORY "${_qmake_path}/../resources") elseif(EXISTS "/usr/share/qt6/resources") MITK_INSTALL(DIRECTORY "/usr/share/qt6/resources") else() message(WARNING "No webengine resources found!") endif() set(_install_DESTINATION "translations") if(EXISTS "${_qmake_path}/../translations/qtwebengine_locales") MITK_INSTALL(DIRECTORY "${_qmake_path}/../translations/qtwebengine_locales") elseif(EXISTS "/usr/share/qt6/translations/qtwebengine_locales") MITK_INSTALL(DIRECTORY "/usr/share/qt6/translations/qtwebengine_locales") else() message(WARNING "No webengine translations found!") endif() 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/mitkMacroCreateCTKPlugin.cmake b/CMake/mitkMacroCreateCTKPlugin.cmake deleted file mode 100644 index c9e80e7bba..0000000000 --- a/CMake/mitkMacroCreateCTKPlugin.cmake +++ /dev/null @@ -1,7 +0,0 @@ -macro(MACRO_CREATE_MITK_CTK_PLUGIN) - - message(WARNING "The MACRO_CREATE_MITK_CTK_PLUGIN macro is deprecated since 2015.05. Use mitk_create_plugin instead.") - - mitk_create_plugin(${ARGN}) - -endmacro() diff --git a/CMakeLists.txt b/CMakeLists.txt index 93ad529af3..adb7e97452 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,1416 +1,1413 @@ #[[ When increasing the minimum required version, check if Boost_ADDITIONAL_VERSIONS in CMake/PackageDepends/MITK_Boost_Config.cmake can be removed. See the first long comment in CMakeExternals/Boost.cmake for details. ]] set(MITK_CMAKE_MINIMUM_REQUIRED_VERSION 3.18) cmake_minimum_required(VERSION ${MITK_CMAKE_MINIMUM_REQUIRED_VERSION}) if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.19 AND CMAKE_VERSION VERSION_LESS 3.19.2) message(FATAL_ERROR "\ CMake v${CMAKE_VERSION} is defective [1]. \ Please either downgrade to v3.18 or upgrade to at least v3.19.2.\n\ [1] https://gitlab.kitware.com/cmake/cmake/-/issues/21529") endif() #----------------------------------------------------------------------------- # Policies #----------------------------------------------------------------------------- #[[ T28060 https://cmake.org/cmake/help/v3.18/policy/CMP0091.html https://cmake.org/cmake/help/v3.18/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html We pass CMP0091 to all external projects as command-line argument: -DCMAKE_POLICY_DEFAULT_CMP0091:STRING=OLD ]] cmake_policy(SET CMP0091 OLD) if(POLICY CMP0135) cmake_policy(SET CMP0135 NEW) # https://cmake.org/cmake/help/v3.24/policy/CMP0135.html endif() #----------------------------------------------------------------------------- # 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 2023.12.99) include_directories(SYSTEM ${MITK_SUPERBUILD_BINARY_DIR}) endif() #----------------------------------------------------------------------------- # MITK Extension Feature #----------------------------------------------------------------------------- set(MITK_EXTENSION_DIRS "" CACHE STRING "") unset(MITK_ABSOLUTE_EXTENSION_DIRS) foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) get_filename_component(MITK_ABSOLUTE_EXTENSION_DIR "${MITK_EXTENSION_DIR}" ABSOLUTE) list(APPEND MITK_ABSOLUTE_EXTENSION_DIRS "${MITK_ABSOLUTE_EXTENSION_DIR}") endforeach() set(MITK_DIR_PLUS_EXTENSION_DIRS "${MITK_SOURCE_DIR}" ${MITK_ABSOLUTE_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_ABSOLUTE_EXTENSION_DIRS}) set(MITK_CMAKE_EXTENSION_DIR "${MITK_EXTENSION_DIR}/CMake") 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(CTest) include(CMakeParseArguments) include(FindPackageHandleStandardArgs) # MITK macros include(mitkFunctionGetGccVersion) include(mitkFunctionCheckCompilerFlags) include(mitkFunctionSuppressWarnings) # includes several functions include(mitkMacroEmptyExternalProject) 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() if(CMAKE_COMPILER_IS_GNUCXX) mitkFunctionGetGccVersion(${CMAKE_CXX_COMPILER} GCC_VERSION) else() set(GCC_VERSION 0) endif() set(MITK_CXX_STANDARD 17) 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++ flag for targets. # However, compile flag checks also need to be done with -std=c++. # The MITK_CXX_FLAG variable is also used for external projects # build during the MITK super-build. mitkFunctionCheckCompilerFlags("-std=c++${MITK_CXX_STANDARD}" MITK_CXX${MITK_CXX_STANDARD}_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) mark_as_advanced( MITK_XVFB_TESTING MITK_FAST_TESTING MITK_BUILD_ALL_APPS ) #----------------------------------------------------------------------------- # Set UI testing flags #----------------------------------------------------------------------------- if(MITK_XVFB_TESTING) set(MITK_XVFB_TESTING_COMMAND "xvfb-run" "--auto-servernum" CACHE STRING "Command and options to test through Xvfb") mark_as_advanced(MITK_XVFB_TESTING_COMMAND) endif(MITK_XVFB_TESTING) # ----------------------------------------- # Other options set(MITK_CUSTOM_REVISION_DESC "" CACHE STRING "Override MITK revision description") mark_as_advanced(MITK_CUSTOM_REVISION_DESC) set_property(GLOBAL PROPERTY MITK_EXTERNAL_PROJECTS "") include(CMakeExternals/ExternalProjectList.cmake) foreach(MITK_EXTENSION_DIR ${MITK_ABSOLUTE_EXTENSION_DIRS}) set(MITK_CMAKE_EXTERNALS_EXTENSION_DIR "${MITK_EXTENSION_DIR}/CMakeExternals") 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_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_ABSOLUTE_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_Qt6 "Use Qt 6 library" ON) if(MITK_USE_Qt6) set(MITK_QT6_MINIMUM_VERSION 6.6) set(MITK_QT6_COMPONENTS Concurrent Core Core5Compat CoreTools Designer DesignerComponentsPrivate Gui Help LinguistTools Network OpenGL OpenGLWidgets Qml Sql StateMachine Svg ToolsTools UiTools WebEngineCore WebEngineWidgets Widgets Xml ) if(APPLE) list(APPEND MITK_QT6_COMPONENTS DBus) endif() # Hint at default install locations of Qt if(NOT Qt6_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 2022) list(APPEND _compilers "msvc2019") # Binary compatible 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() if(APPLE) list(APPEND _compilers macos) endif() foreach(_dir_candidate ${_dir_candidates}) get_filename_component(_dir_candidate ${_dir_candidate} REALPATH) foreach(_compiler ${_compilers}) set(_glob_expression "${_dir_candidate}/6.*/${_compiler}") file(GLOB _hints ${_glob_expression}) list(SORT _hints) list(APPEND MITK_QT6_HINTS ${_hints}) endforeach() endforeach() endif() find_package(Qt6 ${MITK_QT6_MINIMUM_VERSION} COMPONENTS ${MITK_QT6_COMPONENTS} REQUIRED HINTS ${MITK_QT6_HINTS}) get_target_property(QT_QMAKE_EXECUTABLE Qt6::qmake LOCATION) get_target_property(QT_HELPGENERATOR_EXECUTABLE Qt6::qhelpgenerator LOCATION) endif() if(Qt6_DIR) list(APPEND CMAKE_PREFIX_PATH "${Qt6_DIR}/../../..") list(REMOVE_DUPLICATES CMAKE_PREFIX_PATH) endif() # ----------------------------------------- # Custom dependency logic if(WIN32 AND Qt6_DIR) set(_dir_candidate "${Qt6_DIR}/../../../../../Tools/OpenSSLv3/Win_x64") get_filename_component(_dir_candidate ${_dir_candidate} ABSOLUTE) if(EXISTS "${_dir_candidate}") set(OPENSSL_ROOT_DIR "${_dir_candidate}") endif() endif() find_package(OpenSSL 3) if(NOT OpenSSL_FOUND) find_package(OpenSSL 1.1.1) endif() 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) 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 either install Win32 OpenSSL:\n" " https://slproweb.com/products/Win32OpenSSL.html\n" "Or use the Qt Maintenance tool to install:\n" " Developer and Designer Tools > OpenSSL Toolkit > OpenSSL 64-bit binaries\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) set(python3_mininum_version 3.11) else() set(python3_mininum_version 3.8) endif() find_package(Python3 ${python3_mininum_version} REQUIRED COMPONENTS Interpreter Development NumPy) 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() find_package(Git REQUIRED) #----------------------------------------------------------------------------- # 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(mitkFunctionAddManifest) include(mitkFunctionAddCustomModuleTest) include(mitkFunctionCheckModuleDependencies) include(mitkFunctionCompileSnippets) include(mitkFunctionConfigureVisualStudioUserProjectFile) 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 #----------------------------------------------------------------------------- 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) #----------------------------------------------------------------------------- if(OpenSSL_FOUND AND WIN32) #[[ On Windows, CMake is able to locate the link libraries for OpenSSL but it does not look for the corresponding DLLs that we need to copy to our binary directories and include in packaging. Setting these paths manually is cumbersome so we try to use a simple heuristic to automatically set them: - Based on the link libraries (usually located in a lib folder), try to find the "../bin" binary directory. - Use the base file names of the link libraries to find corresponding DLLs like "*.dll", that usually are named like "-1_1-x64.dll" or similar. ]] set(openssl_ssl_dll "") set(openssl_crypto_dll "") if(OPENSSL_SSL_LIBRARY AND EXISTS "${OPENSSL_SSL_LIBRARY}") get_filename_component(openssl_bin_dir "${OPENSSL_SSL_LIBRARY}" DIRECTORY) get_filename_component(openssl_bin_dir "${openssl_bin_dir}" DIRECTORY) set(openssl_bin_dir "${openssl_bin_dir}/bin") if(EXISTS "${openssl_bin_dir}") get_filename_component(openssl_ssl_basename "${OPENSSL_SSL_LIBRARY}" NAME_WE) file(GLOB openssl_ssl_dll "${openssl_bin_dir}/${openssl_ssl_basename}*.dll") list(LENGTH openssl_ssl_dll num_findings) if(num_findings GREATER 1) set(openssl_ssl_dll "") endif() get_filename_component(openssl_crypto_basename "${OPENSSL_CRYPTO_LIBRARY}" NAME_WE) file(GLOB openssl_crypto_dll "${openssl_bin_dir}/${openssl_crypto_basename}*.dll") list(LENGTH openssl_crypto_dll num_findings) if(num_findings GREATER 1) set(openssl_crypto_dll "") endif() endif() endif() set(MITK_OPENSSL_SSL_DLL "${openssl_ssl_dll}" CACHE FILEPATH "") if(DEFINED CACHE{MITK_OPENSSL_SSL_DLL} AND NOT MITK_OPENSSL_SSL_DLL AND openssl_ssl_dll) set(MITK_OPENSSL_SSL_DLL "${openssl_ssl_dll}" CACHE FILEPATH "" FORCE) endif() set(MITK_OPENSSL_CRYPTO_DLL "${openssl_crypto_dll}" CACHE FILEPATH "") if(DEFINED CACHE{MITK_OPENSSL_CRYPTO_DLL} AND NOT MITK_OPENSSL_CRYPTO_DLL AND openssl_crypto_dll) set(MITK_OPENSSL_CRYPTO_DLL "${openssl_crypto_dll}" CACHE FILEPATH "" FORCE) endif() if(MITK_OPENSSL_SSL_DLL AND EXISTS "${MITK_OPENSSL_SSL_DLL}" AND MITK_OPENSSL_CRYPTO_DLL AND EXISTS "${MITK_OPENSSL_CRYPTO_DLL}") foreach(config_type ${CMAKE_CONFIGURATION_TYPES}) execute_process(COMMAND "${CMAKE_COMMAND}" -E make_directory "${MITK_BINARY_DIR}/bin/${config_type}") configure_file("${MITK_OPENSSL_SSL_DLL}" "${MITK_BINARY_DIR}/bin/${config_type}/" COPYONLY) configure_file("${MITK_OPENSSL_CRYPTO_DLL}" "${MITK_BINARY_DIR}/bin/${config_type}/" COPYONLY) endforeach() MITK_INSTALL(FILES "${MITK_OPENSSL_SSL_DLL}" "${MITK_OPENSSL_CRYPTO_DLL}" ) endif() endif() # 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) if(NOT MITK_FAST_TESTING) if(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") 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_CXX${MITK_CXX_STANDARD}_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} -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-deprecated-copy -Wno-array-bounds -Wno-cast-function-type -Wno-maybe-uninitialized -Wno-error=stringop-overread -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_ABSOLUTE_EXTENSION_DIRS}) set(MITK_PACKAGE_DEPENDS_EXTENSION_DIR "${MITK_EXTENSION_DIR}/CMake/PackageDepends") 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.74 1.74.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) 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() 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() 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_Qt6) 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_Qt6) message("> Forcing BLUEBERRY_USE_QT_HELP to OFF because MITK_USE_Qt6 is OFF.") 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) # 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& e) { fprintf(stderr, \"%s\\n\", e.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 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_ABSOLUTE_EXTENSION_DIRS}) get_filename_component(MITK_ROOT_FOLDER "${MITK_EXTENSION_DIR}" NAME) set(MITK_MODULES_EXTENSION_DIR "${MITK_EXTENSION_DIR}/Modules") 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) set(MITK_DOXYGEN_OUTPUT_DIR "${PROJECT_BINARY_DIR}/Documentation/Doxygen" CACHE PATH "Output directory for doxygen generated documentation.") if(MITK_USE_BLUEBERRY) 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_ABSOLUTE_EXTENSION_DIRS}) set(MITK_PLUGINS_EXTENSION_DIR "${MITK_EXTENSION_DIR}/Plugins") 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") 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 #----------------------------------------------------------------------------- set(MITK_DOXYGEN_ADDITIONAL_INPUT_DIRS) set(MITK_DOXYGEN_ADDITIONAL_IMAGE_PATHS) set(MITK_DOXYGEN_ADDITIONAL_EXAMPLE_PATHS) foreach(MITK_EXTENSION_DIR ${MITK_DIR_PLUS_EXTENSION_DIRS}) set(MITK_DOXYGEN_ADDITIONAL_INPUT_DIRS "${MITK_DOXYGEN_ADDITIONAL_INPUT_DIRS} \"${MITK_EXTENSION_DIR}\"") set(MITK_DOXYGEN_ADDITIONAL_IMAGE_PATHS "${MITK_DOXYGEN_ADDITIONAL_IMAGE_PATHS} \"${MITK_EXTENSION_DIR}\"") # MITK_DOXYGEN_ADDITIONAL_EXAMPLE_PATHS should be modified by MITK extensions as needed endforeach() if(DOXYGEN_FOUND) foreach(MITK_EXTENSION_DIR ${MITK_DIR_PLUS_EXTENSION_DIRS}) set(MITK_DOCUMENTATION_EXTENSION_DIR "${MITK_EXTENSION_DIR}/Documentation") file(GLOB MITK_DOCUMENTATION_EXTENSION_FILES CONFIGURE_DEPENDS "${MITK_DOCUMENTATION_EXTENSION_DIR}/*.cmake") foreach(doc_file ${MITK_DOCUMENTATION_EXTENSION_FILES}) include("${doc_file}") endforeach() endforeach() # Transform list of example paths into space-separated string of quoted paths unset(example_paths) foreach(example_path ${MITK_DOXYGEN_ADDITIONAL_EXAMPLE_PATHS}) set(example_paths "${example_paths} \"${example_path}\"") endforeach() set(MITK_DOXYGEN_ADDITIONAL_EXAMPLE_PATHS "${example_paths}") 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") 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_ABSOLUTE_EXTENSION_DIRS}) set(MITK_APPLICATIONS_EXTENSION_DIR "${MITK_EXTENSION_DIR}/Applications") 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/BlueBerryExtensionPointReference.dox b/Documentation/Doxygen/3-DeveloperManual/Application/BlueBerryExtensionPointReference.dox index 855dc0e41a..427ca8e76e 100644 --- a/Documentation/Doxygen/3-DeveloperManual/Application/BlueBerryExtensionPointReference.dox +++ b/Documentation/Doxygen/3-DeveloperManual/Application/BlueBerryExtensionPointReference.dox @@ -1,1354 +1,1356 @@ /** \page BlueBerryExtPointsIndex BlueBerry Extension-Point Reference - \subpage BlueBerryExtPointsIndex_CoreExpr - \subpage BlueBerryExtPointsIndex_PlatformRuntime - \subpage BlueBerryExtPointsIndex_Workbench \page BlueBerryExtPointsIndex_CoreExpr Platform Core Expressions \tableofcontents \section BlueBerryExtPointsIndex_CoreExpr_ExprDef Expression Definitions \subsection BlueBerryExtPointsIndex_CoreExpr_ExprDef_Id Identifier \c org.blueberry.core.expressions.definitions \subsection BlueBerryExtPointsIndex_CoreExpr_ExprDef_Desc Description This extension point allows you to create reusable extensions. They can then be used in other core expression constructs. The reference element in a core expression will evaluated the expression definition with the evaluation context that is active for the reference element. \subsection BlueBerryExtPointsIndex_CoreExpr_ExprDef_ConfMarkup Configuration Markup \code{.unparsed} \endcode - point: a fully qualified identifier of the target extension point - id: an optional identifier of the extension instance - name: an optional name of the extension instance \code{.unparsed} \endcode Provides a global definition of an expression to be used with the \c \ expression element. This helps to reuse common expressions. - id: a globally unique identifier for the expression definition \code{.unparsed} \endcode A generic root element. The element can be used inside an extension point to define its enablement expression. The children of an enablement expression are combined using the and operator. \code{.unparsed} \endcode This element represent a NOT operation on the result of evaluating it's sub-element expression. \code{.unparsed} \endcode This element represent an AND operation on the result of evaluating all it's sub-elements expressions. \code{.unparsed} \endcode This element represent an OR operation on the result of evaluating all it's sub-element expressions. \code{.unparsed} \endcode This element is used to perform an instanceof check of the object in focus. The expression returns \c EvaluationResult.TRUE if the object's type is a sub type of the type specified by the attribute value. Otherwise \c EvaluationResult.FALSE is returned. - value: a fully qualified name of a class or interface \code{.unparsed} \endcode This element is used to evaluate the property state of the object in focus. The set of testable properties can be extended using the propery tester extension point. The test expression returns \c EvaluationResult.NOT_LOADED if the property tester doing the actual testing isn't loaded yet and the attribute \c forcePluginActivation is set to \c false. If \c forcePluginActivation is set to \c true and the evaluation context used to evaluate this expression support plug-in activation then evaluating the property will result in activating the plug-in defining the tester. - property: The name of an object's property to test. - args: Additional arguments passed to the property tester. Multiple arguments are seperated by commas. Each individual argument is converted into a Java base type using the same rules as defined for the value attribute of the test expression. - value: The expected value of the property. Can be omitted if the property is a boolean property. The test expression is supposed to return \c EvaluationResult.TRUE if the property matches the value and \c EvaluationResult.FALSE otherwise. The value attribute is converted into a Java base type using the following rules: - The string \c "true" is converted into \c Boolean.TRUE . - The string \c "false" is converted into \c Boolean.FALSE . - If the string contains a dot then the interpreter tries to convert the value into a \c Float object. If this fails the string is treated as a \c java.lang.String. - If the string only consists of numbers then the interpreter converts the value in an \c Integer object. - In all other cases the string is treated as a \c java.lang.String . - The conversion of the string into a \c Boolean , \c Float , or \c Integer can be suppressed by surrounding the string with single quotes. For example, the attribute \c value="'true'" is converted into the string "true". - forcePluginActivation: A flag indicating whether the plug-in contributing the property tester should be loaded if necessary. As such, this flag should be used judiciously, in order to avoid unnecessary plug-in activations. Most clients should avoid setting this flag to \c true. This flag is only honored if the evaluation context used to evaluate this expression allows plug-in activation. Otherwise the flag is ignored and no plug-in loading takes place. \code{.unparsed} \endcode Tests a system property by calling the \c System.getProperty method and compares the result with the value specified through the value attribute. - property: The name of an system property to test. - value: The expected value of the property. The value is interpreted as a string value. \code{.unparsed} \endcode This element is used to perform an equals check of the object in focus. The expression returns \c EvaluationResult.TRUE if the object is equal to the value provided by the attribute value. Otherwise \c EvaluationResult.FALSE is returned. - value: The expected value. The value provided as a string is converted into a Java base type using the same rules as for the value attribute of the test expression. \code{.unparsed} \endcode This element is used to test the number of elements in a collection. - value: An expression to specify the number of elements in a list. Following wildcard characters can be used: - *: any number of elements - ?: no elements or one element - +: one or more elements - !: no elements - integer value: the list must contain the exact number of elements \code{.unparsed} \endcode This element changes the object to be inspected for all its child element to the object referenced by the given variable. If the variable can not be resolved then the expression will throw an \c ExpressionException when evaluating it. The children of a with expression are combined using the and operator. - variable: The name of the variable to be used for further inspection. It is up to the evaluator of an extension point to provide the variable in the variable pool. \code{.unparsed} \endcode This element changes the object to be inspected for all its child element to the object referenced by the given variable. If the variable can not be resolved then the expression will throw an \c ExpressionException when evaluating it. The children of a with expression are combined using the and operator. - variable: The name of the variable to be resolved. This variable is then used as the object in focus for child element evaluation. It is up to the evaluator of an extension point to provide a corresponding variable resolver (see berry::IVariableResolver) through the evaluation context passed to the root expression element when evaluating the expression. - args: Additional arguments passed to the variable resolver. Multiple arguments are seperated by commas. Each individual argument is converted into a Java base type using the same rules as defined for the value attribute of the test expression. \code{.unparsed} \endcode This element is used to adapt the object in focus to the type specified by the attribute type. The expression returns not loaded if either the adapter or the type referenced isn't loaded yet. It throws an \c ExpressionException during evaluation if the type name doesn't exist at all. The children of an adapt expression are combined using the and operator. - type: the type to which the object in focus is to be adapted \code{.unparsed} \endcode This element is used to iterate over a variable that is of type \c java.util.Collection. If the object in focus is not of type \c java.util.Collection then an \c ExpressionException will be thrown while evaluating the expression. - operator: Either "and" or "or". The operator defines how the child elements will be combined. If not specified, "and" will be used. - ifEmpty: The value return from the iterate expression if the collection is empty. If not specified then \c true is returned when the operator equals "and" and \c false is returned if the operator equals "or". \code{.unparsed} \endcode This element is used to reference an expression from the \c org.blueberry.core.expressions.definitions extension point. The expression definition will be evaluated within the current expression element using the current evaluation context. - definitionId: the unique id of an expression from \c org.blueberry.core.expressions.definitions \subsection BlueBerryExtPointsIndex_CoreExpr_ExprDef_Examples Examples \code{.unparsed} \endcode Then this expression definition can be used when composing other expressions. \code{.unparsed} \endcode \section BlueBerryExtPointsIndex_CoreExpr_CommExpr Common Expressions \subsection BlueBerryExtPointsIndex_CoreExpr_CommExpr_Id Identifier \c org.blueberry.core.expressions.commonExpression \subsection BlueBerryExtPointsIndex_CoreExpr_CommExpr_ConfMarkup Configuration Markup \code{.unparsed} \endcode A generic root element. The element can be used inside an extension point to define its enablement expression. The children of an enablement expression are combined using the and operator. \code{.unparsed} \endcode This element represent a NOT operation on the result of evaluating it's sub-element expression. \code{.unparsed} \endcode This element represent an AND operation on the result of evaluating all it's sub-elements expressions. \code{.unparsed} \endcode This element represent an OR operation on the result of evaluating all it's sub-element expressions. \code{.unparsed} \endcode This element is used to perform an instanceof check of the object in focus. The expression returns \c EvaluationResult.TRUE if the object's type is a sub type of the type specified by the attribute value. Otherwise \c EvaluationResult.FALSE is returned. - value: a fully qualified name of a class or interface \code{.unparsed} \endcode This element is used to evaluate the property state of the object in focus. The set of testable properties can be extended using the propery tester extension point. The test expression returns \c EvaluationResult.NOT_LOADED if the property tester doing the actual testing isn't loaded yet and the attribute \c forcePluginActivation is set to false. If \c forcePluginActivation is set to \c true and the evaluation context used to evaluate this expression support plug-in activation then evaluating the property will result in activating the plug-in defining the tester. - property: The name of an object's property to test. - args: Additional arguments passed to the property tester. Multiple arguments are seperated by commas. Each individual argument is converted into a Java base type using the same rules as defined for the value attribute of the test expression. - value: The expected value of the property. Can be omitted if the property is a boolean property. The test expression is supposed to return EvaluationResult.TRUE if the property matches the value and EvaluationResult.FALSE otherwise. The value attribute is converted into a Java base type using the following rules: - The string "true" is converted into \c Boolean.TRUE - The string "false" is converted into \c Boolean.FALSE - If the string contains a dot then the interpreter tries to convert the value into a \c Float object. If this fails the string is treated as a \c java.lang.String - If the string only consists of numbers then the interpreter converts the value in an \c Integer object. - In all other cases the string is treated as a \c java.lang.String - The conversion of the string into a \c Boolean , \c Float , or \c Integer can be suppressed by surrounding the string with single quotes. For example, the attribute \c value="'true'" is converted into the string "true" - forcePluginActivation: A flag indicating whether the plug-in contributing the property tester should be loaded if necessary. As such, this flag should be used judiciously, in order to avoid unnecessary plug-in activations. Most clients should avoid setting this flag to true. This flag is only honored if the evaluation context used to evaluate this expression allows plug-in activation. Otherwise the flag is ignored and no plug-in loading takes place. \code{.unparsed} \endcode Tests a system property by calling the \c System.getProperty method and compares the result with the value specified through the value attribute. - property: The name of an system property to test. - value: The expected value of the property. The value is interpreted as a string value. \code{.unparsed} \endcode This element is used to perform an equals check of the object in focus. The expression returns \c EvaluationResult.TRUE if the object is equal to the value provided by the attribute value. Otherwise \c EvaluationResult.FALSE is returned. - value: The expected value. The value provided as a string is converted into a Java base type using the same rules as for the value attribute of the test expression. \code{.unparsed} \endcode This element is used to test the number of elements in a collection. - value: An expression to specify the number of elements in a list. Following wildcard characters can be used: - *: any number of elements - ?: no elements or one element - +: one or more elements - !: no elements - integer value: the list must contain the exact number of elements \code{.unparsed} \endcode This element changes the object to be inspected for all its child element to the object referenced by the given variable. If the variable can not be resolved then the expression will throw an \c ExpressionException when evaluating it. The children of a with expression are combined using the and operator. - variable: The name of the variable to be used for further inspection. It is up to the evaluator of an extension point to provide the variable in the variable pool. \code{.unparsed} \endcode This element changes the object to be inspected for all its child element to the object referenced by the given variable. If the variable can not be resolved then the expression will throw an \c ExpressionException when evaluating it. The children of a with expression are combined using the and operator. - variable: The name of the variable to be resolved. This variable is then used as the object in focus for child element evaluation. It is up to the evaluator of an extension point to provide a corresponding variable resolver (see berry::IVariableResolver) through the evaluation context passed to the root expression element when evaluating the expression. - args: Additional arguments passed to the variable resolver. Multiple arguments are seperated by commas. Each individual argument is converted into a Java base type using the same rules as defined for the value attribute of the test expression. \code{.unparsed} \endcode This element is used to adapt the object in focus to the type specified by the attribute type. The expression returns not loaded if either the adapter or the type referenced isn't loaded yet. It throws an \c ExpressionException during evaluation if the type name doesn't exist at all. The children of an adapt expression are combined using the and operator. - type: the type to which the object in focus is to be adapted \code{.unparsed} \endcode This element is used to iterate over a variable that is of type \c java.util.Collection. If the object in focus is not of type \c java.util.Collection then an \c ExpressionException will be thrown while evaluating the expression. - operator: Either "and" or "or". The operator defines how the child elements will be combined. If not specified, "and" will be used. - ifEmpty: The value return from the iterate expression if the collection is empty. If not specified then \c true is returned when the operator equals "and" and \c false is returned if the operator equals "or". \code{.unparsed} \endcode This element is used to reference an expression from the \c org.blueberry.core.expressions.definitions extension point. The expression definition will be evaluated within the current expression element using the current evaluation context. - definitionId: the unique id of an expression from \c org.blueberry.core.expressions.definitions \section BlueBerryExtPointsIndex_CoreExpr_PropTest Property Testers \subsection BlueBerryExtPointsIndex_CoreExpr_PropTest_Id Identifier \c org.blueberry.core.expressions.propertyTesters \subsection BlueBerryExtPointsIndex_CoreExpr_PropTest_Desc Description This extension point allows to add properties to an already existing type. Those properties can then be used inside the expression language's test expression element. \subsection BlueBerryExtPointsIndex_CoreExpr_PropTest_ConfMarkup Configuration Markup \code{.unparsed} \endcode - point: a fully qualified identifier of the target extension point - id: an optional identifier of the extension instance - name: an optional name of the extension instance \code{.unparsed} \endcode - id: Unique identifier for the property tester. - type: The type to be extended by this property tester. - namespace: A unique id determining the name space the properties are added to. - properties: A comma separated list of properties provided by this property tester. - class: The name of the class that implements the testing methods. The class must be public and extend \c org.blueberry.core.expressions.PropertyTester with a public 0-argument constructor. \subsection BlueBerryExtPointsIndex_CoreExpr_PropTest_Examples Examples \code{.unparsed} \endcode \page BlueBerryExtPointsIndex_PlatformRuntime Platform Runtime \tableofcontents \section BlueBerryExtPointsIndex_PlatformRuntime_App Applications \subsection BlueBerryExtPointsIndex_PlatformRuntime_App_Id Identifier \c org.blueberry.osgi.applications \subsection BlueBerryExtPointsIndex_PlatformRuntime_App_Desc Description The applications extension point allows plugins to contribute applications to the BlueBerry Platform. \subsection BlueBerryExtPointsIndex_PlatformRuntime_App_ConfMarkup Configuration Markup \code{.unparsed} \endcode \code{.unparsed} \endcode \code{.unparsed} \endcode \subsection BlueBerryExtPointsIndex_PlatformRuntime_App_Examples Examples \code{.unparsed} \endcode \section BlueBerryExtPointsIndex_PlatformRuntime_Prod Products \subsection BlueBerryExtPointsIndex_PlatformRuntime_Prod_Id Identifier \c org.blueberry.core.runtime.products \subsection BlueBerryExtPointsIndex_PlatformRuntime_Prod_Desc Description Products are the BlueBerry unit of branding. Product extensions are supplied by plug-ins wishing to define one or more products. There must be one product per extension as the extension id is used in processing and identifying the product. There are two possible forms of product extension, static and dynamic. Static product extensions directly contain all relevant information about the product. Dynamic product extensions identify a class (an \c IProductProvider) which is capable of defining one or more products when queried. \subsection BlueBerryExtPointsIndex_PlatformRuntime_Prod_ConfMarkup Configuration Markup \code{.unparsed} \endcode \code{.unparsed} \endcode - application: the default application to run when running this product - name: the human-readable name of this product - description: the human-readable description of this product \code{.unparsed} \endcode - name: the key under which this property is stored - value: the value of this property \code{.unparsed} \endcode \code{.unparsed} \endcode - class: the fully-qualified name of a class which implements \c IProductProvider \subsection BlueBerryExtPointsIndex_PlatformRuntime_Prod_Examples Examples \code{.unparsed} \endcode The following is an example of a dynamic product (product provider) declaration: Following is an example of an application declaration: \code{.unparsed} \endcode \subsection BlueBerryExtPointsIndex_PlatformRuntime_Prod_SupplImpl Supplied Implementation No implementations of \c IProductProvider are supplied. \page BlueBerryExtPointsIndex_Workbench Workbench \tableofcontents \section BlueBerryExtPointsIndex_Workbench_Edit Internal and External Editors \subsection BlueBerryExtPointsIndex_Workbench_Edit_Id Identifier \c org.blueberry.ui.editors \subsection BlueBerryExtPointsIndex_Workbench_Edit_Desc Description This extension point is used to add new editors to the workbench. A editor is a visual component within a workbench page. It is typically used to edit or browse a document or input object. To open an editor, the user will typically invoke "Open" on an \c IFile. When this action is performed the workbench registry is consulted to determine an appropriate editor for the file type and then a new instance of the editor type is created. The actual result depends on the type of the editor. The workbench provides support for the creation of internal editors, which are tightly integrated into the workbench, and external editors, which are launched in a separate frame window. There are also various levels of integration between these extremes. In the case of an internal editor tight integration can be achieved between the workbench window and the editor part. The workbench menu and toolbar are pre-loaded with a number of common actions, such as cut, copy, and paste. The active part, view or editor, is expected to provide the implementation for these actions. An internal editor may also define new actions which appear in the workbench window. These actions only appear when the editor is active. The integration between the workbench and external editors is more tenuous. In this case the workbench may launch an editor but after has no way of determining the state of the external editor or collaborating with it by any means except through the file system. \subsection BlueBerryExtPointsIndex_Workbench_Edit_ConfMarkup Configuration Markup \code{.unparsed} \endcode - point: a fully qualified identifier of the target extension point - id: an optional identifier of the extension instance - name: an optional name of the extension instance \code{.unparsed} \endcode - id: a unique name that will be used to identify this editor - name: a translatable name that will be used in the UI for this editor - icon: A relative name of the icon that will be used for all resources that match the specified extensions. Editors should provide an icon to make it easy for users to distinguish between different editor types. If you specify a command rather than a class, an icon is not needed. In that case, the workbench will use the icon provided by the operating system. - extensions: an optional field containing the list of file types understood by the editor. This is a string containing comma separate file extensions. For instance, an editor which understands hypertext documents may register for "htm, html". - class: the name of a class that implements berry::IEditorPart. The attributes \c class , \c command , and \c launcher are mutually exclusive. If this attribute is defined then \c contributorClass should also be defined. - command: a command to run in order to launch an external editor. The executable command must be located on the system path or in the plug-in's directory. The attributes class, command, and launcher are mutually exclusive. - launcher: the name of a class which that implements berry::IEditorLauncher. A launcher will open an external editor. The attributes \c class , \c command , and \c launcher are mutually exclusive. - contributorClass: the name of a class that implements berry::IEditorActionBarContributor. This attribute should only be defined if the \c class attribute is defined. This class is used to add new actions to the workbench menu and tool bar which reflect the features of the editor type. - default: if true, this editor will be used as the default editor for the type. This is only relevant in a case where more than one editor is registered for the same type. If an editor is not the default for the type, it can still be launched using "Open with..." submenu for the selected resource. Please note that this attribute is only honored for filename and extension associations at this time. It will not be honored for content type bindings. Content type-based resolution will occur on a first come, first serve basis and is not explicitly specified. - filenames: an optional field containing the list of file names understood by the editor. This is a string containing comma separate file names. For instance, an editor which understands specific hypertext documents may register for "ejb.htm, ejb.html". - matchingStrategy: the name of a class that implements berry::IEditorMatchingStrategy. This attribute should only be defined if the \c class attribute is defined. This allows the editor extension to provide its own algorithm for matching the input of one of its editors to a given editor input. \code{.unparsed} \endcode Advertises that the containing editor understands the given content type and is suitable for editing files of that type. - contentTypeId: The content type identifier. This is an ID defined by the \c org.blueberry.core.runtime.contentTypes extension point. \subsection BlueBerryExtPointsIndex_Workbench_Edit_Examples Examples The following is an example of an internal editor extension definition: \code{.unparsed} \endcode \subsection BlueBerryExtPointsIndex_Workbench_Edit_SupplImpl Supplied Implementation The workbench provides a "Default Text Editor". The end user product may contain other editors as part of the shipping bundle. In that case, editors will be registered as extensions using the syntax described above. \section BlueBerryExtPointsIndex_Workbench_Keywords Keywords \subsection BlueBerryExtPointsIndex_Workbench_Keywords_Id Identifier \c org.blueberry.ui.keywords \subsection BlueBerryExtPointsIndex_Workbench_Keywords_Desc Description The keywords extension point defines keywords and a unique id for reference by other schemas. See \c propertyPages and \c preferencePages . \subsection BlueBerryExtPointsIndex_Workbench_Keywords_ConfMarkup Configuration Markup \code{.unparsed} \endcode - point: a fully qualified identifier of the target extension point - id: an optional identifier of the extension instance - name: an optional name of the extension instance \code{.unparsed} \endcode - id: The id is the unique id used to reference the keyword - label: The human readable label of the keyword \subsection BlueBerryExtPointsIndex_Workbench_Keywords_Examples Examples The following is an example of a keyword extension: \code{.unparsed} \endcode \subsection BlueBerryExtPointsIndex_Workbench_Keywords_SupplImpl Supplied Implementation Keywords are used only with preference and property pages. See the \c keywordReference element of the \c org.blueberry.ui.propertyPages and \c org.blueberry.ui.preferencePages extension points. \section BlueBerryExtPointsIndex_Workbench_PerspExt Perspective Extensions \subsection BlueBerryExtPointsIndex_Workbench_PerspExt_Id Identifier \c org.blueberry.ui.perspectiveExtensions \subsection BlueBerryExtPointsIndex_Workbench_PerspExt_Desc Description This extension point is used to extend perspectives registered by other plug-ins. A perspective defines the initial contents of the window action bars (menu and toolbar) and the initial set of views and their layout within a workbench page. Other plug-ins may contribute actions or views to the perspective which appear when the perspective is selected. Optional additions by other plug-ins are appended to the initial definition. \subsection BlueBerryExtPointsIndex_Workbench_PerspExt_ConfMarkup Configuration Markup \code{.unparsed} \endcode - point: a fully qualified identifier of the target extension point - id: an optional identifier of the extension instance - name: an optional name of the extension instance \code{.unparsed} \endcode - targetID: the unique identifier of the perspective (as specified in the registry) into which the contribution is made. If the value is set to "*" the extension is applied to all perspectives. \code{.unparsed} \endcode - id: the unique identifier of the action set which will be added to the perspective. \code{.unparsed} \endcode - id: the unique identifier of the view which will be added to the perspective's "Show View" submenu of the "Window" menu. \code{.unparsed} \endcode - id: the unique identifier of the perspective which will be added to the perspective's "Open Perspective" submenu of the "Window" menu. \code{.unparsed} \endcode - id: the unique identifier of the new wizard which will be added to the perspective's "New" submenu of the "File" menu. \code{.unparsed} \endcode - id: the unique identifier of the view which will be added to the perspective's "Show In..." prompter in the Navigate menu. \code{.unparsed} \endcode - id: the unique identifier of the view which will be added to the perspective layout. - relative: the unique identifier of a view which already exists in the perspective. This will be used as a reference point for placement of the view. The relationship between these two views is defined by \c relationship . Ignored if relationship is "fast". - relationship: specifies the relationship between \c id and \c relative . The following values are supported: - fast: the view extension will be created as a fast view. - stack: the view extension will be stacked with the relative view in a folder. - left, right, top, bottom: the view extension will be placed beside the relative view. In this case a \c ratio must also be defined. - ratio: the percentage of area within the relative view which will be donated to the view extension. If the view extension is a fast view, the ratio is the percentage of the workbench the fast view will cover when active. This must be defined as a floating point value and lie between 0.05 and 0.95. - visible: whether the view is initially visible when the perspective is opened. This attribute should have a value of "true" or "false" if used. If this attribute is not used, the view will be initially visible by default. - closeable: whether the view is closeable in the target perspective. This attribute should have a value of "true" or "false" if used. If this attribute is not used, the view will be closeable, unless the perspective itself is marked as fixed. - moveable: whether the view is moveable. A non-moveable view cannot be moved either within the same folder, or moved between folders in the perspective. This attribute should have a value of "true" or "false" if used. If this attribute is not used, the view will be moveable, unless the perspective itself is marked as fixed. - standalone: whether the view is a standalone view. A standalone view cannot be docked together with others in the same folder. This attribute should have a value of "true" or "false" if used. This attribute is ignored if the relationship attribute is "fast" or "stacked". If this attribute is not used, the view will be a regular view, not a standalone view (default is "false"). - showTitle: whether the view's title is shown. This attribute should have a value of "true" or "false" if used. This attribute only applies to standalone views. If this attribute is not used, the view's title will be shown (default is "true"). - minimized: If the perspective extension will result in a new view stack being created (i.e. the 'relationship' attribute is one of left, right, top or bottom) this field determines the new stack's initial display state. \code{.unparsed} \endcode - id: The unique identifier of the Command which is to be removed from the menu. WARNING: This is considered to be a 'Product level' extension and should not be used in consumable plugins without great care. \code{.unparsed} \endcode - id: The unique identifier of the Command which is to be removed from thetoolbar. WARNING: This is considered to be a 'Product level' extension and should not be used in consumable plugins without great care. \subsection BlueBerryExtPointsIndex_Workbench_PerspExt_Examples Examples The following is an example of a perspective extension (note the subelements and the way attributes are used): \code{.unparsed} \endcode In the example above, an action set, view shortcut, new wizard shortcut, and perspective shortcut are contributed to the initial contents of the Resource Perspective. In addition, the Package Explorer view is stacked on the Resource Navigator and the Type Hierarchy View is added beside the Resource Navigator. \section BlueBerryExtPointsIndex_Workbench_Persp Perspectives \subsection BlueBerryExtPointsIndex_Workbench_Persp_Id Identifier \c org.blueberry.ui.perspective \subsection BlueBerryExtPointsIndex_Workbench_Persp_Desc Description This extension point is used to add perspective factories to the workbench. A perspective factory is used to define the initial layout and visible action sets for a perspective. The user can select a perspective by invoking the "Open Perspective" submenu of the "Window" menu. \subsection BlueBerryExtPointsIndex_Workbench_Persp_ConfMarkup Configuration Markup \code{.unparsed} \endcode - point: a fully qualified identifier of the target extension point - id: an optional identifier of the extension instance - name: an optional name of the extension instance \code{.unparsed} \endcode - id: a unique name that will be used to identify this perspective. - name: a translatable name that will be used in the workbench window menu bar to represent this perspective. - class: a fully qualified name of the class that implements berry::IPerspectiveFactory interface. - icon: a relative name of the icon that will be associated with this perspective. - fixed: indicates whether the layout of the perspective is fixed. If true, then views created by the perspective factory are not closeable, and cannot be moved. The default is false. \code{.unparsed} \endcode An optional subelement whose body should contain text providing a short description of the perspective. \subsection BlueBerryExtPointsIndex_Workbench_Persp_Examples Examples The following is an example of a perspective extension: \code{.unparsed} \endcode \subsection BlueBerryExtPointsIndex_Workbench_Persp_SupplImpl Supplied Implementation The workbench provides a "Resource Perspective". Additional perspectives may be added by plug-ins. They are selected using the "Open Perspective" submenu of the "Window" menu. \section BlueBerryExtPointsIndex_Workbench_PrefPages Preference Pages \subsection BlueBerryExtPointsIndex_Workbench_PrefPages_Id Identifier \c org.blueberry.ui.preferencePages \subsection BlueBerryExtPointsIndex_Workbench_PrefPages_Desc Description The workbench provides one common dialog box for preferences. The purpose of this extension point is to allow plug-ins to add pages to the preference dialog box. When preference dialog box is opened (initiated from the menu bar), pages contributed in this way will be added to the dialog box. \subsection BlueBerryExtPointsIndex_Workbench_PrefPages_ConfMarkup Configuration Markup \code{.unparsed} \endcode - point: a fully qualified identifier of the target extension point - id: an optional identifier of the extension instance - name: an optional name of the extension instance \code{.unparsed} \endcode - id: a unique name that will be used to identify this page. - name: a translatable name that will be used in the UI for this page. - class: a name of the fully qualified class that implements berry::IWorkbenchPreferencePage. - category: a path indicating the location of the page in the preference tree. The path may either be a parent node ID or a sequence of IDs separated by '/', representing the full path from the root node. \code{.unparsed} \endcode A reference by a preference page to a keyword. See the keywords extension point. - id: The id of the keyword being referred to. \subsection BlueBerryExtPointsIndex_Workbench_PrefPages_Examples Examples The following is an example for the preference extension point: \code{.unparsed} \endcode \subsection BlueBerryExtPointsIndex_Workbench_PrefPages_SupplImpl Supplied Implementation The workbench adds several pages for setting the preferences of the platform. Pages registered through this extension will be added after them according to their category information. \section BlueBerryExtPointsIndex_Workbench_PresFact Presentation Factories \subsection BlueBerryExtPointsIndex_Workbench_PresFact_Id Identifier \c org.blueberry.ui.presentationFactories \subsection BlueBerryExtPointsIndex_Workbench_PresFact_Desc Description This extension point is used to add presentation factories to the workbench. A presentation factory defines the overall look and feel of the workbench, including how views and editors are presented. \subsection BlueBerryExtPointsIndex_Workbench_PresFact_ConfMarkup Configuration Markup \code{.unparsed} \endcode \code{.unparsed} \endcode - class: Specify the fully qualified class to be used for the presentation factory. The specified value must implement the interface berry::IPresentationFactory. - id: a unique name that will be used to identify this presentation factory - name: a translatable name that can be used to show this presentation factory in the UI \subsection BlueBerryExtPointsIndex_Workbench_PresFact_Examples Examples The following is an example of a presentationFactory extension: \code{.unparsed} \endcode \subsection BlueBerryExtPointsIndex_Workbench_PresFact_SupplImpl Supplied Implementation If a presentation factory is not specified or is missing then the implementation in berry::QtWorkbenchPresentationFactory will be used. \section BlueBerryExtPointsIndex_Workbench_Services Services \subsection BlueBerryExtPointsIndex_Workbench_Services_Id Identifier \c org.blueberry.ui.services \subsection BlueBerryExtPointsIndex_Workbench_Services_Desc Description Define service factories so that services can be contributed declaratively and will be available through berry::IServiceLocator::GetService(Class). The implementation of \c AbstractServiceFactory must be able to return a global service and multiple child services (if applicable). \subsection BlueBerryExtPointsIndex_Workbench_Services_ConfMarkup Configuration Markup \code{.unparsed} \endcode Contribute services to the workbench. \code{.unparsed} \endcode Match a service interface to a factory that can supply a hierachical implementation of that service. - factoryClass: The factory that extends \c AbstractServiceFactory and can create the implementation for the \c serviceClass. \code{.unparsed} \endcode A service this factory can provide. - serviceClass: The interface that represents a service contract. \code{.unparsed} \endcode A Source Provider supplies source variables to the IEvaluationService. It can also notify the IEvaluationService when one or more of the variables change. - provider: This class must provide variables and call the appropriate \c fireSourceChanged(*) method when any of the variables change. \code{.unparsed} \endcode A source variable from this provider. A source provider must declare all variables that it provides. - name: The name of a contributed source variable. It is a good practice to prepend the plugin id to the variable name to avoid collisions with other source providers. - priorityLevel: For conflict resolution used by services like the \c IHandlerService , contributed source variables must assign a priority. workbench is the global default priority. See \c ISources for relative priority information. \subsection BlueBerryExtPointsIndex_Workbench_Services_Examples Examples Here is a basic definition: \code{.unparsed} \endcode The LevelServiceFactory can return an ILevelService when it is requested from the IServiceLocator: \code{.unparsed} berry::ILevelService::Pointer s = GetSite()->GetService(my::ILevelService::GetStaticClassName()); std::cout << s->GetLevel(); \endcode In this test example, the factory would instantiate three \c ILevelService implementations during the first call to \c GetSite()->GetService(*) . The global one in the workbench, one for the workbench window, and one for the site. \section BlueBerryExtPointsIndex_Workbench_Tweak Tweaklets \subsection BlueBerryExtPointsIndex_Workbench_Tweak_Id Identifier \c org.blueberry.ui.tweaklets \subsection BlueBerryExtPointsIndex_Workbench_Tweak_Desc Description Typically, although not required, the value of the \c definition attribute is the fully qualified name without colons of an abstract class defined by the workbench, and the value of the \c implementation attribute is the fully qualified name of a non-abstract class provided by the extending plug-in. \subsection BlueBerryExtPointsIndex_Workbench_Tweak_ConfMarkup Configuration Markup \code{.unparsed} \endcode \code{.unparsed} \endcode - id: a unique name that will be used to identify this tweaklet - name: a translatable name that will be used in the UI for this tweaklet - description: a translatable short description of this tweaklet, to be used in the UI - definition: an identifier of the tweaklet definition in the workbench, typically a fully qualified type name without colons - implementation: an identifier of the tweaklet implementation provided by the extender, typically a fully qualified class name \subsection BlueBerryExtPointsIndex_Workbench_Tweak_SupplImpl Supplied Implementation Tweaklets are usually used to specialize the workbench for a specific GUI toolkit. \section BlueBerryExtPointsIndex_Workbench_Views Views \subsection BlueBerryExtPointsIndex_Workbench_Views_Id Identifier \c org.blueberry.ui.views \subsection BlueBerryExtPointsIndex_Workbench_Views_Desc Description This extension point is used to define additional views for the workbench. A view is a visual component within a workbench page. It is typically used to navigate a hierarchy of information (like the workspace), open an editor, or display properties for the active editor. The user can make a view visible from the Window > Show View menu or close it from the view local title bar. In order to reduce the visual clutter in the Show View Dialog, views should be grouped using categories. \subsection BlueBerryExtPointsIndex_Workbench_Views_ConfMarkup Configuration Markup \code{.unparsed} \endcode - point: a fully qualified identifier of the target extension point - id: an optional identifier of the extension instance - name: an optional name of the extension instance \code{.unparsed} \endcode - id: a unique name that will be used to identify this category - name: a translatable name that will be used in the UI for this category - parentCategory: an optional path composed of category IDs separated by '/'. This allows the creation of a hierarchy of categories. \code{.unparsed} \endcode - id: a unique name that will be used to identify this view - name: a translatable name that will be used in the UI for this view - category: an optional attribute that is composed of the category IDs separated by '/'. Each referenced category must be declared in a corresponding category element. - class: a fully qualified name of the class that implements berry::IViewPart. A common practice is to subclass berry::ViewPart or berry::QtViewPart in order to inherit the default functionality. +- internal: a hint if the view should be considered internal, e.g., in enumerations of views in the UI. - icon: a relative name of the icon that will be associated with the view. - fastViewWidthRatio: the percentage of the width of the workbench that the view will take up as an active fast view. This must be defined as a floating point value and lie between 0.05 and 0.95. If no value is supplied, a default ratio will be used. - allowMultiple: flag indicating whether this view allows multiple instances to be created using IWorkbenchPage::ShowView(QString id, QString secondaryId). The default is false. - restorable: flag indicating whether this view allows to be restored upon workbench restart. If set to false, the view will not be open after a workbench restart. The default is true. \code{.unparsed} \endcode An optional subelement whose body should contain text providing a short description of the view. \code{.unparsed} \endcoe A sticky view is a view that will appear by default across all perspectives in a window once it is opened. Its initial placement is governemed by the location attribute, but nothing prevents it from being moved or closed by the user. Use of this element will only cause a placeholder for the view to be created, it will not show the view. Please note that usage of this element should be done with great care and should only be applied to views that truely have a need to live across perspectives. - id: the id of the view to be made sticky. - location: optional attribute that specifies the location of the sticky view relative to the editor area. If absent, the view will be docked to the right of the editor area. - closeable: optional attribute that specifies wether the view should be closeable. If absent it will be closeable. - moveable: optional attribute that specifies wether the view should be moveable. If absent it will be moveable. \subsection BlueBerryExtPointsIndex_Workbench_Views_Examples Examples The following is an example of the extension point: \code{.unparsed} \endcode The following is an example of a sticky view declaration: \code{.unparsed} \endcode \subsection BlueBerryExtPointsIndex_Workbench_Views_SupplImpl Supplied Implementation The BlueBerry Platform provides a number of standard views. From the user point of view, these views are no different from any other view provided by the plug-ins. All the views can be shown from the "Show View" submenu of the "Window" menu. The position of a view is persistent: it is saved when the view is closed and restored when the view is reopened in a single session. The position is also persisted between workbench sessions. */ diff --git a/Documentation/Doxygen/3-DeveloperManual/Concepts/Selection.dox b/Documentation/Doxygen/3-DeveloperManual/Concepts/Selection.dox index 562426f2f2..646405bd73 100644 --- a/Documentation/Doxygen/3-DeveloperManual/Concepts/Selection.dox +++ b/Documentation/Doxygen/3-DeveloperManual/Concepts/Selection.dox @@ -1,302 +1,302 @@ /** \page SelectionConceptPage Selection Concept \tableofcontents Selecting data nodes is frequently done when working with the MITK workbench. Most of the views in MITK require one or more selected data nodes that will be somehow processed by the underlying algorithms, such as image segmentation, image registration, basic image processing, image statistics computation etc.. In order to overcome some disadvantages of the old data node seletion concept, the following new selection concept has been implemented.
This page introduces the concept and the corresponding implementation. The document starts with a brief explanation of the disadvantages of the old concepts and justifies a need for the new concept. \section Migration Migration idea / background The old data node selection concept is a mixture of a \a global and a \a local selection concept: \subsection GlobalSelection Global selection The global selection was realized by the data manager view: Selecting one or more data nodes in the data manager view lead to a propagation of the selected nodes via the blueberry framework. Other views that derive from QmitkAbstractView received the new selection and processed it individually. All activated views were able to receive the new selection successively, thus it is called a \a global selection. \subsection LocalSelection Local selection The local selection was realized by Qt elements inside a view. An example of such an element is the QmitkDataStorageComboBox. This combo box contains the nodes from the data storage and allows to select one of it. A combo box can be included in a view multiple times. Additionally a node predicate can be set for a combo box so that only a filtered subset of all nodes in the data storage is contained in the combo box. A selection inside a combo box does not affect the selection of another combo box (in the same or another view), thus it is called a \a local selection.
Both concepts have reached their functional limit: -# the global selection does not offer the functionality to filter data nodes -# the global selection does not allow to select different data nodes in different views -# the selection order for multi-node selection might be important, which can be cumbersome to achieve via the data manager -# the local selection does not offer enough flexibility: -# it does not allow to propagate data node selections -# it does not allow multi node selection (multiple combo boxes are needed) -# it does not show the visibility / hierarchy of the data nodes The latest trend was to change the design of the view of the MITK workbench so that the local concept (using the QmitkDataStorageComboBox) was used wherever possible. This was done since the problems of the global selection concept where severe. In cases where the local concept was used positive feedback was received. \section NewSelectionConcept New selection concept The new selection concept is based on the idea of a local selection concept. This accounts for some fundamental requirements, such as individual data node selection for each view and data node filtering. Furthermore it clearly defines the responsibility of the data manager view: the data manager is only used to manage the data to render, e.g. defining the node hierarchy (rendering order) or setting the color or transparency of the pixel data. Additionally the new local selection concept is also able to overcome the problems of the previous local concept: It allows data node selection propagation, multi node selection and is able to show additional information such as data node hierarchy or node visibility. How this is achieved will be explained in the following sections. \subsection BasicIdea Basic idea The basic idea is to provide a set of classes that define the basic functionality of the new selection concept. These classes allow the use of existing and the development of new data storage inspectors or node selection widgets.
\imageMacro{selection_concept_class_diagram.png, "", 16}
Included in this concept is a set of basic data storage inspectors and node selection widgets that are frequently needed. A developer can extend these classes to create own data storage inspectors or node selection widgets to customize a plugins behavior and design. The following paragraphs further describe the most important classes: \b QmitkAbstractDataStorageModel The QmitkAbstractDataStorageModel extends the QAbstractItemModel to provide a custom item model for the data storage. This custom item model extends the Qt-model functionality in order to accept an mitk::DataStorage and an mitk::NodePredicateBase. The data storage is used to define on which data storage the model operates. In order to update the data storage model if the data storage changes, the QmitkAbstractDataStorageModel provides four pure virtual functions, QAbstractItemModel::DataStorageChanged, QAbstractItemModel::NodeAdded, QAbstractItemModel::NodeChanged and QAbstractItemModel::NodeRemoved. This abstract model calls the first function if the data storage has been reset using the SetDataStorage-function (i.e. to a new data storage or to a nullptr). The last three functions are connected to the corresponding events of the data storage (AddNodeEvent, ChangedNodeEvent and RemoveNodeEvent). The node predicate can be set and used to filter the data storage, so that only a subset of the contained data nodes is represented by the data storage model. In order to update the data storage model if the node predicate changes, the QmitkAbstractDataStorageModel provides a pure virtual function, QAbstractItemModel::NodePredicateChanged. This abstract model calls this function if the node predicate has been reset using the SetNodePredicate-function (i.e. to a new node predicate or to a nullptr). Any subclass of this abstract data storage model can define its own functionality by overriding the five corresponding functions. The abstract data storage model does not implement any Qt model functionality, so the functions of the QAbstractItemModel have to be overwritten in the subclasses, according to the model type (e.g. list model, table model). \b QmitkAbstractDataStorageInspector The QmitkAbstractDataStorageInspector serves as a base class that can be derived from to provide a custom view onto the data storage using a QmitkAbstractDataStorageModel derivative. This custom widget extends the QWidget functionality in order to accept an mitk::DataStorage and an mitk::NodePredicateBase. The data storage is used to define which data storage the widget should inspect. The node predicate can be set and later be used to filter the data storage, so that only a subset of the contained data nodes is inspected by the data storage inspector. The data storage and the node predicate can be set by the corresponding setter, which in turn calls the pure virtual function QmitkAbstractDataStorageInspector::Initialize. Any subclass of this abstract data storage inspector can now define its own functionality inside the Initialize-function to define what happens if the data storage or the node predicate is (re-)set. Typically an inspector will forward the data storage and the node predicate to the data storage model to make it aware of the data it should hold. Additionally a data storage inspector holds a QmitkModelViewSelectionConnector and initializes it with a QAbstractItemView derived class (e.g. a QListView) and the data storage model. The idea behind this connector-class will be explained in the next section. Furthermore the abstract class provides a QSignal, CurrentSelectionChanged(NodeList), that is emitted if the selection of the underlying data storage model has changed. The abstract class also provides two QSlots, SetSelectOnlyVisibleNodes(bool) and SetCurrentSelection(NodeList). Calling these slots will forward the given arguments to the model view selection connector member which in turn can manipulate the data storage models selection. \b QmitkModelViewSelectionConnector The QmitkModelViewSelectionConnector is used to transform a model selection into a list of selected data nodes and vice versa. The class accepts a QAbstractItemView with a corresponding QmitkAbstractDataStorageModel that operates on a data storage. The connector class provides a QSlot, QmitkModelViewSelectionConnector::ChangeModelSelection(const QItemSelection\&, const QItemSelection\&) that is called if the selectionChanged-signal of the selection model of the given QAbstractItemView is emitted. This indicates a change in the model selection. The slot itself will emit a QSignal, QmitkModelViewSelectionConnector::CurrentSelectionChanged(QList), where the selection of the item view has been transformed to a list of selected data nodes. The transformation is done by using the member functions QmitkModelViewSelectionConnector::GetSelectedNodes and QmitkModelViewSelectionConnector::GetInternalSelectedNodes: The selected indices of the item view's selection model are used to receive the corresponding data node from the data storage model. Additionally the connector class provides a function QmitkModelViewSelectionConnector::SetCurrentSelection(QList), which can be used to change the selection of the QAbstractItemView from outside of this class. The nodes of the list are compared to the nodes that are valid for the data storage model, according to the current node predicate. If the given nodes are valid the corresponding indices are selected in the view. If the given list is equal to the current selection, nothing happens. Using the QmitkModelViewSelectionConnector::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) function it is possible to set a variable that defines if only those nodes should be de-/selectable that are included in the list of filtered data nodes. This means that a new selection ca be received, which might change the current selection of the view. However, those nodes that are not visible, as defined by the node predicate of the data storage model, will not be de-/selectable. \b \anchor QmitkSelectionServiceConnector_ref QmitkSelectionServiceConnector The QmitkSelectionServiceConnector is used to interact with the global selection bus: It provides a private QSlot, QmitkSelectionServiceConnector::OnServiceSelectionChanged(const berry::IWorkbenchPart::Pointer&, const berry::ISelection::ConstPointer&), which is internally called if the selection of the selection bus has been changed. This slot transforms the berry selection into a list of selected data nodes and emits the QSignal QmitkSelectionServiceConnector::ServiceSelectionChanged(QList). Typically this signal is used to react in another class on the change of selected nodes from the selection bus, e.g. inside the QmitkModelViewSelectionConnector to change the selection of an item view via the selection bus. Additionally the connector class provides a function, QmitkSelectionServiceConnector::SetAsSelectionProvider(QmitkDataNodeSelectionProvider*), which can be used to set the connector as a provider for data node selections that will be sent via the global selection bus. This way a QmitkModelViewSelectionConnector can propagate its selection to all listeners of the selection bus via the QmitkSelectionServiceConnector. The following code shows how the two connector classes can be connected: \code void QmitkDataStorageViewerTestView::SetAsSelectionProvider(bool enable) { if (enable) { m_SelectionServiceConnector->SetAsSelectionProvider(GetSite()->GetSelectionProvider().Cast().GetPointer()); connect(m_ModelViewSelectionConnector.get(), SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector.get(), SLOT(ChangeServiceSelection(QList))); } else { m_SelectionServiceConnector->RemoveAsSelectionProvider(); disconnect(m_ModelViewSelectionConnector.get(), SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector.get(), SLOT(ChangeServiceSelection(QList))); } } \endcode
\code void QmitkDataStorageViewerTestView::SetAsSelectionListener(bool enable) { if (enable) { m_SelectionServiceConnector->AddPostSelectionListener(GetSite()->GetWorkbenchWindow()->GetSelectionService()); connect(m_SelectionServiceConnector.get(), SIGNAL(ServiceSelectionChanged(QList)), m_ModelViewSelectionConnector.get(), SLOT(SetCurrentSelection(QList))); } else { m_SelectionServiceConnector->RemovePostSelectionListener(); disconnect(m_SelectionServiceConnector.get(), SIGNAL(ServiceSelectionChanged(QList)), m_ModelViewSelectionConnector.get(), SLOT(SetCurrentSelection(QList))); } } \endcode \subsection DataStorageInspectors The data storage inspectors \b \anchor QmitkNodeSelectionDialog_ref QmitkNodeSelectionDialog The QmitkNodeSelectionDialog is the main widget to be used in order to select data nodes from the data storage. It is a pop-up-dialog that can be included in any other widget, such as the QmitkSingleNodeSelectionWidget or the QmitkMultiNodeSelectionWidget. The node selection dialog serves as a container for different QmitkAbstractDataStorageInspector: It uses a QTabWidget that holds the different data storage inspectors. These inspectors are received by using the mitk::DataStorageInspectorGenerator class. Each data storage inspector is then added to the tab widget and its \a CurrentSelectionChanged-signal is connected to the dialog's \a OnSelectionChanged-slot. If the selection inside a data storage inspector changes, the slot sets the selected nodes of the dialog and propagates this selection to all its known data storage inspectors. This way all inspectors that are currently held in the tab widget show the same selection. In order to dynamically add and receive new data storage inspectors the microservice approach is used: Each concrete implementation of a data storage inspector provider registers itself as an mitk::IDataStorageInspectorProvider via the service registry. For this the QmitkDataStorageInspectorProviderBase can be used. Any class can use the mitk::DataStorageInspectorGenerator to either receive all registered data storage inspector providers or a specific one. A provider in turn provides a specific data storage inspector, which can be used to display the data nodes of the data storage. The user can define which of the registered data storage inspectors should be available when using a QmitkNodeSelectionDialog: Using the workbench preferences one can select the Node Selection entry and enable or disable certain data storage inspectors. \b mitk::IDataStorageInspectorProvider The mitk::IDataStorageInspectorProvider declares the service interface for all data storage inspector providers. It must be implemented to override the mitk::IDataStorageInspectorProvider::CreateInspector-function. This function should return the concrete data storage inspector created by the provider. In order to simplify the use of this interface and to add some basic functionality, the QmitkDataStorageInspectorProviderBase class should be used. \b QmitkDataStorageInspectorProviderBase The QmitkDataStorageInspectorProviderBase implements the mitk::IDataStorageInspectorProvider-interface and is a template implementation: It can be used with a concrete implementation of the QmitkAbstractDataStorageInspector; the data storage inspector that the provider base should create. When the provider base is initialized it registers itself as an mitk::IDataStorageInspectorProvider service reference. The provider base overrides the mitk::IDataStorageInspectorProvider::CreateInspector-function of the interface to create and return a concrete instance of the provided data storage inspector. This way each concrete data storage inspector can be created by receiving the corresponding data storage inspector provider as a service and using the mitk::IDataStorageInspectorProvider::CreateInspector-function. \b mitk::DataStorageInspectorGenerator The mitk::DataStorageInspectorGenerator simply provides two static functions to receive all or a specific data storage provider. These providers have been registered before as an mitk::IDataStorageInspectorProvider service. Using the microservice approach the provider can be received without any further knowledge about the concrete provider. This way a developer can easily add their own concrete data storage inspector by creating a new QmitkDataStorageInspectorProviderBase with the concrete inspector as the template argument. \subsection CustomDataStorageInspector Adding a custom data storage inspector As mentioned above, the microservice approach is used inside the mitk::DataStorageInspectorGenerator to receive all known or a specific data storage provider. In order to let the microservice know about a new custom data storage inspector, it has to be provided by a data storage provider. This data storage provider has to be registered as an mitk::IDataStorageInspectorProvider service. The new selection concept provides the QmitkDataStorageInspectorProviderBase class (see above), which automatically registers the data storage provider as a provider service. For this the following constructor can be used: \code QmitkDataStorageInspectorProviderBase(const std::string& id, const std::string& displayName, const std::string& desc= "") \endcode The constructor can be used like this: \code mitk::IDataStorageInspectorProvider* dataStorageInspectorProvider = new QmitkDataStorageInspectorProviderBase("org.mitk.QmitkDataStorageListInspector", "Simple list", "Displays the filtered content of the data storage in a simple list.")); \endcode This registers a new QmitkDataStorageInspectorProviderBase instance as an mitk::IDataStorageInspectorProvider service. The data storage provider and its specific data storage inspector can later be received using the following code: \code mitk::IDataStorageInspectorProvider* dataStorageProvider = mitk::DataStorageInspectorGenerator::GetProvider("org.mitk.QmitkDataStorageListInspector"); QmitkAbstractDataStorageInspector* dataStorageInspector = dataStorageProvider->CreateInspector(); \endcode In the code snippets the QmitkDataStorageListInspector class was used. This is an example of a concrete data storage inspector which is provided by the presented selection concept. It is a frequently used data storage inspector and already registered via a corresponding provider base. This is done inside the mitk::QtWidgetsActivator class; a class that is used during module activation. Currently four frequently used custom data storage inspectors are already registered. The following sections describe these four frequently used basic inspectors. \subsubsection QmitkDataStorageListInspector The QmitkDataStorageListInspector is an example of a concrete data storage inspector, subclassing the QmitkAbstractDataStorageInspector. Its only purpose is to provide a custom model-view pair that represents a list view onto the data storage. The view is a simple QListView. The model is a custom model derived from the above mentioned QmitkAbstractDataStorageModel: The QmitkDataStorageDefaultListModel overrides the five pure virtual functions to react on changes of the data storage or the node predicate: each function calls the private UpdateModelData-function, which will simply retrieve the currently available (possibly filtered) data nodes of the data storage. Additionally the default list model needs to override some functions of the QAbstractItemModel in order to represent a list model. One important function to override is the data(const QModelIndex\& index, int role = Qt::DisplayRole)}-function: This function is used by Qt to define what has to be displayed in the list view. It is important that a custom model returns an mitk::DataNode::Pointer object for a model index when the role is mitkDataNodeRole. \subsubsection QmitkDataStorageTreeInspector The QmitkDataStorageTreeInspector is another example of a concrete data storage inspector, subclassing the QmitkAbstractDataStorageInspector. Its only purpose is to provide a custom model-view pair that represents a tree view onto the data storage. The view is a simple QTreeView. The model is a custom model derived from the above mentioned QmitkAbstractDataStorageModel: The QmitkDataStorageSimpleTreeModel needs to override some functions of the QAbstractItemModel in order to represent a tree model. Again, one important function to override is the data(const QModelIndex\& index, int role = Qt::DisplayRole)}-function. It is important that the simple tree model returns an mitk::DataNode::Pointer object for a model index when the role is mitkDataNodeRole. The QmitkDataStorageTreeInspector is designed to reflect the classical data manager view. \subsubsection QmitkDataStorageSelectionHistoryInspector The QmitkDataStorageSelectionHistoryInspector is a concrete data storage inspector that allows to view the recently used nodes of the data storage. It uses the same QmitkDataStorageDefaultListModel as the QmitkDataStorageListInspector. The QmitkDataStorageSelectionHistoryInspector provides a function to add nodes to the selection history. The selection history will be displayed in chronological order and a selected node will only appear once in the history list. \subsubsection QmitkDataStorageFavoriteNodesInspector The QmitkDataStorageFavoriteNodesInspector is a concrete data storage inspector that allows to view a user's favorite nodes of the data storage. It extends the QmitkDataStorageListInspector. The QmitkNodeSelectionDialog provides a function to set nodes as favorite nodes using a specific node property. It allows the QmitkDataStorageFavoriteNodesInspector to use a customized node predicate to filter nodes according to their favorite-property-state. This favorite-property-state is defined by the node property "org.mitk.selection.favorite" The QmitkDataStorageFavoriteNodesInspector provides a function to unset nodes as favorite nodes by setting this specific node property to "false", so that they won't appear anymore in the list of favorite nodes. \subsection NodeSelectionWidgets The node selection widgets \b QmitkAbstractNodeSelectionWidget The QmitkAbstractNodeSelectionWidget extends the QWidget to provide a custom widget to show data nodes after they have been selected using the QmitkNodeSelectionDialog with its data storage inspectors. This custom widget extends the QWidget functionality in order to accept an mitk::DataStorage and an mitk::NodePredicateBase. The data storage is used to define which data storage should be used by the selection dialog. The node predicate is used to filter the data storage. Any subclass of this abstract node selection widget needs to override the following functions in order to customize its behavior: - void QmitkAbstractNodeSelectionWidget::SetCurrentSelection(NodeList), in order to set the selection of this widget given an external list of selected nodes. This function may be customized to filter the incoming selected nodes. - void QmitkAbstractNodeSelectionWidget::UpdateInfo(), in order to set the information text and enable / disable the control buttons according to the current selection. - void QmitkAbstractNodeSelectionWidget::OnNodePredicateChanged(), in order to react to a change of the used node predicate. Changing the node predicate might alter the selection. This function is called if QmitkAbstractNodeSelectionWidget::SetNodePredicate(mitk::NodePredicateBase*) was called. - void QmitkAbstractNodeSelectionWidget::OnDataStorageChanged(), in order to react to a change of the used data storage. Changing the data storage might alter the selection. This function is called if QmitkAbstractNodeSelectionWidget::SetDataStorage(mitk::DataStorage*) was called. Furthermore QmitkAbstractNodeSelectionWidget::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) can be overridden to set the modus to (not) include invisible nodes in the selection. Default value is true. \b QmitkSingleNodeSelectionWidget The QmitkSingleNodeSelectionWidget is an example of a concrete node selection widget, subclassing the QmitkAbstractNodeSelectionWidget. It overrides the virtual functions to react on changes of the node selection. If the QmitkNodeSelectionButton of the widget is pressed, a QmitkNodeSelectionDialog is opened as a pop-up for data node selection. This dialog is a \ref QmitkNodeSelectionDialog_ref "QmitkNodeSelectionDialog" (see \ref DataStorageInspectors). It presents the currently known and active data storage inspectors for the user to select a single data node. If a selection is confirmed, the pop-up closes and the selected data node will be shown in the QmitkSingleNodeSelectionWidget. The user will see a thumbnail or an icon of the data node (if available) along with an HTML text of the data node info. The QmitkSingleNodeSelectionWidget is currently used inside plugin views to allow to select specific nodes of the data storage for further processing. A plugin view can connect a function to the CurrentSelectionChanged-signal to immediately react on a new selection of the QmitkSingleNodeSelectionWidget. Using QmitkSingleNodeSelectionWidget::GetSelectedNode the currently selected node of the selection widget can be retrieved anytime. Additionally an auto-selection-mode is available that automatically selects a node from the data storage if such a data storage is set and contains a node that matches the given predicate. The auto-selection-mode only works if the QmitkSingleNodeSelectionWidget does not already show a selected node. \b QmitkMultiNodeSelectionWidget The QmitkMultiNodeSelectionWidget is another example of a concrete node selection widget, subclassing the QmitkAbstractNodeSelectionWidget. It overrides the virtual functions to react on changes of the node selection. If the 'Change selection'-button is pressed a QmitkNodeSelectionDialog is opened as a pop-up for data node selection. This dialog is a \ref QmitkNodeSelectionDialog_ref "QmitkNodeSelectionDialog" (see \ref DataStorageInspectors). It presents the currently known and active data storage inspectors for the user to select a single data node. If a selection is confirmed, the pop-up closes and the selected data nodes will be shown in the QmitkMultiNodeSelectionWidget. Unlike single node selection the multi node selection is presented as a list of all the selected nodes. The QmitkMultiNodeSelectionWidget is currently used inside plugin views to allow to select a set of specific nodes of the data storage for further processing. A plugin view can connect a function to the CurrentSelectionChanged-signal to immediately react on a new selection of the QmitkMultiNodeSelectionWidget. Using QmitkAbstractNodeSelectionWidget::GetSelectedNodes the currently selected node of the selection widget can be retrieved anytime. QmitkMultiNodeSelectionWidget::SetSelectionCheckFunction allows to define a function that puts a constraint on the node selection (dialog) to only allow specific combinations or seletions of nodes. The result of the constraint check has to be either an empty string (indicating a valid node selection) or a string that explains the error / constraint violation. A simple check function can look like this: \code auto checkFunction = [](const QmitkMultiNodeSelectionWidget::NodeList & nodes) { if (!(nodes.size() % 2)) { std::stringstream ss; - ss << "

Invalid selection.

The number of selected nodes must be uneven! the current number is " << nodes.size() << ".

"; + ss << "

Invalid selection.

The number of selected nodes must be uneven! the current number is " << nodes.size() << ".

"; return ss.str(); } return std::string(); }; multNodeSelectionWidget->SetSelectionCheckFunction(checkFunction); \endcode This check function will be passed to the QmitkNodeSelectionDialog and is used to print an error message, if an invalid selection is made inside the node selection dialog. This will prevent the user from confirming an even selection. If a valid selection is made no error message will be printed and the user can confirm the selection. \b QmitkNodeSelectionButton The QmitkNodeSelectionButton is a customized QPushButton and is used for example inside the QmitkSingleNodeSelectionWidget: It displays the thumbnail or icon of the selected data node (if available) along with an HTML text of the data node info. \section DataStorageViewerTestPlugin The DataStorageViewerTest plugin The \a org.mitk.gui.qt.datastorageviewertest plugin can be enabled and used inside the MITK workbench. It serves as a test / demo plugin with a single view that shows different uses of the new selection concept and its related classes. The following classes are used: -# Top row: A QmitkDataStorageListInspector -# Top right: A QmitkDataStorageTreeInspector -# Bottom left: A QmitkSingleNodeSelectionWidget -# Bottom right: A QmitkMultiNodeSelectionWidget The top row presents the two examples of an implementation of the QmitkAbstractDataStorageInspector. They display the whole content of the given data storage in two different ways. No node predicates are used in this case. Both inspectors come with two checkboxes to set each inspectors as a selection provider and a selection listener. With these checkboxes turned on the QmitkSelectionServiceConnector for each inspector is connected to the QmitkModelViewSelectionConnector of each inspector (as shown in \ref QmitkSelectionServiceConnector_ref "QmitkSelectionServiceConnector").
See how the selection also changes in the inspectors if nodes are selected in the mitk::DataManager and the Set as selection listener-checkbox is checked for the inspector. The bottom row presents the two examples of an implementation of the QmitkAbstractNodeSelectionWidget: They display a specific data node selection that was made by the user. Both widgets come with several checkboxes to modify the behavior of the selection widgets. */ diff --git a/Modules/AlgorithmsExt/include/mitkMaskAndCutRoiImageFilter.h b/Modules/AlgorithmsExt/include/mitkMaskAndCutRoiImageFilter.h index be17583bbb..195fa6675b 100644 --- a/Modules/AlgorithmsExt/include/mitkMaskAndCutRoiImageFilter.h +++ b/Modules/AlgorithmsExt/include/mitkMaskAndCutRoiImageFilter.h @@ -1,77 +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. ============================================================================*/ #ifndef mitkMaskAndCutRoiImageFilter_h #define mitkMaskAndCutRoiImageFilter_h #include "MitkAlgorithmsExtExports.h" #include "mitkImageToImageFilter.h" #include "itkRegionOfInterestImageFilter.h" #include "mitkAutoCropImageFilter.h" #include "mitkBoundingObject.h" #include "mitkDataNode.h" #include "mitkMaskImageFilter.h" namespace mitk { /** \brief Cuts a region of interest (ROI) out of an image In the first step, this filter reduces the image region of the given ROI to a minimum. Using this region, a subvolume ist cut out of the given input image. The ROI is then used to mask the subvolume. Pixel inside the ROI will have their original value, pixel outside will be replaced by m_OutsideValue */ class MITKALGORITHMSEXT_EXPORT MaskAndCutRoiImageFilter : public ImageToImageFilter { typedef itk::Image ItkImageType; typedef itk::Image ItkMaskType; typedef itk::ImageRegion<3> RegionType; typedef itk::RegionOfInterestImageFilter ROIFilterType; public: mitkClassMacro(MaskAndCutRoiImageFilter, ImageToImageFilter); itkFactorylessNewMacro(Self); itkCloneMacro(Self); - itkGetMacro(MaxValue, mitk::ScalarType); - itkGetMacro(MinValue, mitk::ScalarType); void SetRegionOfInterest(mitk::BaseData *roi); // void SetRegionOfInterest(Image::Pointer image); // void SetRegionOfInterest(BoundingObject::Pointer boundingObject); // void SetRegionOfInterestByNode(mitk::DataNode::Pointer node); // temporary fix for bug # mitk::Image::Pointer GetOutput(); protected: MaskAndCutRoiImageFilter(); ~MaskAndCutRoiImageFilter() override; void GenerateData() override; ROIFilterType::Pointer m_RoiFilter; mitk::AutoCropImageFilter::Pointer m_CropFilter; mitk::MaskImageFilter::Pointer m_MaskFilter; // needed for temporary fix mitk::Image::Pointer m_outputImage; - mitk::ScalarType m_MaxValue; - mitk::ScalarType m_MinValue; - }; // class } // namespace #endif diff --git a/Modules/AlgorithmsExt/include/mitkMaskImageFilter.h b/Modules/AlgorithmsExt/include/mitkMaskImageFilter.h index ced7d4cb2b..9a8e1b1482 100644 --- a/Modules/AlgorithmsExt/include/mitkMaskImageFilter.h +++ b/Modules/AlgorithmsExt/include/mitkMaskImageFilter.h @@ -1,111 +1,93 @@ /*============================================================================ 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 mitkMaskImageFilter_h #define mitkMaskImageFilter_h #include "MitkAlgorithmsExtExports.h" #include "mitkCommon.h" -#include "mitkImageTimeSelector.h" #include "mitkImageToImageFilter.h" #include "itkImage.h" namespace mitk { //##Documentation //## @brief //## @ingroup Process class MITKALGORITHMSEXT_EXPORT MaskImageFilter : public ImageToImageFilter { public: mitkClassMacro(MaskImageFilter, ImageToImageFilter); itkFactorylessNewMacro(Self); itkCloneMacro(Self); - void SetMask(const mitk::Image *mask); - const mitk::Image *GetMask() const; - - /** - * get/set the min Value of the original image in the masked area - **/ - itkGetMacro(MinValue, mitk::ScalarType); - itkSetMacro(MinValue, mitk::ScalarType); - - /** - * get/set the max Value of the original image in the masked area - **/ - itkGetMacro(MaxValue, mitk::ScalarType); - itkSetMacro(MaxValue, mitk::ScalarType); + void SetMask(const mitk::Image *mask); + const Image *GetMask() const; + Image* GetMask(); /** * This value is used as outside value. This only works * if OverrideOutsideValue is set to true. Default is 0. **/ itkSetMacro(OutsideValue, mitk::ScalarType); /** * This value is used as outside value. This only works * if OverrideOutsideValue is set to true. Default is 0. */ itkGetMacro(OutsideValue, mitk::ScalarType); /** * If OverrideOutsideValue is set to false, this minimum * of the pixel type of the output image is taken as outside * value. If set to true, the value set via SetOutsideValue is * used as background. */ itkSetMacro(OverrideOutsideValue, bool); /** * If OverrideOutsideValue is set to false, this minimum * of the pixel type of the output image is taken as outside * value. If set to true, the value set via SetOutsideValue is * used as background. */ itkGetMacro(OverrideOutsideValue, bool); itkBooleanMacro(OverrideOutsideValue); protected: MaskImageFilter(); ~MaskImageFilter() override; void GenerateInputRequestedRegion() override; void GenerateOutputInformation() override; void GenerateData() override; - template - void InternalComputeMask(itk::Image *itkImage); - - mitk::Image::Pointer m_Mask; - mitk::ImageTimeSelector::Pointer m_InputTimeSelector; - mitk::ImageTimeSelector::Pointer m_MaskTimeSelector; - mitk::ImageTimeSelector::Pointer m_OutputTimeSelector; + template + void InternalComputeMask(itk::Image* itkInput, itk::Image* itkMask); //##Description //## @brief Time when Header was last initialized itk::TimeStamp m_TimeOfHeaderInitialization; mitk::ScalarType m_OutsideValue; - mitk::ScalarType m_MinValue; - mitk::ScalarType m_MaxValue; + TimeStepType m_CurrentOutputTS; bool m_OverrideOutsideValue; }; } // namespace mitk #endif diff --git a/Modules/AlgorithmsExt/include/mitkPadImageFilter.h b/Modules/AlgorithmsExt/include/mitkPadImageFilter.h index cd0d63d72f..d83b134489 100644 --- a/Modules/AlgorithmsExt/include/mitkPadImageFilter.h +++ b/Modules/AlgorithmsExt/include/mitkPadImageFilter.h @@ -1,68 +1,71 @@ /*============================================================================ 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 mitkPadImageFilter_h #define mitkPadImageFilter_h #include "MitkAlgorithmsExtExports.h" #include "mitkCommon.h" #include "mitkImageTimeSelector.h" #include "mitkImageToImageFilter.h" #include "itkImage.h" namespace mitk { /** * \brief PadImageFilter class pads the first input image to the size of the second input image. * Two Images have to be set. * The first image is the image to pad. The second image defines the pad size. * It is also possible to use an included binary filter. * * \ingroup Process */ class MITKALGORITHMSEXT_EXPORT PadImageFilter : public ImageToImageFilter { public: mitkClassMacro(PadImageFilter, ImageToImageFilter); itkFactorylessNewMacro(Self); itkCloneMacro(Self); /** \brief Sets the intensity of the pixel to pad */ itkSetMacro(PadConstant, int); /** \brief sets the binary filter ON or OFF */ itkSetMacro(BinaryFilter, bool); /** \brief Sets the lower threshold of the included binary filter */ itkSetMacro(LowerThreshold, int); /** \brief Sets the upper threshold of the included binary filter */ itkSetMacro(UpperThreshold, int); protected: PadImageFilter(); ~PadImageFilter() override; void GenerateData() override; private: + template + void GenerateDataInternal(SourceImageType* sourceItkImage, mitk::Image::Pointer outputImage); + bool m_BinaryFilter; int m_PadConstant, m_LowerThreshold, m_UpperThreshold; }; } // namespace mitk #endif diff --git a/Modules/AlgorithmsExt/src/mitkMaskAndCutRoiImageFilter.cpp b/Modules/AlgorithmsExt/src/mitkMaskAndCutRoiImageFilter.cpp index 255d1316e1..eb3490c4a7 100644 --- a/Modules/AlgorithmsExt/src/mitkMaskAndCutRoiImageFilter.cpp +++ b/Modules/AlgorithmsExt/src/mitkMaskAndCutRoiImageFilter.cpp @@ -1,92 +1,90 @@ /*============================================================================ 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 "mitkMaskAndCutRoiImageFilter.h" #include "mitkBoundingObjectToSegmentationFilter.h" #include "mitkImageCast.h" mitk::MaskAndCutRoiImageFilter::MaskAndCutRoiImageFilter() { this->SetNumberOfRequiredInputs(2); m_CropFilter = mitk::AutoCropImageFilter::New(); m_RoiFilter = ROIFilterType::New(); m_MaskFilter = mitk::MaskImageFilter::New(); } mitk::MaskAndCutRoiImageFilter::~MaskAndCutRoiImageFilter() { } void mitk::MaskAndCutRoiImageFilter::SetRegionOfInterest(mitk::BaseData *roi) { mitk::Image::Pointer image = dynamic_cast(roi); if (image.IsNotNull()) { this->SetInput(1, image); return; } mitk::BoundingObject::Pointer boundingObject = dynamic_cast(roi); if (boundingObject.IsNotNull() && this->GetInput(0) != nullptr) { mitk::BoundingObjectToSegmentationFilter::Pointer filter = mitk::BoundingObjectToSegmentationFilter::New(); filter->SetBoundingObject(boundingObject); filter->SetInput(this->GetInput(0)); filter->Update(); this->SetInput(1, filter->GetOutput()); return; } } mitk::Image::Pointer mitk::MaskAndCutRoiImageFilter::GetOutput() { return m_outputImage; } void mitk::MaskAndCutRoiImageFilter::GenerateData() { mitk::Image::ConstPointer inputImage = this->GetInput(0); mitk::Image::ConstPointer maskImage = this->GetInput(1); // mitk::Image::Pointer outputImage = this->GetOutput(); // temporary fix for bug # m_outputImage = this->GetOutput(); ItkImageType::Pointer itkImage = ItkImageType::New(); mitk::Image::Pointer tmpImage = mitk::Image::New(); m_CropFilter->SetInput(maskImage); m_CropFilter->SetBackgroundValue(0); m_CropFilter->Update(); RegionType region = m_CropFilter->GetCroppingRegion(); mitk::CastToItkImage(inputImage, itkImage); m_RoiFilter->SetInput(itkImage); m_RoiFilter->SetRegionOfInterest(region); m_RoiFilter->Update(); mitk::CastToMitkImage(m_RoiFilter->GetOutput(), tmpImage); m_MaskFilter->SetInput(0, tmpImage); m_MaskFilter->SetMask(m_CropFilter->GetOutput()); m_MaskFilter->SetOutsideValue(-32765); m_MaskFilter->Update(); - m_MaxValue = m_MaskFilter->GetMaxValue(); - m_MinValue = m_MaskFilter->GetMinValue(); // temporary fix for bug # m_outputImage = m_MaskFilter->GetOutput(); m_outputImage->DisconnectPipeline(); } diff --git a/Modules/AlgorithmsExt/src/mitkMaskImageFilter.cpp b/Modules/AlgorithmsExt/src/mitkMaskImageFilter.cpp index c4d13bff6c..070345dbf0 100644 --- a/Modules/AlgorithmsExt/src/mitkMaskImageFilter.cpp +++ b/Modules/AlgorithmsExt/src/mitkMaskImageFilter.cpp @@ -1,241 +1,129 @@ /*============================================================================ 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 "mitkMaskImageFilter.h" #include "mitkImageTimeSelector.h" #include "mitkProperties.h" #include "mitkTimeHelper.h" +#include "mitkImageTimeSelector.h" #include "mitkImageAccessByItk.h" #include "mitkImageToItk.h" -#include "itkImageRegionConstIterator.h" -#include "itkImageRegionIteratorWithIndex.h" +#include "itkMaskImageFilter.h" #include -mitk::MaskImageFilter::MaskImageFilter() : m_Mask(nullptr) +mitk::MaskImageFilter::MaskImageFilter() { this->SetNumberOfIndexedInputs(2); this->SetNumberOfRequiredInputs(2); - m_InputTimeSelector = mitk::ImageTimeSelector::New(); - m_MaskTimeSelector = mitk::ImageTimeSelector::New(); - m_OutputTimeSelector = mitk::ImageTimeSelector::New(); m_OverrideOutsideValue = false; m_OutsideValue = 0; + m_CurrentOutputTS = 0; } mitk::MaskImageFilter::~MaskImageFilter() { } void mitk::MaskImageFilter::SetMask(const mitk::Image *mask) { // Process object is not const-correct so the const_cast is required here - m_Mask = const_cast(mask); - this->ProcessObject::SetNthInput(1, m_Mask); + auto nonconstMask = const_cast(mask); + this->ProcessObject::SetNthInput(1, nonconstMask); } const mitk::Image *mitk::MaskImageFilter::GetMask() const { - return m_Mask; + return this->GetInput(1); +} + +mitk::Image* mitk::MaskImageFilter::GetMask() +{ + return this->GetInput(1); } void mitk::MaskImageFilter::GenerateInputRequestedRegion() { Superclass::GenerateInputRequestedRegion(); mitk::Image *output = this->GetOutput(); mitk::Image *input = this->GetInput(); - mitk::Image *mask = m_Mask; + mitk::Image *mask = this->GetMask(); if ((output->IsInitialized() == false) || (mask == nullptr) || (mask->GetTimeGeometry()->CountTimeSteps() == 0)) return; input->SetRequestedRegionToLargestPossibleRegion(); mask->SetRequestedRegionToLargestPossibleRegion(); GenerateTimeInInputRegion(output, input); - GenerateTimeInInputRegion(output, mask); } void mitk::MaskImageFilter::GenerateOutputInformation() { mitk::Image::ConstPointer input = this->GetInput(); mitk::Image::Pointer output = this->GetOutput(); if ((output->IsInitialized()) && (this->GetMTime() <= m_TimeOfHeaderInitialization.GetMTime())) return; itkDebugMacro(<< "GenerateOutputInformation()"); output->Initialize(input->GetPixelType(), *input->GetTimeGeometry()); output->SetPropertyList(input->GetPropertyList()->Clone()); m_TimeOfHeaderInitialization.Modified(); } -template -void mitk::MaskImageFilter::InternalComputeMask(itk::Image *inputItkImage) +template +void mitk::MaskImageFilter::InternalComputeMask(itk::Image* itkInput, itk::Image* itkMask) { - // dirty quick fix, duplicating code so both unsigned char and unsigned short are supported - // this should be changed once unsigned char segmentations can be converted to unsigned short - mitk::PixelType pixelType = - m_MaskTimeSelector->GetOutput()->GetImageDescriptor()->GetChannelDescriptor().GetPixelType(); - if (pixelType.GetComponentType() == itk::IOComponentEnum::UCHAR) - { - typedef itk::Image ItkInputImageType; - typedef itk::Image ItkMaskImageType; - typedef itk::Image ItkOutputImageType; - - typedef itk::ImageRegionConstIterator ItkInputImageIteratorType; - typedef itk::ImageRegionConstIterator ItkMaskImageIteratorType; - typedef itk::ImageRegionIteratorWithIndex ItkOutputImageIteratorType; - - typename mitk::ImageToItk::Pointer maskimagetoitk = mitk::ImageToItk::New(); - maskimagetoitk->SetInput(m_MaskTimeSelector->GetOutput()); - maskimagetoitk->Update(); - typename ItkMaskImageType::Pointer maskItkImage = maskimagetoitk->GetOutput(); - - typename mitk::ImageToItk::Pointer outputimagetoitk = - mitk::ImageToItk::New(); - outputimagetoitk->SetInput(m_OutputTimeSelector->GetOutput()); - outputimagetoitk->Update(); - typename ItkOutputImageType::Pointer outputItkImage = outputimagetoitk->GetOutput(); - - // create the iterators - typename ItkInputImageType::RegionType inputRegionOfInterest = inputItkImage->GetLargestPossibleRegion(); - ItkInputImageIteratorType inputIt(inputItkImage, inputRegionOfInterest); - ItkMaskImageIteratorType maskIt(maskItkImage, inputRegionOfInterest); - ItkOutputImageIteratorType outputIt(outputItkImage, inputRegionOfInterest); - - // typename ItkOutputImageType::PixelType outsideValue = itk::NumericTraits::min(); - if (!m_OverrideOutsideValue) - m_OutsideValue = itk::NumericTraits::min(); - - m_MinValue = std::numeric_limits::max(); - m_MaxValue = std::numeric_limits::min(); - - for (inputIt.GoToBegin(), maskIt.GoToBegin(), outputIt.GoToBegin(); !inputIt.IsAtEnd() && !maskIt.IsAtEnd(); - ++inputIt, ++maskIt, ++outputIt) - { - if (maskIt.Get() > itk::NumericTraits::Zero) - { - outputIt.Set(inputIt.Get()); - m_MinValue = std::min((float)inputIt.Get(), (float)m_MinValue); - m_MaxValue = std::max((float)inputIt.Get(), (float)m_MaxValue); - } - else - { - outputIt.Set(m_OutsideValue); - } - } - } - else - { - { - typedef itk::Image ItkInputImageType; - typedef itk::Image ItkMaskImageType; - typedef itk::Image ItkOutputImageType; - - typedef itk::ImageRegionConstIterator ItkInputImageIteratorType; - typedef itk::ImageRegionConstIterator ItkMaskImageIteratorType; - typedef itk::ImageRegionIteratorWithIndex ItkOutputImageIteratorType; - - typename mitk::ImageToItk::Pointer maskimagetoitk = mitk::ImageToItk::New(); - maskimagetoitk->SetInput(m_MaskTimeSelector->GetOutput()); - maskimagetoitk->Update(); - typename ItkMaskImageType::Pointer maskItkImage = maskimagetoitk->GetOutput(); - - typename mitk::ImageToItk::Pointer outputimagetoitk = - mitk::ImageToItk::New(); - outputimagetoitk->SetInput(m_OutputTimeSelector->GetOutput()); - outputimagetoitk->Update(); - typename ItkOutputImageType::Pointer outputItkImage = outputimagetoitk->GetOutput(); - - // create the iterators - typename ItkInputImageType::RegionType inputRegionOfInterest = inputItkImage->GetLargestPossibleRegion(); - ItkInputImageIteratorType inputIt(inputItkImage, inputRegionOfInterest); - ItkMaskImageIteratorType maskIt(maskItkImage, inputRegionOfInterest); - ItkOutputImageIteratorType outputIt(outputItkImage, inputRegionOfInterest); - - // typename ItkOutputImageType::PixelType outsideValue = itk::NumericTraits::min(); - if (!m_OverrideOutsideValue) - m_OutsideValue = itk::NumericTraits::min(); - - m_MinValue = std::numeric_limits::max(); - m_MaxValue = std::numeric_limits::min(); - - for (inputIt.GoToBegin(), maskIt.GoToBegin(), outputIt.GoToBegin(); !inputIt.IsAtEnd() && !maskIt.IsAtEnd(); - ++inputIt, ++maskIt, ++outputIt) - { - if (maskIt.Get() > itk::NumericTraits::Zero) - { - outputIt.Set(inputIt.Get()); - m_MinValue = std::min((float)inputIt.Get(), (float)m_MinValue); - m_MaxValue = std::max((float)inputIt.Get(), (float)m_MaxValue); - } - else - { - outputIt.Set(m_OutsideValue); - } - } - } - } + using MaskFilterType = itk::MaskImageFilter< itk::Image, itk::Image>; + + auto maskFilter = MaskFilterType::New(); + maskFilter->SetInput(itkInput); + maskFilter->SetMaskImage(itkMask); + maskFilter->SetOutsideValue(m_OutsideValue); + maskFilter->Update(); + + auto output = maskFilter->GetOutput(); + + // re-import to MITK + auto mitkOutput = this->GetOutput(); + mitkOutput->SetVolume(output->GetBufferPointer(), m_CurrentOutputTS); } void mitk::MaskImageFilter::GenerateData() { - mitk::Image::ConstPointer input = this->GetInput(); - mitk::Image::Pointer mask = m_Mask; + auto input = this->GetInput(); + auto mask = this->GetMask(); mitk::Image::Pointer output = this->GetOutput(); - if ((output->IsInitialized() == false) || (mask.IsNull()) || (mask->GetTimeGeometry()->CountTimeSteps() == 0)) + if ((output->IsInitialized() == false) || (nullptr == mask) || (mask->GetTimeGeometry()->CountTimeSteps() == 0)) return; - m_InputTimeSelector->SetInput(input); - m_MaskTimeSelector->SetInput(mask); - m_OutputTimeSelector->SetInput(this->GetOutput()); - - mitk::Image::RegionType outputRegion = output->GetRequestedRegion(); - const mitk::TimeGeometry *outputTimeGeometry = output->GetTimeGeometry(); const mitk::TimeGeometry *inputTimeGeometry = input->GetTimeGeometry(); - const mitk::TimeGeometry *maskTimeGeometry = mask->GetTimeGeometry(); - ScalarType timeInMS; - int timestep = 0; - int tstart = outputRegion.GetIndex(3); - int tmax = tstart + outputRegion.GetSize(3); - - int t; - for (t = tstart; t < tmax; ++t) + for (TimeStepType t = 0; t < inputTimeGeometry->CountTimeSteps(); ++t) { - timeInMS = outputTimeGeometry->TimeStepToTimePoint(t); - - timestep = inputTimeGeometry->TimePointToTimeStep(timeInMS); - - m_InputTimeSelector->SetTimeNr(timestep); - m_InputTimeSelector->UpdateLargestPossibleRegion(); - m_OutputTimeSelector->SetTimeNr(t); - m_OutputTimeSelector->UpdateLargestPossibleRegion(); - - timestep = maskTimeGeometry->TimePointToTimeStep(timeInMS); - m_MaskTimeSelector->SetTimeNr(timestep); - m_MaskTimeSelector->UpdateLargestPossibleRegion(); + auto timeInMS = inputTimeGeometry->TimeStepToTimePoint(t); - AccessByItk(m_InputTimeSelector->GetOutput(), InternalComputeMask); + m_CurrentOutputTS = t; + auto inputFrame = SelectImageByTimePoint(input, timeInMS); + auto maskFrame = SelectImageByTimePoint(mask, timeInMS); + AccessTwoImagesFixedDimensionByItk(inputFrame, maskFrame, InternalComputeMask, 3); } m_TimeOfHeaderInitialization.Modified(); } diff --git a/Modules/AlgorithmsExt/src/mitkPadImageFilter.cpp b/Modules/AlgorithmsExt/src/mitkPadImageFilter.cpp index 332f79e0b3..1da308c532 100644 --- a/Modules/AlgorithmsExt/src/mitkPadImageFilter.cpp +++ b/Modules/AlgorithmsExt/src/mitkPadImageFilter.cpp @@ -1,101 +1,105 @@ /*============================================================================ 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 "mitkPadImageFilter.h" #include "mitkImageCast.h" - +#include #include "itkBinaryThresholdImageFilter.h" #include "itkConstantPadImageFilter.h" mitk::PadImageFilter::PadImageFilter() { this->SetNumberOfIndexedInputs(2); this->SetNumberOfRequiredInputs(2); m_BinaryFilter = false; m_PadConstant = -32766; m_LowerThreshold = -32766; m_UpperThreshold = -32765; } mitk::PadImageFilter::~PadImageFilter() { } -void mitk::PadImageFilter::GenerateData() + +template +void mitk::PadImageFilter::GenerateDataInternal(SourceImageType* sourceItkImage, mitk::Image::Pointer outputImage) { - mitk::Image::ConstPointer image = this->GetInput(0); + mitk::Image::ConstPointer sourceImage = this->GetInput(0); mitk::Image::ConstPointer referenceImage = this->GetInput(1); - typedef itk::Image ImageType; - ImageType::Pointer itkImage = ImageType::New(); - mitk::CastToItkImage(image, itkImage); - - mitk::BaseGeometry *imageGeometry = image->GetGeometry(); + mitk::BaseGeometry* imageGeometry = sourceImage->GetGeometry(); mitk::Point3D origin = imageGeometry->GetOrigin(); mitk::Vector3D spacing = imageGeometry->GetSpacing(); - mitk::BaseGeometry *referenceImageGeometry = referenceImage->GetGeometry(); + mitk::BaseGeometry* referenceImageGeometry = referenceImage->GetGeometry(); mitk::Point3D referenceOrigin = referenceImageGeometry->GetOrigin(); double outputOrigin[3]; itk::SizeValueType padLowerBound[3]; itk::SizeValueType padUpperBound[3]; int i; for (i = 0; i < 3; ++i) { outputOrigin[i] = referenceOrigin[i]; padLowerBound[i] = static_cast((origin[i] - referenceOrigin[i]) / spacing[i] + 0.5); - padUpperBound[i] = referenceImage->GetDimension(i) - image->GetDimension(i) - padLowerBound[i]; + padUpperBound[i] = referenceImage->GetDimension(i) - sourceImage->GetDimension(i) - padLowerBound[i]; } // The origin of the input image is passed through the filter and used as // output origin as well. Hence, it needs to be overwritten accordingly. - itkImage->SetOrigin(outputOrigin); + sourceItkImage->SetOrigin(outputOrigin); - typedef itk::ConstantPadImageFilter PadFilterType; - PadFilterType::Pointer padFilter = PadFilterType::New(); - padFilter->SetInput(itkImage); + typedef itk::ConstantPadImageFilter PadFilterType; + typename PadFilterType::Pointer padFilter = PadFilterType::New(); + padFilter->SetInput(sourceItkImage); padFilter->SetConstant(m_PadConstant); padFilter->SetPadLowerBound(padLowerBound); padFilter->SetPadUpperBound(padUpperBound); - mitk::Image::Pointer outputImage = this->GetOutput(); - // If the Binary flag is set, use an additional binary threshold filter after // padding. if (m_BinaryFilter) { typedef itk::Image BinaryImageType; - typedef itk::BinaryThresholdImageFilter BinaryFilterType; - BinaryFilterType::Pointer binaryFilter = BinaryFilterType::New(); + typedef itk::BinaryThresholdImageFilter BinaryFilterType; + typename BinaryFilterType::Pointer binaryFilter = BinaryFilterType::New(); binaryFilter->SetInput(padFilter->GetOutput()); binaryFilter->SetLowerThreshold(m_LowerThreshold); binaryFilter->SetUpperThreshold(m_UpperThreshold); binaryFilter->SetInsideValue(1); binaryFilter->SetOutsideValue(0); binaryFilter->Update(); mitk::CastToMitkImage(binaryFilter->GetOutput(), outputImage); } else { padFilter->Update(); mitk::CastToMitkImage(padFilter->GetOutput(), outputImage); } +} + +void mitk::PadImageFilter::GenerateData() +{ + mitk::Image::Pointer image = this->GetInput(0); + mitk::Image::Pointer outputImage = this->GetOutput(); + + AccessFixedDimensionByItk_1(image, GenerateDataInternal, 3, outputImage); outputImage->SetRequestedRegionToLargestPossibleRegion(); } diff --git a/Modules/Core/include/mitkWeakPointer.h b/Modules/Core/include/mitkWeakPointer.h index a001e5742e..4ee116aa28 100644 --- a/Modules/Core/include/mitkWeakPointer.h +++ b/Modules/Core/include/mitkWeakPointer.h @@ -1,419 +1,419 @@ /*============================================================================ 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 mitkWeakPointer_h #define mitkWeakPointer_h #include #include namespace mitk { template class WeakPointer final { public: using DeleteEventCallbackType = std::function; WeakPointer() noexcept : m_RawPointer(nullptr) { } WeakPointer(T *rawPointer) : m_RawPointer(rawPointer) { this->AddDeleteEventObserver(); } WeakPointer(const WeakPointer &other) : m_RawPointer(other.m_RawPointer) { this->AddDeleteEventObserver(); } WeakPointer(WeakPointer &&other) : m_RawPointer(other.m_RawPointer) { other.RemoveDeleteEventObserver(); other.m_RawPointer = nullptr; this->AddDeleteEventObserver(); } ~WeakPointer() noexcept { try { this->RemoveDeleteEventObserver(); } catch (...) { // Swallow. Otherwise, the application would terminate if another // exception is already propagating. } } // Prefer classic implementation to copy-and-swap idiom. Swapping is // non-trivial for this class as the observed object is keeping references // to its observers. WeakPointer & operator =(const WeakPointer &other) { if (this != &other) { this->RemoveDeleteEventObserver(); m_RawPointer = other.m_RawPointer; this->AddDeleteEventObserver(); } return *this; } WeakPointer & operator =(WeakPointer &&other) { // No check for self-assignment as it is allowed to assume that the // parameter is a unique reference to this argument. this->RemoveDeleteEventObserver(); m_RawPointer = other.m_RawPointer; other.m_RawPointer = nullptr; this->AddDeleteEventObserver(); return *this; } WeakPointer & operator =(std::nullptr_t) { this->RemoveDeleteEventObserver(); m_RawPointer = nullptr; return *this; } WeakPointer & operator =(T *other) { if (m_RawPointer != other) { this->RemoveDeleteEventObserver(); m_RawPointer = other; this->AddDeleteEventObserver(); } return *this; } explicit operator bool() const noexcept { return nullptr != m_RawPointer; } bool IsExpired() const noexcept { return !*this; } itk::SmartPointer Lock() const { return m_RawPointer; } void SetDeleteEventCallback(const DeleteEventCallbackType &callback) { m_DeleteEventCallback = callback; } private: void AddDeleteEventObserver() { if (nullptr != m_RawPointer) { auto command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &WeakPointer::OnDeleteEvent); - using TWithoutConst = typename std::remove_const::type; + using TWithoutConst = typename std::remove_const_t; //cast the pointer to non const before adding the observer. This is done to ensure that //weak pointer also supports const pointers. auto nonConstPointer = const_cast(m_RawPointer); m_ObserverTag = nonConstPointer->AddObserver(itk::DeleteEvent(), command); } } void RemoveDeleteEventObserver() { if (nullptr != m_RawPointer) { - using TWithoutConst = typename std::remove_const::type; + using TWithoutConst = typename std::remove_const_t; //cast the pointer to non const before removing the observer. This is done to ensure that //weak pointer also supports const pointers. auto nonConstPointer = const_cast(m_RawPointer); nonConstPointer->RemoveObserver(m_ObserverTag); } } void OnDeleteEvent() noexcept { // Don't remove any observers from the observed object as it is about to // die and can't handle this operation anymore. m_RawPointer = nullptr; if (m_DeleteEventCallback) m_DeleteEventCallback(); } // The following comparison operators need access to class internals. // All remaining comparison operators are implemented as non-member // non-friend functions that use logical combinations of these non-member // friend functions. friend bool operator ==(const WeakPointer &left, const WeakPointer &right) noexcept { return left.m_RawPointer == right.m_RawPointer; } // Also covers comparisons to T::Pointer and T::ConstPointer as // itk::SmartPointer can be implicitly converted to a raw pointer. friend bool operator ==(const WeakPointer &left, const T *right) noexcept { return left.m_RawPointer == right; } friend bool operator <(const WeakPointer &left, const WeakPointer &right) noexcept { // The specialization of std::less for any pointer type yields a total // order, even if the built-in operator < doesn't. return std::less()(left.m_RawPointer, right.m_RawPointer); } friend bool operator <(const WeakPointer &left, std::nullptr_t right) noexcept { return std::less()(left.m_RawPointer, right); } friend bool operator <(std::nullptr_t left, const WeakPointer &right) noexcept { return std::less()(left, right.m_RawPointer); } friend bool operator <(const WeakPointer &left, const T *right) noexcept { return std::less()(left.m_RawPointer, right); } friend bool operator <(const T *left, const WeakPointer &right) noexcept { return std::less()(left, right.m_RawPointer); } T *m_RawPointer; // m_ObserverTag is completely managed by the two methods // AddDeleteEventObserver() and RemoveDeleteEventObserver(). There // isn't any need to initialize or use it at all outside of these methods. unsigned long m_ObserverTag; DeleteEventCallbackType m_DeleteEventCallback; }; } template bool operator !=(const mitk::WeakPointer &left, const mitk::WeakPointer &right) noexcept { return !(left == right); } template bool operator <=(const mitk::WeakPointer &left, const mitk::WeakPointer &right) noexcept { return !(right < left); } template bool operator >(const mitk::WeakPointer &left, const mitk::WeakPointer &right) noexcept { return right < left; } template bool operator >=(const mitk::WeakPointer &left, const mitk::WeakPointer &right) noexcept { return !(left < right); } template bool operator ==(const mitk::WeakPointer &left, std::nullptr_t) noexcept { return !left; } template bool operator !=(const mitk::WeakPointer &left, std::nullptr_t right) noexcept { return !(left == right); } template bool operator ==(std::nullptr_t, const mitk::WeakPointer &right) noexcept { return !right; } template bool operator !=(std::nullptr_t left, const mitk::WeakPointer &right) noexcept { return !(left == right); } template bool operator <=(const mitk::WeakPointer &left, std::nullptr_t right) noexcept { return !(right < left); } template bool operator >(const mitk::WeakPointer &left, std::nullptr_t right) noexcept { return right < left; } template bool operator >=(const mitk::WeakPointer &left, std::nullptr_t right) noexcept { return !(left < right); } template bool operator <=(std::nullptr_t left, const mitk::WeakPointer &right) noexcept { return !(right < left); } template bool operator >(std::nullptr_t left, const mitk::WeakPointer &right) noexcept { return right < left; } template bool operator >=(std::nullptr_t left, const mitk::WeakPointer &right) noexcept { return !(left < right); } template bool operator !=(const mitk::WeakPointer &left, const T *right) noexcept { return !(left == right); } template bool operator <=(const mitk::WeakPointer &left, const T *right) noexcept { return !(right < left); } template bool operator >(const mitk::WeakPointer &left, const T *right) noexcept { return right < left; } template bool operator >=(const mitk::WeakPointer &left, const T *right) noexcept { return !(left < right); } template bool operator ==(const T *left, const mitk::WeakPointer &right) noexcept { return right == left; } template bool operator !=(const T *left, const mitk::WeakPointer &right) noexcept { return !(right == left); } template bool operator <=(const T *left, const mitk::WeakPointer &right) noexcept { return !(right < left); } template bool operator >(const T *left, const mitk::WeakPointer &right) noexcept { return right < left; } template bool operator >=(const T *left, const mitk::WeakPointer &right) noexcept { return !(left < right); } template bool operator !=(const mitk::WeakPointer &left, itk::SmartPointer right) noexcept { return !(left == right); } template bool operator <=(const mitk::WeakPointer &left, itk::SmartPointer right) noexcept { return !(right < left); } template bool operator >(const mitk::WeakPointer &left, itk::SmartPointer right) noexcept { return right < left; } template bool operator >=(const mitk::WeakPointer &left, itk::SmartPointer right) noexcept { return !(left < right); } template bool operator ==(itk::SmartPointer left, const mitk::WeakPointer &right) noexcept { return right == left; } template bool operator !=(itk::SmartPointer left, const mitk::WeakPointer &right) noexcept { return !(right == left); } template bool operator <=(itk::SmartPointer left, const mitk::WeakPointer &right) noexcept { return !(right < left); } template bool operator >(itk::SmartPointer left, const mitk::WeakPointer &right) noexcept { return right < left; } template bool operator >=(itk::SmartPointer left, const mitk::WeakPointer &right) noexcept { return !(left < right); } #endif diff --git a/Modules/Multilabel/Testing/mitkLabelSetImageTest.cpp b/Modules/Multilabel/Testing/mitkLabelSetImageTest.cpp index 32fc677470..e71358bd70 100644 --- a/Modules/Multilabel/Testing/mitkLabelSetImageTest.cpp +++ b/Modules/Multilabel/Testing/mitkLabelSetImageTest.cpp @@ -1,663 +1,664 @@ /*============================================================================ 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 namespace CppUnit { namespace StringHelper { template<> inline std::string toString(const mitk::LabelSetImage::LabelValueVectorType& lvs) { std::ostringstream stream; stream << "["; for (mitk::LabelSetImage::LabelValueVectorType::const_iterator iter = lvs.begin(); iter!=lvs.end(); ++iter) { stream << *iter; if (iter + 1 != lvs.end()) stream << ", "; } stream << "]"; return stream.str(); } template<> inline std::string toString(const std::vector& strings) { std::ostringstream stream; stream << "["; for (std::vector::const_iterator iter = strings.begin(); iter != strings.end(); ++iter) { stream << *iter; if (iter + 1 != strings.end()) stream << ", "; } stream << "]"; return stream.str(); } } } class mitkLabelSetImageTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkLabelSetImageTestSuite); MITK_TEST(TestInitialize); MITK_TEST(TestClone); MITK_TEST(TestAddLayer); MITK_TEST(TestGetActiveLabelSet); MITK_TEST(TestGetActiveLabel); MITK_TEST(TestInitializeByLabeledImage); MITK_TEST(TestGetLabel); MITK_TEST(TestGetLabelValues); MITK_TEST(TestGetLabelClassNames); MITK_TEST(TestSetUnlabeledLabelLock); MITK_TEST(TestGetTotalNumberOfLabels); MITK_TEST(TestGetNumberOfLabels); MITK_TEST(TestExistsLabel); MITK_TEST(TestExistsGroup); MITK_TEST(TestSetActiveLayer); MITK_TEST(TestRemoveLayer); MITK_TEST(TestRemoveLabels); MITK_TEST(TestEraseLabels); MITK_TEST(TestMergeLabels); MITK_TEST(TestCreateLabelMask); CPPUNIT_TEST_SUITE_END(); private: mitk::LabelSetImage::Pointer m_LabelSetImage; int m_LabelAddedEventCount; int m_LabelModifiedEventCount; int m_LabelRemovedEventCount; int m_LabelsChangedEventCount; int m_GroupAddedEventCount; int m_GroupModifiedEventCount; int m_GroupRemovedEventCount; public: void setUp() override { // Create a new labelset image m_LabelSetImage = mitk::LabelSetImage::New(); mitk::Image::Pointer regularImage = mitk::Image::New(); unsigned int dimensions[3] = { 96, 128, 52 }; regularImage->Initialize(mitk::MakeScalarPixelType(), 3, dimensions); m_LabelSetImage->Initialize(regularImage); this->ResetEvents(); m_LabelSetImage->AddObserver(mitk::LabelAddedEvent(), [this](const itk::EventObject&) { ++(this->m_LabelAddedEventCount); }); m_LabelSetImage->AddObserver(mitk::LabelModifiedEvent(), [this](const itk::EventObject&) { ++(this->m_LabelModifiedEventCount); }); m_LabelSetImage->AddObserver(mitk::LabelRemovedEvent(), [this](const itk::EventObject&) { ++(this->m_LabelRemovedEventCount); }); m_LabelSetImage->AddObserver(mitk::LabelsChangedEvent(), [this](const itk::EventObject&) { ++(this->m_LabelsChangedEventCount); }); m_LabelSetImage->AddObserver(mitk::GroupAddedEvent(), [this](const itk::EventObject&) { ++(this->m_GroupAddedEventCount); }); m_LabelSetImage->AddObserver(mitk::GroupModifiedEvent(), [this](const itk::EventObject&) { ++(this->m_GroupModifiedEventCount); }); m_LabelSetImage->AddObserver(mitk::GroupRemovedEvent(), [this](const itk::EventObject&) { ++(this->m_GroupRemovedEventCount); }); } void tearDown() override { // Delete LabelSetImage m_LabelSetImage = nullptr; } void ResetEvents() { m_LabelAddedEventCount = 0; m_LabelModifiedEventCount = 0; m_LabelRemovedEventCount = 0; m_LabelsChangedEventCount = 0; m_GroupAddedEventCount = 0; m_GroupModifiedEventCount = 0; m_GroupRemovedEventCount = 0; } bool CheckEvents(int lAdd, int lMod, int lRem, int lsC, int gAdd, int gMod, int gRem) { return m_GroupAddedEventCount == gAdd && m_GroupModifiedEventCount == gMod && m_GroupRemovedEventCount == gRem && m_LabelAddedEventCount == lAdd && m_LabelModifiedEventCount == lMod && m_LabelRemovedEventCount == lRem && m_LabelsChangedEventCount == lsC; } void InitializeTestSegmentation() { mitk::Label::Pointer label1 = mitk::Label::New(1, "Label1"); mitk::Label::Pointer label2 = mitk::Label::New(20, "Label2"); mitk::Label::Pointer label22 = mitk::Label::New(22, "Label2"); mitk::Label::Pointer label3 = mitk::Label::New(30, "Label3"); m_LabelSetImage->AddLabel(label1, 0); m_LabelSetImage->AddLayer({ label2, label22, label3 }); m_LabelSetImage->AddLayer(); this->ResetEvents(); } void TestInitialize() { // LabelSet image should always has the pixel type mitk::Label::PixelType CPPUNIT_ASSERT_MESSAGE("LabelSetImage has wrong pixel type", m_LabelSetImage->GetPixelType() == mitk::MakeScalarPixelType()); mitk::Image::Pointer regularImage = mitk::Image::New(); unsigned int dimensions[3] = { 96, 128, 52 }; regularImage->Initialize(mitk::MakeScalarPixelType(), 3, dimensions); mitk::BaseGeometry::Pointer regularImageGeo = regularImage->GetGeometry(); mitk::BaseGeometry::Pointer labelImageGeo = m_LabelSetImage->GetGeometry(); MITK_ASSERT_EQUAL(labelImageGeo, regularImageGeo, "LabelSetImage has wrong geometry"); // By default one layer should be added CPPUNIT_ASSERT_MESSAGE("Image was not correctly initialized - number of layers is not one", m_LabelSetImage->GetNumberOfLayers() == 1); CPPUNIT_ASSERT_MESSAGE("Image was not correctly initialized - active layer has wrong ID", m_LabelSetImage->GetActiveLayer() == 0); CPPUNIT_ASSERT_MESSAGE("Image was not correctly initialized - no active label should be selected", m_LabelSetImage->GetActiveLabel() == nullptr); } void TestClone() { mitk::Label::Pointer label1 = mitk::Label::New(); label1->SetName("Label1"); label1->SetValue(1); mitk::Label::Pointer label2 = mitk::Label::New(); label2->SetName("Label2"); label2->SetValue(200); mitk::Label::Pointer label3 = mitk::Label::New(); label2->SetName("Label3"); label2->SetValue(300); m_LabelSetImage->AddLabel(label1, 0); m_LabelSetImage->AddLayer({ label2, label3 }); auto clone = m_LabelSetImage->Clone(); MITK_ASSERT_EQUAL(m_LabelSetImage, clone, "LabelSetImage clone is not equal."); } void TestAddLayer() { CPPUNIT_ASSERT_MESSAGE("Number of layers is not zero", m_LabelSetImage->GetNumberOfLayers() == 1); m_LabelSetImage->AddLayer(); CPPUNIT_ASSERT_MESSAGE("Layer was not added correctly to image - number of layers is not one", m_LabelSetImage->GetNumberOfLayers() == 2); CPPUNIT_ASSERT_MESSAGE("Layer was not added correctly to image - active layer has wrong ID", m_LabelSetImage->GetActiveLayer() == 0); CPPUNIT_ASSERT_MESSAGE("Layer was not added correctly to image - no active label should be selected", m_LabelSetImage->GetActiveLabel() == nullptr); CPPUNIT_ASSERT_MESSAGE("Event count incorrect", CheckEvents(0,0,0,0,1,0,0)); mitk::Label::Pointer label1 = mitk::Label::New(); label1->SetName("Label1"); label1->SetValue(1); mitk::Label::Pointer label2 = mitk::Label::New(); label2->SetName("Label2"); label2->SetValue(200); const auto layerID = m_LabelSetImage->AddLayer({ label1, label2 }); m_LabelSetImage->SetActiveLabel(200); CPPUNIT_ASSERT_MESSAGE("Layer was not added correctly to image - number of layers is not two", m_LabelSetImage->GetNumberOfLayers() == 3); CPPUNIT_ASSERT_MESSAGE("Layer was not added correctly to image - active layer has wrong ID", m_LabelSetImage->GetActiveLayer() == layerID); CPPUNIT_ASSERT_MESSAGE("Layer was not added correctly to image - active label is wrong", m_LabelSetImage->GetActiveLabel()->GetValue() == 200); CPPUNIT_ASSERT_MESSAGE("Event count incorrect", CheckEvents(0, 0, 0, 0, 2, 0, 0)); } void TestGetActiveLabelSet() { mitk::Label::Pointer label1 = mitk::Label::New(); label1->SetName("Label1"); label1->SetValue(1); mitk::Label::Pointer label2 = mitk::Label::New(); label2->SetName("Label2"); label2->SetValue(200); mitk::LabelSetImage::ConstLabelVectorType refLayer = { label1, label2 }; unsigned int layerID = m_LabelSetImage->AddLayer(refLayer); m_LabelSetImage->SetActiveLabel(200); auto activeLayer = m_LabelSetImage->GetConstLabelsByValue(m_LabelSetImage->GetLabelValuesByGroup(m_LabelSetImage->GetActiveLayer())); CPPUNIT_ASSERT_MESSAGE("Wrong layer ID was returned", layerID == 1); CPPUNIT_ASSERT_MESSAGE("Wrong layer ID was returned", layerID == m_LabelSetImage->GetActiveLayer()); CPPUNIT_ASSERT_MESSAGE("Wrong active labelset returned", mitk::Equal(refLayer, activeLayer, 0.00001, true)); } void TestGetActiveLabel() { mitk::Label::Pointer label1 = mitk::Label::New(); label1->SetName("Label1"); mitk::Label::PixelType value1 = 1; label1->SetValue(value1); mitk::Label::Pointer label2 = mitk::Label::New(); label2->SetName("Label2"); mitk::Label::PixelType value2 = 200; label2->SetValue(value2); m_LabelSetImage->AddLabel(label1,0); m_LabelSetImage->AddLabel(label2,0); m_LabelSetImage->SetActiveLabel(1); CPPUNIT_ASSERT_MESSAGE("Layer was not added correctly to image - active label is wrong", m_LabelSetImage->GetActiveLabel()->GetValue() == value1); m_LabelSetImage->SetActiveLabel(value2); CPPUNIT_ASSERT_MESSAGE("Layer was not added correctly to image - active label is wrong", m_LabelSetImage->GetActiveLabel()->GetValue() == value2); CPPUNIT_ASSERT_MESSAGE("Active Label was not correctly retreived with const getter", const_cast(m_LabelSetImage.GetPointer())->GetActiveLabel()->GetValue() == value2); } void TestInitializeByLabeledImage() { mitk::Image::Pointer image = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelSetTestInitializeImage.nrrd")); m_LabelSetImage->InitializeByLabeledImage(image); CPPUNIT_ASSERT_MESSAGE("Image - number of labels is not 5", m_LabelSetImage->GetNumberOfLabels(0) == 5); } void TestGetLabel() { mitk::Label::Pointer label1 = mitk::Label::New(1, "Label1"); mitk::Label::Pointer label2 = mitk::Label::New(20,"Label2"); m_LabelSetImage->AddLabel(label1,0); m_LabelSetImage->AddLayer(); m_LabelSetImage->AddLabel(label2,1); this->ResetEvents(); CPPUNIT_ASSERT_MESSAGE("Wrong label retrieved for active layer", mitk::Equal(*m_LabelSetImage->GetLabel(1), *label1, 0.0001, true)); CPPUNIT_ASSERT_MESSAGE("Wrong label retrieved for layer 1", mitk::Equal(*m_LabelSetImage->GetLabel(20), *label2, 0.0001, true)); // Try to get a non existing label mitk::Label *unkownLabel = m_LabelSetImage->GetLabel(1000); CPPUNIT_ASSERT_MESSAGE("Non existing label should be nullptr", unkownLabel == nullptr); CPPUNIT_ASSERT_MESSAGE("Event count incorrect", CheckEvents(0, 0, 0, 0, 0, 0, 0)); } void TestGetLabelValues() { InitializeTestSegmentation(); auto labels = m_LabelSetImage->GetLabelValuesByGroup(0); CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong label values retrieved for group 0", mitk::LabelSetImage::LabelValueVectorType({ 1 }), labels); labels = m_LabelSetImage->GetLabelValuesByGroup(1); CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong label values retrieved for group 1", mitk::LabelSetImage::LabelValueVectorType({ 20, 22, 30 }), labels); labels = m_LabelSetImage->GetLabelValuesByGroup(2); CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong label values retrieved for group 2", mitk::LabelSetImage::LabelValueVectorType(), labels); CPPUNIT_ASSERT_THROW(m_LabelSetImage->GetLabelValuesByGroup(3), mitk::Exception); labels = m_LabelSetImage->GetLabelValuesByName(0, "Label1"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong label values retrieved for \"Label2\" in group 0", mitk::LabelSetImage::LabelValueVectorType({ 1 }), labels); labels = m_LabelSetImage->GetLabelValuesByName(1, "Label2"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong label values retrieved for \"Label2\" in group 1", mitk::LabelSetImage::LabelValueVectorType({ 20, 22 }), labels); labels = m_LabelSetImage->GetLabelValuesByName(1, "Label3"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong label values retrieved for \"Label3\" in group 1", mitk::LabelSetImage::LabelValueVectorType({ 30 }), labels); labels = m_LabelSetImage->GetLabelValuesByName(2, "Label1"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong label values retrieved for group 2", mitk::LabelSetImage::LabelValueVectorType(), labels); labels = m_LabelSetImage->GetLabelValuesByName(0, "unkown"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong label values retrieved for unkown name", mitk::LabelSetImage::LabelValueVectorType(), labels); CPPUNIT_ASSERT_THROW(m_LabelSetImage->GetLabelValuesByName(3,"invalid"), mitk::Exception); labels = m_LabelSetImage->GetAllLabelValues(); CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong label values retrieved for unkown name", mitk::LabelSetImage::LabelValueVectorType({1,20,22,30}), labels); CPPUNIT_ASSERT_MESSAGE("Event count incorrect", CheckEvents(0, 0, 0, 0, 0, 0, 0)); } void TestGetLabelClassNames() { InitializeTestSegmentation(); auto names = m_LabelSetImage->GetLabelClassNames(); CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong names retrieved", std::vector({ "Label1", "Label2", "Label3"}), names); names = m_LabelSetImage->GetLabelClassNamesByGroup(0); CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong names retrieved for group 0", std::vector({ "Label1"}), names); names = m_LabelSetImage->GetLabelClassNamesByGroup(1); CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong names retrieved for group 1", std::vector({"Label2", "Label3" }), names); names = m_LabelSetImage->GetLabelClassNamesByGroup(2); CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong names retrieved for group 2", std::vector(), names); CPPUNIT_ASSERT_THROW(m_LabelSetImage->GetLabelValuesByGroup(3), mitk::Exception); CPPUNIT_ASSERT_MESSAGE("Event count incorrect", CheckEvents(0, 0, 0, 0, 0, 0, 0)); } void TestSetUnlabeledLabelLock() { auto locked = m_LabelSetImage->GetUnlabeledLabelLock(); CPPUNIT_ASSERT_MESSAGE("Wrong UnlabeledLabelLock default state", locked == false); m_LabelSetImage->SetUnlabeledLabelLock(true); locked = m_LabelSetImage->GetUnlabeledLabelLock(); CPPUNIT_ASSERT_MESSAGE("Wrong UnlabeledLabelLock state", locked == true); } void TestGetTotalNumberOfLabels() { this->InitializeTestSegmentation(); CPPUNIT_ASSERT_MESSAGE( "Wrong total number of labels", m_LabelSetImage->GetTotalNumberOfLabels() == 4); CPPUNIT_ASSERT_MESSAGE("Event count incorrect", CheckEvents(0, 0, 0, 0, 0, 0, 0)); } void TestGetNumberOfLabels() { this->InitializeTestSegmentation(); CPPUNIT_ASSERT_MESSAGE( "Wrong number of labels in group 0", m_LabelSetImage->GetNumberOfLabels(0) == 1); CPPUNIT_ASSERT_MESSAGE( "Wrong number of labels in group 1", m_LabelSetImage->GetNumberOfLabels(1) == 3); CPPUNIT_ASSERT_MESSAGE( "Wrong number of labels in group 2", m_LabelSetImage->GetNumberOfLabels(2) == 0); CPPUNIT_ASSERT_THROW(m_LabelSetImage->GetNumberOfLabels(3), mitk::Exception); CPPUNIT_ASSERT_MESSAGE("Event count incorrect", CheckEvents(0, 0, 0, 0, 0, 0, 0)); } void TestExistsLabel() { mitk::Label::Pointer label = mitk::Label::New(); label->SetName("Label2"); mitk::Label::PixelType value = 200; label->SetValue(value); m_LabelSetImage->AddLayer(); m_LabelSetImage->AddLabel(label,1); m_LabelSetImage->SetActiveLayer(0); CPPUNIT_ASSERT_MESSAGE("Existing label was not found", m_LabelSetImage->ExistLabel(value) == true); CPPUNIT_ASSERT_MESSAGE("Non existing label was found", m_LabelSetImage->ExistLabel(10000) == false); } void TestExistsGroup() { mitk::Label::Pointer label1 = mitk::Label::New(); label1->SetName("Label1"); label1->SetValue(1); mitk::Label::Pointer label2 = mitk::Label::New(); label2->SetName("Label2"); label2->SetValue(200); m_LabelSetImage->AddLayer({label1, label2}); CPPUNIT_ASSERT_MESSAGE("Check for existing layer failed", m_LabelSetImage->ExistGroup(0) == true); CPPUNIT_ASSERT_MESSAGE("Check for existing layer failed", m_LabelSetImage->ExistGroup(1) == true); CPPUNIT_ASSERT_MESSAGE("Check for existing layer failed", m_LabelSetImage->ExistGroup(20) == false); } void TestSetActiveLayer() { // Cache active layer auto refActiveLayer = m_LabelSetImage->GetConstLabelsByValue(m_LabelSetImage->GetLabelValuesByGroup(m_LabelSetImage->GetActiveLayer())); // Add new layer mitk::Label::Pointer label1 = mitk::Label::New(); label1->SetName("Label1"); label1->SetValue(1); mitk::Label::Pointer label2 = mitk::Label::New(); label2->SetName("Label2"); label2->SetValue(200); mitk::LabelSetImage::ConstLabelVectorType newlayer = { label1, label2 }; unsigned int layerID = m_LabelSetImage->AddLayer(newlayer); // Set initial layer as active layer m_LabelSetImage->SetActiveLayer(0); auto activeLayer = m_LabelSetImage->GetConstLabelsByValue(m_LabelSetImage->GetLabelValuesByGroup(m_LabelSetImage->GetActiveLayer())); CPPUNIT_ASSERT_MESSAGE("Wrong active labelset returned", mitk::Equal(refActiveLayer, activeLayer, 0.00001, true)); // Set previously added layer as active layer m_LabelSetImage->SetActiveLayer(layerID); activeLayer = m_LabelSetImage->GetConstLabelsByValue(m_LabelSetImage->GetLabelValuesByGroup(m_LabelSetImage->GetActiveLayer())); CPPUNIT_ASSERT_MESSAGE("Wrong active labelset returned", mitk::Equal(newlayer, activeLayer, 0.00001, true)); // Set a non existing layer as active layer - nothing should change m_LabelSetImage->SetActiveLayer(10000); CPPUNIT_ASSERT_MESSAGE("Wrong active labelset returned", mitk::Equal(newlayer, activeLayer, 0.00001, true)); } void TestRemoveLayer() { // Cache active layer auto refActiveLayer = m_LabelSetImage->GetConstLabelsByValue(m_LabelSetImage->GetLabelValuesByGroup(m_LabelSetImage->GetActiveLayer())); // Add new layers m_LabelSetImage->AddLayer(); mitk::Label::Pointer label1 = mitk::Label::New(); label1->SetName("Label1"); label1->SetValue(1); mitk::Label::Pointer label2 = mitk::Label::New(); label2->SetName("Label2"); label2->SetValue(200); mitk::LabelSetImage::ConstLabelVectorType newlayer = { label1, label2 }; unsigned int layerID = m_LabelSetImage->AddLayer(newlayer); m_LabelSetImage->SetActiveLayer(layerID); auto activeLayer = m_LabelSetImage->GetConstLabelsByValue(m_LabelSetImage->GetLabelValuesByGroup(m_LabelSetImage->GetActiveLayer())); CPPUNIT_ASSERT_MESSAGE("Wrong active labelset returned", mitk::Equal(newlayer, activeLayer, 0.00001, true)); m_LabelSetImage->RemoveGroup(1); CPPUNIT_ASSERT_MESSAGE("Wrong number of layers, after a layer was removed", m_LabelSetImage->GetNumberOfLayers() == 2); CPPUNIT_ASSERT_MESSAGE("Check for existing layer failed", m_LabelSetImage->ExistGroup(2) == false); CPPUNIT_ASSERT_MESSAGE("Check for existing layer failed", m_LabelSetImage->ExistGroup(1) == true); CPPUNIT_ASSERT_MESSAGE("Check for existing layer failed", m_LabelSetImage->ExistGroup(0) == true); m_LabelSetImage->RemoveGroup(1); activeLayer = m_LabelSetImage->GetConstLabelsByValue(m_LabelSetImage->GetLabelValuesByGroup(m_LabelSetImage->GetActiveLayer())); CPPUNIT_ASSERT_MESSAGE("Wrong number of layers, after a layer was removed", m_LabelSetImage->GetNumberOfLayers() == 1); CPPUNIT_ASSERT_MESSAGE("Check for existing layer failed", m_LabelSetImage->ExistGroup(1) == false); CPPUNIT_ASSERT_MESSAGE("Check for existing layer failed", m_LabelSetImage->ExistGroup(0) == true); CPPUNIT_ASSERT_MESSAGE("Wrong active layer", mitk::Equal(refActiveLayer, activeLayer, 0.00001, true)); m_LabelSetImage->RemoveGroup(0); CPPUNIT_ASSERT_MESSAGE("Wrong number of layers, after a layer was removed", m_LabelSetImage->GetNumberOfLayers() == 0); CPPUNIT_ASSERT_MESSAGE("Check for existing layer failed", m_LabelSetImage->ExistGroup(0) == false); CPPUNIT_ASSERT_THROW_MESSAGE("GetActiveLayers does not fail although all layer have been removed", m_LabelSetImage->GetActiveLayer(), mitk::Exception); } void TestRemoveLabels() { mitk::Image::Pointer image = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelSetTestInitializeImage.nrrd")); m_LabelSetImage = nullptr; m_LabelSetImage = mitk::LabelSetImage::New(); m_LabelSetImage->InitializeByLabeledImage(image); CPPUNIT_ASSERT_MESSAGE("Image - number of labels is not 6", m_LabelSetImage->GetNumberOfLabels(0) == 5); // 2ndMin because of unlabeled pixels = 0 CPPUNIT_ASSERT_MESSAGE("Wrong MIN value", m_LabelSetImage->GetStatistics()->GetScalarValue2ndMin() == 1); CPPUNIT_ASSERT_MESSAGE("Wrong MAX value", m_LabelSetImage->GetStatistics()->GetScalarValueMax() == 7); CPPUNIT_ASSERT_MESSAGE("Label with ID 3 does not exist after initialization", m_LabelSetImage->ExistLabel(3) == true); m_LabelSetImage->RemoveLabel(1); std::vector labelsToBeRemoved; labelsToBeRemoved.push_back(3); labelsToBeRemoved.push_back(7); m_LabelSetImage->RemoveLabels(labelsToBeRemoved); CPPUNIT_ASSERT_MESSAGE("Wrong number of labels after some have been removed", m_LabelSetImage->GetNumberOfLabels(0) == 2); // Values within the image are 0, 1, 3, 5, 6, 7 - New Min / Max value should be 5 / 6 // 2ndMin because of unlabeled pixels = 0 CPPUNIT_ASSERT_MESSAGE("Labels with value 1 and 3 were not removed from the image", m_LabelSetImage->GetStatistics()->GetScalarValue2ndMin() == 5); CPPUNIT_ASSERT_MESSAGE("Label with value 7 was not removed from the image", m_LabelSetImage->GetStatistics()->GetScalarValueMax() == 6); } void TestEraseLabels() { mitk::Image::Pointer image = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelSetTestInitializeImage.nrrd")); m_LabelSetImage = nullptr; m_LabelSetImage = mitk::LabelSetImage::New(); m_LabelSetImage->InitializeByLabeledImage(image); CPPUNIT_ASSERT_MESSAGE("Image - number of labels is not 6", m_LabelSetImage->GetNumberOfLabels(0) == 5); // 2ndMin because of unlabeled pixels = 0 CPPUNIT_ASSERT_MESSAGE("Wrong MIN value", m_LabelSetImage->GetStatistics()->GetScalarValue2ndMin() == 1); CPPUNIT_ASSERT_MESSAGE("Wrong MAX value", m_LabelSetImage->GetStatistics()->GetScalarValueMax() == 7); CPPUNIT_ASSERT_MESSAGE("Label with ID 3 does not exist after initialization", m_LabelSetImage->ExistLabel(3) == true); m_LabelSetImage->EraseLabel(1); std::vector labelsToBeErased; labelsToBeErased.push_back(3); labelsToBeErased.push_back(7); m_LabelSetImage->EraseLabels(labelsToBeErased); CPPUNIT_ASSERT_MESSAGE("Wrong number of labels since none have been removed", m_LabelSetImage->GetNumberOfLabels(0) == 5); // Values within the image are 0, 1, 3, 5, 6, 7 - New Min / Max value should be 5 / 6 // 2ndMin because of unlabeled pixels = 0 CPPUNIT_ASSERT_MESSAGE("Labels with value 1 and 3 were not erased from the image", m_LabelSetImage->GetStatistics()->GetScalarValue2ndMin() == 5); CPPUNIT_ASSERT_MESSAGE("Label with value 7 was not erased from the image", m_LabelSetImage->GetStatistics()->GetScalarValueMax() == 6); } void TestMergeLabels() { mitk::Image::Pointer image = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelSetTestInitializeImage.nrrd")); m_LabelSetImage = nullptr; m_LabelSetImage = mitk::LabelSetImage::New(); m_LabelSetImage->InitializeByLabeledImage(image); CPPUNIT_ASSERT_MESSAGE("Image - number of labels is not 6", m_LabelSetImage->GetNumberOfLabels(0) == 5); // 2ndMin because of unlabeled pixels = 0 CPPUNIT_ASSERT_MESSAGE("Wrong MIN value", m_LabelSetImage->GetStatistics()->GetScalarValue2ndMin() == 1); CPPUNIT_ASSERT_MESSAGE("Wrong MAX value", m_LabelSetImage->GetStatistics()->GetScalarValueMax() == 7); CPPUNIT_ASSERT_MESSAGE("Label with ID 6 does not exist after initialization", m_LabelSetImage->ExistLabel(6) == true); // Merge label 7 with label 6. Result should be that label 7 is not present anymore. m_LabelSetImage->MergeLabel(6, 7); CPPUNIT_ASSERT_MESSAGE("Label with value 7 was not removed from the image", m_LabelSetImage->GetStatistics()->GetScalarValueMax() == 6); // Count all pixels with value 6 = 507 // Count all pixels with value 7 = 823 // Check if merged label has 507 + 823 = 1330 pixels CPPUNIT_ASSERT_MESSAGE("Labels were not correctly merged", m_LabelSetImage->GetStatistics()->GetCountOfMaxValuedVoxels() == 1330); CPPUNIT_ASSERT_MESSAGE("Label with ID 3 does not exist after initialization", m_LabelSetImage->ExistLabel(3) == true); CPPUNIT_ASSERT_MESSAGE("Label with ID 5 does not exist after initialization", m_LabelSetImage->ExistLabel(5) == true); // Merge labels 5 and 6 with 3. Result should be that labels 5 and 6 are not present anymore. std::vector vectorOfSourcePixelValues{ 5, 6 }; m_LabelSetImage->MergeLabels(3, vectorOfSourcePixelValues); // Values within the image are 0, 1, 3, 5, 6, 7 - New Max value should be 3 CPPUNIT_ASSERT_MESSAGE("Labels with value 5 and 6 were not removed from the image", m_LabelSetImage->GetStatistics()->GetScalarValueMax() == 3); // Count all pixels with value 3 = 1893 // Count all pixels with value 5 = 2143 // Count all pixels with value 6 = 1330 // Check if merged label has 1893 + 2143 + 1330 = 5366 pixels CPPUNIT_ASSERT_MESSAGE("Labels were not correctly merged", m_LabelSetImage->GetStatistics()->GetCountOfMaxValuedVoxels() == 5366); } void TestCreateLabelMask() { mitk::Image::Pointer image = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelSetTestInitializeImage.nrrd")); m_LabelSetImage = nullptr; m_LabelSetImage = mitk::LabelSetImage::New(); m_LabelSetImage->InitializeByLabeledImage(image); - auto labelMask = m_LabelSetImage->CreateLabelMask(6); + auto labelMask = mitk::CreateLabelMask(m_LabelSetImage,6); mitk::AutoCropImageFilter::Pointer cropFilter = mitk::AutoCropImageFilter::New(); cropFilter->SetInput(labelMask); cropFilter->SetBackgroundValue(0); cropFilter->SetMarginFactor(1.15); cropFilter->Update(); auto maskImage = cropFilter->GetOutput(); // Count all pixels with value 6 = 507 CPPUNIT_ASSERT_MESSAGE("Label mask not correctly created", maskImage->GetStatistics()->GetCountOfMaxValuedVoxels() == 507); } }; MITK_TEST_SUITE_REGISTRATION(mitkLabelSetImage) diff --git a/Modules/Multilabel/files.cmake b/Modules/Multilabel/files.cmake index 950a2a736f..3253bf602b 100644 --- a/Modules/Multilabel/files.cmake +++ b/Modules/Multilabel/files.cmake @@ -1,21 +1,22 @@ set(CPP_FILES mitkLabel.cpp mitkLabelSetImage.cpp mitkLabelSetImageConverter.cpp mitkLabelSetImageSource.cpp mitkLabelSetImageHelper.cpp mitkLabelSetImageSurfaceStampFilter.cpp mitkLabelSetImageToSurfaceFilter.cpp mitkLabelSetImageToSurfaceThreadedFilter.cpp mitkLabelSetImageVtkMapper2D.cpp mitkMultilabelObjectFactory.cpp mitkMultiLabelIOHelper.cpp mitkMultiLabelEvents.cpp + mitkMultiLabelPredicateHelper.cpp mitkDICOMSegmentationPropertyHelper.cpp mitkDICOMSegmentationConstants.cpp mitkSegmentationTaskList.cpp ) set(RESOURCE_FILES ) diff --git a/Modules/Multilabel/mitkLabel.cpp b/Modules/Multilabel/mitkLabel.cpp index e71e6c3b7a..5499525fae 100644 --- a/Modules/Multilabel/mitkLabel.cpp +++ b/Modules/Multilabel/mitkLabel.cpp @@ -1,309 +1,309 @@ /*============================================================================ 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 "mitkLabel.h" #include "itkProcessObject.h" #include #include #include #include const mitk::Label::PixelType mitk::Label::MAX_LABEL_VALUE = std::numeric_limits::max(); mitk::Label::Label() : PropertyList() { if (GetProperty("locked") == nullptr) SetLocked(true); if (GetProperty("visible") == nullptr) SetVisible(true); if (GetProperty("opacity") == nullptr) SetOpacity(0.6); if (GetProperty("center.coordinates") == nullptr) { mitk::Point3D pnt; pnt.SetElement(0, 0); pnt.SetElement(1, 0); pnt.SetElement(2, 0); SetCenterOfMassCoordinates(pnt); } if (GetProperty("center.index") == nullptr) { mitk::Point3D pnt; pnt.SetElement(0, 0); pnt.SetElement(1, 0); pnt.SetElement(2, 0); SetCenterOfMassIndex(pnt); } if (GetProperty("color") == nullptr) { mitk::Color col; col.Set(0, 0, 0); SetColor(col); } if (GetProperty("name") == nullptr) SetName("noName!"); if (GetProperty("value") == nullptr) SetValue(0); if (GetProperty("layer") == nullptr) SetLayer(0); DICOMSegmentationPropertyHelper::SetDICOMSegmentProperties(this); } mitk::Label::Label(PixelType value, const std::string& name) : Label() { this->SetValue(value); this->SetName(name); } mitk::Label::Label(const Label &other) : PropertyList(other) -// copyconstructer of property List handles the coping action +// copy constructor of property List handles the coping action { auto *map = this->GetMap(); auto it = map->begin(); auto end = map->end(); for (; it != end; ++it) { itk::SimpleMemberCommand