/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.workbench.internal; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.text.Collator; import java.util.ArrayList; import java.util.Iterator; import java.util.Map; import java.util.TreeMap; import org.eclipse.core.internal.resources.Workspace; import org.eclipse.core.net.proxy.IProxyService; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.resources.WorkspaceJob; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IBundleGroup; import org.eclipse.core.runtime.IBundleGroupProvider; import org.eclipse.core.runtime.ILog; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.ProgressMonitorWrapper; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.e4.core.contexts.IEclipseContext; import org.eclipse.e4.ui.internal.workbench.E4Workbench; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.TrayDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.util.Policy; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IPerspectiveDescriptor; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.application.IWorkbenchConfigurer; import org.eclipse.ui.application.IWorkbenchWindowConfigurer; import org.eclipse.ui.application.WorkbenchAdvisor; import org.eclipse.ui.application.WorkbenchWindowAdvisor; import org.eclipse.ui.ide.IDE; import org.eclipse.ui.internal.ISelectionConversionService; import org.eclipse.ui.internal.Workbench; import org.eclipse.ui.internal.ide.AboutInfo; import org.eclipse.ui.internal.ide.IDEInternalPreferences; import org.eclipse.ui.internal.ide.IDEInternalWorkbenchImages; import org.eclipse.ui.internal.ide.IDESelectionConversionService; import org.eclipse.ui.internal.ide.IDEWorkbenchActivityHelper; import org.eclipse.ui.internal.ide.IDEWorkbenchErrorHandler; import org.eclipse.ui.internal.ide.IDEWorkbenchMessages; import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin; import org.eclipse.ui.internal.ide.undo.WorkspaceUndoMonitor; import org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog; import org.eclipse.ui.keys.IBindingService; import org.eclipse.ui.progress.IProgressService; import org.eclipse.ui.statushandlers.AbstractStatusHandler; import org.osgi.framework.Bundle; import org.osgi.framework.ServiceReference; import org.osgi.framework.Version; import org.simantics.CancelStartupException; import org.simantics.PlatformException; import org.simantics.Simantics; import org.simantics.SimanticsPlatform; import org.simantics.SimanticsPlatform.OntologyRecoveryPolicy; import org.simantics.SimanticsPlatform.RecoveryPolicy; import org.simantics.application.arguments.IArguments; import org.simantics.application.arguments.SimanticsArguments; import org.simantics.db.common.Indexing; import org.simantics.db.indexing.DatabaseIndexing; import org.simantics.db.procore.server.environment.RebootRequiredException; import org.simantics.db.procore.server.environment.windows.Product; import org.simantics.db.procore.ui.ProCoreUserAgent; import org.simantics.internal.TimedSessionCache; import org.simantics.project.IProject; import org.simantics.project.ProjectKeys; import org.simantics.ui.SimanticsUI; import org.simantics.ui.jobs.SessionGarbageCollectorJob; import org.simantics.ui.workbench.PerspectiveBarsActivator; import org.simantics.ui.workbench.PerspectiveContextActivator; import org.simantics.utils.logging.TimeLogger; import org.simantics.utils.threads.ThreadUtils; import org.simantics.utils.ui.dialogs.ShowError; import org.simantics.utils.ui.dialogs.ShowMessage; /** * @author Tuukka Lehtonen */ public class SimanticsWorkbenchAdvisor extends WorkbenchAdvisor { private static final boolean PROFILE_PLATFORM_STARTUP = false; private static final String SHUT_DOWN_TASK = "Shutting down..."; private static final String SHUT_DOWN_PLATFORM_TASK = "Shutting down platform..."; private static final String WORKBENCH_PREFERENCE_CATEGORY_ID = "org.eclipse.ui.preferencePages.Workbench"; //$NON-NLS-1$ /** * The dialog setting key to access the known installed features since the * last time the workbench was run. */ private static final String INSTALLED_FEATURES = "installedFeatures"; //$NON-NLS-1$ /** * Default database ID */ private static final String DEFAULT_DATABASE_ID = "acorn"; /** * The arguments received by the application. */ protected final IArguments args; protected final boolean restoredPreviousSession = false; /** * Only true while opening the initial windows during {@link #openWindows()}. * Used by {@link SimanticsWorkbenchWindowAdvisor#postWindowOpen()} to * recognize when to skip all one-time initialization. */ protected boolean workbenchWindowsInitialized = false; /** * Whether or not to save unsaved database changes before exiting the * workbench. */ protected boolean saveAtExit = false; /** * Ordered map of versioned feature ids -> info that are new for this * session; null if uninitialized. Key type: * String, Value type: AboutInfo. */ private Map newlyAddedBundleGroups; /** * Array of AboutInfo for all new installed features that * specify a welcome perspective. */ private AboutInfo[] welcomePerspectiveInfos = null; /** * Helper for managing activites in response to workspace changes. */ private IDEWorkbenchActivityHelper activityHelper = null; /** * Helper for managing work that is performed when the system is otherwise * idle. */ private IDEIdleHelper idleHelper; private Listener settingsChangeListener; /** * Support class for monitoring workspace changes and periodically * validating the undo history */ private WorkspaceUndoMonitor workspaceUndoMonitor; /** * The IDE workbench error handler. */ private AbstractStatusHandler ideWorkbenchErrorHandler; /** * Helper class used to process delayed events. */ private DelayedEventsProcessor delayedEventsProcessor; /** * Creates a new workbench advisor instance. * @param processor */ public SimanticsWorkbenchAdvisor(IArguments args, DelayedEventsProcessor processor) { super(); this.args = args; this.delayedEventsProcessor = processor; Listener closeListener = new Listener() { public void handleEvent(Event event) { boolean doExit = SimanticsWorkbenchWindowAdvisor.promptOnExit(null); event.doit = doExit; if (!doExit) event.type = SWT.None; } }; Display.getDefault().addListener(SWT.Close, closeListener); } public IArguments getArguments() { return args; } public boolean workbenchInitialized() { return workbenchWindowsInitialized; } public boolean restoredPreviousSession() { return restoredPreviousSession; } boolean saveAtExit() { return saveAtExit; } void setSaveAtExit(boolean saveAtExit) { this.saveAtExit = saveAtExit; } /* * (non-Javadoc) * * @see org.eclipse.ui.application.WorkbenchAdvisor#initialize */ @Override public void initialize(IWorkbenchConfigurer configurer) { // By default, we always save and restore the workbench state. configurer.setSaveAndRestore(true); checkWorkspaceDatabaseIndexes(); // Start tracking the active perspective to activate contexts based on it. new PerspectiveContextActivator(); new PerspectiveBarsActivator(); // register workspace adapters IDE.registerAdapters(); // register shared images declareWorkbenchImages(); // initialize the activity helper activityHelper = IDEWorkbenchActivityHelper.getInstance(); // initialize idle handler idleHelper = new IDEIdleHelper(configurer); // initialize the workspace undo monitor workspaceUndoMonitor = WorkspaceUndoMonitor.getInstance(); // show Help button in JFace dialogs TrayDialog.setDialogHelpAvailable(true); Policy.setComparator(Collator.getInstance()); } private void checkWorkspaceDatabaseIndexes() { try { DatabaseIndexing.validateIndexes(); } catch (IOException e) { Activator.logError("Problems encountered while checking database indexes, see exception for details.", e); } } public WorkbenchWindowAdvisor createWorkbenchWindowAdvisorClass(SimanticsWorkbenchAdvisor advisor, IWorkbenchWindowConfigurer configurer) { return new SimanticsWorkbenchWindowAdvisor(this, configurer); } @Override public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) { // Attach database session watchdog. new SessionWatchdog().attach( Simantics.getSessionContextProvider() ); return createWorkbenchWindowAdvisorClass(this, configurer); } /** * For gaining direct access to super.openWindows() in implementations * inheriting this one. */ public boolean openWindowsSuper() { return super.openWindows(); } /** * Sadly we do not know why key bindings are lost and why this helps. But it * does. Visiting the Keys preference page and pressing OK uses * this the same call and it seems to salvage the bindings that have been in * some cases destroyed by BindingToModelProcessor. * *

* Related links: * https://techblog.ralph-schuster.eu/2013/10/13/eclipsee4-problem-with-key-bindings/comment-page-1/ * https://www.eclipse.org/forums/index.php/t/550175/ * https://bugs.eclipse.org/bugs/show_bug.cgi?id=461037 * * @see platform issue #6353 */ private void fixBindings() { try { IBindingService bs = PlatformUI.getWorkbench().getAdapter(IBindingService.class); bs.savePreferences(bs.getActiveScheme(), bs.getBindings()); } catch (IOException e) { Activator.logError(getClass().getSimpleName() + ".fixBindings failed", e); } } @Override public boolean openWindows() { boolean platformOk = startPlatform(); TimeLogger.log("SimanticsWorkbenchAdvisor.startPlatform finished"); if (platformOk) { // At this point workbenchConfigurer.getSaveAndRestore() // returns false iff something has gone terribly wrong // before this. Currently saveAndRestore is always true. boolean windowsOpened = super.openWindows(); TimeLogger.log("Opened windows"); if (windowsOpened) { workbenchWindowsInitialized = true; // Start the database garbage collector after a short while. SessionGarbageCollectorJob.getInstance().scheduleAfterQuietTime(); // Discard database session undo history at this point to prevent // the user from undoing any initialization operations performed // by the platform startup. SimanticsPlatform.INSTANCE.discardSessionUndoHistory(); TimeLogger.log("Discarded session undo history"); // #6353: Workaround for fixBindings(); return true; } } // Make sure platform shutdown is ran if window opening fails. try { platformShutdownRunnable.run(null); } catch (InvocationTargetException e) { Activator.logError(getClass().getSimpleName() + ".openWindows failed", e); } catch (InterruptedException e) { Activator.logError(getClass().getSimpleName() + ".openWindows failed", e); } return false; } protected boolean startPlatform() { // Verify selected perspective if (args.contains(SimanticsArguments.PERSPECTIVE)) { String perspectiveId = args.get(SimanticsArguments.PERSPECTIVE); IPerspectiveDescriptor perspective = PlatformUI.getWorkbench().getPerspectiveRegistry().findPerspectiveWithId(perspectiveId); if (perspective == null) { StringBuilder msg = new StringBuilder(); msg.append("Requested perspective not found: '" + perspectiveId + "'\n"); msg.append("Valid alternatives are:\n"); for (IPerspectiveDescriptor pd : PlatformUI.getWorkbench().getPerspectiveRegistry().getPerspectives()) { msg.append(" " + pd.getId() + "\n"); } ShowMessage.syncShowError("Invalid Perspective", msg.toString()); return false; } } ILog log = Platform.getLog(Activator.getDefault().getBundle()); try { // // // Create Simantics Platform Helper. // // If Simantics is started from Eclipse IDE or with -fixerrors option, // there is an attempt to fix errors. // // On ontology mismatch, there is an attempt to merge new ontology to the // existing database. With -reinstall, the database is cleaned and // reinstalled. // // RecoveryPolicy workspacePolicy = Platform.inDevelopmentMode() ? RecoveryPolicy.FixError : RecoveryPolicy.ThrowError; OntologyRecoveryPolicy ontologyPolicy = Platform.inDevelopmentMode() ? OntologyRecoveryPolicy.Merge : OntologyRecoveryPolicy.ThrowError; if (args.contains(SimanticsArguments.RECOVERY_POLICY_FIX_ERRORS)) { workspacePolicy = RecoveryPolicy.FixError; ontologyPolicy = OntologyRecoveryPolicy.Merge; } boolean requireSynchronize = true; if (args.contains(SimanticsArguments.ONTOLOGY_RECOVERY_POLICY_REINSTALL)) { ontologyPolicy = OntologyRecoveryPolicy.ReinstallDatabase; } if (args.contains(SimanticsArguments.DO_NOT_SYNCHRONIZE_ONTOLOGIES)) { requireSynchronize = false; } if (args.contains(SimanticsArguments.DISABLE_INDEX)) { Indexing.setDefaultDependenciesIndexingEnabled(false); } if (args.contains(SimanticsArguments.SERVER)) { String serverAddress = args.get(SimanticsArguments.SERVER); throw new PlatformException("Argument not supported: " + SimanticsArguments.SERVER + " " + serverAddress); } // TODO: Default to procore for now; String databaseId = DEFAULT_DATABASE_ID; if (args.contains(SimanticsArguments.DATABASE_ID)) { databaseId = args.get(SimanticsArguments.DATABASE_ID); } IProgressMonitor mon = null; if (PROFILE_PLATFORM_STARTUP) mon = new TimingProgressMonitor(); IWorkbench wb = PlatformUI.getWorkbench(); SimanticsPlatform.INSTANCE.startUp(databaseId, mon, workspacePolicy, ontologyPolicy, requireSynchronize, new JFaceUserAgent()); // Make sure that the default perspective comes from the project if // the project has set ProjectKeys#DEFAULT_PERSPECTIVE. // This might go wrong if project features interact with // PerspectiveRegistry while configuring themselves, since that will // cause an invocation to #getInitialWindowPerspectiveId() while // the project has not yet been properly initialized. getWorkbenchConfigurer().getWorkbench().getPerspectiveRegistry().setDefaultPerspective(getInitialWindowPerspectiveId()); TimeLogger.log("Completed setting default perspective"); return true; } catch (CancelStartupException e) { return false; } catch (PlatformException e) { boolean hasStackTrace = e.getStackTrace().length > 0; Throwable ee = e; while (ee.getCause() != null) { ee = ee.getCause(); hasStackTrace = ee.getStackTrace().length > 0; } log.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), hasStackTrace ? e : null)); if (hasStackTrace) { new ShowError("Platform Initialization Failed", "Simantics Platform initialization failed:\n\n" + e.getMessage(), e, true); } else { StringBuilder sb = new StringBuilder(256); sb.append(e.getMessage()); for (Throwable c=e.getCause(); null != c && null != c.getMessage(); c=c.getCause()) sb.append("\ncause: ").append(c.getMessage()); new ShowError("Startup Failed", sb.toString(), (Exception) null, true); } return false; } catch (Exception e) { log.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e)); Throwable cause = e.getCause(); if (cause instanceof RebootRequiredException) { RebootRequiredException rre = (RebootRequiredException) cause; StringBuilder msg = new StringBuilder(); msg.append("The application must be restarted after installing the following products:\n"); for (Product product : rre.products) msg.append("\t" + product + "\n"); msg.append("\nThe application will now close."); MessageDialog.openInformation(null, "Restart Required", msg.toString()); } else { new ShowError("Platform Startup Failed", "Simantics Platform startup failed:\n\n" + e.getMessage(), e, true); } return false; } } /* * (non-Javadoc) * * @see org.eclipse.ui.application.WorkbenchAdvisor#preStartup() */ @Override public void preStartup() { // Suspend background jobs while we startup Job.getJobManager().suspend(); // Register the build actions IProgressService service = PlatformUI.getWorkbench() .getProgressService(); ImageDescriptor newImage = IDEInternalWorkbenchImages .getImageDescriptor(IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC); service.registerIconForFamily(newImage, ResourcesPlugin.FAMILY_MANUAL_BUILD); service.registerIconForFamily(newImage, ResourcesPlugin.FAMILY_AUTO_BUILD); } /* * (non-Javadoc) * * @see org.eclipse.ui.application.WorkbenchAdvisor#postStartup() */ @Override public void postStartup() { try { refreshFromLocal(); activateProxyService(); ((Workbench) PlatformUI.getWorkbench()).registerService( ISelectionConversionService.class, new IDESelectionConversionService()); initializeSettingsChangeListener(); Display.getCurrent().addListener(SWT.Settings, settingsChangeListener); } finally {// Resume background jobs after we startup Job.getJobManager().resume(); } } /** * Activate the proxy service by obtaining it. */ private void activateProxyService() { Bundle bundle = Platform.getBundle("org.eclipse.ui.ide"); //$NON-NLS-1$ Object proxyService = null; if (bundle != null) { ServiceReference ref = bundle.getBundleContext().getServiceReference(IProxyService.class.getName()); if (ref != null) proxyService = bundle.getBundleContext().getService(ref); } if (proxyService == null) { IDEWorkbenchPlugin.log("Proxy service could not be found."); //$NON-NLS-1$ } } /** * Initialize the listener for settings changes. */ private void initializeSettingsChangeListener() { settingsChangeListener = new Listener() { boolean currentHighContrast = Display.getCurrent() .getHighContrast(); @Override public void handleEvent(org.eclipse.swt.widgets.Event event) { if (Display.getCurrent().getHighContrast() == currentHighContrast) return; currentHighContrast = !currentHighContrast; // make sure they really want to do this if (new MessageDialog(null, IDEWorkbenchMessages.SystemSettingsChange_title, null, IDEWorkbenchMessages.SystemSettingsChange_message, MessageDialog.QUESTION, new String[] { IDEWorkbenchMessages.SystemSettingsChange_yes, IDEWorkbenchMessages.SystemSettingsChange_no }, 1).open() == Window.OK) { PlatformUI.getWorkbench().restart(); } } }; } /* * (non-Javadoc) * * @see org.eclipse.ui.application.WorkbenchAdvisor#postShutdown */ @Override public void postShutdown() { if (activityHelper != null) { activityHelper.shutdown(); activityHelper = null; } if (idleHelper != null) { idleHelper.shutdown(); idleHelper = null; } if (workspaceUndoMonitor != null) { workspaceUndoMonitor.shutdown(); workspaceUndoMonitor = null; } if (IDEWorkbenchPlugin.getPluginWorkspace() != null) { disconnectFromWorkspace(); } } /* * (non-Javadoc) * * @see org.eclipse.ui.application.WorkbenchAdvisor#preShutdown() */ @Override public boolean preShutdown() { Display.getCurrent().removeListener(SWT.Settings, settingsChangeListener); return super.preShutdown(); } /** * Return true if the intro plugin is present and false otherwise. * * @return boolean */ public boolean hasIntro() { return getWorkbenchConfigurer().getWorkbench().getIntroManager() .hasIntro(); } private void refreshFromLocal() { String[] commandLineArgs = Platform.getCommandLineArgs(); IPreferenceStore store = IDEWorkbenchPlugin.getDefault() .getPreferenceStore(); boolean refresh = store .getBoolean(IDEInternalPreferences.REFRESH_WORKSPACE_ON_STARTUP); if (!refresh) { return; } // Do not refresh if it was already done by core on startup. for (int i = 0; i < commandLineArgs.length; i++) { if (commandLineArgs[i].equalsIgnoreCase("-refresh")) { //$NON-NLS-1$ return; } } final IContainer root = ResourcesPlugin.getWorkspace().getRoot(); Job job = new WorkspaceJob(IDEWorkbenchMessages.Workspace_refreshing) { @Override public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException { root.refreshLocal(IResource.DEPTH_INFINITE, monitor); return Status.OK_STATUS; } }; job.setRule(root); job.schedule(); } private static class CancelableProgressMonitorWrapper extends ProgressMonitorWrapper { private double total = 0; private ProgressMonitorJobsDialog dialog; CancelableProgressMonitorWrapper(IProgressMonitor monitor, ProgressMonitorJobsDialog dialog) { super(monitor); this.dialog = dialog; } /* * (non-Javadoc) * @see org.eclipse.core.runtime.ProgressMonitorWrapper#internalWorked(double) */ public void internalWorked(double work) { super.internalWorked(work); total += work; updateProgressDetails(); } /* * (non-Javadoc) * @see org.eclipse.core.runtime.ProgressMonitorWrapper#worked(int) */ public void worked(int work) { super.worked(work); total += work; updateProgressDetails(); } public void beginTask(String name, int totalWork) { super.beginTask(name, totalWork); subTask(IDEWorkbenchMessages.IDEWorkbenchAdvisor_preHistoryCompaction); } private void updateProgressDetails() { if (!isCanceled() && Math.abs(total - 4.0) < 0.0001 /* right before history compacting */) { subTask(IDEWorkbenchMessages.IDEWorkbenchAdvisor_cancelHistoryPruning); dialog.setCancelable(true); } if (Math.abs(total - 5.0) < 0.0001 /* history compacting finished */) { subTask(IDEWorkbenchMessages.IDEWorkbenchAdvisor_postHistoryCompaction); dialog.setCancelable(false); } } } private static class CancelableProgressMonitorJobsDialog extends ProgressMonitorJobsDialog { public CancelableProgressMonitorJobsDialog(Shell parent) { super(parent); } /* * (non-Javadoc) * @see org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog#createDetailsButton(org.eclipse.swt.widgets.Composite) */ protected void createButtonsForButtonBar(Composite parent) { super.createButtonsForButtonBar(parent); registerCancelButtonListener(); } public void registerCancelButtonListener() { cancel.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { subTaskLabel.setText(""); //$NON-NLS-1$ } }); } } final IRunnableWithProgress platformShutdownRunnable = new IRunnableWithProgress() { /** * @param monitor * the progress monitor to use for reporting progress to the * user, or null indicating that no progress * should be reported and the operation cannot be cancelled. */ @Override public void run(IProgressMonitor monitor) { SubMonitor progress = SubMonitor.convert(monitor, SHUT_DOWN_PLATFORM_TASK, 100); try { try { progress.subTask("Platform"); SimanticsPlatform.INSTANCE.shutdown(progress.newChild(50)); } catch (PlatformException e) { Activator.logError("Problems encountered while shutting down Simantics platform, see exception for details.", e); } progress.subTask("Remaining database connections"); SimanticsUI.closeSessions(); progress.worked(20); TimedSessionCache.close(); progress.worked(20); progress.subTask("Thread pools"); ThreadUtils.shutdown(); progress.worked(5); progress.subTask("Clear index status"); try { // Everything ok, clear index dirty state. DatabaseIndexing.clearAllDirty(); } catch (IOException e) { Activator.logError("Problems encountered while refreshing database index states, see exception for details.", e); } progress.worked(5); progress.setWorkRemaining(0); } finally { if (monitor != null) { monitor.done(); } } } }; /** * Disconnect from the workspace and close ProCore sessions. */ private void disconnectFromWorkspace() { // save the workspace final MultiStatus status = new MultiStatus( IDEWorkbenchPlugin.IDE_WORKBENCH, 1, IDEWorkbenchMessages.ProblemSavingWorkbench, null); final ProgressMonitorJobsDialog p = new CancelableProgressMonitorJobsDialog( null); final boolean applyPolicy = ResourcesPlugin.getWorkspace() .getDescription().isApplyFileStatePolicy(); final IRunnableWithProgress workspaceShutdownRunnable = new IRunnableWithProgress() { @Override public void run(IProgressMonitor monitor) { try { status.merge(((Workspace) ResourcesPlugin.getWorkspace()).save(true, true, monitor)); } catch (CoreException e) { status.merge(e.getStatus()); } } }; IRunnableWithProgress shutdownRunnable = new IRunnableWithProgress() { @Override public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { if (applyPolicy) monitor = new CancelableProgressMonitorWrapper( monitor, p); SubMonitor progress = SubMonitor.convert(monitor, SHUT_DOWN_TASK, 2); try { workspaceShutdownRunnable.run(progress.newChild(1, SubMonitor.SUPPRESS_NONE)); platformShutdownRunnable.run(progress.newChild(1, SubMonitor.SUPPRESS_NONE)); } finally { monitor.done(); } } }; try { new ProgressMonitorJobsDialog(null).run(true, false, shutdownRunnable); } catch (InvocationTargetException e) { status.merge(new Status(IStatus.ERROR, IDEWorkbenchPlugin.IDE_WORKBENCH, 1, IDEWorkbenchMessages.InternalError, e.getTargetException())); } catch (InterruptedException e) { status.merge(new Status(IStatus.ERROR, IDEWorkbenchPlugin.IDE_WORKBENCH, 1, IDEWorkbenchMessages.InternalError, e)); } ErrorDialog.openError(null, IDEWorkbenchMessages.ProblemsSavingWorkspace, null, status, IStatus.ERROR | IStatus.WARNING); if (!status.isOK()) { IDEWorkbenchPlugin.log( IDEWorkbenchMessages.ProblemsSavingWorkspace, status); } } /* * (non-Javadoc) * * @see org.eclipse.ui.application.WorkbenchAdvisor#getDefaultPageInput */ @Override public IAdaptable getDefaultPageInput() { return ResourcesPlugin.getWorkspace().getRoot(); } /* * (non-Javadoc) * * @see org.eclipse.ui.application.WorkbenchAdvisor */ @Override public String getInitialWindowPerspectiveId() { int index = PlatformUI.getWorkbench().getWorkbenchWindowCount() - 1; String perspectiveId = null; AboutInfo[] welcomeInfos = getWelcomePerspectiveInfos(); if (index >= 0 && welcomeInfos != null && index < welcomeInfos.length) { perspectiveId = welcomeInfos[index].getWelcomePerspectiveId(); } if (perspectiveId == null && args.contains(SimanticsArguments.PERSPECTIVE)) { String id = args.get(SimanticsArguments.PERSPECTIVE); IPerspectiveDescriptor perspective = PlatformUI.getWorkbench().getPerspectiveRegistry().findPerspectiveWithId(id); if (perspective != null) perspectiveId = id; } if (perspectiveId == null) { IProject project = SimanticsUI.peekProject(); if (project != null) perspectiveId = project.getHint(ProjectKeys.DEFAULT_PERSPECTIVE); } //System.out.println("Initial perspective: " + perspectiveId); return perspectiveId; } /** * Returns the map of versioned feature ids -> info object for all installed * features. The format of the versioned feature id (the key of the map) is * featureId + ":" + versionId. * * @return map of versioned feature ids -> info object (key type: * String, value type: AboutInfo) * @since 3.0 */ private Map computeBundleGroupMap() { // use tree map to get predicable order Map ids = new TreeMap(); IBundleGroupProvider[] providers = Platform.getBundleGroupProviders(); for (int i = 0; i < providers.length; ++i) { IBundleGroup[] groups = providers[i].getBundleGroups(); for (int j = 0; j < groups.length; ++j) { IBundleGroup group = groups[j]; AboutInfo info = new AboutInfo(group); String version = info.getVersionId(); version = version == null ? "0.0.0" //$NON-NLS-1$ : new Version(version).toString(); String versionedFeature = group.getIdentifier() + ":" + version; //$NON-NLS-1$ ids.put(versionedFeature, info); } } return ids; } /** * Returns the ordered map of versioned feature ids -> AboutInfo that are * new for this session. * * @return ordered map of versioned feature ids (key type: * String) -> infos (value type: * AboutInfo). */ public Map getNewlyAddedBundleGroups() { if (newlyAddedBundleGroups == null) { newlyAddedBundleGroups = createNewBundleGroupsMap(); } return newlyAddedBundleGroups; } /** * Updates the old features setting and returns a map of new features. */ private Map createNewBundleGroupsMap() { // retrieve list of installed bundle groups from last session IDialogSettings settings = IDEWorkbenchPlugin.getDefault() .getDialogSettings(); String[] previousFeaturesArray = settings.getArray(INSTALLED_FEATURES); // get a map of currently installed bundle groups and store it for next // session Map bundleGroups = computeBundleGroupMap(); String[] currentFeaturesArray = new String[bundleGroups.size()]; bundleGroups.keySet().toArray(currentFeaturesArray); settings.put(INSTALLED_FEATURES, currentFeaturesArray); // remove the previously known from the current set if (previousFeaturesArray != null) { for (int i = 0; i < previousFeaturesArray.length; ++i) { bundleGroups.remove(previousFeaturesArray[i]); } } return bundleGroups; } /** * Declares all IDE-specific workbench images. This includes both "shared" * images (named in {@link IDE.SharedImages}) and internal images (named in * {@link org.eclipse.ui.internal.ide.IDEInternalWorkbenchImages}). * * @see IWorkbenchConfigurer#declareImage */ private void declareWorkbenchImages() { final String ICONS_PATH = "$nl$/icons/full/";//$NON-NLS-1$ final String PATH_ELOCALTOOL = ICONS_PATH + "elcl16/"; // Enabled //$NON-NLS-1$ // toolbar // icons. final String PATH_DLOCALTOOL = ICONS_PATH + "dlcl16/"; // Disabled //$NON-NLS-1$ // //$NON-NLS-1$ // toolbar // icons. final String PATH_ETOOL = ICONS_PATH + "etool16/"; // Enabled toolbar //$NON-NLS-1$ // //$NON-NLS-1$ // icons. final String PATH_DTOOL = ICONS_PATH + "dtool16/"; // Disabled toolbar //$NON-NLS-1$ // //$NON-NLS-1$ // icons. final String PATH_OBJECT = ICONS_PATH + "obj16/"; // Model object //$NON-NLS-1$ // //$NON-NLS-1$ // icons final String PATH_WIZBAN = ICONS_PATH + "wizban/"; // Wizard //$NON-NLS-1$ // //$NON-NLS-1$ // icons Bundle ideBundle = Platform.getBundle(IDEWorkbenchPlugin.IDE_WORKBENCH); declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC, PATH_ETOOL + "build_exec.gif", false); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC_HOVER, PATH_ETOOL + "build_exec.gif", false); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC_DISABLED, PATH_DTOOL + "build_exec.gif", false); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC, PATH_ETOOL + "search_src.gif", false); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC_HOVER, PATH_ETOOL + "search_src.gif", false); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC_DISABLED, PATH_DTOOL + "search_src.gif", false); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_ETOOL_NEXT_NAV, PATH_ETOOL + "next_nav.gif", false); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_ETOOL_PREVIOUS_NAV, PATH_ETOOL + "prev_nav.gif", false); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_WIZBAN_NEWPRJ_WIZ, PATH_WIZBAN + "newprj_wiz.png", false); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_WIZBAN_NEWFOLDER_WIZ, PATH_WIZBAN + "newfolder_wiz.png", false); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_WIZBAN_NEWFILE_WIZ, PATH_WIZBAN + "newfile_wiz.png", false); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_WIZBAN_IMPORTDIR_WIZ, PATH_WIZBAN + "importdir_wiz.png", false); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_WIZBAN_IMPORTZIP_WIZ, PATH_WIZBAN + "importzip_wiz.png", false); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_WIZBAN_EXPORTDIR_WIZ, PATH_WIZBAN + "exportdir_wiz.png", false); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_WIZBAN_EXPORTZIP_WIZ, PATH_WIZBAN + "exportzip_wiz.png", false); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_WIZBAN_RESOURCEWORKINGSET_WIZ, PATH_WIZBAN + "workset_wiz.png", false); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_DLGBAN_SAVEAS_DLG, PATH_WIZBAN + "saveas_wiz.png", false); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_DLGBAN_QUICKFIX_DLG, PATH_WIZBAN + "quick_fix.png", false); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJ_PROJECT, PATH_OBJECT + "prj_obj.gif", true); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJ_PROJECT_CLOSED, PATH_OBJECT + "cprj_obj.gif", true); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OPEN_MARKER, PATH_ELOCALTOOL + "gotoobj_tsk.gif", true); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_ELCL_QUICK_FIX_ENABLED, PATH_ELOCALTOOL + "smartmode_co.gif", true); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_DLCL_QUICK_FIX_DISABLED, PATH_DLOCALTOOL + "smartmode_co.gif", true); //$NON-NLS-1$ // task objects // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_HPRIO_TSK, // PATH_OBJECT+"hprio_tsk.gif"); // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_MPRIO_TSK, // PATH_OBJECT+"mprio_tsk.gif"); // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_LPRIO_TSK, // PATH_OBJECT+"lprio_tsk.gif"); declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJS_TASK_TSK, PATH_OBJECT + "taskmrk_tsk.gif", true); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJS_BKMRK_TSK, PATH_OBJECT + "bkmrk_tsk.gif", true); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_OBJS_COMPLETE_TSK, PATH_OBJECT + "complete_tsk.gif", true); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_OBJS_INCOMPLETE_TSK, PATH_OBJECT + "incomplete_tsk.gif", true); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_OBJS_WELCOME_ITEM, PATH_OBJECT + "welcome_item.gif", true); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_OBJS_WELCOME_BANNER, PATH_OBJECT + "welcome_banner.gif", true); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_OBJS_ERROR_PATH, PATH_OBJECT + "error_tsk.gif", true); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_OBJS_WARNING_PATH, PATH_OBJECT + "warn_tsk.gif", true); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_OBJS_INFO_PATH, PATH_OBJECT + "info_tsk.gif", true); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_LCL_FLAT_LAYOUT, PATH_ELOCALTOOL + "flatLayout.gif", true); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_LCL_HIERARCHICAL_LAYOUT, PATH_ELOCALTOOL + "hierarchicalLayout.gif", true); //$NON-NLS-1$ declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_ETOOL_PROBLEM_CATEGORY, PATH_ETOOL + "problem_category.gif", true); //$NON-NLS-1$ /* declareWorkbenchImage(ideBundle, IDEInternalWorkbenchImages.IMG_LCL_LINKTO_HELP, PATH_ELOCALTOOL + "linkto_help.gif", false); //$NON-NLS-1$ */ // synchronization indicator objects // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_WBET_STAT, // PATH_OVERLAY+"wbet_stat.gif"); // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_SBET_STAT, // PATH_OVERLAY+"sbet_stat.gif"); // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_CONFLICT_STAT, // PATH_OVERLAY+"conflict_stat.gif"); // content locality indicator objects // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_NOTLOCAL_STAT, // PATH_STAT+"notlocal_stat.gif"); // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_LOCAL_STAT, // PATH_STAT+"local_stat.gif"); // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_FILLLOCAL_STAT, // PATH_STAT+"filllocal_stat.gif"); } /** * Declares an IDE-specific workbench image. * * @param symbolicName * the symbolic name of the image * @param path * the path of the image file; this path is relative to the base * of the IDE plug-in * @param shared * true if this is a shared image, and * false if this is not a shared image * @see IWorkbenchConfigurer#declareImage */ private void declareWorkbenchImage(Bundle ideBundle, String symbolicName, String path, boolean shared) { URL url = FileLocator.find(ideBundle, new Path(path), null); ImageDescriptor desc = ImageDescriptor.createFromURL(url); getWorkbenchConfigurer().declareImage(symbolicName, desc, shared); } /* * (non-Javadoc) * * @see org.eclipse.ui.application.WorkbenchAdvisor#getMainPreferencePageId */ @Override public String getMainPreferencePageId() { // indicate that we want the Workench preference page to be prominent return WORKBENCH_PREFERENCE_CATEGORY_ID; } /** * @return the workspace location string, or null if the * location is not being shown */ public String getWorkspaceLocation() { // read command line, which has priority IEclipseContext context = getWorkbenchConfigurer().getWorkbench().getService(IEclipseContext.class); String location = context != null ? (String) context.get(E4Workbench.FORCED_SHOW_LOCATION) : null; if (location != null) { return location; } // read the preference if (IDEWorkbenchPlugin.getDefault().getPreferenceStore().getBoolean(IDEInternalPreferences.SHOW_LOCATION)) { return Platform.getLocation().toOSString(); } return null; } /** * @return the welcome perspective infos, or null if none or * if they should be ignored due to the new intro being present */ public AboutInfo[] getWelcomePerspectiveInfos() { if (welcomePerspectiveInfos == null) { // support old welcome perspectives if intro plugin is not present if (!hasIntro()) { Map m = getNewlyAddedBundleGroups(); ArrayList list = new ArrayList(m.size()); for (Iterator i = m.values().iterator(); i.hasNext();) { AboutInfo info = i.next(); if (info != null && info.getWelcomePerspectiveId() != null && info.getWelcomePageURL() != null) { list.add(info); } } welcomePerspectiveInfos = new AboutInfo[list.size()]; list.toArray(welcomePerspectiveInfos); } } return welcomePerspectiveInfos; } /* * (non-Javadoc) * * @see org.eclipse.ui.application.WorkbenchAdvisor#getWorkbenchErrorHandler() */ @Override public AbstractStatusHandler getWorkbenchErrorHandler() { if (ideWorkbenchErrorHandler == null) { ideWorkbenchErrorHandler = new IDEWorkbenchErrorHandler( getWorkbenchConfigurer()); } return ideWorkbenchErrorHandler; } /* (non-Javadoc) * @see org.eclipse.ui.application.WorkbenchAdvisor#eventLoopIdle(org.eclipse.swt.widgets.Display) */ @Override public void eventLoopIdle(Display display) { if (delayedEventsProcessor != null) delayedEventsProcessor.catchUp(display); super.eventLoopIdle(display); } }