-/*******************************************************************************\r
- * Copyright (c) 2007, 2008 IBM Corporation and others.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- * \r
- * Contributors:\r
- * IBM Corporation - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.project.management.install;\r
-\r
-import org.eclipse.core.runtime.IPath;\r
-import org.eclipse.core.runtime.IProgressMonitor;\r
-import org.eclipse.core.runtime.IStatus;\r
-import org.eclipse.core.runtime.OperationCanceledException;\r
-import org.eclipse.core.runtime.Path;\r
-import org.eclipse.core.runtime.Status;\r
-import org.eclipse.equinox.internal.provisional.p2.installer.IInstallOperation;\r
-import org.eclipse.equinox.internal.provisional.p2.installer.InstallDescription;\r
-import org.eclipse.osgi.util.NLS;\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.events.KeyAdapter;\r
-import org.eclipse.swt.events.KeyEvent;\r
-import org.eclipse.swt.events.SelectionAdapter;\r
-import org.eclipse.swt.events.SelectionEvent;\r
-import org.eclipse.swt.layout.FillLayout;\r
-import org.eclipse.swt.layout.GridData;\r
-import org.eclipse.swt.layout.GridLayout;\r
-import org.eclipse.swt.widgets.Button;\r
-import org.eclipse.swt.widgets.Composite;\r
-import org.eclipse.swt.widgets.DirectoryDialog;\r
-import org.eclipse.swt.widgets.Display;\r
-import org.eclipse.swt.widgets.Event;\r
-import org.eclipse.swt.widgets.Group;\r
-import org.eclipse.swt.widgets.Label;\r
-import org.eclipse.swt.widgets.Listener;\r
-import org.eclipse.swt.widgets.MessageBox;\r
-import org.eclipse.swt.widgets.ProgressBar;\r
-import org.eclipse.swt.widgets.Shell;\r
-import org.eclipse.swt.widgets.Text;\r
-import org.simantics.project.internal.Activator;\r
-\r
-/**\r
- * The install wizard that drives the install. This dialog is used for user input\r
- * prior to the install, progress feedback during the install, and displaying results\r
- * at the end of the install.\r
- */\r
-public class InstallDialog {\r
- /**\r
- * A progress monitor implementation that asynchronously updates the progress bar.\r
- */\r
- class Monitor implements IProgressMonitor {\r
-\r
- boolean canceled = false, running = false;\r
- String subTaskName = ""; //$NON-NLS-1$\r
- double totalWork, usedWork;\r
-\r
- public void beginTask(final String name, final int work) {\r
- totalWork = work;\r
- running = true;\r
- update();\r
- }\r
-\r
- public void done() {\r
- running = false;\r
- usedWork = totalWork;\r
- update();\r
- }\r
-\r
- public void internalWorked(double work) {\r
- usedWork = Math.min(usedWork + work, totalWork);\r
- update();\r
- }\r
-\r
- public boolean isCanceled() {\r
- return returnCode == CANCEL;\r
- }\r
-\r
- public void setCanceled(boolean value) {\r
- returnCode = CANCEL;\r
- }\r
-\r
- public void setTaskName(String name) {\r
- subTaskName = name == null ? "" : name; //$NON-NLS-1$\r
- update();\r
- }\r
-\r
- public void subTask(String name) {\r
- subTaskName = name == null ? "" : name; //$NON-NLS-1$\r
- update();\r
- }\r
-\r
- void update() {\r
- Display display = getDisplay();\r
- if (display == null)\r
- return;\r
- display.asyncExec(new Runnable() {\r
- public void run() {\r
- Shell theShell = getShell();\r
- if (theShell == null || theShell.isDisposed())\r
- return;\r
- progressSubTask.setText(shorten(subTaskName));\r
- if (progressBar.isDisposed())\r
- return;\r
- progressBar.setVisible(running);\r
- progressBar.setMaximum(1000);\r
- progressBar.setMinimum(0);\r
- int value = (int) (usedWork / totalWork * 1000);\r
- if (progressBar.getSelection() < value)\r
- progressBar.setSelection(value);\r
- }\r
-\r
- private String shorten(String text) {\r
- if (text.length() <= 64)\r
- return text;\r
- int len = text.length();\r
- return text.substring(0, 30) + "..." + text.substring(len - 30, len); //$NON-NLS-1$\r
- }\r
- });\r
- }\r
-\r
- public void worked(int work) {\r
- internalWorked(work);\r
- }\r
- }\r
-\r
- /**\r
- * Encapsulates a result passed from an operation running in a background\r
- * thread to the UI thread.\r
- */\r
- static class Result {\r
- private boolean done;\r
- private IStatus status;\r
-\r
- synchronized void done() {\r
- done = true;\r
- }\r
-\r
- synchronized void failed(Throwable t) {\r
- String msg = "Internal error";\r
- status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, msg, t);\r
- }\r
-\r
- synchronized IStatus getStatus() {\r
- return status;\r
- }\r
-\r
- synchronized boolean isDone() {\r
- return done;\r
- }\r
-\r
- public void setStatus(IStatus status) {\r
- this.status = status;\r
- }\r
- }\r
-\r
- private static final int BUTTON_WIDTH = 100;\r
- private static final int CANCEL = 1;\r
- private static final int OK = 0;\r
-\r
- private Button cancelButton;\r
- private Composite contents;\r
- private Button okButton;\r
-\r
- ProgressBar progressBar;\r
- Label progressSubTask;\r
- Label progressTask;\r
-\r
- int returnCode = -1;\r
-\r
- private Button settingsBrowse;\r
- private Label settingsExplain;\r
- private Composite settingsGroup;\r
- private Text settingsLocation;\r
- private Label settingsLocationLabel;\r
- private Button settingsShared;\r
- private Button settingsStandalone;\r
-\r
- private Shell shell;\r
-\r
- private boolean waitingForClose = false;\r
- private Button proxySettingsButton;\r
- private Button manualProxyTypeCheckBox;\r
-\r
- /**\r
- * Creates and opens a progress monitor dialog.\r
- */\r
- public InstallDialog() {\r
- createShell();\r
- progressTask = new Label(contents, SWT.WRAP | SWT.LEFT);\r
- progressTask.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));\r
- createInstallSettingsControls();\r
- createProgressControls();\r
- createButtonBar();\r
-\r
- shell.pack();\r
- shell.layout();\r
- shell.open();\r
- }\r
-\r
- protected void browsePressed() {\r
- DirectoryDialog dirDialog = new DirectoryDialog(shell);\r
- dirDialog.setMessage("Select location");\r
- String location = dirDialog.open();\r
- if (location == null)\r
- location = ""; //$NON-NLS-1$\r
- settingsLocation.setText(location);\r
- validateInstallSettings();\r
- }\r
-\r
- protected void buttonPressed(int code) {\r
- returnCode = code;\r
- if (waitingForClose)\r
- close();\r
- //grey out the cancel button to indicate the request was heard\r
- if (code == CANCEL && !cancelButton.isDisposed())\r
- cancelButton.setEnabled(false);\r
- }\r
-\r
- public void close() {\r
- if (shell == null)\r
- return;\r
- if (!shell.isDisposed())\r
- shell.dispose();\r
- shell = null;\r
- }\r
-\r
- private void createButtonBar() {\r
- Composite buttonBar = new Composite(contents, SWT.NONE);\r
- GridData data = new GridData(GridData.FILL_HORIZONTAL);\r
- data.horizontalAlignment = SWT.RIGHT;\r
- buttonBar.setLayoutData(data);\r
- GridLayout layout = new GridLayout();\r
- layout.numColumns = 2;\r
- layout.makeColumnsEqualWidth = true;\r
- layout.marginHeight = 0;\r
- layout.marginWidth = 0;\r
- buttonBar.setLayout(layout);\r
-\r
- okButton = new Button(buttonBar, SWT.PUSH);\r
- data = new GridData(BUTTON_WIDTH, SWT.DEFAULT);\r
- okButton.setLayoutData(data);\r
- okButton.setText("Install");\r
- okButton.setEnabled(false);\r
- okButton.addSelectionListener(new SelectionAdapter() {\r
- public void widgetSelected(SelectionEvent e) {\r
- buttonPressed(OK);\r
- }\r
- });\r
-\r
- cancelButton = new Button(buttonBar, SWT.PUSH);\r
- data = new GridData(BUTTON_WIDTH, SWT.DEFAULT);\r
- cancelButton.setLayoutData(data);\r
- cancelButton.setText("Cancel");\r
- cancelButton.setEnabled(false);\r
- cancelButton.addSelectionListener(new SelectionAdapter() {\r
- public void widgetSelected(SelectionEvent e) {\r
- buttonPressed(CANCEL);\r
- }\r
- });\r
- }\r
-\r
- /**\r
- * Creates the controls to prompt for the agent and install locations.\r
- */\r
- private void createInstallSettingsControls() {\r
- settingsGroup = new Composite(contents, SWT.NONE);\r
- GridLayout layout = new GridLayout();\r
- settingsGroup.setLayout(layout);\r
- settingsGroup.setLayoutData(new GridData(GridData.FILL_BOTH));\r
-\r
- Listener validateListener = new Listener() {\r
- public void handleEvent(Event event) {\r
- validateInstallSettings();\r
- }\r
- };\r
-\r
- //The group asking for the product install directory\r
- Group installLocationGroup = new Group(settingsGroup, SWT.NONE);\r
- installLocationGroup.setLayout(new GridLayout());\r
- installLocationGroup.setLayoutData(new GridData(GridData.FILL_BOTH));\r
- installLocationGroup.setText("Location");\r
- settingsLocationLabel = new Label(installLocationGroup, SWT.NONE);\r
- settingsLocationLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));\r
- settingsLocationLabel.setText("Location");\r
-\r
- //The sub-group with text entry field and browse button\r
- Composite locationFieldGroup = new Composite(installLocationGroup, SWT.NONE);\r
- locationFieldGroup.setLayoutData(new GridData(GridData.FILL_BOTH));\r
- layout = new GridLayout();\r
- layout.numColumns = 2;\r
- layout.makeColumnsEqualWidth = false;\r
- locationFieldGroup.setLayout(layout);\r
- settingsLocation = new Text(locationFieldGroup, SWT.SINGLE | SWT.BORDER);\r
- settingsLocation.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));\r
- settingsLocation.addListener(SWT.Modify, validateListener);\r
- settingsLocation.addKeyListener(new KeyAdapter() {\r
- public void keyReleased(KeyEvent event) {\r
- if (event.character == SWT.CR || event.character == SWT.KEYPAD_CR)\r
- buttonPressed(OK);\r
- }\r
- });\r
- settingsBrowse = new Button(locationFieldGroup, SWT.PUSH);\r
- settingsBrowse.setLayoutData(new GridData(BUTTON_WIDTH, SWT.DEFAULT));\r
- settingsBrowse.setText("Browse");\r
- settingsBrowse.addListener(SWT.Selection, new Listener() {\r
- public void handleEvent(Event event) {\r
- browsePressed();\r
- }\r
- });\r
-\r
- //Create the radio button group asking for the kind of install (shared vs. standalone)\r
- Group installKindGroup = new Group(settingsGroup, SWT.NONE);\r
- installKindGroup.setText("Layout");\r
- installKindGroup.setLayoutData(new GridData(GridData.FILL_BOTH));\r
- installKindGroup.setLayout(new GridLayout());\r
- settingsStandalone = new Button(installKindGroup, SWT.RADIO);\r
- settingsStandalone.setText("Standalone");\r
- settingsStandalone.addListener(SWT.Selection, validateListener);\r
- settingsStandalone.setSelection(true);\r
- settingsShared = new Button(installKindGroup, SWT.RADIO);\r
- settingsShared.setText("Shared");\r
- settingsShared.addListener(SWT.Selection, validateListener);\r
- settingsExplain = new Label(installKindGroup, SWT.WRAP);\r
- GridData data = new GridData(SWT.DEFAULT, 40);\r
- data.grabExcessHorizontalSpace = true;\r
- data.horizontalAlignment = GridData.FILL;\r
- settingsExplain.setLayoutData(data);\r
- settingsExplain.setText("...");\r
-\r
- //The group asking for the product proxy configuration\r
- Group proxySettingsGroup = new Group(settingsGroup, SWT.NONE);\r
- proxySettingsGroup.setLayout(new GridLayout());\r
- proxySettingsGroup.setLayoutData(new GridData(GridData.FILL_BOTH));\r
- proxySettingsGroup.setText("Proxy");\r
-\r
- //The sub-group with check box, label entry field and settings button\r
- Composite proxySettingsFieldGroup = new Composite(proxySettingsGroup, SWT.NONE);\r
- proxySettingsFieldGroup.setLayoutData(new GridData(GridData.FILL_BOTH));\r
- layout = new GridLayout();\r
- layout.numColumns = 3;\r
- layout.makeColumnsEqualWidth = false;\r
- proxySettingsFieldGroup.setLayout(layout);\r
-\r
- manualProxyTypeCheckBox = new Button(proxySettingsFieldGroup, SWT.CHECK);\r
- manualProxyTypeCheckBox.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));\r
- manualProxyTypeCheckBox.addSelectionListener(new SelectionAdapter() {\r
- public void widgetSelected(SelectionEvent e) {\r
-// IProxyService proxies = (IProxyService) InstallApplication.getService(InstallerActivator.getDefault().getContext(), IProxyService.class.getName());\r
-// if (proxies != null) {\r
-// //When the manual check box is selected the system properties should be disabled. \r
-// //This cases the net component to switch to manual proxy provider.\r
-// proxies.setSystemProxiesEnabled(!manualProxyTypeCheckBox.getSelection());\r
-// if (proxySettingsButton != null) {\r
-// proxySettingsButton.setEnabled(manualProxyTypeCheckBox.getSelection());\r
-// }\r
-// } else {\r
- openMessage("Failed to set proxy", SWT.ICON_ERROR | SWT.OK);\r
-// }\r
- }\r
- });\r
- manualProxyTypeCheckBox.setText("Manual");\r
- proxySettingsButton = new Button(proxySettingsFieldGroup, SWT.PUSH);\r
- proxySettingsButton.setLayoutData(new GridData(BUTTON_WIDTH, SWT.DEFAULT));\r
- proxySettingsButton.setText("Settings");\r
- proxySettingsButton.setEnabled(manualProxyTypeCheckBox.getSelection());\r
- proxySettingsButton.addListener(SWT.Selection, new Listener() {\r
- public void handleEvent(Event event) {\r
- //IProxyService proxies = (IProxyService) InstallApplication.getService(InstallerActivator.getDefault().getContext(), IProxyService.class.getName());\r
- //if (proxies != null) {\r
- // ProxiesDialog proxiesDialog = new ProxiesDialog(proxies);\r
- // proxiesDialog.open();\r
- //} else {\r
- openMessage("Failed to set proxy", SWT.ICON_ERROR | SWT.OK);\r
- //}\r
- }\r
- });\r
-\r
- //make the entire group invisible until we actually need to prompt for locations\r
- settingsGroup.setVisible(false);\r
- }\r
-\r
- private void createProgressControls() {\r
- progressBar = new ProgressBar(contents, SWT.HORIZONTAL | SWT.SMOOTH);\r
- progressBar.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));\r
- progressBar.setVisible(false);\r
- progressSubTask = new Label(contents, SWT.WRAP | SWT.LEFT);\r
- progressSubTask.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));\r
- }\r
-\r
- private void createShell() {\r
- shell = new Shell(SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL | SWT.MIN | SWT.RESIZE);\r
- shell.setBounds(300, 200, 600, 400);\r
- shell.setText("Installer");\r
- shell.setLayout(new FillLayout());\r
- contents = new Composite(shell, SWT.NONE);\r
- GridLayout layout = new GridLayout();\r
- layout.marginWidth = 15;\r
- layout.marginHeight = 15;\r
- contents.setLayout(layout);\r
- }\r
-\r
- public Display getDisplay() {\r
- Shell theShell = shell;\r
- if (theShell == null || theShell.isDisposed())\r
- return null;\r
- return theShell.getDisplay();\r
- }\r
-\r
- public Shell getShell() {\r
- return shell;\r
- }\r
-\r
- /**\r
- * Asks the user to close the dialog, and returns once the dialog is closed.\r
- */\r
- public void promptForClose(String message) {\r
- Display display = getDisplay();\r
- if (display == null)\r
- return;\r
- progressTask.setText(message);\r
- progressSubTask.setText(""); //$NON-NLS-1$\r
- progressBar.setVisible(false);\r
- okButton.setVisible(false);\r
- cancelButton.setText("Close");\r
- cancelButton.setEnabled(true);\r
- waitingForClose = true;\r
- while (shell != null && !shell.isDisposed()) {\r
- if (!display.readAndDispatch())\r
- display.sleep();\r
- }\r
- }\r
-\r
- public boolean promptForLaunch(InstallDescription description) {\r
- Display display = getDisplay();\r
- if (display == null)\r
- return false;\r
- progressTask.setText(NLS.bind("Starting", description.getProductName()));\r
- progressSubTask.setText(""); //$NON-NLS-1$\r
- progressBar.setVisible(false);\r
- okButton.setText("Launch");\r
- okButton.setVisible(true);\r
- cancelButton.setText("Close");\r
- cancelButton.setVisible(true);\r
- waitingForClose = true;\r
- while (shell != null && !shell.isDisposed()) {\r
- if (!display.readAndDispatch())\r
- display.sleep();\r
- }\r
- return returnCode == OK;\r
- }\r
-\r
- /**\r
- * Prompts the user for the install location, and whether the install should\r
- * be shared or standalone.\r
- */\r
- public void promptForLocations(InstallDescription description) {\r
- progressTask.setText(NLS.bind("Location", description.getProductName()));\r
- okButton.setText("Install");\r
- okButton.setVisible(true);\r
- cancelButton.setText("Cancel");\r
- cancelButton.setEnabled(true);\r
- settingsGroup.setVisible(true);\r
- validateInstallSettings();\r
- Display display = getDisplay();\r
- returnCode = -1;\r
- while (returnCode == -1 && shell != null && !shell.isDisposed()) {\r
- if (!display.readAndDispatch())\r
- display.sleep();\r
- }\r
- if (returnCode == CANCEL)\r
- close();\r
- if (shell == null || shell.isDisposed())\r
- throw new OperationCanceledException();\r
- setInstallSettingsEnablement(false);\r
- Path location = new Path(settingsLocation.getText());\r
- description.setInstallLocation(location);\r
- if (settingsStandalone.getSelection()) {\r
- //force everything to be co-located regardless of what values were set in the install description\r
- description.setAgentLocation(location.append("p2")); //$NON-NLS-1$\r
- description.setBundleLocation(location);\r
- } else {\r
- if (description.getAgentLocation() == null)\r
- description.setAgentLocation(new Path(System.getProperty("user.home")).append(".p2/")); //$NON-NLS-1$ //$NON-NLS-2$\r
- //use bundle pool location specified in install description\r
- //by default this will be null, causing the bundle pool to be nested in the agent location\r
- }\r
- okButton.setVisible(false);\r
- }\r
-\r
- /**\r
- * This method runs the given operation in the context of a progress dialog.\r
- * The dialog is opened automatically prior to starting the operation, and closed\r
- * automatically upon completion.\r
- * <p>\r
- * This method must be called from the UI thread. The operation will be\r
- * executed outside the UI thread.\r
- * \r
- * @param operation The operation to run\r
- * @return The result of the operation\r
- */\r
- public IStatus run(final IInstallOperation operation) {\r
- final Result result = new Result();\r
- Thread thread = new Thread() {\r
- public void run() {\r
- try {\r
- result.setStatus(operation.install(new Monitor()));\r
- } catch (ThreadDeath t) {\r
- //must rethrow or the thread won't die\r
- throw t;\r
- } catch (RuntimeException t) {\r
- result.failed(t);\r
- } catch (Error t) {\r
- result.failed(t);\r
- } finally {\r
- Display display = getDisplay();\r
- //ensure all events from the operation have run\r
- if (display != null) {\r
- display.syncExec(new Runnable() {\r
- public void run() {\r
- //do nothing\r
- }\r
- });\r
- }\r
- result.done();\r
- //wake the event loop\r
- if (display != null)\r
- display.wake();\r
- }\r
- }\r
- };\r
- waitingForClose = false;\r
- progressTask.setText("Installing");\r
- cancelButton.setText("Cancel");\r
- thread.start();\r
- Display display = getDisplay();\r
- while (!result.isDone()) {\r
- if (!display.readAndDispatch())\r
- display.sleep();\r
- }\r
- return result.getStatus();\r
- }\r
-\r
- private void setInstallSettingsEnablement(boolean value) {\r
- settingsLocation.setEnabled(value);\r
- settingsShared.setEnabled(value);\r
- settingsStandalone.setEnabled(value);\r
- settingsGroup.setEnabled(value);\r
- settingsExplain.setEnabled(value);\r
- settingsBrowse.setEnabled(value);\r
- settingsLocationLabel.setEnabled(value);\r
- }\r
-\r
- public void setMessage(String message) {\r
- if (progressTask != null && !progressTask.isDisposed())\r
- progressTask.setText(message);\r
- }\r
-\r
- /**\r
- * Validates that the user has correctly entered all required install settings.\r
- */\r
- void validateInstallSettings() {\r
- boolean enabled = settingsStandalone.getSelection() || settingsShared.getSelection();\r
- enabled &= Path.ROOT.isValidPath(settingsLocation.getText());\r
- if (enabled) {\r
- //make sure the install location is an absolute path\r
- IPath location = new Path(settingsLocation.getText());\r
- enabled &= location.isAbsolute();\r
- }\r
- okButton.setEnabled(enabled);\r
-\r
- if (settingsStandalone.getSelection())\r
- settingsExplain.setText("Standalone...");\r
- else\r
- settingsExplain.setText("Shared...");\r
- }\r
-\r
- private void openMessage(String msg, int style) {\r
- MessageBox messageBox = new MessageBox(Display.getDefault().getActiveShell(), style);\r
- messageBox.setMessage(msg);\r
- messageBox.open();\r
- }\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 IBM Corporation and others.
+ * 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:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.simantics.project.management.install;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.equinox.internal.provisional.p2.installer.IInstallOperation;
+import org.eclipse.equinox.internal.provisional.p2.installer.InstallDescription;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.DirectoryDialog;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.MessageBox;
+import org.eclipse.swt.widgets.ProgressBar;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.simantics.project.internal.Activator;
+
+/**
+ * The install wizard that drives the install. This dialog is used for user input
+ * prior to the install, progress feedback during the install, and displaying results
+ * at the end of the install.
+ */
+public class InstallDialog {
+ /**
+ * A progress monitor implementation that asynchronously updates the progress bar.
+ */
+ class Monitor implements IProgressMonitor {
+
+ boolean canceled = false, running = false;
+ String subTaskName = ""; //$NON-NLS-1$
+ double totalWork, usedWork;
+
+ public void beginTask(final String name, final int work) {
+ totalWork = work;
+ running = true;
+ update();
+ }
+
+ public void done() {
+ running = false;
+ usedWork = totalWork;
+ update();
+ }
+
+ public void internalWorked(double work) {
+ usedWork = Math.min(usedWork + work, totalWork);
+ update();
+ }
+
+ public boolean isCanceled() {
+ return returnCode == CANCEL;
+ }
+
+ public void setCanceled(boolean value) {
+ returnCode = CANCEL;
+ }
+
+ public void setTaskName(String name) {
+ subTaskName = name == null ? "" : name; //$NON-NLS-1$
+ update();
+ }
+
+ public void subTask(String name) {
+ subTaskName = name == null ? "" : name; //$NON-NLS-1$
+ update();
+ }
+
+ void update() {
+ Display display = getDisplay();
+ if (display == null)
+ return;
+ display.asyncExec(new Runnable() {
+ public void run() {
+ Shell theShell = getShell();
+ if (theShell == null || theShell.isDisposed())
+ return;
+ progressSubTask.setText(shorten(subTaskName));
+ if (progressBar.isDisposed())
+ return;
+ progressBar.setVisible(running);
+ progressBar.setMaximum(1000);
+ progressBar.setMinimum(0);
+ int value = (int) (usedWork / totalWork * 1000);
+ if (progressBar.getSelection() < value)
+ progressBar.setSelection(value);
+ }
+
+ private String shorten(String text) {
+ if (text.length() <= 64)
+ return text;
+ int len = text.length();
+ return text.substring(0, 30) + "..." + text.substring(len - 30, len); //$NON-NLS-1$
+ }
+ });
+ }
+
+ public void worked(int work) {
+ internalWorked(work);
+ }
+ }
+
+ /**
+ * Encapsulates a result passed from an operation running in a background
+ * thread to the UI thread.
+ */
+ static class Result {
+ private boolean done;
+ private IStatus status;
+
+ synchronized void done() {
+ done = true;
+ }
+
+ synchronized void failed(Throwable t) {
+ String msg = "Internal error";
+ status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, msg, t);
+ }
+
+ synchronized IStatus getStatus() {
+ return status;
+ }
+
+ synchronized boolean isDone() {
+ return done;
+ }
+
+ public void setStatus(IStatus status) {
+ this.status = status;
+ }
+ }
+
+ private static final int BUTTON_WIDTH = 100;
+ private static final int CANCEL = 1;
+ private static final int OK = 0;
+
+ private Button cancelButton;
+ private Composite contents;
+ private Button okButton;
+
+ ProgressBar progressBar;
+ Label progressSubTask;
+ Label progressTask;
+
+ int returnCode = -1;
+
+ private Button settingsBrowse;
+ private Label settingsExplain;
+ private Composite settingsGroup;
+ private Text settingsLocation;
+ private Label settingsLocationLabel;
+ private Button settingsShared;
+ private Button settingsStandalone;
+
+ private Shell shell;
+
+ private boolean waitingForClose = false;
+ private Button proxySettingsButton;
+ private Button manualProxyTypeCheckBox;
+
+ /**
+ * Creates and opens a progress monitor dialog.
+ */
+ public InstallDialog() {
+ createShell();
+ progressTask = new Label(contents, SWT.WRAP | SWT.LEFT);
+ progressTask.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ createInstallSettingsControls();
+ createProgressControls();
+ createButtonBar();
+
+ shell.pack();
+ shell.layout();
+ shell.open();
+ }
+
+ protected void browsePressed() {
+ DirectoryDialog dirDialog = new DirectoryDialog(shell);
+ dirDialog.setMessage("Select location");
+ String location = dirDialog.open();
+ if (location == null)
+ location = ""; //$NON-NLS-1$
+ settingsLocation.setText(location);
+ validateInstallSettings();
+ }
+
+ protected void buttonPressed(int code) {
+ returnCode = code;
+ if (waitingForClose)
+ close();
+ //grey out the cancel button to indicate the request was heard
+ if (code == CANCEL && !cancelButton.isDisposed())
+ cancelButton.setEnabled(false);
+ }
+
+ public void close() {
+ if (shell == null)
+ return;
+ if (!shell.isDisposed())
+ shell.dispose();
+ shell = null;
+ }
+
+ private void createButtonBar() {
+ Composite buttonBar = new Composite(contents, SWT.NONE);
+ GridData data = new GridData(GridData.FILL_HORIZONTAL);
+ data.horizontalAlignment = SWT.RIGHT;
+ buttonBar.setLayoutData(data);
+ GridLayout layout = new GridLayout();
+ layout.numColumns = 2;
+ layout.makeColumnsEqualWidth = true;
+ layout.marginHeight = 0;
+ layout.marginWidth = 0;
+ buttonBar.setLayout(layout);
+
+ okButton = new Button(buttonBar, SWT.PUSH);
+ data = new GridData(BUTTON_WIDTH, SWT.DEFAULT);
+ okButton.setLayoutData(data);
+ okButton.setText("Install");
+ okButton.setEnabled(false);
+ okButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ buttonPressed(OK);
+ }
+ });
+
+ cancelButton = new Button(buttonBar, SWT.PUSH);
+ data = new GridData(BUTTON_WIDTH, SWT.DEFAULT);
+ cancelButton.setLayoutData(data);
+ cancelButton.setText("Cancel");
+ cancelButton.setEnabled(false);
+ cancelButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ buttonPressed(CANCEL);
+ }
+ });
+ }
+
+ /**
+ * Creates the controls to prompt for the agent and install locations.
+ */
+ private void createInstallSettingsControls() {
+ settingsGroup = new Composite(contents, SWT.NONE);
+ GridLayout layout = new GridLayout();
+ settingsGroup.setLayout(layout);
+ settingsGroup.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ Listener validateListener = new Listener() {
+ public void handleEvent(Event event) {
+ validateInstallSettings();
+ }
+ };
+
+ //The group asking for the product install directory
+ Group installLocationGroup = new Group(settingsGroup, SWT.NONE);
+ installLocationGroup.setLayout(new GridLayout());
+ installLocationGroup.setLayoutData(new GridData(GridData.FILL_BOTH));
+ installLocationGroup.setText("Location");
+ settingsLocationLabel = new Label(installLocationGroup, SWT.NONE);
+ settingsLocationLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ settingsLocationLabel.setText("Location");
+
+ //The sub-group with text entry field and browse button
+ Composite locationFieldGroup = new Composite(installLocationGroup, SWT.NONE);
+ locationFieldGroup.setLayoutData(new GridData(GridData.FILL_BOTH));
+ layout = new GridLayout();
+ layout.numColumns = 2;
+ layout.makeColumnsEqualWidth = false;
+ locationFieldGroup.setLayout(layout);
+ settingsLocation = new Text(locationFieldGroup, SWT.SINGLE | SWT.BORDER);
+ settingsLocation.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ settingsLocation.addListener(SWT.Modify, validateListener);
+ settingsLocation.addKeyListener(new KeyAdapter() {
+ public void keyReleased(KeyEvent event) {
+ if (event.character == SWT.CR || event.character == SWT.KEYPAD_CR)
+ buttonPressed(OK);
+ }
+ });
+ settingsBrowse = new Button(locationFieldGroup, SWT.PUSH);
+ settingsBrowse.setLayoutData(new GridData(BUTTON_WIDTH, SWT.DEFAULT));
+ settingsBrowse.setText("Browse");
+ settingsBrowse.addListener(SWT.Selection, new Listener() {
+ public void handleEvent(Event event) {
+ browsePressed();
+ }
+ });
+
+ //Create the radio button group asking for the kind of install (shared vs. standalone)
+ Group installKindGroup = new Group(settingsGroup, SWT.NONE);
+ installKindGroup.setText("Layout");
+ installKindGroup.setLayoutData(new GridData(GridData.FILL_BOTH));
+ installKindGroup.setLayout(new GridLayout());
+ settingsStandalone = new Button(installKindGroup, SWT.RADIO);
+ settingsStandalone.setText("Standalone");
+ settingsStandalone.addListener(SWT.Selection, validateListener);
+ settingsStandalone.setSelection(true);
+ settingsShared = new Button(installKindGroup, SWT.RADIO);
+ settingsShared.setText("Shared");
+ settingsShared.addListener(SWT.Selection, validateListener);
+ settingsExplain = new Label(installKindGroup, SWT.WRAP);
+ GridData data = new GridData(SWT.DEFAULT, 40);
+ data.grabExcessHorizontalSpace = true;
+ data.horizontalAlignment = GridData.FILL;
+ settingsExplain.setLayoutData(data);
+ settingsExplain.setText("...");
+
+ //The group asking for the product proxy configuration
+ Group proxySettingsGroup = new Group(settingsGroup, SWT.NONE);
+ proxySettingsGroup.setLayout(new GridLayout());
+ proxySettingsGroup.setLayoutData(new GridData(GridData.FILL_BOTH));
+ proxySettingsGroup.setText("Proxy");
+
+ //The sub-group with check box, label entry field and settings button
+ Composite proxySettingsFieldGroup = new Composite(proxySettingsGroup, SWT.NONE);
+ proxySettingsFieldGroup.setLayoutData(new GridData(GridData.FILL_BOTH));
+ layout = new GridLayout();
+ layout.numColumns = 3;
+ layout.makeColumnsEqualWidth = false;
+ proxySettingsFieldGroup.setLayout(layout);
+
+ manualProxyTypeCheckBox = new Button(proxySettingsFieldGroup, SWT.CHECK);
+ manualProxyTypeCheckBox.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ manualProxyTypeCheckBox.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+// IProxyService proxies = (IProxyService) InstallApplication.getService(InstallerActivator.getDefault().getContext(), IProxyService.class.getName());
+// if (proxies != null) {
+// //When the manual check box is selected the system properties should be disabled.
+// //This cases the net component to switch to manual proxy provider.
+// proxies.setSystemProxiesEnabled(!manualProxyTypeCheckBox.getSelection());
+// if (proxySettingsButton != null) {
+// proxySettingsButton.setEnabled(manualProxyTypeCheckBox.getSelection());
+// }
+// } else {
+ openMessage("Failed to set proxy", SWT.ICON_ERROR | SWT.OK);
+// }
+ }
+ });
+ manualProxyTypeCheckBox.setText("Manual");
+ proxySettingsButton = new Button(proxySettingsFieldGroup, SWT.PUSH);
+ proxySettingsButton.setLayoutData(new GridData(BUTTON_WIDTH, SWT.DEFAULT));
+ proxySettingsButton.setText("Settings");
+ proxySettingsButton.setEnabled(manualProxyTypeCheckBox.getSelection());
+ proxySettingsButton.addListener(SWT.Selection, new Listener() {
+ public void handleEvent(Event event) {
+ //IProxyService proxies = (IProxyService) InstallApplication.getService(InstallerActivator.getDefault().getContext(), IProxyService.class.getName());
+ //if (proxies != null) {
+ // ProxiesDialog proxiesDialog = new ProxiesDialog(proxies);
+ // proxiesDialog.open();
+ //} else {
+ openMessage("Failed to set proxy", SWT.ICON_ERROR | SWT.OK);
+ //}
+ }
+ });
+
+ //make the entire group invisible until we actually need to prompt for locations
+ settingsGroup.setVisible(false);
+ }
+
+ private void createProgressControls() {
+ progressBar = new ProgressBar(contents, SWT.HORIZONTAL | SWT.SMOOTH);
+ progressBar.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ progressBar.setVisible(false);
+ progressSubTask = new Label(contents, SWT.WRAP | SWT.LEFT);
+ progressSubTask.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ }
+
+ private void createShell() {
+ shell = new Shell(SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL | SWT.MIN | SWT.RESIZE);
+ shell.setBounds(300, 200, 600, 400);
+ shell.setText("Installer");
+ shell.setLayout(new FillLayout());
+ contents = new Composite(shell, SWT.NONE);
+ GridLayout layout = new GridLayout();
+ layout.marginWidth = 15;
+ layout.marginHeight = 15;
+ contents.setLayout(layout);
+ }
+
+ public Display getDisplay() {
+ Shell theShell = shell;
+ if (theShell == null || theShell.isDisposed())
+ return null;
+ return theShell.getDisplay();
+ }
+
+ public Shell getShell() {
+ return shell;
+ }
+
+ /**
+ * Asks the user to close the dialog, and returns once the dialog is closed.
+ */
+ public void promptForClose(String message) {
+ Display display = getDisplay();
+ if (display == null)
+ return;
+ progressTask.setText(message);
+ progressSubTask.setText(""); //$NON-NLS-1$
+ progressBar.setVisible(false);
+ okButton.setVisible(false);
+ cancelButton.setText("Close");
+ cancelButton.setEnabled(true);
+ waitingForClose = true;
+ while (shell != null && !shell.isDisposed()) {
+ if (!display.readAndDispatch())
+ display.sleep();
+ }
+ }
+
+ public boolean promptForLaunch(InstallDescription description) {
+ Display display = getDisplay();
+ if (display == null)
+ return false;
+ progressTask.setText(NLS.bind("Starting", description.getProductName()));
+ progressSubTask.setText(""); //$NON-NLS-1$
+ progressBar.setVisible(false);
+ okButton.setText("Launch");
+ okButton.setVisible(true);
+ cancelButton.setText("Close");
+ cancelButton.setVisible(true);
+ waitingForClose = true;
+ while (shell != null && !shell.isDisposed()) {
+ if (!display.readAndDispatch())
+ display.sleep();
+ }
+ return returnCode == OK;
+ }
+
+ /**
+ * Prompts the user for the install location, and whether the install should
+ * be shared or standalone.
+ */
+ public void promptForLocations(InstallDescription description) {
+ progressTask.setText(NLS.bind("Location", description.getProductName()));
+ okButton.setText("Install");
+ okButton.setVisible(true);
+ cancelButton.setText("Cancel");
+ cancelButton.setEnabled(true);
+ settingsGroup.setVisible(true);
+ validateInstallSettings();
+ Display display = getDisplay();
+ returnCode = -1;
+ while (returnCode == -1 && shell != null && !shell.isDisposed()) {
+ if (!display.readAndDispatch())
+ display.sleep();
+ }
+ if (returnCode == CANCEL)
+ close();
+ if (shell == null || shell.isDisposed())
+ throw new OperationCanceledException();
+ setInstallSettingsEnablement(false);
+ Path location = new Path(settingsLocation.getText());
+ description.setInstallLocation(location);
+ if (settingsStandalone.getSelection()) {
+ //force everything to be co-located regardless of what values were set in the install description
+ description.setAgentLocation(location.append("p2")); //$NON-NLS-1$
+ description.setBundleLocation(location);
+ } else {
+ if (description.getAgentLocation() == null)
+ description.setAgentLocation(new Path(System.getProperty("user.home")).append(".p2/")); //$NON-NLS-1$ //$NON-NLS-2$
+ //use bundle pool location specified in install description
+ //by default this will be null, causing the bundle pool to be nested in the agent location
+ }
+ okButton.setVisible(false);
+ }
+
+ /**
+ * This method runs the given operation in the context of a progress dialog.
+ * The dialog is opened automatically prior to starting the operation, and closed
+ * automatically upon completion.
+ * <p>
+ * This method must be called from the UI thread. The operation will be
+ * executed outside the UI thread.
+ *
+ * @param operation The operation to run
+ * @return The result of the operation
+ */
+ public IStatus run(final IInstallOperation operation) {
+ final Result result = new Result();
+ Thread thread = new Thread() {
+ public void run() {
+ try {
+ result.setStatus(operation.install(new Monitor()));
+ } catch (ThreadDeath t) {
+ //must rethrow or the thread won't die
+ throw t;
+ } catch (RuntimeException t) {
+ result.failed(t);
+ } catch (Error t) {
+ result.failed(t);
+ } finally {
+ Display display = getDisplay();
+ //ensure all events from the operation have run
+ if (display != null) {
+ display.syncExec(new Runnable() {
+ public void run() {
+ //do nothing
+ }
+ });
+ }
+ result.done();
+ //wake the event loop
+ if (display != null)
+ display.wake();
+ }
+ }
+ };
+ waitingForClose = false;
+ progressTask.setText("Installing");
+ cancelButton.setText("Cancel");
+ thread.start();
+ Display display = getDisplay();
+ while (!result.isDone()) {
+ if (!display.readAndDispatch())
+ display.sleep();
+ }
+ return result.getStatus();
+ }
+
+ private void setInstallSettingsEnablement(boolean value) {
+ settingsLocation.setEnabled(value);
+ settingsShared.setEnabled(value);
+ settingsStandalone.setEnabled(value);
+ settingsGroup.setEnabled(value);
+ settingsExplain.setEnabled(value);
+ settingsBrowse.setEnabled(value);
+ settingsLocationLabel.setEnabled(value);
+ }
+
+ public void setMessage(String message) {
+ if (progressTask != null && !progressTask.isDisposed())
+ progressTask.setText(message);
+ }
+
+ /**
+ * Validates that the user has correctly entered all required install settings.
+ */
+ void validateInstallSettings() {
+ boolean enabled = settingsStandalone.getSelection() || settingsShared.getSelection();
+ enabled &= Path.ROOT.isValidPath(settingsLocation.getText());
+ if (enabled) {
+ //make sure the install location is an absolute path
+ IPath location = new Path(settingsLocation.getText());
+ enabled &= location.isAbsolute();
+ }
+ okButton.setEnabled(enabled);
+
+ if (settingsStandalone.getSelection())
+ settingsExplain.setText("Standalone...");
+ else
+ settingsExplain.setText("Shared...");
+ }
+
+ private void openMessage(String msg, int style) {
+ MessageBox messageBox = new MessageBox(Display.getDefault().getActiveShell(), style);
+ messageBox.setMessage(msg);
+ messageBox.open();
+ }
}
\ No newline at end of file