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}