| /* |
| * Copyright (c) 2015-2018 Eike Stepper (Loehne, Germany) and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v2.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v20.html |
| * |
| * Contributors: |
| * Eike Stepper - initial API and implementation |
| * Yatta Solutions - [466264] Enhance UX in simple installer |
| */ |
| package org.eclipse.oomph.setup.internal.installer; |
| |
| import org.eclipse.oomph.base.Annotation; |
| import org.eclipse.oomph.base.util.BaseUtil; |
| import org.eclipse.oomph.internal.setup.SetupPrompter; |
| import org.eclipse.oomph.internal.setup.SetupProperties; |
| import org.eclipse.oomph.internal.ui.FlatButton; |
| import org.eclipse.oomph.internal.ui.ImageCheckbox; |
| import org.eclipse.oomph.internal.ui.ImageHoverButton; |
| import org.eclipse.oomph.jreinfo.JRE; |
| import org.eclipse.oomph.jreinfo.JREManager; |
| import org.eclipse.oomph.jreinfo.ui.JREController; |
| import org.eclipse.oomph.p2.core.AgentManager; |
| import org.eclipse.oomph.p2.core.P2Util; |
| import org.eclipse.oomph.p2.internal.core.DownloadArtifactEvent; |
| import org.eclipse.oomph.setup.AnnotationConstants; |
| import org.eclipse.oomph.setup.AttributeRule; |
| import org.eclipse.oomph.setup.Installation; |
| import org.eclipse.oomph.setup.LicenseInfo; |
| import org.eclipse.oomph.setup.Product; |
| import org.eclipse.oomph.setup.ProductCatalog; |
| import org.eclipse.oomph.setup.ProductVersion; |
| import org.eclipse.oomph.setup.Scope; |
| import org.eclipse.oomph.setup.SetupFactory; |
| import org.eclipse.oomph.setup.SetupPackage; |
| import org.eclipse.oomph.setup.SetupTask; |
| import org.eclipse.oomph.setup.SetupTaskContext; |
| import org.eclipse.oomph.setup.Trigger; |
| import org.eclipse.oomph.setup.User; |
| import org.eclipse.oomph.setup.VariableTask; |
| import org.eclipse.oomph.setup.internal.core.AbstractSetupTaskContext; |
| import org.eclipse.oomph.setup.internal.core.SetupContext; |
| import org.eclipse.oomph.setup.internal.core.SetupTaskPerformer; |
| import org.eclipse.oomph.setup.internal.core.util.SetupCoreUtil; |
| import org.eclipse.oomph.setup.internal.installer.SimpleInstallLaunchButton.State; |
| import org.eclipse.oomph.setup.internal.installer.SimpleMessageOverlay.Type; |
| import org.eclipse.oomph.setup.internal.installer.SimpleProductPage.ProductComposite; |
| import org.eclipse.oomph.setup.log.ProgressLog; |
| import org.eclipse.oomph.setup.ui.EnablementComposite; |
| import org.eclipse.oomph.setup.ui.EnablementDialog; |
| import org.eclipse.oomph.setup.ui.JREDownloadHandler; |
| import org.eclipse.oomph.setup.ui.LicensePrePrompter; |
| import org.eclipse.oomph.setup.ui.SetupUIPlugin; |
| import org.eclipse.oomph.setup.ui.UnsignedContentDialog; |
| import org.eclipse.oomph.setup.ui.wizards.ProgressPage; |
| import org.eclipse.oomph.setup.ui.wizards.SetupWizard.SelectionMemento; |
| import org.eclipse.oomph.ui.StackComposite; |
| import org.eclipse.oomph.ui.UIUtil; |
| import org.eclipse.oomph.util.IOUtil; |
| import org.eclipse.oomph.util.OS; |
| import org.eclipse.oomph.util.ObjectUtil; |
| import org.eclipse.oomph.util.OomphPlugin.Preference; |
| import org.eclipse.oomph.util.Pair; |
| import org.eclipse.oomph.util.PropertiesUtil; |
| import org.eclipse.oomph.util.StringUtil; |
| import org.eclipse.oomph.util.UserCallback; |
| |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.resource.ResourceSet; |
| import org.eclipse.emf.ecore.resource.URIConverter; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.OperationCanceledException; |
| import org.eclipse.equinox.p2.core.UIServices; |
| import org.eclipse.equinox.p2.metadata.ILicense; |
| import org.eclipse.jface.dialogs.IDialogConstants; |
| import org.eclipse.jface.dialogs.MessageDialog; |
| import org.eclipse.jface.layout.GridDataFactory; |
| import org.eclipse.jface.viewers.ArrayContentProvider; |
| import org.eclipse.jface.viewers.ComboViewer; |
| import org.eclipse.jface.viewers.ISelectionChangedListener; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.LabelProvider; |
| import org.eclipse.jface.viewers.SelectionChangedEvent; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.SWTException; |
| import org.eclipse.swt.browser.Browser; |
| import org.eclipse.swt.browser.LocationAdapter; |
| import org.eclipse.swt.browser.LocationEvent; |
| import org.eclipse.swt.custom.CCombo; |
| import org.eclipse.swt.events.ControlEvent; |
| import org.eclipse.swt.events.ControlListener; |
| import org.eclipse.swt.events.DisposeEvent; |
| import org.eclipse.swt.events.DisposeListener; |
| import org.eclipse.swt.events.FocusAdapter; |
| import org.eclipse.swt.events.FocusEvent; |
| import org.eclipse.swt.events.FocusListener; |
| import org.eclipse.swt.events.KeyAdapter; |
| import org.eclipse.swt.events.KeyEvent; |
| import org.eclipse.swt.events.KeyListener; |
| import org.eclipse.swt.events.ModifyEvent; |
| import org.eclipse.swt.events.ModifyListener; |
| import org.eclipse.swt.events.MouseAdapter; |
| import org.eclipse.swt.events.MouseEvent; |
| import org.eclipse.swt.events.MouseListener; |
| import org.eclipse.swt.events.SelectionAdapter; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.events.ShellAdapter; |
| import org.eclipse.swt.events.ShellEvent; |
| import org.eclipse.swt.events.VerifyEvent; |
| import org.eclipse.swt.events.VerifyListener; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.graphics.Rectangle; |
| import org.eclipse.swt.layout.FillLayout; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Dialog; |
| import org.eclipse.swt.widgets.DirectoryDialog; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.swt.widgets.Text; |
| |
| import java.io.File; |
| import java.io.FileFilter; |
| import java.security.cert.Certificate; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.EventObject; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| /** |
| * @author Eike Stepper |
| */ |
| public class SimpleVariablePage extends SimpleInstallerPage |
| { |
| public static final int PROGRESS_WATCHDOG_TIMEOUT = PropertiesUtil.getProperty("oomph.progress.watchdog.timeout", 15); |
| |
| private static final boolean EXIT_AFTER_LAUNCH = !PropertiesUtil.isProperty("oomph.no.exit.after.launch"); |
| |
| private static final Preference PREF_STARTMENU_ENTRY = SetupInstallerPlugin.INSTANCE.getConfigurationPreference("startMenuEntry"); |
| |
| private static final Preference PREF_DESKTOP_SHORTCUT = SetupInstallerPlugin.INSTANCE.getConfigurationPreference("desktopShortcut"); |
| |
| private static final String PROP_INSTALL_ROOT = "oomph.setup.install.root"; |
| |
| private static final Preference PREF_INSTALL_ROOT = SetupInstallerPlugin.INSTANCE.getConfigurationPreference("installRoot"); |
| |
| private static final File FILE_INSTALL_ROOT = new File(SetupInstallerPlugin.INSTANCE.getUserLocation().toFile(), PREF_INSTALL_ROOT.key() + ".txt"); |
| |
| private static final String TEXT_README = "show readme file"; |
| |
| private static final String TEXT_SYSTEM_EXPLOROR = "open in system explorer"; |
| |
| private static final String TEXT_KEEP = "keep installer"; |
| |
| private static final String MESSAGE_SUCCESS = "Installation completed successfully."; |
| |
| private static final String MESSAGE_FAILURE = "Installation failed with an error."; |
| |
| protected static final boolean JRE_CHOICE = Boolean.valueOf(PropertiesUtil.getProperty(SetupProperties.PROP_SETUP_JRE_CHOICE, "true")); |
| |
| protected static final boolean INSTALL_CHOICE = Boolean.valueOf(PropertiesUtil.getProperty(SetupProperties.PROP_SETUP_INSTALL_CHOICE, "true")); |
| |
| private final SelectionMemento selectionMemento; |
| |
| private final Map<String, ProductVersion> productVersions = new HashMap<String, ProductVersion>(); |
| |
| private Product product; |
| |
| private ProductVersion selectedProductVersion; |
| |
| private String readmePath; |
| |
| private Browser detailBrowser; |
| |
| private ProductComposite detailComposite; |
| |
| private CCombo versionCombo; |
| |
| private Label versionLabel; |
| |
| private Control versionSpacer; |
| |
| private ImageCheckbox bitness32Button; |
| |
| private ImageCheckbox bitness64Button; |
| |
| private Label bitness32Spacer; |
| |
| private Label bitness64Spacer; |
| |
| private JREController javaController; |
| |
| private Label javaLabel; |
| |
| private Control javaSpacer; |
| |
| private ComboViewer javaViewer; |
| |
| private FlatButton javaButton; |
| |
| private Control javaTrailingSpacer; |
| |
| private Text folderText; |
| |
| private Label installFolderLabel; |
| |
| private Control installFolderSpacer; |
| |
| private FlatButton folderButton; |
| |
| private String installRoot; |
| |
| private String installFolder; |
| |
| private Thread installThread; |
| |
| private StackComposite installStack; |
| |
| private SimpleInstallLaunchButton installButton; |
| |
| private String installError; |
| |
| private boolean installed; |
| |
| private SetupTaskPerformer performer; |
| |
| private SimpleProgress progress; |
| |
| private FlatButton cancelButton; |
| |
| private FlatButton openInSystemExplorerButton; |
| |
| private FlatButton showReadmeButton; |
| |
| private FlatButton keepInstallerButton; |
| |
| private Composite afterInstallComposite; |
| |
| private Composite errorComposite; |
| |
| private Composite container; |
| |
| private SimpleCheckbox createStartMenuEntryButton; |
| |
| private SimpleCheckbox createDesktopShortcutButton; |
| |
| private Runnable preInstallAction; |
| |
| public SimpleVariablePage(final Composite parent, final SimpleInstallerDialog dialog, SelectionMemento selectionMemento) |
| { |
| super(parent, dialog, true); |
| this.selectionMemento = selectionMemento; |
| } |
| |
| @Override |
| protected void createContent(Composite container) |
| { |
| this.container = container; |
| |
| container.setBackgroundMode(SWT.INHERIT_FORCE); |
| container.setBackground(AbstractSimpleDialog.COLOR_WHITE); |
| |
| String powerShell = KeepInstallerUtil.getPowerShell(); |
| |
| // Row 1 |
| GridData browserLayoutData = GridDataFactory.fillDefaults().indent(0, 13).grab(true, false).create(); |
| Point defaultSize = SimpleInstallerDialog.getDefaultSize(container); |
| browserLayoutData.heightHint = defaultSize.y * (powerShell != null ? 20 : 34) / 100; |
| |
| Composite detailArea = new Composite(container, SWT.NONE); |
| detailArea.setLayoutData(browserLayoutData); |
| detailArea.setLayout(new FillLayout()); |
| |
| if (UIUtil.isBrowserAvailable()) |
| { |
| detailBrowser = new Browser(detailArea, SWT.NO_SCROLL); |
| detailBrowser.addLocationListener(new LocationAdapter() |
| { |
| @Override |
| public void changing(LocationEvent event) |
| { |
| String url = event.location; |
| if (!"about:blank".equals(url)) |
| { |
| OS.INSTANCE.openSystemBrowser(url); |
| event.doit = false; |
| } |
| } |
| }); |
| } |
| else |
| { |
| detailBrowser = null; |
| detailComposite = new ProductComposite(detailArea, null, null); |
| } |
| |
| Composite variablesComposite = new Composite(container, SWT.NONE); |
| GridLayout variablesLayout = new GridLayout(5, false); |
| variablesLayout.horizontalSpacing = 8; |
| variablesLayout.verticalSpacing = 3; |
| variablesLayout.marginLeft = 14; |
| variablesLayout.marginRight = 30; |
| variablesLayout.marginTop = 24; |
| variablesLayout.marginBottom = 0; |
| variablesLayout.marginHeight = 0; |
| variablesComposite.setLayout(variablesLayout); |
| variablesComposite.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).create()); |
| |
| // Row 3 |
| versionLabel = createLabel(variablesComposite, "Product Version"); |
| |
| // Spacer to get a little bit more distance between labels and input fields |
| versionSpacer = spacer(variablesComposite); |
| versionSpacer.setLayoutData(GridDataFactory.swtDefaults().hint(17, SWT.DEFAULT).create()); |
| |
| versionCombo = createComboBox(variablesComposite, SWT.READ_ONLY); |
| versionCombo.addSelectionListener(new SelectionAdapter() |
| { |
| @Override |
| public void widgetSelected(SelectionEvent e) |
| { |
| String label = versionCombo.getItem(versionCombo.getSelectionIndex()); |
| productVersionSelected(productVersions.get(label)); |
| UIUtil.clearTextSelection(versionCombo); |
| } |
| }); |
| |
| if (JREManager.BITNESS_CHANGEABLE) |
| { |
| bitness32Button = new ImageCheckbox(variablesComposite, SetupInstallerPlugin.INSTANCE.getSWTImage("simple/32bit_enabled.png"), |
| SetupInstallerPlugin.INSTANCE.getSWTImage("simple/32bit_selected.png")); |
| bitness32Button.setDisabledImage(SetupInstallerPlugin.INSTANCE.getSWTImage("simple/32bit_disabled.png")); |
| bitness32Button.setLayoutData(GridDataFactory.swtDefaults().align(SWT.BEGINNING, SWT.BEGINNING).indent(4, 0).hint(SWT.DEFAULT, 30).create()); |
| bitness32Button.setChecked(false); |
| bitness32Button.setVisible(JREManager.BITNESS_CHANGEABLE); |
| bitness32Button.setToolTipText("Create a 32 bit installation"); |
| bitness32Button.addSelectionListener(new SelectionAdapter() |
| { |
| @Override |
| public void widgetSelected(SelectionEvent e) |
| { |
| bitness32Button.setChecked(true); |
| bitness64Button.setChecked(false); |
| javaController.setBitness(32); |
| } |
| }); |
| |
| bitness64Button = new ImageCheckbox(variablesComposite, SetupInstallerPlugin.INSTANCE.getSWTImage("simple/64bit_enabled.png"), |
| SetupInstallerPlugin.INSTANCE.getSWTImage("simple/64bit_selected.png")); |
| bitness64Button.setDisabledImage(SetupInstallerPlugin.INSTANCE.getSWTImage("simple/64bit_disabled.png")); |
| bitness64Button.setLayoutData(GridDataFactory.swtDefaults().align(SWT.BEGINNING, SWT.BEGINNING).hint(SWT.DEFAULT, 30).create()); |
| bitness64Button.setChecked(true); |
| bitness64Button.setVisible(JREManager.BITNESS_CHANGEABLE); |
| bitness64Button.setToolTipText("Create a 64 bit installation"); |
| bitness64Button.addSelectionListener(new SelectionAdapter() |
| { |
| @Override |
| public void widgetSelected(SelectionEvent e) |
| { |
| bitness32Button.setChecked(false); |
| bitness64Button.setChecked(true); |
| javaController.setBitness(64); |
| } |
| }); |
| } |
| else |
| { |
| bitness32Spacer = new Label(variablesComposite, SWT.NONE); |
| bitness64Spacer = new Label(variablesComposite, SWT.NONE); |
| } |
| |
| // Row 4 |
| javaLabel = createLabel(variablesComposite, "Java VM"); |
| |
| javaSpacer = spacer(variablesComposite); |
| |
| final CCombo javaCombo = createComboBox(variablesComposite, SWT.READ_ONLY); |
| |
| javaViewer = new ComboViewer(javaCombo); |
| javaViewer.setContentProvider(new ArrayContentProvider()); |
| javaViewer.setLabelProvider(new LabelProvider()); |
| javaViewer.addPostSelectionChangedListener(new ISelectionChangedListener() |
| { |
| public void selectionChanged(SelectionChangedEvent event) |
| { |
| UIUtil.setSelectionToEnd(javaCombo); |
| } |
| }); |
| |
| javaButton = new ImageHoverButton(variablesComposite, SWT.PUSH, SetupInstallerPlugin.INSTANCE.getSWTImage("simple/folder.png"), |
| SetupInstallerPlugin.INSTANCE.getSWTImage("simple/folder_hover.png"), SetupInstallerPlugin.INSTANCE.getSWTImage("simple/folder_disabled.png")); |
| javaButton.setLayoutData(GridDataFactory.swtDefaults().indent(4, 0).create()); |
| javaButton.setToolTipText("Select a Java VM"); |
| javaButton.addSelectionListener(new SelectionAdapter() |
| { |
| @Override |
| public void widgetSelected(SelectionEvent e) |
| { |
| javaController.configureJREs(); |
| } |
| }); |
| |
| JREDownloadHandler downloadHandler = new JREDownloadHandler() |
| { |
| @Override |
| protected Product getProduct() |
| { |
| return product; |
| } |
| }; |
| |
| javaController = new JREController(javaLabel, javaViewer, downloadHandler) |
| { |
| @Override |
| protected void modelEmpty(boolean empty) |
| { |
| super.modelEmpty(empty); |
| validatePage(); |
| } |
| |
| @Override |
| protected void jreChanged(JRE jre) |
| { |
| super.jreChanged(jre); |
| validatePage(); |
| javaCombo.setToolTipText(jre == null ? null : jre.getJavaHome().toString()); |
| } |
| |
| @Override |
| protected void setLabel(String text) |
| { |
| super.setLabel(text + " "); |
| } |
| }; |
| |
| javaTrailingSpacer = spacer(variablesComposite); |
| |
| // Row 5 |
| installFolderLabel = createLabel(variablesComposite, "Installation Folder"); |
| installFolderSpacer = spacer(variablesComposite); |
| |
| folderText = createTextField(variablesComposite); |
| folderText.addModifyListener(new ModifyListener() |
| { |
| /** |
| * A class for delayed validation of the install folder. |
| * @author Ed Merks |
| */ |
| class Validator extends UIUtil.DelayedRunnable |
| { |
| public Validator() |
| { |
| super(folderText, 350); |
| } |
| |
| @Override |
| protected void perform() |
| { |
| validatePage(); |
| } |
| |
| @Override |
| protected void prepareForDispatch() |
| { |
| // Immediately disable the install button if the install folder is currently invalid. |
| if (validateInstallFolder() != null) |
| { |
| installButton.setEnabled(false); |
| } |
| } |
| } |
| |
| private final Validator validator = new Validator(); |
| |
| public void modifyText(ModifyEvent e) |
| { |
| final FocusSelectionAdapter focusSelectionAdapter = (FocusSelectionAdapter)folderText.getData(FocusSelectionAdapter.ADAPTER_KEY); |
| focusSelectionAdapter.setNextSelectionRange(folderText.getSelection()); |
| |
| String folder = folderText.getText().trim(); |
| installFolder = folder; |
| folderText.setToolTipText(installFolder); |
| |
| validator.schedule(); |
| |
| String productInstallFolder = getProductInstallFolder().toString(); |
| installFolderLabel.setToolTipText("Install into the folder '" + productInstallFolder + "'"); |
| installButton.setToolTipText("Start installing the product into '" + productInstallFolder + "'"); |
| } |
| }); |
| |
| new FileCompletionSupport(folderText) |
| { |
| @Override |
| protected void setFolderTextAndSelect(String folder) |
| { |
| SimpleVariablePage.this.setFolderText(folder); |
| } |
| }; |
| |
| folderButton = new ImageHoverButton(variablesComposite, SWT.PUSH, SetupInstallerPlugin.INSTANCE.getSWTImage("simple/folder.png"), |
| SetupInstallerPlugin.INSTANCE.getSWTImage("simple/folder_hover.png"), SetupInstallerPlugin.INSTANCE.getSWTImage("simple/folder_disabled.png")); |
| folderButton.setLayoutData(GridDataFactory.swtDefaults().indent(4, 0).create()); |
| folderButton.setToolTipText("Select an installation folder"); |
| folderButton.addSelectionListener(new SelectionAdapter() |
| { |
| @Override |
| public void widgetSelected(SelectionEvent e) |
| { |
| DirectoryDialog dialog = new DirectoryDialog(getShell()); |
| dialog.setText(PropertiesUtil.getProductName()); |
| dialog.setMessage("Select an installation folder:"); |
| |
| if (!StringUtil.isEmpty(installFolder)) |
| { |
| try |
| { |
| File existingFolder = IOUtil.getExistingFolder(getEffectiveInstallFolder()); |
| if (existingFolder != null) |
| { |
| dialog.setFilterPath(existingFolder.getAbsolutePath()); |
| } |
| } |
| catch (Exception ex) |
| { |
| SetupInstallerPlugin.INSTANCE.log(ex, IStatus.WARNING); |
| } |
| } |
| |
| String dir = dialog.open(); |
| if (dir != null) |
| { |
| validatePage(); |
| setFolderText(dir); |
| |
| UIUtil.getDisplay().asyncExec(new Runnable() |
| { |
| public void run() |
| { |
| folderText.setFocus(); |
| } |
| }); |
| } |
| } |
| }); |
| |
| // Pin rows |
| if (powerShell != null) |
| { |
| { |
| spacer(variablesComposite); |
| spacer(variablesComposite); |
| spacer(variablesComposite); |
| spacer(variablesComposite); |
| spacer(variablesComposite); |
| } |
| |
| { |
| spacer(variablesComposite); |
| spacer(variablesComposite); |
| spacer(variablesComposite); |
| |
| createStartMenuEntryButton = createCheckbox(variablesComposite, "create start menu entry"); |
| createStartMenuEntryButton.setChecked(PREF_STARTMENU_ENTRY.get(true)); |
| createStartMenuEntryButton.addSelectionListener(new SelectionAdapter() |
| { |
| @Override |
| public void widgetSelected(SelectionEvent e) |
| { |
| PREF_STARTMENU_ENTRY.set(createStartMenuEntryButton.isChecked()); |
| } |
| }); |
| |
| spacer(variablesComposite); |
| } |
| |
| { |
| spacer(variablesComposite); |
| spacer(variablesComposite); |
| spacer(variablesComposite); |
| |
| createDesktopShortcutButton = createCheckbox(variablesComposite, "create desktop shortcut"); |
| createDesktopShortcutButton.setChecked(PREF_DESKTOP_SHORTCUT.get(true)); |
| createDesktopShortcutButton.addSelectionListener(new SelectionAdapter() |
| { |
| @Override |
| public void widgetSelected(SelectionEvent e) |
| { |
| PREF_DESKTOP_SHORTCUT.set(createDesktopShortcutButton.isChecked()); |
| } |
| }); |
| |
| spacer(variablesComposite); |
| } |
| } |
| |
| spacer(variablesComposite); |
| spacer(variablesComposite); |
| spacer(variablesComposite); |
| |
| installButton = new SimpleInstallLaunchButton(variablesComposite); |
| Point defaultInstallButtonSize = installButton.computeSize(SWT.DEFAULT, SWT.DEFAULT); |
| installButton |
| .setLayoutData(GridDataFactory.swtDefaults().align(SWT.FILL, SWT.BEGINNING).hint(SWT.DEFAULT, defaultInstallButtonSize.y + 3).indent(0, 32).create()); |
| installButton.setCurrentState(SimpleInstallLaunchButton.State.INSTALL); |
| |
| spacer(variablesComposite); |
| spacer(variablesComposite); |
| spacer(variablesComposite); |
| spacer(variablesComposite); |
| |
| installStack = new StackComposite(variablesComposite, SWT.NONE); |
| installStack.setLayoutData(GridDataFactory.fillDefaults().hint(SWT.DEFAULT, 72).create()); |
| |
| final Composite duringInstallContainer = new Composite(installStack, SWT.NONE); |
| duringInstallContainer.setLayout(UIUtil.createGridLayout(1)); |
| |
| // During installation. |
| cancelButton = createButton(duringInstallContainer, "Cancel Installation", "Cancel", SetupInstallerPlugin.INSTANCE.getSWTImage("simple/delete.png")); |
| cancelButton.addSelectionListener(new SelectionAdapter() |
| { |
| @Override |
| public void widgetSelected(SelectionEvent e) |
| { |
| if (progress != null) |
| { |
| progress.setCanceled(true); |
| } |
| } |
| }); |
| |
| GridLayout afterInstallLayout = UIUtil.createGridLayout(1); |
| afterInstallLayout.verticalSpacing = 3; |
| |
| afterInstallComposite = new Composite(installStack, SWT.NONE); |
| afterInstallComposite.setLayout(afterInstallLayout); |
| |
| showReadmeButton = createButton(afterInstallComposite, TEXT_README, null, null); |
| showReadmeButton.addSelectionListener(new SelectionAdapter() |
| { |
| @Override |
| public void widgetSelected(SelectionEvent e) |
| { |
| if (readmePath != null) |
| { |
| String relativeProductFolder = performer.getRelativeProductFolder(); |
| java.net.URI readmeURI = new File(installFolder, relativeProductFolder + "/" + readmePath).toURI(); |
| dialog.showReadme(readmeURI); |
| } |
| } |
| }); |
| showReadmeButton.setToolTipText("Show the readme file of the installed product"); |
| |
| openInSystemExplorerButton = createButton(afterInstallComposite, TEXT_SYSTEM_EXPLOROR, null, null); |
| openInSystemExplorerButton.addSelectionListener(new SelectionAdapter() |
| { |
| @Override |
| public void widgetSelected(SelectionEvent e) |
| { |
| String launchLocation = getProductInstallFolder().toURI().toString(); |
| OS.INSTANCE.openSystemBrowser(launchLocation); |
| } |
| }); |
| |
| keepInstallerButton = createButton(afterInstallComposite, TEXT_KEEP, null, null); |
| keepInstallerButton.addSelectionListener(new SelectionAdapter() |
| { |
| @Override |
| public void widgetSelected(SelectionEvent e) |
| { |
| dialog.showKeepInstaller(); |
| } |
| }); |
| keepInstallerButton.setToolTipText(KeepInstallerUtil.KEEP_INSTALLER_DESCRIPTION); |
| |
| installButton.addSelectionListener(new SelectionAdapter() |
| { |
| @Override |
| public void widgetSelected(SelectionEvent e) |
| { |
| if (installed) |
| { |
| launchProduct(); |
| } |
| else |
| { |
| if (preInstallAction != null) |
| { |
| preInstallAction.run(); |
| } |
| |
| dialog.clearMessage(); |
| dialog.setButtonsEnabled(false); |
| |
| setEnabled(false); |
| |
| installButton.setCurrentState(State.INSTALLING); |
| installButton.setProgress(0); |
| |
| installStack.setTopControl(duringInstallContainer); |
| installStack.setVisible(true); |
| layout(true, true); |
| |
| forceFocus(); |
| |
| install(); |
| } |
| } |
| }); |
| |
| GridLayout errorLayout = UIUtil.createGridLayout(1); |
| errorLayout.verticalSpacing = 0; |
| |
| errorComposite = new Composite(installStack, SWT.NONE); |
| errorComposite.setLayout(errorLayout); |
| |
| // Exclude browser from focus traversal because otherwise we get |
| // a strange traversal behavior |
| List<Control> tabList = new ArrayList<Control>(Arrays.asList(container.getTabList())); |
| tabList.remove(detailArea); |
| container.setTabList(tabList.toArray(new Control[tabList.size()])); |
| |
| // Just for debugging |
| // installStack.setVisible(true); |
| // installStack.setTopControl(errorComposite); |
| // installButton.setProgress(0.98f); |
| // installButton.setCurrentState(InstallLaunchButton.State.INSTALLING); |
| // installButton.setEnabled(false); |
| } |
| |
| @Override |
| protected void backSelected() |
| { |
| if (promptLaunchProduct("You're about to install another product")) |
| { |
| super.backSelected(); |
| } |
| } |
| |
| public boolean promptLaunchProduct(String currentAction) |
| { |
| if (installButton != null && installButton.getCurrentState() == State.LAUNCH) |
| { |
| MessageDialog prompt = new MessageDialog(dialog, "Launch Product", null, |
| currentAction + " without having launched the installed product.\n\nDo you want to launch it now?", MessageDialog.QUESTION, |
| new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL, IDialogConstants.CANCEL_LABEL }, 0); |
| |
| int result = prompt.open(); |
| if (result == 0) |
| { |
| // Yes: Do launch; then continue. |
| launchProduct(false); |
| return true; |
| } |
| |
| if (result == 1) |
| { |
| // No: Do not launch; but continue. |
| return true; |
| } |
| |
| // Cancel: Do not launch; and do not continue. |
| return false; |
| } |
| |
| // Nothing to launch; just continue. |
| return true; |
| } |
| |
| private FlatButton createButton(Composite parent, String text, String toolTip, Image icon) |
| { |
| FlatButton button = new FlatButton(parent, SWT.PUSH); |
| button.setBackground(AbstractSimpleDialog.COLOR_LIGHTEST_GRAY); |
| button.setFocusForegroundColor(AbstractSimpleDialog.COLOR_LIGHTEST_GRAY); |
| button.setText(text); |
| button.setCornerWidth(10); |
| button.setAlignment(SWT.CENTER); |
| button.setFont(SimpleInstallerDialog.getFont(1, "normal")); |
| button.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).hint(SWT.DEFAULT, 22).create()); |
| button.setForeground(AbstractSimpleDialog.COLOR_LABEL_FOREGROUND); |
| |
| if (icon != null) |
| { |
| button.setImage(icon); |
| } |
| |
| if (toolTip != null) |
| { |
| button.setToolTipText(toolTip); |
| } |
| |
| return button; |
| } |
| |
| protected void productVersionSelected(ProductVersion productVersion) |
| { |
| if (selectedProductVersion != productVersion) |
| { |
| selectedProductVersion = productVersion; |
| |
| String requiredJavaVersion = productVersion.getRequiredJavaVersion(); |
| javaController.setJavaVersion(requiredJavaVersion); |
| |
| ProductPage.saveProductVersionSelection(installer.getCatalogManager(), selectedProductVersion); |
| |
| String toolTipText = ProductPage.getToolTipText(selectedProductVersion); |
| versionLabel.setToolTipText(toolTipText); |
| versionCombo.setToolTipText(toolTipText); |
| } |
| |
| setFolderText(getDefaultInstallationFolder()); |
| } |
| |
| @Override |
| public boolean setFocus() |
| { |
| boolean focused = folderText.setFocus(); |
| |
| // Set the cursor to the end |
| UIUtil.setSelectionToEnd(folderText); |
| |
| return focused; |
| } |
| |
| public void setProduct(Product product) |
| { |
| ProductVersion defaultProductVersion = ProductPage.getDefaultProductVersion(installer.getCatalogManager(), product); |
| List<ProductVersion> validProductVersions = ProductPage.getValidProductVersions(product, PRODUCT_VERSION_FILTER); |
| for (ProductVersion productVersion : validProductVersions) |
| { |
| if (defaultProductVersion == null || !validProductVersions.contains(defaultProductVersion)) |
| { |
| defaultProductVersion = productVersion; |
| } |
| } |
| |
| if (defaultProductVersion != null) |
| { |
| setProductVersion(defaultProductVersion); |
| } |
| } |
| |
| public void setProductVersion(ProductVersion productVersion) |
| { |
| product = productVersion.getProduct(); |
| |
| if (detailBrowser != null) |
| { |
| String html = SimpleInstallerDialog.getPageTemplate(); |
| html = html.replace("%CONTENT%", SimpleProductPage.renderProduct(product, true)); |
| |
| detailBrowser.setText(html, true); |
| } |
| else |
| { |
| detailComposite.setProduct(product); |
| } |
| |
| productVersions.clear(); |
| versionCombo.removeAll(); |
| |
| int i = 0; |
| int selection = -1; |
| List<ProductVersion> validProductVersions = ProductPage.getValidProductVersions(product, PRODUCT_VERSION_FILTER); |
| for (ProductVersion version : validProductVersions) |
| { |
| String label = SetupCoreUtil.getLabel(version); |
| productVersions.put(label, version); |
| versionCombo.add(label); |
| |
| if (version == productVersion) |
| { |
| selection = i; |
| } |
| |
| ++i; |
| } |
| |
| // If the product version is filtered out of the valid available versions, add a choice for it anyway. |
| if (selection == -1) |
| { |
| String label = SetupCoreUtil.getLabel(productVersion); |
| productVersions.put(label, productVersion); |
| versionCombo.add(label); |
| selection = i; |
| } |
| |
| versionCombo.select(selection); |
| productVersionSelected(productVersion); |
| UIUtil.setSelectionToEnd(versionCombo); |
| |
| installButton.setCurrentState(State.INSTALL); |
| installStack.setVisible(false); |
| installed = false; |
| |
| UIUtil.asyncExec(container, new Runnable() |
| { |
| public void run() |
| { |
| setEnabled(true); |
| } |
| }); |
| } |
| |
| private void setVisible(Control control, boolean visible) |
| { |
| if (control != null) |
| { |
| control.setVisible(visible); |
| |
| Object layoutData = control.getLayoutData(); |
| if (layoutData == null) |
| { |
| layoutData = new GridData(); |
| control.setLayoutData(layoutData); |
| } |
| |
| if (layoutData instanceof GridData) |
| { |
| GridData gridData = (GridData)layoutData; |
| gridData.exclude = !visible; |
| } |
| } |
| } |
| |
| @Override |
| public void setEnabled(boolean enabled) |
| { |
| super.setEnabled(enabled); |
| versionCombo.setEnabled(enabled); |
| |
| javaViewer.getControl().setEnabled(enabled); |
| javaButton.setEnabled(enabled); |
| |
| folderText.setEnabled(enabled); |
| folderButton.setEnabled(enabled); |
| |
| if (createStartMenuEntryButton != null) |
| { |
| createStartMenuEntryButton.setEnabled(enabled); |
| } |
| |
| if (createDesktopShortcutButton != null) |
| { |
| createDesktopShortcutButton.setEnabled(enabled); |
| } |
| |
| boolean versionVisible = versionCombo.getItemCount() != 1; |
| setVisible(versionLabel, versionVisible); |
| setVisible(versionSpacer, versionVisible); |
| setVisible(versionCombo.getParent(), versionVisible); |
| setVisible(bitness32Button, versionVisible); |
| setVisible(bitness32Spacer, versionVisible); |
| setVisible(bitness64Button, versionVisible); |
| setVisible(bitness64Spacer, versionVisible); |
| |
| if (JREManager.BITNESS_CHANGEABLE) |
| { |
| int bitness = javaController.getBitness(); |
| bitness32Button.setEnabled(enabled); |
| bitness32Button.setVisible(versionVisible && (enabled || bitness == 32)); |
| bitness64Button.setEnabled(enabled); |
| bitness64Button.setVisible(versionVisible && (enabled || bitness == 64)); |
| } |
| |
| IStructuredSelection structuredSelection = (IStructuredSelection)javaViewer.getSelection(); |
| boolean javaVisible = JRE_CHOICE || !(structuredSelection.getFirstElement() instanceof JRE); |
| setVisible(javaLabel, javaVisible); |
| setVisible(javaSpacer, javaVisible); |
| setVisible(javaViewer.getCCombo().getParent(), javaVisible); |
| setVisible(javaButton, javaVisible); |
| setVisible(javaTrailingSpacer, javaVisible); |
| |
| setVisible(folderText, INSTALL_CHOICE); |
| setVisible(folderText.getParent(), INSTALL_CHOICE); |
| setVisible(installFolderLabel, INSTALL_CHOICE); |
| setVisible(installFolderSpacer, INSTALL_CHOICE); |
| setVisible(folderButton, INSTALL_CHOICE); |
| |
| container.layout(true, true); |
| } |
| |
| public boolean refreshJREs() |
| { |
| if (javaController != null) |
| { |
| javaController.refresh(); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| private File getProductInstallFolder() |
| { |
| String productFolderName = SetupTaskPerformer.getProductFolderName(selectedProductVersion, OS.INSTANCE); |
| String relativeProductFolderName = OS.INSTANCE.getRelativeProductFolder(productFolderName); |
| File result = new File(getEffectiveInstallFolder(), relativeProductFolderName); |
| return result; |
| } |
| |
| private String getDefaultInstallationFolder() |
| { |
| String name = product.getName(); |
| int lastDot = name.lastIndexOf('.'); |
| if (lastDot != -1) |
| { |
| name = name.substring(lastDot + 1); |
| } |
| |
| name += "-" + selectedProductVersion.getName().replace('.', '-'); |
| |
| if (installRoot == null) |
| { |
| installRoot = PropertiesUtil.getProperty(PROP_INSTALL_ROOT); |
| } |
| |
| if (installRoot == null) |
| { |
| if (FILE_INSTALL_ROOT.isFile()) |
| { |
| List<String> lines = IOUtil.readLines(FILE_INSTALL_ROOT, "UTF-8"); |
| if (lines != null && !lines.isEmpty()) |
| { |
| installRoot = lines.get(0); |
| if (installRoot.length() == 0) |
| { |
| installRoot = null; |
| } |
| } |
| } |
| |
| if (installRoot == null) |
| { |
| // Default to ${user.home}/eclipse, unless there is a file at that location, or what looks like an existing Eclipse installation. |
| // In that case default just to ${user.home}. |
| String defaultValue = PropertiesUtil.getUserHome(); |
| File defaultInstallRoot = new File(defaultValue, "eclipse"); |
| if (!defaultInstallRoot.exists()) |
| { |
| defaultValue = defaultInstallRoot.toString(); |
| } |
| else if (defaultInstallRoot.isDirectory()) |
| { |
| boolean isEclipseInstallation = false; |
| for (File file : defaultInstallRoot.listFiles()) |
| { |
| if ("eclipse.ini".equals(file.getName())) |
| { |
| isEclipseInstallation = true; |
| } |
| } |
| |
| if (!isEclipseInstallation) |
| { |
| defaultValue = defaultInstallRoot.toString(); |
| } |
| } |
| |
| installRoot = PREF_INSTALL_ROOT.get(defaultValue); |
| } |
| } |
| |
| for (int i = 1; i < 1000; i++) |
| { |
| String filename = name; |
| if (i != 1) |
| { |
| filename += i; |
| } |
| |
| File folder = new File(installRoot, filename); |
| if (!folder.exists()) |
| { |
| return folder.getAbsolutePath(); |
| } |
| } |
| |
| throw new IllegalStateException("User home is full"); |
| } |
| |
| private void install() |
| { |
| installThread = new Thread() |
| { |
| @Override |
| public void run() |
| { |
| installError = null; |
| performer = null; |
| progress = new SimpleProgress(); |
| |
| try |
| { |
| installPerform(); |
| } |
| catch (InterruptedException ex) |
| { |
| installCancel(); |
| } |
| catch (OperationCanceledException ex) |
| { |
| installCancel(); |
| } |
| catch (UnloggedException ex) |
| { |
| installError = ex.getMessage(); |
| } |
| catch (Exception ex) |
| { |
| if (!progress.isCanceled()) |
| { |
| SetupInstallerPlugin.INSTANCE.log(ex); |
| installError = MESSAGE_FAILURE; |
| } |
| } |
| finally |
| { |
| if (performer != null) |
| { |
| IOUtil.close(performer.getLogStream()); |
| } |
| |
| if (!progress.isCanceled()) |
| { |
| UIUtil.syncExec(new Runnable() |
| { |
| public void run() |
| { |
| try |
| { |
| installFinished(); |
| } |
| catch (SWTException ex) |
| { |
| //$FALL-THROUGH$ |
| } |
| } |
| }); |
| } |
| } |
| } |
| }; |
| |
| installThread.setDaemon(true); |
| installThread.start(); |
| } |
| |
| @SuppressWarnings("restriction") |
| private void installPerform() throws Exception |
| { |
| if (dialog.getPool() != null) |
| { |
| P2Util.getAgentManager().setDefaultBundlePool(SetupUIPlugin.INSTANCE.getSymbolicName(), dialog.getPool()); |
| System.setProperty(AgentManager.PROP_BUNDLE_POOL_LOCATION, dialog.getPool().getLocation().getAbsolutePath()); |
| } |
| else |
| { |
| System.setProperty(AgentManager.PROP_BUNDLE_POOL_LOCATION, AgentManager.BUNDLE_POOL_LOCATION_NONE); |
| } |
| |
| JRE jre = javaController.getJRE(); |
| String vmPath = ProductPage.getVMOption(jre); |
| |
| ResourceSet resourceSet = installer.getResourceSet(); |
| URIConverter uriConverter = resourceSet.getURIConverter(); |
| |
| SetupContext setupContext = SetupContext.create(resourceSet, selectedProductVersion); |
| Installation installation = setupContext.getInstallation(); |
| final User user = setupContext.getUser(); |
| |
| if (UIUtil.isBrowserAvailable()) |
| { |
| UIUtil.syncExec(new Runnable() |
| { |
| public void run() |
| { |
| EList<LicenseInfo> licenses = LicensePrePrompter.execute(getShell(), user); |
| if (licenses != null) |
| { |
| user.getAcceptedLicenses().addAll(licenses); |
| BaseUtil.saveEObject(user); |
| } |
| } |
| }); |
| } |
| |
| UserAdjuster userAdjuster = new UserAdjuster(); |
| userAdjuster.adjust(user, installFolder); |
| |
| try |
| { |
| IOUtil.writeLines(FILE_INSTALL_ROOT, "UTF-8", Collections.singletonList(installRoot)); |
| |
| SimplePrompter prompter = new SimplePrompter(OS.INSTANCE.getForBitness(javaController.getBitness()), vmPath); |
| performer = SetupTaskPerformer.create(uriConverter, prompter, Trigger.BOOTSTRAP, setupContext, false); |
| |
| final List<VariableTask> unresolvedVariables = prompter.getUnresolvedVariables(); |
| if (!unresolvedVariables.isEmpty()) |
| { |
| StringBuilder builder = new StringBuilder(); |
| for (VariableTask variable : unresolvedVariables) |
| { |
| if (builder.length() != 0) |
| { |
| builder.append(", "); |
| } |
| |
| builder.append(variable.getName()); |
| } |
| |
| final String variables = builder.toString(); |
| final boolean multi = unresolvedVariables.size() > 1; |
| |
| UIUtil.syncExec(new Runnable() |
| { |
| public void run() |
| { |
| String message = "The variable" + (multi ? "s" : "") + " " + variables + " " + (multi ? "are" : "is") + " undefined. You likely declared " |
| + (multi ? "them" : "it") |
| + " in your 'user.setup' file without appropriate restrictions, so that you can't use the installer's simple mode anymore." |
| + "\n\nDo you want to switch to the advanced mode now?"; |
| |
| if (MessageDialog.openQuestion(getShell(), "Undefined Variables", message)) |
| { |
| unresolvedVariables.clear(); |
| dialog.switchToAdvancedMode(); |
| } |
| } |
| }); |
| |
| if (unresolvedVariables.isEmpty()) |
| { |
| return; |
| } |
| |
| throw new UnloggedException("Undefined variable" + (multi ? "s" : "") + ": " + variables); |
| } |
| |
| EList<SetupTask> triggeredSetupTasks = performer.getTriggeredSetupTasks(); |
| final Map<EClass, EList<SetupTask>> enablementTasks = EnablementComposite.getEnablementTasks(triggeredSetupTasks); |
| if (!enablementTasks.isEmpty()) |
| { |
| UIUtil.syncExec( |
| |
| getDisplay(), new Runnable() |
| { |
| public void run() |
| { |
| EnablementDialog enablementDialog = new EnablementDialog(getShell(), "the installer", enablementTasks); |
| if (enablementDialog.open() == EnablementDialog.OK) |
| { |
| selectionMemento.setProductVersion(EcoreUtil.getURI(selectedProductVersion)); |
| dialog.restart(); |
| } |
| |
| installCancel(); |
| } |
| }); |
| |
| throw new OperationCanceledException(); |
| } |
| |
| performer.getUnresolvedVariables().clear(); |
| performer.put(UIServices.class, Installer.SERVICE_UI); |
| |
| if (performer.get(ILicense.class) == null) |
| { |
| performer.put(ILicense.class, ProgressPage.LICENSE_CONFIRMER); |
| } |
| |
| if (performer.get(Certificate.class) == null) |
| { |
| performer.put(Certificate.class, UnsignedContentDialog.createUnsignedContentConfirmer(user, false)); |
| } |
| |
| performer.setOffline(PropertiesUtil.isProperty(SetupProperties.PROP_SETUP_OFFLINE_STARTUP)); |
| performer.setMirrors(true); |
| performer.setProgress(progress); |
| performer.log("Executing " + performer.getTrigger().toString().toLowerCase() + " tasks"); |
| performer.put(org.eclipse.equinox.internal.provisional.p2.core.eventbus.ProvisioningListener.class, new DownloadArtifactLister()); |
| performer.perform(progress); |
| performer.recordVariables(installation, null, user); |
| performer.savePasswords(); |
| |
| File configurationLocation = performer.getProductConfigurationLocation(); |
| installation.eResource().setURI(URI.createFileURI(new File(configurationLocation, "org.eclipse.oomph.setup/installation.setup").toString())); |
| BaseUtil.saveEObject(installation); |
| } |
| finally |
| { |
| userAdjuster.undo(); |
| BaseUtil.saveEObject(user); |
| } |
| } |
| |
| private void installCancel() |
| { |
| if (progress != null) |
| { |
| progress.setCanceled(true); |
| } |
| |
| if (installThread != null) |
| { |
| installThread.interrupt(); |
| } |
| |
| UIUtil.syncExec(getDisplay(), new Runnable() |
| { |
| public void run() |
| { |
| dialog.setButtonsEnabled(true); |
| setEnabled(true); |
| |
| installButton.setCurrentState(State.INSTALL); |
| installStack.setVisible(false); |
| |
| dialog.clearMessage(); |
| } |
| }); |
| } |
| |
| private void installFinished() |
| { |
| readmePath = null; |
| boolean success = installError == null; |
| |
| if (performer != null) |
| { |
| Installation installation = performer.getInstallation(); |
| if (installation != null) |
| { |
| ProductVersion productVersion = installation.getProductVersion(); |
| if (productVersion != null) |
| { |
| OS os = performer.getOS(); |
| SetupCoreUtil.sendStats(success, productVersion, os); |
| } |
| } |
| } |
| |
| if (success) |
| { |
| installed = true; |
| |
| installButton.setCurrentState(State.LAUNCH); |
| File launchLocation = performer.getExecutableInfo().getLaunchLocation(); |
| installButton.setToolTipText("Launch '" + launchLocation + "'"); |
| |
| keepInstallerButton.setVisible(KeepInstallerUtil.canKeepInstaller()); |
| |
| Scope scope = selectedProductVersion; |
| while (scope != null) |
| { |
| Annotation annotation = scope.getAnnotation(AnnotationConstants.ANNOTATION_BRANDING_INFO); |
| if (annotation != null) |
| { |
| readmePath = annotation.getDetails().get(AnnotationConstants.KEY_README_PATH); |
| if (readmePath != null) |
| { |
| break; |
| } |
| } |
| |
| scope = scope.getParentScope(); |
| } |
| |
| showReadmeButton.setVisible(readmePath != null); |
| |
| openInSystemExplorerButton.setToolTipText("Open the folder '" + getProductInstallFolder() + "' in the system explorer"); |
| |
| if (createStartMenuEntryButton != null || createDesktopShortcutButton != null) |
| { |
| File executable = performer.getExecutableInfo().getExecutable(); |
| |
| // TODO The entire naming of the shortcuts should be revisited and made more flexible with BrandingInfo annotations. |
| |
| ProductCatalog productCatalog = product.getProductCatalog(); |
| String catalogName = "user.products".equals(productCatalog.getName()) ? "" : productCatalog.getLabel(); |
| int firstDot = catalogName.indexOf('.'); |
| if (firstDot != -1) |
| { |
| catalogName = catalogName.substring(0, firstDot); |
| } |
| |
| String productName = product.getName(); |
| if (productName.startsWith("epp.package.")) |
| { |
| productName = productName.substring("epp.package.".length()); |
| } |
| |
| productName = productName.replace('.', ' '); |
| |
| String qualifiedProductName = productName + " " + selectedProductVersion.getName().replace('.', ' '); |
| |
| String shortCutName = StringUtil.capAll(StringUtil.isEmpty(catalogName) ? qualifiedProductName : catalogName + " " + qualifiedProductName); |
| |
| if (createStartMenuEntryButton != null && createStartMenuEntryButton.isChecked()) |
| { |
| KeepInstallerUtil.createShortCut("Programs", "Eclipse", executable.getAbsolutePath(), shortCutName); |
| } |
| |
| if (createDesktopShortcutButton != null && createDesktopShortcutButton.isChecked()) |
| { |
| KeepInstallerUtil.createShortCut("Desktop", null, executable.getAbsolutePath(), shortCutName); |
| } |
| } |
| |
| showSuccessMessage(); |
| |
| backButton.setEnabled(true); |
| } |
| else |
| { |
| setEnabled(true); |
| installButton.setCurrentState(State.INSTALL); |
| showErrorMessage(); |
| } |
| |
| dialog.setButtonsEnabled(true); |
| } |
| |
| private void showSuccessMessage() |
| { |
| dialog.showMessage(MESSAGE_SUCCESS, Type.SUCCESS, true); |
| |
| installStack.setTopControl(afterInstallComposite); |
| installStack.setVisible(true); |
| layout(true, true); |
| } |
| |
| private void showErrorMessage() |
| { |
| Runnable action = null; |
| String errorMessage = installError; |
| |
| if (isInstallLogAvailable()) |
| { |
| action = new SimpleMessageOverlay.RunnableWithLabel() |
| { |
| public void run() |
| { |
| openInstallLog(); |
| } |
| |
| public String getLabel() |
| { |
| return "Show log."; |
| } |
| }; |
| } |
| |
| dialog.showMessage(errorMessage, Type.ERROR, false, action); |
| |
| installStack.setTopControl(errorComposite); |
| installStack.setVisible(true); |
| layout(true, true); |
| } |
| |
| private void launchProduct() |
| { |
| launchProduct(EXIT_AFTER_LAUNCH); |
| } |
| |
| private void launchProduct(boolean exitAfterLaunch) |
| { |
| try |
| { |
| ProgressPage.launchProduct(performer); |
| } |
| catch (Exception ex) |
| { |
| SetupInstallerPlugin.INSTANCE.log(ex); |
| } |
| |
| if (exitAfterLaunch) |
| { |
| dialog.exitQuiet(); |
| } |
| } |
| |
| private void setFolderText(String folder) |
| { |
| folderText.setText(folder); |
| |
| final FocusSelectionAdapter focusSelectionAdapter = (FocusSelectionAdapter)folderText.getData(FocusSelectionAdapter.ADAPTER_KEY); |
| int index = folder.length(); |
| Point selection = new Point(index, index); |
| folderText.setSelection(selection); |
| focusSelectionAdapter.setNextSelectionRange(selection); |
| } |
| |
| private void validatePage() |
| { |
| preInstallAction = null; |
| |
| String errorMessage = null; |
| |
| Type type = Type.ERROR; |
| errorMessage = validateJREs(); |
| |
| if (errorMessage == null && installFolder != null) |
| { |
| Pair<Type, String> folderValidationMesage = validateInstallFolder(); |
| if (folderValidationMesage != null) |
| { |
| type = folderValidationMesage.getElement1(); |
| errorMessage = folderValidationMesage.getElement2(); |
| } |
| |
| if (errorMessage == null || type == Type.WARNING) |
| { |
| OS os = OS.INSTANCE.getForBitness(javaController.getBitness()); |
| String productFolderName = AbstractSetupTaskContext.getProductFolderName(selectedProductVersion, os); |
| String relativeProductFolderName = OS.INSTANCE.getRelativeProductFolder(productFolderName); |
| folderValidationMesage = validateChildFolder(IOUtil.getCanonicalFile(getEffectiveInstallFolder()), relativeProductFolderName, true); |
| if (folderValidationMesage != null) |
| { |
| type = folderValidationMesage.getElement1(); |
| errorMessage = folderValidationMesage.getElement2(); |
| } |
| } |
| } |
| |
| if (isTop()) |
| { |
| if (errorMessage != null) |
| { |
| if (type == Type.WARNING) |
| { |
| preInstallAction = new Runnable() |
| { |
| public void run() |
| { |
| preInstallAction = null; |
| String folder = IOUtil.getCanonicalFile(getEffectiveInstallFolder()).toString(); |
| setFolderText(folder); |
| } |
| }; |
| } |
| |
| dialog.showMessage(errorMessage, type, false, preInstallAction, preInstallAction); |
| } |
| else |
| { |
| dialog.clearMessage(); |
| } |
| } |
| |
| installButton.setEnabled(errorMessage == null || type == Type.WARNING); |
| } |
| |
| @Override |
| public void aboutToShow() |
| { |
| super.aboutToShow(); |
| keepInstallerButton.setVisible(KeepInstallerUtil.canKeepInstaller()); |
| |
| if (!installed) |
| { |
| validatePage(); |
| } |
| } |
| |
| private String validateJREs() |
| { |
| Object input = javaViewer.getInput(); |
| if (input instanceof Collection<?> && ((Collection<?>)input).isEmpty()) |
| { |
| return "Configuration of JRE failed."; |
| } |
| |
| return null; |
| } |
| |
| private File getEffectiveInstallFolder() |
| { |
| File folder = new File(installFolder.trim()); |
| if (!folder.isAbsolute()) |
| { |
| folder = new File(PropertiesUtil.getUserHome(), "eclipse/" + installFolder.trim()); |
| } |
| |
| return folder; |
| } |
| |
| private Pair<Type, String> validateInstallFolder() |
| { |
| File canonicalFolder = IOUtil.getCanonicalFile(getEffectiveInstallFolder()); |
| File parentFolder = canonicalFolder.getParentFile(); |
| Pair<Type, String> errorMessage = validateFolder(canonicalFolder.getParentFile(), canonicalFolder.getName()); |
| if (errorMessage != null) |
| { |
| return errorMessage; |
| } |
| |
| if (!canonicalFolder.toString().equals(installFolder.trim())) |
| { |
| if (StringUtil.isEmpty(installFolder.trim())) |
| { |
| return Pair.create(Type.WARNING, "The folder is unspecified so '" + canonicalFolder + "' will be used."); |
| } |
| |
| return Pair.create(Type.WARNING, "The folder is specified as '" + installFolder + "' but '" + canonicalFolder + "' will be used."); |
| } |
| |
| installRoot = parentFolder == null ? canonicalFolder.getAbsolutePath() : parentFolder.getAbsolutePath(); |
| |
| return errorMessage; |
| } |
| |
| private Pair<Type, String> validateFolder(File parentFolder, String childFolder) |
| { |
| if (parentFolder == null) |
| { |
| return Pair.create(Type.ERROR, "The product cannot be installed in the root of the file system."); |
| } |
| |
| if (parentFolder.exists()) |
| { |
| if (parentFolder.isDirectory()) |
| { |
| if (IOUtil.canWriteFolder(parentFolder)) |
| { |
| try |
| { |
| new File(parentFolder, childFolder).getCanonicalFile(); |
| Pair<Type, String> result = validateChildFolder(parentFolder, childFolder, false); |
| |
| // The folder exists, but that's not a problem we want to report in this case. |
| if (result == null || result.getElement1() == Type.WARNING) |
| { |
| return null; |
| } |
| |
| return result; |
| } |
| catch (Exception ex) |
| { |
| return Pair.create(Type.ERROR, "Folder '" + childFolder + "' cannot be created in the folder '" + parentFolder + "'."); |
| } |
| } |
| |
| Pair<Type, String> result = validateChildFolder(parentFolder, childFolder, false); |
| if (result != null) |
| { |
| // The folder exists, but that's not a problem we want to report in this case. |
| if (result.getElement1() == Type.WARNING) |
| { |
| return null; |
| } |
| |
| return result; |
| } |
| |
| return Pair.create(Type.ERROR, "Folder '" + childFolder + "' cannot be created in the read-only folder '" + parentFolder + "'."); |
| } |
| |
| return Pair.create(Type.ERROR, |
| "Folder '" + childFolder + "' cannot be created in the folder '" + parentFolder + "' because '" + parentFolder.getName() + "' exists as a file."); |
| } |
| |
| return validateFolder(parentFolder.getParentFile(), parentFolder.getName()); |
| } |
| |
| private Pair<Type, String> validateChildFolder(File parentFolder, String childFolder, boolean isProductLocation) |
| { |
| String prefix = isProductLocation ? "Product folder '" : "Folder '"; |
| File child = new File(parentFolder, childFolder); |
| if (child.exists()) |
| { |
| if (child.isDirectory()) |
| { |
| if (IOUtil.canWriteFolder(child)) |
| { |
| return Pair.create(Type.WARNING, prefix + child + " already exists."); |
| } |
| |
| return Pair.create(Type.ERROR, prefix + child + "' cannot be used because it is read-only."); |
| } |
| |
| return Pair.create(Type.ERROR, prefix + child + "' cannot be used because it exists as file."); |
| } |
| |
| try |
| { |
| new File(parentFolder, childFolder).getCanonicalFile(); |
| } |
| catch (Exception ex) |
| { |
| return Pair.create(Type.ERROR, prefix + childFolder + "' cannot be created."); |
| } |
| |
| return null; |
| } |
| |
| private File getLogFile() |
| { |
| return performer.getLogFile(); |
| } |
| |
| private void openInstallLog() |
| { |
| File installationLogFile = getLogFile(); |
| dialog.showInstallationLog(installationLogFile); |
| } |
| |
| private boolean isInstallLogAvailable() |
| { |
| return performer != null && getLogFile().exists(); |
| } |
| |
| private SimpleCheckbox createCheckbox(Composite parent, String text) |
| { |
| final SimpleCheckbox checkbox = new SimpleCheckbox(parent); |
| checkbox.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).create()); |
| checkbox.setText(text); |
| checkbox.setChecked(true); |
| return checkbox; |
| } |
| |
| /** |
| * @author Ed Merks |
| */ |
| @SuppressWarnings("restriction") |
| private class DownloadArtifactLister implements org.eclipse.equinox.internal.provisional.p2.core.eventbus.SynchronousProvisioningListener |
| { |
| public synchronized void notify(EventObject event) |
| { |
| if (event instanceof DownloadArtifactEvent) |
| { |
| DownloadArtifactEvent downloadArtifactEvent = (DownloadArtifactEvent)event; |
| URI artifactURI = URI.createURI(downloadArtifactEvent.getArtifactURI().toString()); |
| if (downloadArtifactEvent.isCompleted()) |
| { |
| progress.removeArtifactURI(artifactURI); |
| } |
| else |
| { |
| progress.addArtifactURI(artifactURI); |
| } |
| } |
| } |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private static final class UnloggedException extends RuntimeException |
| { |
| private static final long serialVersionUID = 1L; |
| |
| public UnloggedException(String message) |
| { |
| super(message); |
| } |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private static class UserAdjuster |
| { |
| private static final URI INSTALLATION_LOCATION_ATTRIBUTE_URI = SetupTaskPerformer.getAttributeURI(SetupPackage.Literals.INSTALLATION_TASK__LOCATION); |
| |
| private EList<AttributeRule> attributeRules; |
| |
| private String oldValue; |
| |
| private void adjust(User user, String installFolder) |
| { |
| attributeRules = user.getAttributeRules(); |
| for (AttributeRule attributeRule : attributeRules) |
| { |
| if (INSTALLATION_LOCATION_ATTRIBUTE_URI.equals(attributeRule.getAttributeURI())) |
| { |
| oldValue = attributeRule.getValue(); |
| attributeRule.setValue(installFolder); |
| return; |
| } |
| } |
| |
| AttributeRule attributeRule = SetupFactory.eINSTANCE.createAttributeRule(); |
| attributeRule.setAttributeURI(INSTALLATION_LOCATION_ATTRIBUTE_URI); |
| attributeRule.setValue(installFolder); |
| attributeRules.add(attributeRule); |
| } |
| |
| public void undo() |
| { |
| for (Iterator<AttributeRule> it = attributeRules.iterator(); it.hasNext();) |
| { |
| AttributeRule attributeRule = it.next(); |
| if (INSTALLATION_LOCATION_ATTRIBUTE_URI.equals(attributeRule.getAttributeURI())) |
| { |
| if (oldValue == null) |
| { |
| it.remove(); |
| } |
| else |
| { |
| attributeRule.setValue(oldValue); |
| } |
| |
| return; |
| } |
| } |
| } |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private final class SimplePrompter extends HashMap<String, String> implements SetupPrompter |
| { |
| private static final long serialVersionUID = 1L; |
| |
| private final List<VariableTask> unresolvedVariables = new ArrayList<VariableTask>(); |
| |
| private final OS os; |
| |
| private final String vmPath; |
| |
| public OS getOS() |
| { |
| return os; |
| } |
| |
| public SimplePrompter(OS os, String vmPath) |
| { |
| this.os = os; |
| this.vmPath = vmPath; |
| } |
| |
| public String getVMPath() |
| { |
| return vmPath; |
| } |
| |
| public List<VariableTask> getUnresolvedVariables() |
| { |
| return unresolvedVariables; |
| } |
| |
| public boolean promptVariables(List<? extends SetupTaskContext> performers) |
| { |
| for (SetupTaskContext performer : performers) |
| { |
| List<VariableTask> unresolvedVariables = ((SetupTaskPerformer)performer).getUnresolvedVariables(); |
| for (VariableTask variable : unresolvedVariables) |
| { |
| String value = getValue(variable); |
| if (value == null) |
| { |
| this.unresolvedVariables.add(variable); |
| } |
| } |
| } |
| |
| return unresolvedVariables.isEmpty(); |
| } |
| |
| public String getValue(VariableTask variable) |
| { |
| String name = variable.getName(); |
| return get(name); |
| } |
| |
| public UserCallback getUserCallback() |
| { |
| return null; |
| } |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private final class SimpleProgress implements ProgressLog, IProgressMonitor, Runnable |
| { |
| private volatile String name; |
| |
| private volatile double totalWork; |
| |
| private volatile double work; |
| |
| private volatile double lastWork; |
| |
| private volatile long reportWarningTimeout; |
| |
| private volatile boolean canceled; |
| |
| private volatile boolean done; |
| |
| private String lastName; |
| |
| private final Set<URI> artifactURIs = new HashSet<URI>(); |
| |
| private Set<URI> lastArtifactURIs; |
| |
| public synchronized void addArtifactURI(URI uri) |
| { |
| artifactURIs.add(uri); |
| } |
| |
| public synchronized void removeArtifactURI(URI uri) |
| { |
| artifactURIs.remove(uri); |
| } |
| |
| public void setTerminating() |
| { |
| } |
| |
| public void log(String line) |
| { |
| log(line, true, Severity.OK); |
| } |
| |
| public void log(String line, Severity severity) |
| { |
| log(line, true, severity); |
| } |
| |
| public void log(String line, boolean filter) |
| { |
| log(line, filter, Severity.OK); |
| } |
| |
| public synchronized void log(String line, boolean filter, Severity severity) |
| { |
| name = line; |
| } |
| |
| public void log(IStatus status) |
| { |
| String string = SetupInstallerPlugin.toString(status); |
| log(string, false); |
| } |
| |
| public void log(Throwable t) |
| { |
| String string = SetupInstallerPlugin.toString(t); |
| log(string, false); |
| } |
| |
| public synchronized void task(SetupTask setupTask) |
| { |
| if (setupTask != null) |
| { |
| name = "Performing setup task " + setupTask.eClass().getName(); |
| } |
| else |
| { |
| name = null; |
| } |
| } |
| |
| public synchronized boolean isCanceled() |
| { |
| return canceled; |
| } |
| |
| public synchronized void setCanceled(boolean canceled) |
| { |
| this.canceled = canceled; |
| } |
| |
| public synchronized void beginTask(String name, int totalWork) |
| { |
| performer.log(name); |
| if (this.totalWork == 0) |
| { |
| this.totalWork = totalWork; |
| schedule(); |
| } |
| } |
| |
| public synchronized void done() |
| { |
| work = totalWork; |
| done = true; |
| } |
| |
| public synchronized void setTaskName(String name) |
| { |
| performer.log(name); |
| } |
| |
| public synchronized void subTask(String name) |
| { |
| performer.log(name); |
| } |
| |
| public synchronized void internalWorked(double work) |
| { |
| this.work += work; |
| } |
| |
| public void worked(int work) |
| { |
| internalWorked(work); |
| } |
| |
| public void run() |
| { |
| String name; |
| double totalWork; |
| double work; |
| boolean canceled; |
| boolean done; |
| Set<URI> artifactURIs; |
| |
| synchronized (this) |
| { |
| name = this.name; |
| totalWork = this.totalWork; |
| work = this.work; |
| canceled = this.canceled; |
| done = this.done; |
| artifactURIs = new HashSet<URI>(this.artifactURIs); |
| } |
| |
| if (!canceled && !done) |
| { |
| String safeName = StringUtil.safe(name); |
| |
| if (PROGRESS_WATCHDOG_TIMEOUT != 0) |
| { |
| long now = System.currentTimeMillis(); |
| boolean slowArtifactDownload = !artifactURIs.isEmpty() && artifactURIs.equals(lastArtifactURIs); |
| if ((lastWork == work || slowArtifactDownload) && !isModalShellInForeground()) |
| { |
| if (now >= reportWarningTimeout) |
| { |
| if (slowArtifactDownload) |
| { |
| StringBuilder message = new StringBuilder(); |
| Set<URI> hosts = new HashSet<URI>(); |
| for (URI artifactURI : artifactURIs) |
| { |
| URI hostURI = URI.createHierarchicalURI(artifactURI.scheme(), artifactURI.authority(), null, null, null); |
| if (hosts.add(hostURI)) |
| { |
| if (message.length() != 0) |
| { |
| message.append(", "); |
| } |
| |
| message.append(hostURI); |
| } |
| } |
| |
| if (hosts.size() > 1) |
| { |
| message.insert(0, "the following hosts: "); |
| } |
| |
| message.insert(0, "Artifact download is progressing very slowly from "); |
| dialog.showMessage(message.toString().replace(' ', '\u00a0'), Type.WARNING, false); |
| } |
| else |
| { |
| dialog.showMessage(("The installation process is taking longer than usual: " + safeName).replace(' ', '\u00a0'), Type.WARNING, false); |
| } |
| |
| installButton.setProgressAnimationSpeed(0.4f); |
| resetWatchdogTimer(now); |
| } |
| } |
| else |
| { |
| installButton.startProgressAnimation(); |
| installButton.setProgressAnimationSpeed(1); |
| dialog.clearMessage(); |
| resetWatchdogTimer(now); |
| } |
| |
| lastWork = work; |
| lastArtifactURIs = artifactURIs; |
| } |
| |
| double progress = work / totalWork; |
| |
| try |
| { |
| installButton.setProgress((float)progress); |
| |
| if (!ObjectUtil.equals(name, lastName)) |
| { |
| lastName = name; |
| installButton.setToolTipText(safeName); |
| } |
| } |
| catch (SWTException ex) |
| { |
| return; |
| } |
| |
| reschedule(); |
| } |
| } |
| |
| private boolean isModalShellInForeground() |
| { |
| Shell mainShell = getShell(); |
| Shell[] shells = getDisplay().getShells(); |
| |
| for (Shell shell : shells) |
| { |
| if (shell != mainShell) |
| { |
| int style = shell.getStyle(); |
| if ((style & SWT.APPLICATION_MODAL) != 0 || (style & SWT.PRIMARY_MODAL) != 0 || (style & SWT.SYSTEM_MODAL) != 0) |
| { |
| return true; |
| } |
| } |
| } |
| |
| return false; |
| } |
| |
| private void resetWatchdogTimer(long now) |
| { |
| reportWarningTimeout = now + PROGRESS_WATCHDOG_TIMEOUT * 1000; |
| } |
| |
| private void reschedule() |
| { |
| UIUtil.timerExec(100, getDisplay(), this); |
| } |
| |
| private void schedule() |
| { |
| resetWatchdogTimer(System.currentTimeMillis()); |
| UIUtil.asyncExec(getDisplay(), this); |
| } |
| } |
| |
| /** |
| * @author Ed Merks |
| */ |
| private static class FileCompletionSupport extends KeyAdapter implements VerifyListener |
| { |
| private final Text folderText; |
| |
| private Shell shell; |
| |
| public FileCompletionSupport(Text text) |
| { |
| folderText = text; |
| if (OS.INSTANCE.isMac()) |
| { |
| folderText.addKeyListener(this); |
| } |
| else |
| { |
| folderText.addVerifyListener(this); |
| } |
| } |
| |
| protected void setFolderTextAndSelect(String folder) |
| { |
| folderText.setText(folder); |
| int length = folder.length(); |
| folderText.setSelection(new Point(length, length)); |
| } |
| |
| @Override |
| public void keyReleased(KeyEvent e) |
| { |
| if (e.keyCode == ' ' && e.stateMask == SWT.CTRL) |
| { |
| e.doit = false; |
| open(); |
| } |
| } |
| |
| public void verifyText(VerifyEvent e) |
| { |
| if (e.keyCode == ' ' && e.stateMask == SWT.CTRL) |
| { |
| e.doit = false; |
| open(); |
| } |
| } |
| |
| private void open() |
| { |
| if (shell == null) |
| { |
| new Dialog(folderText.getShell()) |
| { |
| private org.eclipse.swt.widgets.List list; |
| |
| private ModifyListener modifyListener = new ModifyListener() |
| { |
| public void modifyText(ModifyEvent e) |
| { |
| updater.schedule(); |
| } |
| }; |
| |
| private FocusListener focusListener = new FocusAdapter() |
| { |
| @Override |
| public void focusLost(FocusEvent e) |
| { |
| checkFocus(); |
| } |
| }; |
| |
| private MouseListener mouseListener = new MouseAdapter() |
| { |
| @Override |
| public void mouseDown(MouseEvent e) |
| { |
| checkFocus(); |
| } |
| }; |
| |
| private ControlListener controlListener = new ControlListener() |
| { |
| public void controlResized(ControlEvent e) |
| { |
| shell.dispose(); |
| } |
| |
| public void controlMoved(ControlEvent e) |
| { |
| shell.dispose(); |
| } |
| }; |
| |
| private KeyListener keyListener = new KeyAdapter() |
| { |
| @Override |
| public void keyReleased(KeyEvent e) |
| { |
| if (e.keyCode == SWT.ARROW_UP) |
| { |
| int itemCount = list.getItemCount(); |
| if (itemCount > 0) |
| { |
| shell.setFocus(); |
| list.select(itemCount - 1); |
| list.showSelection(); |
| } |
| } |
| else if (e.keyCode == SWT.ARROW_DOWN) |
| { |
| int itemCount = list.getItemCount(); |
| if (itemCount > 0) |
| { |
| shell.setFocus(); |
| int selectionIndex = list.getSelectionIndex(); |
| list.select(selectionIndex + 1); |
| } |
| } |
| else if (e.keyCode == '\r') |
| { |
| int selectionIndex = list.getSelectionIndex(); |
| if (selectionIndex != -1) |
| { |
| String folder = list.getItem(selectionIndex); |
| File file = new File(folder); |
| if (!folder.endsWith(File.separator) && file.isDirectory() && !IOUtil.canWriteFolder(file)) |
| { |
| folder += File.separator; |
| } |
| |
| setFolderTextAndSelect(folder); |
| } |
| } |
| } |
| }; |
| |
| /** |
| * A class for delayed update of the list. |
| * @author Ed Merks |
| */ |
| class Updater extends UIUtil.DelayedRunnable |
| { |
| public Updater(Shell shell) |
| { |
| super(shell, 350); |
| } |
| |
| @Override |
| protected void perform() |
| { |
| update(); |
| } |
| } |
| |
| private Updater updater; |
| |
| private void checkFocus() |
| { |
| UIUtil.asyncExec(list, new Runnable() |
| { |
| public void run() |
| { |
| if (shell.getDisplay().getActiveShell() != shell) |
| { |
| shell.dispose(); |
| } |
| } |
| }); |
| } |
| |
| public void open() |
| { |
| Shell parent = getParent(); |
| shell = new Shell(parent, SWT.MODELESS | SWT.NO_TRIM); |
| Control wrapper = folderText.getParent(); |
| Rectangle folderTextBounds = wrapper.getBounds(); |
| Point position = wrapper.getParent().toDisplay(folderTextBounds.x, folderTextBounds.y + folderTextBounds.height); |
| shell.setBounds(position.x, position.y, folderTextBounds.width, 100); |
| shell.setLayout(new FillLayout()); |
| |
| updater = new Updater(shell); |
| |
| list = new org.eclipse.swt.widgets.List(shell, SWT.BORDER | SWT.SINGLE | SWT.V_SCROLL); |
| |
| list.addMouseListener(new MouseAdapter() |
| { |
| @Override |
| public void mouseUp(MouseEvent e) |
| { |
| int selectionIndex = list.getSelectionIndex(); |
| if (selectionIndex != -1) |
| { |
| apply(list.getItem(selectionIndex)); |
| } |
| } |
| }); |
| |
| list.addKeyListener(new KeyAdapter() |
| { |
| @Override |
| public void keyReleased(KeyEvent e) |
| { |
| if (e.keyCode == '\r') |
| { |
| int selectionIndex = list.getSelectionIndex(); |
| if (selectionIndex != -1) |
| { |
| apply(list.getItem(selectionIndex)); |
| } |
| } |
| } |
| }); |
| |
| shell.addShellListener(new ShellAdapter() |
| { |
| @Override |
| public void shellDeactivated(ShellEvent e) |
| { |
| shell.dispose(); |
| } |
| }); |
| |
| shell.addDisposeListener(new DisposeListener() |
| { |
| public void widgetDisposed(DisposeEvent e) |
| { |
| folderText.removeModifyListener(modifyListener); |
| folderText.removeFocusListener(focusListener); |
| folderText.removeMouseListener(mouseListener); |
| folderText.removeKeyListener(keyListener); |
| if (!folderText.getShell().isDisposed()) |
| { |
| folderText.getShell().removeControlListener(controlListener); |
| } |
| |
| shell = null; |
| } |
| }); |
| |
| folderText.addModifyListener(modifyListener); |
| folderText.addFocusListener(focusListener); |
| folderText.addMouseListener(mouseListener); |
| folderText.addKeyListener(keyListener); |
| folderText.getShell().addControlListener(controlListener); |
| |
| update(); |
| |
| shell.setVisible(true); |
| } |
| |
| private void update() |
| { |
| if (!list.isDisposed()) |
| { |
| list.removeAll(); |
| Point selection = folderText.getSelection(); |
| String folderLiteral = StringUtil.trimLeft(folderText.getText().substring(0, selection.x)); |
| File folder = IOUtil.getCanonicalFile(new File(folderLiteral)); |
| final String name = folder.getName().toLowerCase(); |
| if (folderLiteral.length() == 0) |
| { |
| File[] roots = File.listRoots(); |
| if (roots != null) |
| { |
| for (File root : roots) |
| { |
| list.add(root.getPath()); |
| } |
| } |
| } |
| else |
| { |
| boolean isExplicitFolder = folderLiteral.endsWith("/") || folderLiteral.endsWith("\\"); |
| final String nameFilter = isExplicitFolder ? "" : name; |
| |
| File searchFolder = isExplicitFolder ? folder : folder.getParentFile(); |
| if (searchFolder != null) |
| { |
| File[] folders = searchFolder.listFiles(new FileFilter() |
| { |
| public boolean accept(File file) |
| { |
| return file.isDirectory() && file.getName().toLowerCase().startsWith(nameFilter); |
| } |
| }); |
| |
| if (folders != null) |
| { |
| for (File root : folders) |
| { |
| list.add(root.getPath()); |
| } |
| } |
| } |
| else |
| { |
| File[] roots = File.listRoots(); |
| if (roots != null) |
| { |
| String lowerCaseFolderLiteral = folderLiteral.toLowerCase(); |
| for (File root : roots) |
| { |
| String path = root.getPath(); |
| if (path.length() == 1) |
| { |
| File[] folders = root.listFiles(new FileFilter() |
| { |
| public boolean accept(File file) |
| { |
| return file.isDirectory() && file.getName().toLowerCase().startsWith(nameFilter); |
| } |
| }); |
| |
| if (folders != null) |
| { |
| for (File child : folders) |
| { |
| list.add(child.getPath()); |
| } |
| } |
| } |
| else |
| { |
| if (path.toLowerCase().startsWith(lowerCaseFolderLiteral)) |
| { |
| list.add(root.getPath()); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| if (list.getItemCount() != 0) |
| { |
| list.select(0); |
| } |
| |
| int width = list.computeSize(SWT.DEFAULT, SWT.DEFAULT).x; |
| |
| Rectangle clientArea = shell.getClientArea(); |
| Rectangle newClientArea = shell.computeTrim(clientArea.x, clientArea.y, width, clientArea.height); |
| Rectangle bounds = shell.getBounds(); |
| if (bounds.width < newClientArea.width) |
| { |
| bounds.width = newClientArea.width; |
| shell.setBounds(bounds); |
| } |
| } |
| |
| private void apply(String folder) |
| { |
| File file = new File(folder); |
| if (!folder.endsWith(File.separator) && file.isDirectory() && !IOUtil.canWriteFolder(file)) |
| { |
| folder += File.separator; |
| } |
| |
| setFolderTextAndSelect(folder); |
| shell.dispose(); |
| } |
| }.open(); |
| } |
| } |
| } |
| } |