diff --git a/Modules/AppUtil/src/mitkBaseApplication.cpp b/Modules/AppUtil/src/mitkBaseApplication.cpp index acf981f893..030468afad 100644 --- a/Modules/AppUtil/src/mitkBaseApplication.cpp +++ b/Modules/AppUtil/src/mitkBaseApplication.cpp @@ -1,927 +1,925 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #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 : 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); + provFile.setFile(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 +#ifdef Q_OS_MACOS 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 : 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/QtWidgets/src/QmitkPropertyItemDelegate.cpp b/Modules/QtWidgets/src/QmitkPropertyItemDelegate.cpp index 1ab8f63a4d..544b7690a2 100644 --- a/Modules/QtWidgets/src/QmitkPropertyItemDelegate.cpp +++ b/Modules/QtWidgets/src/QmitkPropertyItemDelegate.cpp @@ -1,380 +1,380 @@ /*============================================================================ 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 "QmitkPropertyItemDelegate.h" #include "QmitkPropertyItemModel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include QmitkColorWidget::QmitkColorWidget(QWidget *parent) : QWidget(parent), m_LineEdit(new QLineEdit), m_Button(new QToolButton) { m_LineEdit->setText(m_Color.name()); m_Button->setText("..."); QHBoxLayout *layout = new QHBoxLayout; layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(0); layout->addWidget(m_LineEdit); layout->addWidget(m_Button); this->setFocusProxy(m_LineEdit); this->setLayout(layout); connect(m_LineEdit, SIGNAL(editingFinished()), this, SLOT(OnLineEditEditingFinished())); connect(m_Button, SIGNAL(clicked()), this, SLOT(OnButtonClicked())); } QmitkColorWidget::~QmitkColorWidget() { } QColor QmitkColorWidget::GetColor() const { return m_Color; } void QmitkColorWidget::SetColor(QColor color) { m_Color = color; m_LineEdit->setText(color.name()); } void QmitkColorWidget::OnLineEditEditingFinished() { - if (!QColor::isValidColor(m_LineEdit->text())) + if (!QColor::isValidColorName(m_LineEdit->text())) m_LineEdit->setText("#000000"); - m_Color.setNamedColor(m_LineEdit->text()); + m_Color = QColor::fromString(m_LineEdit->text()); } void QmitkColorWidget::OnButtonClicked() { QColor color = QColorDialog::getColor(m_Color, QApplication::activeWindow()); if (color.isValid()) { this->SetColor(color); emit ColorPicked(); } } QmitkComboBoxListView::QmitkComboBoxListView(QComboBox *comboBox) : m_ComboBox(comboBox) { } QmitkComboBoxListView::~QmitkComboBoxListView() { } void QmitkComboBoxListView::paintEvent(QPaintEvent *event) { if (m_ComboBox != nullptr) { QStyleOptionComboBox option; option.initFrom(m_ComboBox); option.editable = m_ComboBox->isEditable(); if (m_ComboBox->style()->styleHint(QStyle::SH_ComboBox_Popup, &option, m_ComboBox)) { QStyleOptionMenuItem menuOption; menuOption.initFrom(this); menuOption.palette = this->palette(); menuOption.state = QStyle::State_None; menuOption.checkType = QStyleOptionMenuItem::NotCheckable; menuOption.menuRect = event->rect(); menuOption.maxIconWidth = 0; QPainter painter(this->viewport()); m_ComboBox->style()->drawControl(QStyle::CE_MenuEmptyArea, &menuOption, &painter, this); } } QListView::paintEvent(event); } void QmitkComboBoxListView::resizeEvent(QResizeEvent *event) { int width = this->viewport()->width(); int height = this->contentsSize().height(); this->resizeContents(width, height); QListView::resizeEvent(event); } void QmitkComboBoxListView::initViewItemOption(QStyleOptionViewItem* option) const { QListView::initViewItemOption(option); option->showDecorationSelected = true; if (m_ComboBox != nullptr) option->font = m_ComboBox->font(); } 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; }; QmitkPropertyItemDelegate::QmitkPropertyItemDelegate(QObject *parent) : QStyledItemDelegate(parent) { } QmitkPropertyItemDelegate::~QmitkPropertyItemDelegate() { } QWidget *QmitkPropertyItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { QVariant data = index.data(Qt::EditRole); if (data.isValid()) { - if (data.type() == QVariant::Int) + if (data.typeId() == QMetaType::Int) { QSpinBox *spinBox = new QSpinBox(parent); mitk::CoreServicePointer extensions(mitk::CoreServices::GetPropertyExtensions()); std::string name = this->GetPropertyName(index); if (!name.empty() && extensions->HasExtension(name)) { mitk::IntPropertyExtension::Pointer extension = dynamic_cast(extensions->GetExtension(name).GetPointer()); if (extension.IsNotNull()) { spinBox->setMinimum(extension->GetMinimum()); spinBox->setMaximum(extension->GetMaximum()); spinBox->setSingleStep(extension->GetSingleStep()); } } connect(spinBox, SIGNAL(editingFinished()), this, SLOT(OnSpinBoxEditingFinished())); return spinBox; } - if (data.type() == QVariant::Double || static_cast(data.type()) == QMetaType::Float) + if (data.typeId() == QMetaType::Double || data.typeId() == QMetaType::Float) { QDoubleSpinBox *spinBox = new QDoubleSpinBox(parent); mitk::CoreServicePointer extensions(mitk::CoreServices::GetPropertyExtensions()); std::string name = this->GetPropertyName(index); if (!name.empty() && extensions->HasExtension(name)) { mitk::FloatPropertyExtension::Pointer extension = dynamic_cast(extensions->GetExtension(name).GetPointer()); if (extension.IsNotNull()) { spinBox->setMinimum(extension->GetMinimum()); spinBox->setMaximum(extension->GetMaximum()); spinBox->setSingleStep(extension->GetSingleStep()); spinBox->setDecimals(extension->GetDecimals()); } } else { spinBox->setSingleStep(0.1); spinBox->setDecimals(4); } if (name == "opacity") // TODO { spinBox->setMinimum(0.0); spinBox->setMaximum(1.0); } connect(spinBox, SIGNAL(editingFinished()), this, SLOT(OnSpinBoxEditingFinished())); return spinBox; } - if (data.type() == QVariant::StringList) + if (data.typeId() == QMetaType::QStringList) { QComboBox *comboBox = new QComboBox(parent); comboBox->setView(new QmitkComboBoxListView(comboBox)); comboBox->addItems(data.toStringList()); connect(comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnComboBoxCurrentIndexChanged(int))); return comboBox; } - if (data.type() == QVariant::Color) + if (data.typeId() == QMetaType::QColor) { QmitkColorWidget *colorWidget = new QmitkColorWidget(parent); connect(colorWidget, SIGNAL(ColorPicked()), this, SLOT(OnColorPicked())); return colorWidget; } } return QStyledItemDelegate::createEditor(parent, option, index); } std::string QmitkPropertyItemDelegate::GetPropertyName(const QModelIndex &index) const { auto propertyList = m_PropertyList.Lock(); if (propertyList.IsNotNull()) { mitk::BaseProperty *property = reinterpret_cast(index.data(mitk::PropertyRole).value()); const mitk::PropertyList::PropertyMap *propertyMap = propertyList->GetMap(); mitk::PropertyList::PropertyMap::const_iterator it = std::find_if(propertyMap->begin(), propertyMap->end(), PropertyEqualTo(property)); if (it != propertyMap->end()) return it->first; } return ""; } void QmitkPropertyItemDelegate::OnComboBoxCurrentIndexChanged(int) { QComboBox *comboBox = qobject_cast(sender()); emit commitData(comboBox); emit closeEditor(comboBox); } void QmitkPropertyItemDelegate::OnSpinBoxEditingFinished() { QAbstractSpinBox *spinBox = qobject_cast(sender()); emit commitData(spinBox); emit closeEditor(spinBox); } void QmitkPropertyItemDelegate::OnColorPicked() { QmitkColorWidget *colorWidget = qobject_cast(sender()); emit commitData(colorWidget); emit closeEditor(colorWidget); } void QmitkPropertyItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QVariant data = index.data(); - if (index.column() == 1 && data.type() == QVariant::Color) + if (index.column() == 1 && data.typeId() == QMetaType::QColor) { painter->fillRect(option.rect, data.value()); return; } QStyledItemDelegate::paint(painter, option, index); } void QmitkPropertyItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { QVariant data = index.data(Qt::EditRole); if (!data.isValid()) return; - if (data.type() == QVariant::StringList) + if (data.typeId() == QMetaType::QStringList) { QComboBox *comboBox = qobject_cast(editor); comboBox->setCurrentIndex(comboBox->findText(index.data().toString())); } - if (data.type() == QVariant::Color) + if (data.typeId() == QMetaType::QColor) { QmitkColorWidget *colorWidget = qobject_cast(editor); colorWidget->SetColor(data.value()); } else { QStyledItemDelegate::setEditorData(editor, index); } } void QmitkPropertyItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QVariant data = index.data(Qt::EditRole); if (!data.isValid()) return; - if (data.type() == QVariant::Int) + if (data.typeId() == QMetaType::Int) { QSpinBox *spinBox = qobject_cast(editor); model->setData(index, spinBox->value()); } - else if (data.type() == QVariant::Double) + else if (data.typeId() == QMetaType::Double) { QDoubleSpinBox *spinBox = qobject_cast(editor); model->setData(index, spinBox->value()); } - else if (static_cast(data.type()) == QMetaType::Float) + else if (data.typeId() == QMetaType::Float) { QDoubleSpinBox *spinBox = qobject_cast(editor); model->setData(index, static_cast(spinBox->value())); } - else if (data.type() == QVariant::StringList) + else if (data.typeId() == QMetaType::QStringList) { QComboBox *comboBox = qobject_cast(editor); model->setData(index, comboBox->currentText()); } - else if (data.type() == QVariant::Color) + else if (data.typeId() == QMetaType::QColor) { QmitkColorWidget *colorWidget = qobject_cast(editor); model->setData(index, colorWidget->GetColor()); } else { QStyledItemDelegate::setModelData(editor, model, index); } } void QmitkPropertyItemDelegate::SetPropertyList(mitk::PropertyList *propertyList) { if (m_PropertyList != propertyList) m_PropertyList = propertyList; } diff --git a/Plugins/org.blueberry.ui.qt/src/internal/defaultpresentation/berryQCTabBar.cpp b/Plugins/org.blueberry.ui.qt/src/internal/defaultpresentation/berryQCTabBar.cpp index a76bf29bb2..99a8317d73 100755 --- a/Plugins/org.blueberry.ui.qt/src/internal/defaultpresentation/berryQCTabBar.cpp +++ b/Plugins/org.blueberry.ui.qt/src/internal/defaultpresentation/berryQCTabBar.cpp @@ -1,106 +1,106 @@ /*============================================================================ 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 "berryQCTabBar.h" #include #include namespace berry { QCTabBar::QCTabBar(QWidget* parent) : QTabBar(parent) { } QCTabBar::~QCTabBar() { qDeleteAll(tabItemList); } void QCTabBar::tabRemoved(int index) { if (index >= 0 && index < tabItemList.size()) { delete tabItemList.takeAt(index); } } void QCTabBar::mousePressEvent(QMouseEvent* event) { if (event->button() == Qt::LeftButton) - dragStartPosition = event->globalPos(); + dragStartPosition = event->globalPosition().toPoint(); QTabBar::mousePressEvent(event); } void QCTabBar::mouseMoveEvent(QMouseEvent* event) { if (!(event->buttons() & Qt::LeftButton)) { QTabBar::mouseMoveEvent(event); return; } - if ((event->globalPos() - dragStartPosition).manhattanLength() + if ((event->globalPosition().toPoint() - dragStartPosition).manhattanLength() < QApplication::startDragDistance()) { QTabBar::mouseMoveEvent(event); return; } emit dragStarted(dragStartPosition); } AbstractTabItem* QCTabBar::getTab(int index) const { if (index < 0 || index >= tabItemList.size()) return nullptr; return tabItemList[index]; } QList QCTabBar::getTabs() const { return tabItemList; } void QCTabBar::insertTab(int index, AbstractTabItem* item) { tabItemList.insert(index, item); QTabBar::insertTab(index, QString()); } void QCTabBar::moveAbstractTab(int from, int to) { AbstractTabItem* item = tabItemList[from]; if (to >= tabItemList.size()) --to; tabItemList.removeAt(from); tabItemList.insert(to, item); this->moveTab(from, to); } void QCTabBar::setCurrentTab(AbstractTabItem* item) { this->setCurrentIndex(tabItemList.indexOf(item)); } AbstractTabItem* QCTabBar::getCurrentTab() { int index = this->currentIndex(); return tabItemList[index]; } } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkFileSaveAction.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkFileSaveAction.cpp index 58460a6b40..45448868cb 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkFileSaveAction.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkFileSaveAction.cpp @@ -1,275 +1,275 @@ /*============================================================================ 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 "QmitkFileSaveAction.h" #include "internal/org_mitk_gui_qt_application_Activator.h" #include #include #include #include #include #include #include #include #include #include #include namespace { mitk::DataStorage::Pointer GetDataStorage() { auto context = mitk::org_mitk_gui_qt_application_Activator::GetContext(); if (nullptr == context) return nullptr; auto dataStorageServiceReference = context->getServiceReference(); if (!dataStorageServiceReference) return nullptr; auto dataStorageService = context->getService(dataStorageServiceReference); if (nullptr == dataStorageService) return nullptr; auto dataStorageReference = dataStorageService->GetDataStorage(); if (dataStorageReference.IsNull()) return nullptr; return dataStorageReference->GetDataStorage(); } QString GetParentPath(mitk::DataNode::Pointer dataNode) { if (dataNode.IsNull()) return ""; auto dataStorage = GetDataStorage(); if (dataStorage.IsNull()) return ""; auto sources = dataStorage->GetSources(dataNode); if (sources.IsNull() || sources->empty()) return ""; const auto &parentNode = sources->front(); if (parentNode.IsNull()) return ""; auto data = parentNode->GetData(); if (nullptr != data) { auto pathProperty = data->GetConstProperty("path"); if (pathProperty.IsNotNull()) return QFileInfo(QString::fromStdString(pathProperty->GetValueAsString())).canonicalPath(); } return GetParentPath(parentNode); } } class QmitkFileSaveActionPrivate { private: void HandleSelectionChanged(const berry::IWorkbenchPart::Pointer& /*part*/, const berry::ISelection::ConstPointer& selection) { this->SetEnabled(selection); } QScopedPointer m_SelectionListener; public: QmitkFileSaveActionPrivate() : m_SelectionListener(new berry::NullSelectionChangedAdapter( this, &QmitkFileSaveActionPrivate::HandleSelectionChanged)) { } ~QmitkFileSaveActionPrivate() { auto window = m_Window.Lock(); if (window.IsNotNull()) { window->GetSelectionService()->RemoveSelectionListener(m_SelectionListener.data()); } } void Init(berry::IWorkbenchWindow* window, QAction* action) { m_Window = berry::IWorkbenchWindow::Pointer(window); m_Action = action; m_Action->setText("&Save..."); m_Action->setToolTip("Save data objects (images, surfaces,...)"); berry::ISelectionService* selectionService = m_Window.Lock()->GetSelectionService(); SetEnabled(selectionService->GetSelection()); selectionService->AddSelectionListener(m_SelectionListener.data()); QObject::connect(m_Action, SIGNAL(triggered(bool)), m_Action, SLOT(Run())); } mitk::IPreferences* GetPreferences() const { auto* prefService = mitk::CoreServices::GetPreferencesService(); return prefService != nullptr ? prefService->GetSystemPreferences()->Node("/General") : nullptr; } QString GetLastFileSavePath() const { auto* prefs = GetPreferences(); return prefs != nullptr ? QString::fromStdString(prefs->Get("LastFileSavePath", "")) : QString(); } void SetLastFileSavePath(const QString& path) const { auto* prefs = GetPreferences(); if (prefs != nullptr) { prefs->Put("LastFileSavePath", path.toStdString()); prefs->Flush(); } } void SetEnabled(berry::ISelection::ConstPointer selection) { mitk::DataNodeSelection::ConstPointer nodeSelection = selection.Cast(); if (nodeSelection.IsNotNull() && !selection->IsEmpty()) { bool enable = false; std::list dataNodes = nodeSelection->GetSelectedDataNodes(); for (std::list::const_iterator nodeIter = dataNodes.begin(), nodeIterEnd = dataNodes.end(); nodeIter != nodeIterEnd; ++nodeIter) { if ((*nodeIter)->GetData() != nullptr) { enable = true; break; } } m_Action->setEnabled(enable); } else { m_Action->setEnabled(false); } } berry::IWorkbenchWindow::WeakPtr m_Window; QAction* m_Action; }; QmitkFileSaveAction::QmitkFileSaveAction(berry::IWorkbenchWindow::Pointer window) : QAction(tr("Save...")) , d(new QmitkFileSaveActionPrivate) { d->Init(window.GetPointer(), this); } QmitkFileSaveAction::QmitkFileSaveAction(const QIcon& icon, berry::IWorkbenchWindow::Pointer window) : QAction(tr("Save...")) , d(new QmitkFileSaveActionPrivate) { d->Init(window.GetPointer(), this); setIcon(icon); } QmitkFileSaveAction::QmitkFileSaveAction(const QIcon& icon, berry::IWorkbenchWindow* window) : QAction(tr("Save...")) , d(new QmitkFileSaveActionPrivate) { d->Init(window, this); setIcon(icon); } QmitkFileSaveAction::~QmitkFileSaveAction() { } void QmitkFileSaveAction::Run() { // get the list of selected base data objects mitk::DataNodeSelection::ConstPointer selection = d->m_Window.Lock()->GetSelectionService()->GetSelection().Cast(); if (selection.IsNull() || selection->IsEmpty()) { MITK_ERROR << "Assertion failed: data node selection is nullptr or empty"; return; } std::list dataNodes = selection->GetSelectedDataNodes(); std::vector data; QStringList names; for (std::list::const_iterator nodeIter = dataNodes.begin(), nodeIterEnd = dataNodes.end(); nodeIter != nodeIterEnd; ++nodeIter) { data.push_back((*nodeIter)->GetData()); std::string name; (*nodeIter)->GetStringProperty("name", name); names.push_back(QString::fromStdString(name)); } QString path; if (1 == data.size()) { if (nullptr != data[0]) { auto pathProperty = data[0]->GetConstProperty("path"); if (pathProperty.IsNotNull()) path = QFileInfo(QString::fromStdString(pathProperty->GetValueAsString())).canonicalPath(); } if (path.isEmpty()) path = GetParentPath(dataNodes.front()); } if (path.isEmpty()) path = d->GetLastFileSavePath(); try { auto setPathProperty = true; - auto fileNames = QmitkIOUtil::Save(data, names, path, d->m_Action->parentWidget(), setPathProperty); + auto fileNames = QmitkIOUtil::Save(data, names, path, qobject_cast(d->m_Action->parent()), setPathProperty); if (!fileNames.empty()) d->SetLastFileSavePath(QFileInfo(fileNames.back()).absolutePath()); } catch (const mitk::Exception& e) { MITK_INFO << e; return; } }