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