diff --git a/Modules/AppUtil/src/mitkBaseApplication.cpp b/Modules/AppUtil/src/mitkBaseApplication.cpp index 9f8f7c167a..acf981f893 100644 --- a/Modules/AppUtil/src/mitkBaseApplication.cpp +++ b/Modules/AppUtil/src/mitkBaseApplication.cpp @@ -1,927 +1,927 @@ /*============================================================================ 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { void outputImportantQtMessage(QtMsgType type, const QMessageLogContext&, const QString& msg) { auto message = msg.toStdString(); switch (type) { case QtWarningMsg: MITK_WARN << message; break; case QtCriticalMsg: MITK_ERROR << message; break; case QtFatalMsg: MITK_ERROR << message; abort(); default: break; } } void outputQtMessage(QtMsgType type, const QMessageLogContext& context, const QString& msg) { auto message = msg.toStdString(); switch (type) { case QtDebugMsg: MITK_DEBUG << message; break; case QtInfoMsg: MITK_INFO << message; break; case QtWarningMsg: [[fallthrough]]; case QtCriticalMsg: [[fallthrough]]; case QtFatalMsg: outputImportantQtMessage(type, context, msg); break; default: MITK_INFO << message; break; } } } namespace mitk { const QString BaseApplication::ARG_APPLICATION = "BlueBerry.application"; const QString BaseApplication::ARG_CLEAN = "BlueBerry.clean"; const QString BaseApplication::ARG_CONSOLELOG = "BlueBerry.consoleLog"; const QString BaseApplication::ARG_DEBUG = "BlueBerry.debug"; const QString BaseApplication::ARG_FORCE_PLUGIN_INSTALL = "BlueBerry.forcePlugins"; const QString BaseApplication::ARG_HOME = "BlueBerry.home"; const QString BaseApplication::ARG_NEWINSTANCE = "BlueBerry.newInstance"; const QString BaseApplication::ARG_NO_LAZY_REGISTRY_CACHE_LOADING = "BlueBerry.noLazyRegistryCacheLoading"; const QString BaseApplication::ARG_NO_REGISTRY_CACHE = "BlueBerry.noRegistryCache"; const QString BaseApplication::ARG_PLUGIN_CACHE = "BlueBerry.plugin_cache_dir"; const QString BaseApplication::ARG_PLUGIN_DIRS = "BlueBerry.plugin_dirs"; const QString BaseApplication::ARG_PRELOAD_LIBRARY = "BlueBerry.preloadLibrary"; const QString BaseApplication::ARG_PRODUCT = "BlueBerry.product"; const QString BaseApplication::ARG_PROVISIONING = "BlueBerry.provisioning"; const QString BaseApplication::ARG_REGISTRY_MULTI_LANGUAGE = "BlueBerry.registryMultiLanguage"; const QString BaseApplication::ARG_SPLASH_IMAGE = "BlueBerry.splashscreen"; const QString BaseApplication::ARG_STORAGE_DIR = "BlueBerry.storageDir"; const QString BaseApplication::ARG_XARGS = "xargs"; const QString BaseApplication::ARG_LOG_QT_MESSAGES = "Qt.logMessages"; const QString BaseApplication::ARG_SEGMENTATION_LABELSET_PRESET = "Segmentation.labelSetPreset"; const QString BaseApplication::ARG_SEGMENTATION_LABEL_SUGGESTIONS = "Segmentation.labelSuggestions"; const QString BaseApplication::PROP_APPLICATION = "blueberry.application"; const QString BaseApplication::PROP_FORCE_PLUGIN_INSTALL = BaseApplication::ARG_FORCE_PLUGIN_INSTALL; const QString BaseApplication::PROP_NEWINSTANCE = BaseApplication::ARG_NEWINSTANCE; const QString BaseApplication::PROP_NO_LAZY_REGISTRY_CACHE_LOADING = BaseApplication::ARG_NO_LAZY_REGISTRY_CACHE_LOADING; const QString BaseApplication::PROP_NO_REGISTRY_CACHE = BaseApplication::ARG_NO_REGISTRY_CACHE; const QString BaseApplication::PROP_PRODUCT = "blueberry.product"; const QString BaseApplication::PROP_REGISTRY_MULTI_LANGUAGE = BaseApplication::ARG_REGISTRY_MULTI_LANGUAGE; class SplashCloserCallback : public QRunnable { public: SplashCloserCallback(QSplashScreen* splashscreen) : m_Splashscreen(splashscreen) { } void run() override { this->m_Splashscreen->close(); } private: QSplashScreen *m_Splashscreen; // Owned by BaseApplication::Impl }; struct BaseApplication::Impl { ctkProperties m_FWProps; QCoreApplication *m_QApp; int m_Argc; char **m_Argv; #ifdef Q_OS_MAC std::vector m_Argv_macOS; #endif QString m_AppName; QString m_OrgaName; QString m_OrgaDomain; bool m_SingleMode; bool m_SafeMode; QSplashScreen *m_Splashscreen; SplashCloserCallback *m_SplashscreenClosingCallback; bool m_LogQtMessages; QStringList m_PreloadLibs; QString m_ProvFile; Impl(int argc, char **argv) : m_Argc(argc), m_Argv(argv), #ifdef Q_OS_MAC m_Argv_macOS(), #endif m_SingleMode(false), m_SafeMode(true), m_Splashscreen(nullptr), m_SplashscreenClosingCallback(nullptr), m_LogQtMessages(false) { #ifdef Q_OS_MAC /* On macOS the process serial number is passed as an command line argument (-psn_) in certain circumstances. This option causes a Poco exception. We remove it, if present. */ m_Argv_macOS.reserve(argc + 1); const char psn[] = "-psn"; for (int i = 0; i < argc; ++i) { if (0 == strncmp(argv[i], psn, sizeof(psn) - 1)) continue; m_Argv_macOS.push_back(argv[i]); } m_Argv_macOS.push_back(nullptr); m_Argc = static_cast(m_Argv_macOS.size() - 1); m_Argv = m_Argv_macOS.data(); #endif } ~Impl() { delete m_SplashscreenClosingCallback; delete m_Splashscreen; delete m_QApp; } QVariant getProperty(const QString &property) const { auto iter = m_FWProps.find(property); return m_FWProps.end() != iter ? iter.value() : QVariant(); } void handleBooleanOption(const std::string &name, const std::string &) { if (ARG_LOG_QT_MESSAGES.toStdString() == name) { m_LogQtMessages = true; return; } auto fwKey = QString::fromStdString(name); // Translate some keys to proper framework properties if (ARG_CONSOLELOG == fwKey) fwKey = ctkPluginFrameworkLauncher::PROP_CONSOLE_LOG; // For all other options we use the command line option name as the // framework property key. m_FWProps[fwKey] = true; } void handlePreloadLibraryOption(const std::string &, const std::string &value) { m_PreloadLibs.push_back(QString::fromStdString(value)); } void handleClean(const std::string &, const std::string &) { m_FWProps[ctkPluginConstants::FRAMEWORK_STORAGE_CLEAN] = ctkPluginConstants::FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT; } void initializeCTKPluginFrameworkProperties(Poco::Util::LayeredConfiguration &configuration) { // Add all configuration key/value pairs as framework properties Poco::Util::LayeredConfiguration::Keys keys; Poco::Util::LayeredConfiguration::Keys keyStack; configuration.keys(keyStack); std::vector keyChain; while (!keyStack.empty()) { const auto currSubKey = keyStack.back(); if (!keyChain.empty() && keyChain.back() == currSubKey) { keyChain.pop_back(); keyStack.pop_back(); continue; } Poco::Util::LayeredConfiguration::Keys subKeys; configuration.keys(currSubKey, subKeys); if (subKeys.empty()) { std::string finalKey; keyStack.pop_back(); for (const auto& key : keyChain) finalKey += key + '.'; finalKey += currSubKey; keys.push_back(finalKey); } else { keyChain.push_back(currSubKey); for (const auto& key : subKeys) keyStack.push_back(key); } } for (const auto& key : keys) { if (configuration.hasProperty(key)) { // .ini and command line options overwrite already inserted keys auto qKey = QString::fromStdString(key); m_FWProps[qKey] = QString::fromStdString(configuration.getString(key)); } } } void parseProvisioningFile(const QString &filePath) { // Skip parsing if the file path is empty if (filePath.isEmpty()) return; auto consoleLog = this->getProperty(ctkPluginFrameworkLauncher::PROP_CONSOLE_LOG).toBool(); // Read initial plugins from a provisioning file QFileInfo provFile(filePath); QStringList pluginsToStart; if (provFile.exists()) { MITK_INFO(consoleLog) << "Using provisioning file: " << qPrintable(provFile.absoluteFilePath()); ProvisioningInfo provInfo(provFile.absoluteFilePath()); // It can still happen that the encoding is not compatible with the fromUtf8 function (i.e. when // manipulating the LANG variable). The QStringList in provInfo is empty then. if (provInfo.getPluginDirs().empty()) { MITK_ERROR << "Cannot search for provisioning file, the retrieved directory list is empty.\n" << "This can happen if there are some special non-ASCII characters in the install path."; } else { for(const auto& pluginPath : provInfo.getPluginDirs()) ctkPluginFrameworkLauncher::addSearchPath(pluginPath); auto pluginUrlsToStart = provInfo.getPluginsToStart(); - for (const auto& url : qAsConst(pluginUrlsToStart)) + for (const auto& url : std::as_const(pluginUrlsToStart)) pluginsToStart.push_back(url.toString()); } } else { MITK_INFO(consoleLog) << "Provisionig file does not exist."; } if (!pluginsToStart.isEmpty()) { m_FWProps[ctkPluginFrameworkLauncher::PROP_PLUGINS] = pluginsToStart; // Use transient start with declared activation policy (this helps when the provisioning file // changes and some plug-ins should not be installed in the application any more). ctkPlugin::StartOptions startOptions(ctkPlugin::START_TRANSIENT | ctkPlugin::START_ACTIVATION_POLICY); m_FWProps[ctkPluginFrameworkLauncher::PROP_PLUGINS_START_OPTIONS] = static_cast(startOptions); } } }; BaseApplication::BaseApplication(int argc, char **argv) : Application(), d(new Impl(argc, argv)) { } BaseApplication::~BaseApplication() { delete d; } void BaseApplication::printHelp(const std::string &, const std::string &) { Poco::Util::HelpFormatter help(this->options()); help.setAutoIndent(); help.setCommand(this->commandName()); help.format(std::cout); exit(EXIT_OK); } void BaseApplication::setApplicationName(const QString &name) { if (nullptr != qApp) qApp->setApplicationName(name); d->m_AppName = name; } QString BaseApplication::getApplicationName() const { return nullptr != qApp ? qApp->applicationName() : d->m_AppName; } void BaseApplication::setOrganizationName(const QString &name) { if (nullptr != qApp) qApp->setOrganizationName(name); d->m_OrgaName = name; } QString BaseApplication::getOrganizationName() const { return nullptr != qApp ? qApp->organizationName() : d->m_OrgaName; } void BaseApplication::setOrganizationDomain(const QString &domain) { if (nullptr != qApp) qApp->setOrganizationDomain(domain); d->m_OrgaDomain = domain; } QString BaseApplication::getOrganizationDomain() const { return nullptr != qApp ? qApp->organizationDomain() : d->m_OrgaDomain; } void BaseApplication::setSingleMode(bool singleMode) { if (nullptr != qApp) return; d->m_SingleMode = singleMode; } bool BaseApplication::getSingleMode() const { return d->m_SingleMode; } void BaseApplication::setSafeMode(bool safeMode) { if (nullptr != qApp && nullptr == d->m_QApp) return; d->m_SafeMode = safeMode; nullptr == d->m_QApp && getSingleMode() ? static_cast(d->m_QApp)->setSafeMode(safeMode) : static_cast(d->m_QApp)->setSafeMode(safeMode); } bool BaseApplication::getSafeMode() const { return d->m_SafeMode; } void BaseApplication::setPreloadLibraries(const QStringList &libraryBaseNames) { d->m_PreloadLibs = libraryBaseNames; } QStringList BaseApplication::getPreloadLibraries() const { return d->m_PreloadLibs; } void BaseApplication::setProvisioningFilePath(const QString &filePath) { d->m_ProvFile = filePath; } QString BaseApplication::getProvisioningFilePath() const { auto provFilePath = d->m_ProvFile; // A null QString means look up a default provisioning file if (provFilePath.isNull() && nullptr != qApp) { QFileInfo appFilePath(QCoreApplication::applicationFilePath()); QDir basePath(QCoreApplication::applicationDirPath()); auto provFileName = appFilePath.baseName() + ".provisioning"; QFileInfo provFile(basePath.absoluteFilePath(provFileName)); #ifdef Q_OS_MAC /* * On macOS, if started from the build directory, the .provisioning file is located at: * * The executable path is: * * In this case we have to cdUp threetimes. * * During packaging the MitkWorkbench.provisioning file is placed at the same * level like the executable. Nothing has to be done. */ if (!provFile.exists()) { basePath.cdUp(); basePath.cdUp(); basePath.cdUp(); provFile = basePath.absoluteFilePath(provFileName); } #endif if (provFile.exists()) { provFilePath = provFile.absoluteFilePath(); } #ifdef CMAKE_INTDIR else { basePath.cdUp(); provFile.setFile(basePath.absoluteFilePath(provFileName)); if (provFile.exists()) provFilePath = provFile.absoluteFilePath(); } #endif } return provFilePath; } void BaseApplication::initializeQt() { if (nullptr != qApp) return; // Prevent conflicts between native OpenGL applications and QWebEngine QQuickWindow::setGraphicsApi(QSGRendererInterface::Software); #ifdef Q_OS_LINUX qputenv("QTWEBENGINE_CHROMIUM_FLAGS", "--single-process"); // See T29332 #endif // If parameters have been set before, we have to store them to hand them // through to the application auto appName = this->getApplicationName(); auto orgName = this->getOrganizationName(); auto orgDomain = this->getOrganizationDomain(); // Create a QCoreApplication instance this->getQApplication(); // Provide parameters to QCoreApplication this->setApplicationName(appName); this->setOrganizationName(orgName); this->setOrganizationDomain(orgDomain); qInstallMessageHandler(!d->m_LogQtMessages ? outputImportantQtMessage : outputQtMessage); QWebEngineUrlScheme qtHelpScheme("qthelp"); qtHelpScheme.setFlags(QWebEngineUrlScheme::LocalScheme | QWebEngineUrlScheme::LocalAccessAllowed); QWebEngineUrlScheme::registerScheme(qtHelpScheme); } void BaseApplication::initialize(Poco::Util::Application &self) { // 1. Call the super-class method Poco::Util::Application::initialize(self); // 2. Initialize the Qt framework (by creating a QCoreApplication) this->initializeQt(); // 3. Load the "default" configuration, which involves parsing // an optional .ini file and parsing any // command line arguments this->loadConfiguration(); // 4. Add configuration data from the command line and the // optional .ini file as CTK plugin // framework properties. d->initializeCTKPluginFrameworkProperties(this->config()); // 5. Initialize splash screen if an image path is provided // in the .ini file this->initializeSplashScreen(qApp); // 6. Set the custom CTK Plugin Framework storage directory QString storageDir = this->getCTKFrameworkStorageDir(); if (!storageDir.isEmpty()) { d->m_FWProps[ctkPluginConstants::FRAMEWORK_STORAGE] = storageDir; // Initialize core service preferences at the exact same location as their predecessor BlueBerry preferences mitk::CoreServicePointer preferencesService(mitk::CoreServices::GetPreferencesService()); preferencesService->InitializeStorage(storageDir.toStdString() + "/data/3/prefs.xml"); } // 7. Set the library search paths and the pre-load library property this->initializeLibraryPaths(); auto preloadLibs = this->getPreloadLibraries(); if (!preloadLibs.isEmpty()) d->m_FWProps[ctkPluginConstants::FRAMEWORK_PRELOAD_LIBRARIES] = preloadLibs; // 8. Initialize the CppMicroServices library. // The initializeCppMicroServices() method reuses the // FRAMEWORK_STORAGE property, so we call it after the // getCTKFrameworkStorageDir method. this->initializeCppMicroServices(); // 9. Parse the (optional) provisioning file and set the // correct framework properties. d->parseProvisioningFile(this->getProvisioningFilePath()); // 10. Set the CTK Plugin Framework properties ctkPluginFrameworkLauncher::setFrameworkProperties(d->m_FWProps); } void BaseApplication::uninitialize() { auto pfw = this->getFramework(); if (pfw) { pfw->stop(); // Wait for up to 10 seconds for the CTK plugin framework to stop pfw->waitForStop(10000); } Poco::Util::Application::uninitialize(); } int BaseApplication::getArgc() const { return d->m_Argc; } char **BaseApplication::getArgv() const { return d->m_Argv; } QString BaseApplication::getCTKFrameworkStorageDir() const { QString storageDir; if (this->getSingleMode()) { // This function checks if an instance is already running and either sends a message to // it containing the command line arguments or checks if a new instance was forced by // providing the BlueBerry.newInstance command line argument. In the latter case, a path // to a temporary directory for the new application's storage directory is returned. storageDir = handleNewAppInstance(static_cast(d->m_QApp), d->m_Argc, d->m_Argv, ARG_NEWINSTANCE); } if (storageDir.isEmpty()) { // This is a new instance and no other instance is already running. We specify the // storage directory here (this is the same code as in berryInternalPlatform.cpp) // so that we can re-use the location for the persistent data location of the // the CppMicroServices library. // Append a hash value of the absolute path of the executable to the data location. // This allows to start the same application from different build or install trees. storageDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/" + this->getOrganizationName() + "/" + this->getApplicationName() + '_'; storageDir += QString::number(qHash(QCoreApplication::applicationDirPath())) + "/"; } return storageDir; } void BaseApplication::initializeCppMicroServices() { auto storageDir = this->getProperty(ctkPluginConstants::FRAMEWORK_STORAGE).toString(); if (!storageDir.isEmpty()) us::ModuleSettings::SetStoragePath((storageDir + "us" + QDir::separator()).toStdString()); } QCoreApplication *BaseApplication::getQApplication() const { if (nullptr == qApp) { vtkLogger::SetStderrVerbosity(vtkLogger::VERBOSITY_WARNING); vtkOpenGLRenderWindow::SetGlobalMaximumNumberOfMultiSamples(0); auto defaultFormat = QVTKOpenGLNativeWidget::defaultFormat(); defaultFormat.setSamples(0); QSurfaceFormat::setDefaultFormat(defaultFormat); #ifdef Q_OS_OSX QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); #endif QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); #endif QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); d->m_QApp = this->getSingleMode() ? static_cast(new QmitkSingleApplication(d->m_Argc, d->m_Argv, this->getSafeMode())) : static_cast(new QmitkSafeApplication(d->m_Argc, d->m_Argv, this->getSafeMode())); } return qApp; } void BaseApplication::initializeLibraryPaths() { QStringList suffixes; suffixes << "plugins"; #ifdef Q_OS_WINDOWS suffixes << "bin/plugins"; #ifdef CMAKE_INTDIR suffixes << "bin/" CMAKE_INTDIR "/plugins"; #endif #else suffixes << "lib/plugins"; #ifdef CMAKE_INTDIR suffixes << "lib/" CMAKE_INTDIR "/plugins"; #endif #endif #ifdef Q_OS_MAC suffixes << "../../plugins"; #endif // We add a couple of standard library search paths for plug-ins QDir appDir(QCoreApplication::applicationDirPath()); // Walk one directory up and add bin and lib sub-dirs; this might be redundant appDir.cdUp(); - for (const auto& suffix : qAsConst(suffixes)) + for (const auto& suffix : std::as_const(suffixes)) ctkPluginFrameworkLauncher::addSearchPath(appDir.absoluteFilePath(suffix)); } int BaseApplication::main(const std::vector &args) { // Start the plugin framework and all installed plug-ins according to their auto-start setting QStringList arguments; for (auto const &arg : args) arguments.push_back(QString::fromStdString(arg)); if (nullptr != d->m_Splashscreen) { // A splash screen is displayed. Create the closing callback. d->m_SplashscreenClosingCallback = new SplashCloserCallback(d->m_Splashscreen); } return ctkPluginFrameworkLauncher::run(d->m_SplashscreenClosingCallback, QVariant::fromValue(arguments)).toInt(); } void BaseApplication::defineOptions(Poco::Util::OptionSet &options) { Poco::Util::Option helpOption("help", "h", "print this help text"); helpOption.callback(Poco::Util::OptionCallback(this, &BaseApplication::printHelp)); options.addOption(helpOption); Poco::Util::Option newInstanceOption(ARG_NEWINSTANCE.toStdString(), "", "forces a new instance of this application"); newInstanceOption.callback(Poco::Util::OptionCallback(d, &Impl::handleBooleanOption)); options.addOption(newInstanceOption); Poco::Util::Option cleanOption(ARG_CLEAN.toStdString(), "", "cleans the plugin cache"); cleanOption.callback(Poco::Util::OptionCallback(d, &Impl::handleClean)); options.addOption(cleanOption); Poco::Util::Option productOption(ARG_PRODUCT.toStdString(), "", "the id of the product to be launched"); productOption.argument("").binding(PROP_PRODUCT.toStdString()); options.addOption(productOption); Poco::Util::Option appOption(ARG_APPLICATION.toStdString(), "", "the id of the application extension to be executed"); appOption.argument("").binding(PROP_APPLICATION.toStdString()); options.addOption(appOption); Poco::Util::Option provOption(ARG_PROVISIONING.toStdString(), "", "the location of a provisioning file"); provOption.argument("").binding(ARG_PROVISIONING.toStdString()); options.addOption(provOption); Poco::Util::Option storageDirOption(ARG_STORAGE_DIR.toStdString(), "", "the location for storing persistent application data"); storageDirOption.argument("").binding(ctkPluginConstants::FRAMEWORK_STORAGE.toStdString()); options.addOption(storageDirOption); Poco::Util::Option consoleLogOption(ARG_CONSOLELOG.toStdString(), "", "log messages to the console"); consoleLogOption.callback(Poco::Util::OptionCallback(d, &Impl::handleBooleanOption)); options.addOption(consoleLogOption); Poco::Util::Option debugOption(ARG_DEBUG.toStdString(), "", "enable debug mode"); debugOption.argument("", false).binding(ctkPluginFrameworkLauncher::PROP_DEBUG.toStdString()); options.addOption(debugOption); Poco::Util::Option forcePluginOption(ARG_FORCE_PLUGIN_INSTALL.toStdString(), "", "force installing plug-ins with same symbolic name"); forcePluginOption.callback(Poco::Util::OptionCallback(d, &Impl::handleBooleanOption)); options.addOption(forcePluginOption); Poco::Util::Option preloadLibsOption(ARG_PRELOAD_LIBRARY.toStdString(), "", "preload a library"); preloadLibsOption.argument("") .repeatable(true) .callback(Poco::Util::OptionCallback(d, &Impl::handlePreloadLibraryOption)); options.addOption(preloadLibsOption); Poco::Util::Option noRegistryCacheOption(ARG_NO_REGISTRY_CACHE.toStdString(), "", "do not use a cache for the registry"); noRegistryCacheOption.callback(Poco::Util::OptionCallback(d, &Impl::handleBooleanOption)); options.addOption(noRegistryCacheOption); Poco::Util::Option noLazyRegistryCacheLoadingOption(ARG_NO_LAZY_REGISTRY_CACHE_LOADING.toStdString(), "", "do not use lazy cache loading for the registry"); noLazyRegistryCacheLoadingOption.callback(Poco::Util::OptionCallback(d, &Impl::handleBooleanOption)); options.addOption(noLazyRegistryCacheLoadingOption); Poco::Util::Option registryMultiLanguageOption(ARG_REGISTRY_MULTI_LANGUAGE.toStdString(), "", "enable multi-language support for the registry"); registryMultiLanguageOption.callback(Poco::Util::OptionCallback(d, &Impl::handleBooleanOption)); options.addOption(registryMultiLanguageOption); Poco::Util::Option splashScreenOption(ARG_SPLASH_IMAGE.toStdString(), "", "optional picture to use as a splash screen"); splashScreenOption.argument("").binding(ARG_SPLASH_IMAGE.toStdString()); options.addOption(splashScreenOption); Poco::Util::Option xargsOption(ARG_XARGS.toStdString(), "", "Extended argument list"); xargsOption.argument("").binding(ARG_XARGS.toStdString()); options.addOption(xargsOption); Poco::Util::Option logQtMessagesOption(ARG_LOG_QT_MESSAGES.toStdString(), "", "log Qt messages"); logQtMessagesOption.callback(Poco::Util::OptionCallback(d, &Impl::handleBooleanOption)); options.addOption(logQtMessagesOption); Poco::Util::Option labelSetPresetOption(ARG_SEGMENTATION_LABELSET_PRESET.toStdString(), "", "use this label set preset for new segmentations"); labelSetPresetOption.argument("").binding(ARG_SEGMENTATION_LABELSET_PRESET.toStdString()); options.addOption(labelSetPresetOption); Poco::Util::Option labelSuggestionsOption(ARG_SEGMENTATION_LABEL_SUGGESTIONS.toStdString(), "", "use this list of predefined suggestions for segmentation labels"); labelSuggestionsOption.argument("").binding(ARG_SEGMENTATION_LABEL_SUGGESTIONS.toStdString()); options.addOption(labelSuggestionsOption); Poco::Util::Application::defineOptions(options); } QSharedPointer BaseApplication::getFramework() const { return ctkPluginFrameworkLauncher::getPluginFramework(); } ctkPluginContext *BaseApplication::getFrameworkContext() const { auto framework = getFramework(); return framework ? framework->getPluginContext() : nullptr; } void BaseApplication::initializeSplashScreen(QCoreApplication * application) const { auto pixmapFileNameProp = d->getProperty(ARG_SPLASH_IMAGE); if (!pixmapFileNameProp.isNull()) { auto pixmapFileName = pixmapFileNameProp.toString(); QFileInfo checkFile(pixmapFileName); if (checkFile.exists() && checkFile.isFile()) { QPixmap pixmap(checkFile.absoluteFilePath()); d->m_Splashscreen = new QSplashScreen(pixmap, Qt::WindowStaysOnTopHint); d->m_Splashscreen->show(); application->processEvents(); } } } QHash BaseApplication::getFrameworkProperties() const { return d->m_FWProps; } int BaseApplication::run() { this->init(d->m_Argc, d->m_Argv); return Application::run(); } void BaseApplication::setProperty(const QString &property, const QVariant &value) { d->m_FWProps[property] = value; } QVariant BaseApplication::getProperty(const QString &property) const { return d->getProperty(property); } void BaseApplication::installTranslator(QTranslator* translator) { this->getQApplication()->installTranslator(translator); } bool BaseApplication::isRunning() { auto app = dynamic_cast(this->getQApplication()); if (nullptr != app) app->isRunning(); mitkThrow() << "Method not implemented."; } void BaseApplication::sendMessage(const QByteArray msg) { auto app = dynamic_cast(this->getQApplication()); if (nullptr != app) app->sendMessage(msg); mitkThrow() << "Method not implemented."; } } diff --git a/Modules/DICOMUI/src/QmitkDicomLocalStorageWidget.cpp b/Modules/DICOMUI/src/QmitkDicomLocalStorageWidget.cpp index 8ee0dae06b..e7197d08ee 100644 --- a/Modules/DICOMUI/src/QmitkDicomLocalStorageWidget.cpp +++ b/Modules/DICOMUI/src/QmitkDicomLocalStorageWidget.cpp @@ -1,229 +1,229 @@ /*============================================================================ 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. ============================================================================*/ // Qmitk #include "QmitkDicomLocalStorageWidget.h" // Qt #include #include #include #include #include const std::string QmitkDicomLocalStorageWidget::Widget_ID = "org.mitk.Widgets.QmitkDicomLocalStorageWidget"; QmitkDicomLocalStorageWidget::QmitkDicomLocalStorageWidget(QWidget *parent) : QWidget(parent), m_LocalIndexer(new ctkDICOMIndexer(parent)), m_Controls(nullptr) { CreateQtPartControl(this); } QmitkDicomLocalStorageWidget::~QmitkDicomLocalStorageWidget() { m_LocalDatabase->closeDatabase(); } void QmitkDicomLocalStorageWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { m_Controls = new Ui::QmitkDicomLocalStorageWidgetControls; m_Controls->setupUi(parent); connect(m_Controls->deleteButton, SIGNAL(clicked()), this, SLOT(OnDeleteButtonClicked())); connect(m_Controls->viewInternalDataButton, SIGNAL(clicked()), this, SLOT(OnViewButtonClicked())); connect(m_Controls->ctkDicomBrowser, SIGNAL(seriesSelectionChanged(const QStringList &)), this, SLOT(OnSeriesSelectionChanged(const QStringList &))); connect(m_Controls->ctkDicomBrowser, SIGNAL(seriesSelectionChanged(const QStringList &)), this, SLOT(OnSeriesSelectionChanged(const QStringList &))); connect( m_Controls->ctkDicomBrowser, SIGNAL(seriesDoubleClicked(const QModelIndex &)), this, SLOT(OnViewButtonClicked())); connect(m_LocalIndexer, SIGNAL(indexingComplete(int, int, int, int)), this, SIGNAL(SignalFinishedImport())); m_Controls->ctkDicomBrowser->setTableOrientation(Qt::Vertical); } } void QmitkDicomLocalStorageWidget::OnStartDicomImport(const QString &dicomData) { if (m_LocalDatabase->isOpen()) { m_LocalIndexer->addDirectory(dicomData); } } void QmitkDicomLocalStorageWidget::OnStartDicomImport(const QStringList &dicomData) { if (m_LocalDatabase->isOpen()) { m_LocalIndexer->addListOfFiles( dicomData); } } void QmitkDicomLocalStorageWidget::OnDeleteButtonClicked() { if (!this->DeletePatients()) { if (!this->DeleteStudies()) { this->DeleteSeries(); } } m_Controls->ctkDicomBrowser->updateTableViews(); } bool QmitkDicomLocalStorageWidget::DeletePatients() { auto selectedPatientUIDs = m_Controls->ctkDicomBrowser->currentPatientsSelection(); if (!selectedPatientUIDs.empty()) { QStringList studyUIDs; - for (const auto &patientUID : qAsConst(selectedPatientUIDs)) + for (const auto &patientUID : std::as_const(selectedPatientUIDs)) studyUIDs.append(m_LocalDatabase->studiesForPatient(patientUID)); QStringList seriesUIDs; for (const auto &studyUID : studyUIDs) seriesUIDs.append(m_LocalDatabase->seriesForStudy(studyUID)); auto answer = QMessageBox::question(nullptr, "Delete Patients", QString("Do you really want to delete %1 %2, containing %3 series in %4 %5?") .arg(selectedPatientUIDs.count()) .arg(selectedPatientUIDs.count() != 1 ? "patients" : "patient") .arg(seriesUIDs.count()) .arg(studyUIDs.count()) .arg(studyUIDs.count() != 1 ? "studies" : "study"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (answer == QMessageBox::Yes) { - for (const auto &patientUID : qAsConst(selectedPatientUIDs)) + for (const auto &patientUID : std::as_const(selectedPatientUIDs)) m_LocalDatabase->removePatient(patientUID); } return true; } return false; } bool QmitkDicomLocalStorageWidget::DeleteStudies() { auto selectedStudyUIDs = m_Controls->ctkDicomBrowser->currentStudiesSelection(); if (!selectedStudyUIDs.empty()) { QStringList seriesUIDs; - for (const auto &studyUID : qAsConst(selectedStudyUIDs)) + for (const auto &studyUID : std::as_const(selectedStudyUIDs)) seriesUIDs.append(m_LocalDatabase->seriesForStudy(studyUID)); auto answer = QMessageBox::question(nullptr, "Delete Studies", QString("Do you really want to delete %1 %2, containing %3 series?") .arg(selectedStudyUIDs.count()) .arg(selectedStudyUIDs.count() != 1 ? "studies" : "study") .arg(seriesUIDs.count()), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (answer == QMessageBox::Yes) { - for (const auto &studyUID : qAsConst(selectedStudyUIDs)) + for (const auto &studyUID : std::as_const(selectedStudyUIDs)) m_LocalDatabase->removeStudy(studyUID); } return true; } return false; } bool QmitkDicomLocalStorageWidget::DeleteSeries() { auto selectedSeriesUIDs = m_Controls->ctkDicomBrowser->currentSeriesSelection(); if (!selectedSeriesUIDs.empty()) { auto answer = QMessageBox::question(nullptr, "Delete Series", QString("Do you really want to delete %1 series?").arg(selectedSeriesUIDs.count()), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (answer == QMessageBox::Yes) { - for (const auto &seriesUID : qAsConst(selectedSeriesUIDs)) + for (const auto &seriesUID : std::as_const(selectedSeriesUIDs)) m_LocalDatabase->removeSeries(seriesUID); } return true; } return false; } void QmitkDicomLocalStorageWidget::OnViewButtonClicked() { QStringList uids = m_Controls->ctkDicomBrowser->currentSeriesSelection(); QString uid; foreach (uid, uids) { QStringList filesForSeries = m_LocalDatabase->filesForSeries(uid); QHash eventProperty; eventProperty.insert("FilesForSeries", filesForSeries); if (!filesForSeries.isEmpty()) { QString modality = m_LocalDatabase->fileValue(filesForSeries.at(0), "0008,0060"); eventProperty.insert("Modality", modality); } emit SignalDicomToDataManager(eventProperty); } } void QmitkDicomLocalStorageWidget::SetDatabaseDirectory(QString newDatatbaseDirectory) { QDir databaseDirecory = QDir(newDatatbaseDirectory); if (!databaseDirecory.exists()) { databaseDirecory.mkpath(databaseDirecory.absolutePath()); } QString newDatatbaseFile = databaseDirecory.absolutePath() + QString("/ctkDICOM.sql"); this->SetDatabase(newDatatbaseFile); } void QmitkDicomLocalStorageWidget::SetDatabase(QString databaseFile) { m_LocalDatabase = new ctkDICOMDatabase(databaseFile); m_LocalDatabase->setParent(this); m_Controls->ctkDicomBrowser->setDICOMDatabase(m_LocalDatabase); m_LocalIndexer->setDatabase(m_LocalDatabase); } void QmitkDicomLocalStorageWidget::OnSeriesSelectionChanged(const QStringList &s) { m_Controls->viewInternalDataButton->setEnabled((s.size() != 0)); } diff --git a/Modules/QtWidgets/src/QmitkAbstractNodeSelectionWidget.cpp b/Modules/QtWidgets/src/QmitkAbstractNodeSelectionWidget.cpp index acc64021c6..52e3f98ac5 100644 --- a/Modules/QtWidgets/src/QmitkAbstractNodeSelectionWidget.cpp +++ b/Modules/QtWidgets/src/QmitkAbstractNodeSelectionWidget.cpp @@ -1,426 +1,426 @@ /*============================================================================ 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 "QmitkAbstractNodeSelectionWidget.h" #include "QmitkModelViewSelectionConnector.h" QmitkAbstractNodeSelectionWidget::QmitkAbstractNodeSelectionWidget(QWidget* parent) : QWidget(parent) , m_InvalidInfo("Error. Select data.") , m_EmptyInfo("Empty. Make a selection.") , m_PopUpTitel("Select a data node") , m_PopUpHint("") , m_IsOptional(false) , m_SelectOnlyVisibleNodes(true) , m_DataStorageDeletedTag(0) , m_LastEmissionAllowance(true) , m_RecursionGuard(false) { } QmitkAbstractNodeSelectionWidget::~QmitkAbstractNodeSelectionWidget() { auto dataStorage = m_DataStorage.Lock(); if (dataStorage.IsNotNull()) { // remove Listener for the data storage itself dataStorage->RemoveObserver(m_DataStorageDeletedTag); // remove "add node listener" from data storage dataStorage->AddNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkAbstractNodeSelectionWidget::NodeAddedToStorage)); // remove "remove node listener" from data storage dataStorage->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkAbstractNodeSelectionWidget::NodeRemovedFromStorage)); } for (auto& node : m_CurrentInternalSelection) { this->RemoveNodeObserver(node); } } QmitkAbstractNodeSelectionWidget::NodeList QmitkAbstractNodeSelectionWidget::GetSelectedNodes() const { return this->CompileEmitSelection(); } QmitkAbstractNodeSelectionWidget::ConstNodeStdVector QmitkAbstractNodeSelectionWidget::GetSelectedNodesStdVector() const { auto result = this->GetSelectedNodes(); return ConstNodeStdVector(result.begin(), result.end()); } void QmitkAbstractNodeSelectionWidget::SetDataStorage(mitk::DataStorage* dataStorage) { if (m_DataStorage == dataStorage) { return; } auto oldStorage = m_DataStorage.Lock(); if (oldStorage.IsNotNull()) { // remove Listener for the data storage itself oldStorage->RemoveObserver(m_DataStorageDeletedTag); // remove "add node listener" from old data storage oldStorage->AddNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkAbstractNodeSelectionWidget::NodeAddedToStorage)); // remove "remove node listener" from old data storage oldStorage->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkAbstractNodeSelectionWidget::NodeRemovedFromStorage)); } m_DataStorage = dataStorage; auto newStorage = m_DataStorage.Lock(); if (newStorage.IsNotNull()) { // add Listener for the data storage itself auto command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkAbstractNodeSelectionWidget::SetDataStorageDeleted); m_DataStorageDeletedTag = newStorage->AddObserver(itk::DeleteEvent(), command); // add "add node listener" for new data storage newStorage->AddNodeEvent.AddListener( mitk::MessageDelegate1(this, &QmitkAbstractNodeSelectionWidget::NodeAddedToStorage)); // add remove node listener for new data storage newStorage->RemoveNodeEvent.AddListener( mitk::MessageDelegate1(this, &QmitkAbstractNodeSelectionWidget::NodeRemovedFromStorage)); } this->OnDataStorageChanged(); this->HandleChangeOfInternalSelection({}); } void QmitkAbstractNodeSelectionWidget::SetNodePredicate(const mitk::NodePredicateBase* nodePredicate) { if (m_NodePredicate != nodePredicate) { m_NodePredicate = nodePredicate; this->OnNodePredicateChanged(); NodeList newInternalNodes; for (auto& node : m_CurrentInternalSelection) { if (m_NodePredicate.IsNull() || m_NodePredicate->CheckNode(node)) { newInternalNodes.append(node); } } if (!m_SelectOnlyVisibleNodes) { for (auto& node : m_CurrentExternalSelection) { if (!newInternalNodes.contains(node) && (m_NodePredicate.IsNull() || m_NodePredicate->CheckNode(node))) { newInternalNodes.append(node); } } } this->HandleChangeOfInternalSelection(newInternalNodes); } } void QmitkAbstractNodeSelectionWidget::HandleChangeOfInternalSelection(NodeList newInternalSelection) { if (!EqualNodeSelections(m_CurrentInternalSelection, newInternalSelection)) { this->ReviseSelectionChanged(m_CurrentInternalSelection, newInternalSelection); this->SetCurrentInternalSelection(newInternalSelection); this->OnInternalSelectionChanged(); auto newEmission = this->CompileEmitSelection(); this->EmitSelection(newEmission); this->UpdateInfo(); } } void QmitkAbstractNodeSelectionWidget::SetCurrentSelection(NodeList selectedNodes) { if (!m_RecursionGuard) { m_CurrentExternalSelection = selectedNodes; auto dataStorage = m_DataStorage.Lock(); NodeList newInternalSelection; - for (const auto &node : qAsConst(selectedNodes)) + for (const auto &node : std::as_const(selectedNodes)) { if (dataStorage.IsNotNull() && dataStorage->Exists(node) && (m_NodePredicate.IsNull() || m_NodePredicate->CheckNode(node))) { newInternalSelection.append(node); } } this->HandleChangeOfInternalSelection(newInternalSelection); } } const mitk::NodePredicateBase* QmitkAbstractNodeSelectionWidget::GetNodePredicate() const { return m_NodePredicate; } QString QmitkAbstractNodeSelectionWidget::GetInvalidInfo() const { return m_InvalidInfo; } QString QmitkAbstractNodeSelectionWidget::GetEmptyInfo() const { return m_EmptyInfo; } QString QmitkAbstractNodeSelectionWidget::GetPopUpTitel() const { return m_PopUpTitel; } QString QmitkAbstractNodeSelectionWidget::GetPopUpHint() const { return m_PopUpHint; } bool QmitkAbstractNodeSelectionWidget::GetSelectionIsOptional() const { return m_IsOptional; } bool QmitkAbstractNodeSelectionWidget::GetSelectOnlyVisibleNodes() const { return m_SelectOnlyVisibleNodes; } void QmitkAbstractNodeSelectionWidget::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) { if (m_SelectOnlyVisibleNodes != selectOnlyVisibleNodes) { m_SelectOnlyVisibleNodes = selectOnlyVisibleNodes; auto newEmission = this->CompileEmitSelection(); this->EmitSelection(newEmission); } } void QmitkAbstractNodeSelectionWidget::SetInvalidInfo(QString info) { m_InvalidInfo = info; this->UpdateInfo(); } void QmitkAbstractNodeSelectionWidget::SetEmptyInfo(QString info) { m_EmptyInfo = info; this->UpdateInfo(); } void QmitkAbstractNodeSelectionWidget::SetPopUpTitel(QString info) { m_PopUpTitel = info; } void QmitkAbstractNodeSelectionWidget::SetPopUpHint(QString info) { m_PopUpHint = info; } void QmitkAbstractNodeSelectionWidget::SetSelectionIsOptional(bool isOptional) { m_IsOptional = isOptional; this->UpdateInfo(); } void QmitkAbstractNodeSelectionWidget::SetDataStorageDeleted() { this->OnDataStorageChanged(); this->HandleChangeOfInternalSelection({}); } void QmitkAbstractNodeSelectionWidget::ReviseSelectionChanged(const NodeList& /*oldInternalSelection*/, NodeList& /*newInternalSelection*/) { } bool QmitkAbstractNodeSelectionWidget::AllowEmissionOfSelection(const NodeList& /*emissionCandidates*/) const { return true; } void QmitkAbstractNodeSelectionWidget::EmitSelection(const NodeList& emissionCandidates) { m_LastEmissionAllowance = this->AllowEmissionOfSelection(emissionCandidates); if (m_LastEmissionAllowance && !EqualNodeSelections(m_LastEmission, emissionCandidates)) { m_RecursionGuard = true; emit CurrentSelectionChanged(emissionCandidates); m_RecursionGuard = false; m_LastEmission = emissionCandidates; } } void QmitkAbstractNodeSelectionWidget::SetCurrentInternalSelection(NodeList selectedNodes) { for (auto& node : m_CurrentInternalSelection) { this->RemoveNodeObserver(node); } m_CurrentInternalSelection = selectedNodes; for (auto& node : m_CurrentInternalSelection) { this->AddNodeObserver(node); } } const QmitkAbstractNodeSelectionWidget::NodeList& QmitkAbstractNodeSelectionWidget::GetCurrentInternalSelection() const { return m_CurrentInternalSelection; } const QmitkAbstractNodeSelectionWidget::NodeList& QmitkAbstractNodeSelectionWidget::GetCurrentExternalSelection() const { return m_CurrentExternalSelection; } void QmitkAbstractNodeSelectionWidget::OnNodePredicateChanged() { } void QmitkAbstractNodeSelectionWidget::OnDataStorageChanged() { } void QmitkAbstractNodeSelectionWidget::OnInternalSelectionChanged() { } void QmitkAbstractNodeSelectionWidget::NodeAddedToStorage(const mitk::DataNode* node) { this->OnNodeAddedToStorage(node); } void QmitkAbstractNodeSelectionWidget::OnNodeAddedToStorage(const mitk::DataNode* /*node*/) { } void QmitkAbstractNodeSelectionWidget::NodeRemovedFromStorage(const mitk::DataNode* node) { this->OnNodeRemovedFromStorage(node); this->RemoveNodeFromSelection(node); } void QmitkAbstractNodeSelectionWidget::OnNodeRemovedFromStorage(const mitk::DataNode* /*node*/) { } void QmitkAbstractNodeSelectionWidget::OnNodeModified(const itk::Object* caller, const itk::EventObject& event) { if (itk::ModifiedEvent().CheckEvent(&event)) { auto node = dynamic_cast(caller); if (node) { if (m_NodePredicate.IsNotNull() && !m_NodePredicate->CheckNode(node)) { this->RemoveNodeFromSelection(node); } else { auto oldAllowance = m_LastEmissionAllowance; auto newEmission = this->CompileEmitSelection(); auto nonConstNode = const_cast(node); if (newEmission.contains(nonConstNode) && (oldAllowance != this->AllowEmissionOfSelection(newEmission))) { this->EmitSelection(newEmission); this->UpdateInfo(); } } } } } QmitkAbstractNodeSelectionWidget::NodeList QmitkAbstractNodeSelectionWidget::CompileEmitSelection() const { NodeList result = m_CurrentInternalSelection; if (!m_SelectOnlyVisibleNodes) { for (const auto &node : m_CurrentExternalSelection) { if (!result.contains(node) && m_NodePredicate.IsNotNull() && !m_NodePredicate->CheckNode(node)) { result.append(node); } } } return result; } void QmitkAbstractNodeSelectionWidget::RemoveNodeFromSelection(const mitk::DataNode* node) { auto newSelection = m_CurrentInternalSelection; auto finding = std::find(std::begin(newSelection), std::end(newSelection), node); if (finding != std::end(newSelection)) { newSelection.erase(finding); this->HandleChangeOfInternalSelection(newSelection); } } void QmitkAbstractNodeSelectionWidget::AddNodeObserver(mitk::DataNode* node) { if (node) { auto modifiedCommand = itk::MemberCommand::New(); modifiedCommand->SetCallbackFunction(this, &QmitkAbstractNodeSelectionWidget::OnNodeModified); auto nodeModifiedObserverTag = node->AddObserver(itk::ModifiedEvent(), modifiedCommand); m_NodeObserverTags.insert(std::make_pair(node, nodeModifiedObserverTag)); } } void QmitkAbstractNodeSelectionWidget::RemoveNodeObserver(mitk::DataNode* node) { if (node) { auto finding = m_NodeObserverTags.find(node); if (finding != std::end(m_NodeObserverTags)) { node->RemoveObserver(finding->second); } else { MITK_ERROR << "Selection widget is in a wrong state. A node should be removed from the internal selection but seems to have no observer. Node:" << node; } m_NodeObserverTags.erase(node); } } diff --git a/Modules/QtWidgets/src/QmitkDataStorageFavoriteNodesInspector.cpp b/Modules/QtWidgets/src/QmitkDataStorageFavoriteNodesInspector.cpp index 271e19c06d..80adde42ae 100644 --- a/Modules/QtWidgets/src/QmitkDataStorageFavoriteNodesInspector.cpp +++ b/Modules/QtWidgets/src/QmitkDataStorageFavoriteNodesInspector.cpp @@ -1,55 +1,55 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include "QmitkDataStorageDefaultListModel.h" #include "mitkNodePredicateAnd.h" #include "QPushButton" #include "QmitkStyleManager.h" QmitkDataStorageFavoriteNodesInspector::QmitkDataStorageFavoriteNodesInspector(QWidget* parent/* = nullptr*/) : QmitkDataStorageListInspector(parent) { auto favoriteNodesButton = new QPushButton(parent); QmitkDataStorageListInspector::m_Controls.verticalLayout->addWidget(favoriteNodesButton, 0, Qt::AlignRight); favoriteNodesButton->setIcon(QmitkStyleManager::ThemeIcon(QStringLiteral(":/Qmitk/favorite_remove.svg"))); favoriteNodesButton->setIconSize(QSize(24, 24)); favoriteNodesButton->setToolTip("Remove selected nodes as favorite"); m_FavoriteNodeSelectionPredicate = mitk::NodePredicateProperty::New("org.mitk.selection.favorite", mitk::BoolProperty::New(true)); m_NodePredicate = m_FavoriteNodeSelectionPredicate; connect(favoriteNodesButton, &QPushButton::clicked, this, &QmitkDataStorageFavoriteNodesInspector::OnFavoriteNodesButtonClicked); } void QmitkDataStorageFavoriteNodesInspector::SetNodePredicate(const mitk::NodePredicateBase* nodePredicate) { mitk::NodePredicateAnd::Pointer combinedPredicate = mitk::NodePredicateAnd::New(); combinedPredicate->AddPredicate(m_FavoriteNodeSelectionPredicate); combinedPredicate->AddPredicate(nodePredicate); QmitkDataStorageListInspector::SetNodePredicate(combinedPredicate); } void QmitkDataStorageFavoriteNodesInspector::OnFavoriteNodesButtonClicked() { auto selectedNodes = GetSelectedNodes(); - for (auto node : qAsConst(selectedNodes)) + for (auto node : std::as_const(selectedNodes)) { node->SetBoolProperty("org.mitk.selection.favorite", false); } } diff --git a/Modules/QtWidgets/src/QmitkIOUtil.cpp b/Modules/QtWidgets/src/QmitkIOUtil.cpp index 9ab8678e53..e8f59fc640 100644 --- a/Modules/QtWidgets/src/QmitkIOUtil.cpp +++ b/Modules/QtWidgets/src/QmitkIOUtil.cpp @@ -1,587 +1,587 @@ /*============================================================================ 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 "QmitkIOUtil.h" #include "mitkCoreServices.h" #include "mitkCustomMimeType.h" #include "mitkFileReaderRegistry.h" #include "mitkFileWriterRegistry.h" #include "mitkIMimeTypeProvider.h" #include "mitkMimeType.h" #include #include #include "QmitkFileReaderOptionsDialog.h" #include "QmitkFileWriterOptionsDialog.h" // QT #include #include #include #include #include #include // ITK #include #include struct QmitkIOUtil::Impl { struct ReaderOptionsDialogFunctor : public ReaderOptionsFunctorBase { bool operator()(LoadInfo &loadInfo) const override { QmitkFileReaderOptionsDialog dialog(loadInfo); if (dialog.exec() == QDialog::Accepted) { return !dialog.ReuseOptions(); } else { loadInfo.m_Cancel = true; return true; } } }; struct WriterOptionsDialogFunctor : public WriterOptionsFunctorBase { bool operator()(SaveInfo &saveInfo) const override { QmitkFileWriterOptionsDialog dialog(saveInfo); if (dialog.exec() == QDialog::Accepted) { return !dialog.ReuseOptions(); } else { saveInfo.m_Cancel = true; return true; } } }; //! Filename characters that are not valid - depending on the platform (Windows, Posix) static QString s_InvalidFilenameCharacters; //! Return 'true' when: //! - the specified filename contains characters not accepted by the file system (see s_InvalidFilenameCharacters) //! - filename starts or ends in space characters //! //! This test is not exhaustive but just excluding the most common problems. static bool IsIllegalFilename(const QString &fullFilename) { QFileInfo fi(fullFilename); auto filename = fi.fileName(); - for (const auto &ch : qAsConst(s_InvalidFilenameCharacters)) + for (const auto &ch : std::as_const(s_InvalidFilenameCharacters)) { if (filename.contains(ch)) { return true; } } if (filename.startsWith(' ') || filename.endsWith(' ')) { return true; } return false; } }; // Impl #if defined(_WIN32) || defined(_WIN64) QString QmitkIOUtil::Impl::s_InvalidFilenameCharacters = "<>:\"/\\|?*"; #else QString QmitkIOUtil::Impl::s_InvalidFilenameCharacters = "/"; #endif struct MimeTypeComparison { MimeTypeComparison(const std::string &mimeTypeName) : m_Name(mimeTypeName) {} bool operator()(const mitk::MimeType &mimeType) const { return mimeType.GetName() == m_Name; } const std::string m_Name; }; QString QmitkIOUtil::GetFileOpenFilterString() { QString filters; mitk::CoreServicePointer mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider()); std::vector categories = mimeTypeProvider->GetCategories(); for (std::vector::iterator cat = categories.begin(); cat != categories.end(); ++cat) { QSet filterExtensions; std::vector mimeTypes = mimeTypeProvider->GetMimeTypesForCategory(*cat); for (std::vector::iterator mt = mimeTypes.begin(); mt != mimeTypes.end(); ++mt) { std::vector extensions = mt->GetExtensions(); for (std::vector::iterator ext = extensions.begin(); ext != extensions.end(); ++ext) { filterExtensions << QString::fromStdString(*ext); } } QString filter = QString::fromStdString(*cat) + " ("; foreach (const QString &extension, filterExtensions) { filter += "*." + extension + " "; } filter = filter.replace(filter.size() - 1, 1, ')'); filters += ";;" + filter; } filters.prepend("All (*)"); return filters; } QList QmitkIOUtil::Load(const QStringList &paths, QWidget *parent) { std::vector loadInfos; foreach (const QString &file, paths) { loadInfos.push_back(LoadInfo(file.toLocal8Bit().constData())); } Impl::ReaderOptionsDialogFunctor optionsCallback; std::string errMsg = Load(loadInfos, nullptr, nullptr, &optionsCallback); if (!errMsg.empty()) { QMessageBox::warning(parent, "Error reading files", QString::fromStdString(errMsg)); mitkThrow() << errMsg; } QList qResult; for (std::vector::const_iterator iter = loadInfos.begin(), iterEnd = loadInfos.end(); iter != iterEnd; ++iter) { for (const auto &elem : iter->m_Output) { qResult << elem; } } return qResult; } mitk::DataStorage::SetOfObjects::Pointer QmitkIOUtil::Load(const QStringList &paths, mitk::DataStorage &storage, QWidget *parent) { std::vector loadInfos; foreach (const QString &file, paths) { loadInfos.push_back(LoadInfo(file.toLocal8Bit().constData())); } mitk::DataStorage::SetOfObjects::Pointer nodeResult = mitk::DataStorage::SetOfObjects::New(); Impl::ReaderOptionsDialogFunctor optionsCallback; std::string errMsg = Load(loadInfos, nodeResult, &storage, &optionsCallback); if (!errMsg.empty()) { QMessageBox::warning(parent, "Error reading files", QString::fromStdString(errMsg)); } return nodeResult; } QList QmitkIOUtil::Load(const QString &path, QWidget *parent) { QStringList paths; paths << path; return Load(paths, parent); } mitk::DataStorage::SetOfObjects::Pointer QmitkIOUtil::Load(const QString &path, mitk::DataStorage &storage, QWidget *parent) { QStringList paths; paths << path; return Load(paths, storage, parent); } QString QmitkIOUtil::Save(const mitk::BaseData *data, const QString &defaultBaseName, const QString &defaultPath, QWidget *parent, bool setPathProperty) { std::vector dataVector; dataVector.push_back(data); QStringList defaultBaseNames; defaultBaseNames.push_back(defaultBaseName); return Save(dataVector, defaultBaseNames, defaultPath, parent, setPathProperty).back(); } QStringList QmitkIOUtil::Save(const std::vector &data, const QStringList &defaultBaseNames, const QString &defaultPath, QWidget *parent, bool setPathProperty) { QStringList fileNames; QString currentPath = defaultPath; std::vector saveInfos; int counter = 0; for (std::vector::const_iterator dataIter = data.begin(), dataIterEnd = data.end(); dataIter != dataIterEnd; ++dataIter, ++counter) { SaveInfo saveInfo(*dataIter, mitk::MimeType(), std::string()); SaveFilter filters(saveInfo); // If there is only the "__all__" filter string, it means there is no writer for this base data if (filters.Size() < 2) { QMessageBox::warning( parent, "Saving not possible", QString("No writer available for type \"%1\"").arg(QString::fromStdString((*dataIter)->GetNameOfClass()))); continue; } // Construct a default path and file name QString filterString = filters.ToString(); QString selectedFilter = filters.GetDefaultFilter(); QString fileName = currentPath; QString dialogTitle = "Save " + QString::fromStdString((*dataIter)->GetNameOfClass()); if (counter < defaultBaseNames.size()) { dialogTitle += " \"" + defaultBaseNames[counter] + "\""; fileName += QDir::separator() + defaultBaseNames[counter]; // We do not append an extension to the file name by default. The extension // is chosen by the user by either selecting a filter or writing the // extension in the file name himself (in the file save dialog). /* QString defaultExt = filters.GetDefaultExtension(); if (!defaultExt.isEmpty()) { fileName += "." + defaultExt; } */ } // Ask the user for a file name QString nextName = QFileDialog::getSaveFileName(parent, dialogTitle, fileName, filterString, &selectedFilter); if (Impl::IsIllegalFilename(nextName)) { QMessageBox::warning( parent, "Saving not possible", QString("File \"%2\" contains invalid characters.\n\nPlease avoid any of \"%1\"") .arg(Impl::s_InvalidFilenameCharacters.split("", Qt::SkipEmptyParts).join(" ")) .arg(nextName)); continue; } if (nextName.isEmpty()) { // We stop asking for further file names, but we still save the // data where the user already confirmed the save dialog. break; } fileName = nextName; std::string stdFileName = fileName.toLocal8Bit().constData(); QFileInfo fileInfo(fileName); currentPath = fileInfo.absolutePath(); QString suffix = fileInfo.completeSuffix(); mitk::MimeType filterMimeType = filters.GetMimeTypeForFilter(selectedFilter); mitk::MimeType selectedMimeType; if (fileInfo.exists() && !fileInfo.isFile()) { QMessageBox::warning(parent, "Saving not possible", QString("The path \"%1\" is not a file").arg(fileName)); continue; } // Theoretically, the user could have entered an extension that does not match the selected filter // The extension then has prioritry over the filter // Check if one of the available mime-types match the filename std::vector filterMimeTypes = filters.GetMimeTypes(); for (std::vector::const_iterator mimeTypeIter = filterMimeTypes.begin(), mimeTypeIterEnd = filterMimeTypes.end(); mimeTypeIter != mimeTypeIterEnd; ++mimeTypeIter) { if (mimeTypeIter->MatchesExtension(stdFileName)) { selectedMimeType = *mimeTypeIter; break; } } if (!selectedMimeType.IsValid()) { // The file name either does not contain an extension or the // extension is unknown. // If the file already exists, we stop here because we are unable // to (over)write the file without adding a custom suffix. If the file // does not exist, we add the default extension from the currently // selected filter. If the "All" filter was selected, we only add the // default extensions if the file name itself does not already contain // an extension. if (!fileInfo.exists()) { if (filterMimeType == SaveFilter::ALL_MIMETYPE()) { if (suffix.isEmpty()) { // Use the highest ranked mime-type from the list selectedMimeType = filters.GetDefaultMimeType(); } } else { selectedMimeType = filterMimeType; } if (selectedMimeType.IsValid()) { suffix = QString::fromStdString(selectedMimeType.GetExtensions().front()); fileName += "." + suffix; stdFileName = fileName.toLocal8Bit().constData(); // We changed the file name (added a suffix) so ask in case // the file aready exists. fileInfo = QFileInfo(fileName); if (fileInfo.exists()) { if (!fileInfo.isFile()) { QMessageBox::warning( parent, "Saving not possible", QString("The path \"%1\" is not a file").arg(fileName)); continue; } if (QMessageBox::question( parent, "Replace File", QString("A file named \"%1\" already exists. Do you want to replace it?").arg(fileName)) == QMessageBox::No) { continue; } } } } } if (!selectedMimeType.IsValid()) { // The extension/filename is not valid (no mime-type found), bail out QMessageBox::warning( parent, "Saving not possible", QString("No mime-type available which can handle \"%1\".").arg(fileName)); continue; } if (!QFileInfo(fileInfo.absolutePath()).isWritable()) { QMessageBox::warning(parent, "Saving not possible", QString("The path \"%1\" is not writable").arg(fileName)); continue; } fileNames.push_back(fileName); saveInfo.m_Path = stdFileName; saveInfo.m_MimeType = selectedMimeType; // pre-select the best writer for the chosen mime-type saveInfo.m_WriterSelector.Select(selectedMimeType.GetName()); saveInfos.push_back(saveInfo); } if (!saveInfos.empty()) { Impl::WriterOptionsDialogFunctor optionsCallback; std::string errMsg = Save(saveInfos, &optionsCallback, setPathProperty); if (!errMsg.empty()) { QMessageBox::warning(parent, "Error writing files", QString::fromStdString(errMsg)); mitkThrow() << errMsg; } } return fileNames; } void QmitkIOUtil::SaveBaseDataWithDialog(mitk::BaseData *data, std::string fileName, QWidget * /*parent*/) { Save(data, fileName); } void QmitkIOUtil::SaveSurfaceWithDialog(mitk::Surface::Pointer surface, std::string fileName, QWidget * /*parent*/) { Save(surface, fileName); } void QmitkIOUtil::SaveImageWithDialog(mitk::Image::Pointer image, std::string fileName, QWidget * /*parent*/) { Save(image, fileName); } void QmitkIOUtil::SavePointSetWithDialog(mitk::PointSet::Pointer pointset, std::string fileName, QWidget * /*parent*/) { Save(pointset, fileName); } struct QmitkIOUtil::SaveFilter::Impl { Impl(const mitk::IOUtil::SaveInfo &saveInfo) : m_SaveInfo(saveInfo) { // Add an artifical filter for "All" m_MimeTypes.push_back(ALL_MIMETYPE()); m_FilterStrings.push_back("All (*.*)"); // Get all writers and their mime types for the given base data type // (this is sorted already) std::vector mimeTypes = saveInfo.m_WriterSelector.GetMimeTypes(); for (std::vector::const_reverse_iterator iter = mimeTypes.rbegin(), iterEnd = mimeTypes.rend(); iter != iterEnd; ++iter) { QList filterExtensions; mitk::MimeType mimeType = *iter; std::vector extensions = mimeType.GetExtensions(); for (auto &extension : extensions) { filterExtensions << QString::fromStdString(extension); } if (m_DefaultExtension.isEmpty()) { m_DefaultExtension = QString::fromStdString(extensions.front()); } QString filter = QString::fromStdString(mimeType.GetComment()) + " ("; foreach (const QString &extension, filterExtensions) { filter += "*." + extension + " "; } filter = filter.replace(filter.size() - 1, 1, ')'); m_MimeTypes.push_back(mimeType); m_FilterStrings.push_back(filter); } } const mitk::IOUtil::SaveInfo m_SaveInfo; std::vector m_MimeTypes; QStringList m_FilterStrings; QString m_DefaultExtension; }; mitk::MimeType QmitkIOUtil::SaveFilter::ALL_MIMETYPE() { static mitk::CustomMimeType allMimeType(std::string("__all__")); return mitk::MimeType(allMimeType, -1, -1); } QmitkIOUtil::SaveFilter::SaveFilter(const QmitkIOUtil::SaveFilter &other) : d(new Impl(*other.d)) { } QmitkIOUtil::SaveFilter::SaveFilter(const SaveInfo &saveInfo) : d(new Impl(saveInfo)) { } QmitkIOUtil::SaveFilter &QmitkIOUtil::SaveFilter::operator=(const QmitkIOUtil::SaveFilter &other) { d.reset(new Impl(*other.d)); return *this; } std::vector QmitkIOUtil::SaveFilter::GetMimeTypes() const { return d->m_MimeTypes; } QString QmitkIOUtil::SaveFilter::GetFilterForMimeType(const std::string &mimeType) const { std::vector::const_iterator iter = std::find_if(d->m_MimeTypes.begin(), d->m_MimeTypes.end(), MimeTypeComparison(mimeType)); if (iter == d->m_MimeTypes.end()) { return QString(); } int index = static_cast(iter - d->m_MimeTypes.begin()); if (index < 0 || index >= d->m_FilterStrings.size()) { return QString(); } return d->m_FilterStrings[index]; } mitk::MimeType QmitkIOUtil::SaveFilter::GetMimeTypeForFilter(const QString &filter) const { int index = d->m_FilterStrings.indexOf(filter); if (index < 0) { return mitk::MimeType(); } return d->m_MimeTypes[index]; } QString QmitkIOUtil::SaveFilter::GetDefaultFilter() const { if (d->m_FilterStrings.size() > 1) { return d->m_FilterStrings.at(1); } else if (d->m_FilterStrings.size() > 0) { return d->m_FilterStrings.front(); } return QString(); } QString QmitkIOUtil::SaveFilter::GetDefaultExtension() const { return d->m_DefaultExtension; } mitk::MimeType QmitkIOUtil::SaveFilter::GetDefaultMimeType() const { if (d->m_MimeTypes.size() > 1) { return d->m_MimeTypes.at(1); } else if (d->m_MimeTypes.size() > 0) { return d->m_MimeTypes.front(); } return mitk::MimeType(); } QString QmitkIOUtil::SaveFilter::ToString() const { return d->m_FilterStrings.join(";;"); } int QmitkIOUtil::SaveFilter::Size() const { return d->m_FilterStrings.size(); } bool QmitkIOUtil::SaveFilter::IsEmpty() const { return d->m_FilterStrings.isEmpty(); } bool QmitkIOUtil::SaveFilter::ContainsMimeType(const std::string &mimeType) { return std::find_if(d->m_MimeTypes.begin(), d->m_MimeTypes.end(), MimeTypeComparison(mimeType)) != d->m_MimeTypes.end(); } diff --git a/Modules/QtWidgets/src/QmitkModelViewSelectionConnector.cpp b/Modules/QtWidgets/src/QmitkModelViewSelectionConnector.cpp index a52e840471..a30399c0e5 100644 --- a/Modules/QtWidgets/src/QmitkModelViewSelectionConnector.cpp +++ b/Modules/QtWidgets/src/QmitkModelViewSelectionConnector.cpp @@ -1,185 +1,185 @@ /*============================================================================ 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. ============================================================================*/ // mitk gui qt common plugin #include "QmitkModelViewSelectionConnector.h" // qt widgets module #include "QmitkCustomVariants.h" #include "QmitkEnums.h" QmitkModelViewSelectionConnector::QmitkModelViewSelectionConnector() : m_Model(nullptr) , m_View(nullptr) , m_SelectOnlyVisibleNodes(false) { // nothing here } void QmitkModelViewSelectionConnector::SetView(QAbstractItemView* view) { if (nullptr != m_View) { disconnect(m_View->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(ChangeModelSelection(const QItemSelection&, const QItemSelection&))); } // reset model-view pair and check for valid function argument m_View = nullptr; if (nullptr == view) { mitkThrow() << "Invalid item view. To use the model-view selection connector please specify a valid 'QAbstractItemView'."; } auto storageModel = dynamic_cast(view->model()); if (storageModel == nullptr) { mitkThrow() << "Invalid data model. To use the model-view selection connector please set a valid 'QmitkAbstractDataStorageModel' for the given item view."; } // a valid item view and a valid data model was found m_View = view; m_Model = storageModel; connect(m_View->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), SLOT(ChangeModelSelection(const QItemSelection&, const QItemSelection&))); } void QmitkModelViewSelectionConnector::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) { m_SelectOnlyVisibleNodes = selectOnlyVisibleNodes; } void QmitkModelViewSelectionConnector::SetCurrentSelection(QList selectedNodes) { if (nullptr == m_Model || nullptr == m_View) { return; } // filter input nodes and return the modified input node list QList filteredNodes = FilterNodeList(selectedNodes); bool equal = EqualNodeSelections(this->GetInternalSelectedNodes(), filteredNodes); if (equal) { return; } if (!m_SelectOnlyVisibleNodes) { // store the unmodified selection m_NonVisibleSelection = selectedNodes; // remove the nodes in the original selection that are already contained in the filtered input node list // this will keep the selection of the original nodes that are not presented by the current view unmodified, but allows to change the selection of the filtered nodes // later, the nodes of the 'm_NonVisibleSelection' member have to be added again to the list of selected (filtered) nodes, if a selection is sent from the current view (see 'ModelSelectionChanged') auto lambda = [&filteredNodes](mitk::DataNode::Pointer original) { return filteredNodes.contains(original); }; m_NonVisibleSelection.erase(std::remove_if(m_NonVisibleSelection.begin(), m_NonVisibleSelection.end(), lambda), m_NonVisibleSelection.end()); } // create new selection by retrieving the corresponding indices of the (filtered) nodes QItemSelection newCurrentSelection; - for (const auto& node : qAsConst(filteredNodes)) + for (const auto& node : std::as_const(filteredNodes)) { QModelIndexList matched = m_Model->match(m_Model->index(0, 0), QmitkDataNodeRole, QVariant::fromValue(node), 1, Qt::MatchRecursive); if (!matched.empty()) { newCurrentSelection.select(matched.front(), matched.front()); } } m_View->selectionModel()->select(newCurrentSelection, QItemSelectionModel::ClearAndSelect); } void QmitkModelViewSelectionConnector::ChangeModelSelection(const QItemSelection& /*selected*/, const QItemSelection& /*deselected*/) { emit CurrentSelectionChanged(GetSelectedNodes()); } bool QmitkModelViewSelectionConnector::GetSelectOnlyVisibleNodes() const { return m_SelectOnlyVisibleNodes; } QList QmitkModelViewSelectionConnector::GetSelectedNodes() const { auto nodes = GetInternalSelectedNodes(); if (!m_SelectOnlyVisibleNodes) { // add the non-visible nodes from the original selection nodes.append(m_NonVisibleSelection); } return nodes; } QList QmitkModelViewSelectionConnector::GetInternalSelectedNodes() const { if (nullptr == m_Model || nullptr == m_View) { return QList(); } QList nodes; QModelIndexList selectedIndexes = m_View->selectionModel()->selectedIndexes(); - for (const auto& index : qAsConst(selectedIndexes)) + for (const auto& index : std::as_const(selectedIndexes)) { QVariant qvariantDataNode = m_Model->data(index, QmitkDataNodeRole); if (qvariantDataNode.canConvert()) { nodes.push_back(qvariantDataNode.value()); } } return nodes; } QList QmitkModelViewSelectionConnector::FilterNodeList(const QList& nodes) const { if (nodes.isEmpty()) { return QList(); } if (nullptr == m_Model) { return nodes; } auto nodePredicate = m_Model->GetNodePredicate(); if (nullptr == nodePredicate) { // no filter set return nodes; } QList result; for (const auto& node : nodes) { if (true == nodePredicate->CheckNode(node)) { result.push_back(node); } } return result; } bool MITKQTWIDGETS_EXPORT EqualNodeSelections(const QList& selection1, const QList& selection2) { if (selection1.size() == selection2.size()) { // lambda to compare node pointer inside both lists auto lambda = [](mitk::DataNode::Pointer lhs, mitk::DataNode::Pointer rhs) { return lhs == rhs; }; return std::is_permutation(selection1.begin(), selection1.end(), selection2.begin(), selection2.end(), lambda); } return false; } diff --git a/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.cpp b/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.cpp index 1f80c59170..d7c6dc070f 100644 --- a/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.cpp +++ b/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.cpp @@ -1,138 +1,138 @@ /*============================================================================ 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 "QmitkMultiWidgetLayoutSelectionWidget.h" #include #include #include #include #include QmitkMultiWidgetLayoutSelectionWidget::QmitkMultiWidgetLayoutSelectionWidget(QWidget* parent/* = 0*/) : QWidget(parent) { Init(); } void QmitkMultiWidgetLayoutSelectionWidget::Init() { ui.setupUi(this); auto stylesheet = "QTableWidget::item{background-color: white;}\nQTableWidget::item:selected{background-color: #1C97EA;}"; ui.tableWidget->setStyleSheet(stylesheet); connect(ui.tableWidget, &QTableWidget::itemSelectionChanged, this, &QmitkMultiWidgetLayoutSelectionWidget::OnTableItemSelectionChanged); connect(ui.setLayoutPushButton, &QPushButton::clicked, this, &QmitkMultiWidgetLayoutSelectionWidget::OnSetLayoutButtonClicked); connect(ui.loadLayoutPushButton, &QPushButton::clicked, this, &QmitkMultiWidgetLayoutSelectionWidget::OnLoadLayoutButtonClicked); connect(ui.saveLayoutPushButton, &QPushButton::clicked, this, &QmitkMultiWidgetLayoutSelectionWidget::OnSaveLayoutButtonClicked); connect(ui.selectDefaultLayoutComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &QmitkMultiWidgetLayoutSelectionWidget::OnLayoutPresetSelected); ui.selectDefaultLayoutComboBox->addItem("Select a layout preset"); auto presetResources = us::GetModuleContext()->GetModule()->FindResources("/", "mxnLayout_*.json", false); for (const auto& resource : presetResources) { us::ModuleResourceStream jsonStream(resource); auto data = nlohmann::json::parse(jsonStream); auto resourceName = data["name"].get(); ui.selectDefaultLayoutComboBox->addItem(QString::fromStdString(resourceName)); m_PresetMap[ui.selectDefaultLayoutComboBox->count() - 1] = data; } } void QmitkMultiWidgetLayoutSelectionWidget::OnTableItemSelectionChanged() { QItemSelectionModel* selectionModel = ui.tableWidget->selectionModel(); int row = 0; int column = 0; QModelIndexList indices = selectionModel->selectedIndexes(); if (indices.size() > 0) { row = indices[0].row(); column = indices[0].column(); QModelIndex topLeft = ui.tableWidget->model()->index(0, 0, QModelIndex()); QModelIndex bottomRight = ui.tableWidget->model()->index(row, column, QModelIndex()); QItemSelection cellSelection; cellSelection.select(topLeft, bottomRight); selectionModel->select(cellSelection, QItemSelectionModel::Select); } } void QmitkMultiWidgetLayoutSelectionWidget::OnSetLayoutButtonClicked() { int row = 0; int column = 0; QModelIndexList indices = ui.tableWidget->selectionModel()->selectedIndexes(); if (indices.size() > 0) { // find largest row and column - for (const auto& modelIndex : qAsConst(indices)) + for (const auto& modelIndex : std::as_const(indices)) { if (modelIndex.row() > row) { row = modelIndex.row(); } if (modelIndex.column() > column) { column = modelIndex.column(); } } close(); emit LayoutSet(row+1, column+1); } ui.selectDefaultLayoutComboBox->setCurrentIndex(0); } void QmitkMultiWidgetLayoutSelectionWidget::OnSaveLayoutButtonClicked() { QString filename = QFileDialog::getSaveFileName(nullptr, "Select where to save the current layout", "", "MITK Window Layout (*.json)"); if (filename.isEmpty()) return; QString fileExt(".json"); if (!filename.endsWith(fileExt)) filename += fileExt; auto outStream = std::ofstream(filename.toStdString()); emit SaveLayout(&outStream); } void QmitkMultiWidgetLayoutSelectionWidget::OnLoadLayoutButtonClicked() { QString filename = QFileDialog::getOpenFileName(nullptr, "Load a layout file", "", "MITK Window Layouts (*.json)"); if (filename.isEmpty()) return; ui.selectDefaultLayoutComboBox->setCurrentIndex(0); std::ifstream f(filename.toStdString()); auto jsonData = nlohmann::json::parse(f); emit LoadLayout(&jsonData); } void QmitkMultiWidgetLayoutSelectionWidget::OnLayoutPresetSelected(int index) { if (index == 0) { // First entry is only for description return; } auto jsonData = m_PresetMap[index]; close(); emit LoadLayout(&jsonData); } diff --git a/Modules/QtWidgets/src/QmitkNodeSelectionDialog.cpp b/Modules/QtWidgets/src/QmitkNodeSelectionDialog.cpp index 514b9d35c1..5fa811fefc 100644 --- a/Modules/QtWidgets/src/QmitkNodeSelectionDialog.cpp +++ b/Modules/QtWidgets/src/QmitkNodeSelectionDialog.cpp @@ -1,296 +1,296 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkNodeSelectionDialog.h" #include #include #include #include #include #include #include QmitkNodeSelectionDialog::QmitkNodeSelectionDialog(QWidget* parent, QString title, QString hint) : QDialog(parent) , m_NodePredicate(nullptr) , m_SelectOnlyVisibleNodes(false) , m_SelectedNodes(NodeList()) , m_SelectionMode(QAbstractItemView::SingleSelection) { m_Controls.setupUi(this); m_CheckFunction = [](const NodeList &) { return ""; }; auto providers = mitk::DataStorageInspectorGenerator::GetProviders(); auto visibleProviders = mitk::GetVisibleDataStorageInspectors(); auto preferredID = mitk::GetPreferredDataStorageInspector(); if (visibleProviders.empty()) { MITK_DEBUG << "No presets for visible node selection inspectors available. Use fallback (show all available inspectors)"; unsigned int order = 0; for (const auto &proIter : providers) { visibleProviders.insert(std::make_pair(order, proIter.first)); ++order; } } int preferredIndex = 0; bool preferredFound = false; for (const auto &proIter : visibleProviders) { auto finding = providers.find(proIter.second); if (finding != providers.end()) { if (finding->second->GetInspectorID() != QmitkDataStorageFavoriteNodesInspector::INSPECTOR_ID() && finding->second->GetInspectorID() != QmitkDataStorageSelectionHistoryInspector::INSPECTOR_ID()) { auto provider = finding->second; this->AddPanel(provider, preferredID, preferredFound, preferredIndex); } } else { MITK_DEBUG << "No provider registered for inspector that is defined as visible in the preferences. Illegal inspector ID: " << proIter.second; } } if (mitk::GetShowFavoritesInspector()) { auto favoritesPorvider = mitk::DataStorageInspectorGenerator::GetProvider(QmitkDataStorageFavoriteNodesInspector::INSPECTOR_ID()); if (favoritesPorvider != nullptr) { this->AddPanel(favoritesPorvider, preferredID, preferredFound, preferredIndex); } } if (mitk::GetShowHistoryInspector()) { auto historyPorvider = mitk::DataStorageInspectorGenerator::GetProvider(QmitkDataStorageSelectionHistoryInspector::INSPECTOR_ID()); if (historyPorvider != nullptr) { this->AddPanel(historyPorvider, preferredID, preferredFound, preferredIndex); } } m_Controls.tabWidget->setCurrentIndex(preferredIndex); this->setWindowTitle(title); this->setToolTip(hint); m_Controls.hint->setText(hint); m_Controls.hint->setVisible(!hint.isEmpty()); if(hint.isEmpty()) { m_Controls.layoutHint->setContentsMargins(0, 0, 0, 0); } else { m_Controls.layoutHint->setContentsMargins(6, 6, 6, 6); } this->SetErrorText(""); m_Controls.btnAddToFav->setIcon(QmitkStyleManager::ThemeIcon(QStringLiteral(":/Qmitk/favorite_add.svg"))); connect(m_Controls.btnAddToFav, &QPushButton::clicked, this, &QmitkNodeSelectionDialog::OnFavoriteNodesButtonClicked); connect(m_Controls.buttonBox, &QDialogButtonBox::accepted, this, &QmitkNodeSelectionDialog::OnOK); connect(m_Controls.buttonBox, &QDialogButtonBox::rejected, this, &QmitkNodeSelectionDialog::OnCancel); } void QmitkNodeSelectionDialog::SetDataStorage(mitk::DataStorage* dataStorage) { if (m_DataStorage != dataStorage) { m_DataStorage = dataStorage; auto lockedDataStorage = m_DataStorage.Lock(); if (lockedDataStorage.IsNotNull()) { for (auto panel : m_Panels) { panel->SetDataStorage(lockedDataStorage); } } } } void QmitkNodeSelectionDialog::SetNodePredicate(const mitk::NodePredicateBase* nodePredicate) { if (m_NodePredicate != nodePredicate) { m_NodePredicate = nodePredicate; for (auto panel : m_Panels) { panel->SetNodePredicate(m_NodePredicate); } } } const mitk::NodePredicateBase* QmitkNodeSelectionDialog::GetNodePredicate() const { return m_NodePredicate; } QmitkNodeSelectionDialog::NodeList QmitkNodeSelectionDialog::GetSelectedNodes() const { return m_SelectedNodes; } void QmitkNodeSelectionDialog::SetSelectionCheckFunction(const SelectionCheckFunctionType &checkFunction) { m_CheckFunction = checkFunction; auto checkResponse = m_CheckFunction(m_SelectedNodes); SetErrorText(checkResponse); m_Controls.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(checkResponse.empty()); } void QmitkNodeSelectionDialog::SetErrorText(const std::string& checkResponse) { m_Controls.error->setText(QString::fromStdString(checkResponse)); m_Controls.error->setVisible(!checkResponse.empty()); if (checkResponse.empty()) { m_Controls.layoutError->setContentsMargins(0, 0, 0, 0); } else { m_Controls.layoutError->setContentsMargins(6, 6, 6, 6); } } bool QmitkNodeSelectionDialog::GetSelectOnlyVisibleNodes() const { return m_SelectOnlyVisibleNodes; } void QmitkNodeSelectionDialog::SetSelectionMode(SelectionMode mode) { m_SelectionMode = mode; for (auto panel : m_Panels) { panel->SetSelectionMode(mode); } } QmitkNodeSelectionDialog::SelectionMode QmitkNodeSelectionDialog::GetSelectionMode() const { return m_SelectionMode; } void QmitkNodeSelectionDialog::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) { if (m_SelectOnlyVisibleNodes != selectOnlyVisibleNodes) { m_SelectOnlyVisibleNodes = selectOnlyVisibleNodes; for (auto panel : m_Panels) { panel->SetSelectOnlyVisibleNodes(m_SelectOnlyVisibleNodes); } } } void QmitkNodeSelectionDialog::SetCurrentSelection(NodeList selectedNodes) { m_SelectedNodes = selectedNodes; auto checkResponse = m_CheckFunction(m_SelectedNodes); SetErrorText(checkResponse); m_Controls.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(checkResponse.empty()); for (auto panel : m_Panels) { panel->SetCurrentSelection(selectedNodes); } } void QmitkNodeSelectionDialog::OnSelectionChanged(NodeList selectedNodes) { SetCurrentSelection(selectedNodes); emit CurrentSelectionChanged(selectedNodes); } void QmitkNodeSelectionDialog::OnFavoriteNodesButtonClicked() { - for (auto node : qAsConst(m_SelectedNodes)) + for (auto node : std::as_const(m_SelectedNodes)) { node->SetBoolProperty("org.mitk.selection.favorite", true); } } void QmitkNodeSelectionDialog::OnOK() { - for (const auto &node : qAsConst(m_SelectedNodes)) + for (const auto &node : std::as_const(m_SelectedNodes)) { QmitkDataStorageSelectionHistoryInspector::AddNodeToHistory(node); } this->accept(); } void QmitkNodeSelectionDialog::OnCancel() { this->reject(); } void QmitkNodeSelectionDialog::AddPanel(const mitk::IDataStorageInspectorProvider * provider, const mitk::IDataStorageInspectorProvider::InspectorIDType& preferredID, bool &preferredFound, int &preferredIndex) { auto inspector = provider->CreateInspector(); QString name = QString::fromStdString(provider->GetInspectorDisplayName()); QString desc = QString::fromStdString(provider->GetInspectorDescription()); inspector->setParent(this); inspector->SetSelectionMode(m_SelectionMode); auto tabPanel = new QWidget(); tabPanel->setObjectName(QString("tab_") + name); tabPanel->setToolTip(desc); auto verticalLayout = new QVBoxLayout(tabPanel); verticalLayout->setSpacing(0); verticalLayout->setContentsMargins(0, 0, 0, 0); verticalLayout->addWidget(inspector); auto panelPos = m_Controls.tabWidget->insertTab(m_Controls.tabWidget->count(), tabPanel, name); auto icon = provider->GetInspectorIcon(); if (!icon.isNull()) { m_Controls.tabWidget->setTabIcon(panelPos, icon); } m_Panels.push_back(inspector); connect(inspector, &QmitkAbstractDataStorageInspector::CurrentSelectionChanged, this, &QmitkNodeSelectionDialog::OnSelectionChanged); connect(inspector->GetView(), &QAbstractItemView::doubleClicked, this, &QmitkNodeSelectionDialog::OnDoubleClicked); preferredFound = preferredFound || provider->GetInspectorID() == preferredID; if (!preferredFound) { ++preferredIndex; } } void QmitkNodeSelectionDialog::OnDoubleClicked(const QModelIndex& /*index*/) { const auto isOK = m_Controls.buttonBox->button(QDialogButtonBox::Ok)->isEnabled(); if (!m_SelectedNodes.empty() && isOK) { this->OnOK(); } } diff --git a/Modules/QtWidgets/src/QmitkPropertyItemModel.cpp b/Modules/QtWidgets/src/QmitkPropertyItemModel.cpp index 10514fbe2a..22a464abba 100644 --- a/Modules/QtWidgets/src/QmitkPropertyItemModel.cpp +++ b/Modules/QtWidgets/src/QmitkPropertyItemModel.cpp @@ -1,478 +1,478 @@ /*============================================================================ 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 "QmitkPropertyItemModel.h" #include "QmitkPropertyItem.h" #include #include #include #include #include #include #include #include namespace { QColor MitkToQt(const mitk::Color& color) { return QColor(color.GetRed() * 255, color.GetGreen() * 255, color.GetBlue() * 255); } mitk::BaseProperty* GetBaseProperty(const QVariant& data) { return data.isValid() ? reinterpret_cast(data.value()) : nullptr; } mitk::Color QtToMitk(const QColor& color) { mitk::Color mitkColor; mitkColor.SetRed(color.red() / 255.0f); mitkColor.SetGreen(color.green() / 255.0f); mitkColor.SetBlue(color.blue() / 255.0f); return mitkColor; } } class PropertyEqualTo { public: PropertyEqualTo(const mitk::BaseProperty *property) : m_Property(property) {} bool operator()(const mitk::PropertyList::PropertyMapElementType &pair) const { return pair.second.GetPointer() == m_Property; } private: const mitk::BaseProperty *m_Property; }; QmitkPropertyItemModel::QmitkPropertyItemModel(QObject *parent) : QAbstractItemModel(parent), m_PropertyAliases(mitk::CoreServices::GetPropertyAliases()), m_PropertyFilters(mitk::CoreServices::GetPropertyFilters()) { this->CreateRootItem(); } QmitkPropertyItemModel::~QmitkPropertyItemModel() { this->SetNewPropertyList(nullptr); } int QmitkPropertyItemModel::columnCount(const QModelIndex &parent) const { if (parent.isValid()) return static_cast(parent.internalPointer())->GetColumnCount(); else return m_RootItem->GetColumnCount(); } void QmitkPropertyItemModel::CreateRootItem() { QList rootData; rootData << "Property" << "Value"; m_RootItem.reset(new QmitkPropertyItem(rootData)); this->beginResetModel(); this->endResetModel(); } QVariant QmitkPropertyItemModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); mitk::BaseProperty *property = index.column() == 1 ? GetBaseProperty(static_cast(index.internalPointer())->GetData(1)) : nullptr; if (role == Qt::DisplayRole) { if (index.column() == 0) { return static_cast(index.internalPointer())->GetData(0); } else if (index.column() == 1 && property != nullptr) { if (auto colorProperty = dynamic_cast(property)) return MitkToQt(colorProperty->GetValue()); else if (dynamic_cast(property) == nullptr) return QString::fromStdString(property->GetValueAsString()); } } else if (index.column() == 1 && property != nullptr) { if (role == Qt::CheckStateRole) { if (auto boolProperty = dynamic_cast(property)) return boolProperty->GetValue() ? Qt::Checked : Qt::Unchecked; } else if (role == Qt::EditRole) { if (dynamic_cast(property) != nullptr) { return QString::fromStdString(property->GetValueAsString()); } else if (auto intProperty = dynamic_cast(property)) { return intProperty->GetValue(); } else if (auto floatProperty = dynamic_cast(property)) { return floatProperty->GetValue(); } else if (auto doubleProperty = dynamic_cast(property)) { return doubleProperty->GetValue(); } else if (auto enumProperty = dynamic_cast(property)) { QStringList values; for (mitk::EnumerationProperty::EnumConstIterator it = enumProperty->Begin(); it != enumProperty->End(); it++) values << QString::fromStdString(it->second); return values; } else if (auto colorProperty = dynamic_cast(property)) { return MitkToQt(colorProperty->GetValue()); } } else if (role == mitk::PropertyRole) { return QVariant::fromValue(property); } } return QVariant(); } QModelIndex QmitkPropertyItemModel::FindProperty(const mitk::BaseProperty *property) { if (property == nullptr) return QModelIndex(); auto propertyList = m_PropertyList.Lock(); if (propertyList.IsNull()) return QModelIndex(); auto propertyMap = propertyList->GetMap(); auto it = std::find_if(propertyMap->begin(), propertyMap->end(), PropertyEqualTo(property)); if (it == propertyMap->end()) return QModelIndex(); QString name = QString::fromStdString(it->first); if (!name.contains('.')) { QModelIndexList item = this->match(index(0, 0), Qt::DisplayRole, name, 1, Qt::MatchExactly); if (!item.empty()) return item[0]; } else { QStringList names = name.split('.'); QModelIndexList items = this->match(index(0, 0), Qt::DisplayRole, names.last(), -1, Qt::MatchRecursive | Qt::MatchExactly); - for (auto item : qAsConst(items)) + for (auto item : std::as_const(items)) { QModelIndex candidate = item; for (int i = names.length() - 1; i != 0; --i) { QModelIndex parent = item.parent(); if (parent.parent() == QModelIndex()) { if (parent.data() != names.first()) break; return candidate; } if (parent.data() != names[i - 1]) break; item = parent; } } } return QModelIndex(); } Qt::ItemFlags QmitkPropertyItemModel::flags(const QModelIndex &index) const { Qt::ItemFlags flags = QAbstractItemModel::flags(index); if (index.column() == 1) { if (index.data(Qt::EditRole).isValid()) flags |= Qt::ItemIsEditable; if (index.data(Qt::CheckStateRole).isValid()) flags |= Qt::ItemIsUserCheckable; } return flags; } mitk::PropertyList *QmitkPropertyItemModel::GetPropertyList() const { return m_PropertyList.Lock().GetPointer(); } QVariant QmitkPropertyItemModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) return m_RootItem->GetData(section); return QVariant(); } QModelIndex QmitkPropertyItemModel::index(int row, int column, const QModelIndex &parent) const { if (!this->hasIndex(row, column, parent)) return QModelIndex(); QmitkPropertyItem *parentItem = parent.isValid() ? static_cast(parent.internalPointer()) : m_RootItem.get(); QmitkPropertyItem *childItem = parentItem->GetChild(row); return childItem != nullptr ? this->createIndex(row, column, childItem) : QModelIndex(); } void QmitkPropertyItemModel::OnPropertyListModified() { this->SetNewPropertyList(m_PropertyList.Lock()); } void QmitkPropertyItemModel::OnPropertyListDeleted() { this->CreateRootItem(); } void QmitkPropertyItemModel::OnPropertyModified(const itk::Object *property, const itk::EventObject &) { QModelIndex index = this->FindProperty(static_cast(property)); if (index != QModelIndex()) emit dataChanged(index, index); } QModelIndex QmitkPropertyItemModel::parent(const QModelIndex &child) const { if (!child.isValid()) return QModelIndex(); QmitkPropertyItem *parentItem = static_cast(child.internalPointer())->GetParent(); if (parentItem == m_RootItem.get()) return QModelIndex(); return this->createIndex(parentItem->GetRow(), 0, parentItem); } int QmitkPropertyItemModel::rowCount(const QModelIndex &parent) const { if (parent.column() > 0) return 0; QmitkPropertyItem *parentItem = parent.isValid() ? static_cast(parent.internalPointer()) : m_RootItem.get(); return parentItem->GetChildCount(); } bool QmitkPropertyItemModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!index.isValid() || index.column() != 1 || (role != Qt::EditRole && role != Qt::CheckStateRole)) return false; mitk::BaseProperty *property = GetBaseProperty(static_cast(index.internalPointer())->GetData(1)); if (property == nullptr) return false; if (mitk::BoolProperty *boolProperty = dynamic_cast(property)) { boolProperty->SetValue(value.toInt() == Qt::Checked ? true : false); } else if (mitk::StringProperty *stringProperty = dynamic_cast(property)) { stringProperty->SetValue(value.toString().toStdString()); } else if (mitk::IntProperty *intProperty = dynamic_cast(property)) { intProperty->SetValue(value.toInt()); } else if (mitk::FloatProperty *floatProperty = dynamic_cast(property)) { floatProperty->SetValue(value.toFloat()); } else if (mitk::DoubleProperty *doubleProperty = dynamic_cast(property)) { doubleProperty->SetValue(value.toDouble()); } else if (mitk::EnumerationProperty *enumProperty = dynamic_cast(property)) { std::string selection = value.toString().toStdString(); if (selection != enumProperty->GetValueAsString() && enumProperty->IsValidEnumerationValue(selection)) enumProperty->SetValue(selection); } else if (mitk::ColorProperty *colorProperty = dynamic_cast(property)) { colorProperty->SetValue(QtToMitk(value.value())); } auto propertyList = m_PropertyList.Lock(); propertyList->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); return true; } void QmitkPropertyItemModel::SetNewPropertyList(mitk::PropertyList *newPropertyList) { typedef mitk::PropertyList::PropertyMap PropertyMap; this->beginResetModel(); auto propertyList = m_PropertyList.Lock(); if (propertyList.IsNotNull()) { propertyList->RemoveObserver(m_PropertyListDeletedTag); propertyList->RemoveObserver(m_PropertyListModifiedTag); const PropertyMap *propertyMap = propertyList->GetMap(); for (PropertyMap::const_iterator propertyIt = propertyMap->begin(); propertyIt != propertyMap->end(); ++propertyIt) { std::map::const_iterator tagIt = m_PropertyModifiedTags.find(propertyIt->first); if (tagIt != m_PropertyModifiedTags.end()) propertyIt->second->RemoveObserver(tagIt->second); tagIt = m_PropertyDeletedTags.find(propertyIt->first); if (tagIt != m_PropertyDeletedTags.end()) propertyIt->second->RemoveObserver(tagIt->second); } m_PropertyModifiedTags.clear(); m_PropertyDeletedTags.clear(); } m_PropertyList = newPropertyList; propertyList = m_PropertyList.Lock(); if (propertyList.IsNotNull()) { auto onPropertyListModified = itk::SimpleMemberCommand::New(); onPropertyListModified->SetCallbackFunction(this, &QmitkPropertyItemModel::OnPropertyListModified); m_PropertyListModifiedTag = propertyList->AddObserver(itk::ModifiedEvent(), onPropertyListModified); auto onPropertyListDeleted = itk::SimpleMemberCommand::New(); onPropertyListDeleted->SetCallbackFunction(this, &QmitkPropertyItemModel::OnPropertyListDeleted); m_PropertyListDeletedTag = propertyList->AddObserver(itk::DeleteEvent(), onPropertyListDeleted); auto modifiedCommand = itk::MemberCommand::New(); modifiedCommand->SetCallbackFunction(this, &QmitkPropertyItemModel::OnPropertyModified); const PropertyMap *propertyMap = m_PropertyList.Lock()->GetMap(); for (PropertyMap::const_iterator it = propertyMap->begin(); it != propertyMap->end(); ++it) m_PropertyModifiedTags.insert( std::make_pair(it->first, it->second->AddObserver(itk::ModifiedEvent(), modifiedCommand))); } this->CreateRootItem(); propertyList = m_PropertyList.Lock(); if (propertyList.IsNotNull() && !propertyList->IsEmpty()) { mitk::PropertyList::PropertyMap filteredProperties; bool filterProperties = false; if (m_PropertyFilters->HasFilter() || m_PropertyFilters->HasFilter(m_ClassName.toStdString())) { filteredProperties = m_PropertyFilters->ApplyFilter(*propertyList->GetMap(), m_ClassName.toStdString()); filterProperties = true; } const mitk::PropertyList::PropertyMap *propertyMap = !filterProperties ? propertyList->GetMap() : &filteredProperties; mitk::PropertyList::PropertyMap::const_iterator end = propertyMap->end(); for (mitk::PropertyList::PropertyMap::const_iterator iter = propertyMap->begin(); iter != end; ++iter) { std::vector aliases; aliases = m_PropertyAliases->GetAliases(iter->first, m_ClassName.toStdString()); if (aliases.empty() && !m_ClassName.isEmpty()) aliases = m_PropertyAliases->GetAliases(iter->first); if (aliases.empty()) { QList data; data << QString::fromStdString(iter->first) << QVariant::fromValue((reinterpret_cast(iter->second.GetPointer()))); m_RootItem->AppendChild(new QmitkPropertyItem(data)); } else { std::vector::const_iterator end = aliases.end(); for (std::vector::const_iterator aliasIter = aliases.begin(); aliasIter != end; ++aliasIter) { QList data; data << QString::fromStdString(*aliasIter) << QVariant::fromValue((reinterpret_cast(iter->second.GetPointer()))); m_RootItem->AppendChild(new QmitkPropertyItem(data)); } } } } this->endResetModel(); } void QmitkPropertyItemModel::SetPropertyList(mitk::PropertyList *propertyList, const QString &className) { if (m_PropertyList != propertyList) { m_ClassName = className; this->SetNewPropertyList(propertyList); } } void QmitkPropertyItemModel::Update() { this->SetNewPropertyList(m_PropertyList.Lock()); } diff --git a/Modules/QtWidgets/src/QmitkRenderWindowDataNodeTableModel.cpp b/Modules/QtWidgets/src/QmitkRenderWindowDataNodeTableModel.cpp index b1666aa931..c389e3e529 100644 --- a/Modules/QtWidgets/src/QmitkRenderWindowDataNodeTableModel.cpp +++ b/Modules/QtWidgets/src/QmitkRenderWindowDataNodeTableModel.cpp @@ -1,372 +1,372 @@ /*============================================================================ 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 "QmitkRenderWindowDataNodeTableModel.h" // mitk core #include // qt widgets module #include #include #include #include #include #include #include #include QmitkRenderWindowDataNodeTableModel::QmitkRenderWindowDataNodeTableModel(QObject* parent /*= nullptr*/) : QAbstractItemModel(parent) { m_RenderWindowLayerController = std::make_unique(); m_VisibleIcon = QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/visible.svg")); m_InvisibleIcon = QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/invisible.svg")); m_ArrowIcon = QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/reset.svg")); m_TimesIcon = QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/times.svg")); } void QmitkRenderWindowDataNodeTableModel::UpdateModelData() { auto baseRenderer = m_BaseRenderer.Lock(); auto greaterThan = [&baseRenderer](const mitk::DataNode* dataNodeLeft, const mitk::DataNode* dataNodeRight) { int layerLeft = -1; int layerRight = -1; bool layerLeftFound = dataNodeLeft->GetIntProperty("layer", layerLeft, baseRenderer); bool layerRightFound = dataNodeRight->GetIntProperty("layer", layerRight, baseRenderer); if (layerLeftFound && layerRightFound) { return layerLeft > layerRight; } return true; }; // sort node selection beginResetModel(); std::sort(m_CurrentSelection.begin(), m_CurrentSelection.end(), greaterThan); endResetModel(); emit ModelUpdated(); } void QmitkRenderWindowDataNodeTableModel::SetDataStorage(mitk::DataStorage* dataStorage) { m_RenderWindowLayerController->SetDataStorage(dataStorage); } void QmitkRenderWindowDataNodeTableModel::SetCurrentRenderer(mitk::BaseRenderer* baseRenderer) { if (m_BaseRenderer == baseRenderer) { // resetting the same base renderer does nothing return; } m_BaseRenderer = baseRenderer; // update the model, since a new base renderer could have set the relevant node-properties differently this->UpdateModelData(); } mitk::BaseRenderer::Pointer QmitkRenderWindowDataNodeTableModel::GetCurrentRenderer() const { return m_BaseRenderer.Lock(); } void QmitkRenderWindowDataNodeTableModel::SetCurrentSelection(NodeList selectedNodes) { m_CurrentSelection = selectedNodes; // update the model: sort the current internal selection this->UpdateModelData(); } QmitkRenderWindowDataNodeTableModel::NodeList QmitkRenderWindowDataNodeTableModel::GetCurrentSelection() const { return m_CurrentSelection; } QModelIndex QmitkRenderWindowDataNodeTableModel::index(int row, int column, const QModelIndex& parent /*= QModelIndex()*/) const { bool hasIndex = this->hasIndex(row, column, parent); if (hasIndex) { return this->createIndex(row, column); } return QModelIndex(); } QModelIndex QmitkRenderWindowDataNodeTableModel::parent(const QModelIndex& /*child*/) const { return QModelIndex(); } int QmitkRenderWindowDataNodeTableModel::rowCount(const QModelIndex& parent /*= QModelIndex()*/) const { if (parent.isValid()) { return 0; } return static_cast(m_CurrentSelection.size()); } int QmitkRenderWindowDataNodeTableModel::columnCount(const QModelIndex& parent /*= QModelIndex()*/) const { if (parent.isValid()) { return 0; } return 4; } Qt::ItemFlags QmitkRenderWindowDataNodeTableModel::flags(const QModelIndex &index) const { if (this != index.model()) { return Qt::NoItemFlags; } if (index.isValid()) { if (index.column() == 0) { return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; } return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; } else { return Qt::ItemIsDropEnabled; } } QVariant QmitkRenderWindowDataNodeTableModel::data(const QModelIndex& index, int role) const { if (!index.isValid() || this != index.model()) { return QVariant(); } if (index.row() < 0 || index.row() >= static_cast(m_CurrentSelection.size())) { return QVariant(); } mitk::DataNode* dataNode = m_CurrentSelection.at(index.row()); if (role == QmitkDataNodeRole) { return QVariant::fromValue(mitk::DataNode::Pointer(dataNode)); } if (role == QmitkDataNodeRawPointerRole) { return QVariant::fromValue(dataNode); } if (index.column() == 0) // data node information column { QString nodeName = QString::fromStdString(dataNode->GetName()); if (nodeName.isEmpty()) { nodeName = "unnamed"; } if (role == Qt::DisplayRole || role == Qt::EditRole) { return nodeName; } if (role == Qt::ToolTipRole) { return QVariant("Name of the data node."); } if (role == Qt::DecorationRole) { QmitkNodeDescriptor* nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(dataNode); return QVariant(nodeDescriptor->GetIcon(dataNode)); } } if (index.column() == 1) // node visibility column { if (role == Qt::DecorationRole) { auto baseRenderer = m_BaseRenderer.Lock(); bool visibility = false; dataNode->GetVisibility(visibility, baseRenderer); return visibility ? QVariant(m_VisibleIcon) : QVariant(m_InvisibleIcon); } if (role == Qt::EditRole) { auto baseRenderer = m_BaseRenderer.Lock(); bool visibility = false; dataNode->GetVisibility(visibility, baseRenderer); return QVariant(visibility); } } if (index.column() == 2) // reset geometry column { if (role == Qt::DecorationRole) { return QVariant(m_ArrowIcon); } } if (index.column() == 3) // remove node column { if (role == Qt::DecorationRole) { return QVariant(m_TimesIcon); } } return QVariant(); } bool QmitkRenderWindowDataNodeTableModel::setData(const QModelIndex& index, const QVariant& value, int role) { if (!index.isValid() || this != index.model()) { return false; } if (index.row() < 0 || index.row() >= static_cast(m_CurrentSelection.size())) { return false; } mitk::DataNode* dataNode = m_CurrentSelection.at(index.row()); if (index.column() == 0) // data node information column { if (role == Qt::EditRole && !value.toString().isEmpty()) { dataNode->SetName(value.toString().toStdString()); emit dataChanged(index, index); return true; } } if (index.column() == 1) // data node visibility column { if (role == Qt::EditRole) { auto baseRenderer = m_BaseRenderer.Lock(); bool visibility = value.toBool(); dataNode->SetVisibility(visibility, baseRenderer); if (baseRenderer.IsNotNull()) { // Explicitly request an update since a renderer-specific property change does not mark the node as modified. // see https://phabricator.mitk.org/T22322 mitk::RenderingManager::GetInstance()->RequestUpdate(baseRenderer->GetRenderWindow()); } emit dataChanged(index, index); return true; } } return false; } Qt::DropActions QmitkRenderWindowDataNodeTableModel::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } Qt::DropActions QmitkRenderWindowDataNodeTableModel::supportedDragActions() const { return Qt::CopyAction | Qt::MoveAction; } QStringList QmitkRenderWindowDataNodeTableModel::mimeTypes() const { QStringList types = QAbstractItemModel::mimeTypes(); types << QmitkMimeTypes::DataNodePtrs; return types; } QMimeData* QmitkRenderWindowDataNodeTableModel::mimeData(const QModelIndexList& indexes) const { QMimeData* mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); for (const auto& index : indexes) { if (index.isValid()) { auto dataNode = data(index, QmitkDataNodeRawPointerRole).value(); stream << reinterpret_cast(dataNode); } } mimeData->setData(QmitkMimeTypes::DataNodePtrs, encodedData); return mimeData; } bool QmitkRenderWindowDataNodeTableModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int /*row*/, int /*column*/, const QModelIndex& parent) { if (action == Qt::IgnoreAction) { return true; } if (!data->hasFormat(QmitkMimeTypes::DataNodePtrs)) { return false; } if (parent.isValid()) { auto baseRenderer = m_BaseRenderer.Lock(); int layer = -1; auto dataNode = this->data(parent, QmitkDataNodeRawPointerRole).value(); if (nullptr != dataNode) { dataNode->GetIntProperty("layer", layer, baseRenderer); } auto dataNodeList = QmitkMimeTypes::ToDataNodePtrList(data); - for (const auto& dataNode : qAsConst(dataNodeList)) + for (const auto& dataNode : std::as_const(dataNodeList)) { m_RenderWindowLayerController->MoveNodeToPosition(dataNode, layer, baseRenderer); } this->UpdateModelData(); return true; } return false; } diff --git a/Modules/QtWidgets/src/QmitkRenderWindowDataStorageTreeModel.cpp b/Modules/QtWidgets/src/QmitkRenderWindowDataStorageTreeModel.cpp index c1543e3f54..6e71ca65b5 100644 --- a/Modules/QtWidgets/src/QmitkRenderWindowDataStorageTreeModel.cpp +++ b/Modules/QtWidgets/src/QmitkRenderWindowDataStorageTreeModel.cpp @@ -1,608 +1,608 @@ /*============================================================================ 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. ============================================================================*/ // render window manager UI module #include "QmitkRenderWindowDataStorageTreeModel.h" #include // qt widgets module #include "QmitkCustomVariants.h" #include "QmitkEnums.h" #include "QmitkMimeTypes.h" #include "QmitkNodeDescriptorManager.h" #include QmitkRenderWindowDataStorageTreeModel::QmitkRenderWindowDataStorageTreeModel(QObject* parent /*= nullptr*/) : QmitkAbstractDataStorageModel(parent) , m_Root(nullptr) { m_RenderWindowLayerController = std::make_unique(); ResetTree(); } void QmitkRenderWindowDataStorageTreeModel::DataStorageChanged() { m_RenderWindowLayerController->SetDataStorage(m_DataStorage.Lock()); ResetTree(); UpdateModelData(); } void QmitkRenderWindowDataStorageTreeModel::NodePredicateChanged() { ResetTree(); UpdateModelData(); } void QmitkRenderWindowDataStorageTreeModel::NodeAdded(const mitk::DataNode* node) { auto baseRenderer = m_BaseRenderer.Lock(); if (baseRenderer.IsNull()) { return; } if (m_NodePredicate.IsNotNull()) { if (m_NodePredicate->CheckNode(node)) { AddNodeInternal(node, baseRenderer); } } } void QmitkRenderWindowDataStorageTreeModel::NodeChanged(const mitk::DataNode* node) { auto item = m_Root->Find(node); if (nullptr != item) { auto parentItem = item->GetParent(); // as the root node should not be removed one should always have a parent item if (nullptr == parentItem) { return; } auto index = createIndex(item->GetIndex(), 0, item); emit dataChanged(index, index); } } void QmitkRenderWindowDataStorageTreeModel::NodeRemoved(const mitk::DataNode* node) { RemoveNodeInternal(node); } QModelIndex QmitkRenderWindowDataStorageTreeModel::index(int row, int column, const QModelIndex& parent) const { auto item = GetItemByIndex(parent); if (nullptr != item) { item = item->GetChild(row); } if (nullptr == item) { return QModelIndex(); } return createIndex(row, column, item); } QModelIndex QmitkRenderWindowDataStorageTreeModel::parent(const QModelIndex& parent) const { auto item = GetItemByIndex(parent); if (nullptr != item) { item = item->GetParent(); } if(nullptr == item) { return QModelIndex(); } if (item == m_Root) { return QModelIndex(); } return createIndex(item->GetIndex(), 0, item); } int QmitkRenderWindowDataStorageTreeModel::rowCount(const QModelIndex& parent /*= QModelIndex()*/) const { auto item = GetItemByIndex(parent); if (nullptr == item) { return 0; } return item->GetChildCount(); } int QmitkRenderWindowDataStorageTreeModel::columnCount(const QModelIndex&/* parent = QModelIndex()*/) const { if (0 == m_Root->GetChildCount()) { // no items stored, no need to display columns return 0; } return 1; } QVariant QmitkRenderWindowDataStorageTreeModel::data(const QModelIndex& index, int role) const { auto baseRenderer = m_BaseRenderer.Lock(); if (baseRenderer.IsNull()) { return QVariant(); } if (!index.isValid() || this != index.model()) { return QVariant(); } auto item = GetItemByIndex(index); if (nullptr == item) { return QVariant(); } auto dataNode = item->GetDataNode(); if (nullptr == dataNode) { return QVariant(); } if (Qt::CheckStateRole == role) { bool visibility = false; dataNode->GetVisibility(visibility, baseRenderer); if (visibility) { return Qt::Checked; } else { return Qt::Unchecked; } } else if (Qt::DisplayRole == role) { return QVariant(QString::fromStdString(dataNode->GetName())); } else if (Qt::ToolTipRole == role) { return QVariant("Name of the data node."); } else if (Qt::DecorationRole == role) { QmitkNodeDescriptor* nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(dataNode); return nodeDescriptor->GetIcon(dataNode); } else if (Qt::UserRole == role || QmitkDataNodeRawPointerRole == role) { // user role always returns a reference to the data node, // which can be used to modify the data node in the data storage return QVariant::fromValue(dataNode); } else if (QmitkDataNodeRole == role) { return QVariant::fromValue(mitk::DataNode::Pointer(dataNode)); } return QVariant(); } bool QmitkRenderWindowDataStorageTreeModel::setData(const QModelIndex& index, const QVariant& value, int role /*= Qt::EditRole*/) { auto baseRenderer = m_BaseRenderer.Lock(); if (baseRenderer.IsNull()) { return false; } if (!index.isValid() || this != index.model()) { return false; } auto item = GetItemByIndex(index); if (nullptr == item) { return false; } auto dataNode = item->GetDataNode(); if (nullptr == dataNode) { return false; } if (Qt::EditRole == role && !value.toString().isEmpty()) { dataNode->SetName(value.toString().toStdString().c_str()); emit dataChanged(index, index); return true; } if (Qt::CheckStateRole == role) { Qt::CheckState newCheckState = static_cast(value.toInt()); bool isVisible = newCheckState; dataNode->SetVisibility(isVisible, baseRenderer); emit dataChanged(index, index); mitk::RenderingManager::GetInstance()->RequestUpdate(baseRenderer->GetRenderWindow()); return true; } return false; } Qt::ItemFlags QmitkRenderWindowDataStorageTreeModel::flags(const QModelIndex& index) const { if (this != index.model()) { return Qt::NoItemFlags; } if (!index.isValid()) { return Qt::ItemIsDropEnabled; } auto item = GetItemByIndex(index); if (nullptr == item) { return Qt::NoItemFlags; } const auto dataNode = item->GetDataNode(); if (m_NodePredicate.IsNull() || m_NodePredicate->CheckNode(dataNode)) { return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; } return Qt::NoItemFlags; } Qt::DropActions QmitkRenderWindowDataStorageTreeModel::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } Qt::DropActions QmitkRenderWindowDataStorageTreeModel::supportedDragActions() const { return Qt::CopyAction | Qt::MoveAction; } QStringList QmitkRenderWindowDataStorageTreeModel::mimeTypes() const { QStringList types = QAbstractItemModel::mimeTypes(); types << QmitkMimeTypes::DataNodePtrs; return types; } QMimeData* QmitkRenderWindowDataStorageTreeModel::mimeData(const QModelIndexList& indexes) const { QMimeData* mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); for (const auto& index : indexes) { if (index.isValid()) { auto dataNode = data(index, QmitkDataNodeRawPointerRole).value(); stream << reinterpret_cast(dataNode); } } mimeData->setData(QmitkMimeTypes::DataNodePtrs, encodedData); return mimeData; } bool QmitkRenderWindowDataStorageTreeModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int /*row*/, int /*column*/, const QModelIndex& parent) { auto baseRenderer = m_BaseRenderer.Lock(); if (baseRenderer.IsNull()) { return false; } if (action == Qt::IgnoreAction) { return true; } if (!data->hasFormat(QmitkMimeTypes::DataNodePtrs)) { return false; } if (!parent.isValid()) { return false; } int layer = -1; auto dataNode = this->data(parent, QmitkDataNodeRawPointerRole).value(); if (nullptr != dataNode) { dataNode->GetIntProperty("layer", layer, baseRenderer); } auto dataNodeList = QmitkMimeTypes::ToDataNodePtrList(data); - for (const auto& dataNode : qAsConst(dataNodeList)) + for (const auto& dataNode : std::as_const(dataNodeList)) { m_RenderWindowLayerController->MoveNodeToPosition(dataNode, layer, baseRenderer); } ResetTree(); UpdateModelData(); AdjustLayerProperty(); return true; } void QmitkRenderWindowDataStorageTreeModel::SetControlledRenderer(mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer) { ResetTree(); auto dataStorage = m_DataStorage.Lock(); if (dataStorage.IsNull()) { return; } for (const auto& renderer : controlledRenderer) { if (nullptr == renderer) { continue; } auto allDataNodes = dataStorage->GetAll(); for (const auto& dataNode : *allDataNodes) { // add the node to each render window mitk::RenderWindowLayerUtilities::SetRenderWindowProperties(dataNode, renderer); } } } void QmitkRenderWindowDataStorageTreeModel::SetCurrentRenderer(mitk::BaseRenderer* baseRenderer) { if (m_BaseRenderer == baseRenderer) { return; } // base renderer changed // reset tree to build a new renderer-specific item hierarchy m_BaseRenderer = baseRenderer; ResetTree(); UpdateModelData(); } mitk::BaseRenderer::Pointer QmitkRenderWindowDataStorageTreeModel::GetCurrentRenderer() const { return m_BaseRenderer.Lock(); } void QmitkRenderWindowDataStorageTreeModel::ResetTree() { beginResetModel(); if (nullptr != m_Root) { m_Root->Delete(); } mitk::DataNode::Pointer rootDataNode = mitk::DataNode::New(); rootDataNode->SetName("Data Storage"); m_Root = new QmitkDataStorageTreeModelInternalItem(rootDataNode); endResetModel(); } void QmitkRenderWindowDataStorageTreeModel::UpdateModelData() { auto dataStorage = m_DataStorage.Lock(); if (dataStorage.IsNotNull()) { auto baseRenderer = m_BaseRenderer.Lock(); if (baseRenderer.IsNotNull()) { auto allDataNodes = dataStorage->GetAll(); for (const auto& dataNode : *allDataNodes) { // add the node to each render window mitk::RenderWindowLayerUtilities::SetRenderWindowProperties(dataNode, baseRenderer); } if (m_NodePredicate.IsNotNull()) { auto filteredDataNodes = dataStorage->GetSubset(m_NodePredicate); for (const auto& dataNode : *filteredDataNodes) { AddNodeInternal(dataNode, baseRenderer); } } } } } void QmitkRenderWindowDataStorageTreeModel::AdjustLayerProperty() { auto baseRenderer = m_BaseRenderer.Lock(); if (baseRenderer.IsNull()) { return; } std::vector treeAsVector; TreeToVector(m_Root, treeAsVector); int i = treeAsVector.size() - 1; for (auto it = treeAsVector.begin(); it != treeAsVector.end(); ++it) { auto dataNode = (*it)->GetDataNode(); dataNode->SetIntProperty("layer", i, baseRenderer); --i; } } void QmitkRenderWindowDataStorageTreeModel::TreeToVector(QmitkDataStorageTreeModelInternalItem* parent, std::vector& treeAsVector) const { QmitkDataStorageTreeModelInternalItem* item; for (int i = 0; i < parent->GetChildCount(); ++i) { item = parent->GetChild(i); TreeToVector(item, treeAsVector); treeAsVector.push_back(item); } } void QmitkRenderWindowDataStorageTreeModel::AddNodeInternal(const mitk::DataNode* dataNode, const mitk::BaseRenderer* renderer) { if (nullptr == dataNode || m_DataStorage.IsExpired() || nullptr != m_Root->Find(dataNode)) { return; } // find out if we have a root node auto parentItem = m_Root; QModelIndex index; auto parentDataNode = GetParentNode(dataNode); if (nullptr != parentDataNode) // no top level data node { parentItem = m_Root->Find(parentDataNode); if (nullptr == parentItem) { // parent node not contained in the tree; add it NodeAdded(parentDataNode); parentItem = m_Root->Find(parentDataNode); if (nullptr == parentItem) { // could not find and add the parent tree; abort return; } } // get the index of this parent with the help of the grand parent index = createIndex(parentItem->GetIndex(), 0, parentItem); } int firstRowWithASiblingBelow = 0; int nodeLayer = -1; dataNode->GetIntProperty("layer", nodeLayer, renderer); for (const auto& siblingItem : parentItem->GetChildren()) { int siblingLayer = -1; auto siblingNode = siblingItem->GetDataNode(); if (nullptr != siblingNode) { siblingNode->GetIntProperty("layer", siblingLayer, renderer); } if (nodeLayer > siblingLayer) { break; } ++firstRowWithASiblingBelow; } beginInsertRows(index, firstRowWithASiblingBelow, firstRowWithASiblingBelow); auto newNode = new QmitkDataStorageTreeModelInternalItem(const_cast(dataNode)); parentItem->InsertChild(newNode, firstRowWithASiblingBelow); endInsertRows(); } void QmitkRenderWindowDataStorageTreeModel::RemoveNodeInternal(const mitk::DataNode* dataNode) { if (nullptr == dataNode || nullptr == m_Root) { return; } auto item = m_Root->Find(dataNode); if (nullptr == item) { return; } auto parentItem = item->GetParent(); auto parentIndex = GetIndexByItem(parentItem); auto children = item->GetChildren(); beginRemoveRows(parentIndex, item->GetIndex(), item->GetIndex()); parentItem->RemoveChild(item); delete item; endRemoveRows(); if (!children.empty()) { // rebuild tree because children could not be at the top level ResetTree(); UpdateModelData(); } } mitk::DataNode* QmitkRenderWindowDataStorageTreeModel::GetParentNode(const mitk::DataNode* node) const { mitk::DataNode* dataNode = nullptr; auto dataStorage = m_DataStorage.Lock(); if (dataStorage.IsNull()) { return dataNode; } auto sources = dataStorage->GetSources(node); if (sources->empty()) { return dataNode; } return sources->front(); } QmitkDataStorageTreeModelInternalItem* QmitkRenderWindowDataStorageTreeModel::GetItemByIndex(const QModelIndex& index) const { if (index.isValid()) { return static_cast(index.internalPointer()); } return m_Root; } QModelIndex QmitkRenderWindowDataStorageTreeModel::GetIndexByItem(QmitkDataStorageTreeModelInternalItem* item) const { if (item == m_Root) { return QModelIndex(); } return createIndex(item->GetIndex(), 0, item); } diff --git a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageListModel.cpp b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageListModel.cpp index 5177ec6657..0859779c25 100644 --- a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageListModel.cpp +++ b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageListModel.cpp @@ -1,352 +1,352 @@ /*============================================================================ 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. ============================================================================*/ // render window manager UI module #include "QmitkRenderWindowDataStorageListModel.h" // qt widgets module #include "QmitkCustomVariants.h" #include "QmitkEnums.h" #include "QmitkMimeTypes.h" #include "QmitkNodeDescriptorManager.h" #include QmitkRenderWindowDataStorageListModel::QmitkRenderWindowDataStorageListModel(QObject* parent /*= nullptr*/) : QmitkAbstractDataStorageModel(parent) { m_RenderWindowLayerController = std::make_unique(); } void QmitkRenderWindowDataStorageListModel::DataStorageChanged() { m_RenderWindowLayerController->SetDataStorage(m_DataStorage.Lock()); UpdateModelData(); } void QmitkRenderWindowDataStorageListModel::NodePredicateChanged() { UpdateModelData(); } void QmitkRenderWindowDataStorageListModel::NodeAdded(const mitk::DataNode* node) { // add a node to each render window specific list (or to a global list initially) AddDataNodeToAllRenderer(const_cast(node)); UpdateModelData(); } void QmitkRenderWindowDataStorageListModel::NodeChanged(const mitk::DataNode* /*node*/) { // nothing here, since the "'NodeChanged'-event is currently sent far too often } void QmitkRenderWindowDataStorageListModel::NodeRemoved(const mitk::DataNode* /*node*/) { // update model data to create a new list without the removed data node UpdateModelData(); } QModelIndex QmitkRenderWindowDataStorageListModel::index(int row, int column, const QModelIndex& parent) const { bool hasIndex = this->hasIndex(row, column, parent); if (hasIndex) { return this->createIndex(row, column); } return QModelIndex(); } QModelIndex QmitkRenderWindowDataStorageListModel::parent(const QModelIndex& /*child*/) const { return QModelIndex(); } int QmitkRenderWindowDataStorageListModel::rowCount(const QModelIndex& parent /*= QModelIndex()*/) const { if (parent.isValid()) { return 0; } return static_cast(m_LayerStack.size()); } int QmitkRenderWindowDataStorageListModel::columnCount(const QModelIndex& parent /*= QModelIndex()*/) const { if (parent.isValid()) { return 0; } return 1; } QVariant QmitkRenderWindowDataStorageListModel::data(const QModelIndex& index, int role) const { auto baseRenderer = m_BaseRenderer.Lock(); if (baseRenderer.IsNull()) { return QVariant(); } if (!index.isValid() || this != index.model()) { return QVariant(); } if (index.row() < 0 || index.row() >= static_cast(m_LayerStack.size())) { return QVariant(); } mitk::RenderWindowLayerUtilities::LayerStack::const_iterator layerStackIt = m_LayerStack.begin(); std::advance(layerStackIt, index.row()); mitk::DataNode* dataNode = layerStackIt->second; if (Qt::CheckStateRole == role) { bool visibility = false; dataNode->GetVisibility(visibility, baseRenderer); if (visibility) { return Qt::Checked; } else { return Qt::Unchecked; } } else if (Qt::DisplayRole == role) { return QVariant(QString::fromStdString(dataNode->GetName())); } else if (Qt::ToolTipRole == role) { return QVariant("Name of the data node."); } else if (Qt::DecorationRole == role) { QmitkNodeDescriptor* nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(dataNode); return nodeDescriptor->GetIcon(dataNode); } else if (Qt::UserRole == role || QmitkDataNodeRawPointerRole == role) { // user role always returns a reference to the data node, // which can be used to modify the data node in the data storage return QVariant::fromValue(dataNode); } else if (QmitkDataNodeRole == role) { return QVariant::fromValue(mitk::DataNode::Pointer(dataNode)); } return QVariant(); } bool QmitkRenderWindowDataStorageListModel::setData(const QModelIndex& index, const QVariant& value, int role /*= Qt::EditRole*/) { auto baseRenderer = m_BaseRenderer.Lock(); if (baseRenderer.IsNull()) { return false; } if (!index.isValid() || this != index.model()) { return false; } if (index.row() < 0 || index.row() >= static_cast(m_LayerStack.size())) { return false; } mitk::RenderWindowLayerUtilities::LayerStack::const_iterator layerStackIt = m_LayerStack.begin(); std::advance(layerStackIt, index.row()); mitk::DataNode* dataNode = layerStackIt->second; if (Qt::CheckStateRole == role) { Qt::CheckState newCheckState = static_cast(value.toInt()); bool isVisible = newCheckState; dataNode->SetVisibility(isVisible, baseRenderer); emit dataChanged(index, index); mitk::RenderingManager::GetInstance()->RequestUpdate(baseRenderer->GetRenderWindow()); return true; } return false; } Qt::ItemFlags QmitkRenderWindowDataStorageListModel::flags(const QModelIndex &index) const { if (this != index.model()) { return Qt::NoItemFlags; } if (!index.isValid()) { return Qt::ItemIsDropEnabled; } return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; } Qt::DropActions QmitkRenderWindowDataStorageListModel::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } Qt::DropActions QmitkRenderWindowDataStorageListModel::supportedDragActions() const { return Qt::CopyAction | Qt::MoveAction; } QStringList QmitkRenderWindowDataStorageListModel::mimeTypes() const { QStringList types = QAbstractItemModel::mimeTypes(); types << QmitkMimeTypes::DataNodePtrs; return types; } QMimeData* QmitkRenderWindowDataStorageListModel::mimeData(const QModelIndexList& indexes) const { QMimeData* mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); for (const auto& index : indexes) { if (index.isValid()) { auto dataNode = data(index, QmitkDataNodeRawPointerRole).value(); stream << reinterpret_cast(dataNode); } } mimeData->setData(QmitkMimeTypes::DataNodePtrs, encodedData); return mimeData; } bool QmitkRenderWindowDataStorageListModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int /*row*/, int column, const QModelIndex& parent) { auto baseRenderer = m_BaseRenderer.Lock(); if (baseRenderer.IsNull()) { return false; } if (action == Qt::IgnoreAction) { return true; } if (!data->hasFormat(QmitkMimeTypes::DataNodePtrs)) { return false; } if (column > 0) { return false; } if (parent.isValid()) { int layer = -1; auto dataNode = this->data(parent, QmitkDataNodeRawPointerRole).value(); if (nullptr != dataNode) { dataNode->GetIntProperty("layer", layer, baseRenderer); } auto dataNodeList = QmitkMimeTypes::ToDataNodePtrList(data); - for (const auto& dataNode : qAsConst(dataNodeList)) + for (const auto& dataNode : std::as_const(dataNodeList)) { m_RenderWindowLayerController->MoveNodeToPosition(dataNode, layer, baseRenderer); } UpdateModelData(); return true; } return false; } void QmitkRenderWindowDataStorageListModel::SetControlledRenderer(mitk::RenderWindowLayerUtilities::RendererVector /*controlledRenderer*/) { auto dataStorage = m_DataStorage.Lock(); if (dataStorage.IsNotNull()) { mitk::DataStorage::SetOfObjects::ConstPointer allDataNodes = dataStorage->GetAll(); for (mitk::DataStorage::SetOfObjects::ConstIterator it = allDataNodes->Begin(); it != allDataNodes->End(); ++it) { mitk::DataNode::Pointer dataNode = it->Value(); if (dataNode.IsNull()) { continue; } AddDataNodeToAllRenderer(dataNode); } } } void QmitkRenderWindowDataStorageListModel::SetCurrentRenderer(mitk::BaseRenderer* baseRenderer) { if (m_BaseRenderer == baseRenderer) { return; } m_BaseRenderer = baseRenderer; if (!m_BaseRenderer.IsExpired()) { UpdateModelData(); } } mitk::BaseRenderer::Pointer QmitkRenderWindowDataStorageListModel::GetCurrentRenderer() const { return m_BaseRenderer.Lock(); } void QmitkRenderWindowDataStorageListModel::AddDataNodeToAllRenderer(mitk::DataNode* dataNode) { m_RenderWindowLayerController->InsertLayerNode(dataNode); } void QmitkRenderWindowDataStorageListModel::UpdateModelData() { auto dataStorage = m_DataStorage.Lock(); if (dataStorage.IsNotNull()) { auto baseRenderer = m_BaseRenderer.Lock(); if (baseRenderer.IsNotNull()) { // update the model, so that it will be filled with the nodes of the new data storage beginResetModel(); // get the current layer stack of the given base renderer m_LayerStack = mitk::RenderWindowLayerUtilities::GetLayerStack(dataStorage, baseRenderer); endResetModel(); } } } diff --git a/Modules/SegmentationUI/Qmitk/QmitkMultiLabelInspector.cpp b/Modules/SegmentationUI/Qmitk/QmitkMultiLabelInspector.cpp index 2b2002ec07..0f4565a621 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkMultiLabelInspector.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitkMultiLabelInspector.cpp @@ -1,1139 +1,1139 @@ /*============================================================================ 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 // mitk #include #include #include // Qmitk #include #include #include #include // Qt #include #include #include #include #include QmitkMultiLabelInspector::QmitkMultiLabelInspector(QWidget* parent/* = nullptr*/) : QWidget(parent), m_Controls(new Ui::QmitkMultiLabelInspector) { m_Controls->setupUi(this); m_Model = new QmitkMultiLabelTreeModel(this); m_Controls->view->setModel(m_Model); m_ColorItemDelegate = new QmitkLabelColorItemDelegate(this); auto visibleIcon = QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/visible.svg")); auto invisibleIcon = QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/invisible.svg")); m_VisibilityItemDelegate = new QmitkLabelToggleItemDelegate(visibleIcon, invisibleIcon, this); auto lockIcon = QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/lock.svg")); auto unlockIcon = QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/unlock.svg")); m_LockItemDelegate = new QmitkLabelToggleItemDelegate(lockIcon, unlockIcon, this); auto* view = this->m_Controls->view; view->setItemDelegateForColumn(1, m_LockItemDelegate); view->setItemDelegateForColumn(2, m_ColorItemDelegate); view->setItemDelegateForColumn(3, m_VisibilityItemDelegate); auto* header = view->header(); header->setSectionResizeMode(0,QHeaderView::Stretch); header->setSectionResizeMode(1, QHeaderView::ResizeToContents); header->setSectionResizeMode(2, QHeaderView::ResizeToContents); header->setSectionResizeMode(3, QHeaderView::ResizeToContents); view->setContextMenuPolicy(Qt::CustomContextMenu); connect(m_Model, &QAbstractItemModel::modelReset, this, &QmitkMultiLabelInspector::OnModelReset); connect(view->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), SLOT(OnChangeModelSelection(const QItemSelection&, const QItemSelection&))); connect(view, &QAbstractItemView::customContextMenuRequested, this, &QmitkMultiLabelInspector::OnContextMenuRequested); connect(view, &QAbstractItemView::doubleClicked, this, &QmitkMultiLabelInspector::OnItemDoubleClicked); } QmitkMultiLabelInspector::~QmitkMultiLabelInspector() { delete m_Controls; } void QmitkMultiLabelInspector::Initialize() { m_LastValidSelectedLabels = {}; m_ModelManipulationOngoing = false; m_Model->SetSegmentation(m_Segmentation); m_Controls->view->expandAll(); m_LastValidSelectedLabels = {}; //in singel selection mode, if at least one label exist select the first label of the mode. if (m_Segmentation.IsNotNull() && !this->GetMultiSelectionMode() && m_Segmentation->GetTotalNumberOfLabels() > 0) { auto firstIndex = m_Model->FirstLabelInstanceIndex(QModelIndex()); auto labelVariant = firstIndex.data(QmitkMultiLabelTreeModel::ItemModelRole::LabelInstanceValueRole); if (labelVariant.isValid()) { this->SetSelectedLabel(labelVariant.value()); m_Controls->view->selectionModel()->setCurrentIndex(firstIndex, QItemSelectionModel::NoUpdate); } } } void QmitkMultiLabelInspector::SetMultiSelectionMode(bool multiMode) { m_Controls->view->setSelectionMode(multiMode ? QAbstractItemView::SelectionMode::MultiSelection : QAbstractItemView::SelectionMode::SingleSelection); } bool QmitkMultiLabelInspector::GetMultiSelectionMode() const { return QAbstractItemView::SelectionMode::MultiSelection == m_Controls->view->selectionMode(); } void QmitkMultiLabelInspector::SetAllowVisibilityModification(bool visibilityMod) { m_AllowVisibilityModification = visibilityMod; this->m_Model->SetAllowVisibilityModification(visibilityMod); } void QmitkMultiLabelInspector::SetAllowLabelModification(bool labelMod) { m_AllowLabelModification = labelMod; } bool QmitkMultiLabelInspector::GetAllowVisibilityModification() const { return m_AllowVisibilityModification; } void QmitkMultiLabelInspector::SetAllowLockModification(bool lockMod) { m_AllowLockModification = lockMod; this->m_Model->SetAllowLockModification(lockMod); } bool QmitkMultiLabelInspector::GetAllowLockModification() const { return m_AllowLockModification; } bool QmitkMultiLabelInspector::GetAllowLabelModification() const { return m_AllowLabelModification; } void QmitkMultiLabelInspector::SetDefaultLabelNaming(bool defaultLabelNaming) { m_DefaultLabelNaming = defaultLabelNaming; } void QmitkMultiLabelInspector::SetMultiLabelSegmentation(mitk::LabelSetImage* segmentation) { if (segmentation != m_Segmentation) { m_Segmentation = segmentation; this->Initialize(); } } bool QmitkMultiLabelInspector::GetModelManipulationOngoing() const { return m_ModelManipulationOngoing; } void QmitkMultiLabelInspector::OnModelReset() { m_LastValidSelectedLabels = {}; m_ModelManipulationOngoing = false; } bool EqualLabelSelections(const QmitkMultiLabelInspector::LabelValueVectorType& selection1, const QmitkMultiLabelInspector::LabelValueVectorType& selection2) { if (selection1.size() == selection2.size()) { // lambda to compare node pointer inside both lists return std::is_permutation(selection1.begin(), selection1.end(), selection2.begin()); } return false; } void QmitkMultiLabelInspector::SetSelectedLabels(const LabelValueVectorType& selectedLabels) { if (EqualLabelSelections(this->GetSelectedLabels(), selectedLabels)) { return; } this->UpdateSelectionModel(selectedLabels); m_LastValidSelectedLabels = selectedLabels; } void QmitkMultiLabelInspector::UpdateSelectionModel(const LabelValueVectorType& selectedLabels) { // create new selection by retrieving the corresponding indices of the labels QItemSelection newCurrentSelection; for (const auto& labelID : selectedLabels) { QModelIndexList matched = m_Model->match(m_Model->index(0, 0), QmitkMultiLabelTreeModel::ItemModelRole::LabelInstanceValueRole, QVariant(labelID), 1, Qt::MatchRecursive); if (!matched.empty()) { newCurrentSelection.select(matched.front(), matched.front()); } } m_Controls->view->selectionModel()->select(newCurrentSelection, QItemSelectionModel::ClearAndSelect|QItemSelectionModel::Current); } void QmitkMultiLabelInspector::SetSelectedLabel(mitk::LabelSetImage::LabelValueType selectedLabel) { this->SetSelectedLabels({ selectedLabel }); } QmitkMultiLabelInspector::LabelValueVectorType QmitkMultiLabelInspector::GetSelectedLabelsFromSelectionModel() const { LabelValueVectorType result; QModelIndexList selectedIndexes = m_Controls->view->selectionModel()->selectedIndexes(); - for (const auto& index : qAsConst(selectedIndexes)) + for (const auto& index : std::as_const(selectedIndexes)) { QVariant qvariantDataNode = m_Model->data(index, QmitkMultiLabelTreeModel::ItemModelRole::LabelInstanceValueRole); if (qvariantDataNode.canConvert()) { result.push_back(qvariantDataNode.value()); } } return result; } QmitkMultiLabelInspector::LabelValueVectorType QmitkMultiLabelInspector::GetSelectedLabels() const { return m_LastValidSelectedLabels; } mitk::Label* QmitkMultiLabelInspector::GetFirstSelectedLabelObject() const { if (m_LastValidSelectedLabels.empty() || m_Segmentation.IsNull()) return nullptr; return m_Segmentation->GetLabel(m_LastValidSelectedLabels.front()); } void QmitkMultiLabelInspector::OnChangeModelSelection(const QItemSelection& /*selected*/, const QItemSelection& /*deselected*/) { if (!m_ModelManipulationOngoing) { auto internalSelection = GetSelectedLabelsFromSelectionModel(); if (internalSelection.empty()) { //empty selections are not allowed by UI interactions, there should always be at least on label selected. //but selections are e.g. also cleared if the model is updated (e.g. due to addition of labels) UpdateSelectionModel(m_LastValidSelectedLabels); } else { m_LastValidSelectedLabels = internalSelection; emit CurrentSelectionChanged(GetSelectedLabels()); } } } void QmitkMultiLabelInspector::WaitCursorOn() const { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); } void QmitkMultiLabelInspector::WaitCursorOff() const { this->RestoreOverrideCursor(); } void QmitkMultiLabelInspector::RestoreOverrideCursor() const { QApplication::restoreOverrideCursor(); } mitk::Label* QmitkMultiLabelInspector::GetCurrentLabel() const { auto currentIndex = this->m_Controls->view->currentIndex(); auto labelVariant = currentIndex.data(QmitkMultiLabelTreeModel::ItemModelRole::LabelDataRole); mitk::Label::Pointer currentIndexLabel = nullptr; if (labelVariant.isValid()) { auto uncastedLabel = labelVariant.value(); currentIndexLabel = static_cast(uncastedLabel); } return currentIndexLabel; } QmitkMultiLabelInspector::IndexLevelType QmitkMultiLabelInspector::GetCurrentLevelType() const { auto currentIndex = this->m_Controls->view->currentIndex(); auto labelInstanceVariant = currentIndex.data(QmitkMultiLabelTreeModel::ItemModelRole::LabelInstanceDataRole); auto labelVariant = currentIndex.data(QmitkMultiLabelTreeModel::ItemModelRole::LabelDataRole); if (labelInstanceVariant.isValid() ) { return IndexLevelType::LabelInstance; } else if (labelVariant.isValid()) { return IndexLevelType::LabelClass; } return IndexLevelType::Group; } QmitkMultiLabelInspector::LabelValueVectorType QmitkMultiLabelInspector::GetCurrentlyAffactedLabelInstances() const { auto currentIndex = m_Controls->view->currentIndex(); return m_Model->GetLabelsInSubTree(currentIndex); } QmitkMultiLabelInspector::LabelValueVectorType QmitkMultiLabelInspector::GetLabelInstancesOfSelectedFirstLabel() const { if (m_Segmentation.IsNull()) return {}; if (this->GetSelectedLabels().empty()) return {}; const auto index = m_Model->indexOfLabel(this->GetSelectedLabels().front()); return m_Model->GetLabelInstancesOfSameLabelClass(index); } mitk::Label* QmitkMultiLabelInspector::AddNewLabelInstanceInternal(mitk::Label* templateLabel) { if (!m_AllowLabelModification) mitkThrow() << "QmitkMultiLabelInspector is configured incorrectly. Set AllowLabelModification to true to allow the usage of AddNewLabelInstance."; if (nullptr == templateLabel) mitkThrow() << "QmitkMultiLabelInspector is in an invalid state. AddNewLabelInstanceInternal was called with a non existing label as template"; auto groupID = m_Segmentation->GetGroupIndexOfLabel(templateLabel->GetValue()); auto group = m_Segmentation->GetLabelSet(groupID); m_ModelManipulationOngoing = true; auto newLabel = group->AddLabel(templateLabel, true); m_ModelManipulationOngoing = false; this->SetSelectedLabel(newLabel->GetValue()); auto index = m_Model->indexOfLabel(newLabel->GetValue()); if (index.isValid()) { m_Controls->view->expand(index.parent()); } else { mitkThrow() << "Segmentation or QmitkMultiLabelTreeModel is in an invalid state. Label is not present in the model after adding it to the segmentation. Label value: " << newLabel->GetValue(); } emit ModelUpdated(); return newLabel; } mitk::Label* QmitkMultiLabelInspector::AddNewLabelInstance() { auto currentLabel = this->GetFirstSelectedLabelObject(); if (nullptr == currentLabel) return nullptr; return this->AddNewLabelInstanceInternal(currentLabel); } mitk::Label* QmitkMultiLabelInspector::AddNewLabelInternal(const mitk::LabelSetImage::GroupIndexType& containingGroup) { auto newLabel = mitk::LabelSetImageHelper::CreateNewLabel(m_Segmentation); if (!m_DefaultLabelNaming) emit LabelRenameRequested(newLabel, false); auto group = m_Segmentation->GetLabelSet(containingGroup); m_ModelManipulationOngoing = true; group->AddLabel(newLabel, false); m_ModelManipulationOngoing = false; this->SetSelectedLabel(newLabel->GetValue()); auto index = m_Model->indexOfLabel(newLabel->GetValue()); if (!index.isValid()) mitkThrow() << "Segmentation or QmitkMultiLabelTreeModel is in an invalid state. Label is not present in the " "model after adding it to the segmentation. Label value: " << newLabel->GetValue(); m_Controls->view->expand(index.parent()); emit ModelUpdated(); return newLabel; } mitk::Label* QmitkMultiLabelInspector::AddNewLabel() { if (!m_AllowLabelModification) mitkThrow() << "QmitkMultiLabelInspector is configured incorrectly. Set AllowLabelModification to true to allow the usage of AddNewLabel."; if (m_Segmentation.IsNull()) { return nullptr; } auto currentLabel = this->GetFirstSelectedLabelObject(); mitk::LabelSetImage::GroupIndexType groupID = nullptr != currentLabel ? m_Segmentation->GetGroupIndexOfLabel(currentLabel->GetValue()) : 0; return AddNewLabelInternal(groupID); } void QmitkMultiLabelInspector::DeleteLabelInstance() { if (!m_AllowLabelModification) mitkThrow() << "QmitkMultiLabelInspector is configured incorrectly. Set AllowLabelModification to true to allow the usage of DeleteLabelInstance."; if (m_Segmentation.IsNull()) return; auto label = this->GetFirstSelectedLabelObject(); if (nullptr == label) return; auto index = m_Model->indexOfLabel(label->GetValue()); auto instanceName = index.data(Qt::DisplayRole); auto question = "Do you really want to delete label instance \"" + instanceName.toString() + "\"?"; auto answer = QMessageBox::question(this, QString("Delete label instances"), question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answer == QMessageBox::Yes) this->DeleteLabelInternal({ label->GetValue() }); } void QmitkMultiLabelInspector::DeleteLabel() { if (!m_AllowLabelModification) mitkThrow() << "QmitkMultiLabelInspector is configured incorrectly. Set AllowLabelModification to true to allow the usage of DeleteLabel."; if (m_Segmentation.IsNull()) return; const auto label = this->GetFirstSelectedLabelObject(); if (nullptr == label) return; const auto relevantLabels = this->GetLabelInstancesOfSelectedFirstLabel(); if (relevantLabels.empty()) return; auto question = "Do you really want to delete label \"" + QString::fromStdString(label->GetName()); question = relevantLabels.size()==1 ? question + "\"?" : question + "\" with all "+QString::number(relevantLabels.size()) +" instances?"; auto answer = QMessageBox::question(this, QString("Delete label"), question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answer == QMessageBox::Yes) this->DeleteLabelInternal(relevantLabels); } void QmitkMultiLabelInspector::DeleteLabelInternal(const LabelValueVectorType& labelValues) { if (!m_AllowLabelModification) mitkThrow() << "QmitkMultiLabelInspector is configured incorrectly. Set AllowLabelModification to true to allow the usage of DeleteLabelInternal."; if (m_Segmentation.IsNull()) { return; } QVariant nextLabelVariant; this->WaitCursorOn(); m_ModelManipulationOngoing = true; for (auto labelValue : labelValues) { if (labelValue == labelValues.back()) { auto currentIndex = m_Model->indexOfLabel(labelValue); auto nextIndex = m_Model->ClosestLabelInstanceIndex(currentIndex); nextLabelVariant = nextIndex.data(QmitkMultiLabelTreeModel::ItemModelRole::LabelInstanceValueRole); } m_Segmentation->RemoveLabel(labelValue); } m_ModelManipulationOngoing = false; this->WaitCursorOff(); if (nextLabelVariant.isValid()) { auto newLabelValue = nextLabelVariant.value(); this->SetSelectedLabel(newLabelValue); auto index = m_Model->indexOfLabel(newLabelValue); //we have to get index again, because it could have changed due to remove operation. if (index.isValid()) { m_Controls->view->expand(index.parent()); } else { mitkThrow() << "Segmentation or QmitkMultiLabelTreeModel is in an invalid state. Label is not present in the model after adding it to the segmentation. Label value: " << newLabelValue; } } else { this->SetSelectedLabels({}); } emit ModelUpdated(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } mitk::Label* QmitkMultiLabelInspector::AddNewGroup() { if (!m_AllowLabelModification) mitkThrow() << "QmitkMultiLabelInspector is configured incorrectly. Set AllowLabelModification to true to allow the usage of AddNewLabel."; if (m_Segmentation.IsNull()) { return nullptr; } mitk::LabelSetImage::GroupIndexType groupID = 0; mitk::Label* newLabel = nullptr; m_ModelManipulationOngoing = true; try { this->WaitCursorOn(); groupID = m_Segmentation->AddLayer(); this->WaitCursorOff(); newLabel = this->AddNewLabelInternal(groupID); } catch (mitk::Exception& e) { this->WaitCursorOff(); m_ModelManipulationOngoing = false; MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(this, "Add group", "Could not add a new group. See error log for details."); } m_ModelManipulationOngoing = false; emit ModelUpdated(); return newLabel; } void QmitkMultiLabelInspector::RemoveGroupInternal(const mitk::LabelSetImage::GroupIndexType& groupID) { if (!m_AllowLabelModification) mitkThrow() << "QmitkMultiLabelInspector is configured incorrectly. Set AllowLabelModification to true to allow the usage of RemoveLabel."; if (m_Segmentation.IsNull()) return; if (m_Segmentation->GetNumberOfLayers() < 2) return; auto currentIndex = m_Model->indexOfGroup(groupID); auto nextIndex = m_Model->ClosestLabelInstanceIndex(currentIndex); auto labelVariant = nextIndex.data(QmitkMultiLabelTreeModel::ItemModelRole::LabelInstanceValueRole); try { this->WaitCursorOn(); m_ModelManipulationOngoing = true; m_Segmentation->RemoveGroup(groupID); m_ModelManipulationOngoing = false; this->WaitCursorOff(); } catch (mitk::Exception& e) { m_ModelManipulationOngoing = false; this->WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(this, "Delete group", "Could not delete the currently active group. See error log for details."); return; } if (labelVariant.isValid()) { auto newLabelValue = labelVariant.value(); this->SetSelectedLabel(newLabelValue); auto index = m_Model->indexOfLabel(newLabelValue); //we have to get index again, because it could have changed due to remove operation. if (index.isValid()) { m_Controls->view->expand(index.parent()); } else { mitkThrow() << "Segmentation or QmitkMultiLabelTreeModel is in an invalid state. Label is not present in the model after adding it to the segmentation. Label value: " << newLabelValue; } } else { this->SetSelectedLabels({}); } emit ModelUpdated(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkMultiLabelInspector::RemoveGroup() { if (!m_AllowLabelModification) mitkThrow() << "QmitkMultiLabelInspector is configured incorrectly. Set AllowLabelModification to true to allow the usage of RemoveLabel."; if (m_Segmentation.IsNull()) return; if (m_Segmentation->GetNumberOfLayers() < 2) { QMessageBox::information(this, "Delete group", "Cannot delete last remaining group. A segmentation must contain at least a single group."); return; } const auto* selectedLabel = this->GetFirstSelectedLabelObject(); if (selectedLabel == nullptr) return; const auto group = m_Segmentation->GetGroupIndexOfLabel(selectedLabel->GetValue()); auto question = QStringLiteral("Do you really want to delete group %1 including all of its labels?").arg(group); auto answer = QMessageBox::question(this, QStringLiteral("Delete group %1").arg(group), question, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); if (answer != QMessageBox::Yes) return; this->RemoveGroupInternal(group); } void QmitkMultiLabelInspector::OnDeleteGroup() { if (!m_AllowLabelModification) mitkThrow() << "QmitkMultiLabelInspector is configured incorrectly. Set AllowLabelModification to true to allow the usage of RemoveLabel."; if (m_Segmentation.IsNull()) return; auto currentIndex = this->m_Controls->view->currentIndex(); auto groupIDVariant = currentIndex.data(QmitkMultiLabelTreeModel::ItemModelRole::GroupIDRole); if (groupIDVariant.isValid()) { auto groupID = groupIDVariant.value(); auto question = QStringLiteral("Do you really want to delete group %1 including all of its labels?").arg(groupID); auto answer = QMessageBox::question(this, QString("Delete group %1").arg(groupID), question, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); if (answer != QMessageBox::Yes) return; this->RemoveGroupInternal(groupID); } }; void QmitkMultiLabelInspector::OnContextMenuRequested(const QPoint& /*pos*/) { if (m_Segmentation.IsNull() || !this->isEnabled()) return; const auto indexLevel = this->GetCurrentLevelType(); if (IndexLevelType::Group == indexLevel) { QMenu* menu = new QMenu(this); if (m_AllowLabelModification) { QAction* addInstanceAction = new QAction(QmitkStyleManager::ThemeIcon(QStringLiteral(":/Qmitk/icon_label_add.svg")), "&Add label", this); QObject::connect(addInstanceAction, &QAction::triggered, this, &QmitkMultiLabelInspector::OnAddLabel); menu->addAction(addInstanceAction); if (m_Segmentation->GetNumberOfLayers() > 1) { QAction* removeAction = new QAction(QmitkStyleManager::ThemeIcon(QStringLiteral(":/Qmitk/icon_group_delete.svg")), "Delete group", this); QObject::connect(removeAction, &QAction::triggered, this, &QmitkMultiLabelInspector::OnDeleteGroup); menu->addAction(removeAction); } } if (m_AllowLockModification) { menu->addSeparator(); QAction* lockAllAction = new QAction(QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/lock.svg")), "Lock group", this); QObject::connect(lockAllAction, &QAction::triggered, this, &QmitkMultiLabelInspector::OnLockAffectedLabels); menu->addAction(lockAllAction); QAction* unlockAllAction = new QAction(QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/unlock.svg")), "Unlock group", this); QObject::connect(unlockAllAction, &QAction::triggered, this, &QmitkMultiLabelInspector::OnUnlockAffectedLabels); menu->addAction(unlockAllAction); } if (m_AllowVisibilityModification) { menu->addSeparator(); QAction* viewAllAction = new QAction(QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/visible.svg")), "Show group", this); QObject::connect(viewAllAction, &QAction::triggered, this, &QmitkMultiLabelInspector::OnSetAffectedLabelsVisible); menu->addAction(viewAllAction); QAction* hideAllAction = new QAction(QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/invisible.svg")), "Hide group", this); QObject::connect(hideAllAction, &QAction::triggered, this, &QmitkMultiLabelInspector::OnSetAffectedLabelsInvisible); menu->addAction(hideAllAction); menu->addSeparator(); auto opacityAction = this->CreateOpacityAction(); if (nullptr != opacityAction) menu->addAction(opacityAction); } menu->popup(QCursor::pos()); } else if (IndexLevelType::LabelClass == indexLevel) { QMenu* menu = new QMenu(this); if (m_AllowLabelModification) { QAction* addInstanceAction = new QAction(QmitkStyleManager::ThemeIcon(QStringLiteral(":/Qmitk/icon_label_add_instance.svg")), "Add label instance", this); QObject::connect(addInstanceAction, &QAction::triggered, this, &QmitkMultiLabelInspector::OnAddLabelInstance); menu->addAction(addInstanceAction); QAction* renameAction = new QAction(QIcon(":/Qmitk/RenameLabel.png"), "&Rename label", this); QObject::connect(renameAction, SIGNAL(triggered(bool)), this, SLOT(OnRenameLabel(bool))); menu->addAction(renameAction); QAction* removeAction = new QAction(QmitkStyleManager::ThemeIcon(QStringLiteral(":/Qmitk/icon_label_delete.svg")), "&Delete label", this); QObject::connect(removeAction, &QAction::triggered, this, &QmitkMultiLabelInspector::OnDeleteAffectedLabel); menu->addAction(removeAction); } if (m_AllowLockModification) { menu->addSeparator(); QAction* lockAllAction = new QAction(QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/lock.svg")), "Lock label instances", this); QObject::connect(lockAllAction, &QAction::triggered, this, &QmitkMultiLabelInspector::OnLockAffectedLabels); menu->addAction(lockAllAction); QAction* unlockAllAction = new QAction(QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/unlock.svg")), "Unlock label instances", this); QObject::connect(unlockAllAction, &QAction::triggered, this, &QmitkMultiLabelInspector::OnUnlockAffectedLabels); menu->addAction(unlockAllAction); } if (m_AllowVisibilityModification) { menu->addSeparator(); QAction* viewAllAction = new QAction(QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/visible.svg")), "Show label instances", this); QObject::connect(viewAllAction, &QAction::triggered, this, &QmitkMultiLabelInspector::OnSetAffectedLabelsVisible); menu->addAction(viewAllAction); QAction* hideAllAction = new QAction(QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/invisible.svg")), "Hide label instances", this); QObject::connect(hideAllAction, &QAction::triggered, this, &QmitkMultiLabelInspector::OnSetAffectedLabelsInvisible); menu->addAction(hideAllAction); menu->addSeparator(); auto opacityAction = this->CreateOpacityAction(); if (nullptr!=opacityAction) menu->addAction(opacityAction); } menu->popup(QCursor::pos()); } else { auto selectedLabelValues = this->GetSelectedLabels(); if (selectedLabelValues.empty()) return; QMenu* menu = new QMenu(this); if (this->GetMultiSelectionMode() && selectedLabelValues.size() > 1) { QAction* mergeAction = new QAction(QIcon(":/Qmitk/MergeLabels.png"), "Merge selection on current label", this); QObject::connect(mergeAction, SIGNAL(triggered(bool)), this, SLOT(OnMergeLabels(bool))); menu->addAction(mergeAction); QAction* removeLabelsAction = new QAction(QmitkStyleManager::ThemeIcon(QStringLiteral(":/Qmitk/icon_label_delete_instance.svg")), "&Delete selected labels", this); QObject::connect(removeLabelsAction, SIGNAL(triggered(bool)), this, SLOT(OnDeleteLabels(bool))); menu->addAction(removeLabelsAction); QAction* clearLabelsAction = new QAction(QIcon(":/Qmitk/EraseLabel.png"), "&Clear selected labels", this); QObject::connect(clearLabelsAction, SIGNAL(triggered(bool)), this, SLOT(OnClearLabels(bool))); menu->addAction(clearLabelsAction); } else { if (m_AllowLabelModification) { QAction* addInstanceAction = new QAction(QmitkStyleManager::ThemeIcon(QStringLiteral(":/Qmitk/icon_label_add_instance.svg")), "&Add label instance", this); QObject::connect(addInstanceAction, &QAction::triggered, this, &QmitkMultiLabelInspector::OnAddLabelInstance); menu->addAction(addInstanceAction); const auto selectedLabelIndex = m_Model->indexOfLabel(selectedLabelValues.front()); if (m_Model->GetLabelInstancesOfSameLabelClass(selectedLabelIndex).size() > 1) // Only labels that actually appear as instance (having additional instances) { QAction* renameAction = new QAction(QIcon(":/Qmitk/RenameLabel.png"), "&Rename label instance", this); QObject::connect(renameAction, SIGNAL(triggered(bool)), this, SLOT(OnRenameLabel(bool))); menu->addAction(renameAction); QAction* removeInstanceAction = new QAction(QmitkStyleManager::ThemeIcon(QStringLiteral(":/Qmitk/icon_label_delete_instance.svg")), "&Delete label instance", this); QObject::connect(removeInstanceAction, &QAction::triggered, this, &QmitkMultiLabelInspector::DeleteLabelInstance); menu->addAction(removeInstanceAction); } else { QAction* renameAction = new QAction(QIcon(":/Qmitk/RenameLabel.png"), "&Rename label", this); QObject::connect(renameAction, SIGNAL(triggered(bool)), this, SLOT(OnRenameLabel(bool))); menu->addAction(renameAction); } QAction* removeLabelAction = new QAction(QmitkStyleManager::ThemeIcon(QStringLiteral(":/Qmitk/icon_label_delete.svg")), "Delete &label", this); QObject::connect(removeLabelAction, &QAction::triggered, this, &QmitkMultiLabelInspector::DeleteLabel); menu->addAction(removeLabelAction); QAction* clearAction = new QAction(QIcon(":/Qmitk/EraseLabel.png"), "&Clear content", this); QObject::connect(clearAction, SIGNAL(triggered(bool)), this, SLOT(OnClearLabel(bool))); menu->addAction(clearAction); } if (m_AllowVisibilityModification) { menu->addSeparator(); QAction* viewOnlyAction = new QAction(QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/visible.svg")), "Hide everything in group but this", this); QObject::connect(viewOnlyAction, SIGNAL(triggered(bool)), this, SLOT(OnSetOnlyActiveLabelVisible(bool))); menu->addAction(viewOnlyAction); menu->addSeparator(); auto opacityAction = this->CreateOpacityAction(); if (nullptr != opacityAction) menu->addAction(opacityAction); } } menu->popup(QCursor::pos()); } } QWidgetAction* QmitkMultiLabelInspector::CreateOpacityAction() { auto relevantLabelValues = this->GetCurrentlyAffactedLabelInstances(); std::vector relevantLabels; if (!relevantLabelValues.empty()) { //we assume here that all affacted label belong to one group. auto groupID = m_Segmentation->GetGroupIndexOfLabel(relevantLabelValues.front()); auto group = m_Segmentation->GetLabelSet(groupID); for (auto value : relevantLabelValues) { auto label = this->m_Segmentation->GetLabel(value); if (nullptr == label) mitkThrow() << "Invalid state. Internal model returned a label value that does not exist in segmentation. Invalid value:" << value; relevantLabels.emplace_back(label); } auto* opacitySlider = new QSlider; opacitySlider->setMinimum(0); opacitySlider->setMaximum(100); opacitySlider->setOrientation(Qt::Horizontal); auto opacity = relevantLabels.front()->GetOpacity(); opacitySlider->setValue(static_cast(opacity * 100)); auto segmentation = m_Segmentation; QObject::connect(opacitySlider, &QSlider::valueChanged, this, [segmentation, relevantLabels, group](const int value) { auto opacity = static_cast(value) / 100.0f; for (auto label : relevantLabels) { label->SetOpacity(opacity); group->UpdateLookupTable(label->GetValue()); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } ); QLabel* opacityLabel = new QLabel("Opacity: "); QVBoxLayout* opacityWidgetLayout = new QVBoxLayout; opacityWidgetLayout->setContentsMargins(4, 4, 4, 4); opacityWidgetLayout->addWidget(opacityLabel); opacityWidgetLayout->addWidget(opacitySlider); QWidget* opacityWidget = new QWidget; opacityWidget->setLayout(opacityWidgetLayout); QWidgetAction* opacityAction = new QWidgetAction(this); opacityAction->setDefaultWidget(opacityWidget); return opacityAction; } return nullptr; } void QmitkMultiLabelInspector::OnClearLabels(bool /*value*/) { QString question = "Do you really want to clear the selected labels?"; QMessageBox::StandardButton answerButton = QMessageBox::question( this, "Clear selected labels", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton == QMessageBox::Yes) { this->WaitCursorOn(); m_Segmentation->EraseLabels(this->GetSelectedLabels()); this->WaitCursorOff(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkMultiLabelInspector::OnDeleteAffectedLabel() { if (!m_AllowLabelModification) mitkThrow() << "QmitkMultiLabelInspector is configured incorrectly. Set AllowLabelModification to true to allow the usage of RemoveLabel."; if (m_Segmentation.IsNull()) { return; } auto affectedLabels = GetCurrentlyAffactedLabelInstances(); auto currentLabel = m_Segmentation->GetLabel(affectedLabels.front()); QString question = "Do you really want to delete all instances of label \"" + QString::fromStdString(currentLabel->GetName()) + "\"?"; QMessageBox::StandardButton answerButton = QMessageBox::question(this, "Delete label", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton == QMessageBox::Yes) { this->DeleteLabelInternal(affectedLabels); } } void QmitkMultiLabelInspector::OnDeleteLabels(bool /*value*/) { QString question = "Do you really want to remove the selected labels?"; QMessageBox::StandardButton answerButton = QMessageBox::question( this, "Remove selected labels", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton == QMessageBox::Yes) { this->WaitCursorOn(); m_Segmentation->RemoveLabels(this->GetSelectedLabels()); this->WaitCursorOff(); } } void QmitkMultiLabelInspector::OnMergeLabels(bool /*value*/) { auto currentLabel = GetCurrentLabel(); QString question = "Do you really want to merge selected labels into \"" + QString::fromStdString(currentLabel->GetName())+"\"?"; QMessageBox::StandardButton answerButton = QMessageBox::question( this, "Merge selected label", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton == QMessageBox::Yes) { this->WaitCursorOn(); m_Segmentation->MergeLabels(currentLabel->GetValue(), this->GetSelectedLabels(), m_Segmentation->GetActiveLayer()); this->WaitCursorOff(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkMultiLabelInspector::OnAddLabel() { auto currentIndex = this->m_Controls->view->currentIndex(); auto groupIDVariant = currentIndex.data(QmitkMultiLabelTreeModel::ItemModelRole::GroupIDRole); if (groupIDVariant.isValid()) { auto groupID = groupIDVariant.value(); this->AddNewLabelInternal(groupID); } } void QmitkMultiLabelInspector::OnAddLabelInstance() { auto currentLabel = this->GetCurrentLabel(); if (nullptr == currentLabel) return; this->AddNewLabelInstanceInternal(currentLabel); } void QmitkMultiLabelInspector::OnClearLabel(bool /*value*/) { auto currentLabel = GetFirstSelectedLabelObject(); QString question = "Do you really want to clear the contents of label \"" + QString::fromStdString(currentLabel->GetName())+"\"?"; QMessageBox::StandardButton answerButton = QMessageBox::question(this, "Clear label", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton == QMessageBox::Yes) { this->WaitCursorOn(); m_Segmentation->EraseLabel(currentLabel->GetValue()); this->WaitCursorOff(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkMultiLabelInspector::OnRenameLabel(bool /*value*/) { auto relevantLabelValues = this->GetCurrentlyAffactedLabelInstances(); auto currentLabel = this->GetCurrentLabel(); emit LabelRenameRequested(currentLabel, true); //we assume here that all affacted label belong to one group. auto groupID = m_Segmentation->GetGroupIndexOfLabel(currentLabel->GetValue()); auto group = m_Segmentation->GetLabelSet(groupID); for (auto value : relevantLabelValues) { if (value != currentLabel->GetValue()) { auto label = this->m_Segmentation->GetLabel(value); if (nullptr == label) mitkThrow() << "Invalid state. Internal model returned a label value that does not exist in segmentation. Invalid value:" << value; label->SetName(currentLabel->GetName()); label->SetColor(currentLabel->GetColor()); group->UpdateLookupTable(label->GetValue()); mitk::DICOMSegmentationPropertyHelper::SetDICOMSegmentProperties(label); } } emit ModelUpdated(); } void QmitkMultiLabelInspector::SetLockOfAffectedLabels(bool locked) const { auto relevantLabelValues = this->GetCurrentlyAffactedLabelInstances(); if (!relevantLabelValues.empty()) { for (auto value : relevantLabelValues) { auto label = this->m_Segmentation->GetLabel(value); if (nullptr == label) mitkThrow() << "Invalid state. Internal model returned a label value that does not exist in segmentation. Invalid value:" << value; label->SetLocked(locked); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkMultiLabelInspector::OnUnlockAffectedLabels() { this->SetLockOfAffectedLabels(false); } void QmitkMultiLabelInspector::OnLockAffectedLabels() { this->SetLockOfAffectedLabels(true); } void QmitkMultiLabelInspector::SetVisibilityOfAffectedLabels(bool visible) const { auto relevantLabelValues = this->GetCurrentlyAffactedLabelInstances(); if (!relevantLabelValues.empty()) { //we assume here that all affacted label belong to one group. auto groupID = m_Segmentation->GetGroupIndexOfLabel(relevantLabelValues.front()); auto group = m_Segmentation->GetLabelSet(groupID); for (auto value : relevantLabelValues) { auto label = this->m_Segmentation->GetLabel(value); if (nullptr == label) mitkThrow() << "Invalid state. Internal model returned a label value that does not exist in segmentation. Invalid value:" << value; label->SetVisible(visible); group->UpdateLookupTable(label->GetValue()); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkMultiLabelInspector::OnSetAffectedLabelsVisible() { this->SetVisibilityOfAffectedLabels(true); } void QmitkMultiLabelInspector::OnSetAffectedLabelsInvisible() { this->SetVisibilityOfAffectedLabels(false); } void QmitkMultiLabelInspector::OnSetOnlyActiveLabelVisible(bool /*value*/) { auto currentLabel = GetFirstSelectedLabelObject(); const auto labelID = currentLabel->GetValue(); auto groupID = m_Segmentation->GetGroupIndexOfLabel(currentLabel->GetValue()); auto group = m_Segmentation->GetLabelSet(groupID); group->SetAllLabelsVisible(false); currentLabel->SetVisible(true); group->UpdateLookupTable(labelID); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); this->PrepareGoToLabel(labelID); } void QmitkMultiLabelInspector::OnItemDoubleClicked(const QModelIndex& index) { if (!index.isValid()) return; if (index.column() > 0) return; auto labelVariant = index.data(QmitkMultiLabelTreeModel::ItemModelRole::LabelInstanceValueRole); if (!labelVariant.isValid()) return; const auto labelID = labelVariant.value(); if (QApplication::queryKeyboardModifiers().testFlag(Qt::AltModifier)) { this->OnRenameLabel(false); return; } this->PrepareGoToLabel(labelID); } void QmitkMultiLabelInspector::PrepareGoToLabel(mitk::Label::PixelType labelID) const { this->WaitCursorOn(); m_Segmentation->UpdateCenterOfMass(labelID); const auto currentLabel = m_Segmentation->GetLabel(labelID); const mitk::Point3D& pos = currentLabel->GetCenterOfMassCoordinates(); this->WaitCursorOff(); if (pos.GetVnlVector().max_value() > 0.0) { emit GoToLabel(currentLabel->GetValue(), pos); } } diff --git a/Modules/SegmentationUI/Qmitk/QmitkToolSelectionBox.cpp b/Modules/SegmentationUI/Qmitk/QmitkToolSelectionBox.cpp index 537099f301..8676ab7211 100755 --- a/Modules/SegmentationUI/Qmitk/QmitkToolSelectionBox.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitkToolSelectionBox.cpp @@ -1,623 +1,623 @@ /*============================================================================ 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. ============================================================================*/ //#define MBILOG_ENABLE_DEBUG 1 #include #include "QmitkToolSelectionBox.h" #include "QmitkToolGUI.h" #include "mitkBaseRenderer.h" #include #include #include #include #include #include #include #include #include "usModuleResource.h" #include "usModuleResourceStream.h" #include "mitkToolManagerProvider.h" QmitkToolSelectionBox::QmitkToolSelectionBox(QWidget *parent, mitk::DataStorage *) : QWidget(parent), m_SelfCall(false), m_DisplayedGroups("default"), m_LayoutColumns(2), m_ShowNames(true), m_GenerateAccelerators(false), m_ToolGUIWidget(nullptr), m_LastToolGUI(nullptr), m_ToolButtonGroup(nullptr), m_ButtonLayout(nullptr) { QFont currentFont = QWidget::font(); currentFont.setBold(true); QWidget::setFont(currentFont); m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); // QButtonGroup m_ToolButtonGroup = new QButtonGroup(this); // some features of QButtonGroup m_ToolButtonGroup->setExclusive(false); // mutually exclusive toggle buttons RecreateButtons(); QWidget::setContentsMargins(0, 0, 0, 0); if (layout() != nullptr) { layout()->setContentsMargins(0, 0, 0, 0); } // reactions to signals connect(m_ToolButtonGroup, &QButtonGroup::idClicked, this, &QmitkToolSelectionBox::toolButtonClicked); // reactions to ToolManager events m_ToolManager->ActiveToolChanged += mitk::MessageDelegate(this, &QmitkToolSelectionBox::OnToolManagerToolModified); m_ToolManager->ReferenceDataChanged += mitk::MessageDelegate(this, &QmitkToolSelectionBox::OnToolManagerReferenceDataModified); m_ToolManager->WorkingDataChanged += mitk::MessageDelegate(this, &QmitkToolSelectionBox::OnToolManagerWorkingDataModified); // show active tool SetOrUnsetButtonForActiveTool(); QWidget::setEnabled(false); } QmitkToolSelectionBox::~QmitkToolSelectionBox() { m_ToolManager->ActiveToolChanged -= mitk::MessageDelegate(this, &QmitkToolSelectionBox::OnToolManagerToolModified); m_ToolManager->ReferenceDataChanged -= mitk::MessageDelegate(this, &QmitkToolSelectionBox::OnToolManagerReferenceDataModified); m_ToolManager->WorkingDataChanged -= mitk::MessageDelegate(this, &QmitkToolSelectionBox::OnToolManagerWorkingDataModified); } mitk::ToolManager *QmitkToolSelectionBox::GetToolManager() { return m_ToolManager; } void QmitkToolSelectionBox::SetToolManager( mitk::ToolManager &newManager) // no nullptr pointer allowed here, a manager is required { // say bye to the old manager m_ToolManager->ActiveToolChanged -= mitk::MessageDelegate(this, &QmitkToolSelectionBox::OnToolManagerToolModified); m_ToolManager->ReferenceDataChanged -= mitk::MessageDelegate(this, &QmitkToolSelectionBox::OnToolManagerReferenceDataModified); m_ToolManager->WorkingDataChanged -= mitk::MessageDelegate(this, &QmitkToolSelectionBox::OnToolManagerWorkingDataModified); if (QWidget::isEnabled()) { m_ToolManager->UnregisterClient(); } m_ToolManager = &newManager; RecreateButtons(); // greet the new one m_ToolManager->ActiveToolChanged += mitk::MessageDelegate(this, &QmitkToolSelectionBox::OnToolManagerToolModified); m_ToolManager->ReferenceDataChanged += mitk::MessageDelegate(this, &QmitkToolSelectionBox::OnToolManagerReferenceDataModified); m_ToolManager->WorkingDataChanged += mitk::MessageDelegate(this, &QmitkToolSelectionBox::OnToolManagerWorkingDataModified); if (QWidget::isEnabled()) { m_ToolManager->RegisterClient(); } // ask the new one what the situation is like SetOrUnsetButtonForActiveTool(); } void QmitkToolSelectionBox::toolButtonClicked(int id) { if (!QWidget::isEnabled()) return; // this method could be triggered from the constructor, when we are still disabled MITK_DEBUG << "toolButtonClicked(" << id << "): id translates to tool ID " << m_ToolIDForButtonID[id]; QToolButton *toolButton = dynamic_cast(m_ToolButtonGroup->buttons().at(id)); if (toolButton) { if ((m_ButtonIDForToolID.find(m_ToolManager->GetActiveToolID()) != m_ButtonIDForToolID.end()) // if we have this tool in our box && (m_ButtonIDForToolID[m_ToolManager->GetActiveToolID()] == id)) // the tool corresponding to this button is already active { // disable this button, disable all tools toolButton->setChecked(false); m_ToolManager->ActivateTool(-1); // disable everything } else { // enable the corresponding tool m_SelfCall = true; m_ToolManager->ActivateTool(m_ToolIDForButtonID[id]); m_SelfCall = false; } } } void QmitkToolSelectionBox::OnToolManagerToolModified() { SetOrUnsetButtonForActiveTool(); } void QmitkToolSelectionBox::SetOrUnsetButtonForActiveTool() { // we want to emit a signal in any case, whether we selected ourselves or somebody else changes "our" tool manager. // --> emit before check on m_SelfCall int id = m_ToolManager->GetActiveToolID(); // don't emit signal for shape model tools bool emitSignal = true; mitk::Tool *tool = m_ToolManager->GetActiveTool(); if (tool && std::string(tool->GetGroup()) == "organ_segmentation") emitSignal = false; if (emitSignal) emit ToolSelected(id); // delete old GUI (if any) if (m_LastToolGUI && m_ToolGUIWidget) { if (m_ToolGUIWidget->layout()) { m_ToolGUIWidget->layout()->removeWidget(m_LastToolGUI); } m_LastToolGUI->setParent(nullptr); delete m_LastToolGUI; // will hopefully notify parent and layouts m_LastToolGUI = nullptr; QLayout *layout = m_ToolGUIWidget->layout(); if (layout) { layout->activate(); } } QToolButton *toolButton(nullptr); if (m_ButtonIDForToolID.find(id) != m_ButtonIDForToolID.end()) // if this tool is in our box { toolButton = dynamic_cast(m_ToolButtonGroup->buttons().at(m_ButtonIDForToolID[id])); } if (toolButton) { // mmueller // uncheck all other buttons QAbstractButton *tmpBtn = nullptr; for (int i = 0; i < m_ToolButtonGroup->buttons().size(); ++i) { tmpBtn = m_ToolButtonGroup->buttons().at(i); if (tmpBtn != toolButton) dynamic_cast(tmpBtn)->setChecked(false); } toolButton->setChecked(true); if (m_ToolGUIWidget && tool) { // create and reparent new GUI (if any) itk::Object::Pointer possibleGUI = tool->GetGUI("Qmitk", "GUI").GetPointer(); // prefix and postfix if (possibleGUI.IsNull()) possibleGUI = tool->GetGUI("", "GUI").GetPointer(); QmitkToolGUI *gui = dynamic_cast(possibleGUI.GetPointer()); //! m_LastToolGUI = gui; if (gui) { gui->SetTool(tool); gui->setParent(m_ToolGUIWidget); gui->move(gui->geometry().topLeft()); gui->show(); QLayout *layout = m_ToolGUIWidget->layout(); if (!layout) { layout = new QVBoxLayout(m_ToolGUIWidget); } if (layout) { layout->addWidget(gui); layout->activate(); } } } } else { // disable all buttons QToolButton *selectedToolButton = dynamic_cast(m_ToolButtonGroup->checkedButton()); if (selectedToolButton) { selectedToolButton->setChecked(false); } } } void QmitkToolSelectionBox::OnToolManagerReferenceDataModified() { if (m_SelfCall) return; MITK_DEBUG << "OnToolManagerReferenceDataModified()"; this->UpdateButtonsEnabledState(); } void QmitkToolSelectionBox::OnToolManagerWorkingDataModified() { if (m_SelfCall) return; MITK_DEBUG << "OnToolManagerWorkingDataModified()"; this->UpdateButtonsEnabledState(); } void QmitkToolSelectionBox::setEnabled(bool enable) { if (QWidget::isEnabled() == enable) return; QWidget::setEnabled(enable); if (enable) { m_ToolManager->RegisterClient(); auto id = m_ToolManager->GetActiveToolID(); emit ToolSelected(id); } else { m_ToolManager->ActivateTool(-1); m_ToolManager->UnregisterClient(); emit ToolSelected(-1); } } void QmitkToolSelectionBox::UpdateButtonsEnabledState() { auto buttons = m_ToolButtonGroup->buttons(); const auto refDataNode = m_ToolManager->GetReferenceData(0); const mitk::BaseData* refData = nullptr; if (nullptr != refDataNode) { refData = refDataNode->GetData(); } const auto workingDataNode = m_ToolManager->GetWorkingData(0); const mitk::BaseData* workingData = nullptr; if (nullptr != workingDataNode) { workingData = workingDataNode->GetData(); } - for (const auto& button : qAsConst(buttons)) + for (const auto& button : std::as_const(buttons)) { const auto buttonID = m_ToolButtonGroup->id(button); const auto toolID = m_ToolIDForButtonID[buttonID]; const auto tool = m_ToolManager->GetToolById(toolID); button->setEnabled(tool->CanHandle(refData, workingData)); } } void QmitkToolSelectionBox::RecreateButtons() { if (m_ToolManager.IsNull()) return; QList l = m_ToolButtonGroup->buttons(); // remove all buttons that are there QList::iterator it; QAbstractButton *btn; for (it = l.begin(); it != l.end(); ++it) { btn = *it; m_ToolButtonGroup->removeButton(btn); delete btn; } mitk::ToolManager::ToolVectorTypeConst allPossibleTools = m_ToolManager->GetTools(); mitk::ToolManager::ToolVectorTypeConst allTools; typedef std::pair SortPairType; typedef std::priority_queue SortedToolQueueType; SortedToolQueueType toolPositions; // clear and sort all tools // step one: find name/group of all tools in m_DisplayedGroups string. remember these positions for all tools. for (mitk::ToolManager::ToolVectorTypeConst::const_iterator iter = allPossibleTools.begin(); iter != allPossibleTools.end(); ++iter) { const mitk::Tool *tool = *iter; std::string::size_type namePos = m_DisplayedGroups.find(std::string("'") + tool->GetName() + "'"); std::string::size_type groupPos = m_DisplayedGroups.find(std::string("'") + tool->GetGroup() + "'"); if (!m_DisplayedGroups.empty() && namePos == std::string::npos && groupPos == std::string::npos) continue; // skip if (m_DisplayedGroups.empty() && std::string(tool->GetName()).length() > 0) { namePos = static_cast(tool->GetName()[0]); } SortPairType thisPair = std::make_pair(namePos < groupPos ? namePos : groupPos, *iter); toolPositions.push(thisPair); } // step two: sort tools according to previously found positions in m_DisplayedGroups MITK_DEBUG << "Sorting order of tools (lower number --> earlier in button group)"; while (!toolPositions.empty()) { SortPairType thisPair = toolPositions.top(); MITK_DEBUG << "Position " << thisPair.first << " : " << thisPair.second->GetName(); allTools.push_back(thisPair.second); toolPositions.pop(); } std::reverse(allTools.begin(), allTools.end()); MITK_DEBUG << "Sorted tools:"; for (mitk::ToolManager::ToolVectorTypeConst::const_iterator iter = allTools.begin(); iter != allTools.end(); ++iter) { MITK_DEBUG << (*iter)->GetName(); } if (m_ButtonLayout == nullptr) m_ButtonLayout = new QGridLayout; int row(0); int column(-1); int currentButtonID(0); m_ButtonIDForToolID.clear(); m_ToolIDForButtonID.clear(); QToolButton *button = nullptr; MITK_DEBUG << "Creating buttons for tools"; // fill group box with buttons for (mitk::ToolManager::ToolVectorTypeConst::const_iterator iter = allTools.begin(); iter != allTools.end(); ++iter) { const mitk::Tool *tool = *iter; int currentToolID(m_ToolManager->GetToolID(tool)); ++column; // new line if we are at the maximum columns if (column == m_LayoutColumns) { ++row; column = 0; } button = new QToolButton; button->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum)); // add new button to the group MITK_DEBUG << "Adding button with ID " << currentToolID; m_ToolButtonGroup->addButton(button, currentButtonID); // ... and to the layout MITK_DEBUG << "Adding button in row/column " << row << "/" << column; m_ButtonLayout->addWidget(button, row, column); if (m_LayoutColumns == 1) { button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); } else { button->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); } button->setCheckable(true); if (currentToolID == m_ToolManager->GetActiveToolID()) button->setChecked(true); QString label; if (m_GenerateAccelerators) { label += "&"; } label += tool->GetName(); QString tooltip = tool->GetName(); MITK_DEBUG << tool->GetName() << ", " << label.toLocal8Bit().constData() << ", '" << tooltip.toLocal8Bit().constData(); if (m_ShowNames) { button->setText(label); // a label button->setToolTip(tooltip); QFont currentFont = button->font(); currentFont.setBold(false); button->setFont(currentFont); } us::ModuleResource iconResource = tool->GetIconResource(); if (!iconResource.IsValid()) { button->setIcon(QIcon(QPixmap(tool->GetXPM()))); } else { auto isSVG = "svg" == iconResource.GetSuffix(); auto openmode = isSVG ? std::ios_base::in : std::ios_base::binary; us::ModuleResourceStream resourceStream(iconResource, openmode); resourceStream.seekg(0, std::ios::end); std::ios::pos_type length = resourceStream.tellg(); resourceStream.seekg(0, std::ios::beg); char *data = new char[length]; resourceStream.read(data, length); if (isSVG) { button->setIcon(QmitkStyleManager::ThemeIcon(QByteArray::fromRawData(data, length))); } else { QPixmap pixmap; pixmap.loadFromData(QByteArray::fromRawData(data, length)); button->setIcon(QIcon(pixmap)); } delete[] data; if (m_ShowNames) { if (m_LayoutColumns == 1) button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); else button->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); button->setIconSize(QSize(24, 24)); } else { button->setToolButtonStyle(Qt::ToolButtonIconOnly); button->setIconSize(QSize(32, 32)); button->setToolTip(tooltip); } } if (m_GenerateAccelerators) { QString firstLetter = QString(tool->GetName()); firstLetter.truncate(1); button->setShortcut( firstLetter); // a keyboard shortcut (just the first letter of the given name w/o any CTRL or something) } m_ButtonIDForToolID[currentToolID] = currentButtonID; m_ToolIDForButtonID[currentButtonID] = currentToolID; MITK_DEBUG << "m_ButtonIDForToolID[" << currentToolID << "] == " << currentButtonID; MITK_DEBUG << "m_ToolIDForButtonID[" << currentButtonID << "] == " << currentToolID; tool->GUIProcessEventsMessage += mitk::MessageDelegate( this, &QmitkToolSelectionBox::OnToolGUIProcessEventsMessage); // will never add a listener twice, so we don't have // to check here tool->ErrorMessage += mitk::MessageDelegate1( this, &QmitkToolSelectionBox::OnToolErrorMessage); // will never add a listener twice, so we don't have to check here tool->GeneralMessage += mitk::MessageDelegate1(this, &QmitkToolSelectionBox::OnGeneralToolMessage); ++currentButtonID; } // setting grid layout for this groupbox this->setLayout(m_ButtonLayout); this->UpdateButtonsEnabledState(); // this->update(); } void QmitkToolSelectionBox::OnToolGUIProcessEventsMessage() { qApp->processEvents(); } void QmitkToolSelectionBox::OnToolErrorMessage(std::string s) { QMessageBox::critical( this, "MITK", QString(s.c_str()), QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); } void QmitkToolSelectionBox::OnGeneralToolMessage(std::string s) { QMessageBox::information( this, "MITK", QString(s.c_str()), QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); } void QmitkToolSelectionBox::SetDisplayedToolGroups(const std::string &toolGroups) { if (m_DisplayedGroups != toolGroups) { QString q_DisplayedGroups = toolGroups.c_str(); // quote all unquoted single words q_DisplayedGroups = q_DisplayedGroups.replace(QRegularExpression("\\b(\\w+)\\b|'([^']+)'"), "'\\1\\2'"); MITK_DEBUG << "m_DisplayedGroups was \"" << toolGroups << "\""; m_DisplayedGroups = q_DisplayedGroups.toLocal8Bit().constData(); MITK_DEBUG << "m_DisplayedGroups is \"" << m_DisplayedGroups << "\""; RecreateButtons(); SetOrUnsetButtonForActiveTool(); } } void QmitkToolSelectionBox::SetLayoutColumns(int columns) { if (columns > 0 && columns != m_LayoutColumns) { m_LayoutColumns = columns; RecreateButtons(); } } void QmitkToolSelectionBox::SetShowNames(bool show) { if (show != m_ShowNames) { m_ShowNames = show; RecreateButtons(); } } void QmitkToolSelectionBox::SetGenerateAccelerators(bool accel) { if (accel != m_GenerateAccelerators) { m_GenerateAccelerators = accel; RecreateButtons(); } } void QmitkToolSelectionBox::SetToolGUIArea(QWidget *parentWidget) { m_ToolGUIWidget = parentWidget; } diff --git a/Modules/SemanticRelationsUI/src/QmitkLesionTreeModel.cpp b/Modules/SemanticRelationsUI/src/QmitkLesionTreeModel.cpp index b554ebd685..eceb1003be 100644 --- a/Modules/SemanticRelationsUI/src/QmitkLesionTreeModel.cpp +++ b/Modules/SemanticRelationsUI/src/QmitkLesionTreeModel.cpp @@ -1,298 +1,298 @@ /*============================================================================ 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. ============================================================================*/ // semantic relations UI module #include "QmitkLesionTreeModel.h" // semantic relations module #include #include #include #include #include #include // qt #include QmitkLesionTreeModel::QmitkLesionTreeModel(QObject* parent/* = nullptr*/) : QmitkAbstractSemanticRelationsStorageModel(parent) , m_LastSegmentation(nullptr) , m_RootItem(std::make_shared(mitk::LesionData())) { // nothing here } ////////////////////////////////////////////////////////////////////////// // overridden virtual functions from QAbstractItemModel ////////////////////////////////////////////////////////////////////////// QModelIndex QmitkLesionTreeModel::index(int row, int column, const QModelIndex& itemIndex) const { if (!hasIndex(row, column, itemIndex)) { return QModelIndex(); } auto childItem = GetItemByIndex(itemIndex)->GetChildInRow(row); if (nullptr == childItem) { return QModelIndex(); } return createIndex(row, column, childItem.get()); } QModelIndex QmitkLesionTreeModel::parent(const QModelIndex& itemIndex) const { if (!itemIndex.isValid()) { return QModelIndex(); } auto parentItem = GetItemByIndex(itemIndex)->GetParent(); if (parentItem.expired()) { return QModelIndex(); } auto sharedParent = parentItem.lock(); if (sharedParent == m_RootItem) { return QModelIndex(); } return createIndex(sharedParent->GetRow(), 0, sharedParent.get()); } int QmitkLesionTreeModel::rowCount(const QModelIndex& itemIndex/* = QModelIndex()*/) const { return GetItemByIndex(itemIndex)->ChildCount(); } int QmitkLesionTreeModel::columnCount(const QModelIndex&/* itemIndex = QModelIndex() */) const { if (0 == m_RootItem->ChildCount()) { // no lesion items stored, no need to display columns return 0; } return m_ControlPoints.size() + 1; } QVariant QmitkLesionTreeModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) { return QVariant(); } if (index.column() < 0 || index.column() > static_cast(m_ControlPoints.size())) { return QVariant(); } QmitkLesionTreeItem* currentItem = GetItemByIndex(index); if (Qt::DisplayRole == role) { if (currentItem->GetParent().expired()) { return QVariant(); } auto parentItem = currentItem->GetParent().lock(); // parent exists and is the root item -> 1. item of a lesion entry if (m_RootItem == parentItem) { // display role fills the first columns with the lesion UID / name if (0 == index.column()) { std::string itemString = currentItem->GetData().GetLesionName(); if (itemString.empty()) { itemString = currentItem->GetData().GetLesionUID(); } return QString::fromStdString(itemString); } else { // display role fills other columns with the lesion presence info const auto lesionPresence = currentItem->GetData().GetLesionPresence(); if (index.column() - 1 > static_cast(lesionPresence.size())) { return "N/A"; } if (lesionPresence.at(index.column() - 1)) { return QString::fromStdString("present"); } return QString::fromStdString("not present"); } } } if (Qt::BackgroundRole == role) { auto it = m_DataNodePresence.find(currentItem->GetData().GetLesion().UID); if (it != m_DataNodePresence.end()) { return it->second ? QVariant(QColor(Qt::darkGreen)) : QVariant(QColor(Qt::transparent)); } return QVariant(QColor(Qt::transparent)); } if (Qt::UserRole == role) { return QVariant::fromValue(currentItem); } return QVariant(); } QVariant QmitkLesionTreeModel::headerData(int section, Qt::Orientation orientation, int role) const { if (0 == m_RootItem->ChildCount()) { // no lesion items stored, no need to display the header return QVariant(); } if (Qt::Horizontal == orientation && Qt::DisplayRole == role) { if (0 == section) { return QVariant("Lesion"); } if (static_cast(m_ControlPoints.size()) >= section) { mitk::SemanticTypes::ControlPoint currentControlPoint = m_ControlPoints.at(section-1); return QVariant(QString::fromStdString(currentControlPoint.ToString())); } } return QVariant(); } const mitk::DataNode* QmitkLesionTreeModel::GetLastSegmentation() const { return m_LastSegmentation; } void QmitkLesionTreeModel::NodeAdded(const mitk::DataNode* dataNode) { if (mitk::NodePredicates::GetSegmentationPredicate()->CheckNode(dataNode)) { m_LastSegmentation = dataNode; } } void QmitkLesionTreeModel::SetData() { m_RootItem = std::make_shared(mitk::LesionData()); // get all control points of current case m_ControlPoints = mitk::RelationStorage::GetAllControlPointsOfCase(m_CaseID); // sort the vector of control points for the timeline std::sort(m_ControlPoints.begin(), m_ControlPoints.end()); SetLesionData(); SetSelectedDataNodesPresence(); } void QmitkLesionTreeModel::SetLesionData() { m_CurrentLesions = mitk::RelationStorage::GetAllLesionsOfCase(m_CaseID); for (auto& lesion : m_CurrentLesions) { AddLesion(lesion); } } void QmitkLesionTreeModel::AddLesion(const mitk::SemanticTypes::Lesion& lesion) { auto dataStorage = m_DataStorage.Lock(); if (dataStorage.IsNull()) { return; } // create new lesion tree item data and modify it according to the control point data mitk::LesionData lesionData(lesion); mitk::ComputeLesionPresence(lesionData, m_CaseID); // add the top-level lesion item to the root item std::shared_ptr newLesionTreeItem = std::make_shared(lesionData); m_RootItem->AddChild(newLesionTreeItem); } void QmitkLesionTreeModel::SetSelectedDataNodesPresence() { m_DataNodePresence.clear(); - for (const auto& dataNode : qAsConst(m_SelectedDataNodes)) + for (const auto& dataNode : std::as_const(m_SelectedDataNodes)) { if (!mitk::SemanticRelationsInference::InstanceExists(dataNode)) { continue; } for (const auto& lesion : m_CurrentLesions) { if (!mitk::SemanticRelationsInference::InstanceExists(m_CaseID, lesion)) { continue; } try { // set the lesion presence for the current node bool dataNodePresence = mitk::SemanticRelationsInference::IsLesionPresent(lesion, dataNode); SetDataNodePresenceOfLesion(&lesion, dataNodePresence); } catch (const mitk::SemanticRelationException&) { continue; } } } } void QmitkLesionTreeModel::SetDataNodePresenceOfLesion(const mitk::SemanticTypes::Lesion* lesion, bool dataNodePresence) { std::map::iterator iter = m_DataNodePresence.find(lesion->UID); if (iter != m_DataNodePresence.end()) { // key already existing, overwrite already stored bool value iter->second = dataNodePresence; } else { m_DataNodePresence.insert(std::make_pair(lesion->UID, dataNodePresence)); } } QmitkLesionTreeItem* QmitkLesionTreeModel::GetItemByIndex(const QModelIndex& index) const { if (index.isValid()) { auto item = static_cast(index.internalPointer()); if (nullptr != item) { return item; } } return m_RootItem.get(); } diff --git a/Modules/SemanticRelationsUI/src/QmitkPatientTableHeaderView.cpp b/Modules/SemanticRelationsUI/src/QmitkPatientTableHeaderView.cpp index eae7be7291..7a2eb49438 100644 --- a/Modules/SemanticRelationsUI/src/QmitkPatientTableHeaderView.cpp +++ b/Modules/SemanticRelationsUI/src/QmitkPatientTableHeaderView.cpp @@ -1,240 +1,240 @@ /*============================================================================ 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. ============================================================================*/ // semantic relations UI module #include "QmitkPatientTableHeaderView.h" // qt #include #include QmitkPatientTableHeaderView::QmitkPatientTableHeaderView(QWidget* parent/* = nullptr*/) : QHeaderView(Qt::Horizontal, parent) , m_HeaderModel(nullptr) { // nothing here } QmitkPatientTableHeaderView::~QmitkPatientTableHeaderView() { // nothing here } void QmitkPatientTableHeaderView::setModel(QAbstractItemModel* model) { // retrieve the header model from the given table model QVariant variant = model->data(QModelIndex(), HorizontalHeaderDataRole); if (variant.isValid() && variant.canConvert()) { m_HeaderModel = variant.value(); } QHeaderView::setModel(model); } void QmitkPatientTableHeaderView::paintSection(QPainter* painter, const QRect& rect, int logicalIndex) const { if (rect.isValid()) { int top = rect.y(); QModelIndex leafIndex = HeaderIndex(logicalIndex); QModelIndexList indexes = ParentIndexList(leafIndex); - for (const auto& index : qAsConst(indexes)) + for (const auto& index : std::as_const(indexes)) { top = PaintHeader(painter, index, logicalIndex, rect, top); } return; } QHeaderView::paintSection(painter, rect, logicalIndex); } QSize QmitkPatientTableHeaderView::sectionSizeFromContents(int logicalIndex) const { if (nullptr != m_HeaderModel) { QModelIndex headerIndex = HeaderIndex(logicalIndex); if (headerIndex.isValid()) { QSize headerSize = HeaderSize(headerIndex); headerIndex = headerIndex.parent(); while (headerIndex.isValid()) { QSize currentHeaderSize = HeaderSize(headerIndex); headerSize.rheight() += currentHeaderSize.height(); if (currentHeaderSize.width() > headerSize.width()) { headerSize.rwidth() = currentHeaderSize.width(); } headerIndex = headerIndex.parent(); } return headerSize; } } return QHeaderView::sectionSizeFromContents(logicalIndex); } int QmitkPatientTableHeaderView::PaintHeader(QPainter* painter, const QModelIndex& currentIndex, int logicalIndex, const QRect& sectionRect, int top) const { QModelIndex headerIndex = HeaderIndex(logicalIndex); int height = HeaderSize(currentIndex).height(); if (currentIndex == headerIndex) { height = sectionRect.height() - top; } int left = CurrentHeaderLeft(currentIndex, headerIndex, logicalIndex, sectionRect.left()); int width = CurrentHeaderWidth(currentIndex, headerIndex, logicalIndex); QStyleOptionHeader headerStyleOptions; initStyleOption(&headerStyleOptions); headerStyleOptions.text = currentIndex.data(Qt::DisplayRole).toString(); headerStyleOptions.textAlignment = Qt::AlignCenter; painter->save(); QRect rect(left, top, width, height); headerStyleOptions.rect = rect; style()->drawControl(QStyle::CE_Header, &headerStyleOptions, painter, this); painter->restore(); return top + height; } QSize QmitkPatientTableHeaderView::HeaderSize(const QModelIndex& index) const { QFont font = this->font(); font.setBold(true); QFontMetrics fontMetrics(font); QSize fontSize = fontMetrics.size(0, index.data(Qt::DisplayRole).toString()); QSize emptyFontSize = fontMetrics.size(0, ""); return fontSize + emptyFontSize; } int QmitkPatientTableHeaderView::CurrentHeaderLeft(const QModelIndex& currentIndex, const QModelIndex& headerIndex, int sectionIndex, int left) const { QModelIndexList headerList = ListHeader(currentIndex); if (!headerList.empty()) { int index = headerList.indexOf(headerIndex); int firstHeaderSectionIndex = sectionIndex - index; --index; for (; index >= 0; --index) { left -= sectionSize(firstHeaderSectionIndex + index); } } return left; } int QmitkPatientTableHeaderView::CurrentHeaderWidth(const QModelIndex& currentIndex, const QModelIndex& headerIndex, int sectionIndex) const { QModelIndexList headerList = ListHeader(currentIndex); if (headerList.empty()) { return sectionSize(sectionIndex); } int width = 0; int index = headerList.indexOf(headerIndex); int firstHeaderSectionIndex = sectionIndex - index; for (int i = 0; i < headerList.size(); ++i) { width += sectionSize(firstHeaderSectionIndex + i); } return width; } QModelIndexList QmitkPatientTableHeaderView::ParentIndexList(QModelIndex index) const { QModelIndexList indexList; while (index.isValid()) { indexList.push_front(index); index = index.parent(); } return indexList; } QModelIndex QmitkPatientTableHeaderView::HeaderIndex(int sectionIndex) const { if (nullptr != m_HeaderModel) { int currentHeaderIndex = -1; for (int i = 0; i < m_HeaderModel->columnCount(); ++i) { QModelIndex modelIndex = FindHeader(m_HeaderModel->index(0, i), sectionIndex, currentHeaderIndex); if (modelIndex.isValid()) { return modelIndex; } } } return QModelIndex(); } QModelIndex QmitkPatientTableHeaderView::FindHeader(const QModelIndex& currentIndex, int sectionIndex, int& currentHeaderIndex) const { if (currentIndex.isValid()) { int childCount = currentIndex.model()->columnCount(currentIndex); if (childCount > 0) { for (int i = 0; i < childCount; ++i) { QModelIndex modelIndex = FindHeader(currentIndex.model()->index(0, i, currentIndex), sectionIndex, currentHeaderIndex); if (modelIndex.isValid()) { return modelIndex; } } } else { ++currentHeaderIndex; if (currentHeaderIndex == sectionIndex) { return currentIndex; } } } return QModelIndex(); } QModelIndexList QmitkPatientTableHeaderView::ListHeader(const QModelIndex& currentIndex) const { QModelIndexList headerList; if (currentIndex.isValid()) { int childCount = currentIndex.model()->columnCount(currentIndex); if (childCount > 0) { for (int i = 0; i < childCount; ++i) { headerList += ListHeader(currentIndex.model()->index(0, i, currentIndex)); } } else { headerList.push_back(currentIndex); } } return headerList; } diff --git a/Plugins/org.blueberry.core.runtime/src/berryDebugUtil.cpp b/Plugins/org.blueberry.core.runtime/src/berryDebugUtil.cpp index 7aadca18ea..0fc0e56205 100755 --- a/Plugins/org.blueberry.core.runtime/src/berryDebugUtil.cpp +++ b/Plugins/org.blueberry.core.runtime/src/berryDebugUtil.cpp @@ -1,537 +1,537 @@ /*============================================================================ 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 "berryIDebugObjectListener.h" #include "berryDebugUtil.h" #include "berryObject.h" #include "berryLog.h" #include "berryPlatform.h" #include "berryDebugBreakpointManager.h" #include "internal/berryCTKPluginActivator.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace berry { static IDebugObjectListener::Events _G_ObjectEvents; const QString DebugUtil::DEBUG_UTIL_XML = "debugutil.xml"; const QString DebugUtil::DEBUGUTIL_TAG = "debugutil"; const QString DebugUtil::TRACEOBJECT_TAG = "traceObject"; const QString DebugUtil::TRACECLASS_TAG = "traceClass"; const QString DebugUtil::ID_ATTR = "id"; const QString DebugUtil::NAME_ATTR = "name"; QHash > DebugUtil::m_TraceIdToSmartPointerMap; QHash DebugUtil::m_TraceIdToObjectMap; QSet DebugUtil::m_TracedObjects; QSet DebugUtil::m_TracedClasses; class NotClassName { QString name; public: NotClassName(const QString& s) : name(s) { } bool operator()(const Object* entry) const { return name != entry->GetClassName(); } }; DebugBreakpointManager* DebugUtil::GetBreakpointManager() { static DebugBreakpointManager breakpointManager; return &breakpointManager; } #ifdef BLUEBERRY_DEBUG_SMARTPOINTER void DebugUtil::TraceObject(const Object* object) { BERRY_INFO << "Tracing enabled for: " << object->GetTraceId() << std::endl; m_TracedObjects.insert(object->GetTraceId()); _G_ObjectEvents.objTracingEvent(object->GetTraceId(), true, object); } #else void DebugUtil::TraceObject(const Object* /*object*/) { } #endif #ifdef BLUEBERRY_DEBUG_SMARTPOINTER void DebugUtil::TraceObject(unsigned int traceId) { BERRY_INFO << "Tracing enabled for: " << traceId << std::endl; m_TracedObjects.insert(traceId); TraceIdToObjectType::ConstIterator i = m_TraceIdToObjectMap.find(traceId); if (i != m_TraceIdToObjectMap.end()) _G_ObjectEvents.objTracingEvent(traceId, true, i.value()); else _G_ObjectEvents.objTracingEvent(traceId, true, 0); } #else void DebugUtil::TraceObject(unsigned int /*traceId*/) { } #endif #ifdef BLUEBERRY_DEBUG_SMARTPOINTER void DebugUtil::TraceClass(const QString& className) { BERRY_INFO << "Tracing enabled for: " << className << std::endl; m_TracedClasses.insert(className); //_G_ObjectEvents.objTracingEvent(object->GetTraceId(), true, object); } #else void DebugUtil::TraceClass(const QString& /*className*/) { } #endif #ifdef BLUEBERRY_DEBUG_SMARTPOINTER void DebugUtil::StopTracing(unsigned int traceId) { BERRY_INFO << "Tracing stopped for: " << traceId << std::endl; m_TracedObjects.remove(traceId); TraceIdToObjectType::ConstIterator i = m_TraceIdToObjectMap.find(traceId); if (i != m_TraceIdToObjectMap.end()) _G_ObjectEvents.objTracingEvent(traceId, false, i.value()); else _G_ObjectEvents.objTracingEvent(traceId, false, 0); } #else void DebugUtil::StopTracing(unsigned int /*traceId*/) { } #endif #ifdef BLUEBERRY_DEBUG_SMARTPOINTER void DebugUtil::StopTracing(const Object* obj) { BERRY_INFO << "Tracing stopped for: " << obj->GetTraceId() << std::endl; m_TracedObjects.remove(obj->GetTraceId()); _G_ObjectEvents.objTracingEvent(obj->GetTraceId(), false, obj); } #else void DebugUtil::StopTracing(const Object* /*obj*/) { } #endif #ifdef BLUEBERRY_DEBUG_SMARTPOINTER void DebugUtil::StopTracing(const QString& className) { BERRY_INFO << "Tracing stopped for: " << className << std::endl; m_TracedClasses.remove(className); //_G_ObjectEvents.objTracingEvent(obj->GetTraceId(), false, obj); } #else void DebugUtil::StopTracing(const QString& /*className*/) { } #endif #ifdef BLUEBERRY_DEBUG_SMARTPOINTER bool DebugUtil::IsTraced(const Object* object) { if (m_TracedObjects.find(object->GetTraceId()) != m_TracedObjects.end()) return true; if (m_TracedClasses.find(object->GetClassName()) != m_TracedClasses.end()) return true; return false; } #else bool DebugUtil::IsTraced(const Object* /*object*/) { return false; } #endif #ifdef BLUEBERRY_DEBUG_SMARTPOINTER bool DebugUtil::IsTraced(unsigned int traceId) { if (m_TracedObjects.find(traceId) != m_TracedObjects.end()) return true; TraceIdToObjectType::Iterator it = m_TraceIdToObjectMap.find(traceId); if (it != m_TraceIdToObjectMap.end()) { if (m_TracedClasses.find(it.value()->GetClassName()) != m_TracedClasses.end()) return true; } return false; } #else bool DebugUtil::IsTraced(unsigned int /*traceId*/) { return false; } #endif #ifdef BLUEBERRY_DEBUG_SMARTPOINTER bool DebugUtil::IsTraced(const QString& className) { return m_TracedClasses.find(className) != m_TracedClasses.end(); } #else bool DebugUtil::IsTraced(const QString& /*className*/) { return false; } #endif QSet DebugUtil::GetTracedObjects() { return m_TracedObjects; } const Object* DebugUtil::GetObject(unsigned int traceId) { return m_TraceIdToObjectMap[traceId]; } #ifdef BLUEBERRY_DEBUG_SMARTPOINTER QList DebugUtil::GetSmartPointerIDs( const Object* objectPointer, const QList& excludeList) { Q_ASSERT(objectPointer != 0); QList ids = m_TraceIdToSmartPointerMap[objectPointer->GetTraceId()]; for (QList::const_iterator iter = excludeList.begin(); iter != excludeList.end(); ++iter) ids.removeAll(*iter); return ids; } #else QList DebugUtil::GetSmartPointerIDs( const Object* /*objectPointer*/, const QList& /*excludeList*/) { return QList(); } #endif QList DebugUtil::GetRegisteredObjects() { return m_TraceIdToObjectMap.values(); } void DebugUtil::PrintSmartPointerIDs(const Object* objectPointer, const QList& excludeList) { qDebug() << "SmartPointer IDs [ "; if (IsTraced(objectPointer)) { QList ids = GetSmartPointerIDs(objectPointer, excludeList); for (QList::const_iterator iter = ids.begin(); iter != ids.end(); ++iter) { qDebug() << *iter << " "; } } else { qDebug() << "n/a "; } qDebug() << "]\n"; } void DebugUtil::AddObjectListener(IDebugObjectListener* listener) { _G_ObjectEvents.AddListener(listener); } void DebugUtil::RemoveObjectListener(IDebugObjectListener* listener) { _G_ObjectEvents.RemoveListener(listener); } void DebugUtil::ResetObjectSummary() { m_TraceIdToObjectMap.clear(); m_TraceIdToSmartPointerMap.clear(); m_TracedObjects.clear(); } bool DebugUtil::PrintObjectSummary(bool details) { QSet names; - for (auto object : qAsConst(m_TraceIdToObjectMap)) + for (auto object : std::as_const(m_TraceIdToObjectMap)) names.insert(object->GetClassName()); if (!names.isEmpty()) { std::cout << std::endl << std::endl << "#########################################################" << std::endl; std::cout << "######## berry::Object leakage summary: ########" << std::endl << std::endl; for (QSet::const_iterator i = names.begin(); i != names.end(); ++i) { PrintObjectSummary(*i, details); if (details) std::cout << std::endl; } std::cout << std::endl << "#########################################################" << std::endl << std::endl; } return !names.isEmpty(); } bool DebugUtil::PrintObjectSummary(const QString& className, bool details) { TraceIdToObjectType::ConstIterator endIter = std::remove_if(m_TraceIdToObjectMap.begin(), m_TraceIdToObjectMap.end(), NotClassName(className)); qDebug() << "Class:" << className; if (details) std::cout << std::endl; std::size_t count = 0; for (TraceIdToObjectType::ConstIterator iter = m_TraceIdToObjectMap.begin(); iter != endIter; ++iter, ++count) { if (details) { qDebug() << (*(iter.value())); PrintSmartPointerIDs(iter.value()); } } qDebug() << "(" << count << " instances)\n"; return (count!=0); } unsigned int& DebugUtil::GetSmartPointerCounter() { static unsigned int counter = 0; return counter; } #ifdef BLUEBERRY_DEBUG_SMARTPOINTER void DebugUtil::UnregisterSmartPointer(unsigned int smartPointerId, const Object* objectPointer) { poco_assert(objectPointer != 0); m_TraceIdToSmartPointerMap[objectPointer->GetTraceId()].removeAll(smartPointerId); _G_ObjectEvents.spDestroyedEvent(smartPointerId, objectPointer); } #else void DebugUtil::UnregisterSmartPointer(unsigned int /*smartPointerId*/, const Object* /*objectPointer*/) { } #endif #ifdef BLUEBERRY_DEBUG_SMARTPOINTER void DebugUtil::RegisterSmartPointer(unsigned int smartPointerId, const Object* objectPointer, bool /*recordStack*/) { poco_assert(objectPointer != 0); if (m_TracedClasses.find(objectPointer->GetClassName()) != m_TracedClasses.end() || m_TracedObjects.find(objectPointer->GetTraceId()) != m_TracedObjects.end()) { m_TraceIdToSmartPointerMap[objectPointer->GetTraceId()].push_back(smartPointerId); _G_ObjectEvents.spCreatedEvent(smartPointerId, objectPointer); } if (GetBreakpointManager()->BreakAtSmartpointer(smartPointerId)) poco_debugger_msg("SmartPointer Breakpoint reached"); } #else void DebugUtil::RegisterSmartPointer(unsigned int /*smartPointerId*/, const Object* /*objectPointer*/, bool /*recordStack*/) { } #endif #ifdef BLUEBERRY_DEBUG_SMARTPOINTER void DebugUtil::RegisterObject(const Object* objectPointer) { m_TraceIdToObjectMap.insert(objectPointer->GetTraceId(), objectPointer); _G_ObjectEvents.objCreatedEvent(objectPointer); if (GetBreakpointManager()->BreakAtObject(objectPointer->GetTraceId())) { std::string msg = "SmartPointer Breakpoint reached for "; msg += objectPointer->GetClassName().toStdString(); poco_debugger_msg(msg.c_str()); } } #else void DebugUtil::RegisterObject(const Object* /*objectPointer*/) { } #endif #ifdef BLUEBERRY_DEBUG_SMARTPOINTER void DebugUtil::UnregisterObject(const Object* objectPointer) { m_TraceIdToObjectMap.remove(objectPointer->GetTraceId()); _G_ObjectEvents.objDestroyedEvent(objectPointer); } #else void DebugUtil::UnregisterObject(const Object* /*objectPointer*/) { } #endif bool DebugUtil::GetPersistencePath(QDir& path) { QFileInfo statePath = CTKPluginActivator::getPluginContext()->getDataFile(QString()); path = statePath.absoluteFilePath(); return true; } void DebugUtil::SaveState(const QDir& path) { QString saveFile = path.absoluteFilePath(DEBUG_UTIL_XML); auto doc = new Poco::XML::Document(); Poco::XML::Element* debugutil = doc->createElement(DEBUGUTIL_TAG.toStdString()); doc->appendChild(debugutil)->release(); for (QSet::const_iterator i = m_TracedObjects.begin(); i != m_TracedObjects.end(); ++i) { Poco::XML::Element* traceObject = doc->createElement(TRACEOBJECT_TAG.toStdString()); debugutil->appendChild(traceObject)->release(); traceObject->setAttribute(ID_ATTR.toStdString(), QString::number(*i).toStdString()); } for (QSet::const_iterator i = m_TracedClasses.begin(); i != m_TracedClasses.end(); ++i) { Poco::XML::Element* traceClass = doc->createElement(TRACECLASS_TAG.toStdString()); debugutil->appendChild(traceClass)->release(); traceClass->setAttribute(NAME_ATTR.toStdString(), i->toStdString()); } try { Poco::FileOutputStream writer(saveFile.toStdString()); Poco::XML::DOMWriter out; out.setOptions(3); //write declaration and pretty print out.writeNode(writer, doc); doc->release(); // save BreakpointManager QString saveBM = path.absoluteFilePath(QString::fromStdString(DebugBreakpointManager::BREAKPOINTS_XML)); GetBreakpointManager()->SaveState(saveBM); } catch (Poco::FileException& e) { BERRY_WARN << e.displayText(); } } void DebugUtil::RestoreState(const QDir& path) { QString restoreFile = path.absoluteFilePath(DEBUG_UTIL_XML); try { Poco::XML::DOMParser parser; Poco::FileInputStream reader(restoreFile.toStdString()); Poco::XML::InputSource source(reader); //source.setSystemId(baseDir); Poco::XML::Document* doc = parser.parse(&source); Poco::XML::Element* debugutil = doc->documentElement(); if (debugutil) { // restore traced objects Poco::XML::NodeList* elementList = debugutil->getElementsByTagName(TRACEOBJECT_TAG.toStdString()); for (std::size_t i = 0; i < elementList->length(); i++) { Poco::XML::Element* elem = dynamic_cast (elementList->item(static_cast(i))); if (!elem->hasAttribute(ID_ATTR.toStdString())) continue; const std::string& attr = elem->getAttribute(ID_ATTR.toStdString()); int traceId = 0; try { traceId = Poco::NumberParser::parse(attr); } catch (const Poco::SyntaxException& e) { BERRY_WARN << e.displayText(); } DebugUtil::TraceObject(traceId); } elementList->release(); // restore traced classes elementList = debugutil->getElementsByTagName(TRACECLASS_TAG.toStdString()); for (std::size_t i = 0; i < elementList->length(); i++) { Poco::XML::Element* elem = dynamic_cast (elementList->item(static_cast(i))); if (!elem->hasAttribute(NAME_ATTR.toStdString())) continue; const std::string& traceClass = elem->getAttribute(NAME_ATTR.toStdString()); if (!traceClass.empty()) DebugUtil::TraceClass(QString::fromStdString(traceClass)); } elementList->release(); } doc->release(); } catch (Poco::XML::SAXParseException& e) { BERRY_WARN << e.displayText(); } catch (Poco::FileNotFoundException&) { } catch (Poco::FileException& e) { BERRY_WARN << e.displayText(); } // restore BreakpointManager GetBreakpointManager()->RestoreState(path.absoluteFilePath(QString::fromStdString(DebugBreakpointManager::BREAKPOINTS_XML))); } } diff --git a/Plugins/org.blueberry.core.runtime/src/internal/berryApplicationContainer.cpp b/Plugins/org.blueberry.core.runtime/src/internal/berryApplicationContainer.cpp index f3337fdca9..1b4a74dde7 100644 --- a/Plugins/org.blueberry.core.runtime/src/internal/berryApplicationContainer.cpp +++ b/Plugins/org.blueberry.core.runtime/src/internal/berryApplicationContainer.cpp @@ -1,718 +1,718 @@ /*============================================================================ 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 "berryApplicationContainer.h" #include #include #include #include #include #include #include #include "berryApplicationHandle.h" #include "berryApplicationDescriptor.h" #include "berryCoreException.h" #include "berryErrorApplication.h" #include "berryMainApplicationLauncher.h" #include "berryProductExtensionBranding.h" #include "berryProviderExtensionBranding.h" #include #include "berryCTKPluginActivator.h" #include #include namespace berry { static const QString PI_OSGI = "org.blueberry.osgi"; const QString ApplicationContainer::PI_RUNTIME = "org.blueberry.core.runtime"; const QString ApplicationContainer::PT_APPLICATIONS = "applications"; const QString ApplicationContainer::PT_APP_VISIBLE = "visible"; const QString ApplicationContainer::PT_APP_THREAD = "thread"; const QString ApplicationContainer::PT_APP_THREAD_ANY = "any"; const QString ApplicationContainer::PT_APP_CARDINALITY = "cardinality"; const QString ApplicationContainer::PT_APP_CARDINALITY_SINGLETON_GLOBAL = "singleton-global"; const QString ApplicationContainer::PT_APP_CARDINALITY_SINGLETON_SCOPED = "singleton-scoped"; const QString ApplicationContainer::PT_APP_CARDINALITY_UNLIMITED = "*"; const QString ApplicationContainer::PT_APP_ICON = "icon"; const QString ApplicationContainer::PT_PRODUCTS = "products"; const QString ApplicationContainer::EXT_ERROR_APP = "org.blueberry.core.runtime.app.error"; const QString ApplicationContainer::PROP_PRODUCT = "blueberry.product"; const QString ApplicationContainer::PROP_BLUEBERRY_APPLICATION = "blueberry.application"; const QString ApplicationContainer::PROP_BLUEBERRY_APPLICATION_LAUNCH_DEFAULT = "blueberry.application.launchDefault"; const int ApplicationContainer::NOT_LOCKED = 0; const int ApplicationContainer::LOCKED_SINGLETON_GLOBAL_RUNNING = 1; const int ApplicationContainer::LOCKED_SINGLETON_GLOBAL_APPS_RUNNING = 2; const int ApplicationContainer::LOCKED_SINGLETON_SCOPED_RUNNING = 3; const int ApplicationContainer::LOCKED_SINGLETON_LIMITED_RUNNING = 4; const int ApplicationContainer::LOCKED_MAIN_THREAD_RUNNING = 5; ApplicationContainer::ApplicationContainer(ctkPluginContext* context, IExtensionRegistry* extensionRegistry) : context(context) , extensionRegistry(extensionRegistry) , launcherTracker(new ctkServiceTracker(context, this)) , branding(nullptr) , missingProductReported(false) , defaultMainThreadAppHandle(nullptr) , missingApp(false) { } ApplicationContainer::~ApplicationContainer() { } void ApplicationContainer::Start() { launcherTracker->open(); extensionRegistry->AddListener(this, PI_OSGI + '.' + PT_APPLICATIONS); // need to listen for system bundle stopping context->connectPluginListener(this, SLOT(PluginChanged(ctkPluginEvent)), Qt::DirectConnection); // register all the descriptors RegisterAppDescriptors(); QVariant startDefaultProp = context->getProperty(ApplicationContainer::PROP_BLUEBERRY_APPLICATION_LAUNCH_DEFAULT); if (startDefaultProp.isNull() || startDefaultProp.toBool()) { // Start the default application try { StartDefaultApp(true); } catch (const ctkApplicationException& e) { BERRY_ERROR << "An error occurred while starting the application:" << e.message(); } } } void ApplicationContainer::Stop() { // stop all applications StopAllApps(); context->disconnectPluginListener(this); extensionRegistry->RemoveListener(this); // flush the apps apps.clear(); branding.reset(); missingProductReported = false; launcherTracker->close(); } IBranding* ApplicationContainer::GetBranding() const { if (branding) { return branding.data(); } // try pluginContext properties if (context == nullptr) return nullptr; QString productId = context->getProperty(PROP_PRODUCT).toString(); if (productId.isEmpty()) return nullptr; QList entries = extensionRegistry->GetConfigurationElementsFor(PI_RUNTIME, PT_PRODUCTS, productId); if (!entries.isEmpty()) { // There should only be one product with the given id so just take the first element branding.reset(new ProductExtensionBranding(productId, entries[0])); return branding.data(); } QList elements = extensionRegistry->GetConfigurationElementsFor(PI_RUNTIME, PT_PRODUCTS); - for (const auto &element : qAsConst(elements)) + for (const auto &element : std::as_const(elements)) { if (element->GetName().compare("provider", Qt::CaseInsensitive) == 0) { try { IProductProvider* provider = element->CreateExecutableExtension("run"); QList products = provider->GetProducts(); - for (const auto &product : qAsConst(products)) + for (const auto &product : std::as_const(products)) { if (productId.compare(product->GetId(), Qt::CaseInsensitive) == 0) { branding.reset(new ProviderExtensionBranding(product)); return branding.data(); } } } catch (const CoreException&) { BERRY_WARN << "Problem creating the provider registered by " << element->GetParent()->ToString() << "."; } } } if (!missingProductReported) { BERRY_WARN << "Product " << productId << " could not be found."; missingProductReported = true; } return nullptr; } ctkPluginContext* ApplicationContainer::GetContext() const { return context; } ApplicationDescriptor* ApplicationContainer::GetAppDescriptor(const QString& applicationId) { ApplicationDescriptor* result = nullptr; { QMutexLocker l(&appDescLock); auto iter = apps.find(applicationId); result = iter == apps.end() ? nullptr : iter.value(); } if (result == nullptr) { RegisterAppDescriptor(applicationId); // try again just in case we are waiting for an event { QMutexLocker l(&appDescLock); auto iter = apps.find(applicationId); result = iter == apps.end() ? nullptr : iter.value(); } } return result; } ApplicationDescriptor* ApplicationContainer::CreateAppDescriptor(const SmartPointer& appExtension) { if (org_blueberry_core_runtime_Activator::DEBUG) { BERRY_INFO << "Creating application descriptor: " << appExtension->GetUniqueIdentifier(); } QString iconPath; { QMutexLocker l(&appDescLock); auto iter = apps.find(appExtension->GetUniqueIdentifier()); ApplicationDescriptor* appDescriptor = iter == apps.end() ? nullptr : iter.value(); if (appDescriptor != nullptr) { return appDescriptor; } // the appDescriptor does not exist for the app ID; create it QList configs = appExtension->GetConfigurationElements(); ApplicationDescriptor::Flags flags = ApplicationDescriptor::FLAG_CARD_SINGLETON_GLOGAL | ApplicationDescriptor::FLAG_VISIBLE | ApplicationDescriptor::FLAG_TYPE_MAIN_THREAD; int cardinality = 0; if (!configs.isEmpty()) { QString sVisible = configs[0]->GetAttribute(PT_APP_VISIBLE); if (!sVisible.isEmpty() && sVisible.compare("true", Qt::CaseInsensitive) != 0) { flags &= ~(ApplicationDescriptor::FLAG_VISIBLE); } QString sThread = configs[0]->GetAttribute(PT_APP_THREAD); if (PT_APP_THREAD_ANY == sThread) { flags |= ApplicationDescriptor::FLAG_TYPE_ANY_THREAD; flags &= ~(ApplicationDescriptor::FLAG_TYPE_MAIN_THREAD); } QString sCardinality = configs[0]->GetAttribute(PT_APP_CARDINALITY); if (!sCardinality.isEmpty()) { flags &= ~(ApplicationDescriptor::FLAG_CARD_SINGLETON_GLOGAL); // clear the global bit if (PT_APP_CARDINALITY_SINGLETON_SCOPED == sCardinality) { flags |= ApplicationDescriptor::FLAG_CARD_SINGLETON_SCOPED; } else if (PT_APP_CARDINALITY_UNLIMITED == sCardinality) { flags |= ApplicationDescriptor::FLAG_CARD_UNLIMITED; } else if (PT_APP_CARDINALITY_SINGLETON_GLOBAL == sCardinality) { flags |= ApplicationDescriptor::FLAG_CARD_SINGLETON_GLOGAL; } else { bool okay = false; cardinality = sCardinality.toInt(&okay); if (okay) { flags |= ApplicationDescriptor::FLAG_CARD_LIMITED; } else { // TODO should we log this? // just fall back to the default flags |= ApplicationDescriptor::FLAG_CARD_SINGLETON_GLOGAL; } } } QString defaultApp = GetDefaultAppId(); QString appId = appExtension->GetUniqueIdentifier(); if (defaultApp == appId) { flags |= ApplicationDescriptor::FLAG_DEFAULT_APP; } iconPath = configs[0]->GetAttribute(PT_APP_ICON); } appDescriptor = new ApplicationDescriptor(org_blueberry_core_runtime_Activator::GetPlugin(appExtension->GetContributor()), appExtension->GetUniqueIdentifier(), appExtension->GetLabel(), iconPath, flags, cardinality, this); // register the appDescriptor as a service ctkServiceRegistration sr = context->registerService(appDescriptor, appDescriptor->GetServiceProperties()); appDescriptor->SetServiceRegistration(sr); // save the app descriptor in the cache apps.insert(appExtension->GetUniqueIdentifier(), appDescriptor); return appDescriptor; } } ApplicationDescriptor*ApplicationContainer::RemoveAppDescriptor(const QString& applicationId) { if (org_blueberry_core_runtime_Activator::DEBUG) { BERRY_INFO << "Removing application descriptor: " << applicationId; } { QMutexLocker l(&appDescLock); ApplicationDescriptor* appDescriptor = apps.take(applicationId); if (appDescriptor == nullptr) { return nullptr; } appDescriptor->Unregister(); return appDescriptor; } } void ApplicationContainer::StartDefaultApp(bool delayError) { // find the default application QString applicationId = GetDefaultAppId(); ApplicationDescriptor* defaultDesc = nullptr; QHash args; args.insert(ApplicationDescriptor::APP_DEFAULT, true); if (applicationId.isEmpty() && !delayError) { // the application id is not set; use a descriptor that will throw an exception args.insert(ErrorApplication::ERROR_EXCEPTION, QString("No application id has been found.")); defaultDesc = GetAppDescriptor(EXT_ERROR_APP); } else { defaultDesc = GetAppDescriptor(applicationId); if (defaultDesc == nullptr && !delayError) { // the application id is not available in the registry; use a descriptor that will throw an exception args.insert(ErrorApplication::ERROR_EXCEPTION, QString("Application \"%1\" could not be found in the registry. The applications available are: %2.") .arg(applicationId) .arg(GetAvailableAppsMsg())); defaultDesc = GetAppDescriptor(EXT_ERROR_APP); } } if (delayError && defaultDesc == nullptr) { // could not find the application; but we want to delay the error. // another bundle may get installed that provides the application // before we actually try to launch it. missingApp = true; return; } if (defaultDesc != nullptr) { defaultDesc->launch(args); } else { throw ctkApplicationException(ctkApplicationException::APPLICATION_INTERNAL_ERROR, "No application id has been found."); } } void ApplicationContainer::RegisterAppDescriptors() { QList availableApps = GetAvailableAppExtensions(); for (int i = 0; i < availableApps.size(); i++) { CreateAppDescriptor(availableApps[i]); } } void ApplicationContainer::RegisterAppDescriptor(const QString& applicationId) { IExtension::Pointer appExtension = GetAppExtension(applicationId); if (appExtension.IsNotNull()) { CreateAppDescriptor(appExtension); } } QList > ApplicationContainer::GetAvailableAppExtensions() const { IExtensionPoint::Pointer point = extensionRegistry->GetExtensionPoint(PI_OSGI + '.' + PT_APPLICATIONS); if (point.IsNull()) { return QList(); } return point->GetExtensions(); } QString ApplicationContainer::GetAvailableAppsMsg() const { QList availableApps = GetAvailableAppExtensions(); QString availableAppsMsg = ""; if (!availableApps.isEmpty()) { availableAppsMsg = availableApps.front()->GetUniqueIdentifier(); - for (const auto &availableApp : qAsConst(availableApps)) + for (const auto &availableApp : std::as_const(availableApps)) { availableAppsMsg = availableAppsMsg + ", " + availableApp->GetUniqueIdentifier(); } } return availableAppsMsg; } SmartPointer ApplicationContainer::GetAppExtension(const QString& applicationId) const { return extensionRegistry->GetExtension(PI_OSGI, PT_APPLICATIONS, applicationId); } void ApplicationContainer::Launch(ApplicationHandle* appHandle) { bool isDefault = appHandle->IsDefault(); if (appHandle->getApplicationDescriptor()->GetThreadType() == ApplicationDescriptor::FLAG_TYPE_MAIN_THREAD) { // use the ApplicationLauncher provided by the framework to ensure it is launched on the main thread //DefaultApplicationListener curDefaultApplicationListener = null; MainApplicationLauncher* curMissingAppLauncher = nullptr; ctkApplicationLauncher* appLauncher = nullptr; { QMutexLocker l(this); appLauncher = launcherTracker->getService(); if (appLauncher == nullptr) { if (isDefault) { // we need to wait to allow the ApplicationLauncher to get registered; // save the handle to be launched as soon as the ApplicationLauncher is available defaultMainThreadAppHandle = appHandle; return; } throw ctkApplicationException(ctkApplicationException::APPLICATION_INTERNAL_ERROR, QString("The main thread is not available to launch the application: %1").arg(appHandle->getInstanceId())); } //curDefaultApplicationListener = defaultAppListener; curMissingAppLauncher = missingAppLauncher.data(); } //if (curDefaultApplicationListener != nullptr) //{ // curDefaultApplicationListener->launch(appHandle); //} //else if (curMissingAppLauncher != nullptr) { curMissingAppLauncher->Launch(appHandle); } else { appLauncher->launch(appHandle, appHandle->GetArguments()[IApplicationContext::APPLICATION_ARGS]); } } else { if (isDefault) { //DefaultApplicationListener curDefaultApplicationListener = null; MainApplicationLauncher* curMissingAppLauncher = nullptr; ctkApplicationLauncher* appLauncher = nullptr; { QMutexLocker l(this); appLauncher = launcherTracker->getService(); //if (defaultAppListener == nullptr) //{ // defaultAppListener = new DefaultApplicationListener(appHandle); //} //curDefaultApplicationListener = defaultAppListener; if (appLauncher == nullptr) { // we need to wait to allow the ApplicationLauncher to get registered; // save the default app listener to be launched as soon as the ApplicationLauncher is available //defaultMainThreadAppHandle = curDefaultApplicationListener; return; } curMissingAppLauncher = missingAppLauncher.data(); } if (curMissingAppLauncher != nullptr) { //curMissingAppLauncher->Launch(curDefaultApplicationListener); } else { //appLauncher->Launch(curDefaultApplicationListener, QVariant()); } } else { //AnyThreadAppLauncher.launchEclipseApplication(appHandle); } } } void ApplicationContainer::PluginChanged(const ctkPluginEvent& event) { // if this is not the system bundle stopping then ignore the event if ((ctkPluginEvent::STOPPING & event.getType()) == 0 || event.getPlugin()->getPluginId() != 0) { return; } // The system bundle is stopping; better stop all applications and containers now StopAllApps(); } void ApplicationContainer::StopAllApps() { // get a stapshot of running applications QList runningRefs = context->getServiceReferences("(!(application.state=STOPPING))"); - for (const auto &runningRef : qAsConst(runningRefs)) + for (const auto &runningRef : std::as_const(runningRefs)) { ctkApplicationHandle* handle = context->getService(runningRef); try { if (handle != nullptr) { handle->destroy(); } } catch (const std::exception&) { BERRY_WARN << QString("An error occurred while stopping the application: %1").arg(handle->getInstanceId()); } if (handle != nullptr) { context->ungetService(runningRef); } } } QString ApplicationContainer::GetDefaultAppId() const { if (!defaultAppId.isNull()) { return defaultAppId; } // try plugin context properties defaultAppId = context->getProperty(ApplicationContainer::PROP_BLUEBERRY_APPLICATION).toString(); if (!defaultAppId.isEmpty()) { return defaultAppId; } //Derive the application from the product information defaultAppId = GetBranding() == nullptr ? QString("") : GetBranding()->GetApplication(); return defaultAppId; } void ApplicationContainer::Lock(ApplicationHandle* /*appHandle*/) { /* ApplicationDescriptor eclipseApp = (ApplicationDescriptor) appHandle.getApplicationDescriptor(); { QMutexLocker l(&appDescLock); switch (isLocked(eclipseApp)) { case NOT_LOCKED : break; case LOCKED_SINGLETON_GLOBAL_RUNNING : throw new ApplicationException(ApplicationException.APPLICATION_NOT_LAUNCHABLE, NLS.bind(Messages.singleton_running, activeGlobalSingleton.getInstanceId())); case LOCKED_SINGLETON_GLOBAL_APPS_RUNNING : throw new ApplicationException(ApplicationException.APPLICATION_NOT_LAUNCHABLE, Messages.apps_running); case LOCKED_SINGLETON_SCOPED_RUNNING : throw new ApplicationException(ApplicationException.APPLICATION_NOT_LAUNCHABLE, NLS.bind(Messages.singleton_running, activeScopedSingleton.getInstanceId())); case LOCKED_SINGLETON_LIMITED_RUNNING : throw new ApplicationException(ApplicationException.APPLICATION_NOT_LAUNCHABLE, NLS.bind(Messages.max_running, eclipseApp.getApplicationId())); case LOCKED_MAIN_THREAD_RUNNING : throw new ApplicationException(ApplicationException.APPLICATION_NOT_LAUNCHABLE, NLS.bind(Messages.main_running, activeMain.getInstanceId())); default : break; } // ok we can now successfully lock the container switch (eclipseApp.getCardinalityType()) { case ApplicationDescriptor::FLAG_CARD_SINGLETON_GLOGAL : activeGlobalSingleton = appHandle; break; case ApplicationDescriptor::FLAG_CARD_SINGLETON_SCOPED : activeScopedSingleton = appHandle; break; case ApplicationDescriptor::FLAG_CARD_LIMITED : if (activeLimited == null) activeLimited = new HashMap(3); ArrayList limited = (ArrayList) activeLimited.get(eclipseApp.getApplicationId()); if (limited == null) { limited = new ArrayList(eclipseApp.getCardinality()); activeLimited.put(eclipseApp.getApplicationId(), limited); } limited.add(appHandle); break; case ApplicationDescriptor::FLAG_CARD_UNLIMITED : break; default : break; } if (eclipseApp.getThreadType() == ApplicationDescriptor::FLAG_TYPE_MAIN_THREAD) { activeMain = appHandle; } activeHandles.add(appHandle); refreshAppDescriptors(); } */ } void ApplicationContainer::Unlock(ApplicationHandle* /*appHandle*/) { /* QMutexLocker l(&appDescLock); if (activeGlobalSingleton == appHandle) activeGlobalSingleton = null; else if (activeScopedSingleton == appHandle) activeScopedSingleton = null; else if (((ApplicationDescriptor) appHandle.getApplicationDescriptor()).getCardinalityType() == ApplicationDescriptor::FLAG_CARD_LIMITED) { if (activeLimited != null) { ArrayList limited = (ArrayList) activeLimited.get(((ApplicationDescriptor) appHandle.getApplicationDescriptor()).getApplicationId()); if (limited != null) limited.remove(appHandle); } } if (activeMain == appHandle) activeMain = null; if (activeHandles.remove(appHandle)) refreshAppDescriptors(); // only refresh descriptors if we really unlocked something */ } int ApplicationContainer::IsLocked(const ApplicationDescriptor* /*eclipseApp*/) const { /* { QMutexLocker l(&appDescLock); if (activeGlobalSingleton != null) return LOCKED_SINGLETON_GLOBAL_RUNNING; switch (eclipseApp.getCardinalityType()) { case ApplicationDescriptor::FLAG_CARD_SINGLETON_GLOGAL : if (activeHandles.size() > 0) return LOCKED_SINGLETON_GLOBAL_APPS_RUNNING; break; case ApplicationDescriptor::FLAG_CARD_SINGLETON_SCOPED : if (activeScopedSingleton != null) return LOCKED_SINGLETON_SCOPED_RUNNING; break; case ApplicationDescriptor::FLAG_CARD_LIMITED : if (activeLimited != null) { ArrayList limited = (ArrayList) activeLimited.get(eclipseApp.getApplicationId()); if (limited != null && limited.size() >= eclipseApp.getCardinality()) return LOCKED_SINGLETON_LIMITED_RUNNING; } break; case ApplicationDescriptor::FLAG_CARD_UNLIMITED : break; default : break; } if (eclipseApp.getThreadType() == ApplicationDescriptor::FLAG_TYPE_MAIN_THREAD && activeMain != null) return LOCKED_MAIN_THREAD_RUNNING; return NOT_LOCKED; } */ return NOT_LOCKED; } ctkApplicationLauncher* ApplicationContainer::addingService(const ctkServiceReference& reference) { ctkApplicationLauncher* appLauncher = nullptr; ctkApplicationRunnable* appRunnable = nullptr; { QMutexLocker l(this); appLauncher = context->getService(reference); // see if there is a default main threaded application waiting to run appRunnable = defaultMainThreadAppHandle; // null out so we do not attempt to start this handle again defaultMainThreadAppHandle = nullptr; if (appRunnable == nullptr && missingApp) { missingAppLauncher.reset(new MainApplicationLauncher(this)); appRunnable = missingAppLauncher.data(); missingApp = false; } } if (appRunnable != nullptr) { // found a main threaded app; start it now that the app launcher is available ApplicationHandle* handle = dynamic_cast(appRunnable); appLauncher->launch(appRunnable, handle ? handle->GetArguments()[IApplicationContext::APPLICATION_ARGS] : QVariant()); } return appLauncher; } void ApplicationContainer::modifiedService(const ctkServiceReference& /*reference*/, ctkApplicationLauncher* /*service*/) { // Do nothing } void ApplicationContainer::removedService(const ctkServiceReference& /*reference*/, ctkApplicationLauncher* /*service*/) { // Do nothing } void ApplicationContainer::Added(const QList >& extensions) { for (const IExtension::Pointer &extension : extensions) { CreateAppDescriptor(extension); } } void ApplicationContainer::Added(const QList >& /*extensionPoints*/) { // nothing } void ApplicationContainer::Removed(const QList >& extensions) { for (const IExtension::Pointer &extension : extensions) { RemoveAppDescriptor(extension->GetUniqueIdentifier()); } } void ApplicationContainer::Removed(const QList >& /*extensionPoints*/) { // nothing } void ApplicationContainer::RefreshAppDescriptors() { QMutexLocker l(&appDescLock); for (ApplicationDescriptor* app : apps.values()) { app->RefreshProperties(); } } } diff --git a/Plugins/org.blueberry.core.runtime/src/internal/berryCTKPluginActivator.cpp b/Plugins/org.blueberry.core.runtime/src/internal/berryCTKPluginActivator.cpp index e95b2dbebc..fd2cb919fa 100755 --- a/Plugins/org.blueberry.core.runtime/src/internal/berryCTKPluginActivator.cpp +++ b/Plugins/org.blueberry.core.runtime/src/internal/berryCTKPluginActivator.cpp @@ -1,284 +1,284 @@ /*============================================================================ 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 NOMINMAX #define NOMINMAX #endif #include "berryCTKPluginActivator.h" #include #include #include #include "berryApplicationContainer.h" #include "berryPlatform.h" #include "berryInternalPlatform.h" #include "berryErrorApplication.h" #include "berryExtensionRegistry.h" #include "berryRegistryConstants.h" #include "berryRegistryProperties.h" #include "berryRegistryStrategy.h" #include "berryRegistryContributor.h" #include #include namespace berry { static const QString XP_APPLICATIONS = "org.blueberry.osgi.applications"; ctkPluginContext* org_blueberry_core_runtime_Activator::context = nullptr; QScopedPointer org_blueberry_core_runtime_Activator::appContainer; const bool org_blueberry_core_runtime_Activator::DEBUG = false; void org_blueberry_core_runtime_Activator::start(ctkPluginContext* context) { this->context = context; BERRY_REGISTER_EXTENSION_CLASS(ErrorApplication, context) RegistryProperties::SetContext(context); //ProcessCommandLine(); this->startRegistry(); // // register a listener to catch new plugin installations/resolutions. // pluginListener.reset(new CTKPluginListener(m_ExtensionPointService)); // context->connectPluginListener(pluginListener.data(), SLOT(pluginChanged(ctkPluginEvent)), Qt::DirectConnection); // // populate the registry with all the currently installed plugins. // // There is a small window here while processPlugins is being // // called where the pluginListener may receive a ctkPluginEvent // // to add/remove a plugin from the registry. This is ok since // // the registry is a synchronized object and will not add the // // same bundle twice. // pluginListener->processPlugins(context->getPlugins()); this->startAppContainer(); InternalPlatform::GetInstance()->Start(context); } void org_blueberry_core_runtime_Activator::stop(ctkPluginContext* context) { InternalPlatform::GetInstance()->Stop(context); //pluginListener.reset(); //Platform::GetServiceRegistry().UnRegisterService(IExtensionPointService::SERVICE_ID); this->stopRegistry(); RegistryProperties::SetContext(nullptr); stopAppContainer(); this->context = nullptr; } ctkPluginContext* org_blueberry_core_runtime_Activator::getPluginContext() { return context; } ApplicationContainer* org_blueberry_core_runtime_Activator::GetContainer() { return appContainer.data(); } #if defined(Q_OS_LINUX) || defined(Q_OS_DARWIN) #include QString org_blueberry_core_runtime_Activator::getPluginId(void *symbol) { if (symbol == nullptr) return QString(); Dl_info info = {nullptr,nullptr,nullptr,nullptr}; if(dladdr(symbol, &info) == 0) { return QString(); } else if(info.dli_fname) { QFile soPath(info.dli_fname); int index = soPath.fileName().lastIndexOf('.'); QString pluginId = soPath.fileName().left(index); if (pluginId.startsWith("lib")) pluginId = pluginId.mid(3); return pluginId.replace('_', '.'); } return QString(); } #elif defined(Q_CC_MSVC) #include #include #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable: 4091) #endif #include #ifdef _MSC_VER # pragma warning(pop) #endif QString org_blueberry_core_runtime_Activator::getPluginId(void *symbol) { if (symbol == nullptr) return QString(); if (ctk::DebugSymInitialize()) { std::vector moduleBuffer(sizeof(IMAGEHLP_MODULE64)); PIMAGEHLP_MODULE64 pModuleInfo = (PIMAGEHLP_MODULE64)&moduleBuffer.front(); pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64); if (SymGetModuleInfo64(GetCurrentProcess(), (DWORD64)symbol, pModuleInfo)) { QString pluginId = pModuleInfo->ModuleName; return pluginId.replace('_', '.'); } } return QString(); } #endif QSharedPointer org_blueberry_core_runtime_Activator::GetPlugin(const SmartPointer& contributor) { if (RegistryContributor::Pointer regContributor = contributor.Cast()) { bool okay = false; long id = regContributor->GetActualId().toLong(&okay); if (okay) { if (context != nullptr) { return context->getPlugin(id); } } else { // try using the name of the contributor below } } auto plugins = context->getPlugins(); //Return the first plugin that is not installed or uninstalled - for (auto plugin : qAsConst(plugins)) + for (auto plugin : std::as_const(plugins)) { if (!(plugin->getState() == ctkPlugin::INSTALLED || plugin->getState() == ctkPlugin::UNINSTALLED)) { return plugin; } } return QSharedPointer(); } org_blueberry_core_runtime_Activator::org_blueberry_core_runtime_Activator() : userRegistryKey(new QObject()) , masterRegistryKey(new QObject()) { } org_blueberry_core_runtime_Activator::~org_blueberry_core_runtime_Activator() { } void org_blueberry_core_runtime_Activator::startRegistry() { // see if the customer suppressed the creation of default registry QString property = context->getProperty(RegistryConstants::PROP_DEFAULT_REGISTRY).toString(); if (property.compare("false", Qt::CaseInsensitive) == 0) return; // check to see if we need to use null as a userToken if (context->getProperty(RegistryConstants::PROP_REGISTRY_nullptr_USER_TOKEN).toString().compare("true", Qt::CaseInsensitive) == 0) { userRegistryKey.reset(nullptr); } // Determine primary and alternative registry locations. BlueBerry extension registry cache // can be found in one of the two locations: // a) in the local configuration area (standard location passed in by the platform) -> priority // b) in the shared configuration area (typically, shared install is used) QList registryLocations; QList readOnlyLocations; RegistryStrategy* strategy = nullptr; //Location configuration = OSGIUtils.getDefault().getConfigurationLocation(); QString configuration = context->getDataFile("").absoluteFilePath(); if (configuration.isEmpty()) { RegistryProperties::SetProperty(RegistryConstants::PROP_NO_REGISTRY_CACHE, "true"); RegistryProperties::SetProperty(RegistryConstants::PROP_NO_LAZY_REGISTRY_CACHE_LOADING, "true"); strategy = new RegistryStrategy(QList(), QList(), masterRegistryKey.data()); } else { //File primaryDir = new File(configuration.getURL().getPath() + '/' + STORAGE_DIR); //bool primaryReadOnly = configuration.isReadOnly(); QString primaryDir = configuration; bool primaryReadOnly = false; //Location parentLocation = configuration.getParentLocation(); QString parentLocation; if (!parentLocation.isEmpty()) { // File secondaryDir = new File(parentLocation.getURL().getFile() + '/' + IRegistryConstants.RUNTIME_NAME); // registryLocations << primaryDir << secondaryDir; // readOnlyLocations << primaryReadOnly << true; // secondary BlueBerry location is always read only } else { registryLocations << primaryDir; readOnlyLocations << primaryReadOnly; } strategy = new RegistryStrategy(registryLocations, readOnlyLocations, masterRegistryKey.data()); } auto registry = new ExtensionRegistry(strategy, masterRegistryKey.data(), userRegistryKey.data()); defaultRegistry.reset(registry); registryServiceReg = context->registerService(registry); //commandRegistration = EquinoxUtils.registerCommandProvider(Activator.getContext()); } void org_blueberry_core_runtime_Activator::stopRegistry() { if (!defaultRegistry.isNull()) { registryServiceReg.unregister(); defaultRegistry->Stop(masterRegistryKey.data()); } // if (!commandRegistration.isNull()) // { // commandRegistration.unregister(); // } } void org_blueberry_core_runtime_Activator::startAppContainer() { appContainer.reset(new ApplicationContainer(context, defaultRegistry.data())); appContainer->Start(); } void org_blueberry_core_runtime_Activator::stopAppContainer() { appContainer->Stop(); } } diff --git a/Plugins/org.blueberry.core.runtime/src/internal/berryProductExtensionBranding.cpp b/Plugins/org.blueberry.core.runtime/src/internal/berryProductExtensionBranding.cpp index 2bfa5131d4..409824922f 100644 --- a/Plugins/org.blueberry.core.runtime/src/internal/berryProductExtensionBranding.cpp +++ b/Plugins/org.blueberry.core.runtime/src/internal/berryProductExtensionBranding.cpp @@ -1,92 +1,92 @@ /*============================================================================ 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 "berryProductExtensionBranding.h" #include #include #include #include "berryCTKPluginActivator.h" namespace berry { const QString ProductExtensionBranding::ATTR_DESCRIPTION = "description"; const QString ProductExtensionBranding::ATTR_NAME = "name"; const QString ProductExtensionBranding::ATTR_APPLICATION = "application"; const QString ProductExtensionBranding::ATTR_VALUE = "value"; ProductExtensionBranding::ProductExtensionBranding(const QString& id, const SmartPointer& element) : id(id) { if (element.IsNull()) return; application = element->GetAttribute(ATTR_APPLICATION); name = element->GetAttribute(ATTR_NAME); description = element->GetAttribute(ATTR_DESCRIPTION); LoadProperties(element); } QSharedPointer ProductExtensionBranding::GetDefiningPlugin() const { return definingPlugin; } QString ProductExtensionBranding::GetApplication() const { return application; } QString ProductExtensionBranding::GetName() const { return name; } QString ProductExtensionBranding::GetDescription() const { return description; } QString ProductExtensionBranding::GetId() const { return id; } QString ProductExtensionBranding::GetProperty(const QString& key) const { auto iter = properties.find(key); return iter != properties.end() ? iter.value() : QString(); } SmartPointer ProductExtensionBranding::GetProduct() const { return IProduct::Pointer(); } void ProductExtensionBranding::LoadProperties(const SmartPointer& element) { QList children = element->GetChildren(); properties.clear(); - for (const auto &child : qAsConst(children)) + for (const auto &child : std::as_const(children)) { QString key = child->GetAttribute(ATTR_NAME); QString value = child->GetAttribute(ATTR_VALUE); if (!key.isEmpty() && !value.isEmpty()) { properties.insert(key, value); } } definingPlugin = org_blueberry_core_runtime_Activator::GetPlugin(element->GetContributor()); } } diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryChangeToPerspectiveMenu.cpp b/Plugins/org.blueberry.ui.qt/src/internal/berryChangeToPerspectiveMenu.cpp index f4657ee302..f820a434c1 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryChangeToPerspectiveMenu.cpp +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryChangeToPerspectiveMenu.cpp @@ -1,251 +1,251 @@ /*============================================================================ 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 "berryChangeToPerspectiveMenu.h" #include #include #include #include #include #include #include #include #include #include #include "berryCommandContributionItemParameter.h" #include "berryWorkbenchPlugin.h" #include "berryWorkbenchPreferenceConstants.h" #include "berryPreferenceConstants.h" #include #include namespace berry { const QString ChangeToPerspectiveMenu::NO_TARGETS_MSG = ""; bool PerspectiveComparator(const IPerspectiveDescriptor::Pointer& d1, const IPerspectiveDescriptor::Pointer& d2) { return d1->GetLabel() < d2->GetLabel(); } ChangeToPerspectiveMenu::ChangeToPerspectiveMenu(IWorkbenchWindow* window, const QString& id) : ContributionItem(id) , window(window) , reg(window->GetWorkbench()->GetPerspectiveRegistry()) , showActive(true) , dirty(true) { CommandContributionItemParameter::Pointer showDlgItemParms( new CommandContributionItemParameter( window, QString(), IWorkbenchCommandConstants::PERSPECTIVES_SHOW_PERSPECTIVE, CommandContributionItem::STYLE_PUSH)); showDlgItemParms->label = "&Other..."; showDlgItem = new CommandContributionItem(showDlgItemParms); // indicate that a open perspectives submenu has been created /* if (WorkbenchWindow* window = dynamic_cast(window)) { window->AddSubmenu(WorkbenchWindow::OPEN_PERSPECTIVE_SUBMENU); } */ } void ChangeToPerspectiveMenu::Fill(QMenu* menu, QAction* before) { if (MenuManager* mm = dynamic_cast(GetParent())) { this->connect(mm, SIGNAL(AboutToShow(IMenuManager*)), SLOT(AboutToShow(IMenuManager*))); } if (!dirty) { return; } MenuManager::Pointer manager(new MenuManager("")); FillMenu(manager.GetPointer()); QList items = manager->GetItems(); if (items.isEmpty()) { auto action = new QAction(NO_TARGETS_MSG, menu); action->setEnabled(false); menu->insertAction(before, action); } else { foreach (IContributionItem::Pointer item, items) { item->Fill(menu, before); } } dirty = false; } bool ChangeToPerspectiveMenu::IsDirty() const { return dirty; } bool ChangeToPerspectiveMenu::IsDynamic() const { return true; } void ChangeToPerspectiveMenu::AboutToShow(IMenuManager* manager) { manager->MarkDirty(); dirty = true; } void ChangeToPerspectiveMenu::FillMenu(IMenuManager* manager) { // Clear out the manager so that we have a blank slate. manager->RemoveAll(); // Collect and sort perspective descriptors. QList persps = GetPerspectiveShortcuts(); std::sort(persps.begin(), persps.end(), PerspectiveComparator); /* * Convert the perspective descriptors to command parameters, and filter * using the activity/capability mechanism. */ - for (const IPerspectiveDescriptor::Pointer &descriptor : qAsConst(persps)) + for (const IPerspectiveDescriptor::Pointer &descriptor : std::as_const(persps)) { CommandContributionItemParameter::Pointer ccip = GetItem(descriptor); // if (WorkbenchActivityHelper.filterItem(ccip)) { // continue; // } CommandContributionItem::Pointer item(new CommandContributionItem(ccip)); manager->Add(item); } auto* prefs = WorkbenchPlugin::GetDefault()->GetPreferences(); bool showOther = prefs->GetBool(WorkbenchPreferenceConstants::SHOW_OTHER_IN_PERSPECTIVE_MENU, true); if (showOther) { // Add a separator and then "Other..." if (!manager->IsEmpty()) { IContributionItem::Pointer separator(new Separator()); manager->Add(separator); } manager->Add(showDlgItem); } } SmartPointer ChangeToPerspectiveMenu::GetItem(const IPerspectiveDescriptor::Pointer& desc) const { auto* prefs = WorkbenchPlugin::GetDefault()->GetPreferences(); int mode = prefs->GetInt(PreferenceConstants::OPEN_PERSP_MODE, PreferenceConstants::OPM_ACTIVE_PAGE); IWorkbenchPage::Pointer page = window->GetActivePage(); IPerspectiveDescriptor::Pointer persp; if (page.IsNotNull()) { persp = page->GetPerspective(); } QString perspId = desc->GetId(); class PluginCCIP : public CommandContributionItemParameter, public IPluginContribution { QString localId; QString pluginId; public: typedef PluginCCIP Self; static const char* GetStaticClassName() { return "PluginCCIP"; } berryObjectTypeInfo(CommandContributionItemParameter, IPluginContribution) PluginCCIP(const IPerspectiveDescriptor::Pointer& v, IServiceLocator* serviceLocator, const QString& id, const QString& commandId, CommandContributionItem::Style style) : CommandContributionItemParameter(serviceLocator, id, commandId, style) { PerspectiveDescriptor::Pointer vd = v.Cast(); localId = vd->GetLocalId(); pluginId = vd->GetPluginId(); } QString GetLocalId() const override { return localId; } QString GetPluginId() const override { return pluginId; } }; CommandContributionItemParameter::Pointer parms(new PluginCCIP(desc, window, perspId, IWorkbenchCommandConstants::PERSPECTIVES_SHOW_PERSPECTIVE, CommandContributionItem::STYLE_PUSH)); parms->label = desc->GetLabel(); parms->icon = desc->GetImageDescriptor(); Object::Pointer strId(new ObjectString(perspId)); parms->parameters.insert(IWorkbenchCommandConstants::PERSPECTIVES_SHOW_PERSPECTIVE_PARM_ID, strId); // Only open a new window if user preference is set and the window // has an active perspective. if (PreferenceConstants::OPM_NEW_WINDOW == mode && persp.IsNotNull()) { Object::Pointer bNewWnd(new ObjectBool(true)); parms->parameters.insert(IWorkbenchCommandConstants::PERSPECTIVES_SHOW_PERSPECTIVE_PARM_NEWWINDOW, bNewWnd); } return parms; } QList > ChangeToPerspectiveMenu::GetPerspectiveShortcuts() const { QList list; IWorkbenchPage::Pointer page = window->GetActivePage(); if (page.IsNull()) { return list; } QList ids = page->GetPerspectiveShortcuts(); for (int i = 0; i < ids.size(); i++) { IPerspectiveDescriptor::Pointer desc = reg->FindPerspectiveWithId(ids[i]); if (desc.IsNotNull() && !list.contains(desc)) { /* if (WorkbenchActivityHelper::FilterItem(desc)) { continue; } */ list.push_back(desc); } } return list; } } diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryPreferencePageParameterValues.cpp b/Plugins/org.blueberry.ui.qt/src/internal/berryPreferencePageParameterValues.cpp index 2c1c25354e..e942c99d24 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryPreferencePageParameterValues.cpp +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryPreferencePageParameterValues.cpp @@ -1,74 +1,74 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "berryPreferencePageParameterValues.h" #include "berryPlatform.h" #include "berryPlatformUI.h" #include "berryWorkbenchRegistryConstants.h" #include "berryIConfigurationElement.h" #include "berryIExtensionRegistry.h" #include "berryIWorkbench.h" namespace berry { PreferencePageParameterValues::PreferencePageParameterValues() { QString xpId = PlatformUI::PLUGIN_ID() + "." + WorkbenchRegistryConstants::PL_PREFERENCES; Platform::GetExtensionRegistry()->AddListener(this, xpId); } QHash PreferencePageParameterValues::GetParameterValues() const { if (preferenceMap.empty()) { IExtensionRegistry* registry = Platform::GetExtensionRegistry(); if (registry) { QList configElements = registry->GetConfigurationElementsFor(PlatformUI::PLUGIN_ID(), WorkbenchRegistryConstants::PL_PREFERENCES); - for (const auto &configElement : qAsConst(configElements)) + for (const auto &configElement : std::as_const(configElements)) { if(configElement->GetName() == "page") { preferenceMap.insert(configElement->GetAttribute("name"), configElement->GetAttribute("id")); } } } } return preferenceMap; } void PreferencePageParameterValues::Added(const QList >& /*extensions*/) { preferenceMap.clear(); } void berry::PreferencePageParameterValues::Removed(const QList >& /*extensions*/) { preferenceMap.clear(); } void PreferencePageParameterValues::Added(const QList >& /*extensionPoints*/) { preferenceMap.clear(); } void PreferencePageParameterValues::Removed(const QList >& /*extensionPoints*/) { preferenceMap.clear(); } } diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryQtShowViewDialog.cpp b/Plugins/org.blueberry.ui.qt/src/internal/berryQtShowViewDialog.cpp index 7c801ef93e..51bda7e93a 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryQtShowViewDialog.cpp +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryQtShowViewDialog.cpp @@ -1,328 +1,328 @@ /*============================================================================ 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 "berryQtShowViewDialog.h" #include #include #include "berryWorkbenchPlugin.h" #include "berryXMLMemento.h" #include #include #include namespace berry { static const QString TAG_SHOWVIEWDIALOG = "ShowViewDialog"; static const QString TAG_CATEGORY = "category"; static const QString TAG_SELECTION = "selection"; static const QString TAG_GEOMETRY = "geometry"; class ViewFilterProxyModel : public QSortFilterProxyModel { public: ViewFilterProxyModel(QObject* parent = nullptr) : QSortFilterProxyModel(parent) , m_FilterOnKeywords(true) { this->setFilterCaseSensitivity(Qt::CaseInsensitive); } bool filterOnKeywords() const { return m_FilterOnKeywords; } void setFilterOnKeywords(bool filterOnKeywords) { if (m_FilterOnKeywords != filterOnKeywords) { m_FilterOnKeywords = filterOnKeywords; this->invalidateFilter(); } } protected: bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override { QRegularExpression regExp = filterRegularExpression(); if (!regExp.isValid() || regExp.pattern().isEmpty()) return true; QModelIndex sourceIndex = sourceModel()->index(sourceRow, 0, sourceParent); QStringList keywords; if (m_FilterOnKeywords) { keywords = sourceModel()->data(sourceIndex, ViewTreeModel::Keywords).toStringList(); } else { if (sourceModel()->hasChildren(sourceIndex)) { // this is a category item int numChildren = sourceModel()->rowCount(sourceIndex); for (int i = 0; i < numChildren; ++i) { keywords.push_back(sourceModel()->data(sourceModel()->index(i, 0, sourceIndex)).toString()); } } else { // this is a view item keywords.push_back(sourceModel()->data(sourceIndex).toString()); } } for(auto& keyword : keywords) { if (keyword.contains(regExp)) return true; } return false; } private: bool m_FilterOnKeywords; }; QtShowViewDialog::QtShowViewDialog(const IWorkbenchWindow* window, IViewRegistry* registry, QWidget* parent, Qt::WindowFlags f) : QDialog(parent, f) , m_Window(window) , m_ViewReg(registry) , m_FilterModel(nullptr) { m_UserInterface.setupUi(this); m_UserInterface.m_TreeView->header()->setVisible(false); m_UserInterface.m_TreeView->setSelectionMode(QAbstractItemView::ExtendedSelection); m_FilterModel = new ViewFilterProxyModel(this); auto sourceModel = new ViewTreeModel(window, m_FilterModel); m_FilterModel->setSourceModel(sourceModel); m_UserInterface.m_TreeView->setModel(m_FilterModel); connect(m_UserInterface.m_Filter, SIGNAL(textChanged(QString)), this, SLOT(setFilter(QString))); connect(m_UserInterface.m_TreeView, SIGNAL(clicked(QModelIndex)), this, SLOT(setDescription(QModelIndex))); connect(m_UserInterface.m_TreeView, SIGNAL(collapsed(QModelIndex)), this, SLOT(categoryCollapsed(QModelIndex))); connect(m_UserInterface.m_TreeView, SIGNAL(expanded(QModelIndex)), this, SLOT(categoryExpanded(QModelIndex))); connect(m_UserInterface.m_TreeView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(accept())); connect(m_UserInterface.m_TreeView, SIGNAL(activated(QModelIndex)), this, SLOT(accept())); connect(m_UserInterface.m_TreeView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(selectionChanged(QItemSelection,QItemSelection))); connect(m_UserInterface.m_KeywordFilter, SIGNAL(clicked(bool)), this, SLOT(enableKeywordFilter(bool))); this->RestoreState(); m_UserInterface.m_Filter->selectAll(); this->UpdateButtons(); } void QtShowViewDialog::setDescription(const QModelIndex& index) { QString description = m_UserInterface.m_TreeView->model()->data(index, Qt::WhatsThisRole).toString(); m_UserInterface.m_Description->setText(description); } void QtShowViewDialog::enableKeywordFilter(bool enable) { m_FilterModel->setFilterOnKeywords(enable); this->RestoreExpandedState(); } void QtShowViewDialog::setFilter(const QString& filter) { m_FilterModel->setFilterWildcard(filter); this->RestoreExpandedState(); } void QtShowViewDialog::categoryCollapsed(const QModelIndex& index) { m_ExpandedCategories.removeAll(m_FilterModel->mapToSource(index)); } void QtShowViewDialog::categoryExpanded(const QModelIndex& index) { m_ExpandedCategories.push_back(m_FilterModel->mapToSource(index)); } void QtShowViewDialog::selectionChanged(const QItemSelection& /*selected*/, const QItemSelection& /*deselected*/) { UpdateButtons(); } void QtShowViewDialog::RestoreExpandedState() { int rowCount = m_FilterModel->rowCount(); for (int i = 0; i < rowCount; ++i) { QModelIndex index = m_FilterModel->index(i, 0); if (m_ExpandedCategories.contains(m_FilterModel->mapToSource(index))) { m_UserInterface.m_TreeView->expand(index); } } } void QtShowViewDialog::UpdateButtons() { QPushButton* okBtn = m_UserInterface.m_ButtonBox->button(QDialogButtonBox::Ok); if (okBtn) { okBtn->setEnabled(!m_UserInterface.m_TreeView->selectionModel()->selection().isEmpty()); } } void QtShowViewDialog::RestoreState() { auto* prefs = WorkbenchPlugin::GetDefault()->GetPreferences(); auto str = QString::fromStdString(prefs->Get(TAG_SHOWVIEWDIALOG.toStdString(), "")); if (str.isEmpty()) return; std::stringstream ss(str.toStdString()); XMLMemento::Pointer memento = XMLMemento::CreateReadRoot(ss); bool keywordFilter = false; if (memento->GetBoolean("keywordFilter", keywordFilter)) { m_UserInterface.m_KeywordFilter->setChecked(keywordFilter); m_FilterModel->setFilterOnKeywords(keywordFilter); } QString filter; if (memento->GetString("filter", filter)) { m_UserInterface.m_Filter->setText(filter); } IMemento::Pointer geomChild = memento->GetChild(TAG_GEOMETRY); if (geomChild.IsNotNull()) { QString geom = geomChild->GetTextData(); if (!geom.isEmpty()) { QByteArray ba = QByteArray::fromBase64(geom.toLatin1()); this->restoreGeometry(ba); } } QHash rootIndices; int rowCount = m_FilterModel->sourceModel()->rowCount(); for (int i = 0; i < rowCount; ++i) { QModelIndex sourceIndex = m_FilterModel->sourceModel()->index(i, 0); QString id = sourceIndex.data(ViewTreeModel::Id).toString(); if (!id.isEmpty()) { rootIndices[id] = sourceIndex; } } for (const IMemento::Pointer &categoryChild : memento->GetChildren(TAG_CATEGORY)) { QString id = categoryChild->GetID(); if (!id.isEmpty()) { if (rootIndices.contains(id)) { m_ExpandedCategories.push_back(rootIndices[id]); } } } this->RestoreExpandedState(); QItemSelection itemSelection; for (const IMemento::Pointer &selectionChild : memento->GetChildren(TAG_SELECTION)) { QString id = selectionChild->GetID(); if (!id.isEmpty()) { QModelIndexList indexList = m_FilterModel->match(m_FilterModel->index(0, 0), ViewTreeModel::Id, QVariant::fromValue(id), 1, Qt::MatchExactly | Qt::MatchRecursive); if (!indexList.isEmpty()) { QItemSelection subSelection(indexList.front(), indexList.front()); itemSelection.merge(subSelection, QItemSelectionModel::SelectCurrent); } } } m_UserInterface.m_TreeView->selectionModel()->select(itemSelection, QItemSelectionModel::ClearAndSelect); } void QtShowViewDialog::SaveState() { XMLMemento::Pointer memento = XMLMemento::CreateWriteRoot(TAG_SHOWVIEWDIALOG); memento->PutString("filter", m_UserInterface.m_Filter->text()); memento->PutBoolean("keywordFilter", m_UserInterface.m_KeywordFilter->isChecked()); // dialog geometry QByteArray geom = this->saveGeometry(); IMemento::Pointer geomChild = memento->CreateChild(TAG_GEOMETRY); geomChild->PutTextData(geom.toBase64().constData()); // expanded categories - for (const QPersistentModelIndex &index : qAsConst(m_ExpandedCategories)) + for (const QPersistentModelIndex &index : std::as_const(m_ExpandedCategories)) { if (index.isValid()) { QString id = index.data(ViewTreeModel::Id).toString(); if (!id.isEmpty()) { memento->CreateChild(TAG_CATEGORY, id); } } } // we only record a single selected item. restoring a multi-selection might be // confusing for the user QModelIndexList selectedIndices = m_UserInterface.m_TreeView->selectionModel()->selectedIndexes(); if (!selectedIndices.isEmpty()) { QString id = selectedIndices.back().data(ViewTreeModel::Id).toString(); if (!id.isEmpty()) { memento->CreateChild(TAG_SELECTION, id); } } std::stringstream ss; memento->Save(ss); auto* prefs = WorkbenchPlugin::GetDefault()->GetPreferences(); prefs->Put(TAG_SHOWVIEWDIALOG.toStdString(), ss.str()); prefs->Flush(); } void QtShowViewDialog::done(int r) { this->SaveState(); QDialog::done(r); } QList QtShowViewDialog::GetSelection() const { QList selected; QModelIndexList indices = m_UserInterface.m_TreeView->selectionModel()->selectedIndexes(); - for(QModelIndex index : qAsConst(indices)) + for(QModelIndex index : std::as_const(indices)) { QString id = m_FilterModel->data(index, ViewTreeModel::Id).toString(); selected.push_back(id); } return selected; } } diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berrySwitchToWindowMenu.cpp b/Plugins/org.blueberry.ui.qt/src/internal/berrySwitchToWindowMenu.cpp index c92f6dad15..f882dff528 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/berrySwitchToWindowMenu.cpp +++ b/Plugins/org.blueberry.ui.qt/src/internal/berrySwitchToWindowMenu.cpp @@ -1,155 +1,155 @@ /*============================================================================ 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 "berrySwitchToWindowMenu.h" #include #include #include #include #include #include #include #include namespace berry { void SwitchToWindowMenu::AboutToShow(IMenuManager* manager) { manager->MarkDirty(); dirty = true; } void SwitchToWindowMenu::MenuItemTriggered(int index) { if (index < 0 || index >= windows.size()) return; IWorkbenchWindow* window = windows[index]; Shell::Pointer windowShell = window->GetShell(); if (windowShell->GetMinimized()) { windowShell->SetMinimized(false); } windowShell->SetActive(); windowShell->GetControl()->raise(); } QString SwitchToWindowMenu::CalcText(int number, IWorkbenchWindow* window) { QString suffix = window->GetShell()->GetText(); if (suffix.isEmpty()) { return QString(); } QString sb; if (number < 10) { sb.append('&'); } sb.append(QString::number(number)); sb.append(' '); if (suffix.size() <= MAX_TEXT_LENGTH) { sb.append(suffix); } else { sb.append(QStringView(suffix).left(MAX_TEXT_LENGTH)); sb.append("..."); } return sb; } SwitchToWindowMenu::SwitchToWindowMenu(IWorkbenchWindow* window, const QString& id, bool showSeparator) : ContributionItem(id) , workbenchWindow(window) , showSeparator(showSeparator) , dirty(true) { } void SwitchToWindowMenu::Fill(QMenu* menu, QAction* before) { // Get workbench windows. IWorkbench* workbench = workbenchWindow->GetWorkbench(); windows.clear(); for (const auto &window : workbench->GetWorkbenchWindows()) { windows.push_back(window.GetPointer()); } // avoid showing the separator and list for 0 or 1 items if (windows.size() < 2) { return; } if (MenuManager* mm = dynamic_cast(GetParent())) { this->connect(mm, SIGNAL(AboutToShow(IMenuManager*)), SLOT(AboutToShow(IMenuManager*))); } if (!dirty) { return; } // Add separator. if (showSeparator) { menu->insertSeparator(before); } // Add one item for each window. auto actionGroup = new QActionGroup(menu); actionGroup->setExclusive(true); auto signalMapper = new QSignalMapper(menu); connect(signalMapper, SIGNAL(mapped(int)), SLOT(MenuItemTriggered(int))); int count = 0; - for (auto window : qAsConst(windows)) + for (auto window : std::as_const(windows)) { // can encounter disposed shells if this update is in response to a shell closing //if (!window->GetShell()->IsDisposed()) //{ QString name = CalcText(count, window); if (!name.isEmpty()) { auto mi = new QAction(name, menu); mi->setCheckable(true); mi->setChecked(window == workbenchWindow); actionGroup->addAction(mi); menu->insertAction(before, mi); signalMapper->setMapping(mi, count); connect(mi, SIGNAL(triggered()), signalMapper, SLOT(map())); } ++count; } //} dirty = false; } bool SwitchToWindowMenu::IsDirty() const { return dirty; } bool SwitchToWindowMenu::IsDynamic() const { return true; } } diff --git a/Plugins/org.blueberry.ui.qt/src/internal/dialogs/berryPerspectivesPreferencePage.cpp b/Plugins/org.blueberry.ui.qt/src/internal/dialogs/berryPerspectivesPreferencePage.cpp index ad0a0a8df1..89ef9a6060 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/dialogs/berryPerspectivesPreferencePage.cpp +++ b/Plugins/org.blueberry.ui.qt/src/internal/dialogs/berryPerspectivesPreferencePage.cpp @@ -1,292 +1,292 @@ /*============================================================================ 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 "berryPerspectivesPreferencePage.h" #include "ui_berryPerspectivesPreferencePage.h" #include #include "internal/berryPerspective.h" #include "internal/berryPerspectiveRegistry.h" #include "internal/berryPreferenceConstants.h" #include "internal/berryWorkbenchPage.h" #include "berryWorkbenchPlugin.h" #include #include #include namespace { mitk::IPreferences* GetPreferences() { return berry::WorkbenchPlugin::GetDefault()->GetPreferences(); } } namespace berry { bool PerspectiveComparator(const PerspectiveDescriptor::Pointer& p1, const PerspectiveDescriptor::Pointer& p2) { return p1->GetLabel() < p2->GetLabel(); } PerspectivesPreferencePage::PerspectivesPreferencePage() : ui(nullptr) , pageWidget(nullptr) , workbench(nullptr) , perspRegistry(nullptr) { } PerspectivesPreferencePage::~PerspectivesPreferencePage() { delete ui; } void PerspectivesPreferencePage::Init(berry::IWorkbench::Pointer workbench) { ui = new Ui::PerspectivesPreferencePage; this->workbench = workbench.GetPointer(); perspRegistry = dynamic_cast(workbench->GetPerspectiveRegistry()); } void PerspectivesPreferencePage::CreateQtControl(QWidget* parent) { pageWidget = new QWidget(parent); ui->setupUi(pageWidget); ui->perspectivesListWidget->setSelectionMode(QAbstractItemView::SingleSelection); ui->perspectivesListWidget->setIconSize(QSize(16, 16)); connect(ui->sameWindowButton, SIGNAL(clicked()), this, SLOT(OpenPerspInSameWindow())); connect(ui->newWindowButton, SIGNAL(clicked()), this, SLOT(OpenPerspInNewWindow())); connect(ui->perspectivesListWidget, SIGNAL(itemSelectionChanged()), this, SLOT(PerspectiveSelectionChanged())); connect(ui->revertButton, SIGNAL(clicked()), this, SLOT(RevertPerspective())); connect(ui->makeDefaultButton, SIGNAL(clicked()), this, SLOT(MakeDefaultPerspective())); connect(ui->deleteButton, SIGNAL(clicked()), this, SLOT(DeletePerspective())); this->Update(); } QWidget* PerspectivesPreferencePage::GetQtControl() const { return pageWidget; } bool PerspectivesPreferencePage::PerformOk() { // Set the default perspective if (defaultPerspectiveId != perspRegistry->GetDefaultPerspective()) { perspRegistry->SetDefaultPerspective(defaultPerspectiveId); } //Delete the perspective if(perspectives.size() < perspRegistry->GetPerspectives().size()) { QList windows = workbench->GetWorkbenchWindows(); // close any perspectives that are about to be deleted for (int i = 0; i < windows.size(); i++) { QList pages = windows[i]->GetPages(); for (int j = 0; j < pages.size(); j++) { WorkbenchPage::Pointer page = pages[j].Cast(); for (int k = 0; k < perspToDelete.size(); k++) { IPerspectiveDescriptor::Pointer desc(perspToDelete[k].GetPointer()); if (page->FindPerspective(desc).IsNotNull()) { page->ClosePerspective(desc, true, true); } } } } perspRegistry->DeletePerspectives(perspToDelete); } // Revert the perspectives perspRegistry->RevertPerspectives(perspToRevert); // store the open perspective mode setting auto* prefs = GetPreferences(); prefs->PutInt(PreferenceConstants::OPEN_PERSP_MODE, openPerspMode); return true; } void PerspectivesPreferencePage::PerformCancel() { } void PerspectivesPreferencePage::Update() { auto* prefs = GetPreferences(); openPerspMode = prefs->GetInt(PreferenceConstants::OPEN_PERSP_MODE, PreferenceConstants::OPM_ACTIVE_PAGE); ui->sameWindowButton->setChecked(openPerspMode == PreferenceConstants::OPM_ACTIVE_PAGE); ui->newWindowButton->setChecked(openPerspMode == PreferenceConstants::OPM_NEW_WINDOW); // Populate the perspectivesTable perspectives.clear(); perspToRevert.clear(); perspToDelete.clear(); QList persps = perspRegistry->GetPerspectives(); for (int i = 0; i < persps.size(); i++) { perspectives.push_back(persps[i].Cast()); } std::sort(perspectives.begin(), perspectives.end(), PerspectiveComparator); defaultPerspectiveId = perspRegistry->GetDefaultPerspective(); UpdatePerspectivesTable(); } void PerspectivesPreferencePage::OpenPerspInSameWindow() { openPerspMode = PreferenceConstants::OPM_ACTIVE_PAGE; } void PerspectivesPreferencePage::OpenPerspInNewWindow() { openPerspMode = PreferenceConstants::OPM_NEW_WINDOW; } void PerspectivesPreferencePage::PerspectiveSelectionChanged() { UpdateButtons(); } void PerspectivesPreferencePage::RevertPerspective() { PerspectiveDescriptor::Pointer desc = GetSelectedPerspective(); if (desc.IsNotNull() && !perspToRevert.contains(desc)) { perspToRevert.push_back(desc); } UpdateButtons(); } void PerspectivesPreferencePage::DeletePerspective() { PerspectiveDescriptor::Pointer desc = GetSelectedPerspective(); if (desc.IsNotNull() && !perspToDelete.contains(desc)) { if (!FindOpenInstance(desc)) { perspToDelete.push_back(desc); perspToRevert.removeAll(desc); perspectives.removeAll(desc); UpdatePerspectivesTable(); } } UpdateButtons(); } void PerspectivesPreferencePage::MakeDefaultPerspective() { PerspectiveDescriptor::Pointer desc = GetSelectedPerspective(); if (desc.IsNotNull() && !perspToDelete.contains(desc)) { int row = perspectives.indexOf(desc); defaultPerspectiveId = desc->GetId(); UpdatePerspectivesTable(); ui->perspectivesListWidget->item(row)->setSelected(true); } UpdateButtons(); } void PerspectivesPreferencePage::UpdateButtons() { PerspectiveDescriptor::Pointer desc = GetSelectedPerspective(); if (desc) { ui->revertButton->setEnabled(desc->IsPredefined() && desc->HasCustomDefinition() && !perspToRevert.contains(desc)); ui->deleteButton->setEnabled(!desc->IsPredefined()); ui->makeDefaultButton->setEnabled(true); } else { ui->revertButton->setEnabled(false); ui->deleteButton->setEnabled(false); ui->makeDefaultButton->setEnabled(false); } } void PerspectivesPreferencePage::UpdatePerspectivesTable() { ui->perspectivesListWidget->clear(); - for (const PerspectiveDescriptor::Pointer &desc : qAsConst(perspectives)) + for (const PerspectiveDescriptor::Pointer &desc : std::as_const(perspectives)) { NewPerspectivesTableItem(desc); } } void PerspectivesPreferencePage::NewPerspectivesTableItem(const SmartPointer& desc) { QString label = desc->GetLabel(); if (desc->GetId() == defaultPerspectiveId) { label += " (default)"; } new QListWidgetItem(desc->GetImageDescriptor(), label, ui->perspectivesListWidget); } bool PerspectivesPreferencePage::FindOpenInstance(const PerspectiveDescriptor::Pointer& desc) { QList windows = workbench->GetWorkbenchWindows(); //find all active perspectives currently for (int i = 0; i < windows.size(); i++) { QList pages = windows[i]->GetPages(); for (int j = 0; j < pages.size(); j++) { WorkbenchPage::Pointer page = pages[j].Cast(); if (page->FindPerspective(desc).IsNotNull()) { QMessageBox::StandardButton returnCode = QMessageBox::question(workbench->GetActiveWorkbenchWindow()->GetShell()->GetControl(), "Delete Perspective", QString("Are you sure you want to delete the \"%1\" perspective? It has open instances.").arg(desc->GetLabel()), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); return (returnCode != QMessageBox::Yes); } } } return false; } SmartPointer PerspectivesPreferencePage::GetSelectedPerspective() const { PerspectiveDescriptor::Pointer desc; QList selection = ui->perspectivesListWidget->selectedItems(); if (!selection.isEmpty()) { int row = ui->perspectivesListWidget->row(selection.back()); if (row > -1) { desc = perspectives.at(row); } } return desc; } } diff --git a/Plugins/org.blueberry.ui.qt/src/model/berryViewTreeModel.cpp b/Plugins/org.blueberry.ui.qt/src/model/berryViewTreeModel.cpp index 93d035151b..71a4a90ae2 100644 --- a/Plugins/org.blueberry.ui.qt/src/model/berryViewTreeModel.cpp +++ b/Plugins/org.blueberry.ui.qt/src/model/berryViewTreeModel.cpp @@ -1,461 +1,461 @@ /*============================================================================ 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 "berryViewTreeModel.h" #include "berryIViewRegistry.h" #include "berryIViewCategory.h" #include "berryIWorkbench.h" #include "berryIWorkbenchWindow.h" #include "berryIWorkbenchPage.h" #include "internal/intro/berryIntroConstants.h" #include "internal/berryKeywordRegistry.h" #include #include #include namespace berry { // --------------------------- Tree Item Classes --------------------------- struct ViewTreeItem; bool CompareViewTreeItem(ViewTreeItem* item1, ViewTreeItem* item2); struct ViewTreeItem { ViewTreeItem(ViewTreeModel* model) : m_parent(nullptr) , m_model(model) {} virtual ~ViewTreeItem() { QList children = m_children; if (m_parent) m_parent->removeChild(this); qDeleteAll(children); } virtual QVariant data(int role) { if (role == ViewTreeModel::Keywords) { if (m_keywordCache.isEmpty()) { m_keywordCache = keywordLabels().values(); } return m_keywordCache; } return QVariant(); } virtual Qt::ItemFlags flags() const { return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } virtual QSet keywordLabels() const { return QSet(); } void appendChild(ViewTreeItem* child) { m_children.push_back(child); child->m_parent = this; std::sort(m_children.begin(), m_children.end(), CompareViewTreeItem); } void removeChild(ViewTreeItem* child) { m_children.removeAll(child); } QList takeChildren() { QList children = m_children; m_children.clear(); return children; } ViewTreeItem* childItem(int row) const { if (row < 0 || row >= m_children.size()) return nullptr; return m_children.at(row); } ViewTreeItem* parentItem() const { return m_parent; } int childCount() const { return m_children.size(); } int row() const { if (m_parent) return m_parent->rowIndex(this); return 0; } int rowIndex(const ViewTreeItem* child) const { return m_children.indexOf(const_cast(child)); } QList m_children; ViewTreeItem* m_parent; ViewTreeModel* m_model; private: QStringList m_keywordCache; }; bool CompareViewTreeItem(ViewTreeItem* item1, ViewTreeItem* item2) { return item1->data(Qt::DisplayRole).toString() < item2->data(Qt::DisplayRole).toString(); } struct RootTreeItem : ViewTreeItem { RootTreeItem(ViewTreeModel* model) : ViewTreeItem(model) {} QVariant data(int /*role*/) override { return QVariant(); } }; struct DescriptorTreeItem : ViewTreeItem { DescriptorTreeItem(ViewTreeModel* model, IViewDescriptor::Pointer descriptor, ViewTreeItem* parent = nullptr); QVariant data(int role) override; protected: QSet keywordLabels() const override; IViewDescriptor::Pointer m_descriptor; }; struct CategoryTreeItem : ViewTreeItem { CategoryTreeItem(ViewTreeModel* model, IViewCategory::Pointer category, ViewTreeItem* parent = nullptr); QVariant data(int role) override; Qt::ItemFlags flags() const override; protected: QSet keywordLabels() const override; /** * Removes the temporary intro view from the list so that it cannot be activated except through * the introduction command. */ void RemoveIntroView(QList& list); private: void CreateChildren(); IViewCategory::Pointer m_category; }; // --------------------------- Tree Model Classes --------------------------- struct ViewTreeModel::Impl { Impl(const IWorkbenchWindow* window) : window(window) , viewRegistry(*window->GetWorkbench()->GetViewRegistry()) { } const IWorkbenchWindow* window; IViewRegistry& viewRegistry; QScopedPointer rootItem; }; ViewTreeModel::ViewTreeModel(const IWorkbenchWindow* window, QObject* parent) : QAbstractItemModel(parent) , d(new Impl(window)) { d->rootItem.reset(new RootTreeItem(this)); QList categoryItems; QList categories = d->viewRegistry.GetCategories(); - for (const auto &category : qAsConst(categories)) + for (const auto &category : std::as_const(categories)) { if (category->GetViews().isEmpty()) continue; CategoryTreeItem* categoryItem = new CategoryTreeItem(this, category); if (categoryItem->childCount() == 0) { delete categoryItem; } else { categoryItems.push_back(categoryItem); } } // if there is only one category, return it's children directly if (categoryItems.size() == 1) { QList items = categoryItems.front()->takeChildren(); - for (auto item : qAsConst(items)) + for (auto item : std::as_const(items)) { d->rootItem->appendChild(item); } qDeleteAll(categoryItems); } else { - for (auto category : qAsConst(categoryItems)) + for (auto category : std::as_const(categoryItems)) { d->rootItem->appendChild(category); } } } ViewTreeModel::~ViewTreeModel() { } QVariant ViewTreeModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); return static_cast(index.internalPointer())->data(role); } Qt::ItemFlags ViewTreeModel::flags(const QModelIndex& index) const { if (!index.isValid()) return {}; return static_cast(index.internalPointer())->flags(); } QVariant ViewTreeModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const { if (role == Qt::DisplayRole && section == 0) { return "View"; } return QVariant(); } QModelIndex ViewTreeModel::index(int row, int column, const QModelIndex& parent) const { if (!hasIndex(row, column, parent)) { return QModelIndex(); } ViewTreeItem* parentItem = nullptr; if (!parent.isValid()) { parentItem = d->rootItem.data(); } else { parentItem = static_cast(parent.internalPointer()); } ViewTreeItem* childItem = parentItem->childItem(row); if (childItem) { return createIndex(row, column, childItem); } return QModelIndex(); } QModelIndex ViewTreeModel::parent(const QModelIndex& child) const { if (!child.isValid()) { return QModelIndex(); } ViewTreeItem* childItem = static_cast(child.internalPointer()); ViewTreeItem* parentItem = childItem->parentItem(); if (parentItem == d->rootItem.data()) { return QModelIndex(); } return createIndex(parentItem->row(), 0, parentItem); } int ViewTreeModel::rowCount(const QModelIndex& parent) const { ViewTreeItem* parentItem = nullptr; if (parent.column() > 0) return 0; if (!parent.isValid()) { parentItem = d->rootItem.data(); } else { parentItem = static_cast(parent.internalPointer()); } return parentItem->childCount(); } int ViewTreeModel::columnCount(const QModelIndex& /*parent*/) const { return 1; } const IWorkbenchWindow*ViewTreeModel::GetWorkbenchWindow() const { return d->window; } // --------------------------- DescriptorTreeItem --------------------------- DescriptorTreeItem::DescriptorTreeItem(ViewTreeModel* model, IViewDescriptor::Pointer descriptor, ViewTreeItem* parent) : ViewTreeItem(model) , m_descriptor(descriptor) { if (parent) parent->appendChild(this); } QVariant DescriptorTreeItem::data(int role) { if (role == Qt::DisplayRole) { return m_descriptor->GetLabel(); } else if (role == Qt::DecorationRole) { return m_descriptor->GetImageDescriptor(); } else if (role == Qt::ForegroundRole) { IWorkbenchPage::Pointer page = this->m_model->GetWorkbenchWindow()->GetActivePage(); if (page.IsNotNull()) { if (page->FindViewReference(m_descriptor->GetId()).IsNotNull()) { return QBrush(QColor(Qt::gray)); } } } else if (role == ViewTreeModel::Description) { return m_descriptor->GetDescription(); } else if (role == ViewTreeModel::Id) { return m_descriptor->GetId(); } return ViewTreeItem::data(role); } QSet DescriptorTreeItem::keywordLabels() const { KeywordRegistry* registry = KeywordRegistry::GetInstance(); QStringList ids = m_descriptor->GetKeywordReferences(); QSet keywords; keywords.insert(m_descriptor->GetLabel()); - for(const auto &id : qAsConst(ids)) + for(const auto &id : std::as_const(ids)) { QString label = registry->GetKeywordLabel(id); for (const auto &keyword : label.split(' ', Qt::SkipEmptyParts)) { keywords.insert(keyword); } } return keywords; } // --------------------------- CategoryTreeItem --------------------------- CategoryTreeItem::CategoryTreeItem(ViewTreeModel* model, IViewCategory::Pointer category, ViewTreeItem* parent) : ViewTreeItem(model) , m_category(category) { if (parent) parent->appendChild(this); this->CreateChildren(); } QVariant CategoryTreeItem::data(int role) { if (role == Qt::DisplayRole) { return m_category->GetLabel(); } else if (role == Qt::DecorationRole) { return QIcon::fromTheme("folder"); } else if (role == ViewTreeModel::Id) { return m_category->GetId(); } return ViewTreeItem::data(role); } Qt::ItemFlags CategoryTreeItem::flags() const { return Qt::ItemIsEnabled; } QSet CategoryTreeItem::keywordLabels() const { QSet keywords; for(auto child : this->m_children) { for (const auto &keyword : child->data(ViewTreeModel::Keywords).toStringList()) { keywords.insert(keyword); } } return keywords; } void CategoryTreeItem::CreateChildren() { auto viewDescriptors = m_category->GetViews(); RemoveIntroView(viewDescriptors); - for(const auto &viewDescriptor : qAsConst(viewDescriptors)) + for(const auto &viewDescriptor : std::as_const(viewDescriptors)) { new DescriptorTreeItem(this->m_model, viewDescriptor, this); } } void CategoryTreeItem::RemoveIntroView(QList& list) { for (auto view = list.begin(); view != list.end();) { if ((*view)->GetId() == IntroConstants::INTRO_VIEW_ID) { view = list.erase(view); } else ++view; } } } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeContextMenu.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeContextMenu.cpp index 33107498da..9be4827ce2 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeContextMenu.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeContextMenu.cpp @@ -1,489 +1,489 @@ /*============================================================================ 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 #include #include #include #include QmitkDataNodeContextMenu::QmitkDataNodeContextMenu(berry::IWorkbenchPartSite::Pointer workbenchPartSite, QWidget* parent) : QMenu(parent), m_Parent(parent), m_WorkbenchPartSite(workbenchPartSite) { this->InitNodeDescriptors(); this->InitDefaultActions(); this->InitExtensionPointActions(); } QmitkDataNodeContextMenu::~QmitkDataNodeContextMenu() { for (auto& descriptorActionPair : m_DescriptorActionList) descriptorActionPair.first->RemoveAction(descriptorActionPair.second); } void QmitkDataNodeContextMenu::SetDataStorage(mitk::DataStorage* dataStorage) { m_DataStorage = dataStorage; for (auto& descriptorActionPair : m_DescriptorActionList) { auto dataNodeAction = dynamic_cast(descriptorActionPair.second); if (nullptr != dataNodeAction) dataNodeAction->SetDataStorage(dataStorage); } } void QmitkDataNodeContextMenu::SetBaseRenderer(mitk::BaseRenderer* baseRenderer) { m_BaseRenderer = baseRenderer; for (auto& descriptorActionPair : m_DescriptorActionList) { auto dataNodeAction = dynamic_cast(descriptorActionPair.second); if (nullptr != dataNodeAction) dataNodeAction->SetBaseRenderer(baseRenderer); } } void QmitkDataNodeContextMenu::SetSurfaceDecimation(bool surfaceDecimation) { m_SurfaceDecimation = surfaceDecimation; } void QmitkDataNodeContextMenu::SetSelectedNodes(const QList& selectedNodes) { m_SelectedNodes = selectedNodes; } void QmitkDataNodeContextMenu::InitNodeDescriptors() { auto nodeDescriptorManager = QmitkNodeDescriptorManager::GetInstance(); m_UnknownDataNodeDescriptor = nodeDescriptorManager->GetUnknownDataNodeDescriptor(); m_ImageDataNodeDescriptor = nodeDescriptorManager->GetDescriptor("Image"); m_MultiComponentImageDataNodeDescriptor = nodeDescriptorManager->GetDescriptor("MultiComponentImage"); m_DiffusionImageDataNodeDescriptor = nodeDescriptorManager->GetDescriptor("DiffusionImage"); m_FiberBundleDataNodeDescriptor = nodeDescriptorManager->GetDescriptor("FiberBundle"); m_PeakImageDataNodeDescriptor = nodeDescriptorManager->GetDescriptor("PeakImage"); m_SegmentDataNodeDescriptor = nodeDescriptorManager->GetDescriptor("Segment"); m_SurfaceDataNodeDescriptor = nodeDescriptorManager->GetDescriptor("Surface"); m_PointSetNodeDescriptor = nodeDescriptorManager->GetDescriptor("PointSet"); m_PlanarLineNodeDescriptor = nodeDescriptorManager->GetDescriptor("PlanarLine"); m_PlanarCircleNodeDescriptor = nodeDescriptorManager->GetDescriptor("PlanarCircle"); m_PlanarEllipseNodeDescriptor = nodeDescriptorManager->GetDescriptor("PlanarEllipse"); m_PlanarAngleNodeDescriptor = nodeDescriptorManager->GetDescriptor("PlanarAngle"); m_PlanarFourPointAngleNodeDescriptor = nodeDescriptorManager->GetDescriptor("PlanarFourPointAngle"); m_PlanarRectangleNodeDescriptor = nodeDescriptorManager->GetDescriptor("PlanarRectangle"); m_PlanarPolygonNodeDescriptor = nodeDescriptorManager->GetDescriptor("PlanarPolygon"); m_PlanarPathNodeDescriptor = nodeDescriptorManager->GetDescriptor("PlanarPath"); m_PlanarDoubleEllipseNodeDescriptor = nodeDescriptorManager->GetDescriptor("PlanarDoubleEllipse"); m_PlanarBezierCurveNodeDescriptor = nodeDescriptorManager->GetDescriptor("PlanarBezierCurve"); m_PlanarSubdivisionPolygonNodeDescriptor = nodeDescriptorManager->GetDescriptor("PlanarSubdivisionPolygon"); } void QmitkDataNodeContextMenu::InitDefaultActions() { auto workbenchPartSite = m_WorkbenchPartSite.Lock(); m_GlobalReinitAction = new QmitkDataNodeGlobalReinitAction(m_Parent, workbenchPartSite); m_GlobalReinitAction->setIcon(QIcon(":/org.mitk.gui.qt.datamanager/Refresh_48.png")); m_UnknownDataNodeDescriptor->AddAction(m_GlobalReinitAction, true); m_DescriptorActionList.push_back(std::make_pair(m_UnknownDataNodeDescriptor, m_GlobalReinitAction)); m_ReinitAction = new QmitkDataNodeReinitAction(m_Parent, workbenchPartSite); m_ReinitAction->setIcon(QIcon(":/org.mitk.gui.qt.datamanager/Refresh_48.png")); m_UnknownDataNodeDescriptor->AddAction(m_ReinitAction, true); m_DescriptorActionList.push_back(std::make_pair(m_UnknownDataNodeDescriptor, m_ReinitAction)); m_ResetGeometryAction = new QmitkDataNodeResetGeometryAction(m_Parent, workbenchPartSite); m_ResetGeometryAction->setIcon(QIcon(":/org.mitk.gui.qt.datamanager/Refresh_48.png")); m_UnknownDataNodeDescriptor->AddAction(m_ResetGeometryAction, true); m_DescriptorActionList.push_back(std::make_pair(m_UnknownDataNodeDescriptor, m_ResetGeometryAction)); QAction* saveAction = new QmitkFileSaveAction(QIcon(":/org.mitk.gui.qt.datamanager/Save_48.png"), workbenchPartSite->GetWorkbenchWindow()); m_UnknownDataNodeDescriptor->AddAction(saveAction, true); m_DescriptorActionList.push_back(std::make_pair(m_UnknownDataNodeDescriptor, saveAction)); m_RemoveAction = new QmitkDataNodeRemoveAction(m_Parent, workbenchPartSite); m_RemoveAction->setIcon(QIcon(":/org.mitk.gui.qt.datamanager/Remove_48.png")); m_UnknownDataNodeDescriptor->AddAction(m_RemoveAction, true); m_DescriptorActionList.push_back(std::make_pair(m_UnknownDataNodeDescriptor, m_RemoveAction)); m_ShowSelectedNodesAction = new QmitkDataNodeShowSelectedNodesAction(m_Parent, workbenchPartSite); m_ShowSelectedNodesAction->setIcon(QIcon(":/org.mitk.gui.qt.datamanager/ShowSelectedNode_48.png")); m_UnknownDataNodeDescriptor->AddAction(m_ShowSelectedNodesAction, true); m_DescriptorActionList.push_back(std::make_pair(m_UnknownDataNodeDescriptor, m_ShowSelectedNodesAction)); m_ToggleVisibilityAction = new QmitkDataNodeToggleVisibilityAction(m_Parent, workbenchPartSite); m_ToggleVisibilityAction->setIcon(QIcon(":/org.mitk.gui.qt.datamanager/InvertShowSelectedNode_48.png")); m_UnknownDataNodeDescriptor->AddAction(m_ToggleVisibilityAction, true); m_DescriptorActionList.push_back(std::make_pair(m_UnknownDataNodeDescriptor, m_ToggleVisibilityAction)); m_ShowDetailsAction = new QmitkDataNodeShowDetailsAction(m_Parent, workbenchPartSite); m_ShowDetailsAction->setIcon(QIcon(":/org.mitk.gui.qt.datamanager/ShowDataInfo_48.png")); m_UnknownDataNodeDescriptor->AddAction(m_ShowDetailsAction, true); m_DescriptorActionList.push_back(std::make_pair(m_UnknownDataNodeDescriptor, m_ShowDetailsAction)); m_OpacityAction = new QmitkDataNodeOpacityAction(m_Parent, workbenchPartSite); m_UnknownDataNodeDescriptor->AddAction(m_OpacityAction, false); m_DescriptorActionList.push_back(std::make_pair(m_UnknownDataNodeDescriptor, m_OpacityAction)); m_ColorAction = new QmitkDataNodeColorAction(m_Parent, workbenchPartSite); this->AddColorAction(m_ColorAction); m_ColormapAction = new QmitkDataNodeColorMapAction(m_Parent, workbenchPartSite); m_ImageDataNodeDescriptor->AddAction(m_ColormapAction); m_DescriptorActionList.push_back(std::make_pair(m_ImageDataNodeDescriptor, m_ColormapAction)); if (nullptr != m_DiffusionImageDataNodeDescriptor) { m_DiffusionImageDataNodeDescriptor->AddAction(m_ColormapAction, false); m_DescriptorActionList.push_back(std::make_pair(m_DiffusionImageDataNodeDescriptor, m_ColormapAction)); } m_ComponentAction = new QmitkDataNodeComponentAction(m_Parent, workbenchPartSite); m_MultiComponentImageDataNodeDescriptor->AddAction(m_ComponentAction, false); m_DescriptorActionList.push_back(std::make_pair(m_MultiComponentImageDataNodeDescriptor, m_ComponentAction)); if (nullptr != m_DiffusionImageDataNodeDescriptor) { m_DiffusionImageDataNodeDescriptor->AddAction(m_ComponentAction, false); m_DescriptorActionList.push_back(std::make_pair(m_DiffusionImageDataNodeDescriptor, m_ComponentAction)); } m_TextureInterpolationAction = new QmitkDataNodeTextureInterpolationAction(m_Parent, workbenchPartSite); m_ImageDataNodeDescriptor->AddAction(m_TextureInterpolationAction, false); m_DescriptorActionList.push_back(std::make_pair(m_ImageDataNodeDescriptor, m_TextureInterpolationAction)); if (nullptr != m_DiffusionImageDataNodeDescriptor) { m_DiffusionImageDataNodeDescriptor->AddAction(m_TextureInterpolationAction, false); m_DescriptorActionList.push_back(std::make_pair(m_DiffusionImageDataNodeDescriptor, m_TextureInterpolationAction)); } if (nullptr != m_SegmentDataNodeDescriptor) { m_SegmentDataNodeDescriptor->AddAction(m_TextureInterpolationAction, false); m_DescriptorActionList.push_back(std::make_pair(m_SegmentDataNodeDescriptor, m_TextureInterpolationAction)); } m_SurfaceRepresentationAction = new QmitkDataNodeSurfaceRepresentationAction(m_Parent, workbenchPartSite); m_SurfaceDataNodeDescriptor->AddAction(m_SurfaceRepresentationAction, false); m_DescriptorActionList.push_back(std::make_pair(m_SurfaceDataNodeDescriptor, m_SurfaceRepresentationAction)); } void QmitkDataNodeContextMenu::InitExtensionPointActions() { auto extensionPointService = berry::Platform::GetExtensionRegistry(); auto customMenuConfigs = extensionPointService->GetConfigurationElementsFor("org.mitk.gui.qt.datamanager.contextMenuActions"); DescriptorActionListType descriptorActionList; m_ConfigElements.clear(); - for (const auto& customMenuConfig : qAsConst(customMenuConfigs)) + for (const auto& customMenuConfig : std::as_const(customMenuConfigs)) { auto descriptorName = customMenuConfig->GetAttribute("nodeDescriptorName"); auto actionLabel = customMenuConfig->GetAttribute("label"); auto actionClass = customMenuConfig->GetAttribute("class"); if (descriptorName.isEmpty() || actionLabel.isEmpty() || actionClass.isEmpty()) continue; auto descriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(descriptorName); if (nullptr == descriptor) { MITK_WARN << "Cannot add action \"" << actionLabel << "\" to non-existent descriptor \"" << descriptorName << "\"."; continue; } QAction* action = nullptr; auto actionIcon = customMenuConfig->GetAttribute("icon"); if (!actionIcon.isEmpty()) { QIcon icon = !QFile::exists(actionIcon) ? berry::AbstractUICTKPlugin::ImageDescriptorFromPlugin(customMenuConfig->GetContributor()->GetName(), actionIcon) : QIcon(actionIcon); action = new QAction(icon, actionLabel, m_Parent); } else { action = new QAction(actionLabel, m_Parent); } if (nullptr != action) { // See T26938. We do not know why but without the lambda function indirection, the // connection is lost after the content menu was shown for the first time. connect(action, &QAction::triggered, [action, this]() { this->OnExtensionPointActionTriggered(action); }); m_ConfigElements[action] = customMenuConfig; descriptorActionList.push_back(std::make_pair(descriptor, action)); } } this->AddDescriptorActionList(descriptorActionList); } void QmitkDataNodeContextMenu::InitServiceActions() { } void QmitkDataNodeContextMenu::OnContextMenuRequested(const QPoint& /*pos*/) { auto workbenchPartSite = m_WorkbenchPartSite.Lock(); if (workbenchPartSite.IsNull()) return; auto selection = workbenchPartSite->GetWorkbenchWindow()->GetSelectionService()->GetSelection() .Cast(); if (selection.IsNull() || selection->IsEmpty()) return; auto nodes = selection->GetSelectedDataNodes(); m_SelectedNodes = QList(nodes.begin(), nodes.end()); if (!m_SelectedNodes.isEmpty()) { this->clear(); auto actions = m_SelectedNodes.size() == 1 ? this->GetActions(m_SelectedNodes.front()) : this->GetActions(m_SelectedNodes); for (auto& action : actions) { auto dataNodeAction = dynamic_cast(action); if (nullptr != dataNodeAction) dataNodeAction->SetSelectedNodes(m_SelectedNodes); } this->addActions(actions); this->popup(QCursor::pos()); } } void QmitkDataNodeContextMenu::OnExtensionPointActionTriggered(QAction* action) { auto configElementIter = m_ConfigElements.find(action); if (m_ConfigElements.end() == configElementIter) { MITK_WARN << "Associated configuration element for action \"" << action->text() << "\" not found."; return; } auto configElement = configElementIter->second; auto contextMenuAction = configElement->CreateExecutableExtension("class"); auto dataStorage = m_DataStorage.Lock(); if (dataStorage.IsNotNull()) contextMenuAction->SetDataStorage(dataStorage); if ("QmitkCreatePolygonModelAction" == configElement->GetAttribute("class")) { contextMenuAction->SetSmoothed("true" == configElement->GetAttribute("smoothed")); contextMenuAction->SetDecimated(m_SurfaceDecimation); } contextMenuAction->Run(m_SelectedNodes); } void QmitkDataNodeContextMenu::AddColorAction(QWidgetAction* colorAction) { if (nullptr != m_ImageDataNodeDescriptor) { m_ImageDataNodeDescriptor->AddAction(colorAction, true); m_DescriptorActionList.push_back(std::make_pair(m_ImageDataNodeDescriptor, colorAction)); } if (nullptr != m_MultiComponentImageDataNodeDescriptor) { m_MultiComponentImageDataNodeDescriptor->AddAction(colorAction, true); m_DescriptorActionList.push_back(std::make_pair(m_MultiComponentImageDataNodeDescriptor, colorAction)); } if (nullptr != m_DiffusionImageDataNodeDescriptor) { m_DiffusionImageDataNodeDescriptor->AddAction(colorAction, true); m_DescriptorActionList.push_back(std::make_pair(m_DiffusionImageDataNodeDescriptor, colorAction)); } if (nullptr != m_FiberBundleDataNodeDescriptor) { m_FiberBundleDataNodeDescriptor->AddAction(colorAction, false); m_DescriptorActionList.push_back(std::make_pair(m_FiberBundleDataNodeDescriptor, colorAction)); } if (nullptr != m_PeakImageDataNodeDescriptor) { m_PeakImageDataNodeDescriptor->AddAction(colorAction, false); m_DescriptorActionList.push_back(std::make_pair(m_PeakImageDataNodeDescriptor, colorAction)); } if (nullptr != m_SegmentDataNodeDescriptor) { m_SegmentDataNodeDescriptor->AddAction(colorAction, false); m_DescriptorActionList.push_back(std::make_pair(m_SegmentDataNodeDescriptor, colorAction)); } if (nullptr != m_SurfaceDataNodeDescriptor) { m_SurfaceDataNodeDescriptor->AddAction(colorAction, true); m_DescriptorActionList.push_back(std::make_pair(m_SurfaceDataNodeDescriptor, colorAction)); } if (nullptr != m_PointSetNodeDescriptor) { m_PointSetNodeDescriptor->AddAction(colorAction, true); m_DescriptorActionList.push_back(std::make_pair(m_PointSetNodeDescriptor, colorAction)); } if (nullptr != m_PlanarLineNodeDescriptor) { m_PlanarLineNodeDescriptor->AddAction(colorAction, true); m_DescriptorActionList.push_back(std::make_pair(m_PlanarLineNodeDescriptor, colorAction)); } if (nullptr != m_PlanarCircleNodeDescriptor) { m_PlanarCircleNodeDescriptor->AddAction(colorAction, true); m_DescriptorActionList.push_back(std::make_pair(m_PlanarCircleNodeDescriptor, colorAction)); } if (nullptr != m_PlanarEllipseNodeDescriptor) { m_PlanarEllipseNodeDescriptor->AddAction(colorAction, true); m_DescriptorActionList.push_back(std::make_pair(m_PlanarEllipseNodeDescriptor, colorAction)); } if (nullptr != m_PlanarAngleNodeDescriptor) { m_PlanarAngleNodeDescriptor->AddAction(colorAction, true); m_DescriptorActionList.push_back(std::make_pair(m_PlanarAngleNodeDescriptor, colorAction)); } if (nullptr != m_PlanarFourPointAngleNodeDescriptor) { m_PlanarFourPointAngleNodeDescriptor->AddAction(colorAction, true); m_DescriptorActionList.push_back(std::make_pair(m_PlanarFourPointAngleNodeDescriptor, colorAction)); } if (nullptr != m_PlanarRectangleNodeDescriptor) { m_PlanarRectangleNodeDescriptor->AddAction(colorAction, true); m_DescriptorActionList.push_back(std::make_pair(m_PlanarRectangleNodeDescriptor, colorAction)); } if (nullptr != m_PlanarPolygonNodeDescriptor) { m_PlanarPolygonNodeDescriptor->AddAction(colorAction, true); m_DescriptorActionList.push_back(std::make_pair(m_PlanarPolygonNodeDescriptor, colorAction)); } if (nullptr != m_PlanarPathNodeDescriptor) { m_PlanarPathNodeDescriptor->AddAction(colorAction, true); m_DescriptorActionList.push_back(std::make_pair(m_PlanarPathNodeDescriptor, colorAction)); } if (nullptr != m_PlanarDoubleEllipseNodeDescriptor) { m_PlanarDoubleEllipseNodeDescriptor->AddAction(colorAction, true); m_DescriptorActionList.push_back(std::make_pair(m_PlanarDoubleEllipseNodeDescriptor, colorAction)); } if (nullptr != m_PlanarBezierCurveNodeDescriptor) { m_PlanarBezierCurveNodeDescriptor->AddAction(colorAction, true); m_DescriptorActionList.push_back(std::make_pair(m_PlanarBezierCurveNodeDescriptor, colorAction)); } if (nullptr != m_PlanarSubdivisionPolygonNodeDescriptor) { m_PlanarSubdivisionPolygonNodeDescriptor->AddAction(colorAction, true); m_DescriptorActionList.push_back(std::make_pair(m_PlanarSubdivisionPolygonNodeDescriptor, colorAction)); } } void QmitkDataNodeContextMenu::AddDescriptorActionList(DescriptorActionListType& descriptorActionList) { using ListItem = std::pair; std::sort(descriptorActionList.begin(), descriptorActionList.end(), [](const ListItem& left, const ListItem& right) -> bool { return left.second->text() < right.second->text(); }); for (auto& descriptorActionPair : descriptorActionList) { descriptorActionPair.first->AddAction(descriptorActionPair.second); m_DescriptorActionList.push_back(descriptorActionPair); } } QList QmitkDataNodeContextMenu::GetActions(const mitk::DataNode* node) { QList actions; for(const auto& descriptorActionPair : m_DescriptorActionList) { if (descriptorActionPair.first->CheckNode(node) || "Unknown" == descriptorActionPair.first->GetNameOfClass()) actions.append(descriptorActionPair.second); } return actions; } QList QmitkDataNodeContextMenu::GetActions(const QList& nodes) { QList actions; for (const auto& descriptorActionPair : m_DescriptorActionList) { for (const auto& node : nodes) { if (descriptorActionPair.first->CheckNode(node) || "Unknown" == descriptorActionPair.first->GetNameOfClass()) { auto batchActions = descriptorActionPair.first->GetBatchActions(); if (std::find(batchActions.begin(), batchActions.end(), descriptorActionPair.second) != batchActions.end()) actions.append(descriptorActionPair.second); break; } } } return actions; } diff --git a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkViewCoordinator.cpp b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkViewCoordinator.cpp index 2a6a403d21..007a1a3c03 100644 --- a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkViewCoordinator.cpp +++ b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkViewCoordinator.cpp @@ -1,234 +1,234 @@ /*============================================================================ 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 "QmitkViewCoordinator.h" #include "QmitkAbstractView.h" #include #include #include #include #include QmitkViewCoordinator::QmitkViewCoordinator() : m_ActiveZombieView(nullptr) , m_ActiveRenderWindowPart(nullptr) , m_VisibleRenderWindowPart(nullptr) { } QmitkViewCoordinator::~QmitkViewCoordinator() { } void QmitkViewCoordinator::Start() { berry::PlatformUI::GetWorkbench()->AddWindowListener(this); QList wnds(berry::PlatformUI::GetWorkbench()->GetWorkbenchWindows()); for (QList::iterator i = wnds.begin(); i != wnds.end(); ++i) { (*i)->GetPartService()->AddPartListener(this); } } void QmitkViewCoordinator::Stop() { if (!berry::PlatformUI::IsWorkbenchRunning()) return; berry::PlatformUI::GetWorkbench()->RemoveWindowListener(this); QList wnds(berry::PlatformUI::GetWorkbench()->GetWorkbenchWindows()); for (QList::iterator i = wnds.begin(); i != wnds.end(); ++i) { (*i)->GetPartService()->RemovePartListener(this); } } berry::IPartListener::Events::Types QmitkViewCoordinator::GetPartEventTypes() const { return berry::IPartListener::Events::ACTIVATED | berry::IPartListener::Events::DEACTIVATED | berry::IPartListener::Events::CLOSED | berry::IPartListener::Events::HIDDEN | berry::IPartListener::Events::VISIBLE | berry::IPartListener::Events::OPENED | berry::IPartListener::Events::INPUT_CHANGED; } void QmitkViewCoordinator::PartActivated(const berry::IWorkbenchPartReference::Pointer& partRef) { //MITK_INFO << "*** PartActivated (" << partRef->GetPart(false)->GetPartName() << ")"; berry::IWorkbenchPart* part = partRef->GetPart(false).GetPointer(); // Check for a render window part and inform IRenderWindowPartListener views // that it was activated if (mitk::IRenderWindowPart* renderPart = dynamic_cast(part)) { if (m_VisibleRenderWindowPart != renderPart) { RenderWindowPartActivated(renderPart); m_ActiveRenderWindowPart = renderPart; m_VisibleRenderWindowPart = renderPart; } } // Check if the activated part wants to be notified if (mitk::ILifecycleAwarePart* lifecycleAwarePart = dynamic_cast(part)) { lifecycleAwarePart->Activated(); } // Check if a zombie view has been activated. if (mitk::IZombieViewPart* zombieView = dynamic_cast(part)) { if (m_ActiveZombieView && (m_ActiveZombieView != zombieView)) { // Another zombie view has been activated. Tell the old one about it. m_ActiveZombieView->ActivatedZombieView(partRef); m_ActiveZombieView = zombieView; } } } void QmitkViewCoordinator::PartDeactivated(const berry::IWorkbenchPartReference::Pointer& partRef) { //MITK_INFO << "*** PartDeactivated (" << partRef->GetPart(false)->GetPartName() << ")"; berry::IWorkbenchPart* part = partRef->GetPart(false).GetPointer(); // Check for a render window part and inform IRenderWindowPartListener views // that it was deactivated if (mitk::IRenderWindowPart* renderPart = dynamic_cast(part)) { if (m_ActiveRenderWindowPart == renderPart) { this->RenderWindowPartDeactivated(renderPart); m_ActiveRenderWindowPart = nullptr; m_VisibleRenderWindowPart = nullptr; } } if (mitk::ILifecycleAwarePart* lifecycleAwarePart = dynamic_cast(part)) { lifecycleAwarePart->Deactivated(); } } void QmitkViewCoordinator::PartOpened(const berry::IWorkbenchPartReference::Pointer& partRef) { //MITK_INFO << "*** PartOpened (" << partRef->GetPart(false)->GetPartName() << ")"; berry::IWorkbenchPart* part = partRef->GetPart(false).GetPointer(); if (mitk::IRenderWindowPartListener* renderWindowListener = dynamic_cast(part)) { m_RenderWindowListeners.insert(renderWindowListener); } } void QmitkViewCoordinator::PartClosed(const berry::IWorkbenchPartReference::Pointer& partRef) { //MITK_INFO << "*** PartClosed (" << partRef->GetPart(false)->GetPartName() << ")"; berry::IWorkbenchPart* part = partRef->GetPart(false).GetPointer(); if (mitk::IRenderWindowPartListener* renderWindowListener = dynamic_cast(part)) { m_RenderWindowListeners.remove(renderWindowListener); } } void QmitkViewCoordinator::PartHidden(const berry::IWorkbenchPartReference::Pointer& partRef) { //MITK_INFO << "*** PartHidden (" << partRef->GetPart(false)->GetPartName() << ")"; berry::IWorkbenchPart* part = partRef->GetPart(false).GetPointer(); // Check for a render window part and if it is the currently active on. // Inform IRenderWindowPartListener views that it has been hidden. if (mitk::IRenderWindowPart* renderPart = dynamic_cast(part)) { if (!m_ActiveRenderWindowPart && m_VisibleRenderWindowPart == renderPart) { RenderWindowPartDeactivated(renderPart); m_VisibleRenderWindowPart = nullptr; } } if (mitk::ILifecycleAwarePart* lifecycleAwarePart = dynamic_cast(part)) { lifecycleAwarePart->Hidden(); } } void QmitkViewCoordinator::PartVisible(const berry::IWorkbenchPartReference::Pointer& partRef) { //MITK_INFO << "*** PartVisible (" << partRef->GetPart(false)->GetPartName() << ")"; berry::IWorkbenchPart* part = partRef->GetPart(false).GetPointer(); // Check for a render window part and inform IRenderWindowPartListener views // that it was activated if (mitk::IRenderWindowPart* renderPart = dynamic_cast(part)) { if (!m_ActiveRenderWindowPart) { RenderWindowPartActivated(renderPart); m_VisibleRenderWindowPart = renderPart; } } if (mitk::ILifecycleAwarePart* lifecycleAwarePart = dynamic_cast(part)) { lifecycleAwarePart->Visible(); } } void QmitkViewCoordinator::PartInputChanged(const berry::IWorkbenchPartReference::Pointer& partRef) { berry::IWorkbenchPart* part = partRef->GetPart(false).GetPointer(); // Check for a render window part and inform IRenderWindowPartListener views // that it was changed if (mitk::IRenderWindowPart* renderPart = dynamic_cast(part)) { if (!m_ActiveRenderWindowPart) { RenderWindowPartInputChanged(renderPart); } } } void QmitkViewCoordinator::WindowOpened(const berry::IWorkbenchWindow::Pointer& window) { window->GetPartService()->AddPartListener(this); } void QmitkViewCoordinator::WindowClosed(const berry::IWorkbenchWindow::Pointer& /*window*/) { } void QmitkViewCoordinator::RenderWindowPartActivated(mitk::IRenderWindowPart* renderPart) { - for (auto& listener : qAsConst(m_RenderWindowListeners)) + for (auto& listener : std::as_const(m_RenderWindowListeners)) { listener->RenderWindowPartActivated(renderPart); } } void QmitkViewCoordinator::RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderPart) { - for (auto& listener : qAsConst(m_RenderWindowListeners)) + for (auto& listener : std::as_const(m_RenderWindowListeners)) { listener->RenderWindowPartDeactivated(renderPart); } } void QmitkViewCoordinator::RenderWindowPartInputChanged(mitk::IRenderWindowPart* renderPart) { - for (auto& listener : qAsConst(m_RenderWindowListeners)) + for (auto& listener : std::as_const(m_RenderWindowListeners)) { listener->RenderWindowPartInputChanged(renderPart); } } diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.cpp b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.cpp index 7adc044f6d..6c8668c497 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.cpp +++ b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.cpp @@ -1,231 +1,231 @@ /*============================================================================ 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 "QmitkDataManagerView.h" // mitk gui qt datamanager #include "internal/QmitkDataManagerItemDelegate.h" #include "internal/QmitkNodeTableViewKeyFilter.h" // mitk core #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // qt widgets module #include #include #include #include #include // mitk core services plugin #include #include // mitk gui common plugin #include // mitk gui qt application plugin #include #include // mitk gui qt common plugin #include // qt #include #include #include const QString QmitkDataManagerView::VIEW_ID = "org.mitk.views.datamanager"; QmitkDataManagerView::QmitkDataManagerView() : m_ItemDelegate(nullptr) { } QmitkDataManagerView::~QmitkDataManagerView() { // nothing here } void QmitkDataManagerView::CreateQtPartControl(QWidget* parent) { m_CurrentRowCount = 0; m_Parent = parent; auto* prefs = this->GetPreferences(); assert(prefs != nullptr); m_NodeTreeModel = new QmitkDataStorageTreeModel(GetDataStorage(), prefs->GetBool("Place new nodes on top", true)); m_NodeTreeModel->setParent(parent); m_NodeTreeModel->SetAllowHierarchyChange(prefs->GetBool("Allow changing of parent node", false)); // Prepare filters m_HelperObjectFilterPredicate = mitk::NodePredicateOr::New( mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true)), mitk::NodePredicateProperty::New("hidden object", mitk::BoolProperty::New(true))); m_NodeWithNoDataFilterPredicate = mitk::NodePredicateData::New(nullptr); m_FilterModel = new QmitkDataStorageFilterProxyModel(); m_FilterModel->setSourceModel(m_NodeTreeModel); m_FilterModel->AddFilterPredicate(m_HelperObjectFilterPredicate); m_FilterModel->AddFilterPredicate(m_NodeWithNoDataFilterPredicate); m_NodeTreeView = new QTreeView; m_NodeTreeView->setHeaderHidden(true); m_NodeTreeView->setSelectionMode(QAbstractItemView::ExtendedSelection); m_NodeTreeView->setSelectionBehavior(QAbstractItemView::SelectRows); m_NodeTreeView->setAlternatingRowColors(true); m_NodeTreeView->setDragEnabled(true); m_NodeTreeView->setDropIndicatorShown(true); m_NodeTreeView->setAcceptDrops(true); m_NodeTreeView->setContextMenuPolicy(Qt::CustomContextMenu); m_NodeTreeView->setModel(m_FilterModel); m_NodeTreeView->setTextElideMode(Qt::ElideMiddle); m_NodeTreeView->installEventFilter(new QmitkNodeTableViewKeyFilter(this, GetDataStorage())); m_ItemDelegate = new QmitkDataManagerItemDelegate(m_NodeTreeView); m_NodeTreeView->setItemDelegate(m_ItemDelegate); connect(m_NodeTreeModel, SIGNAL(rowsInserted(const QModelIndex&, int, int)), this, SLOT(NodeTreeViewRowsInserted(const QModelIndex&, int, int))); connect(m_NodeTreeModel, SIGNAL(rowsRemoved(const QModelIndex&, int, int)), this, SLOT(NodeTreeViewRowsRemoved(const QModelIndex&, int, int))); connect(m_NodeTreeView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), this, SLOT(NodeSelectionChanged(const QItemSelection &, const QItemSelection &))); connect(m_NodeTreeModel, &QmitkDataStorageTreeModel::nodeVisibilityChanged, this, &QmitkDataManagerView::OnNodeVisibilityChanged); // data node context menu and menu actions m_DataNodeContextMenu = new QmitkDataNodeContextMenu(GetSite(), m_NodeTreeView); m_DataNodeContextMenu->SetDataStorage(GetDataStorage()); connect(m_NodeTreeView, SIGNAL(customContextMenuRequested(const QPoint&)), m_DataNodeContextMenu, SLOT(OnContextMenuRequested(const QPoint&))); QGridLayout* dndFrameWidgetLayout = new QGridLayout; dndFrameWidgetLayout->addWidget(m_NodeTreeView, 0, 0); dndFrameWidgetLayout->setContentsMargins(0, 0, 0, 0); m_DnDFrameWidget = new QmitkDnDFrameWidget(m_Parent); m_DnDFrameWidget->setLayout(dndFrameWidgetLayout); QVBoxLayout* layout = new QVBoxLayout(parent); layout->addWidget(m_DnDFrameWidget); layout->setContentsMargins(0, 0, 0, 0); m_Parent->setLayout(layout); } void QmitkDataManagerView::SetFocus() { } ////////////////////////////////////////////////////////////////////////// // Node tree modification ////////////////////////////////////////////////////////////////////////// void QmitkDataManagerView::NodeTreeViewRowsInserted(const QModelIndex& parent, int /*start*/, int /*end*/) { QModelIndex viewIndex = m_FilterModel->mapFromSource(parent); m_NodeTreeView->setExpanded(viewIndex, true); // a new row was inserted if (m_CurrentRowCount == 0 && m_NodeTreeModel->rowCount() == 1) { mitk::WorkbenchUtil::OpenRenderWindowPart(GetSite()->GetPage()); m_CurrentRowCount = m_NodeTreeModel->rowCount(); } } void QmitkDataManagerView::NodeTreeViewRowsRemoved(const QModelIndex& /*parent*/, int /*start*/, int /*end*/) { m_CurrentRowCount = m_NodeTreeModel->rowCount(); } void QmitkDataManagerView::NodeSelectionChanged(const QItemSelection& /*selected*/, const QItemSelection& /*deselected*/) { auto selectedNodes = GetCurrentSelection(); auto nodeSet = m_NodeTreeModel->GetNodeSet(); - for (auto node : qAsConst(nodeSet)) + for (auto node : std::as_const(nodeSet)) { if (node.IsNotNull()) { node->SetSelected(selectedNodes.contains(node)); } } m_DataNodeContextMenu->SetSelectedNodes(selectedNodes); } void QmitkDataManagerView::OnNodeVisibilityChanged() { ToggleVisibilityAction::Run(GetSite(), GetDataStorage(), QList()); } void QmitkDataManagerView::NodeChanged(const mitk::DataNode* /*node*/) { // m_FilterModel->invalidate(); // fix as proposed by R. Khlebnikov in the mitk-users mail from 02.09.2014 QMetaObject::invokeMethod(m_FilterModel, "invalidate", Qt::QueuedConnection); } void QmitkDataManagerView::OnPreferencesChanged(const mitk::IPreferences* prefs) { if (m_NodeTreeModel->GetPlaceNewNodesOnTopFlag() != prefs->GetBool("Place new nodes on top", true)) { m_NodeTreeModel->SetPlaceNewNodesOnTop(!m_NodeTreeModel->GetPlaceNewNodesOnTopFlag()); } bool hideHelperObjects = !prefs->GetBool("Show helper objects", false); if (m_FilterModel->HasFilterPredicate(m_HelperObjectFilterPredicate) != hideHelperObjects) { if (hideHelperObjects) { m_FilterModel->AddFilterPredicate(m_HelperObjectFilterPredicate); } else { m_FilterModel->RemoveFilterPredicate(m_HelperObjectFilterPredicate); } } bool hideNodesWithNoData = !prefs->GetBool("Show nodes containing no data", false); if (m_FilterModel->HasFilterPredicate(m_NodeWithNoDataFilterPredicate) != hideNodesWithNoData) { if (hideNodesWithNoData) { m_FilterModel->AddFilterPredicate(m_NodeWithNoDataFilterPredicate); } else { m_FilterModel->RemoveFilterPredicate(m_NodeWithNoDataFilterPredicate); } } m_NodeTreeView->expandAll(); m_NodeTreeModel->SetAllowHierarchyChange(prefs->GetBool("Allow changing of parent node", false)); GlobalReinitAction::Run(GetSite(), GetDataStorage()); } QItemSelectionModel* QmitkDataManagerView::GetDataNodeSelectionModel() const { return m_NodeTreeView->selectionModel(); } diff --git a/Plugins/org.mitk.gui.qt.ext/src/QmitkExtWorkbenchWindowAdvisor.cpp b/Plugins/org.mitk.gui.qt.ext/src/QmitkExtWorkbenchWindowAdvisor.cpp index 409d9920be..50c9125b77 100644 --- a/Plugins/org.mitk.gui.qt.ext/src/QmitkExtWorkbenchWindowAdvisor.cpp +++ b/Plugins/org.mitk.gui.qt.ext/src/QmitkExtWorkbenchWindowAdvisor.cpp @@ -1,1444 +1,1444 @@ /*============================================================================ 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 "QmitkExtWorkbenchWindowAdvisor.h" #include "QmitkExtActionBarAdvisor.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // UGLYYY #include "internal/QmitkExtWorkbenchWindowAdvisorHack.h" #include "internal/QmitkCommonExtPlugin.h" #include "mitkUndoController.h" #include "mitkVerboseLimitedLinearUndo.h" #include #include #include #include #include #include QmitkExtWorkbenchWindowAdvisorHack* QmitkExtWorkbenchWindowAdvisorHack::undohack = new QmitkExtWorkbenchWindowAdvisorHack(); QString QmitkExtWorkbenchWindowAdvisor::QT_SETTINGS_FILENAME = "QtSettings.ini"; static bool USE_EXPERIMENTAL_COMMAND_CONTRIBUTIONS = false; class PartListenerForTitle: public berry::IPartListener { public: PartListenerForTitle(QmitkExtWorkbenchWindowAdvisor* wa) : windowAdvisor(wa) { } Events::Types GetPartEventTypes() const override { return Events::ACTIVATED | Events::BROUGHT_TO_TOP | Events::CLOSED | Events::HIDDEN | Events::VISIBLE; } void PartActivated(const berry::IWorkbenchPartReference::Pointer& ref) override { if (ref.Cast ()) { windowAdvisor->UpdateTitle(false); } } void PartBroughtToTop(const berry::IWorkbenchPartReference::Pointer& ref) override { if (ref.Cast ()) { windowAdvisor->UpdateTitle(false); } } void PartClosed(const berry::IWorkbenchPartReference::Pointer& /*ref*/) override { windowAdvisor->UpdateTitle(false); } void PartHidden(const berry::IWorkbenchPartReference::Pointer& ref) override { auto lockedLastActiveEditor = windowAdvisor->lastActiveEditor.Lock(); if (lockedLastActiveEditor.IsNotNull() && ref->GetPart(false) == lockedLastActiveEditor) { windowAdvisor->UpdateTitle(true); } } void PartVisible(const berry::IWorkbenchPartReference::Pointer& ref) override { auto lockedLastActiveEditor = windowAdvisor->lastActiveEditor.Lock(); if (lockedLastActiveEditor.IsNotNull() && ref->GetPart(false) == lockedLastActiveEditor) { windowAdvisor->UpdateTitle(false); } } private: QmitkExtWorkbenchWindowAdvisor* windowAdvisor; }; class PartListenerForViewNavigator: public berry::IPartListener { public: PartListenerForViewNavigator(QAction* act) : viewNavigatorAction(act) { } Events::Types GetPartEventTypes() const override { return Events::OPENED | Events::CLOSED | Events::HIDDEN | Events::VISIBLE; } void PartOpened(const berry::IWorkbenchPartReference::Pointer& ref) override { if (ref->GetId()=="org.mitk.views.viewnavigator") { viewNavigatorAction->setChecked(true); } } void PartClosed(const berry::IWorkbenchPartReference::Pointer& ref) override { if (ref->GetId()=="org.mitk.views.viewnavigator") { viewNavigatorAction->setChecked(false); } } void PartVisible(const berry::IWorkbenchPartReference::Pointer& ref) override { if (ref->GetId()=="org.mitk.views.viewnavigator") { viewNavigatorAction->setChecked(true); } } void PartHidden(const berry::IWorkbenchPartReference::Pointer& ref) override { if (ref->GetId()=="org.mitk.views.viewnavigator") { viewNavigatorAction->setChecked(false); } } private: QAction* viewNavigatorAction; }; class PartListenerForImageNavigator: public berry::IPartListener { public: PartListenerForImageNavigator(QAction* act) : imageNavigatorAction(act) { } Events::Types GetPartEventTypes() const override { return Events::OPENED | Events::CLOSED | Events::HIDDEN | Events::VISIBLE; } void PartOpened(const berry::IWorkbenchPartReference::Pointer& ref) override { if (ref->GetId()=="org.mitk.views.imagenavigator") { imageNavigatorAction->setChecked(true); } } void PartClosed(const berry::IWorkbenchPartReference::Pointer& ref) override { if (ref->GetId()=="org.mitk.views.imagenavigator") { imageNavigatorAction->setChecked(false); } } void PartVisible(const berry::IWorkbenchPartReference::Pointer& ref) override { if (ref->GetId()=="org.mitk.views.imagenavigator") { imageNavigatorAction->setChecked(true); } } void PartHidden(const berry::IWorkbenchPartReference::Pointer& ref) override { if (ref->GetId()=="org.mitk.views.imagenavigator") { imageNavigatorAction->setChecked(false); } } private: QAction* imageNavigatorAction; }; class PerspectiveListenerForTitle: public berry::IPerspectiveListener { public: PerspectiveListenerForTitle(QmitkExtWorkbenchWindowAdvisor* wa) : windowAdvisor(wa) , perspectivesClosed(false) { } Events::Types GetPerspectiveEventTypes() const override { if (USE_EXPERIMENTAL_COMMAND_CONTRIBUTIONS) { return Events::ACTIVATED | Events::SAVED_AS | Events::DEACTIVATED; } else { return Events::ACTIVATED | Events::SAVED_AS | Events::DEACTIVATED | Events::CLOSED | Events::OPENED; } } void PerspectiveActivated(const berry::IWorkbenchPage::Pointer& /*page*/, const berry::IPerspectiveDescriptor::Pointer& /*perspective*/) override { windowAdvisor->UpdateTitle(false); } void PerspectiveSavedAs(const berry::IWorkbenchPage::Pointer& /*page*/, const berry::IPerspectiveDescriptor::Pointer& /*oldPerspective*/, const berry::IPerspectiveDescriptor::Pointer& /*newPerspective*/) override { windowAdvisor->UpdateTitle(false); } void PerspectiveDeactivated(const berry::IWorkbenchPage::Pointer& /*page*/, const berry::IPerspectiveDescriptor::Pointer& /*perspective*/) override { windowAdvisor->UpdateTitle(false); } void PerspectiveOpened(const berry::IWorkbenchPage::Pointer& /*page*/, const berry::IPerspectiveDescriptor::Pointer& /*perspective*/) override { if (perspectivesClosed) { QListIterator i(windowAdvisor->viewActions); while (i.hasNext()) { i.next()->setEnabled(true); } //GetViewRegistry()->Find("org.mitk.views.imagenavigator"); if(windowAdvisor->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.dicombrowser")) { windowAdvisor->openDicomEditorAction->setEnabled(true); } if (windowAdvisor->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.stdmultiwidget")) { windowAdvisor->openStdMultiWidgetEditorAction->setEnabled(true); } if (windowAdvisor->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.mxnmultiwidget")) { windowAdvisor->openMxNMultiWidgetEditorAction->setEnabled(true); } windowAdvisor->fileSaveProjectAction->setEnabled(true); windowAdvisor->closeProjectAction->setEnabled(true); windowAdvisor->undoAction->setEnabled(true); windowAdvisor->redoAction->setEnabled(true); windowAdvisor->imageNavigatorAction->setEnabled(true); windowAdvisor->viewNavigatorAction->setEnabled(true); windowAdvisor->resetPerspAction->setEnabled(true); if( windowAdvisor->GetShowClosePerspectiveMenuItem() ) { windowAdvisor->closePerspAction->setEnabled(true); } } perspectivesClosed = false; } void PerspectiveClosed(const berry::IWorkbenchPage::Pointer& /*page*/, const berry::IPerspectiveDescriptor::Pointer& /*perspective*/) override { berry::IWorkbenchWindow::Pointer wnd = windowAdvisor->GetWindowConfigurer()->GetWindow(); bool allClosed = true; if (wnd->GetActivePage()) { QList perspectives(wnd->GetActivePage()->GetOpenPerspectives()); allClosed = perspectives.empty(); } if (allClosed) { perspectivesClosed = true; QListIterator i(windowAdvisor->viewActions); while (i.hasNext()) { i.next()->setEnabled(false); } if(windowAdvisor->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.dicombrowser")) { windowAdvisor->openDicomEditorAction->setEnabled(false); } if (windowAdvisor->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.stdmultiwidget")) { windowAdvisor->openStdMultiWidgetEditorAction->setEnabled(false); } if (windowAdvisor->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.mxnmultiwidget")) { windowAdvisor->openMxNMultiWidgetEditorAction->setEnabled(false); } windowAdvisor->fileSaveProjectAction->setEnabled(false); windowAdvisor->closeProjectAction->setEnabled(false); windowAdvisor->undoAction->setEnabled(false); windowAdvisor->redoAction->setEnabled(false); windowAdvisor->imageNavigatorAction->setEnabled(false); windowAdvisor->viewNavigatorAction->setEnabled(false); windowAdvisor->resetPerspAction->setEnabled(false); if( windowAdvisor->GetShowClosePerspectiveMenuItem() ) { windowAdvisor->closePerspAction->setEnabled(false); } } } private: QmitkExtWorkbenchWindowAdvisor* windowAdvisor; bool perspectivesClosed; }; class PerspectiveListenerForMenu: public berry::IPerspectiveListener { public: PerspectiveListenerForMenu(QmitkExtWorkbenchWindowAdvisor* wa) : windowAdvisor(wa) { } Events::Types GetPerspectiveEventTypes() const override { return Events::ACTIVATED | Events::DEACTIVATED; } void PerspectiveActivated(const berry::IWorkbenchPage::Pointer& /*page*/, const berry::IPerspectiveDescriptor::Pointer& perspective) override { QAction* action = windowAdvisor->mapPerspIdToAction[perspective->GetId()]; if (action) { action->setChecked(true); } } void PerspectiveDeactivated(const berry::IWorkbenchPage::Pointer& /*page*/, const berry::IPerspectiveDescriptor::Pointer& perspective) override { QAction* action = windowAdvisor->mapPerspIdToAction[perspective->GetId()]; if (action) { action->setChecked(false); } } private: QmitkExtWorkbenchWindowAdvisor* windowAdvisor; }; QmitkExtWorkbenchWindowAdvisor::QmitkExtWorkbenchWindowAdvisor(berry::WorkbenchAdvisor* wbAdvisor, berry::IWorkbenchWindowConfigurer::Pointer configurer) : berry::WorkbenchWindowAdvisor(configurer) , lastInput(nullptr) , wbAdvisor(wbAdvisor) , showViewToolbar(true) , showPerspectiveToolbar(false) , showVersionInfo(true) , showMitkVersionInfo(true) , showViewMenuItem(true) , showNewWindowMenuItem(false) , showClosePerspectiveMenuItem(true) , viewNavigatorFound(false) , showMemoryIndicator(true) , dropTargetListener(new QmitkDefaultDropTargetListener) { productName = QCoreApplication::applicationName(); viewExcludeList.push_back("org.mitk.views.viewnavigator"); } QmitkExtWorkbenchWindowAdvisor::~QmitkExtWorkbenchWindowAdvisor() { } berry::ActionBarAdvisor::Pointer QmitkExtWorkbenchWindowAdvisor::CreateActionBarAdvisor(berry::IActionBarConfigurer::Pointer configurer) { if (USE_EXPERIMENTAL_COMMAND_CONTRIBUTIONS) { berry::ActionBarAdvisor::Pointer actionBarAdvisor(new QmitkExtActionBarAdvisor(configurer)); return actionBarAdvisor; } else { return berry::WorkbenchWindowAdvisor::CreateActionBarAdvisor(configurer); } } QWidget* QmitkExtWorkbenchWindowAdvisor::CreateEmptyWindowContents(QWidget* parent) { QWidget* parentWidget = static_cast(parent); auto label = new QLabel(parentWidget); label->setText("No perspectives are open. Open a perspective in the Window->Open Perspective menu."); label->setContentsMargins(10,10,10,10); label->setAlignment(Qt::AlignTop); label->setEnabled(false); parentWidget->layout()->addWidget(label); return label; } void QmitkExtWorkbenchWindowAdvisor::ShowClosePerspectiveMenuItem(bool show) { showClosePerspectiveMenuItem = show; } bool QmitkExtWorkbenchWindowAdvisor::GetShowClosePerspectiveMenuItem() { return showClosePerspectiveMenuItem; } void QmitkExtWorkbenchWindowAdvisor::ShowMemoryIndicator(bool show) { showMemoryIndicator = show; } bool QmitkExtWorkbenchWindowAdvisor::GetShowMemoryIndicator() { return showMemoryIndicator; } void QmitkExtWorkbenchWindowAdvisor::ShowNewWindowMenuItem(bool show) { showNewWindowMenuItem = show; } void QmitkExtWorkbenchWindowAdvisor::ShowViewToolbar(bool show) { showViewToolbar = show; } void QmitkExtWorkbenchWindowAdvisor::ShowViewMenuItem(bool show) { showViewMenuItem = show; } void QmitkExtWorkbenchWindowAdvisor::ShowPerspectiveToolbar(bool show) { showPerspectiveToolbar = show; } void QmitkExtWorkbenchWindowAdvisor::ShowVersionInfo(bool show) { showVersionInfo = show; } void QmitkExtWorkbenchWindowAdvisor::ShowMitkVersionInfo(bool show) { showMitkVersionInfo = show; } void QmitkExtWorkbenchWindowAdvisor::SetProductName(const QString& product) { productName = product; } void QmitkExtWorkbenchWindowAdvisor::SetWindowIcon(const QString& wndIcon) { windowIcon = wndIcon; } void QmitkExtWorkbenchWindowAdvisor::PostWindowCreate() { // very bad hack... berry::IWorkbenchWindow::Pointer window = this->GetWindowConfigurer()->GetWindow(); QMainWindow* mainWindow = qobject_cast (window->GetShell()->GetControl()); if (!windowIcon.isEmpty()) { mainWindow->setWindowIcon(QIcon(windowIcon)); } mainWindow->setContextMenuPolicy(Qt::PreventContextMenu); // Load icon theme QIcon::setThemeSearchPaths(QStringList() << QStringLiteral(":/org_mitk_icons/icons/")); QIcon::setThemeName(QStringLiteral("awesome")); // ==== Application menu ============================ QMenuBar* menuBar = mainWindow->menuBar(); menuBar->setContextMenuPolicy(Qt::PreventContextMenu); #ifdef __APPLE__ menuBar->setNativeMenuBar(true); #else menuBar->setNativeMenuBar(false); #endif auto basePath = QStringLiteral(":/org_mitk_icons/icons/awesome/scalable/actions/"); auto fileOpenAction = new QmitkFileOpenAction(berry::QtStyleManager::ThemeIcon(basePath + "document-open.svg"), window); fileOpenAction->setShortcut(QKeySequence::Open); auto fileSaveAction = new QmitkFileSaveAction(berry::QtStyleManager::ThemeIcon(basePath + "document-save.svg"), window); fileSaveAction->setShortcut(QKeySequence::Save); fileSaveProjectAction = new QmitkExtFileSaveProjectAction(window); fileSaveProjectAction->setIcon(berry::QtStyleManager::ThemeIcon(basePath + "document-save.svg")); closeProjectAction = new QmitkCloseProjectAction(window); closeProjectAction->setIcon(berry::QtStyleManager::ThemeIcon(basePath + "edit-delete.svg")); auto perspGroup = new QActionGroup(menuBar); std::map VDMap; // sort elements (converting vector to map...) QList::const_iterator iter; berry::IViewRegistry* viewRegistry = berry::PlatformUI::GetWorkbench()->GetViewRegistry(); const QList viewDescriptors = viewRegistry->GetViews(); bool skip = false; for (iter = viewDescriptors.begin(); iter != viewDescriptors.end(); ++iter) { // if viewExcludeList is set, it contains the id-strings of view, which // should not appear as an menu-entry in the menu if (viewExcludeList.size() > 0) { for (int i=0; iGetId()) { skip = true; break; } } if (skip) { skip = false; continue; } } if ((*iter)->GetId() == "org.blueberry.ui.internal.introview") continue; if ((*iter)->GetId() == "org.mitk.views.imagenavigator") continue; if ((*iter)->GetId() == "org.mitk.views.viewnavigator") continue; std::pair p((*iter)->GetLabel(), (*iter)); VDMap.insert(p); } std::map::const_iterator MapIter; for (MapIter = VDMap.begin(); MapIter != VDMap.end(); ++MapIter) { berry::QtShowViewAction* viewAction = new berry::QtShowViewAction(window, (*MapIter).second); viewActions.push_back(viewAction); } if (!USE_EXPERIMENTAL_COMMAND_CONTRIBUTIONS) { QMenu* fileMenu = menuBar->addMenu("&File"); fileMenu->setObjectName("FileMenu"); fileMenu->addAction(fileOpenAction); fileMenu->addAction(fileSaveAction); fileMenu->addAction(fileSaveProjectAction); fileMenu->addAction(closeProjectAction); fileMenu->addSeparator(); QAction* fileExitAction = new QmitkFileExitAction(window); fileExitAction->setIcon(berry::QtStyleManager::ThemeIcon(basePath + "system-log-out.svg")); fileExitAction->setShortcut(QKeySequence::Quit); fileExitAction->setObjectName("QmitkFileExitAction"); fileMenu->addAction(fileExitAction); // another bad hack to get an edit/undo menu... QMenu* editMenu = menuBar->addMenu("&Edit"); undoAction = editMenu->addAction(berry::QtStyleManager::ThemeIcon(basePath + "edit-undo.svg"), "&Undo", QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onUndo()), QKeySequence("CTRL+Z")); undoAction->setToolTip("Undo the last action (not supported by all modules)"); redoAction = editMenu->addAction(berry::QtStyleManager::ThemeIcon(basePath + "edit-redo.svg"), "&Redo", QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onRedo()), QKeySequence("CTRL+Y")); redoAction->setToolTip("execute the last action that was undone again (not supported by all modules)"); // ==== Window Menu ========================== QMenu* windowMenu = menuBar->addMenu("Window"); if (showNewWindowMenuItem) { windowMenu->addAction("&New Window", QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onNewWindow())); windowMenu->addSeparator(); } QMenu* perspMenu = windowMenu->addMenu("&Open Perspective"); QMenu* viewMenu = nullptr; if (showViewMenuItem) { viewMenu = windowMenu->addMenu("Show &View"); viewMenu->setObjectName("Show View"); } windowMenu->addSeparator(); resetPerspAction = windowMenu->addAction("&Reset Perspective", QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onResetPerspective())); if(showClosePerspectiveMenuItem) closePerspAction = windowMenu->addAction("&Close Perspective", QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onClosePerspective())); windowMenu->addSeparator(); windowMenu->addAction("&Preferences...", QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onEditPreferences()), QKeySequence("CTRL+P")); // fill perspective menu berry::IPerspectiveRegistry* perspRegistry = window->GetWorkbench()->GetPerspectiveRegistry(); QList perspectives( perspRegistry->GetPerspectives()); skip = false; for (QList::iterator perspIt = perspectives.begin(); perspIt != perspectives.end(); ++perspIt) { // if perspectiveExcludeList is set, it contains the id-strings of perspectives, which // should not appear as an menu-entry in the perspective menu if (perspectiveExcludeList.size() > 0) { for (int i=0; iGetId()) { skip = true; break; } } if (skip) { skip = false; continue; } } QAction* perspAction = new berry::QtOpenPerspectiveAction(window, *perspIt, perspGroup); mapPerspIdToAction.insert((*perspIt)->GetId(), perspAction); } perspMenu->addActions(perspGroup->actions()); if (showViewMenuItem) { - for (auto viewAction : qAsConst(viewActions)) + for (auto viewAction : std::as_const(viewActions)) { viewMenu->addAction(viewAction); } } // ===== Help menu ==================================== QMenu* helpMenu = menuBar->addMenu("&Help"); helpMenu->addAction("&Welcome",this, SLOT(onIntro())); helpMenu->addAction("&Open Help Perspective", this, SLOT(onHelpOpenHelpPerspective())); helpMenu->addAction("&Context Help",this, SLOT(onHelp()), QKeySequence("F1")); helpMenu->addAction("&About",this, SLOT(onAbout())); // ===================================================== } else { undoAction = new QmitkUndoAction(berry::QtStyleManager::ThemeIcon(basePath + "edit-undo.svg"), nullptr); undoAction->setShortcut(QKeySequence::Undo); redoAction = new QmitkRedoAction(berry::QtStyleManager::ThemeIcon(basePath + "edit-redo.svg"), nullptr); redoAction->setShortcut(QKeySequence::Redo); } // toolbar for showing file open, undo, redo and other main actions auto mainActionsToolBar = new QToolBar; mainActionsToolBar->setObjectName("mainActionsToolBar"); mainActionsToolBar->setContextMenuPolicy(Qt::PreventContextMenu); #ifdef __APPLE__ mainActionsToolBar->setToolButtonStyle ( Qt::ToolButtonTextUnderIcon ); #else mainActionsToolBar->setToolButtonStyle ( Qt::ToolButtonTextBesideIcon ); #endif basePath = QStringLiteral(":/org.mitk.gui.qt.ext/"); imageNavigatorAction = new QAction(berry::QtStyleManager::ThemeIcon(basePath + "image_navigator.svg"), "&Image Navigator", nullptr); bool imageNavigatorViewFound = window->GetWorkbench()->GetViewRegistry()->Find("org.mitk.views.imagenavigator"); if (this->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.dicombrowser")) { openDicomEditorAction = new QmitkOpenDicomEditorAction(berry::QtStyleManager::ThemeIcon(basePath + "dicom.svg"), window); } if (this->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.stdmultiwidget")) { openStdMultiWidgetEditorAction = new QmitkOpenStdMultiWidgetEditorAction(berry::QtStyleManager::ThemeIcon(basePath + "Editor.svg"), window); } if (this->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.mxnmultiwidget")) { openMxNMultiWidgetEditorAction = new QmitkOpenMxNMultiWidgetEditorAction(berry::QtStyleManager::ThemeIcon(basePath + "Editor.svg"), window); } if (imageNavigatorViewFound) { QObject::connect(imageNavigatorAction, SIGNAL(triggered(bool)), QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onImageNavigator())); imageNavigatorAction->setCheckable(true); // add part listener for image navigator imageNavigatorPartListener.reset(new PartListenerForImageNavigator(imageNavigatorAction)); window->GetPartService()->AddPartListener(imageNavigatorPartListener.data()); berry::IViewPart::Pointer imageNavigatorView = window->GetActivePage()->FindView("org.mitk.views.imagenavigator"); imageNavigatorAction->setChecked(false); if (imageNavigatorView) { bool isImageNavigatorVisible = window->GetActivePage()->IsPartVisible(imageNavigatorView); if (isImageNavigatorVisible) imageNavigatorAction->setChecked(true); } imageNavigatorAction->setToolTip("Toggle image navigator for navigating through image"); } viewNavigatorAction = new QAction(berry::QtStyleManager::ThemeIcon(QStringLiteral(":/org.mitk.gui.qt.ext/view-manager.svg")),"&View Navigator", nullptr); viewNavigatorFound = window->GetWorkbench()->GetViewRegistry()->Find("org.mitk.views.viewnavigator"); if (viewNavigatorFound) { QObject::connect(viewNavigatorAction, SIGNAL(triggered(bool)), QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onViewNavigator())); viewNavigatorAction->setCheckable(true); // add part listener for view navigator viewNavigatorPartListener.reset(new PartListenerForViewNavigator(viewNavigatorAction)); window->GetPartService()->AddPartListener(viewNavigatorPartListener.data()); berry::IViewPart::Pointer viewnavigatorview = window->GetActivePage()->FindView("org.mitk.views.viewnavigator"); viewNavigatorAction->setChecked(false); if (viewnavigatorview) { bool isViewNavigatorVisible = window->GetActivePage()->IsPartVisible(viewnavigatorview); if (isViewNavigatorVisible) viewNavigatorAction->setChecked(true); } viewNavigatorAction->setToolTip("Toggle View Navigator"); } mainActionsToolBar->addAction(fileOpenAction); mainActionsToolBar->addAction(fileSaveProjectAction); mainActionsToolBar->addAction(closeProjectAction); mainActionsToolBar->addAction(undoAction); mainActionsToolBar->addAction(redoAction); if(this->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.dicombrowser")) { mainActionsToolBar->addAction(openDicomEditorAction); } if (this->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.stdmultiwidget")) { mainActionsToolBar->addAction(openStdMultiWidgetEditorAction); } if (this->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.mxnmultiwidget")) { mainActionsToolBar->addAction(openMxNMultiWidgetEditorAction); } if (imageNavigatorViewFound) { mainActionsToolBar->addAction(imageNavigatorAction); } if (viewNavigatorFound) { mainActionsToolBar->addAction(viewNavigatorAction); } mainWindow->addToolBar(mainActionsToolBar); // ==== Perspective Toolbar ================================== auto qPerspectiveToolbar = new QToolBar; qPerspectiveToolbar->setObjectName("perspectiveToolBar"); if (showPerspectiveToolbar) { qPerspectiveToolbar->addActions(perspGroup->actions()); mainWindow->addToolBar(qPerspectiveToolbar); } else delete qPerspectiveToolbar; if (showViewToolbar) { auto* prefService = mitk::CoreServices::GetPreferencesService(); auto* stylePrefs = prefService->GetSystemPreferences()->Node(berry::QtPreferences::QT_STYLES_NODE); bool showCategoryNames = stylePrefs->GetBool(berry::QtPreferences::QT_SHOW_TOOLBAR_CATEGORY_NAMES, true); // Order view descriptors by category QMultiMap categoryViewDescriptorMap; for (const auto &labelViewDescriptorPair : VDMap) { auto viewDescriptor = labelViewDescriptorPair.second; auto category = !viewDescriptor->GetCategoryPath().isEmpty() ? viewDescriptor->GetCategoryPath().back() : QString(); categoryViewDescriptorMap.insert(category, viewDescriptor); } // Create a separate toolbar for each category for (const auto &category : categoryViewDescriptorMap.uniqueKeys()) { auto viewDescriptorsInCurrentCategory = categoryViewDescriptorMap.values(category); if (!viewDescriptorsInCurrentCategory.isEmpty()) { auto toolbar = new QToolBar; toolbar->setObjectName(category + " View Toolbar"); mainWindow->addToolBar(toolbar); if (showCategoryNames && !category.isEmpty()) { auto categoryButton = new QToolButton; categoryButton->setToolButtonStyle(Qt::ToolButtonTextOnly); categoryButton->setText(category); categoryButton->setStyleSheet("background: transparent; margin: 0; padding: 0;"); toolbar->addWidget(categoryButton); connect(categoryButton, &QToolButton::clicked, [toolbar]() { for (QWidget* widget : toolbar->findChildren()) { if (QStringLiteral("qt_toolbar_ext_button") == widget->objectName() && widget->isVisible()) { QMouseEvent pressEvent(QEvent::MouseButtonPress, QPointF(0.0f, 0.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPointF(0.0f, 0.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); QApplication::sendEvent(widget, &pressEvent); QApplication::sendEvent(widget, &releaseEvent); } } }); } - for (const auto &viewDescriptor : qAsConst(viewDescriptorsInCurrentCategory)) + for (const auto &viewDescriptor : std::as_const(viewDescriptorsInCurrentCategory)) { auto viewAction = new berry::QtShowViewAction(window, viewDescriptor); toolbar->addAction(viewAction); } } } } QSettings settings(GetQSettingsFile(), QSettings::IniFormat); mainWindow->restoreState(settings.value("ToolbarPosition").toByteArray()); auto qStatusBar = new QStatusBar(); //creating a QmitkStatusBar for Output on the QStatusBar and connecting it with the MainStatusBar auto statusBar = new QmitkStatusBar(qStatusBar); //disabling the SizeGrip in the lower right corner statusBar->SetSizeGripEnabled(false); auto progBar = new QmitkProgressBar(); qStatusBar->addPermanentWidget(progBar, 0); progBar->hide(); // progBar->AddStepsToDo(2); // progBar->Progress(1); mainWindow->setStatusBar(qStatusBar); if (showMemoryIndicator) { auto memoryIndicator = new QmitkMemoryUsageIndicatorView(); qStatusBar->addPermanentWidget(memoryIndicator, 0); } } void QmitkExtWorkbenchWindowAdvisor::PreWindowOpen() { berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); // show the shortcut bar and progress indicator, which are hidden by // default //configurer->SetShowPerspectiveBar(true); //configurer->SetShowFastViewBars(true); //configurer->SetShowProgressIndicator(true); // // add the drag and drop support for the editor area // configurer.addEditorAreaTransfer(EditorInputTransfer.getInstance()); // configurer.addEditorAreaTransfer(ResourceTransfer.getInstance()); // configurer.addEditorAreaTransfer(FileTransfer.getInstance()); // configurer.addEditorAreaTransfer(MarkerTransfer.getInstance()); // configurer.configureEditorAreaDropListener(new EditorAreaDropAdapter( // configurer.getWindow())); this->HookTitleUpdateListeners(configurer); menuPerspectiveListener.reset(new PerspectiveListenerForMenu(this)); configurer->GetWindow()->AddPerspectiveListener(menuPerspectiveListener.data()); configurer->AddEditorAreaTransfer(QStringList("text/uri-list")); configurer->ConfigureEditorAreaDropListener(dropTargetListener.data()); } void QmitkExtWorkbenchWindowAdvisor::PostWindowOpen() { berry::WorkbenchWindowAdvisor::PostWindowOpen(); // Force Rendering Window Creation on startup. berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); ctkPluginContext* context = QmitkCommonExtPlugin::getContext(); ctkServiceReference serviceRef = context->getServiceReference(); if (serviceRef) { mitk::IDataStorageService *dsService = context->getService(serviceRef); if (dsService) { mitk::IDataStorageReference::Pointer dsRef = dsService->GetDataStorage(); mitk::DataStorageEditorInput::Pointer dsInput(new mitk::DataStorageEditorInput(dsRef)); mitk::WorkbenchUtil::OpenEditor(configurer->GetWindow()->GetActivePage(),dsInput); } } auto introPart = configurer->GetWindow()->GetWorkbench()->GetIntroManager()->GetIntro(); if (introPart.IsNotNull()) { configurer->GetWindow()->GetWorkbench()->GetIntroManager()->ShowIntro(GetWindowConfigurer()->GetWindow(), false); } } void QmitkExtWorkbenchWindowAdvisor::onIntro() { QmitkExtWorkbenchWindowAdvisorHack::undohack->onIntro(); } void QmitkExtWorkbenchWindowAdvisor::onHelp() { QmitkExtWorkbenchWindowAdvisorHack::undohack->onHelp(); } void QmitkExtWorkbenchWindowAdvisor::onHelpOpenHelpPerspective() { QmitkExtWorkbenchWindowAdvisorHack::undohack->onHelpOpenHelpPerspective(); } void QmitkExtWorkbenchWindowAdvisor::onAbout() { QmitkExtWorkbenchWindowAdvisorHack::undohack->onAbout(); } //-------------------------------------------------------------------------------- // Ugly hack from here on. Feel free to delete when command framework // and undo buttons are done. //-------------------------------------------------------------------------------- QmitkExtWorkbenchWindowAdvisorHack::QmitkExtWorkbenchWindowAdvisorHack() : QObject() { } QmitkExtWorkbenchWindowAdvisorHack::~QmitkExtWorkbenchWindowAdvisorHack() { } void QmitkExtWorkbenchWindowAdvisorHack::onUndo() { mitk::UndoModel* model = mitk::UndoController::GetCurrentUndoModel(); if (model) { if (mitk::VerboseLimitedLinearUndo* verboseundo = dynamic_cast( model )) { mitk::VerboseLimitedLinearUndo::StackDescription descriptions = verboseundo->GetUndoDescriptions(); if (descriptions.size() >= 1) { MITK_INFO << "Undo " << descriptions.front().second; } } model->Undo(); } else { MITK_ERROR << "No undo model instantiated"; } } void QmitkExtWorkbenchWindowAdvisorHack::onRedo() { mitk::UndoModel* model = mitk::UndoController::GetCurrentUndoModel(); if (model) { if (mitk::VerboseLimitedLinearUndo* verboseundo = dynamic_cast( model )) { mitk::VerboseLimitedLinearUndo::StackDescription descriptions = verboseundo->GetRedoDescriptions(); if (descriptions.size() >= 1) { MITK_INFO << "Redo " << descriptions.front().second; } } model->Redo(); } else { MITK_ERROR << "No undo model instantiated"; } } // safe calls to the complete chain // berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage()->FindView("org.mitk.views.imagenavigator"); // to cover for all possible cases of closed pages etc. static void SafeHandleNavigatorView(QString view_query_name) { berry::IWorkbench* wbench = berry::PlatformUI::GetWorkbench(); if( wbench == nullptr ) return; berry::IWorkbenchWindow::Pointer wbench_window = wbench->GetActiveWorkbenchWindow(); if( wbench_window.IsNull() ) return; berry::IWorkbenchPage::Pointer wbench_page = wbench_window->GetActivePage(); if( wbench_page.IsNull() ) return; auto wbench_view = wbench_page->FindView( view_query_name ); if( wbench_view.IsNotNull() ) { bool isViewVisible = wbench_page->IsPartVisible( wbench_view ); if( isViewVisible ) { wbench_page->HideView( wbench_view ); return; } } wbench_page->ShowView( view_query_name ); } void QmitkExtWorkbenchWindowAdvisorHack::onImageNavigator() { // show/hide ImageNavigatorView SafeHandleNavigatorView("org.mitk.views.imagenavigator"); } void QmitkExtWorkbenchWindowAdvisorHack::onViewNavigator() { // show/hide viewnavigatorView SafeHandleNavigatorView("org.mitk.views.viewnavigator"); } void QmitkExtWorkbenchWindowAdvisorHack::onEditPreferences() { QmitkPreferencesDialog _PreferencesDialog(QApplication::activeWindow()); _PreferencesDialog.exec(); } void QmitkExtWorkbenchWindowAdvisorHack::onQuit() { berry::PlatformUI::GetWorkbench()->Close(); } void QmitkExtWorkbenchWindowAdvisorHack::onResetPerspective() { berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage()->ResetPerspective(); } void QmitkExtWorkbenchWindowAdvisorHack::onClosePerspective() { berry::IWorkbenchPage::Pointer page = berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage(); page->ClosePerspective(page->GetPerspective(), true, true); } void QmitkExtWorkbenchWindowAdvisorHack::onNewWindow() { berry::PlatformUI::GetWorkbench()->OpenWorkbenchWindow(nullptr); } void QmitkExtWorkbenchWindowAdvisorHack::onIntro() { bool hasIntro = berry::PlatformUI::GetWorkbench()->GetIntroManager()->HasIntro(); if (!hasIntro) { QRegularExpression reg("(.*)(\\n)*"); QRegularExpression reg2("(\\n)*(.*)"); QFile file(":/org.mitk.gui.qt.ext/index.html"); file.open(QIODevice::ReadOnly | QIODevice::Text); //text file only for reading QString text = QString(file.readAll()); file.close(); QString title = text; title.replace(reg, ""); title.replace(reg2, ""); std::cout << title.toStdString() << std::endl; QMessageBox::information(nullptr, title, text, "Close"); } else { berry::PlatformUI::GetWorkbench()->GetIntroManager()->ShowIntro( berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow(), false); } } void QmitkExtWorkbenchWindowAdvisorHack::onHelp() { ctkPluginContext* context = QmitkCommonExtPlugin::getContext(); if (context == nullptr) { MITK_WARN << "Plugin context not set, unable to open context help"; return; } // Check if the org.blueberry.ui.qt.help plug-in is installed and started QList > plugins = context->getPlugins(); foreach(QSharedPointer p, plugins) { if (p->getSymbolicName() == "org.blueberry.ui.qt.help") { if (p->getState() != ctkPlugin::ACTIVE) { // try to activate the plug-in explicitly try { p->start(ctkPlugin::START_TRANSIENT); } catch (const ctkPluginException& pe) { MITK_ERROR << "Activating org.blueberry.ui.qt.help failed: " << pe.what(); return; } } } } ctkServiceReference eventAdminRef = context->getServiceReference(); ctkEventAdmin* eventAdmin = nullptr; if (eventAdminRef) { eventAdmin = context->getService(eventAdminRef); } if (eventAdmin == nullptr) { MITK_WARN << "ctkEventAdmin service not found. Unable to open context help"; } else { ctkEvent ev("org/blueberry/ui/help/CONTEXTHELP_REQUESTED"); eventAdmin->postEvent(ev); } } void QmitkExtWorkbenchWindowAdvisorHack::onHelpOpenHelpPerspective() { berry::PlatformUI::GetWorkbench()->ShowPerspective("org.blueberry.perspectives.help", berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()); } void QmitkExtWorkbenchWindowAdvisorHack::onAbout() { auto aboutDialog = new QmitkAboutDialog(QApplication::activeWindow(), {}); aboutDialog->open(); } void QmitkExtWorkbenchWindowAdvisor::HookTitleUpdateListeners(berry::IWorkbenchWindowConfigurer::Pointer configurer) { // hook up the listeners to update the window title titlePartListener.reset(new PartListenerForTitle(this)); titlePerspectiveListener.reset(new PerspectiveListenerForTitle(this)); editorPropertyListener.reset(new berry::PropertyChangeIntAdapter< QmitkExtWorkbenchWindowAdvisor>(this, &QmitkExtWorkbenchWindowAdvisor::PropertyChange)); // configurer.getWindow().addPageListener(new IPageListener() { // public void pageActivated(IWorkbenchPage page) { // updateTitle(false); // } // // public void pageClosed(IWorkbenchPage page) { // updateTitle(false); // } // // public void pageOpened(IWorkbenchPage page) { // // do nothing // } // }); configurer->GetWindow()->AddPerspectiveListener(titlePerspectiveListener.data()); configurer->GetWindow()->GetPartService()->AddPartListener(titlePartListener.data()); } QString QmitkExtWorkbenchWindowAdvisor::ComputeTitle() { berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); berry::IWorkbenchPage::Pointer currentPage = configurer->GetWindow()->GetActivePage(); berry::IEditorPart::Pointer activeEditor; if (currentPage) { activeEditor = lastActiveEditor.Lock(); } QString title; berry::IProduct::Pointer product = berry::Platform::GetProduct(); if (product.IsNotNull()) { title = product->GetName(); } if (title.isEmpty()) { // instead of the product name, we use a custom variable for now title = productName; } if(showMitkVersionInfo) { QString mitkVersionInfo = MITK_REVISION_DESC; if(mitkVersionInfo.isEmpty()) mitkVersionInfo = MITK_VERSION_STRING; title += " " + mitkVersionInfo; } if (showVersionInfo) { // add version informatioin QString versions = QString(" (ITK %1.%2.%3 | VTK %4.%5.%6 | Qt %7)") .arg(ITK_VERSION_MAJOR).arg(ITK_VERSION_MINOR).arg(ITK_VERSION_PATCH) .arg(VTK_MAJOR_VERSION).arg(VTK_MINOR_VERSION).arg(VTK_BUILD_VERSION) .arg(QT_VERSION_STR); title += versions; } if (currentPage) { if (activeEditor) { lastEditorTitle = activeEditor->GetTitleToolTip(); if (!lastEditorTitle.isEmpty()) title = lastEditorTitle + " - " + title; } berry::IPerspectiveDescriptor::Pointer persp = currentPage->GetPerspective(); QString label = ""; if (persp) { label = persp->GetLabel(); } berry::IAdaptable* input = currentPage->GetInput(); if (input && input != wbAdvisor->GetDefaultPageInput()) { label = currentPage->GetLabel(); } if (!label.isEmpty()) { title = label + " - " + title; } } title += " (Not for use in diagnosis or treatment of patients)"; return title; } void QmitkExtWorkbenchWindowAdvisor::RecomputeTitle() { berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); QString oldTitle = configurer->GetTitle(); QString newTitle = ComputeTitle(); if (newTitle != oldTitle) { configurer->SetTitle(newTitle); } } void QmitkExtWorkbenchWindowAdvisor::UpdateTitle(bool editorHidden) { berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); berry::IWorkbenchWindow::Pointer window = configurer->GetWindow(); berry::IEditorPart::Pointer activeEditor; berry::IWorkbenchPage::Pointer currentPage = window->GetActivePage(); berry::IPerspectiveDescriptor::Pointer persp; berry::IAdaptable* input = nullptr; if (currentPage) { activeEditor = currentPage->GetActiveEditor(); persp = currentPage->GetPerspective(); input = currentPage->GetInput(); } if (editorHidden) { activeEditor = nullptr; } // Nothing to do if the editor hasn't changed if (activeEditor == lastActiveEditor.Lock() && currentPage == lastActivePage.Lock() && persp == lastPerspective.Lock() && input == lastInput) { return; } auto lockedLastActiveEditor = lastActiveEditor.Lock(); if (lockedLastActiveEditor.IsNotNull()) { lockedLastActiveEditor->RemovePropertyListener(editorPropertyListener.data()); } lastActiveEditor = activeEditor; lastActivePage = currentPage; lastPerspective = persp; lastInput = input; if (activeEditor) { activeEditor->AddPropertyListener(editorPropertyListener.data()); } RecomputeTitle(); } void QmitkExtWorkbenchWindowAdvisor::PropertyChange(const berry::Object::Pointer& /*source*/, int propId) { if (propId == berry::IWorkbenchPartConstants::PROP_TITLE) { auto lockedLastActiveEditor = lastActiveEditor.Lock(); if (lockedLastActiveEditor.IsNotNull()) { QString newTitle = lockedLastActiveEditor->GetPartName(); if (lastEditorTitle != newTitle) { RecomputeTitle(); } } } } void QmitkExtWorkbenchWindowAdvisor::SetPerspectiveExcludeList(const QList& v) { this->perspectiveExcludeList = v; } QList QmitkExtWorkbenchWindowAdvisor::GetPerspectiveExcludeList() { return this->perspectiveExcludeList; } void QmitkExtWorkbenchWindowAdvisor::SetViewExcludeList(const QList& v) { this->viewExcludeList = v; } QList QmitkExtWorkbenchWindowAdvisor::GetViewExcludeList() { return this->viewExcludeList; } void QmitkExtWorkbenchWindowAdvisor::PostWindowClose() { berry::IWorkbenchWindow::Pointer window = this->GetWindowConfigurer()->GetWindow(); QMainWindow* mainWindow = static_cast (window->GetShell()->GetControl()); auto fileName = this->GetQSettingsFile(); if (!fileName.isEmpty()) { QSettings settings(fileName, QSettings::IniFormat); settings.setValue("ToolbarPosition", mainWindow->saveState()); } } QString QmitkExtWorkbenchWindowAdvisor::GetQSettingsFile() const { QFileInfo settingsInfo = QmitkCommonExtPlugin::getContext()->getDataFile(QT_SETTINGS_FILENAME); return settingsInfo.canonicalFilePath(); }