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