All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.ui.plugin.AbstractUIPlugin Maven / Gradle / Ivy

There is a newer version: 3.108.0.v20160602-1232
Show newest version
/*******************************************************************************
 * Copyright (c) 2000, 2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.ui.plugin;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IPluginDescriptor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jface.dialogs.DialogSettings;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTError;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.WWinPluginAction;
import org.eclipse.ui.internal.util.BundleUtility;
import org.eclipse.ui.preferences.ScopedPreferenceStore;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleListener;

/**
 * Abstract base class for plug-ins that integrate with the Eclipse platform UI.
 * 

* Subclasses obtain the following capabilities: *

*

* Preferences *

    *
  • The platform core runtime contains general support for plug-in * preferences (org.eclipse.core.runtime.Preferences). * This class provides appropriate conversion to the older JFace preference * API (org.eclipse.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.
  • *
* Images *
    *
  • A typical UI plug-in will have some images that are used very frequently * and so need to be cached and shared. The plug-in's image registry * provides a central place for a plug-in to store its common images. * Images managed by the registry are created lazily as needed, and will be * automatically disposed of when the plug-in shuts down. Note that the * number of registry images should be kept to a minimum since many OSs * have severe limits on the number of images that can be in memory at once. *
*

* 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}. *

*/ public abstract class AbstractUIPlugin extends Plugin { /** * The name of the dialog settings file (value * "dialog_settings.xml"). */ private static final String FN_DIALOG_SETTINGS = "dialog_settings.xml"; //$NON-NLS-1$ /** * Storage for dialog and wizard data; null if not yet * initialized. */ private IDialogSettings dialogSettings = null; /** * Storage for preferences. */ private ScopedPreferenceStore preferenceStore; /** * The registry for all graphic images; null if not yet * initialized. */ private ImageRegistry imageRegistry = null; /** * The bundle listener used for kicking off refreshPluginActions(). * * @since 3.0.1 */ private BundleListener bundleListener; /** * Creates an abstract UI plug-in runtime object for the given plug-in * descriptor. *

* Note that instances of plug-in runtime classes are automatically created * by the platform in the course of plug-in activation. *

* * @param descriptor the plug-in descriptor * @see Plugin#Plugin(org.eclipse.core.runtime.IPluginDescriptor descriptor) * @deprecated * In Eclipse 3.0 this constructor has been replaced by * {@link #AbstractUIPlugin()}. Implementations of * MyPlugin(IPluginDescriptor descriptor) should be changed to * MyPlugin() and call super() instead of * super(descriptor). * The MyPlugin(IPluginDescriptor descriptor) constructor is * called only for plug-ins which explicitly require the * org.eclipse.core.runtime.compatibility plug-in (or, as in this case, * subclasses which might). */ @Deprecated public AbstractUIPlugin(IPluginDescriptor descriptor) { super(descriptor); } /** * Creates an abstract UI plug-in runtime object. *

* Plug-in runtime classes are BundleActivators and so must * have an default constructor. This method is called by the runtime when * the associated bundle is being activated. *

* For more details, see Plugin's default constructor. * * @see Plugin#Plugin() * @since 3.0 */ public AbstractUIPlugin() { super(); } /** * 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 */ protected 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); } /** * 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 */ public IDialogSettings getDialogSettings() { if (dialogSettings == null) { loadDialogSettings(); } return dialogSettings; } /** * Returns the image registry for this UI plug-in. *

* 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, a plug-in should only keep a small number of images in their * registry. *

* Subclasses should reimplement initializeImageRegistry if they have * custom graphic images to load. *

*

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

* * @return the image registry */ public ImageRegistry getImageRegistry() { if (imageRegistry == null) { imageRegistry = createImageRegistry(); initializeImageRegistry(imageRegistry); } return imageRegistry; } /** * Returns the preference store for this UI plug-in. * This preference store 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 preference store, an empty preference store is * quietly created, initialized with defaults, and returned. *

*

* NOTE: As of Eclipse 3.1 this method is * no longer referring to the core runtime compatibility layer and so * plug-ins relying on Plugin#initializeDefaultPreferences * will have to access the compatibility layer themselves. *

* * @return the preference store */ public IPreferenceStore getPreferenceStore() { // Create the preference store lazily. if (preferenceStore == null) { preferenceStore = new ScopedPreferenceStore(InstanceScope.INSTANCE, getBundle().getSymbolicName()); } return preferenceStore; } /** * 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 */ public IWorkbench getWorkbench() { return PlatformUI.getWorkbench(); } /** * Initializes a preference store with default preference values * for this plug-in. *

* This method is called after the preference store is initially loaded * (default values are never stored in preference stores). *

*

* The default implementation of this method does nothing. * Subclasses should reimplement this method if the plug-in has any preferences. *

*

* A subclass may reimplement this method to set default values for the * preference store using JFace API. This is the older way of initializing * default values. If this method is reimplemented, do not override * initializeDefaultPluginPreferences(). *

* * @param store the preference store to fill * * @deprecated this is only called if the runtime compatibility layer is * present. See {@link #initializeDefaultPluginPreferences}. */ @Deprecated protected void initializeDefaultPreferences(IPreferenceStore store) { // spec'ed to do nothing } /** * The AbstractUIPlugin implementation of this * Plugin method forwards to * initializeDefaultPreferences(IPreferenceStore). *

* A subclass may reimplement this method to set default values for the core * runtime preference store in the standard way. This is the recommended way * to do this. The older * initializeDefaultPreferences(IPreferenceStore) method * serves a similar purpose. If this method is reimplemented, do not send * super, and do not override * initializeDefaultPreferences(IPreferenceStore). *

* * @deprecated this is only called if the runtime compatibility layer is * present. See the deprecated comment in * {@link Plugin#initializeDefaultPluginPreferences}. * * @see #initializeDefaultPreferences * @since 2.0 */ @Deprecated @Override protected void initializeDefaultPluginPreferences() { // N.B. by the time this method is called, the plug-in has a // core runtime preference store (no default values) // call loadPreferenceStore (only) for backwards compatibility with Eclipse 1.0 loadPreferenceStore(); // call initializeDefaultPreferences (only) for backwards compatibility // with Eclipse 1.0 initializeDefaultPreferences(getPreferenceStore()); } /** * 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 initialize * * @see #getImageRegistry */ protected void initializeImageRegistry(ImageRegistry reg) { // spec'ed to do nothing } /** * 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. *

*/ protected 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 } } } /** * Loads the preference store for this plug-in. * The default implementation looks for a standard named file in the * plug-in's read/write state area. If no file is found or a problem * occurs, a new empty preference store is silently created. *

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

* * @deprecated As of Eclipse 2.0, a basic preference store exists for all * plug-ins. This method now exists only for backwards compatibility. * It is called as the plug-in's preference store is being initialized. * The plug-ins preferences are loaded from the file regardless of what * this method does. */ @Deprecated protected void loadPreferenceStore() { // do nothing by default } /** * Refreshes the actions for the plugin. * This method is called from startup. *

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

*/ protected 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() { @Override public void run() { WWinPluginAction.refreshActionList(); } }); } /** * Saves this plug-in's dialog settings. * Any problems which arise are silently ignored. */ protected 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 } } /** * Saves this plug-in's preference store. * Any problems which arise are silently ignored. * * @see Plugin#savePluginPreferences() * @deprecated As of Eclipse 2.0, preferences exist for all plug-ins. The * equivalent of this method is Plugin.savePluginPreferences. * This method now calls savePluginPreferences, and exists only for * backwards compatibility. */ @Deprecated protected void savePreferenceStore() { savePluginPreferences(); } /** * The AbstractUIPlugin implementation of this Plugin * method does nothing. Subclasses may extend this method, but must send * super first. *

* WARNING: Plug-ins may not be started in the UI thread. * The startup() method should not assume that its code runs in * the UI thread, otherwise SWT thread exceptions may occur on startup.' * @deprecated * In Eclipse 3.0, startup has been replaced by {@link Plugin#start(BundleContext context)}. * Implementations of startup should be changed to extend * start(BundleContext context) and call super.start(context) * instead of super.startup(). Like super.startup(), * super.stop(context) must be called as the very first thing. * The startup method is called only for plug-ins which explicitly require the * org.eclipse.core.runtime.compatibility plug-in; in contrast, * the start method is always called. */ @Deprecated @Override public void startup() throws CoreException { // this method no longer does anything // the code that used to be here in 2.1 has moved to start(BundleContext) super.startup(); } /** * The AbstractUIPlugin implementation of this Plugin * method does nothing. Subclasses may extend this method, but must send * super first. * @deprecated * In Eclipse 3.0, shutdown has been replaced by {@link Plugin#stop(BundleContext context)}. * Implementations of shutdown should be changed to extend * stop(BundleContext context) and call super.stop(context) * instead of super.shutdown(). Unlike super.shutdown(), * super.stop(context) must be called as the very last thing rather * than as the very first thing. The shutdown method is called * only for plug-ins which explicitly require the * org.eclipse.core.runtime.compatibility plug-in; * in contrast, the stop method is always called. */ @Deprecated @Override public void shutdown() throws CoreException { // this method no longer does anything interesting // the code that used to be here in 2.1 has moved to stop(BundleContext), // which is called regardless of whether the plug-in being instantiated // requires org.eclipse.core.runtime.compatibility super.shutdown(); } /** * The AbstractUIPlugin implementation of this Plugin * method refreshes the plug-in actions. Subclasses may extend this method, * but must send super first. * {@inheritDoc} * * @since 3.0 */ @Override public void start(BundleContext context) throws Exception { super.start(context); final BundleContext fc = 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() { @Override 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) } /** * The AbstractUIPlugin implementation of this {@link 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.stop() is * always done. * {@inheritDoc} * * @since 3.0 */ @Override public void stop(BundleContext context) throws Exception { try { if (bundleListener != null) { context.removeBundleListener(bundleListener); } saveDialogSettings(); savePreferenceStore(); preferenceStore = null; if (imageRegistry != null) imageRegistry.dispose(); imageRegistry = null; } finally { super.stop(context); } } /** * 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. It will now query the ISharedImages registry first. 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 * @since 3.0 */ public static ImageDescriptor imageDescriptorFromPlugin(String pluginId, String imageFilePath) { if (pluginId == null || imageFilePath == null) { throw new IllegalArgumentException(); } IWorkbench workbench = PlatformUI.isWorkbenchRunning() ? PlatformUI.getWorkbench() : null; ImageDescriptor imageDescriptor = workbench == null ? null : workbench .getSharedImages().getImageDescriptor(imageFilePath); if (imageDescriptor != null) return imageDescriptor; // found in the shared images // if the bundle is not ready then there is no image Bundle bundle = Platform.getBundle(pluginId); if (!BundleUtility.isReady(bundle)) { return null; } // Don't resolve the URL here, but create a URL using the // "platform:/plugin" protocol, which also supports fragments. // Caveat: The resulting URL may contain $nl$ etc., which is not // directly supported by PlatformURLConnection and needs to go through // FileLocator#find(URL), see bug 250432. IPath uriPath = new Path("/plugin").append(pluginId).append(imageFilePath); //$NON-NLS-1$ URL url; try { URI uri = new URI("platform", null, uriPath.toString(), null); //$NON-NLS-1$ url = uri.toURL(); } catch (MalformedURLException | URISyntaxException e) { return null; } // look for the image URL fullPathString = FileLocator.find(url); if (fullPathString == null) { // If not found, reinterpret imageFilePath as full URL. // This is unspecified, but apparently widely-used, see bug 395126. try { fullPathString = new URL(imageFilePath); } catch (MalformedURLException e) { return null; } URL platformURL = FileLocator.find(fullPathString); if (platformURL != null) { url = fullPathString; } } // create image descriptor with the platform:/ URL return ImageDescriptor.createFromURL(url); } /** * FOR INTERNAL WORKBENCH USE ONLY. * * Returns the path to a location in the file system that can be used * to persist/restore state between workbench invocations. * If the location did not exist prior to this call it will be created. * Returns null if no such location is available. * * @return path to a location in the file system where this plug-in can * persist data between sessions, or null if no such * location is available. * @since 3.1 */ private IPath getStateLocationOrNull() { try { return getStateLocation(); } catch (IllegalStateException e) { // This occurs if -data=@none is explicitly specified, so ignore this silently. // Is this OK? See bug 85071. return null; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy