]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.workbench/src/org/simantics/workbench/internal/SimanticsWorkbenchAdvisor.java
Allow ExecutorWorker thread pool shutdown
[simantics/platform.git] / bundles / org.simantics.workbench / src / org / simantics / workbench / internal / SimanticsWorkbenchAdvisor.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.workbench.internal;
13
14 import java.io.IOException;
15 import java.lang.reflect.InvocationTargetException;
16 import java.net.URL;
17 import java.text.Collator;
18 import java.util.ArrayList;
19 import java.util.Iterator;
20 import java.util.Map;
21 import java.util.TreeMap;
22
23 import org.eclipse.core.internal.resources.Workspace;
24 import org.eclipse.core.net.proxy.IProxyService;
25 import org.eclipse.core.resources.IContainer;
26 import org.eclipse.core.resources.IResource;
27 import org.eclipse.core.resources.ResourcesPlugin;
28 import org.eclipse.core.resources.WorkspaceJob;
29 import org.eclipse.core.runtime.CoreException;
30 import org.eclipse.core.runtime.FileLocator;
31 import org.eclipse.core.runtime.IAdaptable;
32 import org.eclipse.core.runtime.IBundleGroup;
33 import org.eclipse.core.runtime.IBundleGroupProvider;
34 import org.eclipse.core.runtime.ILog;
35 import org.eclipse.core.runtime.IProgressMonitor;
36 import org.eclipse.core.runtime.IStatus;
37 import org.eclipse.core.runtime.MultiStatus;
38 import org.eclipse.core.runtime.Path;
39 import org.eclipse.core.runtime.Platform;
40 import org.eclipse.core.runtime.ProgressMonitorWrapper;
41 import org.eclipse.core.runtime.Status;
42 import org.eclipse.core.runtime.SubMonitor;
43 import org.eclipse.core.runtime.jobs.Job;
44 import org.eclipse.e4.core.contexts.IEclipseContext;
45 import org.eclipse.e4.ui.internal.workbench.E4Workbench;
46 import org.eclipse.jface.dialogs.ErrorDialog;
47 import org.eclipse.jface.dialogs.IDialogSettings;
48 import org.eclipse.jface.dialogs.MessageDialog;
49 import org.eclipse.jface.dialogs.TrayDialog;
50 import org.eclipse.jface.operation.IRunnableWithProgress;
51 import org.eclipse.jface.preference.IPreferenceStore;
52 import org.eclipse.jface.resource.ImageDescriptor;
53 import org.eclipse.jface.util.Policy;
54 import org.eclipse.jface.window.Window;
55 import org.eclipse.swt.SWT;
56 import org.eclipse.swt.events.SelectionAdapter;
57 import org.eclipse.swt.events.SelectionEvent;
58 import org.eclipse.swt.widgets.Composite;
59 import org.eclipse.swt.widgets.Display;
60 import org.eclipse.swt.widgets.Event;
61 import org.eclipse.swt.widgets.Listener;
62 import org.eclipse.swt.widgets.Shell;
63 import org.eclipse.ui.IPerspectiveDescriptor;
64 import org.eclipse.ui.PlatformUI;
65 import org.eclipse.ui.application.IWorkbenchConfigurer;
66 import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
67 import org.eclipse.ui.application.WorkbenchAdvisor;
68 import org.eclipse.ui.application.WorkbenchWindowAdvisor;
69 import org.eclipse.ui.ide.IDE;
70 import org.eclipse.ui.internal.ISelectionConversionService;
71 import org.eclipse.ui.internal.Workbench;
72 import org.eclipse.ui.internal.ide.AboutInfo;
73 import org.eclipse.ui.internal.ide.IDEInternalPreferences;
74 import org.eclipse.ui.internal.ide.IDEInternalWorkbenchImages;
75 import org.eclipse.ui.internal.ide.IDESelectionConversionService;
76 import org.eclipse.ui.internal.ide.IDEWorkbenchActivityHelper;
77 import org.eclipse.ui.internal.ide.IDEWorkbenchErrorHandler;
78 import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
79 import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
80 import org.eclipse.ui.internal.ide.undo.WorkspaceUndoMonitor;
81 import org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog;
82 import org.eclipse.ui.keys.IBindingService;
83 import org.eclipse.ui.progress.IProgressService;
84 import org.eclipse.ui.statushandlers.AbstractStatusHandler;
85 import org.osgi.framework.Bundle;
86 import org.osgi.framework.ServiceReference;
87 import org.osgi.framework.Version;
88 import org.simantics.CancelStartupException;
89 import org.simantics.PlatformException;
90 import org.simantics.Simantics;
91 import org.simantics.SimanticsPlatform;
92 import org.simantics.SimanticsPlatform.OntologyRecoveryPolicy;
93 import org.simantics.SimanticsPlatform.RecoveryPolicy;
94 import org.simantics.TimingProgressMonitor;
95 import org.simantics.application.arguments.IArguments;
96 import org.simantics.application.arguments.SimanticsArguments;
97 import org.simantics.db.common.Indexing;
98 import org.simantics.db.indexing.DatabaseIndexing;
99 import org.simantics.db.procore.server.environment.RebootRequiredException;
100 import org.simantics.db.procore.server.environment.windows.Product;
101 import org.simantics.internal.TimedSessionCache;
102 import org.simantics.project.IProject;
103 import org.simantics.project.ProjectKeys;
104 import org.simantics.ui.SimanticsUI;
105 import org.simantics.ui.jobs.SessionGarbageCollectorJob;
106 import org.simantics.ui.workbench.PerspectiveBarsActivator;
107 import org.simantics.ui.workbench.PerspectiveContextActivator;
108 import org.simantics.utils.logging.TimeLogger;
109 import org.simantics.utils.threads.ExecutorWorker;
110 import org.simantics.utils.threads.ThreadUtils;
111 import org.simantics.utils.ui.dialogs.ShowError;
112 import org.simantics.utils.ui.dialogs.ShowMessage;
113 import org.slf4j.Logger;
114 import org.slf4j.LoggerFactory;
115
116
117 /**
118  * @author Tuukka Lehtonen
119  */
120 public class SimanticsWorkbenchAdvisor extends WorkbenchAdvisor {
121     
122     private static final Logger LOGGER = LoggerFactory.getLogger(SimanticsWorkbenchAdvisor.class);
123
124     private static final boolean PROFILE_PLATFORM_STARTUP = false;
125
126     private static final String SHUT_DOWN_TASK = "Shutting down...";
127
128     private static final String SHUT_DOWN_PLATFORM_TASK = "Shutting down platform...";
129
130     private static final String WORKBENCH_PREFERENCE_CATEGORY_ID = "org.eclipse.ui.preferencePages.Workbench"; //$NON-NLS-1$
131
132     /**
133      * The dialog setting key to access the known installed features since the
134      * last time the workbench was run.
135      */
136     private static final String INSTALLED_FEATURES = "installedFeatures"; //$NON-NLS-1$
137
138     /**
139      * The arguments received by the application.
140      */
141     protected final IArguments args;
142
143     protected final boolean restoredPreviousSession = false;
144
145     /**
146      * Only true while opening the initial windows during {@link #openWindows()}.
147      * Used by {@link SimanticsWorkbenchWindowAdvisor#postWindowOpen()} to
148      * recognize when to skip all one-time initialization.
149      */
150     protected boolean workbenchWindowsInitialized = false;
151
152     /**
153      * Whether or not to save unsaved database changes before exiting the
154      * workbench.
155      */
156     protected boolean saveAtExit = false;
157
158     /**
159      * Ordered map of versioned feature ids -> info that are new for this
160      * session; <code>null</code> if uninitialized. Key type:
161      * <code>String</code>, Value type: <code>AboutInfo</code>.
162      */
163     private Map<String, AboutInfo> newlyAddedBundleGroups;
164
165     /**
166      * Array of <code>AboutInfo</code> for all new installed features that
167      * specify a welcome perspective.
168      */
169     private AboutInfo[] welcomePerspectiveInfos = null;
170
171     /**
172      * Helper for managing activites in response to workspace changes.
173      */
174     private IDEWorkbenchActivityHelper activityHelper = null;
175
176     /**
177      * Helper for managing work that is performed when the system is otherwise
178      * idle.
179      */
180     private IDEIdleHelper idleHelper;
181
182     private Listener settingsChangeListener;
183
184     /**
185      * Support class for monitoring workspace changes and periodically
186      * validating the undo history
187      */
188     private WorkspaceUndoMonitor workspaceUndoMonitor;
189
190     /**
191      * The IDE workbench error handler.
192      */
193     private AbstractStatusHandler ideWorkbenchErrorHandler;
194
195     /**
196      * Helper class used to process delayed events.
197      */
198     private DelayedEventsProcessor delayedEventsProcessor;
199     
200     /**
201      * Creates a new workbench advisor instance.
202      * @param processor
203      */
204     public SimanticsWorkbenchAdvisor(IArguments args, DelayedEventsProcessor processor) {
205         super();
206         this.args = args;
207         this.delayedEventsProcessor = processor;
208
209         Listener closeListener = new Listener() {
210             public void handleEvent(Event event) {
211                 boolean doExit = SimanticsWorkbenchWindowAdvisor.promptOnExit(null);
212                 event.doit = doExit;
213                 if (!doExit)
214                     event.type = SWT.None;
215             }
216         };
217         Display.getDefault().addListener(SWT.Close, closeListener);
218     }
219
220     public IArguments getArguments() {
221         return args;
222     }
223
224     public boolean workbenchInitialized() {
225         return workbenchWindowsInitialized;
226     }
227
228     public boolean restoredPreviousSession() {
229         return restoredPreviousSession;
230     }
231
232     boolean saveAtExit() {
233         return saveAtExit;
234     }
235
236     void setSaveAtExit(boolean saveAtExit) {
237         this.saveAtExit = saveAtExit;
238     }
239
240     /*
241      * (non-Javadoc)
242      *
243      * @see org.eclipse.ui.application.WorkbenchAdvisor#initialize
244      */
245     @Override
246     public void initialize(IWorkbenchConfigurer configurer) {
247         // By default, we always save and restore the workbench state.
248         configurer.setSaveAndRestore(true);
249
250         checkWorkspaceDatabaseIndexes();
251
252         // Start tracking the active perspective to activate contexts based on it.
253         new PerspectiveContextActivator();
254         new PerspectiveBarsActivator();
255
256         // register workspace adapters
257         IDE.registerAdapters();
258
259         // register shared images
260         declareWorkbenchImages();
261
262         // initialize the activity helper
263         activityHelper = IDEWorkbenchActivityHelper.getInstance();
264
265         // initialize idle handler
266         idleHelper = new IDEIdleHelper(configurer);
267
268         // initialize the workspace undo monitor
269         workspaceUndoMonitor = WorkspaceUndoMonitor.getInstance();
270
271         // show Help button in JFace dialogs
272         TrayDialog.setDialogHelpAvailable(true);
273
274         Policy.setComparator(Collator.getInstance());
275     }
276
277     private void checkWorkspaceDatabaseIndexes() {
278         try {
279             DatabaseIndexing.validateIndexes();
280         } catch (IOException e) {
281             Activator.logError("Problems encountered while checking database indexes, see exception for details.", e);
282         }
283     }
284
285     public WorkbenchWindowAdvisor createWorkbenchWindowAdvisorClass(SimanticsWorkbenchAdvisor advisor, IWorkbenchWindowConfigurer configurer) {
286         return new SimanticsWorkbenchWindowAdvisor(this, configurer);
287     }
288
289     @Override
290     public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) {
291         // Attach database session watchdog.
292         new SessionWatchdog().attach( Simantics.getSessionContextProvider() );
293
294         return createWorkbenchWindowAdvisorClass(this, configurer);
295     }
296
297     /**
298      * For gaining direct access to super.openWindows() in implementations
299      * inheriting this one.
300      */
301     public boolean openWindowsSuper() {
302         return super.openWindows();
303     }
304
305     /**
306      * Sadly we do not know why key bindings are lost and why this helps. But it
307      * does. Visiting the <code>Keys</code> preference page and pressing OK uses
308      * this the same call and it seems to salvage the bindings that have been in
309      * some cases destroyed by <code>BindingToModelProcessor</code>.
310      * 
311      * <p>
312      * Related links:
313      * https://techblog.ralph-schuster.eu/2013/10/13/eclipsee4-problem-with-key-bindings/comment-page-1/
314      * https://www.eclipse.org/forums/index.php/t/550175/
315      * https://bugs.eclipse.org/bugs/show_bug.cgi?id=461037
316      * 
317      * @see platform issue #6353
318      */
319     private void fixBindings() {
320         try {
321             IBindingService bs = PlatformUI.getWorkbench().getAdapter(IBindingService.class);
322             bs.savePreferences(bs.getActiveScheme(), bs.getBindings());
323         } catch (IOException e) {
324             Activator.logError(getClass().getSimpleName() + ".fixBindings failed", e);
325         }
326     }
327
328     @Override
329     public boolean openWindows() {
330         boolean platformOk = startPlatform();
331         LOGGER.info("startPlatform finished");
332         TimeLogger.log("SimanticsWorkbenchAdvisor.startPlatform finished");
333
334         if (platformOk) {
335             // At this point workbenchConfigurer.getSaveAndRestore()
336             // returns false iff something has gone terribly wrong
337             // before this. Currently saveAndRestore is always true.
338             boolean windowsOpened = super.openWindows();
339             TimeLogger.log("Opened windows");
340             if (windowsOpened) {
341                 workbenchWindowsInitialized = true;
342
343                 // Start the database garbage collector after a short while.
344                 SessionGarbageCollectorJob.getInstance().scheduleAfterQuietTime();
345
346                 // #6353: Workaround for  
347                 fixBindings();
348
349                 return true;
350             }
351         }
352
353         // Make sure platform shutdown is ran if window opening fails.
354         try {
355             platformShutdownRunnable.run(null);
356         } catch (InvocationTargetException e) {
357             Activator.logError(getClass().getSimpleName() + ".openWindows failed", e.getCause());
358         } catch (InterruptedException e) {
359             Activator.logError(getClass().getSimpleName() + ".openWindows failed", e);
360         }
361         return false;
362     }
363
364     protected boolean startPlatform() {
365         // Verify selected perspective
366         if (args.contains(SimanticsArguments.PERSPECTIVE)) {
367             String perspectiveId = args.get(SimanticsArguments.PERSPECTIVE);
368             IPerspectiveDescriptor perspective = PlatformUI.getWorkbench().getPerspectiveRegistry().findPerspectiveWithId(perspectiveId);
369             if (perspective == null) {
370                 StringBuilder msg = new StringBuilder();
371                 msg.append("Requested perspective not found: '" + perspectiveId + "'\n");
372                 msg.append("Valid alternatives are:\n");
373                 for (IPerspectiveDescriptor pd : PlatformUI.getWorkbench().getPerspectiveRegistry().getPerspectives()) {
374                     msg.append("    " + pd.getId() + "\n");
375                 }
376
377                 ShowMessage.syncShowError("Invalid Perspective", msg.toString());
378                 return false;
379             }
380         }
381
382         ILog log = Platform.getLog(Activator.getDefault().getBundle());
383
384         try {
385             //
386             //
387             // Create Simantics Platform Helper.
388             //
389             // If Simantics is started from Eclipse IDE or with -fixerrors option,
390             // there is an attempt to fix errors.
391             //
392             // On ontology mismatch, there is an attempt to merge new ontology to the
393             // existing database. With -reinstall, the database is cleaned and
394             // reinstalled.
395             //
396             //
397
398             RecoveryPolicy workspacePolicy = Platform.inDevelopmentMode() ? RecoveryPolicy.FixError : RecoveryPolicy.ThrowError;
399             OntologyRecoveryPolicy ontologyPolicy = Platform.inDevelopmentMode() ? OntologyRecoveryPolicy.Merge : OntologyRecoveryPolicy.ThrowError;
400
401             if (args.contains(SimanticsArguments.RECOVERY_POLICY_FIX_ERRORS)) {
402                 workspacePolicy = RecoveryPolicy.FixError;
403                 ontologyPolicy = OntologyRecoveryPolicy.Merge;
404             }
405
406             boolean requireSynchronize = true;
407
408             if (args.contains(SimanticsArguments.ONTOLOGY_RECOVERY_POLICY_REINSTALL)) {
409                 ontologyPolicy = OntologyRecoveryPolicy.ReinstallDatabase;
410             }
411
412             if (args.contains(SimanticsArguments.DO_NOT_SYNCHRONIZE_ONTOLOGIES)) {
413                 requireSynchronize = false;
414             }
415             
416             if (args.contains(SimanticsArguments.DISABLE_INDEX)) {
417                 Indexing.setDefaultDependenciesIndexingEnabled(false);
418             }
419
420             if (args.contains(SimanticsArguments.SERVER)) {
421                 String serverAddress = args.get(SimanticsArguments.SERVER);
422                 throw new PlatformException("Argument not supported: " + SimanticsArguments.SERVER + " " + serverAddress);
423             }
424
425             String databaseDriverId = Simantics.getDefaultDatabaseDriver();
426             if (args.contains(SimanticsArguments.DATABASE_ID)) {
427                 databaseDriverId = args.get(SimanticsArguments.DATABASE_ID);
428                 Simantics.setDefaultDatabaseDriver(databaseDriverId);
429             }
430             
431             IProgressMonitor mon = null;
432             if (PROFILE_PLATFORM_STARTUP)
433                 mon = new TimingProgressMonitor();
434             SimanticsPlatform.INSTANCE.startUp(databaseDriverId, mon, workspacePolicy, ontologyPolicy, requireSynchronize, new JFaceUserAgent());
435
436             // Make sure that the default perspective comes from the project if
437             // the project has set ProjectKeys#DEFAULT_PERSPECTIVE.
438             // This might go wrong if project features interact with
439             // PerspectiveRegistry while configuring themselves, since that will
440             // cause an invocation to #getInitialWindowPerspectiveId() while
441             // the project has not yet been properly initialized.
442             getWorkbenchConfigurer().getWorkbench().getPerspectiveRegistry().setDefaultPerspective(getInitialWindowPerspectiveId());
443             TimeLogger.log("Completed setting default perspective");
444
445             return true;
446         } catch (CancelStartupException e) {
447             return false;
448         } catch (PlatformException e) {
449             boolean hasStackTrace = e.getStackTrace().length > 0;
450             Throwable ee = e;
451             while (ee.getCause() != null) {
452                 ee = ee.getCause();
453                 hasStackTrace = ee.getStackTrace().length > 0;
454             }
455
456             log.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), hasStackTrace ? e : null));
457             if (hasStackTrace) {
458                 new ShowError("Platform Initialization Failed", "Simantics Platform initialization failed:\n\n" + e.getMessage(), e, true);
459             } else {
460                 StringBuilder sb = new StringBuilder(256);
461                 sb.append(e.getMessage());
462                 for (Throwable c=e.getCause(); null != c && null != c.getMessage(); c=c.getCause())
463                     sb.append("\ncause: ").append(c.getMessage());
464                 new ShowError("Startup Failed", sb.toString(), (Exception) null, true);
465             }
466
467             return false;
468         } catch (Exception e) {
469             log.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));
470
471             Throwable cause = e.getCause();
472             if (cause instanceof RebootRequiredException) {
473                 RebootRequiredException rre = (RebootRequiredException) cause;
474                 StringBuilder msg = new StringBuilder();
475                 msg.append("The application must be restarted after installing the following products:\n");
476                 for (Product product : rre.products)
477                     msg.append("\t" + product + "\n");
478                 msg.append("\nThe application will now close.");
479                 MessageDialog.openInformation(null, "Restart Required", msg.toString());
480             } else {
481                 new ShowError("Platform Startup Failed", "Simantics Platform startup failed:\n\n" + e.getMessage(), e, true);
482             }
483             return false;
484         }
485
486     }
487
488     /*
489      * (non-Javadoc)
490      *
491      * @see org.eclipse.ui.application.WorkbenchAdvisor#preStartup()
492      */
493     @Override
494     public void preStartup() {
495
496         // Suspend background jobs while we startup
497         Job.getJobManager().suspend();
498
499         // Register the build actions
500         IProgressService service = PlatformUI.getWorkbench()
501         .getProgressService();
502         ImageDescriptor newImage = IDEInternalWorkbenchImages
503         .getImageDescriptor(IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC);
504         service.registerIconForFamily(newImage,
505                 ResourcesPlugin.FAMILY_MANUAL_BUILD);
506         service.registerIconForFamily(newImage,
507                 ResourcesPlugin.FAMILY_AUTO_BUILD);
508     }
509
510     /*
511      * (non-Javadoc)
512      *
513      * @see org.eclipse.ui.application.WorkbenchAdvisor#postStartup()
514      */
515     @Override
516     public void postStartup() {
517         try {
518             refreshFromLocal();
519             activateProxyService();
520             ((Workbench) PlatformUI.getWorkbench()).registerService(
521                     ISelectionConversionService.class,
522                     new IDESelectionConversionService());
523
524             initializeSettingsChangeListener();
525             Display.getCurrent().addListener(SWT.Settings,
526                     settingsChangeListener);
527         } finally {// Resume background jobs after we startup
528             Job.getJobManager().resume();
529         }
530     }
531
532     /**
533      * Activate the proxy service by obtaining it.
534      */
535     private void activateProxyService() {
536         Bundle bundle = Platform.getBundle("org.eclipse.ui.ide"); //$NON-NLS-1$
537         Object proxyService = null;
538         if (bundle != null) {
539             ServiceReference<?> ref = bundle.getBundleContext().getServiceReference(IProxyService.class.getName());
540             if (ref != null)
541                 proxyService = bundle.getBundleContext().getService(ref);
542         }
543         if (proxyService == null) {
544             IDEWorkbenchPlugin.log("Proxy service could not be found."); //$NON-NLS-1$
545         }
546     }
547
548     /**
549      * Initialize the listener for settings changes.
550      */
551     private void initializeSettingsChangeListener() {
552         settingsChangeListener = new Listener() {
553
554             boolean currentHighContrast = Display.getCurrent()
555             .getHighContrast();
556
557             @Override
558             public void handleEvent(org.eclipse.swt.widgets.Event event) {
559                 if (Display.getCurrent().getHighContrast() == currentHighContrast)
560                     return;
561
562                 currentHighContrast = !currentHighContrast;
563
564                 // make sure they really want to do this
565                 if (new MessageDialog(null,
566                         IDEWorkbenchMessages.SystemSettingsChange_title, null,
567                         IDEWorkbenchMessages.SystemSettingsChange_message,
568                         MessageDialog.QUESTION, new String[] {
569                         IDEWorkbenchMessages.SystemSettingsChange_yes,
570                         IDEWorkbenchMessages.SystemSettingsChange_no },
571                         1).open() == Window.OK) {
572                     PlatformUI.getWorkbench().restart();
573                 }
574             }
575         };
576
577     }
578
579     /*
580      * (non-Javadoc)
581      *
582      * @see org.eclipse.ui.application.WorkbenchAdvisor#postShutdown
583      */
584     @Override
585     public void postShutdown() {
586         if (activityHelper != null) {
587             activityHelper.shutdown();
588             activityHelper = null;
589         }
590         if (idleHelper != null) {
591             idleHelper.shutdown();
592             idleHelper = null;
593         }
594         if (workspaceUndoMonitor != null) {
595             workspaceUndoMonitor.shutdown();
596             workspaceUndoMonitor = null;
597         }
598         if (IDEWorkbenchPlugin.getPluginWorkspace() != null) {
599             disconnectFromWorkspace();
600         }
601     }
602
603     /*
604      * (non-Javadoc)
605      *
606      * @see org.eclipse.ui.application.WorkbenchAdvisor#preShutdown()
607      */
608     @Override
609     public boolean preShutdown() {
610         Display.getCurrent().removeListener(SWT.Settings,
611                 settingsChangeListener);
612         return super.preShutdown();
613     }
614
615     /**
616      * Return true if the intro plugin is present and false otherwise.
617      *
618      * @return boolean
619      */
620     public boolean hasIntro() {
621         return getWorkbenchConfigurer().getWorkbench().getIntroManager()
622                 .hasIntro();
623     }
624
625     private void refreshFromLocal() {
626         String[] commandLineArgs = Platform.getCommandLineArgs();
627         IPreferenceStore store = IDEWorkbenchPlugin.getDefault()
628                 .getPreferenceStore();
629         boolean refresh = store
630                 .getBoolean(IDEInternalPreferences.REFRESH_WORKSPACE_ON_STARTUP);
631         if (!refresh) {
632             return;
633         }
634
635         // Do not refresh if it was already done by core on startup.
636         for (int i = 0; i < commandLineArgs.length; i++) {
637             if (commandLineArgs[i].equalsIgnoreCase("-refresh")) { //$NON-NLS-1$
638                 return;
639             }
640         }
641
642         final IContainer root = ResourcesPlugin.getWorkspace().getRoot();
643         Job job = new WorkspaceJob(IDEWorkbenchMessages.Workspace_refreshing) {
644             @Override
645             public IStatus runInWorkspace(IProgressMonitor monitor)
646                     throws CoreException {
647                 root.refreshLocal(IResource.DEPTH_INFINITE, monitor);
648                 return Status.OK_STATUS;
649             }
650         };
651         job.setRule(root);
652         job.schedule();
653     }
654
655     private static class CancelableProgressMonitorWrapper extends ProgressMonitorWrapper {
656         private double total = 0;
657         private ProgressMonitorJobsDialog dialog;
658
659         CancelableProgressMonitorWrapper(IProgressMonitor monitor,
660                 ProgressMonitorJobsDialog dialog) {
661             super(monitor);
662             this.dialog = dialog;
663         }
664
665         /*
666          * (non-Javadoc)
667          * @see org.eclipse.core.runtime.ProgressMonitorWrapper#internalWorked(double)
668          */
669         public void internalWorked(double work) {
670             super.internalWorked(work);
671             total += work;
672             updateProgressDetails();
673         }
674
675         /*
676          * (non-Javadoc)
677          * @see org.eclipse.core.runtime.ProgressMonitorWrapper#worked(int)
678          */
679         public void worked(int work) {
680             super.worked(work);
681             total += work;
682             updateProgressDetails();
683         }
684
685         public void beginTask(String name, int totalWork) {
686             super.beginTask(name, totalWork);
687             subTask(IDEWorkbenchMessages.IDEWorkbenchAdvisor_preHistoryCompaction);
688         }
689
690         private void updateProgressDetails() {
691             if (!isCanceled() && Math.abs(total - 4.0) < 0.0001 /* right before history compacting */) {
692                 subTask(IDEWorkbenchMessages.IDEWorkbenchAdvisor_cancelHistoryPruning);
693                 dialog.setCancelable(true);
694             }
695             if (Math.abs(total - 5.0) < 0.0001 /* history compacting finished */) {
696                 subTask(IDEWorkbenchMessages.IDEWorkbenchAdvisor_postHistoryCompaction);
697                 dialog.setCancelable(false);
698             }
699         }
700     }
701
702     private static class CancelableProgressMonitorJobsDialog extends ProgressMonitorJobsDialog {
703
704         public CancelableProgressMonitorJobsDialog(Shell parent) {
705             super(parent);
706         }
707
708         /*
709          * (non-Javadoc)
710          * @see org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog#createDetailsButton(org.eclipse.swt.widgets.Composite)
711          */
712         protected void createButtonsForButtonBar(Composite parent) {
713             super.createButtonsForButtonBar(parent);
714             registerCancelButtonListener();
715         }
716
717         public void registerCancelButtonListener() {
718             cancel.addSelectionListener(new SelectionAdapter() {
719                 public void widgetSelected(SelectionEvent e) {
720                     subTaskLabel.setText(""); //$NON-NLS-1$
721                 }
722             });
723         }
724     }
725
726
727     final IRunnableWithProgress platformShutdownRunnable = new IRunnableWithProgress() {
728         /**
729          * @param monitor
730          *            the progress monitor to use for reporting progress to the
731          *            user, or <code>null</code> indicating that no progress
732          *            should be reported and the operation cannot be cancelled.
733          */
734         @Override
735         public void run(IProgressMonitor monitor) {
736             SubMonitor progress = SubMonitor.convert(monitor, SHUT_DOWN_PLATFORM_TASK, 100);
737             try {
738                 try {
739                     progress.subTask("Platform");
740                     SimanticsPlatform.INSTANCE.shutdown(progress.newChild(50));
741                 } catch (PlatformException e) {
742                     Activator.logError("Problems encountered while shutting down Simantics platform, see exception for details.", e);
743                 }
744
745                 progress.subTask("Remaining database connections");
746                 SimanticsUI.closeSessions();
747                 progress.worked(20);
748                 TimedSessionCache.close();
749                 progress.worked(20);
750
751                 progress.subTask("Thread pools");
752                 ThreadUtils.shutdown();
753                 ExecutorWorker.shutdown();
754                 progress.worked(5);
755
756                 progress.subTask("Clear index status");
757                 try {
758                     // Everything ok, clear index dirty state.
759                     DatabaseIndexing.clearAllDirty();
760                 } catch (IOException e) {
761                     Activator.logError("Problems encountered while refreshing database index states, see exception for details.", e);
762                 }
763                 progress.worked(5);
764
765                 progress.setWorkRemaining(0);
766             } finally {
767                 if (monitor != null) {
768                     monitor.done();
769                 }
770             }
771         }
772     };
773
774     /**
775      * Disconnect from the workspace and close ProCore sessions.
776      */
777     private void disconnectFromWorkspace() {
778         // save the workspace
779         final MultiStatus status = new MultiStatus(
780                 IDEWorkbenchPlugin.IDE_WORKBENCH, 1,
781                 IDEWorkbenchMessages.ProblemSavingWorkbench, null);
782
783         final ProgressMonitorJobsDialog p = new CancelableProgressMonitorJobsDialog(
784                 null);
785
786         final boolean applyPolicy = ResourcesPlugin.getWorkspace()
787                 .getDescription().isApplyFileStatePolicy();
788
789         final IRunnableWithProgress workspaceShutdownRunnable = new IRunnableWithProgress() {
790             @Override
791             public void run(IProgressMonitor monitor) {
792                 try {
793                     status.merge(((Workspace) ResourcesPlugin.getWorkspace()).save(true, true, monitor));
794                 } catch (CoreException e) {
795                     status.merge(e.getStatus());
796                 }
797             }
798         };
799
800         IRunnableWithProgress shutdownRunnable = new IRunnableWithProgress() {
801             @Override
802             public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
803                 if (applyPolicy)
804                     monitor = new CancelableProgressMonitorWrapper(
805                             monitor, p);
806
807                 SubMonitor progress = SubMonitor.convert(monitor, SHUT_DOWN_TASK, 2);
808                 try {
809                     workspaceShutdownRunnable.run(progress.newChild(1, SubMonitor.SUPPRESS_NONE));
810                     platformShutdownRunnable.run(progress.newChild(1, SubMonitor.SUPPRESS_NONE));
811                 } finally {
812                     monitor.done();
813                 }
814             }
815         };
816
817         try {
818             new ProgressMonitorJobsDialog(null).run(true, false, shutdownRunnable);
819         } catch (InvocationTargetException e) {
820             status.merge(new Status(IStatus.ERROR,
821                     IDEWorkbenchPlugin.IDE_WORKBENCH, 1,
822                     IDEWorkbenchMessages.InternalError, e.getTargetException()));
823         } catch (InterruptedException e) {
824             status.merge(new Status(IStatus.ERROR,
825                     IDEWorkbenchPlugin.IDE_WORKBENCH, 1,
826                     IDEWorkbenchMessages.InternalError, e));
827         }
828         ErrorDialog.openError(null,
829                 IDEWorkbenchMessages.ProblemsSavingWorkspace, null, status,
830                 IStatus.ERROR | IStatus.WARNING);
831         if (!status.isOK()) {
832             IDEWorkbenchPlugin.log(
833                     IDEWorkbenchMessages.ProblemsSavingWorkspace, status);
834         }
835     }
836
837     /*
838      * (non-Javadoc)
839      *
840      * @see org.eclipse.ui.application.WorkbenchAdvisor#getDefaultPageInput
841      */
842     @Override
843     public IAdaptable getDefaultPageInput() {
844         return ResourcesPlugin.getWorkspace().getRoot();
845     }
846
847     /*
848      * (non-Javadoc)
849      *
850      * @see org.eclipse.ui.application.WorkbenchAdvisor
851      */
852     @Override
853     public String getInitialWindowPerspectiveId() {
854         int index = PlatformUI.getWorkbench().getWorkbenchWindowCount() - 1;
855
856         String perspectiveId = null;
857         AboutInfo[] welcomeInfos = getWelcomePerspectiveInfos();
858         if (index >= 0 && welcomeInfos != null && index < welcomeInfos.length) {
859             perspectiveId = welcomeInfos[index].getWelcomePerspectiveId();
860         }
861
862         if (perspectiveId == null && args.contains(SimanticsArguments.PERSPECTIVE)) {
863             String id = args.get(SimanticsArguments.PERSPECTIVE);
864             IPerspectiveDescriptor perspective = PlatformUI.getWorkbench().getPerspectiveRegistry().findPerspectiveWithId(id);
865             if (perspective != null)
866                 perspectiveId = id;
867         }
868
869         if (perspectiveId == null) {
870             IProject project = SimanticsUI.peekProject();
871             if (project != null)
872                 perspectiveId = project.getHint(ProjectKeys.DEFAULT_PERSPECTIVE);
873         }
874
875         //System.out.println("Initial perspective: " + perspectiveId);
876
877         return perspectiveId;
878     }
879
880     /**
881      * Returns the map of versioned feature ids -> info object for all installed
882      * features. The format of the versioned feature id (the key of the map) is
883      * featureId + ":" + versionId.
884      *
885      * @return map of versioned feature ids -> info object (key type:
886      *         <code>String</code>, value type: <code>AboutInfo</code>)
887      * @since 3.0
888      */
889     private Map<String, AboutInfo> computeBundleGroupMap() {
890         // use tree map to get predicable order
891         Map<String, AboutInfo> ids = new TreeMap<String, AboutInfo>();
892
893         IBundleGroupProvider[] providers = Platform.getBundleGroupProviders();
894         for (int i = 0; i < providers.length; ++i) {
895             IBundleGroup[] groups = providers[i].getBundleGroups();
896             for (int j = 0; j < groups.length; ++j) {
897                 IBundleGroup group = groups[j];
898                 AboutInfo info = new AboutInfo(group);
899
900                 String version = info.getVersionId();
901                 version = version == null ? "0.0.0" //$NON-NLS-1$
902                         : new Version(version).toString();
903                 String versionedFeature = group.getIdentifier() + ":" + version; //$NON-NLS-1$
904
905                 ids.put(versionedFeature, info);
906             }
907         }
908
909         return ids;
910     }
911
912     /**
913      * Returns the ordered map of versioned feature ids -> AboutInfo that are
914      * new for this session.
915      *
916      * @return ordered map of versioned feature ids (key type:
917      *         <code>String</code>) -> infos (value type:
918      *         <code>AboutInfo</code>).
919      */
920     public Map<String, AboutInfo> getNewlyAddedBundleGroups() {
921         if (newlyAddedBundleGroups == null) {
922             newlyAddedBundleGroups = createNewBundleGroupsMap();
923         }
924         return newlyAddedBundleGroups;
925     }
926
927     /**
928      * Updates the old features setting and returns a map of new features.
929      */
930     private Map<String, AboutInfo> createNewBundleGroupsMap() {
931         // retrieve list of installed bundle groups from last session
932         IDialogSettings settings = IDEWorkbenchPlugin.getDefault()
933                 .getDialogSettings();
934         String[] previousFeaturesArray = settings.getArray(INSTALLED_FEATURES);
935
936         // get a map of currently installed bundle groups and store it for next
937         // session
938         Map<String, AboutInfo> bundleGroups = computeBundleGroupMap();
939         String[] currentFeaturesArray = new String[bundleGroups.size()];
940         bundleGroups.keySet().toArray(currentFeaturesArray);
941         settings.put(INSTALLED_FEATURES, currentFeaturesArray);
942
943         // remove the previously known from the current set
944         if (previousFeaturesArray != null) {
945             for (int i = 0; i < previousFeaturesArray.length; ++i) {
946                 bundleGroups.remove(previousFeaturesArray[i]);
947             }
948         }
949
950         return bundleGroups;
951     }
952
953     /**
954      * Declares all IDE-specific workbench images. This includes both "shared"
955      * images (named in {@link IDE.SharedImages}) and internal images (named in
956      * {@link org.eclipse.ui.internal.ide.IDEInternalWorkbenchImages}).
957      *
958      * @see IWorkbenchConfigurer#declareImage
959      */
960     private void declareWorkbenchImages() {
961
962         final String ICONS_PATH = "$nl$/icons/full/";//$NON-NLS-1$
963         final String PATH_ELOCALTOOL = ICONS_PATH + "elcl16/"; // Enabled //$NON-NLS-1$
964
965         // toolbar
966         // icons.
967         final String PATH_DLOCALTOOL = ICONS_PATH + "dlcl16/"; // Disabled //$NON-NLS-1$
968         // //$NON-NLS-1$
969         // toolbar
970         // icons.
971         final String PATH_ETOOL = ICONS_PATH + "etool16/"; // Enabled toolbar //$NON-NLS-1$
972         // //$NON-NLS-1$
973         // icons.
974         final String PATH_DTOOL = ICONS_PATH + "dtool16/"; // Disabled toolbar //$NON-NLS-1$
975         // //$NON-NLS-1$
976         // icons.
977         final String PATH_OBJECT = ICONS_PATH + "obj16/"; // Model object //$NON-NLS-1$
978         // //$NON-NLS-1$
979         // icons
980         final String PATH_WIZBAN = ICONS_PATH + "wizban/"; // Wizard //$NON-NLS-1$
981         // //$NON-NLS-1$
982         // icons
983
984         Bundle ideBundle = Platform.getBundle(IDEWorkbenchPlugin.IDE_WORKBENCH);
985
986         declareWorkbenchImage(ideBundle,
987                 IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC, PATH_ETOOL
988                 + "build_exec.gif", false); //$NON-NLS-1$
989         declareWorkbenchImage(ideBundle,
990                 IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC_HOVER,
991                 PATH_ETOOL + "build_exec.gif", false); //$NON-NLS-1$
992         declareWorkbenchImage(ideBundle,
993                 IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC_DISABLED,
994                 PATH_DTOOL + "build_exec.gif", false); //$NON-NLS-1$
995
996         declareWorkbenchImage(ideBundle,
997                 IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC, PATH_ETOOL
998                 + "search_src.gif", false); //$NON-NLS-1$
999         declareWorkbenchImage(ideBundle,
1000                 IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC_HOVER,
1001                 PATH_ETOOL + "search_src.gif", false); //$NON-NLS-1$
1002         declareWorkbenchImage(ideBundle,
1003                 IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC_DISABLED,
1004                 PATH_DTOOL + "search_src.gif", false); //$NON-NLS-1$
1005
1006         declareWorkbenchImage(ideBundle,
1007                 IDEInternalWorkbenchImages.IMG_ETOOL_NEXT_NAV, PATH_ETOOL
1008                 + "next_nav.gif", false); //$NON-NLS-1$
1009
1010         declareWorkbenchImage(ideBundle,
1011                 IDEInternalWorkbenchImages.IMG_ETOOL_PREVIOUS_NAV, PATH_ETOOL
1012                 + "prev_nav.gif", false); //$NON-NLS-1$
1013
1014         declareWorkbenchImage(ideBundle,
1015                 IDEInternalWorkbenchImages.IMG_WIZBAN_NEWPRJ_WIZ, PATH_WIZBAN
1016                 + "newprj_wiz.png", false); //$NON-NLS-1$
1017         declareWorkbenchImage(ideBundle,
1018                 IDEInternalWorkbenchImages.IMG_WIZBAN_NEWFOLDER_WIZ,
1019                 PATH_WIZBAN + "newfolder_wiz.png", false); //$NON-NLS-1$
1020         declareWorkbenchImage(ideBundle,
1021                 IDEInternalWorkbenchImages.IMG_WIZBAN_NEWFILE_WIZ, PATH_WIZBAN
1022                 + "newfile_wiz.png", false); //$NON-NLS-1$
1023
1024         declareWorkbenchImage(ideBundle,
1025                 IDEInternalWorkbenchImages.IMG_WIZBAN_IMPORTDIR_WIZ,
1026                 PATH_WIZBAN + "importdir_wiz.png", false); //$NON-NLS-1$
1027         declareWorkbenchImage(ideBundle,
1028                 IDEInternalWorkbenchImages.IMG_WIZBAN_IMPORTZIP_WIZ,
1029                 PATH_WIZBAN + "importzip_wiz.png", false); //$NON-NLS-1$
1030
1031         declareWorkbenchImage(ideBundle,
1032                 IDEInternalWorkbenchImages.IMG_WIZBAN_EXPORTDIR_WIZ,
1033                 PATH_WIZBAN + "exportdir_wiz.png", false); //$NON-NLS-1$
1034         declareWorkbenchImage(ideBundle,
1035                 IDEInternalWorkbenchImages.IMG_WIZBAN_EXPORTZIP_WIZ,
1036                 PATH_WIZBAN + "exportzip_wiz.png", false); //$NON-NLS-1$
1037
1038         declareWorkbenchImage(ideBundle,
1039                 IDEInternalWorkbenchImages.IMG_WIZBAN_RESOURCEWORKINGSET_WIZ,
1040                 PATH_WIZBAN + "workset_wiz.png", false); //$NON-NLS-1$
1041
1042         declareWorkbenchImage(ideBundle,
1043                 IDEInternalWorkbenchImages.IMG_DLGBAN_SAVEAS_DLG, PATH_WIZBAN
1044                 + "saveas_wiz.png", false); //$NON-NLS-1$
1045
1046         declareWorkbenchImage(ideBundle,
1047                 IDEInternalWorkbenchImages.IMG_DLGBAN_QUICKFIX_DLG, PATH_WIZBAN
1048                 + "quick_fix.png", false); //$NON-NLS-1$
1049
1050         declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJ_PROJECT,
1051                 PATH_OBJECT + "prj_obj.gif", true); //$NON-NLS-1$
1052         declareWorkbenchImage(ideBundle,
1053                 IDE.SharedImages.IMG_OBJ_PROJECT_CLOSED, PATH_OBJECT
1054                 + "cprj_obj.gif", true); //$NON-NLS-1$
1055         declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OPEN_MARKER,
1056                 PATH_ELOCALTOOL + "gotoobj_tsk.gif", true); //$NON-NLS-1$
1057
1058         declareWorkbenchImage(ideBundle,
1059                 IDEInternalWorkbenchImages.IMG_ELCL_QUICK_FIX_ENABLED,
1060                 PATH_ELOCALTOOL + "smartmode_co.gif", true); //$NON-NLS-1$
1061
1062         declareWorkbenchImage(ideBundle,
1063                 IDEInternalWorkbenchImages.IMG_DLCL_QUICK_FIX_DISABLED,
1064                 PATH_DLOCALTOOL + "smartmode_co.gif", true); //$NON-NLS-1$
1065
1066         // task objects
1067         // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_HPRIO_TSK,
1068         // PATH_OBJECT+"hprio_tsk.gif");
1069         // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_MPRIO_TSK,
1070         // PATH_OBJECT+"mprio_tsk.gif");
1071         // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_LPRIO_TSK,
1072         // PATH_OBJECT+"lprio_tsk.gif");
1073
1074         declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJS_TASK_TSK,
1075                 PATH_OBJECT + "taskmrk_tsk.gif", true); //$NON-NLS-1$
1076         declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJS_BKMRK_TSK,
1077                 PATH_OBJECT + "bkmrk_tsk.gif", true); //$NON-NLS-1$
1078
1079         declareWorkbenchImage(ideBundle,
1080                 IDEInternalWorkbenchImages.IMG_OBJS_COMPLETE_TSK, PATH_OBJECT
1081                 + "complete_tsk.gif", true); //$NON-NLS-1$
1082         declareWorkbenchImage(ideBundle,
1083                 IDEInternalWorkbenchImages.IMG_OBJS_INCOMPLETE_TSK, PATH_OBJECT
1084                 + "incomplete_tsk.gif", true); //$NON-NLS-1$
1085         declareWorkbenchImage(ideBundle,
1086                 IDEInternalWorkbenchImages.IMG_OBJS_WELCOME_ITEM, PATH_OBJECT
1087                 + "welcome_item.gif", true); //$NON-NLS-1$
1088         declareWorkbenchImage(ideBundle,
1089                 IDEInternalWorkbenchImages.IMG_OBJS_WELCOME_BANNER, PATH_OBJECT
1090                 + "welcome_banner.gif", true); //$NON-NLS-1$
1091         declareWorkbenchImage(ideBundle,
1092                 IDEInternalWorkbenchImages.IMG_OBJS_ERROR_PATH, PATH_OBJECT
1093                 + "error_tsk.gif", true); //$NON-NLS-1$
1094         declareWorkbenchImage(ideBundle,
1095                 IDEInternalWorkbenchImages.IMG_OBJS_WARNING_PATH, PATH_OBJECT
1096                 + "warn_tsk.gif", true); //$NON-NLS-1$
1097         declareWorkbenchImage(ideBundle,
1098                 IDEInternalWorkbenchImages.IMG_OBJS_INFO_PATH, PATH_OBJECT
1099                 + "info_tsk.gif", true); //$NON-NLS-1$
1100
1101         declareWorkbenchImage(ideBundle,
1102                 IDEInternalWorkbenchImages.IMG_LCL_FLAT_LAYOUT, PATH_ELOCALTOOL
1103                 + "flatLayout.gif", true); //$NON-NLS-1$
1104         declareWorkbenchImage(ideBundle,
1105                 IDEInternalWorkbenchImages.IMG_LCL_HIERARCHICAL_LAYOUT,
1106                 PATH_ELOCALTOOL + "hierarchicalLayout.gif", true); //$NON-NLS-1$
1107         declareWorkbenchImage(ideBundle,
1108                 IDEInternalWorkbenchImages.IMG_ETOOL_PROBLEM_CATEGORY,
1109                 PATH_ETOOL + "problem_category.gif", true); //$NON-NLS-1$
1110         /*
1111         declareWorkbenchImage(ideBundle,
1112                 IDEInternalWorkbenchImages.IMG_LCL_LINKTO_HELP, PATH_ELOCALTOOL
1113                         + "linkto_help.gif", false); //$NON-NLS-1$
1114          */
1115
1116         // synchronization indicator objects
1117         // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_WBET_STAT,
1118         // PATH_OVERLAY+"wbet_stat.gif");
1119         // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_SBET_STAT,
1120         // PATH_OVERLAY+"sbet_stat.gif");
1121         // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_CONFLICT_STAT,
1122         // PATH_OVERLAY+"conflict_stat.gif");
1123
1124         // content locality indicator objects
1125         // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_NOTLOCAL_STAT,
1126         // PATH_STAT+"notlocal_stat.gif");
1127         // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_LOCAL_STAT,
1128         // PATH_STAT+"local_stat.gif");
1129         // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_FILLLOCAL_STAT,
1130         // PATH_STAT+"filllocal_stat.gif");
1131     }
1132
1133     /**
1134      * Declares an IDE-specific workbench image.
1135      *
1136      * @param symbolicName
1137      *            the symbolic name of the image
1138      * @param path
1139      *            the path of the image file; this path is relative to the base
1140      *            of the IDE plug-in
1141      * @param shared
1142      *            <code>true</code> if this is a shared image, and
1143      *            <code>false</code> if this is not a shared image
1144      * @see IWorkbenchConfigurer#declareImage
1145      */
1146     private void declareWorkbenchImage(Bundle ideBundle, String symbolicName,
1147             String path, boolean shared) {
1148         URL url = FileLocator.find(ideBundle, new Path(path), null);
1149         ImageDescriptor desc = ImageDescriptor.createFromURL(url);
1150         getWorkbenchConfigurer().declareImage(symbolicName, desc, shared);
1151     }
1152
1153     /*
1154      * (non-Javadoc)
1155      *
1156      * @see org.eclipse.ui.application.WorkbenchAdvisor#getMainPreferencePageId
1157      */
1158     @Override
1159     public String getMainPreferencePageId() {
1160         // indicate that we want the Workench preference page to be prominent
1161         return WORKBENCH_PREFERENCE_CATEGORY_ID;
1162     }
1163
1164     /**
1165      * @return the workspace location string, or <code>null</code> if the
1166      *         location is not being shown
1167      */
1168     public String getWorkspaceLocation() {
1169                 // read command line, which has priority
1170                 IEclipseContext context = getWorkbenchConfigurer().getWorkbench().getService(IEclipseContext.class);
1171                 String location = context != null ? (String) context.get(E4Workbench.FORCED_SHOW_LOCATION) : null;
1172                 if (location != null) {
1173                         return location;
1174                 }
1175                 // read the preference
1176                 if (IDEWorkbenchPlugin.getDefault().getPreferenceStore().getBoolean(IDEInternalPreferences.SHOW_LOCATION)) {
1177                         return Platform.getLocation().toOSString();
1178                 }
1179                 return null;
1180     }
1181
1182     /**
1183      * @return the welcome perspective infos, or <code>null</code> if none or
1184      *         if they should be ignored due to the new intro being present
1185      */
1186     public AboutInfo[] getWelcomePerspectiveInfos() {
1187         if (welcomePerspectiveInfos == null) {
1188             // support old welcome perspectives if intro plugin is not present
1189             if (!hasIntro()) {
1190                 Map<String, AboutInfo> m = getNewlyAddedBundleGroups();
1191                 ArrayList<AboutInfo> list = new ArrayList<AboutInfo>(m.size());
1192                 for (Iterator<AboutInfo> i = m.values().iterator(); i.hasNext();) {
1193                     AboutInfo info = i.next();
1194                     if (info != null && info.getWelcomePerspectiveId() != null
1195                             && info.getWelcomePageURL() != null) {
1196                         list.add(info);
1197                     }
1198                 }
1199                 welcomePerspectiveInfos = new AboutInfo[list.size()];
1200                 list.toArray(welcomePerspectiveInfos);
1201             }
1202         }
1203         return welcomePerspectiveInfos;
1204     }
1205
1206     /*
1207      * (non-Javadoc)
1208      *
1209      * @see org.eclipse.ui.application.WorkbenchAdvisor#getWorkbenchErrorHandler()
1210      */
1211     @Override
1212     public AbstractStatusHandler getWorkbenchErrorHandler() {
1213         if (ideWorkbenchErrorHandler == null) {
1214             ideWorkbenchErrorHandler = new IDEWorkbenchErrorHandler(
1215                     getWorkbenchConfigurer());
1216         }
1217         return ideWorkbenchErrorHandler;
1218     }
1219
1220     /* (non-Javadoc)
1221      * @see org.eclipse.ui.application.WorkbenchAdvisor#eventLoopIdle(org.eclipse.swt.widgets.Display)
1222      */
1223     @Override
1224     public void eventLoopIdle(Display display) {
1225         if (delayedEventsProcessor != null)
1226             delayedEventsProcessor.catchUp(display);
1227         super.eventLoopIdle(display);
1228     }
1229
1230 }