diff --git a/Plugins/org.blueberry.ui.qt/src/berryAbstractUICTKPlugin.cpp b/Plugins/org.blueberry.ui.qt/src/berryAbstractUICTKPlugin.cpp index 13d4c37888..c71efb0bcf 100644 --- a/Plugins/org.blueberry.ui.qt/src/berryAbstractUICTKPlugin.cpp +++ b/Plugins/org.blueberry.ui.qt/src/berryAbstractUICTKPlugin.cpp @@ -1,281 +1,309 @@ /*=================================================================== BlueBerry Platform Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "berryAbstractUICTKPlugin.h" #include "internal/berryBundleUtility.h" #include "berryWorkbenchPlugin.h" #include "berryPlatformUI.h" #include "berryIPreferencesService.h" #include "berryIPreferences.h" +#include #include #include +#include +#include namespace berry { const QString AbstractUICTKPlugin::FN_DIALOG_SETTINGS = "dialog_settings.xml"; AbstractUICTKPlugin::AbstractUICTKPlugin() : preferencesService(nullptr) { } // IDialogSettings getDialogSettings() { // if (dialogSettings == null) { // loadDialogSettings(); // } // return dialogSettings; // } // ImageRegistry getImageRegistry() { // if (imageRegistry == null) { // imageRegistry = createImageRegistry(); // initializeImageRegistry(imageRegistry); // } // return imageRegistry; // } IPreferencesService* AbstractUICTKPlugin::GetPreferencesService() const { // Create the preference store lazily. if (preferencesService == nullptr) { ctkServiceReference serviceRef = m_Context->getServiceReference(); if (!serviceRef) { BERRY_ERROR << "Preferences service not available"; } preferencesService = m_Context->getService(serviceRef); } return preferencesService; } SmartPointer AbstractUICTKPlugin::GetPreferences() const { IPreferencesService* prefService = this->GetPreferencesService(); if (prefService == nullptr) return IPreferences::Pointer(nullptr); return prefService->GetSystemPreferences(); } IWorkbench* AbstractUICTKPlugin::GetWorkbench() { return PlatformUI::GetWorkbench(); } // ImageRegistry createImageRegistry() // { // // //If we are in the UI Thread use that // if (Display.getCurrent() != null) // { // return new ImageRegistry(Display.getCurrent()); // } // // if (PlatformUI.isWorkbenchRunning()) // { // return new ImageRegistry(PlatformUI.getWorkbench().getDisplay()); // } // // //Invalid thread access if it is not the UI Thread // //and the workbench is not created. // throw new SWTError(SWT.ERROR_THREAD_INVALID_ACCESS); // } // void initializeImageRegistry(ImageRegistry reg) { // // spec'ed to do nothing // } // void loadDialogSettings() { // dialogSettings = new DialogSettings("Workbench"); //$NON-NLS-1$ // // // bug 69387: The instance area should not be created (in the call to // // #getStateLocation) if -data @none or -data @noDefault was used // IPath dataLocation = getStateLocationOrNull(); // if (dataLocation != null) { // // try r/w state area in the local file system // String readWritePath = dataLocation.append(FN_DIALOG_SETTINGS) // .toOSString(); // File settingsFile = new File(readWritePath); // if (settingsFile.exists()) { // try { // dialogSettings.load(readWritePath); // } catch (IOException e) { // // load failed so ensure we have an empty settings // dialogSettings = new DialogSettings("Workbench"); //$NON-NLS-1$ // } // // return; // } // } // // // otherwise look for bundle specific dialog settings // URL dsURL = BundleUtility.find(getBundle(), FN_DIALOG_SETTINGS); // if (dsURL == null) { // return; // } // // InputStream is = null; // try { // is = dsURL.openStream(); // BufferedReader reader = new BufferedReader( // new InputStreamReader(is, "utf-8")); //$NON-NLS-1$ // dialogSettings.load(reader); // } catch (IOException e) { // // load failed so ensure we have an empty settings // dialogSettings = new DialogSettings("Workbench"); //$NON-NLS-1$ // } finally { // try { // if (is != null) { // is.close(); // } // } catch (IOException e) { // // do nothing // } // } // } // void refreshPluginActions() { // // If the workbench is not started yet, or is no longer running, do nothing. // if (!PlatformUI.isWorkbenchRunning()) { // return; // } // // // startup() is not guaranteed to be called in the UI thread, // // but refreshPluginActions must run in the UI thread, // // so use asyncExec. See bug 6623 for more details. // Display.getDefault().asyncExec(new Runnable() { // public void run() { // WWinPluginAction.refreshActionList(); // } // }); // } // void saveDialogSettings() { // if (dialogSettings == null) { // return; // } // // try { // IPath path = getStateLocationOrNull(); // if(path == null) { // return; // } // String readWritePath = path // .append(FN_DIALOG_SETTINGS).toOSString(); // dialogSettings.save(readWritePath); // } catch (IOException e) { // // spec'ed to ignore problems // } catch (IllegalStateException e) { // // spec'ed to ignore problems // } // } void AbstractUICTKPlugin::start(ctkPluginContext* context) { Plugin::start(context); // Should only attempt refreshPluginActions() once the bundle // has been fully started. Otherwise, action delegates // can be created while in the process of creating // a triggering action delegate (if UI events are processed during startup). // Also, if the start throws an exception, the bundle will be shut down. // We don't want to have created any delegates if this happens. // See bug 63324 for more details. // bundleListener = new BundleListener() // { // public void bundleChanged(BundleEvent event) // { // if (event.getBundle() == getBundle()) // { // if (event.getType() == BundleEvent.STARTED) // { // // We're getting notified that the bundle has been started. // // Make sure it's still active. It may have been shut down between // // the time this event was queued and now. // if (getBundle().getState() == Bundle.ACTIVE) // { // refreshPluginActions(); // } // fc.removeBundleListener(this); // } // } // } // }; // context.addBundleListener(bundleListener); // bundleListener is removed in stop(BundleContext) } void AbstractUICTKPlugin::stop(ctkPluginContext* context) { Q_UNUSED(context) // try // { // if (bundleListener != null) // { // context.removeBundleListener(bundleListener); // } // saveDialogSettings(); // savePreferenceStore(); // preferenceStore = null; // if (imageRegistry != null) // imageRegistry.dispose(); // imageRegistry = null; //} Plugin::stop(context); } QIcon AbstractUICTKPlugin::ImageDescriptorFromPlugin( const QString& pluginId, const QString& imageFilePath) { if (pluginId.isEmpty() || imageFilePath.isEmpty()) { throw ctkInvalidArgumentException("argument cannot be empty"); } // if the plug-in is not ready then there is no image QSharedPointer plugin = BundleUtility::FindPlugin(pluginId); if (!BundleUtility::IsReady(plugin.data())) { return QIcon(); } QByteArray imgContent = plugin->getResource(imageFilePath); + + if (imageFilePath.endsWith(".svg", Qt::CaseInsensitive)) + imgContent = ApplyTheme(imgContent); + QImage image = QImage::fromData(imgContent); QPixmap pixmap = QPixmap::fromImage(image); return QIcon(pixmap); } QIcon AbstractUICTKPlugin::GetMissingIcon() { return QIcon(":/org.blueberry.ui.qt/icon_missing.png"); } +QByteArray AbstractUICTKPlugin::ApplyTheme(const QByteArray &originalSVG) +{ + auto styleSheet = qApp->styleSheet(); + + if (styleSheet.isEmpty()) + return originalSVG; + + QRegularExpression re; + re.setPattern(QStringLiteral("iconColor\\s*[=:]\\s*(#[0-9a-f]{6})")); + re.setPatternOptions(QRegularExpression::CaseInsensitiveOption); + auto match = re.match(styleSheet); + + auto iconColor = match.hasMatch() + ? match.captured(1) + : QStringLiteral("#000000"); + + auto themedSVG = QString(originalSVG).replace(QStringLiteral("#00ff00"), iconColor, Qt::CaseInsensitive); + + return themedSVG.toLatin1(); +} + } diff --git a/Plugins/org.blueberry.ui.qt/src/berryAbstractUICTKPlugin.h b/Plugins/org.blueberry.ui.qt/src/berryAbstractUICTKPlugin.h index 3e07ba3100..470688516e 100644 --- a/Plugins/org.blueberry.ui.qt/src/berryAbstractUICTKPlugin.h +++ b/Plugins/org.blueberry.ui.qt/src/berryAbstractUICTKPlugin.h @@ -1,294 +1,296 @@ /*=================================================================== BlueBerry Platform Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef BERRYABSTRACTUICTKPLUGIN_H_ #define BERRYABSTRACTUICTKPLUGIN_H_ #include #include namespace berry { template class SmartPointer; struct IPreferences; struct IPreferencesService; struct IWorkbench; /** * \ingroup org_blueberry_ui_qt * * Abstract base class for plug-ins that integrate with the BlueBerry platform UI. *

* Subclasses obtain the following capabilities: *

*

* Preferences *

    *
  • The platform core runtime contains general support for plug-in * preferences (org.blueberry.core.runtime.Preferences). * This class provides appropriate conversion to the older JFace preference * API (org.blueberry.jface.preference.IPreferenceStore).
  • *
  • The method getPreferenceStore returns the JFace preference * store (cf. Plugin.getPluginPreferences which returns * a core runtime preferences object.
  • *
  • Subclasses may reimplement initializeDefaultPreferences * to set up any default values for preferences using JFace API. In this * case, initializeDefaultPluginPreferences should not be * overridden.
  • *
  • Subclasses may reimplement * initializeDefaultPluginPreferences to set up any default * values for preferences using core runtime API. In this * case, initializeDefaultPreferences should not be * overridden.
  • *
  • Preferences are also saved automatically on plug-in shutdown. * However, saving preferences immediately after changing them is * strongly recommended, since that ensures that preference settings * are not lost even in the event of a platform crash.
  • *
* Dialogs *
    *
  • The dialog store is read the first time getDialogSettings * is called.
  • *
  • The dialog store allows the plug-in to "record" important choices made * by the user in a wizard or dialog, so that the next time the * wizard/dialog is used the widgets can be defaulted to better values. A * wizard could also use it to record the last 5 values a user entered into * an editable combo - to show "recent values".
  • *
  • The dialog store is found in the file whose name is given by the * constant FN_DIALOG_STORE. A dialog store file is first * looked for in the plug-in's read/write state area; if not found there, * the plug-in's install directory is checked. * This allows a plug-in to ship with a read-only copy of a dialog store * file containing initial values for certain settings.
  • *
  • Plug-in code can call saveDialogSettings to cause settings to * be saved in the plug-in's read/write state area. A plug-in may opt to do * this each time a wizard or dialog is closed to ensure the latest * information is always safe on disk.
  • *
  • Dialog settings are also saved automatically on plug-in shutdown.
  • *
*

* For easy access to your plug-in object, use the singleton pattern. Declare a * static variable in your plug-in class for the singleton. Store the first * (and only) instance of the plug-in class in the singleton when it is created. * Then access the singleton when needed through a static getDefault * method. *

*

* See the description on {@link Plugin}. *

*/ class BERRY_UI_QT AbstractUICTKPlugin : public Plugin { Q_OBJECT private: /** * The name of the dialog settings file (value * "dialog_settings.xml"). */ static const QString FN_DIALOG_SETTINGS; /** * Storage for dialog and wizard data; null if not yet * initialized. */ //DialogSettings dialogSettings = null; /** * Storage for preferences. */ mutable IPreferencesService* preferencesService; /** * The bundle listener used for kicking off refreshPluginActions(). */ //BundleListener bundleListener; public: /** * Creates an abstract UI plug-in runtime object. *

* Plug-in runtime classes are ctkPluginActivators and so must * have an default constructor. This method is called by the runtime when * the associated bundle is being activated. */ AbstractUICTKPlugin(); /** * Returns the dialog settings for this UI plug-in. * The dialog settings is used to hold persistent state data for the various * wizards and dialogs of this plug-in in the context of a workbench. *

* If an error occurs reading the dialog store, an empty one is quietly created * and returned. *

*

* Subclasses may override this method but are not expected to. *

* * @return the dialog settings */ // IDialogSettings getDialogSettings(); /** * Returns the preferences service for this UI plug-in. * This preferences service is used to hold persistent settings for this plug-in in * the context of a workbench. Some of these settings will be user controlled, * whereas others may be internal setting that are never exposed to the user. *

* If an error occurs reading the preferences service, an empty preference service is * quietly created, initialized with defaults, and returned. *

* * @return the preferences service */ IPreferencesService* GetPreferencesService() const; SmartPointer GetPreferences() const; /** * Returns the Platform UI workbench. *

* This method exists as a convenience for plugin implementors. The * workbench can also be accessed by invoking PlatformUI.getWorkbench(). *

* @return IWorkbench the workbench for this plug-in */ IWorkbench* GetWorkbench(); protected: /** * Returns a new image registry for this plugin-in. The registry will be * used to manage images which are frequently used by the plugin-in. *

* The default implementation of this method creates an empty registry. * Subclasses may override this method if needed. *

* * @return ImageRegistry the resulting registry. * @see #getImageRegistry */ // ImageRegistry createImageRegistry(); /** * Initializes an image registry with images which are frequently used by the * plugin. *

* The image registry contains the images used by this plug-in that are very * frequently used and so need to be globally shared within the plug-in. Since * many OSs have a severe limit on the number of images that can be in memory * at any given time, each plug-in should only keep a small number of images in * its registry. *

* Implementors should create a JFace image descriptor for each frequently used * image. The descriptors describe how to create/find the image should it be needed. * The image described by the descriptor is not actually allocated until someone * retrieves it. *

* Subclasses may override this method to fill the image registry. *

* @param reg the registry to initalize * * @see #getImageRegistry */ // void initializeImageRegistry(ImageRegistry reg); /** * Loads the dialog settings for this plug-in. * The default implementation first looks for a standard named file in the * plug-in's read/write state area; if no such file exists, the plug-in's * install directory is checked to see if one was installed with some default * settings; if no file is found in either place, a new empty dialog settings * is created. If a problem occurs, an empty settings is silently used. *

* This framework method may be overridden, although this is typically * unnecessary. *

*/ // void loadDialogSettings(); /** * Refreshes the actions for the plugin. * This method is called from startup. *

* This framework method may be overridden, although this is typically * unnecessary. *

*/ // void refreshPluginActions(); /** * Saves this plug-in's dialog settings. * Any problems which arise are silently ignored. */ // void saveDialogSettings(); public: /** * The AbstractUIPlugin implementation of this Plugin * method refreshes the plug-in actions. Subclasses may extend this method, * but must send super first. */ void start(ctkPluginContext* context) override; /** * The AbstractUIPlugin implementation of this Plugin * method saves this plug-in's preference and dialog stores and shuts down * its image registry (if they are in use). Subclasses may extend this * method, but must send super last. A try-finally statement should * be used where necessary to ensure that super.shutdown() is * always done. */ void stop(ctkPluginContext* context) override; /** * Creates and returns a new image descriptor for an image file located * within the specified plug-in. *

* This is a convenience method that simply locates the image file in * within the plug-in (no image registries are involved). The path is * relative to the root of the plug-in, and takes into account files * coming from plug-in fragments. The path may include $arg$ elements. * However, the path must not have a leading "." or path separator. * Clients should use a path like "icons/mysample.gif" rather than * "./icons/mysample.gif" or "/icons/mysample.gif". *

* * @param pluginId the id of the plug-in containing the image file; * null is returned if the plug-in does not exist * @param imageFilePath the relative path of the image file, relative to the * root of the plug-in; the path must be legal * @return an image descriptor, or null if no image * could be found */ static QIcon ImageDescriptorFromPlugin( const QString& pluginId, const QString& imageFilePath); static QIcon GetMissingIcon(); + + static QByteArray ApplyTheme(const QByteArray &originalSVG); }; } // namespace berry #endif /*BERRYABSTRACTUICTKPLUGIN_H_*/