X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.workbench%2Fsrc%2Forg%2Fsimantics%2Fworkbench%2Finternal%2FSimanticsWorkbenchAdvisor.java;fp=bundles%2Forg.simantics.workbench%2Fsrc%2Forg%2Fsimantics%2Fworkbench%2Finternal%2FSimanticsWorkbenchAdvisor.java;h=bce220c9c3ae24fb64f8248766f0dce4956c1f8f;hp=d75f1e47672941e9f81eaabf8f7efd8b8d8833d6;hb=5930811a7911090a0c4984380c3b45ed81a93cde;hpb=ffdf83729b496d5afe74c7888075bb17ce1c4bbb diff --git a/bundles/org.simantics.workbench/src/org/simantics/workbench/internal/SimanticsWorkbenchAdvisor.java b/bundles/org.simantics.workbench/src/org/simantics/workbench/internal/SimanticsWorkbenchAdvisor.java index d75f1e476..bce220c9c 100644 --- a/bundles/org.simantics.workbench/src/org/simantics/workbench/internal/SimanticsWorkbenchAdvisor.java +++ b/bundles/org.simantics.workbench/src/org/simantics/workbench/internal/SimanticsWorkbenchAdvisor.java @@ -1,1228 +1,1233 @@ -/******************************************************************************* - * 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.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.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$ - - /** - * 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.getCause()); - } 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); - } - - String databaseDriverId = Simantics.getDefaultDatabaseDriver(); - if (args.contains(SimanticsArguments.DATABASE_ID)) { - databaseDriverId = args.get(SimanticsArguments.DATABASE_ID); - Simantics.setDefaultDatabaseDriver(databaseDriverId); - } - - IProgressMonitor mon = null; - if (PROFILE_PLATFORM_STARTUP) - mon = new TimingProgressMonitor(); - SimanticsPlatform.INSTANCE.startUp(databaseDriverId, 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); - } - -} +/******************************************************************************* + * 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.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.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; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * @author Tuukka Lehtonen + */ +public class SimanticsWorkbenchAdvisor extends WorkbenchAdvisor { + + private static final Logger LOGGER = LoggerFactory.getLogger(SimanticsWorkbenchAdvisor.class); + + 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$ + + /** + * 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(); + LOGGER.info("startPlatform finished"); + 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.getCause()); + } 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); + } + + String databaseDriverId = Simantics.getDefaultDatabaseDriver(); + if (args.contains(SimanticsArguments.DATABASE_ID)) { + databaseDriverId = args.get(SimanticsArguments.DATABASE_ID); + Simantics.setDefaultDatabaseDriver(databaseDriverId); + } + + IProgressMonitor mon = null; + if (PROFILE_PLATFORM_STARTUP) + mon = new TimingProgressMonitor(); + SimanticsPlatform.INSTANCE.startUp(databaseDriverId, 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); + } + +}