Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/eclipse/ui/internal/Workbench.java


1   /*******************************************************************************
2    * Copyright (c) 2000, 2004 IBM Corporation and others.
3    * All rights reserved. This program and the accompanying materials 
4    * are made available under the terms of the Common Public License v1.0
5    * which accompanies this distribution, and is available at
6    * http://www.eclipse.org/legal/cpl-v10.html
7    * 
8    * Contributors:
9    *     IBM Corporation - initial API and implementation
10   *******************************************************************************/
11  
12  package org.eclipse.ui.internal;
13  
14  import java.io.BufferedReader;
15  import java.io.File;
16  import java.io.FileInputStream;
17  import java.io.FileOutputStream;
18  import java.io.IOException;
19  import java.io.InputStreamReader;
20  import java.io.OutputStreamWriter;
21  import java.util.ArrayList;
22  import java.util.Map;
23  import java.util.Set;
24  
25  import org.eclipse.core.runtime.IAdaptable;
26  import org.eclipse.core.runtime.IExtension;
27  import org.eclipse.core.runtime.IExtensionPoint;
28  import org.eclipse.core.runtime.IExtensionRegistry;
29  import org.eclipse.core.runtime.IPath;
30  import org.eclipse.core.runtime.IProduct;
31  import org.eclipse.core.runtime.IStatus;
32  import org.eclipse.core.runtime.MultiStatus;
33  import org.eclipse.core.runtime.Platform;
34  import org.eclipse.core.runtime.Status;
35  import org.eclipse.jface.action.ActionContributionItem;
36  import org.eclipse.jface.action.ExternalActionManager;
37  import org.eclipse.jface.action.IAction;
38  import org.eclipse.jface.action.MenuManager;
39  import org.eclipse.jface.dialogs.ErrorDialog;
40  import org.eclipse.jface.dialogs.IDialogConstants;
41  import org.eclipse.jface.dialogs.MessageDialog;
42  import org.eclipse.jface.operation.ModalContext;
43  import org.eclipse.jface.preference.IPreferenceStore;
44  import org.eclipse.jface.preference.PreferenceManager;
45  import org.eclipse.jface.resource.ImageDescriptor;
46  import org.eclipse.jface.util.ListenerList;
47  import org.eclipse.jface.util.OpenStrategy;
48  import org.eclipse.jface.util.SafeRunnable;
49  import org.eclipse.jface.window.Window;
50  import org.eclipse.jface.window.WindowManager;
51  import org.eclipse.swt.SWT;
52  import org.eclipse.swt.custom.BusyIndicator;
53  import org.eclipse.swt.graphics.DeviceData;
54  import org.eclipse.swt.graphics.Image;
55  import org.eclipse.swt.widgets.Control;
56  import org.eclipse.swt.widgets.Display;
57  import org.eclipse.swt.widgets.Event;
58  import org.eclipse.swt.widgets.Listener;
59  import org.eclipse.swt.widgets.Shell;
60  import org.eclipse.ui.IDecoratorManager;
61  import org.eclipse.ui.IEditorPart;
62  import org.eclipse.ui.IEditorRegistry;
63  import org.eclipse.ui.IElementFactory;
64  import org.eclipse.ui.IMemento;
65  import org.eclipse.ui.IPerspectiveDescriptor;
66  import org.eclipse.ui.IPerspectiveRegistry;
67  import org.eclipse.ui.ISharedImages;
68  import org.eclipse.ui.IWindowListener;
69  import org.eclipse.ui.IWorkbench;
70  import org.eclipse.ui.IWorkbenchPage;
71  import org.eclipse.ui.IWorkbenchPreferenceConstants;
72  import org.eclipse.ui.IWorkbenchWindow;
73  import org.eclipse.ui.IWorkingSetManager;
74  import org.eclipse.ui.PlatformUI;
75  import org.eclipse.ui.WorkbenchException;
76  import org.eclipse.ui.XMLMemento;
77  import org.eclipse.ui.activities.IWorkbenchActivitySupport;
78  import org.eclipse.ui.application.IWorkbenchConfigurer;
79  import org.eclipse.ui.application.WorkbenchAdvisor;
80  import org.eclipse.ui.commands.CommandManagerEvent;
81  import org.eclipse.ui.commands.ICommandManagerListener;
82  import org.eclipse.ui.commands.IWorkbenchCommandSupport;
83  import org.eclipse.ui.contexts.ContextManagerEvent;
84  import org.eclipse.ui.contexts.IContextManagerListener;
85  import org.eclipse.ui.contexts.IWorkbenchContextSupport;
86  import org.eclipse.ui.internal.activities.ws.WorkbenchActivitySupport;
87  import org.eclipse.ui.internal.commands.ws.CommandCallback;
88  import org.eclipse.ui.internal.commands.ws.WorkbenchCommandSupport;
89  import org.eclipse.ui.internal.contexts.ws.WorkbenchContextSupport;
90  import org.eclipse.ui.internal.intro.IIntroRegistry;
91  import org.eclipse.ui.internal.intro.IntroDescriptor;
92  import org.eclipse.ui.internal.misc.Assert;
93  import org.eclipse.ui.internal.misc.Policy;
94  import org.eclipse.ui.internal.misc.UIStats;
95  import org.eclipse.ui.internal.progress.ProgressManager;
96  import org.eclipse.ui.internal.testing.WorkbenchTestable;
97  import org.eclipse.ui.internal.themes.ColorDefinition;
98  import org.eclipse.ui.internal.themes.FontDefinition;
99  import org.eclipse.ui.internal.themes.ThemeElementHelper;
100 import org.eclipse.ui.internal.themes.WorkbenchThemeManager;
101 import org.eclipse.ui.internal.util.PrefUtil;
102 import org.eclipse.ui.intro.IIntroManager;
103 import org.eclipse.ui.progress.IProgressService;
104 import org.eclipse.ui.themes.IThemeManager;
105 
106 /**
107  * The workbench class represents the top of the Eclipse user interface. Its
108  * primary responsability is the management of workbench windows, dialogs,
109  * wizards, and other workbench-related windows.
110  * <p>
111  * Note that any code that is run during the creation of a workbench instance
112  * should not required access to the display.
113  * </p>
114  * <p>
115  * Note that this internal class changed significantly between 2.1 and 3.0.
116  * Applications that used to define subclasses of this internal class need to
117  * be rewritten to use the new workbench advisor API.
118  * </p>
119  */
120 public final class Workbench implements IWorkbench {
121   private static final String VERSION_STRING[] = { "0.046", "2.0" }; //$NON-NLS-1$ //$NON-NLS-2$
122   private static final String DEFAULT_WORKBENCH_STATE_FILENAME = "workbench.xml"; //$NON-NLS-1$
123 
124   /**
125    * Holds onto the only instance of Workbench.
126    */
127   private static Workbench instance;
128 
129   /**
130    * The testable object facade.
131    * 
132    * @since 3.0
133    */
134   private static WorkbenchTestable testableObject;
135 
136   /**
137    * The display used for all UI interactions with this workbench.
138    * 
139    * @since 3.0
140    */
141   private Display display;
142 
143   private WindowManager windowManager;
144   private WorkbenchWindow activatedWindow;
145   private EditorHistory editorHistory;
146   private boolean runEventLoop = true;
147   private boolean isStarting = true;
148   private boolean isClosing = false;
149 
150   /**
151    * PlatformUI return code (as opposed to IPlatformRunnable return code).
152    */
153   private int returnCode;
154 
155   private ListenerList windowListeners = new ListenerList();
156 
157   /**
158    * Advisor providing application-specific configuration and customization
159    * of the workbench.
160    * 
161    * @since 3.0
162    */
163   private WorkbenchAdvisor advisor;
164 
165   /**
166    * Object for configuring the workbench. Lazily initialized to an instance
167    * unique to the workbench instance.
168    * 
169    * @since 3.0
170    */
171   private WorkbenchConfigurer workbenchConfigurer;
172 
173   //for dynamic UI
174   /**
175    * ExtensionEventHandler handles extension life-cycle events. 
176    */
177   private ExtensionEventHandler extensionEventHandler;
178   
179   /**
180      * A count of how many large updates are going on. This tracks nesting of
181      * requests to disable services during a large update -- similar to the
182      * <code>setRedraw</code> functionality on <code>Control</code>. When
183      * this value becomes greater than zero, services are disabled. When this
184      * value becomes zero, services are enabled. Please see
185      * <code>largeUpdateStart()</code> and <code>largeUpdateEnd()</code>.
186      */
187   private int largeUpdates = 0;
188 
189   /**
190    * Creates a new workbench.
191    * 
192    * @param display
193    *            the display to be used for all UI interactions with the
194    *            workbench
195    * @param advisor
196    *            the application-specific advisor that configures and
197    *            specializes this workbench instance
198    * @since 3.0
199    */
200   private Workbench(Display display, WorkbenchAdvisor advisor) {
201     super();
202 
203     if (instance != null && instance.isRunning()) {
204       throw new IllegalStateException(WorkbenchMessages.getString("Workbench.CreatingWorkbenchTwice")); //$NON-NLS-1$
205     }
206     Assert.isNotNull(display);
207     Assert.isNotNull(advisor);
208     this.advisor = advisor;
209     this.display = display;
210     Workbench.instance = this;
211     // for dynamic UI
212     extensionEventHandler = new ExtensionEventHandler(this);
213     Platform.getExtensionRegistry().addRegistryChangeListener(extensionEventHandler);
214   }
215 
216   /**
217    * Returns the one and only instance of the workbench, if there is one.
218    * 
219    * @return the workbench, or <code>null</code> if the workbench has not
220    *         been created, or has been created and already completed
221    */
222   public static final Workbench getInstance() {
223     return instance;
224   }
225 
226   /**
227    * Creates the workbench and associates it with the the given display and
228    * workbench advisor, and runs the workbench UI. This entails processing
229    * and dispatching events until the workbench is closed or restarted.
230    * <p>
231    * This method is intended to be called by <code>PlatformUI</code>.
232    * Fails if the workbench UI has already been created.
233    * </p>
234    * <p>
235    * The display passed in must be the default display.
236    * </p>
237    * 
238    * @param display
239    *            the display to be used for all UI interactions with the
240    *            workbench
241    * @param advisor
242    *            the application-specific advisor that configures and
243    *            specializes the workbench
244    * @return return code {@link PlatformUI#RETURN_OK RETURN_OK}for normal
245    *         exit; {@link PlatformUI#RETURN_RESTART RETURN_RESTART}if the
246    *         workbench was terminated with a call to
247    *         {@link IWorkbench#restart IWorkbench.restart}; other values
248    *         reserved for future use
249    */
250   public static final int createAndRunWorkbench(Display display, WorkbenchAdvisor advisor) {
251     // create the workbench instance
252     Workbench workbench = new Workbench(display, advisor);
253     // run the workbench event loop
254     int returnCode = workbench.runUI();
255     return returnCode;
256   }
257 
258   /**
259    * Creates the <code>Display</code> to be used by the workbench.
260    * 
261    * @return the display
262    */
263   public static Display createDisplay() {
264     // setup the application name used by SWT to lookup resources on some
265     // platforms
266     String applicationName = WorkbenchPlugin.getDefault().getAppName();
267     if (applicationName != null) {
268       Display.setAppName(applicationName);
269     }
270 
271     // create the display
272     Display newDisplay = null;
273     if (Policy.DEBUG_SWT_GRAPHICS) {
274       DeviceData data = new DeviceData();
275       data.tracking = true;
276       newDisplay = new Display(data);
277     } else {
278       newDisplay = new Display();
279     }
280 
281     // workaround for 1GEZ9UR and 1GF07HN
282     newDisplay.setWarnings(false);
283 
284     //Set the priority higher than normal so as to be higher
285     //than the JobManager.
286     Thread.currentThread().setPriority(Math.min(Thread.MAX_PRIORITY, Thread.NORM_PRIORITY + 1));
287 
288     return newDisplay;
289   }
290 
291   /**
292    * Returns the testable object facade, for use by the test harness.
293    * 
294    * @return the testable object facade
295    * @since 3.0
296    */
297   public static WorkbenchTestable getWorkbenchTestable() {
298     if (testableObject == null) {
299       testableObject = new WorkbenchTestable();
300     }
301     return testableObject;
302   }
303 
304   /*
305    * (non-Javadoc) Method declared on IWorkbench.
306    */
307   public void addWindowListener(IWindowListener l) {
308     windowListeners.add(l);
309   }
310 
311   /*
312    * (non-Javadoc) Method declared on IWorkbench.
313    */
314   public void removeWindowListener(IWindowListener l) {
315     windowListeners.remove(l);
316   }
317 
318   /**
319    * Fire window opened event.
320    * 
321    * @param window
322    *            The window which just opened; should not be <code>null</code>.
323    */
324   protected void fireWindowOpened(final IWorkbenchWindow window) {
325     Object list[] = windowListeners.getListeners();
326     for (int i = 0; i < list.length; i++) {
327       final IWindowListener l = (IWindowListener) list[i];
328       Platform.run(new SafeRunnable() {
329         public void run() {
330           l.windowOpened(window);
331         }
332       });
333     }
334   }
335   /**
336    * Fire window closed event.
337    * 
338    * @param window
339    *            The window which just closed; should not be <code>null</code>.
340    */
341   protected void fireWindowClosed(final IWorkbenchWindow window) {
342     if (activatedWindow == window) {
343       // Do not hang onto it so it can be GC'ed
344       activatedWindow = null;
345     }
346 
347     Object list[] = windowListeners.getListeners();
348     for (int i = 0; i < list.length; i++) {
349       final IWindowListener l = (IWindowListener) list[i];
350       Platform.run(new SafeRunnable() {
351         public void run() {
352           l.windowClosed(window);
353         }
354       });
355     }
356   }
357   /**
358    * Fire window activated event.
359    * 
360    * @param window
361    *            The window which was just activated; should not be <code>null</code>.
362    */
363   protected void fireWindowActivated(final IWorkbenchWindow window) {
364     Object list[] = windowListeners.getListeners();
365     for (int i = 0; i < list.length; i++) {
366       final IWindowListener l = (IWindowListener) list[i];
367       Platform.run(new SafeRunnable() {
368         public void run() {
369           l.windowActivated(window);
370         }
371       });
372     }
373   }
374   /**
375    * Fire window deactivated event.
376    * 
377    * @param window
378    *            The window which was just deactivated; should not be <code>null</code>.
379    */
380   protected void fireWindowDeactivated(final IWorkbenchWindow window) {
381     Object list[] = windowListeners.getListeners();
382     for (int i = 0; i < list.length; i++) {
383       final IWindowListener l = (IWindowListener) list[i];
384       Platform.run(new SafeRunnable() {
385         public void run() {
386           l.windowDeactivated(window);
387         }
388       });
389     }
390   }
391 
392   /**
393    * Closes the workbench. Assumes that the busy cursor is active.
394    * 
395    * @param force
396    *            true if the close is mandatory, and false if the close is
397    *            allowed to fail
398    * @return true if the close succeeded, and false otherwise
399    */
400   private boolean busyClose(final boolean force) {
401 
402       // notify the advisor of preShutdown and allow it to veto if not forced
403       isClosing = advisor.preShutdown();
404     if (!force && !isClosing) {
405       return false;
406     }
407       
408     // save any open editors if they are dirty
409     isClosing = saveAllEditors(!force);
410     if (!force && !isClosing) {
411       return false;
412     }
413 
414     IPreferenceStore store = getPreferenceStore();
415     boolean closeEditors = store.getBoolean(IPreferenceConstants.CLOSE_EDITORS_ON_EXIT);
416     if (closeEditors) {
417       Platform.run(new SafeRunnable() {
418         public void run() {
419           IWorkbenchWindow windows[] = getWorkbenchWindows();
420           for (int i = 0; i < windows.length; i++) {
421             IWorkbenchPage pages[] = windows[i].getPages();
422             for (int j = 0; j < pages.length; j++) {
423               isClosing = isClosing && pages[j].closeAllEditors(false);
424             }
425           }
426         }
427       });
428       if (!force && !isClosing) {
429         return false;
430       }
431     }
432 
433     if (getWorkbenchConfigurer().getSaveAndRestore()) {
434       Platform.run(new SafeRunnable() {
435         public void run() {
436           XMLMemento mem = recordWorkbenchState();
437           //Save the IMemento to a file.
438           saveMementoToFile(mem);
439         }
440         public void handleException(Throwable e) {
441           String message;
442           if (e.getMessage() == null) {
443             message = WorkbenchMessages.getString("ErrorClosingNoArg"); //$NON-NLS-1$
444           } else {
445             message = WorkbenchMessages.format("ErrorClosingOneArg", new Object[] { e.getMessage()}); //$NON-NLS-1$
446           }
447 
448           if (!MessageDialog.openQuestion(null, WorkbenchMessages.getString("Error"), message)) { //$NON-NLS-1$
449             isClosing = false;
450           }
451         }
452       });
453     }
454     if (!force && !isClosing) {
455       return false;
456     }
457 
458     Platform.run(new SafeRunnable(WorkbenchMessages.getString("ErrorClosing")) { //$NON-NLS-1$
459       public void run() {
460         if (isClosing || force)
461           isClosing = windowManager.close();
462       }
463     });
464 
465     if (!force && !isClosing) {
466       return false;
467     }
468 
469     shutdown();
470     
471     runEventLoop = false;
472     return true;
473   }
474 
475   /*
476    * (non-Javadoc) Method declared on IWorkbench.
477    */
478   public boolean saveAllEditors(boolean confirm) {
479     final boolean finalConfirm = confirm;
480     final boolean[] result = new boolean[1];
481     result[0] = true;
482 
483     Platform.run(new SafeRunnable(WorkbenchMessages.getString("ErrorClosing")) { //$NON-NLS-1$
484       public void run() {
485         //Collect dirtyEditors
486         ArrayList dirtyEditors = new ArrayList();
487         ArrayList dirtyEditorsInput = new ArrayList();
488         IWorkbenchWindow windows[] = getWorkbenchWindows();
489         for (int i = 0; i < windows.length; i++) {
490           IWorkbenchPage pages[] = windows[i].getPages();
491           for (int j = 0; j < pages.length; j++) {
492             WorkbenchPage page = (WorkbenchPage) pages[j];
493             IEditorPart editors[] = page.getDirtyEditors();
494             for (int k = 0; k < editors.length; k++) {
495               IEditorPart editor = editors[k];
496               if (editor.isDirty()) {
497                 if (!dirtyEditorsInput.contains(editor.getEditorInput())) {
498                   dirtyEditors.add(editor);
499                   dirtyEditorsInput.add(editor.getEditorInput());
500                 }
501               }
502             }
503           }
504         }
505         if (dirtyEditors.size() > 0) {
506           IWorkbenchWindow w = getActiveWorkbenchWindow();
507           if (w == null)
508             w = windows[0];
509           result[0] = EditorManager.saveAll(dirtyEditors, finalConfirm, w);
510         }
511       }
512     });
513     return result[0];
514   }
515 
516   /**
517    * Opens a new workbench window and page with a specific perspective.
518    * 
519    * Assumes that busy cursor is active.
520    */
521   private IWorkbenchWindow busyOpenWorkbenchWindow(String perspID, IAdaptable input)
522     throws WorkbenchException {
523     // Create a workbench window (becomes active window)
524     WorkbenchWindow newWindow = newWorkbenchWindow();
525     newWindow.create(); // must be created before adding to window manager
526     windowManager.add(newWindow);
527 
528     // Create the initial page.
529     try {
530       newWindow.busyOpenPage(perspID, input);
531     } catch (WorkbenchException e) {
532       windowManager.remove(newWindow);
533       throw e;
534     }
535     
536     // Open window after opening page, to avoid flicker.
537     newWindow.open();
538 
539     return newWindow;
540   }
541 
542   /*
543    * (non-Javadoc) Method declared on IWorkbench.
544    */
545   public boolean close() {
546     return close(PlatformUI.RETURN_OK, false);
547   }
548   /**
549    * Closes the workbench, returning the given return code from the run
550    * method. If forced, the workbench is closed no matter what.
551    * 
552    * @param returnCode
553    *            {@link PlatformUI#RETURN_OK RETURN_OK}for normal exit;
554    *            {@link PlatformUI#RETURN_RESTART RETURN_RESTART}if the
555    *            workbench was terminated with a call to
556    *            {@link IWorkbench#restart IWorkbench.restart};
557    *            {@link PlatformUI#RETURN_UNSTARTABLE RETURN_UNSTARTABLE}if
558    *            the workbench could not be started; other values reserved for
559    *            future use
560    * @param force
561    *            true to force the workbench close, and false for a "soft"
562    *            close that can be canceled
563    * @return true if the close was successful, and false if the close was
564    *         canceled
565    */
566   /* package */
567   boolean close(int returnCode, final boolean force) {
568     this.returnCode = returnCode;
569     final boolean[] ret = new boolean[1];
570     BusyIndicator.showWhile(null, new Runnable() {
571       public void run() {
572         ret[0] = busyClose(force);
573       }
574     });
575     return ret[0];
576   }
577 
578   /*
579    * (non-Javadoc) Method declared on IWorkbench.
580    */
581   public IWorkbenchWindow getActiveWorkbenchWindow() {
582       // Return null if called from a non-UI thread.
583       // This is not spec'ed behaviour and is misleading, however this is how it
584       // worked in 2.1 and we cannot change it now.
585       // For more details, see [Bug 57384] [RCP] Main window not active on startup
586       if (Display.getCurrent() == null) {
587           return null;
588       }
589       
590     // Look at the current shell and up its parent
591     // hierarchy for a workbench window.
592     Control shell = display.getActiveShell();
593     while (shell != null) {
594       Object data = shell.getData();
595       if (data instanceof IWorkbenchWindow)
596         return (IWorkbenchWindow) data;
597       shell = shell.getParent();
598     }
599 
600     // Look for the window that was last known being
601     // the active one
602     WorkbenchWindow win = getActivatedWindow();
603     if (win != null) {
604       return win;
605     }
606 
607     // Look at all the shells and pick the first one
608     // that is a workbench window.
609     Shell shells[] = display.getShells();
610     for (int i = 0; i < shells.length; i++) {
611       Object data = shells[i].getData();
612       if (data instanceof IWorkbenchWindow)
613         return (IWorkbenchWindow) data;
614     }
615 
616     // Can't find anything!
617     return null;
618   }
619 
620   /*
621    * Returns the editor history.
622    */
623   protected EditorHistory getEditorHistory() {
624     if (editorHistory == null) {
625       editorHistory = new EditorHistory();
626     }
627     return editorHistory;
628   }
629   /*
630    * (non-Javadoc) Method declared on IWorkbench.
631    */
632   public IEditorRegistry getEditorRegistry() {
633     return WorkbenchPlugin.getDefault().getEditorRegistry();
634   }
635 
636   /*
637    * Returns the number for a new window. This will be the first number > 0
638    * which is not used to identify another window in the workbench.
639    */
640   private int getNewWindowNumber() {
641     // Get window list.
642     Window[] windows = windowManager.getWindows();
643     int count = windows.length;
644 
645     // Create an array of booleans (size = window count).
646     // Cross off every number found in the window list.
647     boolean checkArray[] = new boolean[count];
648     for (int nX = 0; nX < count; nX++) {
649       if (windows[nX] instanceof WorkbenchWindow) {
650         WorkbenchWindow ww = (WorkbenchWindow) windows[nX];
651         int index = ww.getNumber() - 1;
652         if (index >= 0 && index < count)
653           checkArray[index] = true;
654       }
655     }
656 
657     // Return first index which is not used.
658     // If no empty index was found then every slot is full.
659     // Return next index.
660     for (int index = 0; index < count; index++) {
661       if (!checkArray[index])
662         return index + 1;
663     }
664     return count + 1;
665   }
666 
667   /*
668    * (non-Javadoc) Method declared on IWorkbench.
669    */
670   public IPerspectiveRegistry getPerspectiveRegistry() {
671     return WorkbenchPlugin.getDefault().getPerspectiveRegistry();
672   }
673 
674   /*
675    * (non-Javadoc) Method declared on IWorkbench.
676    */
677   public PreferenceManager getPreferenceManager() {
678     return WorkbenchPlugin.getDefault().getPreferenceManager();
679   }
680   /*
681    * (non-Javadoc) Method declared on IWorkbench.
682    */
683   public IPreferenceStore getPreferenceStore() {
684     return WorkbenchPlugin.getDefault().getPreferenceStore();
685   }
686 
687   /*
688    * (non-Javadoc) Method declared on IWorkbench.
689    */
690   public ISharedImages getSharedImages() {
691     return WorkbenchPlugin.getDefault().getSharedImages();
692   }
693   /**
694    * Returns the window manager for this workbench.
695    * 
696    * @return the window manager
697    */
698   /* package */
699   WindowManager getWindowManager() {
700     return windowManager;
701   }
702 
703   /*
704    * Answer the workbench state file.
705    */
706   private File getWorkbenchStateFile() {
707     IPath path = WorkbenchPlugin.getDefault().getStateLocation();
708     path = path.append(DEFAULT_WORKBENCH_STATE_FILENAME);
709     return path.toFile();
710   }
711 
712   /*
713    * (non-Javadoc) Method declared on IWorkbench.
714    */
715   public int getWorkbenchWindowCount() {
716     return windowManager.getWindowCount();
717   }
718 
719   /*
720    * (non-Javadoc) Method declared on IWorkbench.
721    */
722   public IWorkbenchWindow[] getWorkbenchWindows() {
723     Window[] windows = windowManager.getWindows();
724     IWorkbenchWindow[] dwindows = new IWorkbenchWindow[windows.length];
725     System.arraycopy(windows, 0, dwindows, 0, windows.length);
726     return dwindows;
727   }
728 
729   /*
730    * (non-Javadoc) Method declared on IWorkbench.
731    */
732   public IWorkingSetManager getWorkingSetManager() {
733     return WorkbenchPlugin.getDefault().getWorkingSetManager();
734   }
735 
736   /**
737    * Initializes the workbench now that the display is created.
738    * 
739    * @return true if init succeeded.
740    */
741   private boolean init(Display display) {
742     // setup debug mode if required.
743     if (WorkbenchPlugin.getDefault().isDebugging()) {
744       WorkbenchPlugin.DEBUG = true;
745       ModalContext.setDebugMode(true);
746     }
747 
748     // create workbench window manager
749     windowManager = new WindowManager();
750 
751     IIntroRegistry introRegistry = WorkbenchPlugin.getDefault().getIntroRegistry();
752     if (introRegistry.getIntroCount() > 0) {
753         IProduct product = Platform.getProduct();
754         if (product != null) {            
755           introDescriptor = (IntroDescriptor) introRegistry.getIntroForProduct(product.getId());
756       }
757     }    
758     
759         // begin the initialization of the activity, command, and context
760         // managers
761 
762     workbenchActivitySupport = new WorkbenchActivitySupport();
763     activityHelper = ActivityPersistanceHelper.getInstance();
764 
765         workbenchContextSupport = new WorkbenchContextSupport(this);
766         workbenchCommandSupport = new WorkbenchCommandSupport(this);
767         workbenchContextSupport.initialize(); // deferred key binding support
768 
769         workbenchCommandSupport.getCommandManager().addCommandManagerListener(
770                 commandManagerListener);
771 
772         workbenchContextSupport.getContextManager().addContextManagerListener(
773                 contextManagerListener);
774 
775         initializeCommandResolver();
776 
777         addWindowListener(windowListener);
778         
779         // end the initialization of the activity, command, and context
780         // managers
781 
782     initializeImages();
783     initializeFonts();
784     initializeColors();
785     initializeApplicationColors();
786 
787     // now that the workbench is sufficiently initialized, let the advisor
788     // have a turn.
789     advisor.internalBasicInitialize(getWorkbenchConfigurer());
790 
791     // configure use of color icons in toolbars
792     boolean useColorIcons = getPreferenceStore().getBoolean(IPreferenceConstants.COLOR_ICONS);
793     ActionContributionItem.setUseColorIconsInToolbars(useColorIcons);
794 
795     // initialize workbench single-click vs double-click behavior
796     initializeSingleClickOption();
797 
798     // deadlock code
799     boolean avoidDeadlock = true;
800 
801     String[] commandLineArgs = Platform.getCommandLineArgs();
802     for (int i = 0; i < commandLineArgs.length; i++) {
803       if (commandLineArgs[i].equalsIgnoreCase("-allowDeadlock")) //$NON-NLS-1$
804         avoidDeadlock = false;
805     }
806 
807     if (avoidDeadlock) {
808       UILockListener uiLockListener = new UILockListener(display);
809       Platform.getJobManager().setLockListener(uiLockListener);
810       display.setSynchronizer(new UISynchronizer(display, uiLockListener));
811     }
812 
813     // attempt to restore a previous workbench state
814     try {
815       UIStats.start(UIStats.RESTORE_WORKBENCH, "Workbench"); //$NON-NLS-1$
816 
817       advisor.preStartup();
818 
819       if (!advisor.openWindows()) {
820           return false;
821       }
822       
823     } finally {
824       UIStats.end(UIStats.RESTORE_WORKBENCH, "Workbench"); //$NON-NLS-1$
825     }
826 
827     forceOpenPerspective();
828 
829     isStarting = false;
830         
831     return true;
832   }
833 
834   
835   /**
836    * Establishes the relationship between JFace actions and the command manager.
837    */
838   private void initializeCommandResolver() {
839         ExternalActionManager.getInstance().setCallback(new CommandCallback(this));
840     }
841 
842     /**
843    * Initialize colors defined by the new colorDefinitions extension point.
844    * Note this will be rolled into initializeColors() at some point.
845    * 
846    * @since 3.0
847    */
848   private void initializeApplicationColors() {
849     ColorDefinition[] colorDefinitions = WorkbenchPlugin.getDefault().getThemeRegistry().getColors();
850     ThemeElementHelper.populateRegistry(getThemeManager().getTheme(IThemeManager.DEFAULT_THEME), colorDefinitions, getPreferenceStore());
851   }
852 
853   private void initializeSingleClickOption() {
854     IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();
855     boolean openOnSingleClick = store.getBoolean(IPreferenceConstants.OPEN_ON_SINGLE_CLICK);
856     boolean selectOnHover = store.getBoolean(IPreferenceConstants.SELECT_ON_HOVER);
857     boolean openAfterDelay = store.getBoolean(IPreferenceConstants.OPEN_AFTER_DELAY);
858     int singleClickMethod =
859       openOnSingleClick ? OpenStrategy.SINGLE_CLICK : OpenStrategy.DOUBLE_CLICK;
860     if (openOnSingleClick) {
861       if (selectOnHover)
862         singleClickMethod |= OpenStrategy.SELECT_ON_HOVER;
863       if (openAfterDelay)
864         singleClickMethod |= OpenStrategy.ARROW_KEYS_OPEN;
865     }
866     OpenStrategy.setOpenMethod(singleClickMethod);
867   }
868 
869   /*
870    * Initializes the workbench fonts with the stored values. 
871    */
872   private void initializeFonts() {
873       FontDefinition[] fontDefinitions = WorkbenchPlugin.getDefault().getThemeRegistry().getFonts();
874     ThemeElementHelper.populateRegistry(getThemeManager().getTheme(IThemeManager.DEFAULT_THEME), fontDefinitions, getPreferenceStore());
875   }
876 
877   /*
878    * Initialize the workbench images.
879    *
880    * @param windowImages
881    *            An array of the descriptors of the images to be used in the
882    *            corner of each window, or <code>null</code> if none. It is
883    *            expected that the array will contain the same icon, rendered
884    *            at different sizes.
885    * @since 3.0
886    */
887   private void initializeImages() {
888       ImageDescriptor[] windowImages = WorkbenchPlugin.getDefault().getWindowImages(); 
889     if(windowImages == null)
890       return;
891 
892     Image[] images = new Image[windowImages.length];
893     for(int i = 0; i < windowImages.length; ++i)
894       images[i] = windowImages[i].createImage();
895     Window.setDefaultImages(images);
896   }
897 
898   /*
899    * Take the workbenches' images out of the shared registry.
900    * 
901    * @since 3.0
902    */
903   private void uninitializeImages() {
904     Window.setDefaultImage(null);
905   }
906 
907   /*
908    * Initialize the workbench colors.
909    * 
910    * @since 3.0
911    */
912   private void initializeColors() {
913     // @issue some colors are generic; some are app-specific
914     WorkbenchColors.startup();
915   }
916 
917   /**
918    * Returns <code>true</code> if the workbench is in the process of
919    * closing.
920    */
921   public boolean isClosing() {
922     return isClosing;
923   }
924 
925   /*
926    * Returns true if the workbench is in the process of starting
927    */
928   /* package */
929   boolean isStarting() {
930     return isStarting;
931   }
932 
933   /*
934    * Creates a new workbench window.
935    * 
936    * @return the new workbench window
937    */
938   private WorkbenchWindow newWorkbenchWindow() {
939     return new WorkbenchWindow(getNewWindowNumber());
940   }
941 
942   /*
943    * If a perspective was specified on the command line (-perspective) then
944    * force that perspective to open in the active window.
945    */
946   private void forceOpenPerspective() {
947     if (getWorkbenchWindowCount() == 0) {
948       // there should be an open window by now, bail out.
949       return;
950     }
951 
952     String perspId = null;
953     String[] commandLineArgs = Platform.getCommandLineArgs();
954     for (int i = 0; i < commandLineArgs.length - 1; i++) {
955       if (commandLineArgs[i].equalsIgnoreCase("-perspective")) { //$NON-NLS-1$
956         perspId = commandLineArgs[i + 1];
957         break;
958       }
959     }
960     if (perspId == null) {
961       return;
962     }
963     IPerspectiveDescriptor desc = getPerspectiveRegistry().findPerspectiveWithId(perspId);
964     if (desc == null) {
965       return;
966     }
967 
968     IWorkbenchWindow win = getActiveWorkbenchWindow();
969     if (win == null) {
970       win = getWorkbenchWindows()[0];
971     }
972     try {
973       showPerspective(perspId, win);
974     } catch (WorkbenchException e) {
975       String msg = "Workbench exception showing specified command line perspective on startup."; //$NON-NLS-1$
976       WorkbenchPlugin.log(msg, new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, msg, e));
977     }
978   }
979 
980   /*
981    * opens the initial workbench window.
982    */
983   /* package */ void openFirstTimeWindow() {
984 
985     // create the workbench window
986     WorkbenchWindow newWindow = newWorkbenchWindow();
987     newWindow.create();
988     windowManager.add(newWindow);
989 
990     // Create the initial page.
991     try {
992       newWindow.openPage(
993         getPerspectiveRegistry().getDefaultPerspective(),
994         getDefaultPageInput());
995     } catch (WorkbenchException e) {
996       ErrorDialog.openError(newWindow.getShell(), WorkbenchMessages.getString("Problems_Opening_Page"), //$NON-NLS-1$
997       e.getMessage(), e.getStatus());
998     }
999     newWindow.open();
1000  }
1001
1002  /*
1003   * Restores the workbench UI from the workbench state file (workbench.xml).
1004   * 
1005   * @return a status object indicating OK if a window was opened, RESTORE_CODE_RESET if no
1006   *   window was opened but one should be, and RESTORE_CODE_EXIT if the
1007   *   workbench should close immediately
1008   */
1009  /* package */ IStatus restoreState() {
1010
1011    if (!getWorkbenchConfigurer().getSaveAndRestore()) {
1012      String msg = WorkbenchMessages
1013                    .getString("Workbench.restoreDisabled"); //$NON-NLS-1$
1014            return new Status(IStatus.WARNING, WorkbenchPlugin.PI_WORKBENCH,
1015                    IWorkbenchConfigurer.RESTORE_CODE_RESET, msg, null);
1016    }
1017    // Read the workbench state file.
1018    final File stateFile = getWorkbenchStateFile();
1019    // If there is no state file cause one to open.
1020    if (!stateFile.exists()) {
1021        String msg = WorkbenchMessages
1022                    .getString("Workbench.noStateToRestore"); //$NON-NLS-1$
1023            return new Status(IStatus.WARNING, WorkbenchPlugin.PI_WORKBENCH,
1024                    IWorkbenchConfigurer.RESTORE_CODE_RESET, msg, null); //$NON-NLS-1$
1025    }
1026
1027    final IStatus result[] = { new Status(IStatus.OK,
1028                WorkbenchPlugin.PI_WORKBENCH, IStatus.OK, "", null)}; //$NON-NLS-1$
1029    Platform.run(new SafeRunnable(WorkbenchMessages
1030                .getString("ErrorReadingState")) { //$NON-NLS-1$
1031      public void run() throws Exception {
1032        FileInputStream input = new FileInputStream(stateFile);
1033        BufferedReader reader = new BufferedReader(
1034                                new InputStreamReader(input, "utf-8")); //$NON-NLS-1$
1035        IMemento memento = XMLMemento.createReadRoot(reader);
1036
1037        // Validate known version format
1038        String version = memento.getString(IWorkbenchConstants.TAG_VERSION);
1039        boolean valid = false;
1040        for (int i = 0; i < VERSION_STRING.length; i++) {
1041          if (VERSION_STRING[i].equals(version)) {
1042            valid = true;
1043            break;
1044          }
1045        }
1046        if (!valid) {
1047          reader.close();
1048          String msg = WorkbenchMessages.getString("Invalid_workbench_state_ve");  //$NON-NLS-1$
1049          MessageDialog.openError((Shell) null,
1050                                    WorkbenchMessages
1051                                            .getString("Restoring_Problems"), //$NON-NLS-1$
1052                                    msg); //$NON-NLS-1$
1053          stateFile.delete();
1054          result[0] = new Status(IStatus.ERROR,
1055                                    WorkbenchPlugin.PI_WORKBENCH,
1056                                    IWorkbenchConfigurer.RESTORE_CODE_RESET,
1057                                    msg, null);
1058          return;
1059        }
1060
1061        // Validate compatible version format
1062        // We no longer support the release 1.0 format
1063        if (VERSION_STRING[0].equals(version)) {
1064          reader.close();
1065          String msg = WorkbenchMessages
1066                                    .getString("Workbench.incompatibleSavedStateVersion"); //$NON-NLS-1$
1067                    boolean ignoreSavedState = new MessageDialog(
1068                                    null,
1069                                    WorkbenchMessages
1070                                            .getString("Workbench.incompatibleUIState"),//$NON-NLS-1$
1071                                    null,
1072                                    msg,
1073                                    MessageDialog.WARNING, new String[] {
1074                                            IDialogConstants.OK_LABEL,
1075                                            IDialogConstants.CANCEL_LABEL}, 0)
1076                                    .open() == 0;
1077          // OK is the default
1078          if (ignoreSavedState) {
1079            stateFile.delete();
1080            result[0] = new Status(
1081                                        IStatus.WARNING,
1082                                        WorkbenchPlugin.PI_WORKBENCH,
1083                                        IWorkbenchConfigurer.RESTORE_CODE_RESET,
1084                                        msg, null);
1085          } else {
1086            result[0] = new Status(
1087                                IStatus.WARNING,
1088                                WorkbenchPlugin.PI_WORKBENCH,
1089                                IWorkbenchConfigurer.RESTORE_CODE_EXIT,
1090                                msg, null);
1091          }
1092          return;
1093        }
1094
1095        // Restore the saved state
1096        IStatus restoreResult = restoreState(memento);
1097        reader.close();
1098        if (restoreResult.getSeverity() == IStatus.ERROR) {
1099          ErrorDialog.openError(null, WorkbenchMessages.getString("Workspace.problemsTitle"), //$NON-NLS-1$
1100          WorkbenchMessages.getString("Workbench.problemsRestoringMsg"), //$NON-NLS-1$
1101          restoreResult);
1102        }
1103      }
1104      public void handleException(Throwable e) {
1105        super.handleException(e);
1106        String msg = e.getMessage() == null ? "" : e.getMessage(); //$NON-NLS-1$
1107        result[0] = new Status(
1108                        IStatus.ERROR,
1109                        WorkbenchPlugin.PI_WORKBENCH,
1110                        IWorkbenchConfigurer.RESTORE_CODE_RESET,
1111                        msg, e);
1112        stateFile.delete();
1113      }
1114
1115    });
1116    // ensure at least one window was opened
1117    if (result[0].isOK() && windowManager.getWindows().length == 0) {
1118        String msg = WorkbenchMessages.getString("Workbench.noWindowsRestored"); //$NON-NLS-1$
1119      result[0] = new Status(
1120                    IStatus.ERROR,
1121                    WorkbenchPlugin.PI_WORKBENCH,
1122                    IWorkbenchConfigurer.RESTORE_CODE_RESET,
1123                    msg, null);
1124    }
1125    return result[0];
1126  }
1127
1128  /*
1129   * (non-Javadoc) Method declared on IWorkbench.
1130   */
1131  public IWorkbenchWindow openWorkbenchWindow(IAdaptable input) throws WorkbenchException {
1132    return openWorkbenchWindow(getPerspectiveRegistry().getDefaultPerspective(), input);
1133  }
1134
1135  /*
1136   * (non-Javadoc) Method declared on IWorkbench.
1137   */
1138  public IWorkbenchWindow openWorkbenchWindow(final String perspID, final IAdaptable input)
1139    throws WorkbenchException {
1140    // Run op in busy cursor.
1141    final Object[] result = new Object[1];
1142    BusyIndicator.showWhile(null, new Runnable() {
1143      public void run() {
1144        try {
1145          result[0] = busyOpenWorkbenchWindow(perspID, input);
1146        } catch (WorkbenchException e) {
1147          result[0] = e;
1148        }
1149      }
1150    });
1151    if (result[0] instanceof IWorkbenchWindow) {
1152      return (IWorkbenchWindow) result[0];
1153    } else if (result[0] instanceof WorkbenchException) {
1154      throw (WorkbenchException) result[0];
1155    } else {
1156      throw new WorkbenchException(WorkbenchMessages.getString("Abnormal_Workbench_Conditi")); //$NON-NLS-1$
1157    }
1158  }
1159
1160  /*
1161   * Record the workbench UI in a document
1162   */
1163  private XMLMemento recordWorkbenchState() {
1164    XMLMemento memento = XMLMemento.createWriteRoot(IWorkbenchConstants.TAG_WORKBENCH);
1165    IStatus status = saveState(memento);
1166    if (status.getSeverity() != IStatus.OK) {
1167      ErrorDialog.openError((Shell) null, WorkbenchMessages.getString("Workbench.problemsSaving"), //$NON-NLS-1$
1168      WorkbenchMessages.getString("Workbench.problemsSavingMsg"), //$NON-NLS-1$
1169      status);
1170    }
1171    return memento;
1172  }
1173
1174  /*
1175   * (non-Javadoc) Method declared on IWorkbench.
1176   */
1177  public boolean restart() {
1178    // this is the return code from run() to trigger a restart
1179    return close(PlatformUI.RETURN_RESTART, false);
1180  }
1181
1182  /*
1183   * Restores the state of the previously saved workbench
1184   */
1185  private IStatus restoreState(IMemento memento) {
1186
1187    MultiStatus result = new MultiStatus(PlatformUI.PLUGIN_ID, IStatus.OK, WorkbenchMessages.getString("Workbench.problemsRestoring"), null); //$NON-NLS-1$
1188    IMemento childMem;
1189    try {
1190      UIStats.start(UIStats.RESTORE_WORKBENCH, "MRUList"); //$NON-NLS-1$
1191      IMemento mruMemento = memento.getChild(IWorkbenchConstants.TAG_MRU_LIST); //$NON-NLS-1$
1192      if (mruMemento != null) {
1193        result.add(getEditorHistory().restoreState(mruMemento));
1194      }
1195    } finally {
1196      UIStats.end(UIStats.RESTORE_WORKBENCH, "MRUList"); //$NON-NLS-1$
1197    }
1198    // Get the child windows.
1199    IMemento[] children = memento.getChildren(IWorkbenchConstants.TAG_WINDOW);
1200
1201    // Read the workbench windows.
1202    for (int x = 0; x < children.length; x++) {
1203      childMem = children[x];
1204      WorkbenchWindow newWindow = newWorkbenchWindow();
1205      newWindow.create();
1206
1207      // allow the application to specify an initial perspective to open
1208      // @issue temporary workaround for ignoring initial perspective
1209      //      String initialPerspectiveId =
1210      // getAdvisor().getInitialWindowPerspectiveId();
1211      //      if (initialPerspectiveId != null) {
1212      //        IPerspectiveDescriptor desc =
1213      // getPerspectiveRegistry().findPerspectiveWithId(initialPerspectiveId);
1214      //        result.merge(newWindow.restoreState(childMem, desc));
1215      //      }
1216      // add the window so that any work done in newWindow.restoreState that relies on Workbench methods has windows to work with            
1217      windowManager.add(newWindow);
1218      // whether the window was opened
1219      boolean opened = false;
1220      // now that we've added it to the window manager we need to listen 
1221      // for any exception that might hose us before we get a chance to
1222      // open it.  If one occurs, remove the new window from the manager.
1223      try {
1224        result.merge(newWindow.restoreState(childMem, null));
1225        try {
1226          getAdvisor().postWindowRestore(newWindow.getWindowConfigurer());
1227        } catch (WorkbenchException e) {
1228          result.add(e.getStatus());
1229        }
1230        newWindow.open();
1231        opened = true;
1232      }
1233      finally {
1234        if (!opened)
1235          newWindow.close();
1236      }
1237    }
1238    return result;
1239  }
1240
1241  /**
1242   * Returns an array with the ids of all plugins that extend the
1243   * <code>org.eclipse.ui.startup</code> extension point.
1244   */
1245  public String[] getEarlyActivatedPlugins() {
1246    IExtensionPoint point = Platform.getExtensionRegistry()
1247        .getExtensionPoint(PlatformUI.PLUGIN_ID,
1248            IWorkbenchConstants.PL_STARTUP);
1249    IExtension[] extensions = point.getExtensions();
1250    String[] result = new String[extensions.length];
1251    for (int i = 0; i < extensions.length; i++) {
1252      result[i] = extensions[i].getNamespace();
1253    }
1254    return result;
1255  }
1256
1257  /*
1258   * Starts all plugins that extend the <code> org.eclipse.ui.startup </code>
1259   * extension point, and that the user has not disabled via the preference
1260   * page.
1261   */
1262  private void startPlugins() {
1263    Runnable work = new Runnable() {
1264      final String disabledPlugins = getPreferenceStore()
1265          .getString(IPreferenceConstants.PLUGINS_NOT_ACTIVATED_ON_STARTUP);
1266
1267      public void run() {
1268        IExtensionRegistry registry = Platform.getExtensionRegistry();
1269
1270        // bug 55901: don't use getConfigElements directly, for pre-3.0
1271        //            compat, make sure to allow both missing class
1272        //            attribute and a missing startup element
1273        IExtensionPoint point = registry.getExtensionPoint(
1274            PlatformUI.PLUGIN_ID, IWorkbenchConstants.PL_STARTUP);
1275
1276        IExtension[] extensions = point.getExtensions();
1277        for (int i = 0; i < extensions.length; ++i) {
1278          IExtension extension = extensions[i];
1279
1280          // if the plugin is not in the set of disabled plugins, then
1281          // execute the code to start it
1282          if (disabledPlugins.indexOf(extension.getNamespace()) == -1)
1283            Platform.run(new EarlyStartupRunnable(extension));
1284        }
1285      }
1286    };
1287
1288    Thread thread = new Thread(work);
1289    thread.start();
1290  }
1291
1292  /**
1293   * Internal method for running the workbench UI. This entails processing
1294   * and dispatching events until the workbench is closed or restarted.
1295   * 
1296   * @return return code {@link PlatformUI#RETURN_OK RETURN_OK}for normal
1297   *         exit; {@link PlatformUI#RETURN_RESTART RETURN_RESTART}if the
1298   *         workbench was terminated with a call to
1299   *         {@link IWorkbench#restart IWorkbench.restart};
1300   *         {@link PlatformUI#RETURN_UNSTARTABLE RETURN_UNSTARTABLE}if the
1301   *         workbench could not be started; other values reserved for future
1302   *         use
1303   * @since 3.0
1304   */
1305  private int runUI() {
1306    UIStats.start(UIStats.START_WORKBENCH, "Workbench"); //$NON-NLS-1$
1307
1308    Listener closeListener = new Listener() {
1309      public void handleEvent(Event event) {
1310        event.doit = close();
1311      }
1312    };
1313    
1314    // Initialize an exception handler.
1315    Window.IExceptionHandler handler = ExceptionHandler.getInstance();
1316
1317    try {
1318      // react to display close event by closing workbench nicely
1319      display.addListener(SWT.Close, closeListener);
1320
1321      // install backstop to catch exceptions thrown out of event loop
1322      Window.setExceptionHandler(handler);
1323
1324      // initialize workbench and restore or open one window
1325      boolean initOK = init(display);
1326
1327      // drop the splash screen now that a workbench window is up
1328      Platform.endSplash();
1329
1330      // let the advisor run its start up code
1331      if (initOK) {
1332        advisor.postStartup(); // may trigger a close/restart
1333      }
1334
1335      if (initOK && runEventLoop) {
1336        // start eager plug-ins
1337        startPlugins();
1338
1339        display.asyncExec(new Runnable() {
1340          public void run() {
1341            UIStats.end(UIStats.START_WORKBENCH, "Workbench"); //$NON-NLS-1$
1342          }
1343        });
1344
1345        getWorkbenchTestable().init(display, this);
1346
1347        // the event loop
1348        runEventLoop(handler, display);
1349      }
1350      
1351    } catch (final Exception e) {
1352        if (!display.isDisposed()) {
1353            handler.handleException(e);
1354        }
1355        else {
1356            String msg = "Exception in Workbench.runUI after display was disposed"; //$NON-NLS-1$
1357            WorkbenchPlugin.log(msg, new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH, 1, msg, e));
1358        }
1359    } finally {
1360      // mandatory clean up
1361      if (!display.isDisposed()) {
1362        display.removeListener(SWT.Close, closeListener);
1363      }
1364    }
1365
1366    // restart or exit based on returnCode
1367    return returnCode;
1368  }
1369
1370  /*
1371   * Runs an event loop for the workbench.
1372   */
1373  private void runEventLoop(Window.IExceptionHandler handler, Display display) {
1374    runEventLoop = true;
1375    while (runEventLoop) {
1376      try {
1377        if (!display.readAndDispatch()) {
1378          getAdvisor().eventLoopIdle(display);
1379        }
1380      } catch (Throwable t) {
1381        handler.handleException(t);
1382      }
1383    }
1384  }
1385
1386  /*
1387   * Saves the current state of the workbench so it can be restored later on
1388   */
1389  private IStatus saveState(IMemento memento) {
1390    MultiStatus result = new MultiStatus(PlatformUI.PLUGIN_ID, IStatus.OK, WorkbenchMessages.getString("Workbench.problemsSaving"), null); //$NON-NLS-1$
1391
1392    // Save the version number.
1393    memento.putString(IWorkbenchConstants.TAG_VERSION, VERSION_STRING[1]);
1394
1395    // Save the workbench windows.
1396    IWorkbenchWindow[] windows = getWorkbenchWindows();
1397    for (int nX = 0; nX < windows.length; nX++) {
1398      WorkbenchWindow window = (WorkbenchWindow) windows[nX];
1399      IMemento childMem = memento.createChild(IWorkbenchConstants.TAG_WINDOW);
1400      result.merge(window.saveState(childMem));
1401    }
1402    result.add(getEditorHistory().saveState(memento.createChild(IWorkbenchConstants.TAG_MRU_LIST))); //$NON-NLS-1$
1403    return result;
1404  }
1405
1406  /*
1407   * Save the workbench UI in a persistence file.
1408   */
1409  private boolean saveMementoToFile(XMLMemento memento) {
1410    // Save it to a file.
1411    File stateFile = getWorkbenchStateFile();
1412    try {
1413      FileOutputStream stream = new FileOutputStream(stateFile);
1414      OutputStreamWriter writer = new OutputStreamWriter(stream, "utf-8"); //$NON-NLS-1$
1415      memento.save(writer);
1416      writer.close();
1417    } catch (IOException e) {
1418      stateFile.delete();
1419      MessageDialog.openError((Shell) null, WorkbenchMessages.getString("SavingProblem"), //$NON-NLS-1$
1420      WorkbenchMessages.getString("ProblemSavingState")); //$NON-NLS-1$
1421      return false;
1422    }
1423
1424    // Success !
1425    return true;
1426  }
1427
1428  /*
1429   * (non-Javadoc) Method declared on IWorkbench.
1430   */
1431  public IWorkbenchPage showPerspective(String perspectiveId, IWorkbenchWindow window)
1432    throws WorkbenchException {
1433    Assert.isNotNull(perspectiveId);
1434
1435    // If the specified window has the requested perspective open, then the
1436    // window
1437    // is given focus and the perspective is shown. The page's input is
1438    // ignored.
1439    WorkbenchWindow win = (WorkbenchWindow) window;
1440    if (win != null) {
1441      WorkbenchPage page = win.getActiveWorkbenchPage();
1442      if (page != null) {
1443        IPerspectiveDescriptor perspectives[] = page.getOpenedPerspectives();
1444        for (int i = 0; i < perspectives.length; i++) {
1445          IPerspectiveDescriptor persp = perspectives[i];
1446          if (perspectiveId.equals(persp.getId())) {
1447            win.getShell().open();
1448            page.setPerspective(persp);
1449            return page;
1450          }
1451        }
1452      }
1453    }
1454
1455    // If another window that has the workspace root as input and the
1456    // requested
1457    // perpective open and active, then the window is given focus.
1458    IAdaptable input = getDefaultPageInput();
1459    IWorkbenchWindow[] windows = getWorkbenchWindows();
1460    for (int i = 0; i < windows.length; i++) {
1461      win = (WorkbenchWindow) windows[i];
1462      if (window != win) {
1463        WorkbenchPage page = win.getActiveWorkbenchPage();
1464        if (page != null) {
1465          boolean inputSame = false;
1466          if (input == null)
1467            inputSame = (page.getInput() == null);
1468          else
1469            inputSame = input.equals(page.getInput());
1470          if (inputSame) {
1471            Perspective persp = page.getActivePerspective();
1472            if (perspectiveId.equals(persp.getDesc().getId())) {
1473              Shell shell = win.getShell();
1474              shell.open();
1475              if (shell.getMinimized())
1476                shell.setMinimized(false);
1477              return page;
1478            }
1479          }
1480        }
1481      }
1482    }
1483
1484    // Otherwise the requested perspective is opened and shown in the
1485    // specified
1486    // window or in a new window depending on the current user preference
1487    // for opening
1488    // perspectives, and that window is given focus.
1489    win = (WorkbenchWindow) window;
1490    if (win != null) {
1491      IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();
1492      int mode = store.getInt(IPreferenceConstants.OPEN_PERSP_MODE);
1493      IWorkbenchPage page = win.getActiveWorkbenchPage();
1494      IPerspectiveDescriptor persp = null;
1495      if (page != null)
1496        persp = page.getPerspective();
1497
1498      // Only open a new window if user preference is set and the window
1499      // has an active perspective.
1500      if (IPreferenceConstants.OPM_NEW_WINDOW == mode && persp != null) {
1501        IWorkbenchWindow newWindow = openWorkbenchWindow(perspectiveId, input);
1502        return newWindow.getActivePage();
1503      } else {
1504        IPerspectiveDescriptor desc =
1505          getPerspectiveRegistry().findPerspectiveWithId(perspectiveId);
1506        if (desc == null)
1507          throw new WorkbenchException(WorkbenchMessages.getString("WorkbenchPage.ErrorRecreatingPerspective")); //$NON-NLS-1$
1508        win.getShell().open();
1509        if (page == null)
1510          page = win.openPage(perspectiveId, input);
1511        else
1512          page.setPerspective(desc);
1513        return page;
1514      }
1515    }
1516
1517    // Just throw an exception....
1518    throw new WorkbenchException(WorkbenchMessages.format("Workbench.showPerspectiveError", new Object[] { perspectiveId })); //$NON-NLS-1$
1519  }
1520
1521  /*
1522   * (non-Javadoc) Method declared on IWorkbench.
1523   */
1524  public IWorkbenchPage showPerspective(
1525    String perspectiveId,
1526    IWorkbenchWindow window,
1527    IAdaptable input)
1528    throws WorkbenchException {
1529    Assert.isNotNull(perspectiveId);
1530
1531    // If the specified window has the requested perspective open and the
1532    // same requested
1533    // input, then the window is given focus and the perspective is shown.
1534    boolean inputSameAsWindow = false;
1535    WorkbenchWindow win = (WorkbenchWindow) window;
1536    if (win != null) {
1537      WorkbenchPage page = win.getActiveWorkbenchPage();
1538      if (page != null) {
1539        boolean inputSame = false;
1540        if (input == null)
1541          inputSame = (page.getInput() == null);
1542        else
1543          inputSame = input.equals(page.getInput());
1544        if (inputSame) {
1545          inputSameAsWindow = true;
1546          IPerspectiveDescriptor perspectives[] = page.getOpenedPerspectives();
1547          for (int i = 0; i < perspectives.length; i++) {
1548            IPerspectiveDescriptor persp = perspectives[i];
1549            if (perspectiveId.equals(persp.getId())) {
1550              win.getShell().open();
1551              page.setPerspective(persp);
1552              return page;
1553            }
1554          }
1555        }
1556      }
1557    }
1558
1559    // If another window has the requested input and the requested
1560    // perpective open and active, then that window is given focus.
1561    IWorkbenchWindow[] windows = getWorkbenchWindows();
1562    for (int i = 0; i < windows.length; i++) {
1563      win = (WorkbenchWindow) windows[i];
1564      if (window != win) {
1565        WorkbenchPage page = win.getActiveWorkbenchPage();
1566        if (page != null) {
1567          boolean inputSame = false;
1568          if (input == null)
1569            inputSame = (page.getInput() == null);
1570          else
1571            inputSame = input.equals(page.getInput());
1572          if (inputSame) {
1573            Perspective persp = page.getActivePerspective();
1574            if (perspectiveId.equals(persp.getDesc().getId())) {
1575              win.getShell().open();
1576              return page;
1577            }
1578          }
1579        }
1580      }
1581    }
1582
1583    // If the specified window has the same requested input but not the
1584    // requested
1585    // perspective, then the window is given focus and the perspective is
1586    // opened and shown
1587    // on condition that the user preference is not to open perspectives in
1588    // a new window.
1589    win = (WorkbenchWindow) window;
1590    if (inputSameAsWindow && win != null) {
1591      IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();
1592      int mode = store.getInt(IPreferenceConstants.OPEN_PERSP_MODE);
1593
1594      if (IPreferenceConstants.OPM_NEW_WINDOW != mode) {
1595        IWorkbenchPage page = win.getActiveWorkbenchPage();
1596        IPerspectiveDescriptor desc =
1597          getPerspectiveRegistry().findPerspectiveWithId(perspectiveId);
1598        if (desc == null)
1599          throw new WorkbenchException(WorkbenchMessages.getString("WorkbenchPage.ErrorRecreatingPerspective")); //$NON-NLS-1$
1600        win.getShell().open();
1601        if (page == null)
1602          page = win.openPage(perspectiveId, input);
1603        else
1604          page.setPerspective(desc);
1605        return page;
1606      }
1607    }
1608
1609    // If the specified window has no active perspective, then open the
1610    // requested perspective and show the specified window.
1611    if (win != null) {
1612      IWorkbenchPage page = win.getActiveWorkbenchPage();
1613      IPerspectiveDescriptor persp = null;
1614      if (page != null)
1615        persp = page.getPerspective();
1616      if (persp == null) {
1617        IPerspectiveDescriptor desc =
1618          getPerspectiveRegistry().findPerspectiveWithId(perspectiveId);
1619        if (desc == null)
1620          throw new WorkbenchException(WorkbenchMessages.getString("WorkbenchPage.ErrorRecreatingPerspective")); //$NON-NLS-1$
1621        win.getShell().open();
1622        if (page == null)
1623          page = win.openPage(perspectiveId, input);
1624        else
1625          page.setPerspective(desc);
1626        return page;
1627      }
1628    }
1629
1630    // Otherwise the requested perspective is opened and shown in a new
1631    // window, and the
1632    // window is given focus.
1633    IWorkbenchWindow newWindow = openWorkbenchWindow(perspectiveId, input);
1634    return newWindow.getActivePage();
1635  }
1636
1637  /*
1638   * Shuts down the application.
1639   */
1640  private void shutdown() {
1641    // shutdown application-specific portions first
1642    advisor.postShutdown();
1643
1644    // for dynamic UI 
1645    Platform.getExtensionRegistry().removeRegistryChangeListener(extensionEventHandler);
1646
1647    // shutdown the rest of the workbench
1648    WorkbenchColors.shutdown();    
1649    activityHelper.shutdown();
1650    uninitializeImages();
1651    if (WorkbenchPlugin.getDefault() != null) {
1652      WorkbenchPlugin.getDefault().reset();
1653    }
1654    WorkbenchThemeManager.getInstance().dispose();
1655  }
1656
1657  /*
1658   * (non-Javadoc) Method declared on IWorkbench.
1659   */
1660  public IDecoratorManager getDecoratorManager() {
1661    return WorkbenchPlugin.getDefault().getDecoratorManager();
1662  }
1663
1664  /*
1665   * Returns the workbench window which was last known being the active one,
1666   * or <code> null </code> .
1667   */
1668  private WorkbenchWindow getActivatedWindow() {
1669    if (activatedWindow != null) {
1670      Shell shell = activatedWindow.getShell();
1671      if (shell != null && !shell.isDisposed()) {
1672        return activatedWindow;
1673      }
1674    }
1675
1676    return null;
1677  }
1678
1679  /*
1680   * Sets the workbench window which was last known being the active one, or
1681   * <code> null </code> .
1682   */
1683  /* package */
1684  void setActivatedWindow(WorkbenchWindow window) {
1685    activatedWindow = window;
1686  }
1687
1688  /**
1689   * Returns the unique object that applications use to configure the
1690   * workbench.
1691   * <p>
1692   * IMPORTANT This method is declared package-private to prevent regular
1693   * plug-ins from downcasting IWorkbench to Workbench and getting hold of
1694   * the workbench configurer that would allow them to tamper with the
1695   * workbench. The workbench configurer is available only to the
1696   * application.
1697   * </p>
1698   */
1699  /* package */
1700  WorkbenchConfigurer getWorkbenchConfigurer() {
1701    if (workbenchConfigurer == null) {
1702      workbenchConfigurer = new WorkbenchConfigurer();
1703    }
1704    return workbenchConfigurer;
1705  }
1706
1707  /**
1708   * Returns the workbench advisor that created this workbench.
1709   * <p>
1710   * IMPORTANT This method is declared package-private to prevent regular
1711   * plug-ins from downcasting IWorkbench to Workbench and getting hold of
1712   * the workbench advisor that would allow them to tamper with the
1713   * workbench. The workbench advisor is internal to the application.
1714   * </p>
1715   */
1716  /* package */
1717  WorkbenchAdvisor getAdvisor() {
1718    return advisor;
1719  }
1720
1721  /*
1722   * (non-Javadoc) Method declared on IWorkbench.
1723   */
1724  public Display getDisplay() {
1725    return display;
1726  }
1727
1728  /**
1729   * Returns the default perspective id.
1730   * 
1731   * @return the default perspective id
1732   */
1733  public String getDefaultPerspectiveId() {
1734    String id = getAdvisor().getInitialWindowPerspectiveId();
1735    // make sure we the advisor gave us one
1736    Assert.isNotNull(id);
1737    return id;
1738  }
1739
1740  /**
1741   * Returns the default workbench window page input.
1742   * 
1743   * @return the default window page input or <code>null</code> if none
1744   */
1745  public IAdaptable getDefaultPageInput() {
1746    return getAdvisor().getDefaultPageInput();
1747  }
1748
1749  /**
1750   * Returns the id of the preference page that should be presented most
1751   * prominently.
1752   * 
1753   * @return the id of the preference page, or <code>null</code> if none
1754   */
1755  public String getMainPreferencePageId() {
1756    String id = getAdvisor().getMainPreferencePageId();
1757    return id;
1758  }
1759
1760  /*
1761   * (non-Javadoc)
1762   * 
1763   * @see org.eclipse.ui.IWorkbench
1764   * @since 3.0
1765   */
1766  public IElementFactory getElementFactory(String factoryId) {
1767    Assert.isNotNull(factoryId);
1768    return WorkbenchPlugin.getDefault().getElementFactory(factoryId);
1769  }
1770
1771  /*
1772   * (non-Javadoc)
1773   * 
1774   * @see org.eclipse.ui.IWorkbench#getProgressService()
1775   */
1776  public IProgressService getProgressService() {
1777    return ProgressManager.getInstance();
1778  }
1779
1780  private WorkbenchActivitySupport workbenchActivitySupport;
1781
1782    private WorkbenchCommandSupport workbenchCommandSupport;
1783
1784    private WorkbenchContextSupport workbenchContextSupport;
1785
1786    public IWorkbenchActivitySupport getActivitySupport() {
1787        return workbenchActivitySupport;
1788    }
1789
1790    public IWorkbenchCommandSupport getCommandSupport() {
1791        return workbenchCommandSupport;
1792    }
1793
1794    public IWorkbenchContextSupport getContextSupport() {
1795        return workbenchContextSupport;
1796    }
1797
1798    private final ICommandManagerListener commandManagerListener = new ICommandManagerListener() {
1799
1800        public final void commandManagerChanged(
1801                final CommandManagerEvent commandManagerEvent) {
1802            updateActiveWorkbenchWindowMenuManager(false);
1803        }
1804    };
1805
1806    private final IContextManagerListener contextManagerListener = new IContextManagerListener() {
1807
1808        public final void contextManagerChanged(
1809                final ContextManagerEvent contextManagerEvent) {
1810            final Set enabledContextIds = workbenchContextSupport.getContextManager().getEnabledContextIds();
1811            final Map enabledContextTree = workbenchContextSupport.createFilteredContextTreeFor(enabledContextIds); 
1812            workbenchCommandSupport.setActiveContextIds(enabledContextTree);
1813        }
1814    };
1815
1816    private final IWindowListener windowListener = new IWindowListener() {
1817
1818        public void windowActivated(IWorkbenchWindow window) {
1819            updateActiveWorkbenchWindowMenuManager(true);
1820        }
1821
1822        public void windowClosed(IWorkbenchWindow window) {
1823            updateActiveWorkbenchWindowMenuManager(true);
1824        }
1825
1826        public void windowDeactivated(IWorkbenchWindow window) {
1827            updateActiveWorkbenchWindowMenuManager(true);
1828        }
1829
1830        public void windowOpened(IWorkbenchWindow window) {
1831            updateActiveWorkbenchWindowMenuManager(true);
1832        }
1833    };
1834
1835    private void updateActiveWorkbenchWindowMenuManager(boolean textOnly) {
1836        final IWorkbenchWindow workbenchWindow = getActiveWorkbenchWindow();
1837
1838        if (workbenchWindow instanceof WorkbenchWindow) {
1839            final WorkbenchWindow window = (WorkbenchWindow) workbenchWindow;
1840            if (window.isClosing()) { return; }
1841
1842            final MenuManager menuManager = window.getMenuManager();
1843
1844            if (textOnly)
1845                menuManager.update(IAction.TEXT);
1846            else
1847                menuManager.updateAll(true);
1848        }
1849    }
1850  
1851  private ActivityPersistanceHelper activityHelper;
1852  
1853    /* (non-Javadoc)
1854     * @see org.eclipse.ui.IWorkbench#getIntroManager()
1855     */
1856    public IIntroManager getIntroManager() {
1857        return introManager;
1858    }
1859  
1860    /** 
1861     * @return the workbench intro manager
1862     * @since 3.0
1863     */
1864    /*package*/ WorkbenchIntroManager getWorkbenchIntroManager() {
1865        return introManager;
1866    }
1867    
1868    private WorkbenchIntroManager introManager = new WorkbenchIntroManager(this);
1869    
1870  /** 
1871   * @return the intro extension for this workbench.
1872   * 
1873   * @since 3.0
1874   */
1875  public IntroDescriptor getIntroDescriptor() {
1876    return introDescriptor;
1877  }
1878  
1879  /**
1880   * This method exists as a test hook.  This method should 
1881   * <strong>NEVER</strong> be called by clients.
1882   * 
1883   * @since 3.0
1884   */
1885  public void setIntroDescriptor(IntroDescriptor descriptor) {
1886      if (introManager.getIntro() != null) {
1887          introManager.closeIntro(introManager.getIntro());
1888      }
1889      introDescriptor = descriptor;
1890  }
1891    
1892  /**
1893   * The descriptor for the intro extension that is valid for this workspace, <code>null</code> if none.
1894   */
1895  private IntroDescriptor introDescriptor;
1896
1897    /* (non-Javadoc)
1898     * @see org.eclipse.ui.IWorkbench#getThemeManager()
1899     */
1900    public IThemeManager getThemeManager() {
1901        return WorkbenchThemeManager.getInstance();
1902    }
1903
1904    /**
1905     * Returns <code>true</code> if the workbench is running,
1906     * <code>false</code> if it has been terminated. 
1907     */
1908    public boolean isRunning() {
1909        return runEventLoop;
1910    }
1911
1912    /**
1913     * Return the presentation ID specified by the preference or the default ID if undefined.
1914     * 
1915     * @return the presentation ID
1916     * @see IWorkbenchPreferenceConstants#PRESENTATION_FACTORY_ID
1917     */
1918    public String getPresentationId() {
1919      String factoryId = PrefUtil.getAPIPreferenceStore().getString(
1920              IWorkbenchPreferenceConstants.PRESENTATION_FACTORY_ID);
1921      
1922        // Workaround for bug 58975 - New preference mechanism does not properly initialize defaults
1923        // Ensure that the UI plugin has started too.
1924      if (factoryId == null || factoryId.equals("")) {  //$NON-NLS-1$
1925      factoryId = "org.eclipse.ui.presentations.default"; //$NON-NLS-1$
1926      }
1927      return factoryId;
1928  }
1929
1930  /**
1931     * <p>
1932     * Indicates the start of a large update within the workbench. This is used
1933     * to disable CPU-intensive, change-sensitive services that were temporarily
1934     * disabled in the midst of large changes. This method should always be
1935     * called in tandem with <code>largeUpdateEnd</code>, and the event loop
1936     * should not be allowed to spin before that method is called.
1937     * </p>
1938     * <p>
1939     * Important: always use with <code>largeUpdateEnd</code>!
1940     * </p>
1941     */
1942    public final void largeUpdateStart() {
1943        if (largeUpdates++ == 0) {
1944            workbenchCommandSupport.setProcessing(false);
1945            workbenchContextSupport.setProcessing(false);
1946        }
1947    }
1948
1949    /**
1950     * <p>
1951     * Indicates the end of a large update within the workbench. This is used to
1952     * re-enable services that were temporarily disabled in the midst of large
1953     * changes. This method should always be called in tandem with
1954     * <code>largeUpdateStart</code>, and the event loop should not be
1955     * allowed to spin before this method is called.
1956     * </p>
1957     * <p>
1958     * Important: always protect this call by using <code>finally</code>!
1959     * </p>
1960     */
1961    public final void largeUpdateEnd() {
1962        if (--largeUpdates == 0) {
1963            workbenchCommandSupport.setProcessing(true);
1964            workbenchContextSupport.setProcessing(true);
1965        }
1966    }
1967}