Package org.eclipse.ui.internal

Source Code of org.eclipse.ui.internal.Workbench

/*******************************************************************************
* Copyright (c) 2000, 2007 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.internal;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Dictionary;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;

import org.eclipse.core.commands.Command;
import org.eclipse.core.commands.CommandManager;
import org.eclipse.core.commands.common.EventManager;
import org.eclipse.core.commands.contexts.ContextManager;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionDelta;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProduct;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IRegistryChangeEvent;
import org.eclipse.core.runtime.IRegistryChangeListener;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.ExternalActionManager;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.ExternalActionManager.CommandCallback;
import org.eclipse.jface.action.ExternalActionManager.IActiveChecker;
import org.eclipse.jface.bindings.BindingManager;
import org.eclipse.jface.bindings.BindingManagerEvent;
import org.eclipse.jface.bindings.IBindingManagerListener;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.operation.ModalContext;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceManager;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.util.OpenStrategy;
import org.eclipse.jface.util.SafeRunnable;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.window.IShellProvider;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.window.WindowManager;
import org.eclipse.osgi.service.runnable.StartupMonitor;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.graphics.DeviceData;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IDecoratorManager;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorRegistry;
import org.eclipse.ui.IElementFactory;
import org.eclipse.ui.ILocalWorkingSetManager;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IPerspectiveDescriptor;
import org.eclipse.ui.IPerspectiveRegistry;
import org.eclipse.ui.ISaveableFilter;
import org.eclipse.ui.ISaveablePart;
import org.eclipse.ui.ISaveablesLifecycleListener;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IWindowListener;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchListener;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPreferenceConstants;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkingSetManager;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.Saveable;
import org.eclipse.ui.WorkbenchException;
import org.eclipse.ui.XMLMemento;
import org.eclipse.ui.activities.IWorkbenchActivitySupport;
import org.eclipse.ui.application.IWorkbenchConfigurer;
import org.eclipse.ui.application.WorkbenchAdvisor;
import org.eclipse.ui.browser.IWorkbenchBrowserSupport;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.commands.IWorkbenchCommandSupport;
import org.eclipse.ui.contexts.IContextService;
import org.eclipse.ui.contexts.IWorkbenchContextSupport;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.help.IWorkbenchHelpSystem;
import org.eclipse.ui.internal.StartupThreading.StartupRunnable;
import org.eclipse.ui.internal.activities.ws.WorkbenchActivitySupport;
import org.eclipse.ui.internal.browser.WorkbenchBrowserSupport;
import org.eclipse.ui.internal.commands.CommandImageManager;
import org.eclipse.ui.internal.commands.CommandImageService;
import org.eclipse.ui.internal.commands.CommandService;
import org.eclipse.ui.internal.commands.ICommandImageService;
import org.eclipse.ui.internal.commands.WorkbenchCommandSupport;
import org.eclipse.ui.internal.contexts.ActiveContextSourceProvider;
import org.eclipse.ui.internal.contexts.ContextService;
import org.eclipse.ui.internal.contexts.WorkbenchContextSupport;
import org.eclipse.ui.internal.dialogs.PropertyPageContributorManager;
import org.eclipse.ui.internal.handlers.HandlerService;
import org.eclipse.ui.internal.help.WorkbenchHelpSystem;
import org.eclipse.ui.internal.intro.IIntroRegistry;
import org.eclipse.ui.internal.intro.IntroDescriptor;
import org.eclipse.ui.internal.keys.BindingService;
import org.eclipse.ui.internal.menus.FocusControlSourceProvider;
import org.eclipse.ui.internal.menus.WorkbenchMenuService;
import org.eclipse.ui.internal.misc.Policy;
import org.eclipse.ui.internal.misc.StatusUtil;
import org.eclipse.ui.internal.misc.UIStats;
import org.eclipse.ui.internal.progress.ProgressManager;
import org.eclipse.ui.internal.registry.IActionSetDescriptor;
import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
import org.eclipse.ui.internal.registry.UIExtensionTracker;
import org.eclipse.ui.internal.services.ActionSetSourceProvider;
import org.eclipse.ui.internal.services.ActivePartSourceProvider;
import org.eclipse.ui.internal.services.ActiveShellSourceProvider;
import org.eclipse.ui.internal.services.CurrentSelectionSourceProvider;
import org.eclipse.ui.internal.services.EvaluationService;
import org.eclipse.ui.internal.services.IEvaluationService;
import org.eclipse.ui.internal.services.ISourceProviderService;
import org.eclipse.ui.internal.services.MenuSourceProvider;
import org.eclipse.ui.internal.services.ServiceLocator;
import org.eclipse.ui.internal.services.SourceProviderService;
import org.eclipse.ui.internal.splash.EclipseSplashHandler;
import org.eclipse.ui.internal.splash.SplashHandlerFactory;
import org.eclipse.ui.internal.testing.WorkbenchTestable;
import org.eclipse.ui.internal.themes.ColorDefinition;
import org.eclipse.ui.internal.themes.FontDefinition;
import org.eclipse.ui.internal.themes.ThemeElementHelper;
import org.eclipse.ui.internal.themes.WorkbenchThemeManager;
import org.eclipse.ui.internal.tweaklets.GrabFocus;
import org.eclipse.ui.internal.tweaklets.Tweaklets;
import org.eclipse.ui.internal.util.PrefUtil;
import org.eclipse.ui.internal.util.Util;
import org.eclipse.ui.intro.IIntroManager;
import org.eclipse.ui.keys.IBindingService;
import org.eclipse.ui.menus.IMenuService;
import org.eclipse.ui.operations.IWorkbenchOperationSupport;
import org.eclipse.ui.progress.IProgressService;
import org.eclipse.ui.services.IDisposable;
import org.eclipse.ui.splash.AbstractSplashHandler;
import org.eclipse.ui.statushandlers.StatusManager;
import org.eclipse.ui.swt.IFocusService;
import org.eclipse.ui.themes.IThemeManager;
import org.eclipse.ui.views.IViewRegistry;
import org.eclipse.ui.wizards.IWizardRegistry;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.SynchronousBundleListener;

/**
* The workbench class represents the top of the Eclipse user interface. Its
* primary responsability is the management of workbench windows, dialogs,
* wizards, and other workbench-related windows.
* <p>
* Note that any code that is run during the creation of a workbench instance
* should not required access to the display.
* </p>
* <p>
* Note that this internal class changed significantly between 2.1 and 3.0.
* Applications that used to define subclasses of this internal class need to be
* rewritten to use the new workbench advisor API.
* </p>
*/
public final class Workbench extends EventManager implements IWorkbench {

  private final class StartupProgressBundleListener implements
      SynchronousBundleListener {

    private final IProgressMonitor progressMonitor;

    private final int maximumProgressCount;

    // stack of names of bundles currently starting
    private final List starting;

    StartupProgressBundleListener(IProgressMonitor progressMonitor,
        int maximumProgressCount) {
      super();
      this.progressMonitor = progressMonitor;
      this.maximumProgressCount = maximumProgressCount;
      this.starting = new ArrayList();
    }

    public void bundleChanged(BundleEvent event) {
      int eventType = event.getType();
      String bundleName;

      synchronized (this) {
        if (eventType == BundleEvent.STARTING) {
          starting.add(bundleName = event.getBundle()
              .getSymbolicName());
        } else if (eventType == BundleEvent.STARTED) {
          progressCount++;
          if (progressCount <= maximumProgressCount) {
            progressMonitor.worked(1);
          }
          int index = starting.lastIndexOf(event.getBundle()
              .getSymbolicName());
          if (index >= 0) {
            starting.remove(index);
          }
          if (index != starting.size()) {
            return; // not currently displayed
          }
          bundleName = index == 0 ? null : (String) starting
              .get(index - 1);
        } else {
          return; // uninteresting event
        }
      }

      String taskName;

      if (bundleName == null) {
        taskName = WorkbenchMessages.Startup_Loading_Workbench;
      } else {
        taskName = NLS.bind(WorkbenchMessages.Startup_Loading,
            bundleName);
      }

      progressMonitor.subTask(taskName);
    }
  }

  /**
   * Family for the early startup job.
   */
  public static final String EARLY_STARTUP_FAMILY = "earlyStartup"; //$NON-NLS-1$

  static final String VERSION_STRING[] = { "0.046", "2.0" }; //$NON-NLS-1$ //$NON-NLS-2$

  static final String DEFAULT_WORKBENCH_STATE_FILENAME = "workbench.xml"; //$NON-NLS-1$

  /**
   * Holds onto the only instance of Workbench.
   */
  private static Workbench instance;

  /**
   * The testable object facade.
   *
   * @since 3.0
   */
  private static WorkbenchTestable testableObject;

  /**
   * Signals that the workbench should create a splash implementation when
   * instantiated. Intial value is <code>true</code>.
   *
   * @since 3.3
   */
  private static boolean createSplash = true;

  /**
   * The splash handler.
   */
  private static AbstractSplashHandler splash;

  /**
   * The display used for all UI interactions with this workbench.
   *
   * @since 3.0
   */
  private Display display;

  private WindowManager windowManager;

  private WorkbenchWindow activatedWindow;

  private EditorHistory editorHistory;

  private boolean runEventLoop = true;

  private boolean isStarting = true;

  private boolean isClosing = false;

  /**
   * PlatformUI return code (as opposed to IPlatformRunnable return code).
   */
  private int returnCode = PlatformUI.RETURN_UNSTARTABLE;

  /**
   * Advisor providing application-specific configuration and customization of
   * the workbench.
   *
   * @since 3.0
   */
  private WorkbenchAdvisor advisor;

  /**
   * Object for configuring the workbench. Lazily initialized to an instance
   * unique to the workbench instance.
   *
   * @since 3.0
   */
  private WorkbenchConfigurer workbenchConfigurer;

  // for dynamic UI
  /**
   * ExtensionEventHandler handles extension life-cycle events.
   */
  private ExtensionEventHandler extensionEventHandler;

  /**
   * A count of how many large updates are going on. This tracks nesting of
   * requests to disable services during a large update -- similar to the
   * <code>setRedraw</code> functionality on <code>Control</code>. When
   * this value becomes greater than zero, services are disabled. When this
   * value becomes zero, services are enabled. Please see
   * <code>largeUpdateStart()</code> and <code>largeUpdateEnd()</code>.
   */
  private int largeUpdates = 0;

  /**
   * The service locator maintained by the workbench. These services are
   * initialized during workbench during the <code>init</code> method.
   */
  private final ServiceLocator serviceLocator = new ServiceLocator();

  /**
   * A count of how many plug-ins were loaded while restoring the workbench
   * state. Initially -1 for unknown number.
   */
  private int progressCount = -1;

  /**
   * A field to hold the workbench windows that have been restored. In the
   * event that not all windows have been restored, this field allows the
   * openWindowsAfterRestore method to open some windows.
   */
  private WorkbenchWindow[] createdWindows;

  /**
   * Listener list for registered IWorkbenchListeners .
   */
  private ListenerList workbenchListeners = new ListenerList(
      ListenerList.IDENTITY);

  /**
   * Creates a new workbench.
   *
   * @param display
   *            the display to be used for all UI interactions with the
   *            workbench
   * @param advisor
   *            the application-specific advisor that configures and
   *            specializes this workbench instance
   * @since 3.0
   */
  private Workbench(Display display, WorkbenchAdvisor advisor) {
    super();
    StartupThreading.setWorkbench(this);
    if (instance != null && instance.isRunning()) {
      throw new IllegalStateException(
          WorkbenchMessages.Workbench_CreatingWorkbenchTwice);
    }
    Assert.isNotNull(display);
    Assert.isNotNull(advisor);
    this.advisor = advisor;
    this.display = display;
    Workbench.instance = this;

    // for dynamic UI [This seems to be for everything that isn't handled by
    // some
    // subclass of RegistryManager. I think that when an extension is moved
    // to the
    // RegistryManager implementation, then it should be removed from the
    // list in
    // ExtensionEventHandler#appear.
    // I've found that the new wizard extension in particular is a poor
    // choice to
    // use as an example, since the result of reading the registry is not
    // cached
    // -- so it is re-read each time. The only real contribution of this
    // dialog is
    // to show the user a nice dialog describing the addition.]
    extensionEventHandler = new ExtensionEventHandler(this);
    Platform.getExtensionRegistry().addRegistryChangeListener(
        extensionEventHandler);
  }

  /**
   * Returns the one and only instance of the workbench, if there is one.
   *
   * @return the workbench, or <code>null</code> if the workbench has not
   *         been created, or has been created and already completed
   */
  public static final Workbench getInstance() {
    return instance;
  }

  /**
   * Creates the workbench and associates it with the the given display and
   * workbench advisor, and runs the workbench UI. This entails processing and
   * dispatching events until the workbench is closed or restarted.
   * <p>
   * This method is intended to be called by <code>PlatformUI</code>. Fails
   * if the workbench UI has already been created.
   * </p>
   * <p>
   * The display passed in must be the default display.
   * </p>
   *
   * @param display
   *            the display to be used for all UI interactions with the
   *            workbench
   * @param advisor
   *            the application-specific advisor that configures and
   *            specializes the workbench
   * @return return code {@link PlatformUI#RETURN_OK RETURN_OK}for normal
   *         exit; {@link PlatformUI#RETURN_RESTART RETURN_RESTART}if the
   *         workbench was terminated with a call to
   *         {@link IWorkbench#restart IWorkbench.restart}; other values
   *         reserved for future use
   */
  public static final int createAndRunWorkbench(final Display display,
      final WorkbenchAdvisor advisor) {
    final int[] returnCode = new int[1];
    Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
      public void run() {
        // create the workbench instance
        Workbench workbench = new Workbench(display, advisor);
        // run the workbench event loop
        returnCode[0] = workbench.runUI();
      }
    });
    return returnCode[0];
  }

  /**
   * Creates the <code>Display</code> to be used by the workbench.
   *
   * @return the display
   */
  public static Display createDisplay() {
    // setup the application name used by SWT to lookup resources on some
    // platforms
    String applicationName = WorkbenchPlugin.getDefault().getAppName();
    if (applicationName != null) {
      Display.setAppName(applicationName);
    }

    // create the display
    Display newDisplay = Display.getCurrent();
    if(newDisplay == null) {
      if (Policy.DEBUG_SWT_GRAPHICS || Policy.DEBUG_SWT_DEBUG) {
        DeviceData data = new DeviceData();
        if (Policy.DEBUG_SWT_GRAPHICS) {
          data.tracking = true;
        }
        if (Policy.DEBUG_SWT_DEBUG) {
          data.debug = true;
        }
        newDisplay = new Display(data);
      } else {
        newDisplay = new Display();
      }
    }

    // workaround for 1GEZ9UR and 1GF07HN
    newDisplay.setWarnings(false);

    // Set the priority higher than normal so as to be higher
    // than the JobManager.
    Thread.currentThread().setPriority(
        Math.min(Thread.MAX_PRIORITY, Thread.NORM_PRIORITY + 1));

    initializeImages();

    return newDisplay;
  }

  /**
   * Create the splash wrapper and set it to work.
   *
   * @since 3.3
   */
  private void createSplashWrapper() {
    final Display display = getDisplay();
    String splashLoc = System.getProperty("org.eclipse.equinox.launcher.splash.location"); //$NON-NLS-1$
    final Image background = loadImage(splashLoc);
   
    SafeRunnable run = new SafeRunnable() {

      public void run() throws Exception {
        String splashHandle = System.getProperty("org.eclipse.equinox.launcher.splash.handle"); //$NON-NLS-1$
        if (splashHandle == null) {
          createSplash = false;
          return;
        }
       
        // create the splash
        getSplash();
        if (splash == null) {
          createSplash = false;
          return;
        }
       
        Shell splashShell = splash.getSplash();
        if (splashShell == null) {
          // look for the 32 bit internal_new shell method
          try {
            Method method = Shell.class
                .getMethod(
                    "internal_new", new Class[] { Display.class, int.class }); //$NON-NLS-1$
            // we're on a 32 bit platform so invoke it with splash
            // handle as an int
            splashShell = (Shell) method.invoke(null, new Object[] {
                display, new Integer(splashHandle) });
          } catch (NoSuchMethodException e) {
            // look for the 64 bit internal_new shell method
            try {
              Method method = Shell.class
                  .getMethod(
                      "internal_new", new Class[] { Display.class, long.class }); //$NON-NLS-1$

              // we're on a 64 bit platform so invoke it with a long
              splashShell = (Shell) method.invoke(null,
                  new Object[] { display,
                      new Long(splashHandle) });
            } catch (NoSuchMethodException e2) {
              // cant find either method - don't do anything.
            }
          }
         
          if (splashShell == null)
            return;
          if (background != null)
            splashShell.setBackgroundImage(background);
        }

        Dictionary properties = new Hashtable();
        properties.put(Constants.SERVICE_RANKING, new Integer(Integer.MAX_VALUE));
        BundleContext context = WorkbenchPlugin.getDefault().getBundleContext();
        final ServiceRegistration registration[] = new ServiceRegistration[1];
        StartupMonitor startupMonitor = new StartupMonitor() {

          public void applicationRunning() {
            splash.dispose();
            if (background != null)
              background.dispose();
            registration[0].unregister(); // unregister ourself
          }

          public void update() {
            // do nothing - we come into the picture far too late
            // for this to be relevant
          }
        };
        registration[0] = context.registerService(StartupMonitor.class
            .getName(), startupMonitor, properties);
       
        splash.init(splashShell);
      }
      /* (non-Javadoc)
       * @see org.eclipse.jface.util.SafeRunnable#handleException(java.lang.Throwable)
       */
      public void handleException(Throwable e) {
        StatusManager.getManager().handle(
            StatusUtil.newStatus(WorkbenchPlugin.PI_WORKBENCH,
                "Could not instantiate splash", e)); //$NON-NLS-1$
        createSplash = false;
        splash = null;
        if (background != null)
          background.dispose();
       
      }
      };
      SafeRunner.run(run);
  }

  /**
   * Load an image from a filesystem path.
   *
   * @param splashLoc the location to load from
   * @return the image or <code>null</code>
   * @since 3.3
   */
  private Image loadImage(String splashLoc) {
    Image background = null;
    if (splashLoc != null) {
      try {
        InputStream input = new BufferedInputStream(
            new FileInputStream(splashLoc));
        background = new Image(display, input);
      } catch (IOException e) {
        StatusManager.getManager().handle(
            StatusUtil.newStatus(WorkbenchPlugin.PI_WORKBENCH, e));
      }
    }
    return background;
  }

  /**
   * Return the splash handler for this application. If none is specifically
   * provided the default Eclipse implementation is returned.
   *
   * @return the splash handler for this application or <code>null</code>
   * @since 3.3
   */
  private static AbstractSplashHandler getSplash() {
    if (!createSplash)
      return null;
   
    if (splash == null) {
     
      IProduct product = Platform.getProduct();
      if (product != null)
        splash = SplashHandlerFactory.findSplashHandlerFor(product);
     
      if (splash == null)
        splash = new EclipseSplashHandler();
    }
    return splash;
  }

  /**
   * Returns the testable object facade, for use by the test harness.
   *
   * @return the testable object facade
   * @since 3.0
   */
  public static WorkbenchTestable getWorkbenchTestable() {
    if (testableObject == null) {
      testableObject = new WorkbenchTestable();
    }
    return testableObject;
  }

  /*
   * (non-Javadoc) Method declared on IWorkbench.
   *
   * @since 3.2
   */
  public void addWorkbenchListener(IWorkbenchListener listener) {
    workbenchListeners.add(listener);
  }

  /*
   * (non-Javadoc) Method declared on IWorkbench.
   *
   * @since 3.2
   */
  public void removeWorkbenchListener(IWorkbenchListener listener) {
    workbenchListeners.remove(listener);
  }

  /**
   * Fire workbench preShutdown event, stopping at the first one to veto
   *
   * @param forced
   *            flag indicating whether the shutdown is being forced
   * @return <code>true</code> to allow the workbench to proceed with
   *         shutdown, <code>false</code> to veto a non-forced shutdown
   * @since 3.2
   */
  boolean firePreShutdown(final boolean forced) {
    Object list[] = workbenchListeners.getListeners();
    for (int i = 0; i < list.length; i++) {
      final IWorkbenchListener l = (IWorkbenchListener) list[i];
      final boolean[] result = new boolean[] { false };
      SafeRunnable.run(new SafeRunnable() {
        public void run() {
          result[0] = l.preShutdown(Workbench.this, forced);
        }
      });
      if (!result[0]) {
        return false;
      }
    }
    return true;
  }

  /**
   * Fire workbench postShutdown event.
   *
   * @since 3.2
   */
  void firePostShutdown() {
    Object list[] = workbenchListeners.getListeners();
    for (int i = 0; i < list.length; i++) {
      final IWorkbenchListener l = (IWorkbenchListener) list[i];
      SafeRunnable.run(new SafeRunnable() {
        public void run() {
          l.postShutdown(Workbench.this);
        }
      });
    }
  }

  /*
   * (non-Javadoc) Method declared on IWorkbench.
   */
  public void addWindowListener(IWindowListener l) {
    addListenerObject(l);
  }

  /*
   * (non-Javadoc) Method declared on IWorkbench.
   */
  public void removeWindowListener(IWindowListener l) {
    removeListenerObject(l);
  }

  /**
   * Fire window opened event.
   *
   * @param window
   *            The window which just opened; should not be <code>null</code>.
   */
  protected void fireWindowOpened(final IWorkbenchWindow window) {
    Object list[] = getListeners();
    for (int i = 0; i < list.length; i++) {
      final IWindowListener l = (IWindowListener) list[i];
      SafeRunner.run(new SafeRunnable() {
        public void run() {
          l.windowOpened(window);
        }
      });
    }
  }

  /**
   * Fire window closed event.
   *
   * @param window
   *            The window which just closed; should not be <code>null</code>.
   */
  protected void fireWindowClosed(final IWorkbenchWindow window) {
    if (activatedWindow == window) {
      // Do not hang onto it so it can be GC'ed
      activatedWindow = null;
    }

    Object list[] = getListeners();
    for (int i = 0; i < list.length; i++) {
      final IWindowListener l = (IWindowListener) list[i];
      SafeRunner.run(new SafeRunnable() {
        public void run() {
          l.windowClosed(window);
        }
      });
    }
  }

  /**
   * Fire window activated event.
   *
   * @param window
   *            The window which was just activated; should not be
   *            <code>null</code>.
   */
  protected void fireWindowActivated(final IWorkbenchWindow window) {
    Object list[] = getListeners();
    for (int i = 0; i < list.length; i++) {
      final IWindowListener l = (IWindowListener) list[i];
      SafeRunner.run(new SafeRunnable() {
        public void run() {
          l.windowActivated(window);
        }
      });
    }
  }

  /**
   * Fire window deactivated event.
   *
   * @param window
   *            The window which was just deactivated; should not be
   *            <code>null</code>.
   */
  protected void fireWindowDeactivated(final IWorkbenchWindow window) {
    Object list[] = getListeners();
    for (int i = 0; i < list.length; i++) {
      final IWindowListener l = (IWindowListener) list[i];
      SafeRunner.run(new SafeRunnable() {
        public void run() {
          l.windowDeactivated(window);
        }
      });
    }
  }

  /**
   * Closes the workbench. Assumes that the busy cursor is active.
   *
   * @param force
   *            true if the close is mandatory, and false if the close is
   *            allowed to fail
   * @return true if the close succeeded, and false otherwise
   */
  private boolean busyClose(final boolean force) {

    // notify the advisor of preShutdown and allow it to veto if not forced
    isClosing = advisor.preShutdown();
    if (!force && !isClosing) {
      return false;
    }

    // notify regular workbench clients of preShutdown and allow them to
    // veto if not forced
    isClosing = firePreShutdown(force);
    if (!force && !isClosing) {
      return false;
    }

    // save any open editors if they are dirty
    isClosing = saveAllEditors(!force);
    if (!force && !isClosing) {
      return false;
    }

    boolean closeEditors = !force
        && PrefUtil.getAPIPreferenceStore().getBoolean(
            IWorkbenchPreferenceConstants.CLOSE_EDITORS_ON_EXIT);
    if (closeEditors) {
      SafeRunner.run(new SafeRunnable() {
        public void run() {
          IWorkbenchWindow windows[] = getWorkbenchWindows();
          for (int i = 0; i < windows.length; i++) {
            IWorkbenchPage pages[] = windows[i].getPages();
            for (int j = 0; j < pages.length; j++) {
              isClosing = isClosing
                  && pages[j].closeAllEditors(false);
            }
          }
        }
      });
      if (!force && !isClosing) {
        return false;
      }
    }

    if (getWorkbenchConfigurer().getSaveAndRestore()) {
      SafeRunner.run(new SafeRunnable() {
        public void run() {
          XMLMemento mem = recordWorkbenchState();
          // Save the IMemento to a file.
          saveMementoToFile(mem);
        }

        public void handleException(Throwable e) {
          String message;
          if (e.getMessage() == null) {
            message = WorkbenchMessages.ErrorClosingNoArg;
          } else {
            message = NLS.bind(
                WorkbenchMessages.ErrorClosingOneArg, e
                    .getMessage());
          }

          if (!MessageDialog.openQuestion(null,
              WorkbenchMessages.Error, message)) {
            isClosing = false;
          }
        }
      });
    }
    if (!force && !isClosing) {
      return false;
    }

    SafeRunner.run(new SafeRunnable(WorkbenchMessages.ErrorClosing) {
      public void run() {
        if (isClosing || force) {
          isClosing = windowManager.close();
        }
      }
    });

    if (!force && !isClosing) {
      return false;
    }

    shutdown();

    runEventLoop = false;
    return true;
  }

 
  /* (non-Javadoc)
   * @see org.eclipse.ui.IWorkbench#saveAllEditors(boolean)
   */
  public boolean saveAllEditors(boolean confirm) {
    final boolean finalConfirm = confirm;
    final boolean[] result = new boolean[1];
    result[0] = true;

    SafeRunner.run(new SafeRunnable(WorkbenchMessages.ErrorClosing) {
      public void run() {
        // Collect dirtyParts
        ArrayList dirtyParts = new ArrayList();
        ArrayList dirtyEditorsInput = new ArrayList();
        IWorkbenchWindow windows[] = getWorkbenchWindows();
        for (int i = 0; i < windows.length; i++) {
          IWorkbenchPage pages[] = windows[i].getPages();
          for (int j = 0; j < pages.length; j++) {
            WorkbenchPage page = (WorkbenchPage) pages[j];

            ISaveablePart[] parts = page.getDirtyParts();

            for (int k = 0; k < parts.length; k++) {
              ISaveablePart part = parts[k];

              if (part.isSaveOnCloseNeeded()) {
                if (part instanceof IEditorPart) {
                  IEditorPart editor = (IEditorPart) part;
                  if (!dirtyEditorsInput.contains(editor
                      .getEditorInput())) {
                    dirtyParts.add(editor);
                    dirtyEditorsInput.add(editor
                        .getEditorInput());
                  }
                } else {
                  dirtyParts.add(part);
                }
              }
            }
          }
        }
        IShellProvider shellProvider;
        IRunnableContext runnableContext;
        IWorkbenchWindow w = getActiveWorkbenchWindow();
        if (w == null && windows.length > 0) {
          w = windows[0];
        }
        if (w != null) {
          shellProvider = (WorkbenchWindow)w;
          runnableContext = w;
        } else {
          shellProvider = new IShellProvider() {
            public Shell getShell() {
              return null;
            }
          };
          runnableContext = new ProgressMonitorDialog(null);
        }
        // The fourth parameter is true to also save saveables from
        // non-part sources, see bug 139004.
        result[0] = EditorManager.saveAll(dirtyParts, finalConfirm,
            false, true, runnableContext, shellProvider);
      }
    });
    return result[0];
  }

  /**
   * Opens a new workbench window and page with a specific perspective.
   *
   * Assumes that busy cursor is active.
   */
  private IWorkbenchWindow busyOpenWorkbenchWindow(final String perspID,
      final IAdaptable input) throws WorkbenchException {
    // Create a workbench window (becomes active window)
    final WorkbenchWindow newWindowArray[] = new WorkbenchWindow[1];
    StartupThreading.runWithWorkbenchExceptions(new StartupRunnable() {
      public void runWithException() {
        newWindowArray[0] = newWorkbenchWindow();
      }
    });

    final WorkbenchWindow newWindow = newWindowArray[0];
   
    StartupThreading.runWithoutExceptions(new StartupRunnable() {

      public void runWithException() {
        newWindow.create(); // must be created before adding to window
                  // manager
      }
    });
    windowManager.add(newWindow);

    final WorkbenchException [] exceptions = new WorkbenchException[1];
    // Create the initial page.
    if (perspID != null) {
      StartupThreading.runWithWorkbenchExceptions(new StartupRunnable() {

        public void runWithException() throws WorkbenchException {
          try {
            newWindow.busyOpenPage(perspID, input);
          } catch (WorkbenchException e) {
            windowManager.remove(newWindow);
            exceptions[0] = e;
          }
        }})
    }
    if (exceptions[0] != null)
      throw exceptions[0];

    // Open window after opening page, to avoid flicker.
    StartupThreading.runWithWorkbenchExceptions(new StartupRunnable() {

      public void runWithException() {
        newWindow.open();
      }
    });

    return newWindow;
  }

  /*
   * (non-Javadoc) Method declared on IWorkbench.
   */
  public boolean close() {
    return close(PlatformUI.RETURN_OK, false);
  }

  /**
   * Closes the workbench, returning the given return code from the run
   * method. If forced, the workbench is closed no matter what.
   *
   * @param returnCode
   *            {@link PlatformUI#RETURN_OK RETURN_OK}for normal exit;
   *            {@link PlatformUI#RETURN_RESTART RETURN_RESTART}if the
   *            workbench was terminated with a call to
   *            {@link IWorkbench#restart IWorkbench.restart};
   *            {@link PlatformUI#RETURN_EMERGENCY_CLOSE} for an emergency
   *            shutdown
   *            {@link PlatformUI#RETURN_UNSTARTABLE RETURN_UNSTARTABLE}if
   *            the workbench could not be started; other values reserved for
   *            future use
   *
   * @param force
   *            true to force the workbench close, and false for a "soft"
   *            close that can be canceled
   * @return true if the close was successful, and false if the close was
   *         canceled
   */
  /* package */
  boolean close(int returnCode, final boolean force) {
    this.returnCode = returnCode;
    final boolean[] ret = new boolean[1];
    BusyIndicator.showWhile(null, new Runnable() {
      public void run() {
        ret[0] = busyClose(force);
      }
    });
    return ret[0];
  }

  /*
   * (non-Javadoc) Method declared on IWorkbench.
   */
  public IWorkbenchWindow getActiveWorkbenchWindow() {
    // Return null if called from a non-UI thread.
    // This is not spec'ed behaviour and is misleading, however this is how
    // it
    // worked in 2.1 and we cannot change it now.
    // For more details, see [Bug 57384] [RCP] Main window not active on
    // startup
    if (Display.getCurrent() == null) {
      return null;
    }

    // Look at the current shell and up its parent
    // hierarchy for a workbench window.
    Control shell = display.getActiveShell();
    while (shell != null) {
      Object data = shell.getData();
      if (data instanceof IWorkbenchWindow) {
        return (IWorkbenchWindow) data;
      }
      shell = shell.getParent();
    }

    // Look for the window that was last known being
    // the active one
    WorkbenchWindow win = getActivatedWindow();
    if (win != null) {
      return win;
    }

    // Look at all the shells and pick the first one
    // that is a workbench window.
    Shell shells[] = display.getShells();
    for (int i = 0; i < shells.length; i++) {
      Object data = shells[i].getData();
      if (data instanceof IWorkbenchWindow) {
        return (IWorkbenchWindow) data;
      }
    }

    // Can't find anything!
    return null;
  }

  /*
   * Returns the editor history.
   */
  public EditorHistory getEditorHistory() {
    if (editorHistory == null) {
      editorHistory = new EditorHistory();
    }
    return editorHistory;
  }

  /*
   * (non-Javadoc) Method declared on IWorkbench.
   */
  public IEditorRegistry getEditorRegistry() {
    return WorkbenchPlugin.getDefault().getEditorRegistry();
  }

  /*
   * Returns the number for a new window. This will be the first number > 0
   * which is not used to identify another window in the workbench.
   */
  private int getNewWindowNumber() {
    // Get window list.
    Window[] windows = windowManager.getWindows();
    int count = windows.length;

    // Create an array of booleans (size = window count).
    // Cross off every number found in the window list.
    boolean checkArray[] = new boolean[count];
    for (int nX = 0; nX < count; nX++) {
      if (windows[nX] instanceof WorkbenchWindow) {
        WorkbenchWindow ww = (WorkbenchWindow) windows[nX];
        int index = ww.getNumber() - 1;
        if (index >= 0 && index < count) {
          checkArray[index] = true;
        }
      }
    }

    // Return first index which is not used.
    // If no empty index was found then every slot is full.
    // Return next index.
    for (int index = 0; index < count; index++) {
      if (!checkArray[index]) {
        return index + 1;
      }
    }
    return count + 1;
  }

  /*
   * (non-Javadoc) Method declared on IWorkbench.
   */
  public IWorkbenchOperationSupport getOperationSupport() {
    return WorkbenchPlugin.getDefault().getOperationSupport();
  }

  /*
   * (non-Javadoc) Method declared on IWorkbench.
   */
  public IPerspectiveRegistry getPerspectiveRegistry() {
    return WorkbenchPlugin.getDefault().getPerspectiveRegistry();
  }

  /*
   * (non-Javadoc) Method declared on IWorkbench.
   */
  public PreferenceManager getPreferenceManager() {
    return WorkbenchPlugin.getDefault().getPreferenceManager();
  }

  /*
   * (non-Javadoc) Method declared on IWorkbench.
   */
  public IPreferenceStore getPreferenceStore() {
    return WorkbenchPlugin.getDefault().getPreferenceStore();
  }

  /*
   * (non-Javadoc) Method declared on IWorkbench.
   */
  public ISharedImages getSharedImages() {
    return WorkbenchPlugin.getDefault().getSharedImages();
  }

  /**
   * Returns the window manager for this workbench.
   *
   * @return the window manager
   */
  /* package */
  WindowManager getWindowManager() {
    return windowManager;
  }

  /*
   * Answer the workbench state file.
   */
  private File getWorkbenchStateFile() {
    IPath path = WorkbenchPlugin.getDefault().getDataLocation();
    if (path == null) {
      return null;
    }
    path = path.append(DEFAULT_WORKBENCH_STATE_FILENAME);
    return path.toFile();
  }

  /*
   * (non-Javadoc) Method declared on IWorkbench.
   */
  public int getWorkbenchWindowCount() {
    return windowManager.getWindowCount();
  }

  /*
   * (non-Javadoc) Method declared on IWorkbench.
   */
  public IWorkbenchWindow[] getWorkbenchWindows() {
    Window[] windows = windowManager.getWindows();
    IWorkbenchWindow[] dwindows = new IWorkbenchWindow[windows.length];
    System.arraycopy(windows, 0, dwindows, 0, windows.length);
    return dwindows;
  }

  /*
   * (non-Javadoc) Method declared on IWorkbench.
   */
  public IWorkingSetManager getWorkingSetManager() {
    return WorkbenchPlugin.getDefault().getWorkingSetManager();
  }

  /**
   * {@inheritDoc}
   */
  public ILocalWorkingSetManager createLocalWorkingSetManager() {
    return new LocalWorkingSetManager(WorkbenchPlugin.getDefault()
        .getBundleContext());
  }

  /**
   * Initializes the workbench now that the display is created.
   *
   * @return true if init succeeded.
   */
  private boolean init() {
    // setup debug mode if required.
    if (WorkbenchPlugin.getDefault().isDebugging()) {
      WorkbenchPlugin.DEBUG = true;
      ModalContext.setDebugMode(true);
    }

    // Set up the JFace preference store
    JFaceUtil.initializeJFacePreferences();

    // create workbench window manager
    windowManager = new WindowManager();

    IIntroRegistry introRegistry = WorkbenchPlugin.getDefault()
        .getIntroRegistry();
    if (introRegistry.getIntroCount() > 0) {
      IProduct product = Platform.getProduct();
      if (product != null) {
        introDescriptor = (IntroDescriptor) introRegistry
            .getIntroForProduct(product.getId());
      }
    }

    // Initialize the activity support.
    workbenchActivitySupport = new WorkbenchActivitySupport();
    activityHelper = ActivityPersistanceHelper.getInstance();

    initializeDefaultServices();
    initializeFonts();
    initializeColors();
    initializeApplicationColors();

    // now that the workbench is sufficiently initialized, let the advisor
    // have a turn.
    StartupThreading.runWithoutExceptions(new StartupRunnable() {

      public void runWithException() {
        advisor.internalBasicInitialize(getWorkbenchConfigurer());
      }
    });
   
    // configure use of color icons in toolbars
    boolean useColorIcons = PrefUtil.getInternalPreferenceStore()
        .getBoolean(IPreferenceConstants.COLOR_ICONS);
    ActionContributionItem.setUseColorIconsInToolbars(useColorIcons);

    // initialize workbench single-click vs double-click behavior
    initializeSingleClickOption();
   
    StartupThreading.runWithoutExceptions(new StartupRunnable() {

      public void runWithException() {
        ((GrabFocus) Tweaklets.get(GrabFocus.KEY))
            .init(getDisplay());
      }
    });
   

    // attempt to restore a previous workbench state
    try {
      UIStats.start(UIStats.RESTORE_WORKBENCH, "Workbench"); //$NON-NLS-1$

      final boolean bail [] = new boolean[1];
      StartupThreading.runWithoutExceptions(new StartupRunnable() {

        public void runWithException() throws Throwable {
          advisor.preStartup();
         
          if (!advisor.openWindows()) {
            bail[0] = true;
          }
        }});
     
      if (bail[0])
        return false;

    } finally {
      UIStats.end(UIStats.RESTORE_WORKBENCH, this, "Workbench"); //$NON-NLS-1$
    }

    forceOpenPerspective();

    return true;
  }

  /**
   * Establishes the relationship between JFace actions and the command
   * manager.
   */
  private void initializeCommandResolver() {
    ExternalActionManager.getInstance().setCallback(
        new CommandCallback(bindingManager, commandManager,
            new IActiveChecker() {
              public final boolean isActive(final String commandId) {
                return workbenchActivitySupport
                    .getActivityManager().getIdentifier(
                        commandId).isEnabled();
              }
            }));
  }

  /**
   * Initialize colors defined by the new colorDefinitions extension point.
   * Note this will be rolled into initializeColors() at some point.
   *
   * @since 3.0
   */
  private void initializeApplicationColors() {
    StartupThreading.runWithoutExceptions(new StartupRunnable() {

      public void runWithException() {
        ColorDefinition[] colorDefinitions = WorkbenchPlugin
            .getDefault().getThemeRegistry().getColors();
        ThemeElementHelper.populateRegistry(getThemeManager().getTheme(
            IThemeManager.DEFAULT_THEME), colorDefinitions,
            PrefUtil.getInternalPreferenceStore());
      }
    });
  }

  private void initializeSingleClickOption() {
    IPreferenceStore store = WorkbenchPlugin.getDefault()
        .getPreferenceStore();
    boolean openOnSingleClick = store
        .getBoolean(IPreferenceConstants.OPEN_ON_SINGLE_CLICK);
    boolean selectOnHover = store
        .getBoolean(IPreferenceConstants.SELECT_ON_HOVER);
    boolean openAfterDelay = store
        .getBoolean(IPreferenceConstants.OPEN_AFTER_DELAY);
    int singleClickMethod = openOnSingleClick ? OpenStrategy.SINGLE_CLICK
        : OpenStrategy.DOUBLE_CLICK;
    if (openOnSingleClick) {
      if (selectOnHover) {
        singleClickMethod |= OpenStrategy.SELECT_ON_HOVER;
      }
      if (openAfterDelay) {
        singleClickMethod |= OpenStrategy.ARROW_KEYS_OPEN;
      }
    }
    OpenStrategy.setOpenMethod(singleClickMethod);
  }

  /*
   * Initializes the workbench fonts with the stored values.
   */
  private void initializeFonts() {
    StartupThreading.runWithoutExceptions(new StartupRunnable() {

      public void runWithException() {
        FontDefinition[] fontDefinitions = WorkbenchPlugin.getDefault()
            .getThemeRegistry().getFonts();

        ThemeElementHelper.populateRegistry(getThemeManager()
            .getCurrentTheme(), fontDefinitions, PrefUtil
            .getInternalPreferenceStore());
      }
    });
  }

  /*
   * Initialize the workbench images.
   *
   * @param windowImages An array of the descriptors of the images to be used
   * in the corner of each window, or <code>null</code> if none. It is
   * expected that the array will contain the same icon, rendered at different
   * sizes.
   *
   * @since 3.0
   */
  private static void initializeImages() {
    ImageDescriptor[] windowImages = WorkbenchPlugin.getDefault()
        .getWindowImages();
    if (windowImages == null) {
      return;
    }

    Image[] images = new Image[windowImages.length];
    for (int i = 0; i < windowImages.length; ++i) {
      images[i] = windowImages[i].createImage();
    }
    Window.setDefaultImages(images);
  }

  /*
   * Take the workbenches' images out of the shared registry.
   *
   * @since 3.0
   */
  private void uninitializeImages() {
    WorkbenchImages.dispose();
    Image[] images = Window.getDefaultImages();
    Window.setDefaultImage(null);
    for (int i = 0; i < images.length; i++) {
      images[i].dispose();     
    }
  }

  /*
   * Initialize the workbench colors.
   *
   * @since 3.0
   */
  private void initializeColors() {
    StartupThreading.runWithoutExceptions(new StartupRunnable() {
      public void runWithException() {
        WorkbenchColors.startup();
      }});
  }

  /*
   * (non-Javadoc) Method declared on IWorkbench.
   */
  public boolean isClosing() {
    return isClosing;
  }

  /**
   * Initializes all of the default services for the workbench. For
   * initializing the command-based services, this also parses the registry
   * and hooks up all the required listeners.
   */
  private final void initializeDefaultServices() {
   
    StartupThreading.runWithoutExceptions(new StartupRunnable() {

      public void runWithException() {
        serviceLocator.registerService(IWorkbench.class,
            Workbench.this);
      }
    });
   
    // TODO Correctly order service initialization
    // there needs to be some serious consideration given to
    // the services, and hooking them up in the correct order
    final EvaluationService evaluationService = new EvaluationService();
   
    StartupThreading.runWithoutExceptions(new StartupRunnable() {

      public void runWithException() {
        serviceLocator.registerService(IEvaluationService.class,
            evaluationService);
      }
    });
   
   

    StartupThreading.runWithoutExceptions(new StartupRunnable() {

      public void runWithException() {
        serviceLocator.registerService(ISaveablesLifecycleListener.class,
            new SaveablesList());
      }});
   
    /*
     * Phase 1 of the initialization of commands. When this phase completes,
     * all the services and managers will exist, and be accessible via the
     * getService(Object) method.
     */
    StartupThreading.runWithoutExceptions(new StartupRunnable() {

      public void runWithException() {
        Command.DEBUG_COMMAND_EXECUTION = Policy.DEBUG_COMMANDS;
        commandManager = new CommandManager();
      }});
   
    final CommandService [] commandService = new CommandService[1];
    StartupThreading.runWithoutExceptions(new StartupRunnable() {

      public void runWithException() {
        commandService[0] = new CommandService(commandManager);
        commandService[0].readRegistry();
        serviceLocator.registerService(ICommandService.class, commandService[0]);

      }});
   
    StartupThreading.runWithoutExceptions(new StartupRunnable() {

      public void runWithException() {
        ContextManager.DEBUG = Policy.DEBUG_CONTEXTS;
        contextManager = new ContextManager();
        }});
   
    final IContextService contextService = new ContextService(
        contextManager);
   
    StartupThreading.runWithoutExceptions(new StartupRunnable() {

      public void runWithException() {
        contextService.readRegistry();
        }});
   
    serviceLocator.registerService(IContextService.class, contextService);
 
   
    final IHandlerService [] handlerService = new IHandlerService[1];
 
    StartupThreading.runWithoutExceptions(new StartupRunnable() {

      public void runWithException() {
        handlerService[0] = new HandlerService(
            commandService[0], evaluationService);
        handlerService[0].readRegistry();
      }});
   
    serviceLocator.registerService(IHandlerService.class, handlerService[0]);

    final IBindingService [] bindingService = new BindingService[1];
   
    StartupThreading.runWithoutExceptions(new StartupRunnable() {

      public void runWithException() {
        BindingManager.DEBUG = Policy.DEBUG_KEY_BINDINGS;
        bindingManager = new BindingManager(contextManager, commandManager);
        bindingService[0] = new BindingService(
            bindingManager, commandService[0], Workbench.this);
       
      }});
   
    bindingService[0].readRegistryAndPreferences(commandService[0]);
    serviceLocator.registerService(IBindingService.class, bindingService[0]);

    final CommandImageManager commandImageManager = new CommandImageManager();
    final CommandImageService commandImageService = new CommandImageService(
        commandImageManager, commandService[0]);
    commandImageService.readRegistry();
    serviceLocator.registerService(ICommandImageService.class,
        commandImageService);
   
    final WorkbenchMenuService menuService = new WorkbenchMenuService(serviceLocator);
   
    serviceLocator.registerService(IMenuService.class, menuService);
    // the service must be registered before it is initialized - its
    // initialization uses the service locator to address a dependency on
    // the menu service
    StartupThreading.runWithoutExceptions(new StartupRunnable() {

      public void runWithException() {
        menuService.readRegistry();
      }});

    /*
     * Phase 2 of the initialization of commands. The source providers that
     * the workbench provides are creating and registered with the above
     * services. These source providers notify the services when particular
     * pieces of workbench state change.
     */
    final ISourceProviderService sourceProviderService = new SourceProviderService();
    serviceLocator.registerService(ISourceProviderService.class,
        sourceProviderService);
    StartupThreading.runWithoutExceptions(new StartupRunnable() {

      public void runWithException() {
        final ActiveShellSourceProvider activeShellSourceProvider = new ActiveShellSourceProvider(
            Workbench.this);
        evaluationService.addSourceProvider(activeShellSourceProvider);
        handlerService[0].addSourceProvider(activeShellSourceProvider);
        contextService.addSourceProvider(activeShellSourceProvider);
        menuService.addSourceProvider(activeShellSourceProvider);
        sourceProviderService.registerProvider(activeShellSourceProvider);   
      }});
   
    StartupThreading.runWithoutExceptions(new StartupRunnable() {

      public void runWithException() {
        final ActivePartSourceProvider activePartSourceProvider = new ActivePartSourceProvider(
            Workbench.this);
        evaluationService.addSourceProvider(activePartSourceProvider);
        handlerService[0].addSourceProvider(activePartSourceProvider);
        contextService.addSourceProvider(activePartSourceProvider);
        menuService.addSourceProvider(activePartSourceProvider);
        sourceProviderService.registerProvider(activePartSourceProvider);
      }});
    StartupThreading.runWithoutExceptions(new StartupRunnable() {

      public void runWithException() {
        final ActiveContextSourceProvider activeContextSourceProvider = new ActiveContextSourceProvider(
            contextService);
        evaluationService.addSourceProvider(activeContextSourceProvider);
        handlerService[0].addSourceProvider(activeContextSourceProvider);
        menuService.addSourceProvider(activeContextSourceProvider);
        sourceProviderService.registerProvider(activeContextSourceProvider);
      }});
    StartupThreading.runWithoutExceptions(new StartupRunnable() {

      public void runWithException() {
        final CurrentSelectionSourceProvider currentSelectionSourceProvider = new CurrentSelectionSourceProvider(
            Workbench.this);
        evaluationService.addSourceProvider(currentSelectionSourceProvider);
        handlerService[0].addSourceProvider(currentSelectionSourceProvider);
        contextService.addSourceProvider(currentSelectionSourceProvider);
        menuService.addSourceProvider(currentSelectionSourceProvider);
        sourceProviderService.registerProvider(currentSelectionSourceProvider);
       
        actionSetSourceProvider = new ActionSetSourceProvider();
        evaluationService.addSourceProvider(actionSetSourceProvider);
        handlerService[0].addSourceProvider(actionSetSourceProvider);
        contextService.addSourceProvider(actionSetSourceProvider);
        menuService.addSourceProvider(actionSetSourceProvider);
        sourceProviderService.registerProvider(actionSetSourceProvider);
       
        FocusControlSourceProvider focusControl = new FocusControlSourceProvider();
        serviceLocator.registerService(IFocusService.class, focusControl);
        evaluationService.addSourceProvider(focusControl);
        handlerService[0].addSourceProvider(focusControl);
        contextService.addSourceProvider(focusControl);
        menuService.addSourceProvider(focusControl);
        sourceProviderService.registerProvider(focusControl);
       
       
        menuSourceProvider = new MenuSourceProvider();
        evaluationService.addSourceProvider(menuSourceProvider);
        handlerService[0].addSourceProvider(menuSourceProvider);
        contextService.addSourceProvider(menuSourceProvider);
        menuService.addSourceProvider(menuSourceProvider);
        sourceProviderService.registerProvider(menuSourceProvider);
      }});
   
    /*
     * Phase 3 of the initialization of commands. This handles the creation
     * of wrappers for legacy APIs. By the time this phase completes, any
     * code trying to access commands through legacy APIs should work.
     */
    workbenchContextSupport = new WorkbenchContextSupport(this,
        contextManager);
    workbenchCommandSupport = new WorkbenchCommandSupport(bindingManager,
        commandManager, contextManager, handlerService[0]);
    initializeCommandResolver();

    addWindowListener(windowListener);
    bindingManager.addBindingManagerListener(bindingManagerListener);

    serviceLocator.registerService(ISelectionConversionService.class,
        new SelectionConversionService());
  }

  /**
   * Returns true if the Workbench is in the process of starting.
   *
   * @return <code>true</code> if the Workbench is starting, but not yet
   *         running the event loop.
   */
  public boolean isStarting() {
    return isStarting;
  }

  /*
   * Creates a new workbench window.
   *
   * @return the new workbench window
   */
  private WorkbenchWindow newWorkbenchWindow() {
    return new WorkbenchWindow(getNewWindowNumber());
  }

  /*
   * If a perspective was specified on the command line (-perspective) then
   * force that perspective to open in the active window.
   */
  private void forceOpenPerspective() {
    if (getWorkbenchWindowCount() == 0) {
      // there should be an open window by now, bail out.
      return;
    }

    String perspId = null;
    String[] commandLineArgs = Platform.getCommandLineArgs();
    for (int i = 0; i < commandLineArgs.length - 1; i++) {
      if (commandLineArgs[i].equalsIgnoreCase("-perspective")) { //$NON-NLS-1$
        perspId = commandLineArgs[i + 1];
        break;
      }
    }
    if (perspId == null) {
      return;
    }
    IPerspectiveDescriptor desc = getPerspectiveRegistry()
        .findPerspectiveWithId(perspId);
    if (desc == null) {
      return;
    }

    IWorkbenchWindow win = getActiveWorkbenchWindow();
    if (win == null) {
      win = getWorkbenchWindows()[0];
    }
   
    final String threadPerspId = perspId;
    final IWorkbenchWindow threadWin = win;
      StartupThreading.runWithoutExceptions(new StartupRunnable() {
      public void runWithException() throws Throwable {
        try {
          showPerspective(threadPerspId, threadWin);
        } catch (WorkbenchException e) {
          String msg = "Workbench exception showing specified command line perspective on startup."; //$NON-NLS-1$
          WorkbenchPlugin.log(msg, new Status(IStatus.ERROR,
              PlatformUI.PLUGIN_ID, 0, msg, e));
        }
      }});
  }

  /**
   * Opens the initial workbench window.
   */
  /* package */void openFirstTimeWindow() {
    final boolean showProgress = PrefUtil.getAPIPreferenceStore()
        .getBoolean(
            IWorkbenchPreferenceConstants.SHOW_PROGRESS_ON_STARTUP);

    if (!showProgress) {
      doOpenFirstTimeWindow();
    } else {
      // We don't know how many plug-ins will be loaded,
      // assume we are loading a tenth of the installed plug-ins.
      // (The Eclipse SDK loads 7 of 86 plug-ins at startup as of
      // 2005-5-20)
      final int expectedProgressCount = Math.max(1, WorkbenchPlugin
          .getDefault().getBundleCount() / 10);

      runStartupWithProgress(expectedProgressCount, new Runnable() {
        public void run() {
          doOpenFirstTimeWindow();
        }
      });
    }
  }

  private void runStartupWithProgress(final int expectedProgressCount,
      final Runnable runnable) {
    progressCount = 0;
    final double cutoff = 0.95;

    AbstractSplashHandler handler = getSplash();
    IProgressMonitor progressMonitor = null;
    if (handler != null)
      progressMonitor = handler.getBundleProgressMonitor();
    
    if (progressMonitor == null) {
      // cannot report progress (e.g. if the splash screen is not showing)
      // fall back to starting without showing progress.
      runnable.run();
    } else {
      progressMonitor.beginTask("", expectedProgressCount); //$NON-NLS-1$
      SynchronousBundleListener bundleListener = new StartupProgressBundleListener(
          progressMonitor, (int) (expectedProgressCount * cutoff));
      WorkbenchPlugin.getDefault().addBundleListener(bundleListener);
      try {
        runnable.run();
        progressMonitor.subTask(WorkbenchMessages.Startup_Done);
        int remainingWork = expectedProgressCount
            - Math.min(progressCount,
                (int) (expectedProgressCount * cutoff));
        progressMonitor.worked(remainingWork);
        progressMonitor.done();
      } finally {
        WorkbenchPlugin.getDefault().removeBundleListener(
            bundleListener);
      }
    }
  }

  private void doOpenFirstTimeWindow() {
    try {
      final IAdaptable input [] = new IAdaptable[1];
      StartupThreading.runWithoutExceptions(new StartupRunnable() {

        public void runWithException() throws Throwable {
          input[0] = getDefaultPageInput();
        }});
     
      busyOpenWorkbenchWindow(getPerspectiveRegistry()
          .getDefaultPerspective(), input[0]);
    } catch (final WorkbenchException e) {
      // Don't use the window's shell as the dialog parent,
      // as the window is not open yet (bug 76724).
      StartupThreading.runWithoutExceptions(new StartupRunnable() {

        public void runWithException() throws Throwable {
          ErrorDialog.openError(null,
              WorkbenchMessages.Problems_Opening_Page, e.getMessage(), e
                  .getStatus());
        }});
    }
  }

  /*
   * Restores the workbench UI from the workbench state file (workbench.xml).
   *
   * @return a status object indicating OK if a window was opened,
   * RESTORE_CODE_RESET if no window was opened but one should be, and
   * RESTORE_CODE_EXIT if the workbench should close immediately
   */
  /* package */IStatus restoreState() {

    if (!getWorkbenchConfigurer().getSaveAndRestore()) {
      String msg = WorkbenchMessages.Workbench_restoreDisabled;
      return new Status(IStatus.WARNING, WorkbenchPlugin.PI_WORKBENCH,
          IWorkbenchConfigurer.RESTORE_CODE_RESET, msg, null);
    }
    // Read the workbench state file.
    final File stateFile = getWorkbenchStateFile();
    // If there is no state file cause one to open.
    if (stateFile == null || !stateFile.exists()) {
      String msg = WorkbenchMessages.Workbench_noStateToRestore;
      return new Status(IStatus.WARNING, WorkbenchPlugin.PI_WORKBENCH,
          IWorkbenchConfigurer.RESTORE_CODE_RESET, msg, null);
    }

    final IStatus result[] = { new Status(IStatus.OK,
        WorkbenchPlugin.PI_WORKBENCH, IStatus.OK, "", null) }; //$NON-NLS-1$
    SafeRunner.run(new SafeRunnable(WorkbenchMessages.ErrorReadingState) {
      public void run() throws Exception {
        FileInputStream input = new FileInputStream(stateFile);
        BufferedReader reader = new BufferedReader(
            new InputStreamReader(input, "utf-8")); //$NON-NLS-1$
        IMemento memento = XMLMemento.createReadRoot(reader);

        // Validate known version format
        String version = memento
            .getString(IWorkbenchConstants.TAG_VERSION);
        boolean valid = false;
        for (int i = 0; i < VERSION_STRING.length; i++) {
          if (VERSION_STRING[i].equals(version)) {
            valid = true;
            break;
          }
        }
        if (!valid) {
          reader.close();
          String msg = WorkbenchMessages.Invalid_workbench_state_ve;
          MessageDialog.openError((Shell) null,
              WorkbenchMessages.Restoring_Problems, msg);
          stateFile.delete();
          result[0] = new Status(IStatus.ERROR,
              WorkbenchPlugin.PI_WORKBENCH,
              IWorkbenchConfigurer.RESTORE_CODE_RESET, msg, null);
          return;
        }

        // Validate compatible version format
        // We no longer support the release 1.0 format
        if (VERSION_STRING[0].equals(version)) {
          reader.close();
          String msg = WorkbenchMessages.Workbench_incompatibleSavedStateVersion;
          boolean ignoreSavedState = new MessageDialog(null,
              WorkbenchMessages.Workbench_incompatibleUIState,
              null, msg, MessageDialog.WARNING, new String[] {
                  IDialogConstants.OK_LABEL,
                  IDialogConstants.CANCEL_LABEL }, 0).open() == 0;
          // OK is the default
          if (ignoreSavedState) {
            stateFile.delete();
            result[0] = new Status(IStatus.WARNING,
                WorkbenchPlugin.PI_WORKBENCH,
                IWorkbenchConfigurer.RESTORE_CODE_RESET, msg,
                null);
          } else {
            result[0] = new Status(IStatus.WARNING,
                WorkbenchPlugin.PI_WORKBENCH,
                IWorkbenchConfigurer.RESTORE_CODE_EXIT, msg,
                null);
          }
          return;
        }

        // Restore the saved state
        final IStatus restoreResult = restoreState(memento);
        reader.close();
        if (restoreResult.getSeverity() == IStatus.ERROR) {
          StartupThreading
              .runWithoutExceptions(new StartupRunnable() {

                public void runWithException() throws Throwable {
                  ErrorDialog
                      .openError(
                          null,
                          WorkbenchMessages.Workspace_problemsTitle,
                          WorkbenchMessages.Workbench_problemsRestoringMsg,
                          restoreResult);
                }
              });

        }
      }

      public void handleException(final Throwable e) {
        StartupThreading.runWithoutExceptions(new StartupRunnable() {

          public void runWithException() {
            handle(e);
            String msg = e.getMessage() == null ? "" : e.getMessage(); //$NON-NLS-1$
            result[0] = new Status(IStatus.ERROR,
                WorkbenchPlugin.PI_WORKBENCH,
                IWorkbenchConfigurer.RESTORE_CODE_RESET, msg, e);
            stateFile.delete();
          }});
      }
     
      private void handle(final Throwable e) {
        super.handleException(e);
      }
    });
    // ensure at least one window was opened
    if (result[0].isOK() && windowManager.getWindows().length == 0) {
      String msg = WorkbenchMessages.Workbench_noWindowsRestored;
      result[0] = new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH,
          IWorkbenchConfigurer.RESTORE_CODE_RESET, msg, null);
    }
    return result[0];
  }

  /*
   * (non-Javadoc) Method declared on IWorkbench.
   */
  public IWorkbenchWindow openWorkbenchWindow(IAdaptable input)
      throws WorkbenchException {
    return openWorkbenchWindow(getPerspectiveRegistry()
        .getDefaultPerspective(), input);
  }

  /*
   * (non-Javadoc) Method declared on IWorkbench.
   */
  public IWorkbenchWindow openWorkbenchWindow(final String perspID,
      final IAdaptable input) throws WorkbenchException {
    // Run op in busy cursor.
    final Object[] result = new Object[1];
    BusyIndicator.showWhile(null, new Runnable() {
      public void run() {
        try {
          result[0] = busyOpenWorkbenchWindow(perspID, input);
        } catch (WorkbenchException e) {
          result[0] = e;
        }
      }
    });
    if (result[0] instanceof IWorkbenchWindow) {
      return (IWorkbenchWindow) result[0];
    } else if (result[0] instanceof WorkbenchException) {
      throw (WorkbenchException) result[0];
    } else {
      throw new WorkbenchException(
          WorkbenchMessages.Abnormal_Workbench_Conditi);
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.ui.IWorkbench#restoreWorkbenchWindow(org.eclipse.ui.IMemento)
   */
  IWorkbenchWindow restoreWorkbenchWindow(IMemento memento)
      throws WorkbenchException {
    WorkbenchWindow newWindow = newWorkbenchWindow();
    newWindow.create();

    windowManager.add(newWindow);

    // whether the window was opened
    boolean opened = false;

    try {
      newWindow.restoreState(memento, null);
      newWindow.fireWindowRestored();
      newWindow.open();
      opened = true;
    } finally {
      if (!opened) {
        newWindow.close();
      }
    }

    return newWindow;
  }

  /*
   * Record the workbench UI in a document
   */
  private XMLMemento recordWorkbenchState() {
    XMLMemento memento = XMLMemento
        .createWriteRoot(IWorkbenchConstants.TAG_WORKBENCH);
    final IStatus status = saveState(memento);
    if (status.getSeverity() != IStatus.OK) {
      // don't use newWindow as parent because it has not yet been opened
      // (bug 76724)
      StartupThreading.runWithoutExceptions(new StartupRunnable() {

        public void runWithException() throws Throwable {
          ErrorDialog.openError(null,
              WorkbenchMessages.Workbench_problemsSaving,
              WorkbenchMessages.Workbench_problemsSavingMsg, status);
        }});
     
    }
    return memento;
  }

  /*
   * (non-Javadoc) Method declared on IWorkbench.
   */
  public boolean restart() {
    // this is the return code from run() to trigger a restart
    return close(PlatformUI.RETURN_RESTART, false);
  }

  /*
   * Restores the state of the previously saved workbench
   */
  private IStatus restoreState(final IMemento memento) {

    final MultiStatus result = new MultiStatus(PlatformUI.PLUGIN_ID,
        IStatus.OK, WorkbenchMessages.Workbench_problemsRestoring, null);

    final boolean showProgress = PrefUtil.getAPIPreferenceStore()
        .getBoolean(
            IWorkbenchPreferenceConstants.SHOW_PROGRESS_ON_STARTUP);

    try {
      /*
       * Restored windows will be set in the createdWindows field to be
       * used by the openWindowsAfterRestore() method
       */
      if (!showProgress) {
        doRestoreState(memento, result);
      } else {
        // Retrieve how many plug-ins were loaded while restoring the
        // workbench
        Integer lastProgressCount = memento
            .getInteger(IWorkbenchConstants.TAG_PROGRESS_COUNT);

        // If we don't know how many plug-ins were loaded last time,
        // assume we are loading half of the installed plug-ins.
        final int expectedProgressCount = Math.max(1,
            lastProgressCount == null ? WorkbenchPlugin
                .getDefault().getBundleCount() / 2
                : lastProgressCount.intValue());

        runStartupWithProgress(expectedProgressCount, new Runnable() {
          public void run() {
            doRestoreState(memento, result);
          }
        });
      }
    } finally {
      openWindowsAfterRestore();
    }
    return result;
  }

  /**
   * Returns the ids of all plug-ins that extend the
   * <code>org.eclipse.ui.startup</code> extension point.
   *
   * @return the ids of all plug-ins containing 1 or more startup extensions
   */
  public String[] getEarlyActivatedPlugins() {
    IExtensionPoint point = Platform.getExtensionRegistry()
        .getExtensionPoint(PlatformUI.PLUGIN_ID,
            IWorkbenchRegistryConstants.PL_STARTUP);
    IExtension[] extensions = point.getExtensions();
    ArrayList pluginIds = new ArrayList(extensions.length);
    for (int i = 0; i < extensions.length; i++) {
      String id = extensions[i].getNamespace();
      if (!pluginIds.contains(id)) {
        pluginIds.add(id);
      }
    }
    return (String[]) pluginIds.toArray(new String[pluginIds.size()]);
  }

  /**
   * Returns the ids of the early activated plug-ins that have been disabled
   * by the user.
   *
   * @return the ids of the early activated plug-ins that have been disabled
   *         by the user
   */
  public String[] getDisabledEarlyActivatedPlugins() {
    String pref = PrefUtil.getInternalPreferenceStore().getString(
        IPreferenceConstants.PLUGINS_NOT_ACTIVATED_ON_STARTUP);
    return Util.getArrayFromList(pref, ";"); //$NON-NLS-1$
  }

  /*
   * Starts all plugins that extend the <code> org.eclipse.ui.startup </code>
   * extension point, and that the user has not disabled via the preference
   * page.
   */
  private void startPlugins() {
    IExtensionRegistry registry = Platform.getExtensionRegistry();

    // bug 55901: don't use getConfigElements directly, for pre-3.0
    // compat, make sure to allow both missing class
    // attribute and a missing startup element
    IExtensionPoint point = registry.getExtensionPoint(
        PlatformUI.PLUGIN_ID, IWorkbenchRegistryConstants.PL_STARTUP);

    final IExtension[] extensions = point.getExtensions();
    if (extensions.length == 0) {
      return;
    }
    Job job = new Job("Workbench early startup") { //$NON-NLS-1$
      protected IStatus run(IProgressMonitor monitor) {
        HashSet disabledPlugins = new HashSet(Arrays
            .asList(getDisabledEarlyActivatedPlugins()));
        monitor.beginTask(WorkbenchMessages.Workbench_startingPlugins,
            extensions.length);
        for (int i = 0; i < extensions.length; ++i) {
          if (monitor.isCanceled() || !isRunning()) {
            return Status.CANCEL_STATUS;
          }
          IExtension extension = extensions[i];

          // if the plugin is not in the set of disabled plugins, then
          // execute the code to start it
          if (!disabledPlugins.contains(extension.getNamespace())) {
            monitor.subTask(extension.getNamespace());
            SafeRunner.run(new EarlyStartupRunnable(extension));
          }
          monitor.worked(1);
        }
        monitor.done();
        return Status.OK_STATUS;
      }

      public boolean belongsTo(Object family) {
        return EARLY_STARTUP_FAMILY.equals(family);
      }
    };
    job.setSystem(true);
    job.schedule();
  }

  /**
   * Internal method for running the workbench UI. This entails processing and
   * dispatching events until the workbench is closed or restarted.
   *
   * @return return code {@link PlatformUI#RETURN_OK RETURN_OK}for normal
   *         exit; {@link PlatformUI#RETURN_RESTART RETURN_RESTART}if the
   *         workbench was terminated with a call to
   *         {@link IWorkbench#restart IWorkbench.restart};
   *         {@link PlatformUI#RETURN_UNSTARTABLE RETURN_UNSTARTABLE}if the
   *         workbench could not be started; other values reserved for future
   *         use
   * @since 3.0
   */
  private int runUI() {
    UIStats.start(UIStats.START_WORKBENCH, "Workbench"); //$NON-NLS-1$

    // deadlock code
    boolean avoidDeadlock = true;

    String[] commandLineArgs = Platform.getCommandLineArgs();
    for (int i = 0; i < commandLineArgs.length; i++) {
      if (commandLineArgs[i].equalsIgnoreCase("-allowDeadlock")) { //$NON-NLS-1$
        avoidDeadlock = false;
      }
    }

    final UISynchronizer synchronizer;
   
    if (avoidDeadlock) {
      UILockListener uiLockListener = new UILockListener(display);
      Platform.getJobManager().setLockListener(uiLockListener);
      synchronizer = new UISynchronizer(display, uiLockListener);
      display
          .setSynchronizer(synchronizer);
      // declare the main thread to be a startup thread.
      UISynchronizer.startupThread.set(Boolean.TRUE);
    }
    else
      synchronizer = null;
   
    // prime the splash nice and early
    if (createSplash)
      createSplashWrapper();

    // ModalContext should not spin the event loop (there is no UI yet to
    // block)
    ModalContext.setAllowReadAndDispatch(false);

    // if the -debug command line argument is used and the event loop is
    // being
    // run while starting the Workbench, log a warning.
    if (WorkbenchPlugin.getDefault().isDebugging()) {
      display.asyncExec(new Runnable() {
        public void run() {
          if (isStarting()) {
            WorkbenchPlugin
                .log(StatusUtil
                    .newStatus(
                        IStatus.WARNING,
                        "Event loop should not be run while the Workbench is starting.", //$NON-NLS-1$
                        new RuntimeException()));
          }
        }
      });
    }

    Listener closeListener = new Listener() {
      public void handleEvent(Event event) {
        event.doit = close();
      }
    };

    // Initialize an exception handler.
    Window.IExceptionHandler handler = ExceptionHandler.getInstance();

    try {
      // react to display close event by closing workbench nicely
      display.addListener(SWT.Close, closeListener);

      // install backstop to catch exceptions thrown out of event loop
      Window.setExceptionHandler(handler);

      final boolean [] initOK = new boolean[1];
     
      if (getSplash() != null) {
       
        final boolean[] initDone = new boolean[]{false};
        Thread initThread = new Thread() {
        /* (non-Javadoc)
         * @see java.lang.Thread#run()
         */
        public void run() {
          try {
            //declare us to be a startup thread so that our syncs will be executed
            UISynchronizer.startupThread.set(Boolean.TRUE);
            initOK[0] = Workbench.this.init();
          } finally {
            initDone[0] = true;
            display.wake();
          }
        }};
        initThread.start();
        while (true) {
          if (!display.readAndDispatch()) {
            if (initDone[0])
              break;
            display.sleep();
          }
         
        }
      }
      else {
        // initialize workbench and restore or open one window
        initOK[0] = init();

      }
      // drop the splash screen now that a workbench window is up
      Platform.endSplash();

      // let the advisor run its start up code
      if (initOK[0]) {
        advisor.postStartup(); // may trigger a close/restart
      }

      if (initOK[0] && runEventLoop) {
        // start eager plug-ins
        startPlugins();
        addStartupRegistryListener();

        // WWinPluginAction.refreshActionList();

        display.asyncExec(new Runnable() {
          public void run() {
            UIStats.end(UIStats.START_WORKBENCH, this, "Workbench"); //$NON-NLS-1$
            UIStats.startupComplete();
          }
        });

        getWorkbenchTestable().init(display, this);

        // allow ModalContext to spin the event loop
        ModalContext.setAllowReadAndDispatch(true);
        isStarting = false;

        if (synchronizer != null)
          synchronizer.started();
        // the event loop
        runEventLoop(handler, display);
      }

    } catch (final Exception e) {
      if (!display.isDisposed()) {
        handler.handleException(e);
      } else {
        String msg = "Exception in Workbench.runUI after display was disposed"; //$NON-NLS-1$
        WorkbenchPlugin.log(msg, new Status(IStatus.ERROR,
            WorkbenchPlugin.PI_WORKBENCH, 1, msg, e));
      }
    } finally {
      // mandatory clean up

      // The runEventLoop flag may not have been cleared if an exception
      // occurred
      // Needs to be false to ensure PlatformUI.isWorkbenchRunning()
      // returns false.
      runEventLoop = false;

      if (!display.isDisposed()) {
        display.removeListener(SWT.Close, closeListener);
      }
    }

    // restart or exit based on returnCode
    return returnCode;
  }

  /*
   * Runs an event loop for the workbench.
   */
  private void runEventLoop(Window.IExceptionHandler handler, Display display) {
    runEventLoop = true;
    while (runEventLoop) {
      try {
        if (!display.readAndDispatch()) {
          getAdvisor().eventLoopIdle(display);
        }
      } catch (Throwable t) {
        handler.handleException(t);
      }
    }
  }

  /*
   * Saves the current state of the workbench so it can be restored later on
   */
  private IStatus saveState(IMemento memento) {
    MultiStatus result = new MultiStatus(PlatformUI.PLUGIN_ID, IStatus.OK,
        WorkbenchMessages.Workbench_problemsSaving, null);

    // Save the version number.
    memento.putString(IWorkbenchConstants.TAG_VERSION, VERSION_STRING[1]);

    // Save how many plug-ins were loaded while restoring the workbench
    if (progressCount != -1) {
      memento.putInteger(IWorkbenchConstants.TAG_PROGRESS_COUNT,
          progressCount);
    }

    // Save the advisor state.
    IMemento advisorState = memento
        .createChild(IWorkbenchConstants.TAG_WORKBENCH_ADVISOR);
    result.add(getAdvisor().saveState(advisorState));

    // Save the workbench windows.
    IWorkbenchWindow[] windows = getWorkbenchWindows();
    for (int nX = 0; nX < windows.length; nX++) {
      WorkbenchWindow window = (WorkbenchWindow) windows[nX];
      IMemento childMem = memento
          .createChild(IWorkbenchConstants.TAG_WINDOW);
      result.merge(window.saveState(childMem));
    }
    result.add(getEditorHistory().saveState(
        memento.createChild(IWorkbenchConstants.TAG_MRU_LIST)));
    return result;
  }

  /*
   * Save the workbench UI in a persistence file.
   */
  private boolean saveMementoToFile(XMLMemento memento) {
    // Save it to a file.
    // XXX: nobody currently checks the return value of this method.
    File stateFile = getWorkbenchStateFile();
    if (stateFile == null) {
      return false;
    }
    try {
      FileOutputStream stream = new FileOutputStream(stateFile);
      OutputStreamWriter writer = new OutputStreamWriter(stream, "utf-8"); //$NON-NLS-1$
      memento.save(writer);
      writer.close();
    } catch (IOException e) {
      stateFile.delete();
      MessageDialog.openError((Shell) null,
          WorkbenchMessages.SavingProblem,
          WorkbenchMessages.ProblemSavingState);
      return false;
    }

    // Success !
    return true;
  }

  /*
   * (non-Javadoc) Method declared on IWorkbench.
   */
  public IWorkbenchPage showPerspective(String perspectiveId,
      IWorkbenchWindow window) throws WorkbenchException {
    Assert.isNotNull(perspectiveId);

    // If the specified window has the requested perspective open, then the
    // window
    // is given focus and the perspective is shown. The page's input is
    // ignored.
    WorkbenchWindow win = (WorkbenchWindow) window;
    if (win != null) {
      WorkbenchPage page = win.getActiveWorkbenchPage();
      if (page != null) {
        IPerspectiveDescriptor perspectives[] = page
            .getOpenPerspectives();
        for (int i = 0; i < perspectives.length; i++) {
          IPerspectiveDescriptor persp = perspectives[i];
          if (perspectiveId.equals(persp.getId())) {
            win.makeVisible();
            page.setPerspective(persp);
            return page;
          }
        }
      }
    }

    // If another window that has the workspace root as input and the
    // requested
    // perpective open and active, then the window is given focus.
    IAdaptable input = getDefaultPageInput();
    IWorkbenchWindow[] windows = getWorkbenchWindows();
    for (int i = 0; i < windows.length; i++) {
      win = (WorkbenchWindow) windows[i];
      if (window != win) {
        WorkbenchPage page = win.getActiveWorkbenchPage();
        if (page != null) {
          boolean inputSame = false;
          if (input == null) {
            inputSame = (page.getInput() == null);
          } else {
            inputSame = input.equals(page.getInput());
          }
          if (inputSame) {
            Perspective persp = page.getActivePerspective();
            if (persp != null) {
              IPerspectiveDescriptor desc = persp.getDesc();
              if (desc != null) {
                if (perspectiveId.equals(desc.getId())) {
                  Shell shell = win.getShell();
                  shell.open();
                  if (shell.getMinimized()) {
                    shell.setMinimized(false);
                  }
                  return page;
                }
              }
            }
          }
        }
      }
    }

    // Otherwise the requested perspective is opened and shown in the
    // specified
    // window or in a new window depending on the current user preference
    // for opening
    // perspectives, and that window is given focus.
    win = (WorkbenchWindow) window;
    if (win != null) {
      IPreferenceStore store = WorkbenchPlugin.getDefault()
          .getPreferenceStore();
      int mode = store.getInt(IPreferenceConstants.OPEN_PERSP_MODE);
      IWorkbenchPage page = win.getActiveWorkbenchPage();
      IPerspectiveDescriptor persp = null;
      if (page != null) {
        persp = page.getPerspective();
      }

      // Only open a new window if user preference is set and the window
      // has an active perspective.
      if (IPreferenceConstants.OPM_NEW_WINDOW == mode && persp != null) {
        IWorkbenchWindow newWindow = openWorkbenchWindow(perspectiveId,
            input);
        return newWindow.getActivePage();
      }

      IPerspectiveDescriptor desc = getPerspectiveRegistry()
          .findPerspectiveWithId(perspectiveId);
      if (desc == null) {
        throw new WorkbenchException(
            NLS
                .bind(
                    WorkbenchMessages.WorkbenchPage_ErrorCreatingPerspective,
                    perspectiveId));
      }
      win.getShell().open();
      if (page == null) {
        page = win.openPage(perspectiveId, input);
      } else {
        page.setPerspective(desc);
      }
      return page;
    }

    // Just throw an exception....
    throw new WorkbenchException(NLS
        .bind(WorkbenchMessages.Workbench_showPerspectiveError,
            perspectiveId));
  }

  /*
   * (non-Javadoc) Method declared on IWorkbench.
   */
  public IWorkbenchPage showPerspective(String perspectiveId,
      IWorkbenchWindow window, IAdaptable input)
      throws WorkbenchException {
    Assert.isNotNull(perspectiveId);

    // If the specified window has the requested perspective open and the
    // same requested
    // input, then the window is given focus and the perspective is shown.
    boolean inputSameAsWindow = false;
    WorkbenchWindow win = (WorkbenchWindow) window;
    if (win != null) {
      WorkbenchPage page = win.getActiveWorkbenchPage();
      if (page != null) {
        boolean inputSame = false;
        if (input == null) {
          inputSame = (page.getInput() == null);
        } else {
          inputSame = input.equals(page.getInput());
        }
        if (inputSame) {
          inputSameAsWindow = true;
          IPerspectiveDescriptor perspectives[] = page
              .getOpenPerspectives();
          for (int i = 0; i < perspectives.length; i++) {
            IPerspectiveDescriptor persp = perspectives[i];
            if (perspectiveId.equals(persp.getId())) {
              win.makeVisible();
              page.setPerspective(persp);
              return page;
            }
          }
        }
      }
    }

    // If another window has the requested input and the requested
    // perpective open and active, then that window is given focus.
    IWorkbenchWindow[] windows = getWorkbenchWindows();
    for (int i = 0; i < windows.length; i++) {
      win = (WorkbenchWindow) windows[i];
      if (window != win) {
        WorkbenchPage page = win.getActiveWorkbenchPage();
        if (page != null) {
          boolean inputSame = false;
          if (input == null) {
            inputSame = (page.getInput() == null);
          } else {
            inputSame = input.equals(page.getInput());
          }
          if (inputSame) {
            Perspective persp = page.getActivePerspective();
            if (persp != null) {
              IPerspectiveDescriptor desc = persp.getDesc();
              if (desc != null) {
                if (perspectiveId.equals(desc.getId())) {
                  win.getShell().open();
                  return page;
                }
              }
            }
          }
        }
      }
    }

    // If the specified window has the same requested input but not the
    // requested
    // perspective, then the window is given focus and the perspective is
    // opened and shown
    // on condition that the user preference is not to open perspectives in
    // a new window.
    win = (WorkbenchWindow) window;
    if (inputSameAsWindow && win != null) {
      IPreferenceStore store = WorkbenchPlugin.getDefault()
          .getPreferenceStore();
      int mode = store.getInt(IPreferenceConstants.OPEN_PERSP_MODE);

      if (IPreferenceConstants.OPM_NEW_WINDOW != mode) {
        IWorkbenchPage page = win.getActiveWorkbenchPage();
        IPerspectiveDescriptor desc = getPerspectiveRegistry()
            .findPerspectiveWithId(perspectiveId);
        if (desc == null) {
          throw new WorkbenchException(
              NLS
                  .bind(
                      WorkbenchMessages.WorkbenchPage_ErrorCreatingPerspective,
                      perspectiveId));
        }
        win.getShell().open();
        if (page == null) {
          page = win.openPage(perspectiveId, input);
        } else {
          page.setPerspective(desc);
        }
        return page;
      }
    }

    // If the specified window has no active perspective, then open the
    // requested perspective and show the specified window.
    if (win != null) {
      IWorkbenchPage page = win.getActiveWorkbenchPage();
      IPerspectiveDescriptor persp = null;
      if (page != null) {
        persp = page.getPerspective();
      }
      if (persp == null) {
        IPerspectiveDescriptor desc = getPerspectiveRegistry()
            .findPerspectiveWithId(perspectiveId);
        if (desc == null) {
          throw new WorkbenchException(
              NLS
                  .bind(
                      WorkbenchMessages.WorkbenchPage_ErrorCreatingPerspective,
                      perspectiveId));
        }
        win.getShell().open();
        if (page == null) {
          page = win.openPage(perspectiveId, input);
        } else {
          page.setPerspective(desc);
        }
        return page;
      }
    }

    // Otherwise the requested perspective is opened and shown in a new
    // window, and the
    // window is given focus.
    IWorkbenchWindow newWindow = openWorkbenchWindow(perspectiveId, input);
    return newWindow.getActivePage();
  }

  /*
   * Shuts down the application.
   */
  private void shutdown() {
    // shutdown application-specific portions first
    advisor.postShutdown();

    // notify regular workbench clients of shutdown, and clear the list when
    // done
    firePostShutdown();
    workbenchListeners.clear();

    cancelEarlyStartup();

    // for dynamic UI
    Platform.getExtensionRegistry().removeRegistryChangeListener(
        extensionEventHandler);
    Platform.getExtensionRegistry().removeRegistryChangeListener(
        startupRegistryListener);

    ((GrabFocus) Tweaklets.get(GrabFocus.KEY)).dispose();
   
    // Bring down all of the services.
    serviceLocator.dispose();

    workbenchActivitySupport.dispose();
    WorkbenchHelpSystem.disposeIfNecessary();

    // shutdown the rest of the workbench
    WorkbenchColors.shutdown();
    activityHelper.shutdown();
    uninitializeImages();
    if (WorkbenchPlugin.getDefault() != null) {
      WorkbenchPlugin.getDefault().reset();
    }
    WorkbenchThemeManager.getInstance().dispose();
    PropertyPageContributorManager.getManager().dispose();
    ObjectActionContributorManager.getManager().dispose();
    if (tracker != null) {
      tracker.close();
    }
  }

  /**
   * Cancels the early startup job, if it's still running.
   */
  private void cancelEarlyStartup() {
    Platform.getJobManager().cancel(EARLY_STARTUP_FAMILY);
    // We do not currently wait for any plug-in currently being started to
    // complete
    // (e.g. by doing a join on EARLY_STARTUP_FAMILY), since they may do a
    // syncExec,
    // which would hang. See bug 94537 for rationale.
  }

  /*
   * (non-Javadoc) Method declared on IWorkbench.
   */
  public IDecoratorManager getDecoratorManager() {
    return WorkbenchPlugin.getDefault().getDecoratorManager();
  }

  /*
   * Returns the workbench window which was last known being the active one,
   * or <code> null </code> .
   */
  private WorkbenchWindow getActivatedWindow() {
    if (activatedWindow != null) {
      Shell shell = activatedWindow.getShell();
      if (shell != null && !shell.isDisposed()) {
        return activatedWindow;
      }
    }

    return null;
  }

  /*
   * Sets the workbench window which was last known being the active one, or
   * <code> null </code> .
   */
  /* package */
  void setActivatedWindow(WorkbenchWindow window) {
    activatedWindow = window;
  }

  /**
   * Returns the unique object that applications use to configure the
   * workbench.
   * <p>
   * IMPORTANT This method is declared package-private to prevent regular
   * plug-ins from downcasting IWorkbench to Workbench and getting hold of the
   * workbench configurer that would allow them to tamper with the workbench.
   * The workbench configurer is available only to the application.
   * </p>
   */
  /* package */
  WorkbenchConfigurer getWorkbenchConfigurer() {
    if (workbenchConfigurer == null) {
      workbenchConfigurer = new WorkbenchConfigurer();
    }
    return workbenchConfigurer;
  }

  /**
   * Returns the workbench advisor that created this workbench.
   * <p>
   * IMPORTANT This method is declared package-private to prevent regular
   * plug-ins from downcasting IWorkbench to Workbench and getting hold of the
   * workbench advisor that would allow them to tamper with the workbench. The
   * workbench advisor is internal to the application.
   * </p>
   */
  /* package */
  WorkbenchAdvisor getAdvisor() {
    return advisor;
  }

  /*
   * (non-Javadoc) Method declared on IWorkbench.
   */
  public Display getDisplay() {
    return display;
  }

  /**
   * Returns the default perspective id, which may be <code>null</code>.
   *
   * @return the default perspective id, or <code>null</code>
   */
  public String getDefaultPerspectiveId() {
    return getAdvisor().getInitialWindowPerspectiveId();
  }

  /**
   * Returns the default workbench window page input.
   *
   * @return the default window page input or <code>null</code> if none
   */
  public IAdaptable getDefaultPageInput() {
    return getAdvisor().getDefaultPageInput();
  }

  /**
   * Returns the id of the preference page that should be presented most
   * prominently.
   *
   * @return the id of the preference page, or <code>null</code> if none
   */
  public String getMainPreferencePageId() {
    String id = getAdvisor().getMainPreferencePageId();
    return id;
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.ui.IWorkbench
   * @since 3.0
   */
  public IElementFactory getElementFactory(String factoryId) {
    Assert.isNotNull(factoryId);
    return WorkbenchPlugin.getDefault().getElementFactory(factoryId);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.ui.IWorkbench#getProgressService()
   */
  public IProgressService getProgressService() {
    return ProgressManager.getInstance();
  }

  private WorkbenchActivitySupport workbenchActivitySupport;

  private WorkbenchCommandSupport workbenchCommandSupport;

  private WorkbenchContextSupport workbenchContextSupport;

  /**
   * The single instance of the binding manager used by the workbench. This is
   * initialized in <code>Workbench.init(Display)</code> and then never
   * changed. This value will only be <code>null</code> if the
   * initialization call has not yet completed.
   *
   * @since 3.1
   */
  private BindingManager bindingManager;

  /**
   * The single instance of the command manager used by the workbench. This is
   * initialized in <code>Workbench.init(Display)</code> and then never
   * changed. This value will only be <code>null</code> if the
   * initialization call has not yet completed.
   *
   * @since 3.1
   */
  private CommandManager commandManager;

  /**
   * The single instance of the context manager used by the workbench. This is
   * initialized in <code>Workbench.init(Display)</code> and then never
   * changed. This value will only be <code>null</code> if the
   * initialization call has not yet completed.
   *
   * @since 3.1
   */
  private ContextManager contextManager;

  public IWorkbenchActivitySupport getActivitySupport() {
    return workbenchActivitySupport;
  }

  public IWorkbenchCommandSupport getCommandSupport() {
    return workbenchCommandSupport;
  }

  public IWorkbenchContextSupport getContextSupport() {
    return workbenchContextSupport;
  }

  private final IWindowListener windowListener = new IWindowListener() {

    public void windowActivated(IWorkbenchWindow window) {
      updateActiveWorkbenchWindowMenuManager(true);
    }

    public void windowClosed(IWorkbenchWindow window) {
      updateActiveWorkbenchWindowMenuManager(true);
    }

    public void windowDeactivated(IWorkbenchWindow window) {
      updateActiveWorkbenchWindowMenuManager(true);
    }

    public void windowOpened(IWorkbenchWindow window) {
      updateActiveWorkbenchWindowMenuManager(true);
    }
  };

  private final IBindingManagerListener bindingManagerListener = new IBindingManagerListener() {

    public void bindingManagerChanged(
        BindingManagerEvent bindingManagerEvent) {
      if (bindingManagerEvent.isActiveBindingsChanged()) {
        updateActiveWorkbenchWindowMenuManager(true);
      }
    }
  };

  /**
   * The source provider that tracks the activation of action sets within the
   * workbench. This source provider is <code>null</code> until
   * {@link #initializeDefaultServices()} is called.
   */
  private ActionSetSourceProvider actionSetSourceProvider;

  private WorkbenchWindow activeWorkbenchWindow = null;

  private void updateActiveWorkbenchWindowMenuManager(boolean textOnly) {
    if (activeWorkbenchWindow != null) {
      activeWorkbenchWindow
          .removeActionSetsListener(actionSetSourceProvider);
      activeWorkbenchWindow = null;
    }
    boolean actionSetsUpdated = false;

    final IWorkbenchWindow workbenchWindow = getActiveWorkbenchWindow();

    if (workbenchWindow instanceof WorkbenchWindow) {
      activeWorkbenchWindow = (WorkbenchWindow) workbenchWindow;
      if (activeWorkbenchWindow.isClosing()) {
        return;
      }

      // Update the action sets.
      final Shell windowShell = activeWorkbenchWindow.getShell();
      final Shell activeShell = getDisplay().getActiveShell();
      final IContextService service = (IContextService) getService(IContextService.class);
      if (Util.equals(windowShell, activeShell)
          || service.getShellType(activeShell) == IContextService.TYPE_WINDOW) {
        activeWorkbenchWindow
            .addActionSetsListener(actionSetSourceProvider);
        final WorkbenchPage page = activeWorkbenchWindow
            .getActiveWorkbenchPage();
        final IActionSetDescriptor[] newActionSets;
        if (page != null) {
          newActionSets = page.getActionSets();
          final ActionSetsEvent event = new ActionSetsEvent(
              newActionSets);
          actionSetSourceProvider.actionSetsChanged(event);
          actionSetsUpdated = true;
        }
      }

      final MenuManager menuManager = activeWorkbenchWindow
          .getMenuManager();

      if (textOnly) {
        menuManager.update(IAction.TEXT);
      } else {
        menuManager.updateAll(true);
      }
    }

    if (!actionSetsUpdated) {
      final ActionSetsEvent event = new ActionSetsEvent(null);
      actionSetSourceProvider.actionSetsChanged(event);
    }
  }

  private ActivityPersistanceHelper activityHelper;

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.ui.IWorkbench#getIntroManager()
   */
  public IIntroManager getIntroManager() {
    return getWorkbenchIntroManager();
  }

  /**
   * @return the workbench intro manager
   * @since 3.0
   */
  /* package */WorkbenchIntroManager getWorkbenchIntroManager() {
    if (introManager == null) {
      introManager = new WorkbenchIntroManager(this);
    }
    return introManager;
  }

  private WorkbenchIntroManager introManager;

  /**
   * @return the intro extension for this workbench.
   *
   * @since 3.0
   */
  public IntroDescriptor getIntroDescriptor() {
    return introDescriptor;
  }

  /**
   * This method exists as a test hook. This method should <strong>NEVER</strong>
   * be called by clients.
   *
   * @param descriptor
   *            The intro descriptor to use.
   * @since 3.0
   */
  public void setIntroDescriptor(IntroDescriptor descriptor) {
    if (getIntroManager().getIntro() != null) {
      getIntroManager().closeIntro(getIntroManager().getIntro());
    }
    introDescriptor = descriptor;
  }

  /**
   * The descriptor for the intro extension that is valid for this workspace,
   * <code>null</code> if none.
   */
  private IntroDescriptor introDescriptor;

  private IExtensionTracker tracker;

  private IRegistryChangeListener startupRegistryListener = new IRegistryChangeListener() {

    /*
     * (non-Javadoc)
     *
     * @see org.eclipse.core.runtime.IRegistryChangeListener#registryChanged(org.eclipse.core.runtime.IRegistryChangeEvent)
     */
    public void registryChanged(IRegistryChangeEvent event) {
      final IExtensionDelta[] deltas = event.getExtensionDeltas(
          PlatformUI.PLUGIN_ID,
          IWorkbenchRegistryConstants.PL_STARTUP);
      if (deltas.length == 0) {
        return;
      }
      final String disabledPlugins = PrefUtil
          .getInternalPreferenceStore()
          .getString(
              IPreferenceConstants.PLUGINS_NOT_ACTIVATED_ON_STARTUP);

      for (int i = 0; i < deltas.length; i++) {
        IExtension extension = deltas[i].getExtension();
        if (deltas[i].getKind() == IExtensionDelta.REMOVED) {
          continue;
        }

        // if the plugin is not in the set of disabled plugins,
        // then
        // execute the code to start it
        if (disabledPlugins.indexOf(extension.getNamespace()) == -1) {
          SafeRunner.run(new EarlyStartupRunnable(extension));
        }
      }

    }
  };

  private String factoryID;

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.ui.IWorkbench#getThemeManager()
   */
  public IThemeManager getThemeManager() {
    return WorkbenchThemeManager.getInstance();
  }

  /**
   * Returns <code>true</code> if the workbench is running,
   * <code>false</code> if it has been terminated.
   *
   * @return <code>true</code> if the workbench is running,
   *         <code>false</code> if it has been terminated.
   */
  public boolean isRunning() {
    return runEventLoop;
  }

  /**
   * Return the presentation ID specified by the preference or the default ID
   * if undefined.
   *
   * @return the presentation ID
   * @see IWorkbenchPreferenceConstants#PRESENTATION_FACTORY_ID
   */
  public String getPresentationId() {
    if (factoryID != null) {
      return factoryID;
    }

    factoryID = PrefUtil.getAPIPreferenceStore().getString(
        IWorkbenchPreferenceConstants.PRESENTATION_FACTORY_ID);

    // Workaround for bug 58975 - New preference mechanism does not properly
    // initialize defaults
    // Ensure that the UI plugin has started too.
    if (factoryID == null || factoryID.equals("")) { //$NON-NLS-1$
      factoryID = IWorkbenchConstants.DEFAULT_PRESENTATION_ID;
    }
    return factoryID;
  }

  /**
   * <p>
   * Indicates the start of a large update within the workbench. This is used
   * to disable CPU-intensive, change-sensitive services that were temporarily
   * disabled in the midst of large changes. This method should always be
   * called in tandem with <code>largeUpdateEnd</code>, and the event loop
   * should not be allowed to spin before that method is called.
   * </p>
   * <p>
   * Important: always use with <code>largeUpdateEnd</code>!
   * </p>
   */
  public final void largeUpdateStart() {
    if (largeUpdates++ == 0) {
      // TODO Consider whether these lines still need to be here.
      // workbenchCommandSupport.setProcessing(false);
      // workbenchContextSupport.setProcessing(false);

      final IWorkbenchWindow[] windows = getWorkbenchWindows();
      for (int i = 0; i < windows.length; i++) {
        IWorkbenchWindow window = windows[i];
        if (window instanceof WorkbenchWindow) {
          ((WorkbenchWindow) window).largeUpdateStart();
        }
      }
    }
  }

  /**
   * <p>
   * Indicates the end of a large update within the workbench. This is used to
   * re-enable services that were temporarily disabled in the midst of large
   * changes. This method should always be called in tandem with
   * <code>largeUpdateStart</code>, and the event loop should not be
   * allowed to spin before this method is called.
   * </p>
   * <p>
   * Important: always protect this call by using <code>finally</code>!
   * </p>
   */
  public final void largeUpdateEnd() {
    if (--largeUpdates == 0) {
      // TODO Consider whether these lines still need to be here.
      // workbenchCommandSupport.setProcessing(true);
      // workbenchContextSupport.setProcessing(true);

      // Perform window-specific blocking.
      final IWorkbenchWindow[] windows = getWorkbenchWindows();
      for (int i = 0; i < windows.length; i++) {
        IWorkbenchWindow window = windows[i];
        if (window instanceof WorkbenchWindow) {
          ((WorkbenchWindow) window).largeUpdateEnd();
        }
      }
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.ui.IWorkbench#getExtensionTracker()
   */
  public IExtensionTracker getExtensionTracker() {
    if (tracker == null) {
      tracker = new UIExtensionTracker(getDisplay());
    }
    return tracker;
  }

  /**
   * Adds the listener that handles startup plugins
   *
   * @since 3.1
   */
  private void addStartupRegistryListener() {
    IExtensionRegistry registry = Platform.getExtensionRegistry();
    registry.addRegistryChangeListener(startupRegistryListener);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.ui.IWorkbench#getHelpSystem()
   */
  public IWorkbenchHelpSystem getHelpSystem() {
    return WorkbenchHelpSystem.getInstance();
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.ui.IWorkbench#getHelpSystem()
   */
  public IWorkbenchBrowserSupport getBrowserSupport() {
    return WorkbenchBrowserSupport.getInstance();
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.ui.IWorkbench#getViewRegistry()
   */
  public IViewRegistry getViewRegistry() {
    return WorkbenchPlugin.getDefault().getViewRegistry();
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.ui.IWorkbench#getNewWizardRegistry()
   */
  public IWizardRegistry getNewWizardRegistry() {
    return WorkbenchPlugin.getDefault().getNewWizardRegistry();
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.ui.IWorkbench#getImportWizardRegistry()
   */
  public IWizardRegistry getImportWizardRegistry() {
    return WorkbenchPlugin.getDefault().getImportWizardRegistry();
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.ui.IWorkbench#getExportWizardRegistry()
   */
  public IWizardRegistry getExportWizardRegistry() {
    return WorkbenchPlugin.getDefault().getExportWizardRegistry();
  }

  public final Object getAdapter(final Class key) {
    return serviceLocator.getService(key);
  }

  private void doRestoreState(final IMemento memento, final MultiStatus status) {
    IMemento childMem;
    try {
      UIStats.start(UIStats.RESTORE_WORKBENCH, "MRUList"); //$NON-NLS-1$
      IMemento mruMemento = memento
          .getChild(IWorkbenchConstants.TAG_MRU_LIST);
      if (mruMemento != null) {
        status.add(getEditorHistory().restoreState(mruMemento));
      }
    } finally {
      UIStats.end(UIStats.RESTORE_WORKBENCH, this, "MRUList"); //$NON-NLS-1$
    }

    // Restore advisor state.
    IMemento advisorState = memento
        .getChild(IWorkbenchConstants.TAG_WORKBENCH_ADVISOR);
    if (advisorState != null) {
      status.add(getAdvisor().restoreState(advisorState));
    }

    // Get the child windows.
    IMemento[] children = memento
        .getChildren(IWorkbenchConstants.TAG_WINDOW);

    createdWindows = new WorkbenchWindow[children.length];

    // Read the workbench windows.
    for (int i = 0; i < children.length; i++) {
      childMem = children[i];
      final WorkbenchWindow [] newWindow = new WorkbenchWindow[1];
     
      StartupThreading.runWithoutExceptions(new StartupRunnable() {

        public void runWithException() {
          newWindow[0] = newWorkbenchWindow();
          newWindow[0].create()
        }});
      createdWindows[i] = newWindow[0];

      // allow the application to specify an initial perspective to open
      // @issue temporary workaround for ignoring initial perspective
      // String initialPerspectiveId =
      // getAdvisor().getInitialWindowPerspectiveId();
      // if (initialPerspectiveId != null) {
      // IPerspectiveDescriptor desc =
      // getPerspectiveRegistry().findPerspectiveWithId(initialPerspectiveId);
      // result.merge(newWindow.restoreState(childMem, desc));
      // }
      // add the window so that any work done in newWindow.restoreState
      // that relies on Workbench methods has windows to work with
      windowManager.add(newWindow[0]);

      // now that we've added it to the window manager we need to listen
      // for any exception that might hose us before we get a chance to
      // open it. If one occurs, remove the new window from the manager.
      // Assume that the new window is a phantom for now
      boolean restored = false;
      try {
        status.merge(newWindow[0].restoreState(childMem, null));
        try {
          newWindow[0].fireWindowRestored();
        } catch (WorkbenchException e) {
          status.add(e.getStatus());
        }
        // everything worked so far, don't close now
        restored = true;
      } finally {
        if (!restored) {
          // null the window in newWindowHolder so that it won't be
          // opened later on
          createdWindows[i] = null;
          StartupThreading.runWithoutExceptions(new StartupRunnable() {

            public void runWithException() throws Throwable {
              newWindow[0].close();
            }});
        }
      }
    }
  }

  private void openWindowsAfterRestore() {
    if (createdWindows == null) {
      return;
    }
    // now open the windows (except the ones that were nulled because we
    // closed them above)
    for (int i = 0; i < createdWindows.length; i++) {
      if (createdWindows[i] != null) {
        final WorkbenchWindow myWindow = createdWindows[i];
        StartupThreading.runWithoutExceptions(new StartupRunnable() {

          public void runWithException() throws Throwable {
            boolean opened = false;
            try {
              myWindow.open();
              opened = true;
            } finally {
              if (!opened) {
                myWindow.close();
              }
            }
          }});
      }
    }
    createdWindows = null;
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.ui.services.IServiceLocator#getService(java.lang.Object)
   */
  public final Object getService(final Class key) {
    return serviceLocator.getService(key);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.ui.services.IServiceLocator#hasService(java.lang.Object)
   */
  public final boolean hasService(final Class key) {
    return serviceLocator.hasService(key);
  }

  /**
   * Registers a service with this locator. If there is an existing service
   * matching the same <code>api</code> and it implements
   * {@link IDisposable}, it will be disposed.
   *
   * @param api
   *            This is the interface that the service implements. Must not be
   *            <code>null</code>.
   * @param service
   *            The service to register. This must be some implementation of
   *            <code>api</code>. This value must not be <code>null</code>.
   */
  public final void registerService(final Class api, final Object service) {
    serviceLocator.registerService(api, service);
  }

  /**
   * The source provider that tracks which context menus (i.e., menus with
   * target identifiers) are now showing. This value is <code>null</code>
   * until {@link #initializeDefaultServices()} is called.
   */
  private MenuSourceProvider menuSourceProvider;


  /**
   * Adds the ids of a menu that is now showing to the menu source provider.
   * This is used for legacy action-based handlers which need to become active
   * only for the duration of a menu being visible.
   *
   * @param menuIds
   *            The identifiers of the menu that is now showing; must not be
   *            <code>null</code>.
   */
  public final void addShowingMenus(final Set menuIds,
      final ISelection localSelection, final ISelection localEditorInput) {
    menuSourceProvider.addShowingMenus(menuIds, localSelection,
        localEditorInput);
  }

  /**
   * Removes the ids of a menu that is now hidden from the menu source
   * provider. This is used for legacy action-based handlers which need to
   * become active only for the duration of a menu being visible.
   *
   * @param menuIds
   *            The identifiers of the menu that is now hidden; must not be
   *            <code>null</code>.
   */
  public final void removeShowingMenus(final Set menuIds,
      final ISelection localSelection, final ISelection localEditorInput) {
    menuSourceProvider.removeShowingMenus(menuIds, localSelection,
        localEditorInput);
  }

  /* (non-Javadoc)
   * @see org.eclipse.ui.IWorkbench#saveAll(org.eclipse.jface.window.IShellProvider, org.eclipse.jface.operation.IRunnableContext, org.eclipse.ui.ISaveableFilter, boolean)
   */
  public boolean saveAll(IShellProvider shellProvider,
      IRunnableContext runnableContext, ISaveableFilter filter,
      boolean confirm) {
    SaveablesList saveablesList = (SaveablesList) PlatformUI.getWorkbench()
        .getService(ISaveablesLifecycleListener.class);
    Saveable[] saveables = saveablesList.getOpenModels();
    List toSave = getFilteredSaveables(filter, saveables);
    if (toSave.isEmpty())
      return true;
   
    if (!confirm) {
      return !saveablesList.saveModels(toSave, shellProvider, runnableContext);
    }
   
    // We must negate the result since false is cancel saveAll
    return !saveablesList.promptForSaving(toSave, shellProvider, runnableContext, true, false);
  }

  /*
   * Apply the given filter to the list of saveables
   */
  private List getFilteredSaveables(ISaveableFilter filter, Saveable[] saveables) {
    List toSave = new ArrayList();
    if (filter == null) {
      for (int i = 0; i < saveables.length; i++) {
        Saveable saveable = saveables[i];
        if (saveable.isDirty())
          toSave.add(saveable);
      }
    } else {
      SaveablesList saveablesList = (SaveablesList)getService(ISaveablesLifecycleListener.class);
      for (int i = 0; i < saveables.length; i++) {
        Saveable saveable = saveables[i];
        if (saveable.isDirty()) {
          IWorkbenchPart[] parts = saveablesList.getPartsForSaveable(saveable);
          if (matchesFilter(filter, saveable, parts))
            toSave.add(saveable);
        }
      }
    }
    return toSave;
  }
 
  /*
   * Test whether the given filter matches the saveable
   */
  private boolean matchesFilter(ISaveableFilter filter, Saveable saveable,
      IWorkbenchPart[] parts) {
    return filter == null || filter.select(saveable, parts);
  }
}
TOP

Related Classes of org.eclipse.ui.internal.Workbench

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.