org.eclipse.oomph.setup.ui.wizards.ProgressPage.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.oomph.setup.ui.wizards.ProgressPage.java

Source

/*
 * Copyright (c) 2014, 2015 Eike Stepper (Berlin, Germany) 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:
 *    Eike Stepper - initial API and implementation
 */
package org.eclipse.oomph.setup.ui.wizards;

import org.eclipse.oomph.base.util.BaseUtil;
import org.eclipse.oomph.internal.ui.AccessUtil;
import org.eclipse.oomph.internal.ui.OomphAdapterFactoryContentProvider;
import org.eclipse.oomph.setup.Installation;
import org.eclipse.oomph.setup.LicenseInfo;
import org.eclipse.oomph.setup.SetupTask;
import org.eclipse.oomph.setup.Trigger;
import org.eclipse.oomph.setup.UnsignedPolicy;
import org.eclipse.oomph.setup.User;
import org.eclipse.oomph.setup.Workspace;
import org.eclipse.oomph.setup.impl.DynamicSetupTaskImpl;
import org.eclipse.oomph.setup.internal.core.SetupContext;
import org.eclipse.oomph.setup.internal.core.SetupTaskPerformer;
import org.eclipse.oomph.setup.internal.core.SetupTaskPerformer.ExecutableInfo;
import org.eclipse.oomph.setup.internal.core.util.SetupCoreUtil;
import org.eclipse.oomph.setup.log.ProgressLog;
import org.eclipse.oomph.setup.log.ProgressLog.Severity;
import org.eclipse.oomph.setup.log.ProgressLogFilter;
import org.eclipse.oomph.setup.log.ProgressLogProvider;
import org.eclipse.oomph.setup.log.ProgressLogRunnable;
import org.eclipse.oomph.setup.provider.SetupEditPlugin;
import org.eclipse.oomph.setup.ui.AbstractConfirmDialog;
import org.eclipse.oomph.setup.ui.AbstractDialogConfirmer;
import org.eclipse.oomph.setup.ui.LicenseDialog;
import org.eclipse.oomph.setup.ui.LicensePrePrompter;
import org.eclipse.oomph.setup.ui.SetupPropertyTester;
import org.eclipse.oomph.setup.ui.SetupUIPlugin;
import org.eclipse.oomph.setup.ui.ToolTipLabelProvider;
import org.eclipse.oomph.setup.ui.UnsignedContentDialog;
import org.eclipse.oomph.setup.util.FileUtil;
import org.eclipse.oomph.ui.BackgroundProgressPart;
import org.eclipse.oomph.ui.ButtonBar;
import org.eclipse.oomph.ui.ErrorDialog;
import org.eclipse.oomph.ui.UIUtil;
import org.eclipse.oomph.util.Confirmer;
import org.eclipse.oomph.util.IORuntimeException;
import org.eclipse.oomph.util.IOUtil;
import org.eclipse.oomph.util.OS;
import org.eclipse.oomph.util.Pair;

import org.eclipse.emf.common.ui.viewer.ColumnViewerInformationControlToolTipSupport;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.edit.provider.IItemFontProvider;
import org.eclipse.emf.edit.provider.ItemProvider;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider;
import org.eclipse.emf.edit.ui.provider.ExtendedFontRegistry;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.IJobManager;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.ILicense;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.TextViewer;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.wizard.IWizardContainer;
import org.eclipse.jface.wizard.ProgressMonitorPart;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.LocationEvent;
import org.eclipse.swt.browser.LocationListener;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.progress.JobInfo;
import org.eclipse.ui.internal.progress.ProgressManager;

import java.io.File;
import java.lang.reflect.Constructor;
import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author Eike Stepper
 */
public class ProgressPage extends SetupWizardPage {
    public static final Object PROGRESS_FAMILY = new Object();

    public static final String PROGRESS_STATUS = "org.eclipse.oomph.setup.status";

    public static final String PAGE_NAME = "ProgressPage";

    private final Map<SetupTask, Point> setupTaskSelections = new HashMap<SetupTask, Point>();

    private Constructor<? extends ProgressLog> progressLogWrapper;

    private TreeViewer treeViewer;

    private final ISelectionChangedListener treeViewerSelectionChangedListener = new ISelectionChangedListener() {
        public void selectionChanged(SelectionChangedEvent event) {
            IStructuredSelection selection = (IStructuredSelection) event.getSelection();
            Object element = selection.getFirstElement();
            if (element instanceof EObject) {
                for (EObject eObject = (EObject) element; eObject != null; eObject = eObject.eContainer()) {
                    if (eObject != currentTask && eObject instanceof SetupTask) {
                        Point textSelection = setupTaskSelections.get(eObject);
                        if (textSelection != null) {
                            int start = textSelection.x;
                            // Treat -1 so that at selects to the very end.
                            int end = textSelection.y;
                            if (end == -1) {
                                end = logText.getCharCount();
                            }

                            String selectedText = logText.getText(start, end);
                            int index = 0;
                            int length = selectedText.length();

                            // Skip leading line feeds.
                            for (; index < length; ++index) {
                                char c = selectedText.charAt(index);
                                if (c == '\n' || c == '\r') {
                                    ++start;
                                } else {
                                    break;
                                }
                            }

                            // Force the first line to be scrolled into view
                            logText.setSelection(start, start);

                            // Determine the number of lines of text to be selected
                            int lineFeedCount = 0;
                            int carriageReturnCount = 0;
                            for (; index < length; ++index) {
                                char c = selectedText.charAt(index);
                                if (c == '\n') {
                                    ++lineFeedCount;
                                } else if (c == '\r') {
                                    ++carriageReturnCount;
                                }
                            }

                            // If the number of visible lines is greater than the number of lines in the selection, invert the
                            // selection range to scroll the top line into view.
                            int visibleLineCount = logText.getClientArea().height / logText.getLineHeight();
                            if (lineFeedCount > visibleLineCount || carriageReturnCount > visibleLineCount) {
                                logText.setSelection(end, start);
                            } else {
                                logText.setSelection(start, end);
                            }
                        }
                    }
                }
            }
        }
    };

    private StyledText logText;

    private ProgressMonitorPart progressMonitorPart;

    private final Document logDocument = new Document();

    private final ProgressLogFilter logFilter = new ProgressLogFilter();

    private SetupTask currentTask;

    private ProgressPageLog progressPageLog;

    private boolean scrollLock;

    private boolean dismissAutomatically;

    private boolean launchAutomatically;

    private Button scrollLockButton;

    private Button dismissButton;

    private Button launchButton;

    private boolean hasLaunched;

    public static final Confirmer LICENSE_CONFIRMER = new AbstractDialogConfirmer() {
        @Override
        protected AbstractConfirmDialog createDialog(boolean defaultConfirmed, Object info) {
            @SuppressWarnings("unchecked")
            Map<ILicense, List<IInstallableUnit>> licensesToIUs = (Map<ILicense, List<IInstallableUnit>>) info;
            return new LicenseDialog(licensesToIUs);
        }
    };

    public ProgressPage() {
        super(PAGE_NAME);
        setTitle("Progress");
        setDescription(
                "Wait for the setup to complete, or cancel the progress indicator and press Back to make changes.");
    }

    @Override
    protected Control createUI(final Composite parent) {
        Composite mainComposite = new Composite(parent, SWT.NONE);
        mainComposite.setLayout(UIUtil.createGridLayout(1));

        SashForm sashForm = new SashForm(mainComposite, SWT.SMOOTH | SWT.VERTICAL);
        sashForm.setLayoutData(new GridData(GridData.FILL_BOTH));
        AccessUtil.setKey(sashForm, "sash");

        treeViewer = new TreeViewer(sashForm, SWT.BORDER);
        Tree tree = treeViewer.getTree();
        addHelpCallout(tree, 1);

        ILabelProvider labelProvider = createLabelProvider();
        treeViewer.setLabelProvider(labelProvider);

        final AdapterFactoryContentProvider contentProvider = new OomphAdapterFactoryContentProvider(
                getAdapterFactory());
        treeViewer.setContentProvider(contentProvider);
        treeViewer.addSelectionChangedListener(treeViewerSelectionChangedListener);

        new ColumnViewerInformationControlToolTipSupport(treeViewer, new LocationListener() {
            public void changing(LocationEvent event) {
            }

            public void changed(LocationEvent event) {
            }
        });

        tree.setLayoutData(new GridData(GridData.FILL_BOTH));
        tree.setBackground(getShell().getDisplay().getSystemColor(SWT.COLOR_WHITE));

        TextViewer logTextViewer = new TextViewer(sashForm,
                SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.CANCEL | SWT.MULTI);
        logTextViewer.setDocument(logDocument);

        logText = logTextViewer.getTextWidget();
        logText.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
        logText.setFont(JFaceResources.getFont(JFaceResources.TEXT_FONT));
        logText.setEditable(false);
        logText.setLayoutData(new GridData(GridData.FILL_BOTH));
        logText.getVerticalBar().addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent event) {
                if (event.detail == SWT.DRAG && !scrollLock) {
                    scrollLockButton.setSelection(true);
                    scrollLock = true;
                }
            }
        });

        addHelpCallout(logText, 2);
        AccessUtil.setKey(logText, "log");

        return mainComposite;
    }

    @Override
    protected void createCheckButtons(ButtonBar buttonBar) {
        scrollLockButton = buttonBar.addCheckButton("Scroll lock",
                "Keep the log from scrolling to the end when new messages are added", false, null);
        scrollLock = scrollLockButton.getSelection();
        scrollLockButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                scrollLock = scrollLockButton.getSelection();
            }
        });
        AccessUtil.setKey(scrollLockButton, "lock");

        dismissButton = buttonBar.addCheckButton("Dismiss automatically",
                "Dismiss this wizard when all setup tasks have performed successfully", false,
                "dismissAutomatically");
        dismissAutomatically = dismissButton.getSelection();
        dismissButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                dismissAutomatically = dismissButton.getSelection();
            }
        });
        AccessUtil.setKey(dismissButton, "dismiss");

        if (getWizard().getOS().isCurrentOS()) {
            if (getTrigger() == Trigger.BOOTSTRAP) {
                launchButton = buttonBar.addCheckButton("Launch automatically",
                        "Launch the installed product when all setup tasks have performed successfully", true,
                        "launchAutomatically");
            } else {
                launchButton = buttonBar.addCheckButton("Restart automatically if needed",
                        "Restart the current product if the installation has been changed by setup tasks", false,
                        "restartIfNeeded");
            }

            launchAutomatically = launchButton.getSelection();
            launchButton.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(SelectionEvent e) {
                    launchAutomatically = launchButton.getSelection();
                }
            });
            AccessUtil.setKey(launchButton, "launch");
        }
    }

    @Override
    protected void createFooter(Composite parent) {
        progressMonitorPart = new BackgroundProgressPart(parent, null, true) {
            @Override
            protected void initialize(Layout layout, int progressIndicatorHeight) {
                super.initialize(layout, progressIndicatorHeight);
                fLabel.dispose();

                if (PlatformUI.isWorkbenchRunning()) {
                    for (Control child : getChildren()) {
                        if (child instanceof ToolBar) {
                            ToolBar toolBar = (ToolBar) child;
                            ToolItem minimizeButton = new ToolItem(toolBar, SWT.PUSH);
                            minimizeButton.setImage(SetupUIPlugin.INSTANCE.getSWTImage("hide"));
                            minimizeButton.setToolTipText("Minimize to the status area");
                            minimizeButton.addSelectionListener(new SelectionAdapter() {
                                @Override
                                public void widgetSelected(SelectionEvent event) {
                                    getWizard().getShell().setVisible(false);
                                }
                            });

                            break;
                        }
                    }
                }
            }

            @Override
            protected void updateLabel() {
            }

            @Override
            public void done() {
                UIUtil.syncExec(new Runnable() {
                    public void run() {
                        fProgressIndicator.sendRemainingWork();
                        fProgressIndicator.done();
                        removeFromCancelComponent(null);
                        progressMonitorPart.setLayoutData(new GridData(0, 0));
                        progressMonitorPart.getParent().layout();
                    }
                });
            }
        };

        progressMonitorPart.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
        AccessUtil.setKey(progressMonitorPart, "progress");
    }

    @Override
    public void enterPage(boolean forward) {
        if (forward) {
            setPageComplete(false);
            setErrorMessage(null);
            setMessage(null);

            hasLaunched = false;

            progressPageLog = new ProgressPageLog(progressMonitorPart);
            logDocument.set("");

            // This is a private hook so we can monitor progress for documentation capture.
            ProgressLog progressLog = progressPageLog;
            if (progressLogWrapper != null) {
                try {
                    progressLog = progressLogWrapper.newInstance(progressLog);
                } catch (Throwable ex) {
                    // Ignore.
                }
            }

            final SetupTaskPerformer performer = getPerformer();
            User performerUser = performer.getUser();

            performer.setProgress(progressLog);
            performer.put(ILicense.class, LICENSE_CONFIRMER);
            performer.put(Certificate.class,
                    UnsignedContentDialog.createUnsignedContentConfirmer(performerUser, false));

            File renamed = null;
            if (getTrigger() == Trigger.BOOTSTRAP) {
                File configurationLocation = performer.getProductConfigurationLocation();
                if (configurationLocation.exists()) {
                    try {
                        // This must happen before the performer opens the logStream for the first logging!
                        renamed = FileUtil.rename(configurationLocation);
                    } catch (RuntimeException ex) {
                        throw ex;
                    } catch (Exception ex) {
                        progressPageLog.log(ex);
                        setErrorMessage("Could not rename '" + configurationLocation
                                + "'.  Press Back twice to choose a different installation location.");
                        progressPageLog.done();

                        throw new IORuntimeException(ex);
                    }
                }

                if (UIUtil.isBrowserAvailable()) {
                    EList<LicenseInfo> licenses = LicensePrePrompter.execute(getShell(), performerUser);
                    if (licenses != null) {
                        ResourceSet resourceSet = SetupCoreUtil.createResourceSet();
                        User user = SetupContext.createUserOnly(resourceSet).getUser();
                        user.getAcceptedLicenses().addAll(licenses);
                        BaseUtil.saveEObject(user);
                    }
                }
            }

            treeViewer.setInput(new ItemProvider(performer.getNeededTasks()));

            String jobName = "Executing " + getTriggerName().toLowerCase() + " tasks";
            performer.log(jobName, false, Severity.INFO);

            if (renamed != null) {
                performer.log("Renamed existing configuration folder to " + renamed);
            }

            run(jobName, new ProgressLogRunnable() {
                public Set<String> run(ProgressLog log) throws Exception {
                    final ProgressManager oldProgressProvider = ProgressManager.getInstance();
                    ProgressLogProvider newProgressLogProvider = new ProgressLogProvider(progressPageLog,
                            oldProgressProvider);

                    // When the workbench isn't running org.eclipse.ui.internal.progress.new JobChangeAdapter()'s done(IJobChangeEvent) method one cleanup.
                    JobChangeAdapter jobChangeListener = PlatformUI.isWorkbenchRunning() ? null
                            : new JobChangeAdapter() {
                                @Override
                                public void done(IJobChangeEvent event) {
                                    Job job = event.getJob();
                                    for (JobInfo jobInfo : oldProgressProvider.getJobInfos(true)) {
                                        if (jobInfo.getJob() == job) {
                                            oldProgressProvider.removeJobInfo(jobInfo);
                                            break;
                                        }
                                    }
                                }
                            };

                    IJobManager jobManager = Job.getJobManager();
                    jobManager.setProgressProvider(newProgressLogProvider);
                    if (jobChangeListener != null) {
                        jobManager.addJobChangeListener(jobChangeListener);
                    }

                    try {
                        performer.perform(progressPageLog);
                        return performer.getRestartReasons();
                    } finally {
                        jobManager.setProgressProvider(oldProgressProvider);
                        if (jobChangeListener != null) {
                            jobManager.removeJobChangeListener(jobChangeListener);
                        }
                    }
                }
            });
        }
    }

    @Override
    public void leavePage(boolean forward) {
        if (forward) {
            setPageComplete(false);
        } else {
            setPageComplete(false);
            hasLaunched = false;
            setButtonState(IDialogConstants.CANCEL_ID, true);
        }
    }

    @Override
    public boolean performCancel() {
        return progressPageLog == null || progressPageLog.isDone() || progressPageLog.isCanceled();
    }

    @Override
    protected void setButtonState(int buttonID, boolean enabled) {
        super.setButtonState(buttonID, enabled);

        if (buttonID == IDialogConstants.CANCEL_ID && getPerformer().hasSuccessfullyPerformed()) {
            scrollLockButton.setEnabled(enabled);
            dismissButton.setEnabled(enabled);

            if (launchButton != null) {
                launchButton.setEnabled(!hasLaunched);
            }
        }
    }

    private ILabelProvider createLabelProvider() {
        return new ToolTipLabelProvider(getAdapterFactory()) {
            @Override
            public Font getFont(Object element) {
                if (element == currentTask) {
                    return ExtendedFontRegistry.INSTANCE.getFont(treeViewer.getControl().getFont(),
                            IItemFontProvider.BOLD_FONT);
                }

                return super.getFont(element);
            }
        };
    }

    private void run(final String jobName, final ProgressLogRunnable runnable) {
        try {
            // Remember and use the progressPageLog that is valid at this point in time.
            final ProgressPageLog progressLog = progressPageLog;

            Runnable jobRunnable = new Runnable() {
                public void run() {
                    final SetupWizard wizard = getWizard();
                    final Shell shell = wizard.getShell();

                    setButtonState(IDialogConstants.CANCEL_ID, false);
                    setButtonState(IDialogConstants.BACK_ID, false);

                    final Job job = new Job(jobName) {
                        @Override
                        protected IStatus run(IProgressMonitor monitor) {
                            progressLog.setProgressMonitor(monitor);

                            final Trigger trigger = getTrigger();
                            long start = System.currentTimeMillis();
                            boolean success = false;
                            Set<String> restartReasons = null;

                            UIUtil.syncExec(new Runnable() {
                                public void run() {
                                    shell.setData(PROGRESS_STATUS, null);
                                    if (trigger != Trigger.BOOTSTRAP) {
                                        if (trigger == Trigger.STARTUP
                                                || !SetupPropertyTester.isShowProgressInWizard()) {
                                            shell.setVisible(false);
                                        }

                                        SetupPropertyTester.setPerformingShell(shell);
                                    }
                                }
                            });

                            try {
                                restartReasons = runnable.run(progressLog);

                                SetupTaskPerformer performer = getPerformer();
                                saveLocalFiles(performer);

                                if (launchAutomatically && trigger == Trigger.BOOTSTRAP) {
                                    hasLaunched = launchProduct(performer);
                                }

                                success = true;
                            } catch (OperationCanceledException ex) {
                                // Do nothing
                            } catch (Throwable ex) {
                                final IStatus status = SetupUIPlugin.INSTANCE.getStatus(ex);
                                SetupUIPlugin.INSTANCE.log(new IStatus() {
                                    public IStatus[] getChildren() {
                                        return status.getChildren();
                                    }

                                    public int getCode() {
                                        return status.getCode();
                                    }

                                    public Throwable getException() {
                                        return status.getException();
                                    }

                                    public String getMessage() {
                                        return status.getMessage();
                                    }

                                    public String getPlugin() {
                                        return status.getPlugin();
                                    }

                                    public int getSeverity() {
                                        return IStatus.WARNING;
                                    }

                                    public boolean isMultiStatus() {
                                        return status.isMultiStatus();
                                    }

                                    public boolean isOK() {
                                        return false;
                                    }

                                    public boolean matches(int severityMask) {
                                        return (severityMask & IStatus.WARNING) != 0;
                                    }

                                    @Override
                                    public String toString() {
                                        StringBuilder result = new StringBuilder();
                                        result.append("Status WARNING");
                                        result.append(": ");
                                        result.append(getPlugin());
                                        result.append(" code=");
                                        result.append(getCode());
                                        result.append(' ');
                                        result.append(getMessage());
                                        result.append(' ');
                                        result.append(getException());
                                        result.append(" children=[");
                                        result.append(status);
                                        result.append("]");
                                        return result.toString();
                                    }
                                });
                                progressLog.log(ex);
                            } finally {
                                long seconds = (System.currentTimeMillis() - start) / 1000;
                                progressLog.setTerminating();
                                progressLog.message("Took " + seconds + " seconds.");

                                getWizard().sendStats(success);

                                final AtomicBoolean disableCancelButton = new AtomicBoolean(true);

                                final boolean restart = restartReasons != null && !restartReasons.isEmpty()
                                        && trigger != Trigger.BOOTSTRAP;
                                if (restart) {
                                    progressLog.message("A restart is needed for the following reasons:", false,
                                            Severity.INFO);
                                    for (String reason : restartReasons) {
                                        progressLog.message("  - " + reason);
                                    }

                                    wizard.setFinishAction(new Runnable() {
                                        public void run() {
                                            progressLog.done();

                                            UIUtil.asyncExec(new Runnable() {
                                                public void run() {
                                                    // Also include any triggered task whose implementation is currently unavailable.
                                                    // Such tasks will not be needed by are likely needed after the restart when their implementations have been installed.
                                                    SetupTaskPerformer performer = getPerformer();
                                                    EList<SetupTask> remainingTasks = new BasicEList<SetupTask>(
                                                            performer.getNeededTasks());
                                                    for (SetupTask setupTask : performer.getTriggeredSetupTasks()) {
                                                        if (setupTask instanceof DynamicSetupTaskImpl) {
                                                            remainingTasks.add(setupTask);
                                                        }
                                                    }

                                                    SetupUIPlugin.restart(trigger, remainingTasks);
                                                }
                                            });
                                        }
                                    });

                                    if (success && launchAutomatically) {
                                        wizard.performFinish();
                                        return Status.OK_STATUS;
                                    }

                                    progressLog.message("Press Finish to restart now or Cancel to restart later.",
                                            Severity.INFO);
                                    disableCancelButton.set(false);
                                } else {
                                    if (success && dismissAutomatically) {
                                        wizard.setFinishAction(new Runnable() {
                                            public void run() {
                                                IWizardContainer container = getContainer();
                                                if (container instanceof WizardDialog) {
                                                    WizardDialog dialog = (WizardDialog) container;
                                                    progressLog.done();
                                                    dialog.close();
                                                }
                                            }
                                        });

                                        wizard.performFinish();
                                        return Status.OK_STATUS;
                                    }

                                    if (success) {
                                        progressLog.message("Press Finish to close the dialog.", Severity.INFO);

                                        if (launchButton != null && !hasLaunched && trigger == Trigger.BOOTSTRAP) {
                                            wizard.setFinishAction(new Runnable() {
                                                public void run() {
                                                    if (launchAutomatically) {
                                                        try {
                                                            hasLaunched = launchProduct(getPerformer());
                                                        } catch (Exception ex) {
                                                            SetupUIPlugin.INSTANCE.log(ex);
                                                        }
                                                    }
                                                }
                                            });
                                        }
                                    } else {
                                        if (progressLog.isCanceled()) {
                                            progressLog.message("Task execution was canceled.", Severity.WARNING);
                                        } else {
                                            progressLog.message("There are failed tasks.", Severity.ERROR);
                                        }

                                        progressLog.message(
                                                "Press Back to choose different settings or Cancel to abort.",
                                                Severity.INFO);
                                    }
                                }

                                IOUtil.close(getPerformer().getLogStream());

                                final boolean finalSuccess = success;
                                UIUtil.syncExec(new Runnable() {
                                    public void run() {
                                        progressLog.done();
                                        setPageComplete(finalSuccess);
                                        setButtonState(IDialogConstants.BACK_ID, true);

                                        if (finalSuccess) {
                                            if (restart) {
                                                setMessage(
                                                        "Task execution has successfully completed but requires a restart.  Press Finish to restart now or Cancel to restart later.",
                                                        IMessageProvider.WARNING);
                                                setButtonState(IDialogConstants.CANCEL_ID, true);

                                                shell.setData(PROGRESS_STATUS, new Status(IStatus.WARNING,
                                                        SetupEditPlugin.INSTANCE.getSymbolicName(),
                                                        "Task execution has successfully completed but requires a restart"));
                                            } else {
                                                setMessage(
                                                        "Task execution has successfully completed.  Press Back to choose different settings or Finish to exit.");
                                                if (disableCancelButton.get()) {
                                                    setButtonState(IDialogConstants.CANCEL_ID, false);
                                                }

                                                shell.setData(PROGRESS_STATUS,
                                                        new Status(IStatus.OK,
                                                                SetupEditPlugin.INSTANCE.getSymbolicName(),
                                                                "Task execution has successfully completed"));
                                            }
                                        } else {
                                            setButtonState(IDialogConstants.CANCEL_ID, true);
                                            if (progressLog.isCanceled()) {
                                                setErrorMessage(
                                                        "Task execution was canceled.  Press Back to choose different settings or Cancel to abort.");

                                                shell.setData(PROGRESS_STATUS,
                                                        new Status(IStatus.CANCEL,
                                                                SetupEditPlugin.INSTANCE.getSymbolicName(),
                                                                "Task execution was canceled."));
                                            } else {
                                                setErrorMessage(
                                                        "There are failed tasks.  Press Back to choose different settings or Cancel to abort.");

                                                shell.setData(PROGRESS_STATUS,
                                                        new Status(IStatus.ERROR,
                                                                SetupEditPlugin.INSTANCE.getSymbolicName(),
                                                                "Task execution was failed."));
                                            }
                                        }
                                    }
                                });
                            }

                            return Status.OK_STATUS;
                        }

                        @Override
                        public boolean belongsTo(Object family) {
                            return family == PROGRESS_FAMILY;
                        }
                    };

                    job.schedule();

                }
            };

            UIUtil.asyncExec(jobRunnable);
        } catch (

        Throwable ex)

        {
            SetupUIPlugin.INSTANCE.log(ex);
            ErrorDialog.open(ex);
        }

    }

    private void saveLocalFiles(SetupTaskPerformer performer) {
        User performerUser = performer.getUser();
        ResourceSet resourceSet = SetupCoreUtil.createResourceSet();
        User user = SetupContext.createUserOnly(resourceSet).getUser();

        boolean shouldSave = user.getAcceptedLicenses().addAll(performerUser.getAcceptedLicenses());
        UnsignedPolicy userUnsignedPolicy = user.getUnsignedPolicy();
        UnsignedPolicy performerUserUnsignedPolicy = performerUser.getUnsignedPolicy();
        if (userUnsignedPolicy != performerUserUnsignedPolicy) {
            user.setUnsignedPolicy(performerUserUnsignedPolicy);
            shouldSave = true;
        }

        if (shouldSave) {
            BaseUtil.saveEObject(user);
        }

        SetupContext setupContext = getWizard().getSetupContext();

        Installation installation = setupContext.getInstallation();
        BaseUtil.saveEObject(installation);

        Workspace workspace = setupContext.getWorkspace();
        if (workspace != null) {
            BaseUtil.saveEObject(workspace);
        }

        SetupContext.associate(installation, workspace);
    }

    public static boolean launchProduct(SetupTaskPerformer performer) throws Exception {
        OS os = performer.getOS();
        if (os.isCurrentOS()) {
            performer.log("Launching the installed product...");
            ExecutableInfo info = performer.getExecutableInfo();

            List<String> command = new ArrayList<String>();
            command.add(info.getExecutable().toString());

            File ws = performer.getWorkspaceLocation();
            if (ws != null) {
                SetupUIPlugin.initialStart(ws, performer.isOffline(), performer.isMirrors());

                command.add("-data");
                command.add(ws.toString());
            }

            command.add("-vmargs");
            command.add("-Duser.dir=" + info.getEclipseLocation());

            os.execute(command, info.needsConsole());
            return true;
        }

        performer.log("Launching the installed product is not possible for cross-platform installs. Skipping.");
        return false;
    }

    /**
     * @author Eike Stepper
     */
    private class ProgressPageLog implements ProgressLog, IProgressMonitor {
        /**
         * A list that contains instances of String and/or Pair<String, ProgressLog.Severity>.
         */
        private List<Object> queue;

        private final ProgressMonitorPart progressMonitorPart;

        private IProgressMonitor progressMonitor;

        private boolean canceled;

        private boolean terminating;

        private boolean done;

        public ProgressPageLog(ProgressMonitorPart progressMonitorPart) {
            this.progressMonitorPart = progressMonitorPart;
            progressMonitorPart.attachToCancelComponent(null);
            progressMonitorPart.setCanceled(false);
            progressMonitorPart.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
            progressMonitorPart.getParent().layout();
        }

        public void setProgressMonitor(IProgressMonitor progressMonitor) {
            this.progressMonitor = progressMonitor;
        }

        public void setTerminating() {
            terminating = true;
        }

        public boolean isCanceled() {
            if (!canceled) {
                if (progressMonitorPart.isCanceled() || progressMonitor != null && progressMonitor.isCanceled()) {
                    canceled = true;
                }
            }

            return canceled;
        }

        public boolean isDone() {
            return done;
        }

        public void done() {
            done = true;
            progressMonitorPart.done();

            if (progressMonitor != null) {
                progressMonitor.done();
            }
        }

        public void beginTask(final String name, final int totalWork) {
            progressMonitorPart.beginTask(name, totalWork);
            logTaskName(name);

            if (progressMonitor != null) {
                progressMonitor.beginTask(name, totalWork);
            }
        }

        public void internalWorked(final double work) {
            progressMonitorPart.internalWorked(work);
            if (progressMonitor != null) {
                progressMonitor.internalWorked(work);
            }
        }

        public void setCanceled(boolean canceled) {
            this.canceled = canceled;
            if (progressMonitor != null) {
                progressMonitor.setCanceled(canceled);
            }
        }

        public void setTaskName(String name) {
            logTaskName(name);

            if (progressMonitor != null) {
                progressMonitor.setTaskName(name);
            }
        }

        public void subTask(String name) {
            logTaskName(name);

            if (progressMonitor != null) {
                progressMonitor.subTask(name);
            }
        }

        public void worked(final int work) {
            progressMonitorPart.worked(work);
            if (progressMonitor != null) {
                progressMonitor.internalWorked(work);
            }
        }

        public void task(final SetupTask setupTask) {
            UIUtil.syncExec(new Runnable() {
                public void run() {
                    SetupTask previousCurrentTask = currentTask;
                    currentTask = setupTask;

                    int offset = 0;
                    if (previousCurrentTask != null) {
                        Point previousTextSelection = setupTaskSelections.get(previousCurrentTask);
                        offset = logText.getCharCount() - 1;
                        int start = previousTextSelection.x;
                        setupTaskSelections.put(previousCurrentTask, new Point(start, offset));
                        treeViewer.refresh(previousCurrentTask, true);
                    }

                    if (setupTask != null) {
                        setupTaskSelections.put(setupTask, new Point(offset, -1));
                        treeViewer.refresh(setupTask, true);
                        treeViewer.removeSelectionChangedListener(treeViewerSelectionChangedListener);
                        treeViewer.setSelection(new StructuredSelection(setupTask), true);
                        treeViewer.addSelectionChangedListener(treeViewerSelectionChangedListener);
                    }
                }
            });
        }

        public void log(String line) {
            log(line, true);
        }

        public void log(IStatus status) {
            String string = SetupUIPlugin.toString(status);
            log(string, false, Severity.fromStatus(status));
        }

        public void log(Throwable t) {
            String string = SetupUIPlugin.toString(t);
            log(string, false, Severity.ERROR);
        }

        public void log(String line, Severity severity) {
            log(line, true, severity);
        }

        public void log(String line, boolean filter) {
            log(line, filter, Severity.OK);
        }

        public void log(String line, boolean filter, Severity severity) {
            if (done) {
                return;
            }

            message(line, filter, severity);
        }

        public void message(String line) {
            message(line, true, Severity.OK);
        }

        public void message(String line, Severity severity) {
            message(line, true, severity);
        }

        private void message(String line, boolean filter, Severity severity) {
            if (!terminating && isCanceled()) {
                throw new OperationCanceledException();
            }

            if (filter) {
                line = logFilter.filter(line);
            }

            if (line == null) {
                return;
            }

            boolean wasEmpty = enqueue(line, severity);
            if (wasEmpty) {
                UIUtil.asyncExec(new Runnable() {
                    public void run() {
                        List<Object> lines = dequeue();
                        appendText(lines);
                    }
                });
            }
        }

        private synchronized boolean enqueue(String line, Severity severity) {
            boolean wasEmpty = queue == null;
            if (wasEmpty) {
                queue = new ArrayList<Object>();
            }

            if (severity == Severity.OK) {
                queue.add(line);
            } else {
                queue.add(Pair.create(line, severity));
            }

            return wasEmpty;
        }

        private synchronized List<Object> dequeue() {
            List<Object> result = queue;
            queue = null;
            return result;
        }

        private void appendText(List<Object> lines) {
            if (logText.isDisposed()) {
                return;
            }

            for (Object value : lines) {
                String line;
                Severity severity;
                if (value instanceof String) {
                    line = (String) value;
                    severity = Severity.OK;
                } else {
                    @SuppressWarnings("unchecked")
                    Pair<String, Severity> pair = (Pair<String, Severity>) value;

                    line = pair.getElement1();
                    severity = pair.getElement2();
                }

                line += "\n";

                try {
                    int length = logDocument.getLength();
                    logDocument.replace(length, 0, line);

                    int colorID;
                    switch (severity) {
                    case INFO:
                        colorID = SWT.COLOR_BLUE;
                        break;

                    case WARNING:
                        colorID = SWT.COLOR_DARK_YELLOW;
                        break;

                    case ERROR:
                        colorID = SWT.COLOR_RED;
                        break;

                    default:
                        colorID = SWT.COLOR_BLACK;
                        break;

                    }

                    if (colorID != SWT.COLOR_BLACK) {
                        Color color = logText.getDisplay().getSystemColor(colorID);
                        StyleRange styleRange = new StyleRange(length, line.length(), color, null);
                        if (severity == Severity.INFO) {
                            styleRange.fontStyle = SWT.BOLD;
                        }

                        logText.setStyleRange(styleRange);
                    }

                    if (!scrollLock) {
                        int lineCount = logText.getLineCount();
                        logText.setTopIndex(lineCount - 1);
                    }
                } catch (Exception ex) {
                    SetupUIPlugin.INSTANCE.log(ex);
                }
            }
        }

        private void logTaskName(String name) {
            SetupTaskPerformer performer = getPerformer();
            if (performer != null) {
                performer.log(name);
            }
        }
    }
}