/*******************************************************************************
* Copyright (c) 2014 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.installer.ui;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
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.Label;
import com.codesourcery.installer.IInstallData;
import com.codesourcery.installer.IInstallMode;
import com.codesourcery.installer.IInstallWizardPage;
import com.codesourcery.installer.Installer;
import com.codesourcery.installer.IInstallDescription.WizardNavigation;
import com.codesourcery.internal.installer.ContributorRegistry;
import com.codesourcery.internal.installer.IInstallerImages;
import com.codesourcery.internal.installer.InstallMessages;
import com.codesourcery.internal.installer.ui.BusyAnimationControl;
import com.codesourcery.internal.installer.ui.ISetupWizardPage;
import com.codesourcery.internal.installer.ui.InstallWizard;
import com.codesourcery.internal.installer.ui.SideBarComposite;
import com.codesourcery.internal.installer.ui.StepsControl;
import com.codesourcery.internal.installer.ui.pages.ProgressPage;
/**
* Install wizard base page class. All install wizard pages should subclass
* this class.
* Subclasses should provide an implementation of {@link #createContents(Composite)}.
* A page can show a warning or error, a page can call {@link #showStatus(IStatus[])}.
* A page can show a busy animation by calling {@link #showBusy(String)}.
*/
public abstract class InstallWizardPage extends WizardPage implements IInstallWizardPage {
/** Auto update delay (ms) */
public static final int DEFAULT_UPDATE_DELAY = 2000;
/** Default width in characters */
protected static final int DEFAULT_WIDTH = 120;
/** Default height in characters */
protected static final int DEFAULT_HEIGHT = 20;
/** Options indenting */
protected static final int DEFAULT_INDENT = 10;
/** Maximum number of lines to display in warning panel */
protected static final int MAX_WARNING_LINES = 3;
/** Page side bar */
private SideBarComposite sideBar;
/** Page top bar */
private StepsControl topBar;
/** Page label */
private String pageLabel;
/** Page container */
private Composite pageContainer;
/** Page area */
private Composite pageArea;
/** Page client area */
private Composite pageClientArea;
/** Warning panel */
private WarningPanel warningPanel;
/** Waiting progress panel */
private BusyPanel busyPanel;
/** Status */
private IStatus[] status;
/** Bold font */
private Font boldFont;
/** Busy message or <code>null</code> if not busy */
private String busyMessage = null;
/** Page navigation */
private WizardNavigation pageNavigation = WizardNavigation.TOP;
/** <code>true</code> if page is auto updating */
private boolean autoUpdate = false;
/** Auto-update job */
private AutoUpdateJob updateJob;
/** Auto-update delay */
private int autoUpdateDelay;
/** Maximum height of warning panel */
private int maxWarningHeight;
/**
* Constructor
*
* @param pageName Page name
* @param title Page title
*/
protected InstallWizardPage(String pageName, String title) {
super(pageName, "", null); //$NON-NLS-1$
setPageLabel(title);
// For install default to mode specified in installer properties
if (Installer.getDefault().getInstallManager().getInstallMode().isInstall()) {
setPageNavigation(Installer.getDefault().getInstallManager().getInstallDescription().getPageNavigation());
}
}
/**
* Returns the install data.
*
* @return Install data
*/
protected IInstallData getInstallData() {
return Installer.getDefault().getInstallManager().getInstallData();
}
/**
* Sets the page navigation. This can be one of the following:
*
* @param pageNavigation Page navigation
*/
public void setPageNavigation(WizardNavigation pageNavigation) {
this.pageNavigation = pageNavigation;
}
/**
* Returns the page navigation.
*
* @return Page navigation
*/
public WizardNavigation getPageNavigation() {
return pageNavigation;
}
@Override
public void dispose() {
if (boldFont != null) {
boldFont.dispose();
}
// Stop any update thread
if (updateJob != null) {
updateJob.cancel();
try {
updateJob.join();
} catch (InterruptedException e) {
// Ignore
}
}
super.dispose();
}
/**
* Returns a bold font.
*
* @return Bold font
*/
protected Font getBoldFont() {
if (boldFont == null) {
FontData[] fd = getFont().getFontData();
fd[0].setStyle(SWT.BOLD);
boldFont = new Font(getShell().getDisplay(), fd[0]);
}
return boldFont;
}
/**
* Called to give the page a chance to make any label adjustments
* based on installation mode.
*/
public void initPageLabel() {
// Base does nothing
}
/**
* Returns the page label.
*
* @return Page label
*/
public String getPageLabel() {
return pageLabel;
}
/**
* Sets the page label.
*
* @param pageLabel Page label
*/
public void setPageLabel(String pageLabel) {
this.pageLabel = pageLabel;
}
@Override
public void setActive(IInstallData data) {
// If top bar, update current page so scrolling is adjusted
if (topBar != null) {
topBar.setCurrentStep(getPageLabel());
}
}
/**
* Shows success for this page in the side bar.
*
* @param success <code>true</code> to show success.
*/
protected void showSuccess(boolean success) {
if (sideBar != null) {
sideBar.setState(getPageLabel(), success ?
SideBarComposite.StepState.SUCCESS : SideBarComposite.StepState.NONE);
}
}
/**
* Returns the default indention.
*
* @return Indention
*/
public int getDefaultIndent() {
return DEFAULT_INDENT;
}
@Override
public String getTitle() {
if (Installer.getDefault().getInstallManager().getInstallMode().isInstall()) {
return Installer.getDefault().getInstallManager().getInstallDescription().getTitle();
}
return super.getTitle();
}
@Override
public Image getImage() {
Image image = null;
// Use wizard title image if available
try {
image = ((InstallWizard)getWizard()).getTitleImage();
}
catch (Exception e) {
Installer.log(e);
}
// Otherwise, use registered title image
if (image == null) {
image = ContributorRegistry.getDefault().getTitleIcon();
if (image != null) {
return image;
}
else {
return Installer.getDefault().getImageRegistry().get(IInstallerImages.PAGE_BANNER);
}
}
return image;
}
@Override
public final void createControl(Composite parent) {
initializeDialogUnits(parent);
// Compute maximum height of warning panel
maxWarningHeight = convertHeightInCharsToPixels(MAX_WARNING_LINES);
boolean leftNavigation = (getPageNavigation() == WizardNavigation.LEFT) || (getPageNavigation() == WizardNavigation.LEFT_MINIMAL);
Composite area = new Composite(parent, SWT.NONE) {
@Override
public Point computeSize(int wHint, int hHint, boolean changed) {
Point defaultSize = super.computeSize(wHint, hHint, changed);
int defaultHeight = convertHeightInCharsToPixels(DEFAULT_HEIGHT);
// Limit the width of the page to a default so that labels wrap instead of extending the wizard dialog.
// Limit the height to the page contents or default height (whichever is largest) plus the maximum
// width of the warning panel.
return new Point(
convertWidthInCharsToPixels(DEFAULT_WIDTH),
Math.max(defaultSize.y, defaultHeight) + maxWarningHeight);
}
};
GridData areaData = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1);
area.setLayoutData(areaData);
GridLayout layout = new GridLayout(leftNavigation ? 3 : 2, false);
layout.marginHeight = 0;
layout.marginWidth = 0;
area.setLayout(layout);
// Top navigation bar
if (getPageNavigation() == WizardNavigation.TOP) {
topBar = new StepsControl(area, SWT.NONE);
topBar.setFont(getFont());
topBar.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1));
}
// Left navigation bar
else if (leftNavigation) {
if (getPageNavigation() == WizardNavigation.LEFT) {
sideBar = new SideBarComposite(
area,
SWT.NONE,
Installer.getDefault().getImageRegistry().get(IInstallerImages.BULLET_EMPTY),
Installer.getDefault().getImageRegistry().get(IInstallerImages.BULLET_SOLID),
Installer.getDefault().getImageRegistry().get(IInstallerImages.BULLET_CHECKED),
Installer.getDefault().getImageRegistry().get(IInstallerImages.BULLET_ARROW),
Installer.getDefault().getImageRegistry().get(IInstallerImages.BULLET_ERROR),
true);
}
else {
sideBar = new SideBarComposite(
area,
SWT.NONE,
Installer.getDefault().getImageRegistry().get(IInstallerImages.BULLET_EMPTY2),
Installer.getDefault().getImageRegistry().get(IInstallerImages.BULLET_EMPTY2),
Installer.getDefault().getImageRegistry().get(IInstallerImages.BULLET_CHECKED2),
Installer.getDefault().getImageRegistry().get(IInstallerImages.BULLET_ARROW2),
Installer.getDefault().getImageRegistry().get(IInstallerImages.BULLET_ERROR2),
false);
}
sideBar.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, false, true, 1, 1));
// Vertical separator
Label verticalSeparator = new Label(area, SWT.SEPARATOR | SWT.VERTICAL);
verticalSeparator.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, false, true, 1, 1));
}
// Page container
pageContainer = new Composite(area, SWT.NONE);
pageContainer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
layout = new GridLayout(1, false);
layout.marginHeight = 0;
layout.marginWidth = 0;
pageContainer.setLayout(layout);
// Page area
pageArea = new Composite(pageContainer, SWT.NONE);
pageArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
layout = new GridLayout(1, false);
layout.marginHeight = 0;
layout.marginWidth = 0;
pageArea.setLayout(layout);
// Page client area
pageClientArea = new Composite(pageArea, SWT.NONE);
pageClientArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
layout = new GridLayout(1, false);
layout.marginHeight = 0;
layout.marginWidth = 4;
pageClientArea.setLayout(layout);
// Create page contents
createContents(pageClientArea);
// Warning area
final Composite warningArea = new Composite(pageArea, SWT.NONE);
warningArea.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
GridLayout warningAreaLayout = new GridLayout(1, true);
warningAreaLayout.marginTop = 0;
warningAreaLayout.marginBottom = 2;
warningAreaLayout.marginLeft = 0;
warningAreaLayout.marginRight = 2;
warningArea.setLayout(warningAreaLayout);
// Warning pane (initially hidden unless a status is available)
warningPanel = new WarningPanel(warningArea, SWT.NONE);
GridData warningPanelData = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1);
warningPanelData.exclude = (status == null);
warningPanel.setLayoutData(warningPanelData);
if (status != null) {
warningPanel.setStatus(status);
}
// Waiting pane (initially hidden)
busyPanel = new BusyPanel(pageContainer, SWT.NONE);
GridData busyPanelData = new GridData(SWT.CENTER, SWT.CENTER, true, true, 1, 1);
busyPanelData.exclude = true;
busyPanel.setLayoutData(busyPanelData);
if (busyMessage != null) {
showBusy(busyMessage);
}
// Set page control
setControl(area);
}
/**
* @return The page container
*/
protected Composite getPageContainer() {
return pageContainer;
}
/**
* Returns the page area.
*
* @return Page area
*/
protected Composite getPageArea() {
return pageArea;
}
/**
* Returns the page client area.
*
* @return Page area
*/
protected Composite getPageClientArea() {
return pageClientArea;
}
/**
* Sets the current status for the page.
*
* @param status Status
*/
protected void setStatus(IStatus[] status) {
this.status = status;
}
/**
* Returns the current status for the page.
*
* @return Status or <code>null</code>
*/
public IStatus[] getStatus() {
return status;
}
/**
* Returns if the page status has errors.
*
* @return <code>true</code> if status has errors
*/
public boolean hasStatusError() {
boolean isError = false;
if (status != null) {
for (IStatus stat : status) {
if (stat.getSeverity() == IStatus.ERROR) {
isError = true;
break;
}
}
}
return isError;
}
/**
* Returns the current page status as a console message.
*
* @param status Status for message
* @return Console message
*/
protected String getStatusMessage(IStatus[] status) {
String message = null;
if (status != null) {
StringBuilder buffer = new StringBuilder();
for (IStatus stat : status) {
// Information
if (stat.getSeverity() == IStatus.INFO) {
buffer.append(stat.getMessage());
}
// Error
else if (stat.getSeverity() == IStatus.ERROR) {
buffer.append(NLS.bind(InstallMessages.ConsoleError0, stat.getMessage()));
}
// Warning
else if (stat.getSeverity() == IStatus.WARNING) {
buffer.append(NLS.bind(InstallMessages.ConsoleWarning0, stat.getMessage()));
}
buffer.append('\n');
}
message = buffer.toString();
}
return message;
}
/**
* Shows a status pane at the button of the page.
*
* @param status Status to show
*/
public void showStatus(IStatus[] status) {
setStatus(status);
if (warningPanel != null) {
// Update status
warningPanel.setStatus(status);
// Show pane
GridData data = (GridData)warningPanel.getLayoutData();
data.exclude = false;
getPageArea().layout(true);
if (sideBar != null) {
sideBar.setState(getPageLabel(), hasStatusError() ?
SideBarComposite.StepState.ERROR : SideBarComposite.StepState.NONE);
}
}
}
/**
* Hides the status pane.
*/
protected void hideStatus() {
setStatus(null);
if (warningPanel != null) {
// Clear the status
warningPanel.clearStatus();
// Hide the status panel
GridData data = (GridData)warningPanel.getLayoutData();
data.exclude = true;
warningPanel.setSize(0, 0);
getPageArea().layout(true);
if (sideBar != null) {
sideBar.setState(getPageLabel(), SideBarComposite.StepState.NONE);
}
}
}
/**
* Hides the page client area and shows a busy message.
*
* @param message Message to display
*/
public void showBusy(String message) {
GridData data;
this.busyMessage = message;
if (busyPanel != null) {
// Hide the page contents
data = (GridData)getPageArea().getLayoutData();
data.exclude = true;
getPageArea().setSize(0, 0);
// Show the busy panel
busyPanel.startBusy(message);
data = (GridData)busyPanel.getLayoutData();
data.exclude = false;
getPageContainer().layout(true);
}
}
/**
* Hides the busy message and shows he page client area.
* If the page is not busy, this method does nothing.
*/
public void hideBusy() {
GridData data;
if (busyMessage != null) {
this.busyMessage = null;
// Show the page contents
data = (GridData)getPageArea().getLayoutData();
data.exclude = false;
// Hide the status panel
busyPanel.stopBusy();
data = (GridData)busyPanel.getLayoutData();
data.exclude = true;
busyPanel.setSize(0, 0);
getPageContainer().layout(true);
}
}
/**
* Returns if the page is running in console mode.
*
* @return <code>true</code> if console mode, <code>false</code> if GUI mode.
*/
public boolean isConsoleMode() {
return (getShell() == null);
}
/**
* Prints a line of console output.
*
* @param output Output
*/
protected void printConsole(String output) {
System.out.println(output);
}
/**
* Returns if the page is currently busy.
*
* @return <code>true</code> if page is busy.
*/
public boolean isBusy() {
return (busyMessage != null);
}
/**
* Initializes the page navigation steps.
*/
public void setupNavigation() {
IWizardPage[] pages = getWizard().getPages();
for (IWizardPage page : pages) {
// Skip any setup page
if (page instanceof ISetupWizardPage)
continue;
InstallWizardPage installPage = (InstallWizardPage)page;
// Page is supported
if (installPage.isSupported()) {
if (sideBar != null)
sideBar.addStep(installPage.getPageLabel());
if (topBar != null)
topBar.addStep(installPage.getPageLabel());
}
}
if (sideBar != null) {
sideBar.layout(true);
sideBar.getParent().layout(true);
sideBar.setCurrentStep(getPageLabel());
}
if (topBar != null) {
topBar.layout(true);
topBar.getParent().layout(true);
topBar.setCurrentStep(getPageLabel());
}
}
/**
* Called to create the page contents.
* Subclasses should override.
*
* @param parent Parent
*/
public abstract Control createContents(Composite parent);
@Override
public IWizardPage getPreviousPage() {
IWizardPage previousPage = super.getPreviousPage();
// Don't allow moving back to a setup page if present
if (previousPage instanceof ISetupWizardPage) {
return null;
}
else {
return previousPage;
}
}
@Override
public boolean canFlipToNextPage() {
IWizardPage nextPage = getWizard().getNextPage(this);
// The installing page is only shown when
// the install button is selected.
if (nextPage instanceof ProgressPage) {
return false;
}
else {
return super.canFlipToNextPage();
}
}
@Override
public void saveInstallData(IInstallData data) throws CoreException {
}
@Override
public void setErrorMessage(String newMessage) {
super.setErrorMessage(newMessage);
// Set sidebar state
if (sideBar != null) {
sideBar.setState(getPageLabel(), newMessage == null ?
SideBarComposite.StepState.NONE : SideBarComposite.StepState.ERROR);
}
}
@Override
public boolean validate() {
return true;
}
@Override
public void setDescription(String description) {
throw new IllegalArgumentException("Description is not allowed for installer pages.");
}
/**
* Performs a long running operation. If the installer is running in GUI mode, a busy animation is
* displayed instead of the page contents until the operation is complete. If the insaller is running
* in console mode, the runnable is called directly.
*
* @param message Busy message to display
* @param runnable Operation to run
*/
protected void runOperation(String message, Runnable runnable) {
// Console mode
if (isConsoleMode()) {
runnable.run();
}
// GUI mode
else {
InstallWizard wizard = (InstallWizard)getWizard();
wizard.runOperation(this, message, runnable);
}
}
/**
* Performs a long running operation. A busy animation is displayed
* instead of the page contents if the operation takes longer than the
* specified time.
*
* @param message Busy message to display
* @param runnable Operation to run
* @param delay Delay (ms) before showing busy animation
*/
protected void runOperation(String message, Runnable runnable, int delay) {
InstallWizard wizard = (InstallWizard)getWizard();
wizard.runOperation(this, message, runnable, delay);
}
/**
* @return Returns the current install mode.
*/
protected IInstallMode getInstallMode() {
return Installer.getDefault().getInstallManager().getInstallMode();
}
/**
* Formats a message for the console. Any special formatting tags are
* removed. Copyright and trademark symbols are replaced with suitable
* substitutes for the console.
*
* @param text Formatted text
* @return Text with formatting removed
*/
public static String formatConsoleMessage(String text) {
// Remove formatting
text = text.replace("<b>", "");
text = text.replace("</b>", "");
text = text.replace("<i>", "");
text = text.replace("</i>", "");
text = text.replace("<u>", "");
text = text.replace("</u>", "");
text = text.replace("<strike>", "");
text = text.replace("</strike>", "");
text = text.replace("<small>", "");
text = text.replace("</small>", "");
text = text.replace("<big>", "");
text = text.replace("</big>", "");
// Replace any trademarks
text = replaceTrademarks(text);
return text;
}
/**
* Replaces copyright and trademark symbols substitutes.
*
* @param text Text to replace
* @return Replaced text
*/
public static String replaceTrademarks(String text) {
text = text.replaceAll("(?i)\\u00a9", "Copyright");
text = text.replaceAll("(?i)\\u00ae", "(R)");
text = text.replaceAll("(?i)\\u2122", "(TM)");
return text;
}
@Override
public boolean isSupported() {
IInstallMode mode = Installer.getDefault().getInstallManager().getInstallMode();
// By default, pages are supported in a new install only
return (mode.isInstall() && !mode.isUpdate() && !mode.isPatch() && !mode.isMirror());
}
@Override
public void setVisible(boolean visible) {
super.setVisible(visible);
// If auto-updating
if (getAutoUpdate()) {
// Start update thread if page is visible
if (visible) {
runUpdateJob(true);
}
// else stop update thread when page is not visible
else {
runUpdateJob(false);
}
}
}
/**
* Sets the page to start automatically updating. If auto-update is enabled, the {@link #autoUpdate()}
* method will be called periodically to update the page.
*
* @see #autoUpdate()
* @see #stopAutoUpdate()
*/
protected void startAutoUpdate() {
startAutoUpdate(DEFAULT_UPDATE_DELAY);
}
/**
* Sets the page to start automatically updating. If auto-update is enabled, the {@link #autoUpdate()}
* method will be called periodically to update the page.
*
* @param delay Delay in milliseconds.
* @see #autoUpdate()
* @see #stopAutoUpdate()
*/
protected void startAutoUpdate(int delay) {
this.autoUpdate = true;
if (delay < 0) {
delay = DEFAULT_UPDATE_DELAY;
}
this.autoUpdateDelay = delay;
runUpdateJob(true);
}
/**
* Stops the page auto-updating.
*/
protected void stopAutoUpdate() {
this.autoUpdate = false;
runUpdateJob(false);
}
/**
* @return <code>true</code> if automatic updating is enabled.
*/
protected boolean getAutoUpdate() {
return autoUpdate;
}
/**
* Starts or stops the automatic update job.
*
* @param start <code>true</code> to start, <code>false</code> to stop.
*/
private void runUpdateJob(boolean start) {
if (start) {
if (updateJob == null) {
updateJob = new AutoUpdateJob(autoUpdateDelay);
updateJob.schedule();
}
}
else {
if (updateJob != null) {
updateJob.cancel();
updateJob = null;
}
}
}
/**
* Called periodically if auto-updating is enabled. This method should be overridden to perform required periodic
* updates the page.
*
* @see {@link #startAutoUpdate()}
* @see {@link #stopAutoUpdate()}
*/
protected void autoUpdate() {
// Base does nothing
}
/**
* Composite to show status.
*/
private class WarningPanel extends ScrolledComposite {
/** Panel area */
private Composite panelArea;
/**
* Constructor
*
* @param parent Parent
* @param style Style
*/
public WarningPanel(Composite parent, int style) {
super(parent, style | SWT.V_SCROLL);
panelArea = new Composite(this, SWT.NONE);
GridLayout panelLayout = new GridLayout(2, false);
panelLayout.marginHeight = panelLayout.marginWidth = 0;
panelArea.setLayout(panelLayout);
setContent(panelArea);
setExpandHorizontal(true);
parent.addControlListener(new ControlAdapter() {
@Override
public void controlResized(ControlEvent e) {
updateLayout();
}
});
}
/**
* Returns the panel area.
*
* @return Panel area
*/
private Composite getPanelArea() {
return panelArea;
}
/**
* Updates the layout of the panel.
*/
private void updateLayout() {
if ((getPanelArea() != null) && !getPanelArea().isDisposed()) {
int width = getParent().getSize().x;
Point panelSize = getPanelArea().computeSize(width > 0 ? width : SWT.DEFAULT, SWT.DEFAULT);
getPanelArea().setSize(panelSize);
getPanelArea().layout(true);
// Limit height of warning panel
GridData data = (GridData)getLayoutData();
data.heightHint = (panelSize.y > maxWarningHeight) ? maxWarningHeight : SWT.DEFAULT;
setLayoutData(data);
getPageArea().layout(true);
}
}
/**
* Sets the panel status.
*
* @param statuses Status to show
*/
public void setStatus(IStatus[] statuses) {
clearStatus();
// Skip warnings and information if the status has errors
boolean onlyErrors = false;
for (IStatus status : statuses) {
if (status.getSeverity() == IStatus.ERROR) {
onlyErrors = true;
}
}
for (IStatus status : statuses) {
// Show only errors
if (onlyErrors && (status.getSeverity() != IStatus.ERROR))
continue;
Label iconLabel = new Label(getPanelArea(), SWT.NONE);
iconLabel.setLayoutData(new GridData(SWT.CENTER, SWT.BEGINNING, false, false, 1, 1));
if (status.getSeverity() == IStatus.WARNING) {
iconLabel.setImage(Installer.getDefault().getImageRegistry().get(IInstallerImages.WARNING));
}
else if (status.getSeverity() == IStatus.ERROR) {
iconLabel.setImage(Installer.getDefault().getImageRegistry().get(IInstallerImages.ERROR));
}
else {
iconLabel.setImage(Installer.getDefault().getImageRegistry().get(IInstallerImages.INFO));
}
StringBuilder buffer = new StringBuilder();
getStatusMessage(buffer, status);
Label messageLabel = new Label(getPanelArea(), SWT.WRAP);
messageLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
messageLabel.setText(buffer.toString());
}
updateLayout();
}
/**
* Combines all status messages.
*
* @param buffer Buffer for messages. Each status message will be terminated
* with a new line.
* @param status Status to combine.
*/
private void getStatusMessage(StringBuilder buffer, IStatus status) {
buffer.append(status.getMessage());
buffer.append('\n');
IStatus[] children = status.getChildren();
for (IStatus child : children) {
getStatusMessage(buffer, child);
}
}
/**
* Clears the panel status.
*/
public void clearStatus() {
Control[] children = getPanelArea().getChildren();
for (Control child : children) {
child.dispose();
}
}
}
/**
* Composite to show page busy status.
*/
private class BusyPanel extends Composite {
private BusyAnimationControl waitCtrl;
/**
* Constructor
*
* @param parent Parent
* @param style Style
*/
public BusyPanel(Composite parent, int style) {
super(parent, style);
setLayout(new GridLayout(1, false));
// Create animation control
waitCtrl = new BusyAnimationControl(this, SWT.NONE);
waitCtrl.setLayoutData(new GridData(SWT.CENTER, SWT.BEGINNING, false, false, 1, 1));
waitCtrl.setFont(getBoldFont());
}
/**
* Starts the busy animation.
*
* @param message Message to display
*/
public void startBusy(String message) {
waitCtrl.setText(message);
waitCtrl.animate(true);
layout(true);
}
/**
* Stops the busy animation.
*/
public void stopBusy() {
waitCtrl.animate(false);
}
}
/**
* Job that periodically calls the auto-update method on the UI thread.
*/
private class AutoUpdateJob extends Job {
/** Update delay */
private int delay;
/**
* Constructs auto-update thread.
*
* @param delay Delay in milliseconds.
*/
public AutoUpdateJob(int delay) {
super("WizardPageAutoUpdateJob");
this.delay = delay;
setSystem(true);
}
@Override
protected IStatus run(final IProgressMonitor monitor) {
try {
while (!monitor.isCanceled()) {
Thread.sleep(delay);
synchronized(this) {
if (!monitor.isCanceled()) {
// Run in UI thread
getShell().getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
try {
autoUpdate();
}
catch (Exception e) {
Installer.log(e);
monitor.setCanceled(true);
}
}
});
}
}
}
} catch (Exception e) {
Installer.log(e);
}
return Status.OK_STATUS;
}
}
}