| /******************************************************************************* |
| * Copyright (c) 2000, 2009 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.URL; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IPluginDescriptor; |
| 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. |
| * <p> |
| * Subclasses obtain the following capabilities: |
| * </p> |
| * <p> |
| * Preferences |
| * <ul> |
| * <li> The platform core runtime contains general support for plug-in |
| * preferences (<code>org.eclipse.core.runtime.Preferences</code>). |
| * This class provides appropriate conversion to the older JFace preference |
| * API (<code>org.eclipse.jface.preference.IPreferenceStore</code>).</li> |
| * <li> The method <code>getPreferenceStore</code> returns the JFace preference |
| * store (cf. <code>Plugin.getPluginPreferences</code> which returns |
| * a core runtime preferences object.</li> |
| * <li> Subclasses may reimplement <code>initializeDefaultPreferences</code> |
| * to set up any default values for preferences using JFace API. In this |
| * case, <code>initializeDefaultPluginPreferences</code> should not be |
| * overridden.</li> |
| * <li> Subclasses may reimplement |
| * <code>initializeDefaultPluginPreferences</code> to set up any default |
| * values for preferences using core runtime API. In this |
| * case, <code>initializeDefaultPreferences</code> should not be |
| * overridden.</li> |
| * <li> 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.</li> |
| * </ul> |
| * Dialogs |
| * <ul> |
| * <li> The dialog store is read the first time <code>getDialogSettings</code> |
| * is called.</li> |
| * <li> 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". </li> |
| * <li> The dialog store is found in the file whose name is given by the |
| * constant <code>FN_DIALOG_STORE</code>. 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.</li> |
| * <li> Plug-in code can call <code>saveDialogSettings</code> 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. </li> |
| * <li> Dialog settings are also saved automatically on plug-in shutdown.</li> |
| * </ul> |
| * Images |
| * <ul> |
| * <li> 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. |
| * </ul> |
| * <p> |
| * 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 <code>getDefault</code> |
| * method. |
| * </p> |
| * <p> |
| * See the description on {@link Plugin}. |
| * </p> |
| */ |
| public abstract class AbstractUIPlugin extends Plugin { |
| |
| /** |
| * The name of the dialog settings file (value |
| * <code>"dialog_settings.xml"</code>). |
| */ |
| private static final String FN_DIALOG_SETTINGS = "dialog_settings.xml"; //$NON-NLS-1$ |
| |
| /** |
| * Storage for dialog and wizard data; <code>null</code> if not yet |
| * initialized. |
| */ |
| private IDialogSettings dialogSettings = null; |
| |
| /** |
| * Storage for preferences. |
| */ |
| private ScopedPreferenceStore preferenceStore; |
| |
| /** |
| * The registry for all graphic images; <code>null</code> 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. |
| * <p> |
| * Note that instances of plug-in runtime classes are automatically created |
| * by the platform in the course of plug-in activation. |
| * <p> |
| * |
| * @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 |
| * <code>MyPlugin(IPluginDescriptor descriptor)</code> should be changed to |
| * <code>MyPlugin()</code> and call <code>super()</code> instead of |
| * <code>super(descriptor)</code>. |
| * The <code>MyPlugin(IPluginDescriptor descriptor)</code> 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). |
| */ |
| public AbstractUIPlugin(IPluginDescriptor descriptor) { |
| super(descriptor); |
| } |
| |
| /** |
| * Creates an abstract UI plug-in runtime object. |
| * <p> |
| * Plug-in runtime classes are <code>BundleActivators</code> and so must |
| * have an default constructor. This method is called by the runtime when |
| * the associated bundle is being activated. |
| * <p> |
| * For more details, see <code>Plugin</code>'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. |
| * <p> |
| * The default implementation of this method creates an empty registry. |
| * Subclasses may override this method if needed. |
| * </p> |
| * |
| * @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. |
| * <p> |
| * If an error occurs reading the dialog store, an empty one is quietly created |
| * and returned. |
| * </p> |
| * <p> |
| * Subclasses may override this method but are not expected to. |
| * </p> |
| * |
| * @return the dialog settings |
| */ |
| public IDialogSettings getDialogSettings() { |
| if (dialogSettings == null) { |
| loadDialogSettings(); |
| } |
| return dialogSettings; |
| } |
| |
| /** |
| * Returns the image registry for this UI plug-in. |
| * <p> |
| * 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. |
| * <p> |
| * Subclasses should reimplement <code>initializeImageRegistry</code> if they have |
| * custom graphic images to load. |
| * </p> |
| * <p> |
| * Subclasses may override this method but are not expected to. |
| * </p> |
| * |
| * @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. |
| * <p> |
| * If an error occurs reading the preference store, an empty preference store is |
| * quietly created, initialized with defaults, and returned. |
| * </p> |
| * <p> |
| * <strong>NOTE:</strong> 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. |
| * </p> |
| * |
| * @return the preference store |
| */ |
| public IPreferenceStore getPreferenceStore() { |
| // Create the preference store lazily. |
| if (preferenceStore == null) { |
| preferenceStore = new ScopedPreferenceStore(new InstanceScope(),getBundle().getSymbolicName()); |
| |
| } |
| return preferenceStore; |
| } |
| |
| /** |
| * Returns the Platform UI workbench. |
| * <p> |
| * This method exists as a convenience for plugin implementors. The |
| * workbench can also be accessed by invoking <code>PlatformUI.getWorkbench()</code>. |
| * </p> |
| * @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. |
| * <p> |
| * This method is called after the preference store is initially loaded |
| * (default values are never stored in preference stores). |
| * </p> |
| * <p> |
| * The default implementation of this method does nothing. |
| * Subclasses should reimplement this method if the plug-in has any preferences. |
| * </p> |
| * <p> |
| * 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 |
| * <code>initializeDefaultPluginPreferences()</code>. |
| * </p> |
| * |
| * @param store the preference store to fill |
| * |
| * @deprecated this is only called if the runtime compatibility layer is |
| * present. See {@link #initializeDefaultPluginPreferences}. |
| */ |
| protected void initializeDefaultPreferences(IPreferenceStore store) { |
| // spec'ed to do nothing |
| } |
| |
| /** |
| * The <code>AbstractUIPlugin</code> implementation of this |
| * <code>Plugin</code> method forwards to |
| * <code>initializeDefaultPreferences(IPreferenceStore)</code>. |
| * <p> |
| * 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 |
| * <code>initializeDefaultPreferences(IPreferenceStore)</code> method |
| * serves a similar purpose. If this method is reimplemented, do not send |
| * super, and do not override |
| * <code>initializeDefaultPreferences(IPreferenceStore)</code>. |
| * </p> |
| * |
| * @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 |
| */ |
| 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. |
| * <p> |
| * 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. |
| * </p><p> |
| * 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. |
| * </p><p> |
| * Subclasses may override this method to fill the image registry. |
| * </p> |
| * @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. |
| * <p> |
| * This framework method may be overridden, although this is typically |
| * unnecessary. |
| * </p> |
| */ |
| 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. |
| * <p> |
| * This framework method may be overridden, although this is typically |
| * unnecessary. |
| * </p> |
| * |
| * @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. |
| */ |
| protected void loadPreferenceStore() { |
| // do nothing by default |
| } |
| |
| /** |
| * Refreshes the actions for the plugin. |
| * This method is called from <code>startup</code>. |
| * <p> |
| * This framework method may be overridden, although this is typically |
| * unnecessary. |
| * </p> |
| */ |
| 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() { |
| 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 <code>Plugin.savePluginPreferences</code>. |
| * This method now calls <code>savePluginPreferences</code>, and exists only for |
| * backwards compatibility. |
| */ |
| protected void savePreferenceStore() { |
| savePluginPreferences(); |
| } |
| |
| /** |
| * The <code>AbstractUIPlugin</code> implementation of this <code>Plugin</code> |
| * method does nothing. Subclasses may extend this method, but must send |
| * super first. |
| * <p> |
| * WARNING: Plug-ins may not be started in the UI thread. |
| * The <code>startup()</code> 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, <code>startup</code> has been replaced by {@link Plugin#start(BundleContext context)}. |
| * Implementations of <code>startup</code> should be changed to extend |
| * <code>start(BundleContext context)</code> and call <code>super.start(context)</code> |
| * instead of <code>super.startup()</code>. Like <code>super.startup()</code>, |
| * <code>super.stop(context)</code> must be called as the very first thing. |
| * The <code>startup</code> method is called only for plug-ins which explicitly require the |
| * org.eclipse.core.runtime.compatibility plug-in; in contrast, |
| * the <code>start</code> method is always called. |
| */ |
| 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 <code>AbstractUIPlugin</code> implementation of this <code>Plugin</code> |
| * method does nothing. Subclasses may extend this method, but must send |
| * super first. |
| * @deprecated |
| * In Eclipse 3.0, <code>shutdown</code> has been replaced by {@link Plugin#stop(BundleContext context)}. |
| * Implementations of <code>shutdown</code> should be changed to extend |
| * <code>stop(BundleContext context)</code> and call <code>super.stop(context)</code> |
| * instead of <code>super.shutdown()</code>. Unlike <code>super.shutdown()</code>, |
| * <code>super.stop(context)</code> must be called as the very <b>last</b> thing rather |
| * than as the very first thing. The <code>shutdown</code> method is called |
| * only for plug-ins which explicitly require the |
| * org.eclipse.core.runtime.compatibility plug-in; |
| * in contrast, the <code>stop</code> method is always called. |
| */ |
| 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 <code>AbstractUIPlugin</code> implementation of this <code>Plugin</code> |
| * method refreshes the plug-in actions. Subclasses may extend this method, |
| * but must send super <b>first</b>. |
| * {@inheritDoc} |
| * |
| * @since 3.0 |
| */ |
| 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() { |
| 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 <code>AbstractUIPlugin</code> 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 <b>last</b>. A try-finally statement should |
| * be used where necessary to ensure that <code>super.stop()</code> is |
| * always done. |
| * {@inheritDoc} |
| * |
| * @since 3.0 |
| */ |
| 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. |
| * <p> |
| * 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". |
| * </p> |
| * |
| * @param pluginId |
| * the id of the plug-in containing the image file; |
| * <code>null</code> 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 <code>null</code> 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; |
| } |
| |
| // look for the image (this will check both the plugin and fragment folders |
| URL fullPathString = BundleUtility.find(bundle, imageFilePath); |
| if (fullPathString == null) { |
| try { |
| fullPathString = new URL(imageFilePath); |
| } catch (MalformedURLException e) { |
| return null; |
| } |
| } |
| |
| return ImageDescriptor.createFromURL(fullPathString); |
| } |
| |
| /** |
| * 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 <code>null</code> 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 <code>null</code> 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; |
| } |
| } |
| |
| } |