/******************************************************************************* * Copyright (c) 2015 Mentor Graphics 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: * Mentor Graphics - initial API and implementation *******************************************************************************/ package com.codesourcery.internal.installer.ui.pages; import java.io.File; import java.util.ArrayList; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Image; 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.Control; import org.eclipse.swt.widgets.Label; import com.codesourcery.installer.IInstallConsoleProvider; import com.codesourcery.installer.IInstallData; import com.codesourcery.installer.IInstallDescription; import com.codesourcery.installer.Installer; import com.codesourcery.installer.console.ConsoleInputPrompter; import com.codesourcery.installer.console.ConsoleListPrompter; import com.codesourcery.installer.ui.BrowseDirectoryDefaultEditor; import com.codesourcery.installer.ui.FormattedLabel; import com.codesourcery.installer.ui.IInstallSummaryProvider; import com.codesourcery.internal.installer.IInstallerImages; import com.codesourcery.internal.installer.InstallMessages; import com.codesourcery.internal.installer.InstallUtils; /** * Wizard page that shows three options: * <ul> * <li>Option to install normally</li> * <li>Option to install and update mirror</li> * <li>Option to install from mirror</li> * </ul> */ public class MirrorPage extends AbstractSetupPage implements IInstallConsoleProvider, IInstallSummaryProvider { /** Install option */ private final static int OPTION_INSTALL = 0; /** Install from saved data option */ private final static int OPTION_LOAD = 1; /** Save option */ private final static int OPTION_SAVE = 2; /** Main content area */ private Composite area; /** Description label */ private FormattedLabel descriptionLabel; /** Install button */ private Button installButton; /** Install from save button */ private Button installFromSaveButton; /** Save button */ private Button saveButton; /** Install from save editor group */ private BrowseDirectoryDefaultEditor installFromSaveEditor; /** Save editor group */ private BrowseDirectoryDefaultEditor saveEditor; /** Currently selected option */ private int selectedOption; /** Save path */ private String savePath; /** Load path*/ private String loadPath; /** Status error text */ private String errorText; /** Console option prompter */ private ConsoleListPrompter<Integer> consoleOptionPrompter; /** Console location prompter */ private ConsoleInputPrompter consoleLocationPrompter; /** Current console state */ private int consoleState = 0; /** * Constructs a mirror page. * * @param pageName Page name * @param title Page title */ public MirrorPage(String pageName, String title) { super(pageName, title); String defaultSavePath = getDefaultSavePath(); setSavePath(defaultSavePath); setLoadPath(defaultSavePath); setSelectedOption(0); } /** * @return Returns the default save path */ protected String getDefaultSavePath() { StringBuilder buffer = new StringBuilder(); IInstallDescription description = Installer.getDefault().getInstallManager().getInstallDescription(); String homeDir = System.getProperty("user.home"); // Mirror download directory String defaultDirectory = description.getText(IInstallDescription.TEXT_MIRROR_PAGE_DEFAULT_DIRECTORY, null); if (defaultDirectory != null) { defaultDirectory = defaultDirectory.replace("~", homeDir); buffer.append(defaultDirectory); } // Default mirror download directory name else { buffer.append(homeDir); buffer.append(System.getProperty("file.separator")); buffer.append("Downloads"); buffer.append(System.getProperty("file.separator")); buffer.append(InstallUtils.makeFileNameSafe(description.getProductId())); buffer.append('_'); buffer.append(description.getProductVersionString()); } Path path = new Path(buffer.toString()); return path.toOSString(); } /** * Sets the selected option. * <ul> * <li>0 = Install</li> * <li>1 = Install and save</li> * <li>2 = Install from saved</li> * </ul> * * @param option Index of selected option */ public void setSelectedOption(int option) { this.selectedOption = option; } /** * @return The index of the selected option */ public int getSelectedOption() { return selectedOption; } /** * Sets the save path. * * @param savePath Save path. */ protected void setSavePath(String savePath) { this.savePath = savePath; } /** * @return The save path. */ public String getSavePath() { return savePath; } /** * Sets the load path. * * @param loadPath Load path. */ protected void setLoadPath(String loadPath) { this.loadPath = loadPath; } /** * @return The load path. */ public String getLoadPath() { return loadPath; } /** * @return The page description text. */ protected String getPageDescription() { IInstallDescription description = Installer.getDefault().getInstallManager().getInstallDescription(); String descriptionText = description.getText(IInstallDescription.TEXT_MIRROR_PAGE_MESSAGE, InstallMessages.MirrorPage_Description); return descriptionText; } /** * @return The install section text. */ protected String getInstallSectionText() { IInstallDescription description = Installer.getDefault().getInstallManager().getInstallDescription(); String installText = description.getText(IInstallDescription.TEXT_MIRROR_PAGE_SECTION_INSTALL, InstallMessages.MirrorPage_InstallSection); return installText; } /** * @return The install option text. */ protected String getInstallOptionText() { IInstallDescription description = Installer.getDefault().getInstallManager().getInstallDescription(); String installText = description.getText(IInstallDescription.TEXT_MIRROR_PAGE_INSTALL, InstallMessages.MirrorPage_Install); return installText; } /** * @return The save section text. */ protected String getSaveSectionText() { IInstallDescription description = Installer.getDefault().getInstallManager().getInstallDescription(); String installSaveText = description.getText(IInstallDescription.TEXT_MIRROR_PAGE_SECTION_SAVE, InstallMessages.MirrorPage_SaveSection); return installSaveText; } /** * @return The save option text. */ protected String getSaveOptionText() { IInstallDescription description = Installer.getDefault().getInstallManager().getInstallDescription(); String installSaveText = description.getText(IInstallDescription.TEXT_MIRROR_PAGE_SAVE, InstallMessages.MirrorPage_Save); return installSaveText; } /** * @return The load option text. */ protected String getLoadOptionText() { IInstallDescription description = Installer.getDefault().getInstallManager().getInstallDescription(); String installLoadText = description.getText(IInstallDescription.TEXT_MIRROR_PAGE_LOAD, InstallMessages.MirrorPage_Load); return installLoadText; } @Override public Control createContents(Composite parent) { String defaultSavePath = getDefaultSavePath(); final int OPTION_INDENT = Installer.getDefault().getImageRegistry().get(IInstallerImages.UPDATE_INSTALL).getImageData().width; final int EDITOR_INDENT = OPTION_INDENT + getDefaultIndent() + getDefaultIndent(); // Main area area = new Composite(parent, SWT.NONE); area.setLayout(new GridLayout(1, true)); // Description descriptionLabel = new FormattedLabel(area, SWT.WRAP); descriptionLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); descriptionLabel.setText(getPageDescription()); // Install section createSpacer(area); createSeparator(area, Installer.getDefault().getImageRegistry().get(IInstallerImages.UPDATE_INSTALL), getInstallSectionText(), 0); // Install option installButton = createOptionButton(area, getInstallOptionText(), OPTION_INDENT); installButton.setSelection(getSelectedOption() == OPTION_INSTALL); installButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { setSelectedOption(OPTION_INSTALL); updateControls(); } }); // Install from save option installFromSaveButton = createOptionButton(area, getLoadOptionText(), OPTION_INDENT); installFromSaveButton.setSelection(getSelectedOption() == OPTION_LOAD); installFromSaveEditor = createOptionEditor(area, installFromSaveButton, OPTION_LOAD, defaultSavePath, EDITOR_INDENT); // Save section createSpacer(area); createSeparator(area, Installer.getDefault().getImageRegistry().get(IInstallerImages.UPDATE_FOLDER), getSaveSectionText(), 0); // Save option saveButton = createOptionButton(area, getSaveOptionText(), OPTION_INDENT); saveButton.setSelection(getSelectedOption() == OPTION_SAVE); saveEditor = createOptionEditor(area, saveButton, OPTION_SAVE, defaultSavePath, EDITOR_INDENT); // Since the page contents can grow or shrink depending on what option editors are currently displayed, fix // the height to that with all editors visible. GridData areaData = new GridData(SWT.FILL, SWT.FILL, true, true); areaData.heightHint = area.computeSize(SWT.DEFAULT, SWT.DEFAULT).y; area.setLayoutData(areaData); updateControls(); return area; } /** * Creates a button for an option. * * @param parent Parent for button * @param text Text for option * @param indent Horizontal indent * @return Option button */ protected Button createOptionButton(Composite parent, String text, int indent) { Button button = new Button(parent, SWT.RADIO); GridData data = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1); data.horizontalIndent = indent; button.setLayoutData(data); button.setText(text); return button; } /** * Creates a separator line. * * @param parent Parent for separator * @param image Image or <code>null</code> * @param text Text for separator * @param indent Horizontal indentation * @return Separator line */ protected Composite createSeparator(Composite parent, Image image, String text, int indent) { Composite area = new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(image == null ? 2 : 3, false); layout.marginHeight = layout.marginWidth = 0; area.setLayout(layout); GridData data = new GridData(SWT.FILL, SWT.CENTER, true, false); data.horizontalIndent = indent; area.setLayoutData(data); if (image != null) { Label iconLabel = new Label(area, SWT.NONE); iconLabel.setImage(image); iconLabel.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false)); } // Label FormattedLabel label = new FormattedLabel(area, SWT.NONE); label.setText("<big><big><big>" + text + "</big></big></big>"); label.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false)); // Separator Label separator = new Label(area, SWT.SEPARATOR | SWT.HORIZONTAL); separator.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); return area; } /** * Creates an path editor group for an option. * * @param parent Parent * @param selectButton Button to show the editor for * @param option Option index * @param defaultText Default text for editor * @param indent Horizontal indention * @return Editor group */ protected BrowseDirectoryDefaultEditor createOptionEditor(Composite parent, Button selectButton, final int option, String defaultText, int indent) { GridData data; final BrowseDirectoryDefaultEditor editor = new BrowseDirectoryDefaultEditor(parent, SWT.NONE, true, true, defaultText); data = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1); data.horizontalIndent = indent; editor.setLayoutData(data); // Show the editor when the option button is selected selectButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { setSelectedOption(option); updateControls(); clearError(); editor.getEditor().setFocus(); } }); editor.getEditor().addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { setSavePath(saveEditor.getEditor().getText()); setLoadPath(installFromSaveEditor.getEditor().getText()); clearError(); updateStatus(); } }); return editor; } /** * Creates spacing. * * @param parent Parent */ protected void createSpacer(Composite parent) { Label label = new Label(parent, SWT.NONE); label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); } /** * Shows or hides an option editor. * * @param editor Editor * @param show <code>true</code> to show, <code>false</code> to hide * @return <code>true</code> if the layout requires an update */ protected boolean showOptionEditor(BrowseDirectoryDefaultEditor editor, boolean show) { GridData data = (GridData)editor.getLayoutData(); boolean result = (data.exclude == !show); data.exclude = !show; editor.setLayoutData(data); editor.setSize(0, 0); return result; } /** * Updates the page controls. */ protected void updateControls() { boolean updateLayout = false; // Show save option editor? if (showOptionEditor(installFromSaveEditor, installFromSaveButton.getSelection())) { updateLayout = true; } // Show save option editor? if (showOptionEditor(saveEditor, saveButton.getSelection())) { updateLayout = true; } updateStatus(); // Update layout if required if (updateLayout) { area.layout(true); } } /** * Updates the page status with any warning or error. */ protected void updateStatus() { if (!isConsoleMode()) { ArrayList<IStatus> status = new ArrayList<IStatus>(); // There is an error if (errorText != null) { // Auto-update in case the error condition is corrected startAutoUpdate(); status.add(new Status(IStatus.ERROR, Installer.ID, errorText)); } // There may be warnings else { stopAutoUpdate(); String[] warnings = getWarnings(); for (String warning : warnings) { status.add(new Status(IStatus.WARNING, Installer.ID, warning)); } } if (status.size() > 0) { showStatus(status.toArray(new IStatus[status.size()])); } else { hideStatus(); } setPageComplete(errorText == null); } } @Override protected void autoUpdate() { // Re-validate to possibly clear any errors for conditions that have been corrected validate(); } /** * Clears any error. */ protected void clearError() { errorText = null; updateStatus(); } /** * @return <code>true</code>if the save directory does not exist or is empty. */ protected boolean checkSaveDirectoryEmpty() { boolean empty = true; File saveFile = new File(getSavePath()); if (saveFile.exists()) { empty = saveFile.listFiles().length == 0; } return empty; } /** * @return Any error for the current settings or <code>null</code>. */ protected String getError() { String error = null; int option = getSelectedOption(); if (option == OPTION_LOAD) { File loadFile = new File(getLoadPath()); if (!loadFile.exists()) { error = InstallMessages.Error_DirectoryNotExist; } } else if (option == OPTION_SAVE) { if (!checkSaveDirectoryEmpty()) { error = InstallMessages.Error_OverwriteDirectory; } } return error; } /** * @return Any warnings for the current settings or <code>null</code>. */ protected String[] getWarnings() { ArrayList<String> warnings = new ArrayList<String>(); int option = getSelectedOption(); if (option == OPTION_LOAD) { warnings.add(InstallMessages.Error_MirrorSelectedLoad); } else if (option == OPTION_SAVE) { warnings.add(InstallMessages.Error_MirrorSelectedSave); } return warnings.toArray(new String[warnings.size()]); } @Override public boolean validate() { setSavePath(saveEditor.getEditor().getText()); setLoadPath(installFromSaveEditor.getEditor().getText()); errorText = getError(); updateStatus(); return (errorText == null); } @Override protected void saveSetup(IInstallData data) throws CoreException { if (!isConsoleMode()) { if (installButton.getSelection()) { setSelectedOption(OPTION_INSTALL); } else if (installFromSaveButton.getSelection()) { setSelectedOption(OPTION_LOAD); } else if (saveButton.getSelection()) { setSelectedOption(OPTION_SAVE); } } final Exception[] error = new Exception[] { null }; // Handle selected option int option = getSelectedOption(); // Install from mirror if (option == OPTION_LOAD) { Installer.getDefault().getInstallManager().setSourceLocation(new Path(getLoadPath())); } // Save to mirror else if (option == OPTION_SAVE) { runOperation(InstallMessages.PreparingInstall, new Runnable() { @Override public void run() { try { Installer.getDefault().getInstallManager().setMirrorLocation(new Path(getSavePath()), null); } catch (Exception e) { error[0] = e; } } }); if (error[0] != null) { Installer.fail(error[0]); } // Update the container buttons to show mirror operation instead of install if (!isConsoleMode()) { getContainer().updateButtons(); } } } @Override public String getConsoleResponse(String input) throws IllegalArgumentException { String response = null; // Initial prompt if (input == null) { consoleState = 0; String prompt = formatConsoleMessage(getPageDescription()) + "\n" + InstallMessages.ConsoleDoPrompt; consoleOptionPrompter = new ConsoleListPrompter<Integer>(prompt, true); // Install option consoleOptionPrompter.addItem(getInstallOptionText(), OPTION_INSTALL); // Load option consoleOptionPrompter.addItem(getLoadOptionText(), OPTION_LOAD); // Save option consoleOptionPrompter.addItem(getSaveOptionText(), OPTION_SAVE); // Default to install consoleOptionPrompter.setDefaultItem(0); } // Prompt to update or use mirror if (consoleState == 0) { response = consoleOptionPrompter.getConsoleResponse(input); if (response == null) { ArrayList<Integer> options = new ArrayList<Integer>(); consoleOptionPrompter.getSelectedData(options); if (options.size() > 0) { int option = options.get(0); setSelectedOption(option); // Display any warnings String[] warnings = getWarnings(); if (warnings.length > 0) { for (String warning : warnings) { printConsole(warning); } } // Move to next prompt if required if (option != OPTION_INSTALL) { consoleState ++; input = null; // Location prompter consoleLocationPrompter = new ConsoleInputPrompter( getSelectedOption() == OPTION_SAVE ? InstallMessages.MirrorPage_MirrorPathSavePrompt : InstallMessages.MirrorPage_MirrorPathLoadPrompt, getSelectedOption() == OPTION_SAVE ? getSavePath() : getLoadPath()); } } } } // Prompt for mirror save or load location if (consoleState == 1) { response = consoleLocationPrompter.getConsoleResponse(input); if (response == null) { if (getSelectedOption() == OPTION_SAVE) { setSavePath(consoleLocationPrompter.getResult()); } else { setLoadPath(consoleLocationPrompter.getResult()); } String error = getError(); if (error != null) { printConsole(error); response = consoleLocationPrompter.getConsoleResponse(null); } } } return response; } @Override public String getInstallSummary() { if (getSelectedOption() == OPTION_SAVE) { StringBuilder buffer = new StringBuilder(); buffer.append("<b>"); buffer.append(getSaveOptionText()); buffer.append("</b>\n"); buffer.append(getSavePath()); buffer.append("\n\n"); return buffer.toString(); } else { return null; } } }