/* * Copyright (C) 2006-2016 DLR, Germany * * All rights reserved * * http://www.rcenvironment.de/ */ package de.rcenvironment.core.start.gui; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.Platform; import org.eclipse.equinox.app.IApplication; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.osgi.service.datalocation.Location; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.internal.ide.ChooseWorkspaceData; import org.eclipse.ui.internal.ide.ChooseWorkspaceDialog; import org.osgi.framework.Version; import de.rcenvironment.core.configuration.CommandLineArguments; import de.rcenvironment.core.configuration.bootstrap.BootstrapConfiguration; import de.rcenvironment.core.gui.utils.incubator.Sleak; import de.rcenvironment.core.start.common.InstanceRunner; import de.rcenvironment.core.start.common.validation.api.InstanceValidationResult; import de.rcenvironment.core.start.common.validation.api.InstanceValidationResult.InstanceValidationResultType; import de.rcenvironment.core.start.gui.internal.ApplicationWorkbenchAdvisor; import de.rcenvironment.core.utils.common.StringUtils; import de.rcenvironment.core.utils.common.VersionUtils; import de.rcenvironment.toolkit.modules.concurrency.api.ThreadGuard; /** * Starts the GUI for RCE. * * @author Sascha Zur * @author Jan Flink * @author Robert Mischke * @author Marc Stammerjohann * @author Doreen Seider */ @SuppressWarnings("restriction") public final class GUIInstanceRunner extends InstanceRunner { private static final int MAX_RECENT_WORKSPACES_HISTORY = 5; private static final boolean ALLOW_WORKSPACE_CHOOSER_SUPPRESSION = true; /** * System property for launching Sleak to detect SWT resource leaks. */ private static final String DRCE_DEBUG_SLEAK = "rce.debug.sleak"; private static boolean tryWorkspaceChoosingAgain = false; /** * Runs the RCE instance in non-headless (GUI) mode. * * @return exit code * @throws Exception : URL */ @Override public int performRun() throws Exception { int exitCode = 0 - 1; // trigger execution of "--exec" commands, if they exist String[] execCommandTokens = CommandLineArguments.getExecCommandTokens(); if (execCommandTokens != null) { initiateAsyncCommandExecution(execCommandTokens, "execution of --exec commands", false); } storeVersionInformationToSystemProperties(); // mark the GUI thread as forbidden (or at least, critical) for certain operations - misc_ro ThreadGuard.setForbiddenThread(Thread.currentThread()); boolean startSleak = System.getProperties().containsKey(DRCE_DEBUG_SLEAK); if (startSleak) { // this needs to be executed before the display has been created org.eclipse.ui.internal.misc.Policy.DEBUG_SWT_GRAPHICS = true; org.eclipse.ui.internal.misc.Policy.DEBUG_SWT_DEBUG = true; } // initialize the GUI Display display = PlatformUI.createDisplay(); if (startSleak) { // this needs to be executed after the display has been created Sleak sleak = new Sleak(); sleak.open(); } // start the workbench - returns as soon as the workbench is closed try { do { // workspace location chooser if (!determineWorkspaceLocation(Platform.getInstanceLocation())) { return IApplication.EXIT_OK; } // If this flag is true, a non-valid workspace was chosen, show the workspace chooser again until a valid workspace is // selected or "cancel" is clicked. } while (tryWorkspaceChoosingAgain); int platformUIExitCode = PlatformUI.createAndRunWorkbench(display, new ApplicationWorkbenchAdvisor()); if (platformUIExitCode == PlatformUI.RETURN_RESTART) { exitCode = IApplication.EXIT_RESTART; } else { exitCode = IApplication.EXIT_OK; } } finally { display.dispose(); } return exitCode; } @Override public boolean onInstanceValidationFailures(Map<InstanceValidationResultType, List<InstanceValidationResult>> validationResults) { if (validationResults.get(InstanceValidationResultType.FAILED_SHUTDOWN_REQUIRED).size() > 0) { InstanceValidationResult result = validationResults.get(InstanceValidationResultType.FAILED_SHUTDOWN_REQUIRED).get(0); showErrorDialog("Instance validation failure", result.getGuiDialogMessage() + "\n\nRCE will be shut down."); return false; } if (validationResults.get(InstanceValidationResultType.FAILED_PROCEEDING_ALLOWED).size() > 0) { for (InstanceValidationResult result : validationResults.get(InstanceValidationResultType.FAILED_PROCEEDING_ALLOWED)) { if (!showQuestionDialog("Instance validation failure", result.getGuiDialogMessage() + "\n\nDo you like to proceed anyway?")) { return false; } } } return true; } @Override public void beforeAwaitShutdown() { PlatformUI.getWorkbench(); } @Override public void triggerShutdown() { Display.getDefault().asyncExec(new Runnable() { @Override public void run() { if (!PlatformUI.isWorkbenchRunning()) { return; } PlatformUI.getWorkbench().close(); } }); } @Override public void triggerRestart() { Display.getDefault().asyncExec(new Runnable() { @Override public void run() { if (!PlatformUI.isWorkbenchRunning()) { return; } PlatformUI.getWorkbench().restart(); } }); } private boolean determineWorkspaceLocation(Location workspaceLocation) throws MalformedURLException, IOException { // if a workspace was defined using the Eclipse "-data" option, use it as an override and don't use our own mechanism if (workspaceLocation.isSet()) { log.info("Not using the workspace chooser or locations stored in the RCE profile, " + "as a workspace location was already defined (probably using the -data option): " + workspaceLocation.getURL()); return true; } WorkspaceSettings workspaceSettings = WorkspaceSettings.getInstance(); File profileDirectory = BootstrapConfiguration.getInstance().getProfileDirectory(); String lastWorkspaceLocation = workspaceSettings.getLastLocation(); String recentWorkspacesData = workspaceSettings.getRecentLocationData(); String defaultWorkdirPath; if (lastWorkspaceLocation != null) { defaultWorkdirPath = new File(lastWorkspaceLocation).getAbsolutePath(); } else { defaultWorkdirPath = new File(profileDirectory, "workspace").getAbsolutePath(); } String[] oldRecentWorkspaces; if (recentWorkspacesData != null) { oldRecentWorkspaces = StringUtils.splitAndUnescape(recentWorkspacesData); } else { oldRecentWorkspaces = new String[] { defaultWorkdirPath }; } ChooseWorkspaceData cwd = new ChooseWorkspaceData(defaultWorkdirPath); cwd.setRecentWorkspaces(oldRecentWorkspaces); ChooseWorkspaceDialog wd = new ChooseWorkspaceDialog(null, cwd, !ALLOW_WORKSPACE_CHOOSER_SUPPRESSION, true); int cwdReturnCode = 0 - 1; // NOTE: review the "last location" storage strategy before re-enabling suppression (if // desired in the future) if (!workspaceSettings.getDontAskAgainSetting() || !ALLOW_WORKSPACE_CHOOSER_SUPPRESSION) { cwdReturnCode = wd.open(); if (cwdReturnCode == Dialog.CANCEL) { return false; } if (!cwd.getShowDialog()) { workspaceSettings.setDontAskAgainSetting(true); } } final String currentWorkspace; if (cwd.getSelection() != null) { currentWorkspace = new File(cwd.getSelection()).getAbsolutePath(); } else { currentWorkspace = defaultWorkdirPath; } // add to head of recent workspaces list, eliminating duplicates List<String> newRecentWorkspaces = new ArrayList<>(); newRecentWorkspaces.add(0, currentWorkspace); int pos = 0; while (pos < oldRecentWorkspaces.length && newRecentWorkspaces.size() < MAX_RECENT_WORKSPACES_HISTORY) { String oldEntry = oldRecentWorkspaces[pos]; if (!oldEntry.equals(currentWorkspace)) { newRecentWorkspaces.add(oldEntry); } pos++; } String[] newRecentWorkspacesArray = newRecentWorkspaces.toArray(new String[newRecentWorkspaces.size()]); // although these values are not used on the next start, writing them keeps "File > Restart" // working - misc_ro cwd.setRecentWorkspaces(newRecentWorkspacesArray); cwd.writePersistedData(); workspaceSettings.updateLocationHistory(currentWorkspace, StringUtils.escapeAndConcat(newRecentWorkspacesArray)); URL userWSURL = new URL("file", null, currentWorkspace); try { workspaceLocation.set(userWSURL, true); tryWorkspaceChoosingAgain = false; } catch (IOException e) { showErrorDialog("Workspace", "Workspace directory could not be created or is read-only."); // A non-valid workspace was chosen, show the workspace chooser again. tryWorkspaceChoosingAgain = true; workspaceSettings.setDontAskAgainSetting(false); } return true; } /** * Stores version information in system properties, which can be read by about dialog or version command. In case of RC or SNAPSHOT the * property for build hint will be set accordingly. */ private void storeVersionInformationToSystemProperties() { Version version = VersionUtils.getVersionOfProduct(); String buildId = VersionUtils.getBuildIdAsString(version); if (buildId == null) { buildId = "-"; } System.setProperty("rce.version", VersionUtils.getVersionAsString(version)); System.setProperty("rce.buildId", buildId); } private void showErrorDialog(String title, String message) { MessageDialog.openError(new Shell(SWT.ON_TOP), title, message); } private boolean showQuestionDialog(String title, String message) { return MessageDialog.openQuestion(new Shell(SWT.ON_TOP), title, message); } }