com.codesourcery.internal.installer.ui.InstallWizard.java Source code

Java tutorial

Introduction

Here is the source code for com.codesourcery.internal.installer.ui.InstallWizard.java

Source

/*******************************************************************************
 *  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.internal.installer.ui;

import java.lang.reflect.InvocationTargetException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
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.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageLoader;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;

import com.codesourcery.installer.IInstallData;
import com.codesourcery.installer.IInstallManager;
import com.codesourcery.installer.IInstallProduct;
import com.codesourcery.installer.IInstallWizardPage;
import com.codesourcery.installer.Installer;
import com.codesourcery.installer.LaunchItem;
import com.codesourcery.installer.ui.InstallWizardPage;
import com.codesourcery.internal.installer.InstallData;
import com.codesourcery.internal.installer.InstallMessages;
import com.codesourcery.internal.installer.RepositoryManager;
import com.codesourcery.internal.installer.ui.pages.ProductsPage;
import com.codesourcery.internal.installer.ui.pages.ProgressPage;
import com.codesourcery.internal.installer.ui.pages.ResultsPage;
import com.codesourcery.internal.installer.ui.pages.AbstractSetupPage;
import com.codesourcery.internal.installer.ui.pages.SummaryPage;

/**
 * Install wizard
 * This wizard shows pages that implement <code>IInstallWizardPage</code>.
 */
public class InstallWizard extends Wizard {
    /**
     * Delay before displaying busy animation for long operations (ms)
     */
    private final static int BUSY_DELAY = 2000;
    /**
     * Summary page
     */
    private SummaryPage summaryPage;
    /**
     * Progress page
     */
    private ProgressPage progressPage;
    /**
     * Result page
     */
    private ResultsPage resultsPage;
    /**
     * <code>true</code> if installation complete
     */
    private boolean installed = false;
    /**
     * Products page
     */
    private ProductsPage productsPage;
    /**
     * Install data
     */
    private IInstallData installData;
    /**
     * Status of install operation.
     */
    private IStatus status;
    /**
     * Title image
     */
    private Image titleImage;

    /**
     * Constructor
     */
    public InstallWizard() {
        setNeedsProgressMonitor(true);
        // Set window title
        String title;
        if (isInstall()) {
            title = getInstallManager().getInstallDescription().getWindowTitle();
            if (title == null) {
                title = MessageFormat.format(InstallMessages.Title0,
                        getInstallManager().getInstallDescription().getProductName());
            }
        } else {
            title = InstallMessages.UninstallTitle;
        }
        setWindowTitle(title);

        // Load title image if available
        try {
            if (isInstall()) {
                IPath titleImagePath = getInstallManager().getInstallDescription().getTitleImage();
                if (titleImagePath != null) {
                    if (titleImagePath.toFile().exists()) {
                        ImageLoader imageLoader = new ImageLoader();
                        ImageData[] imageDatas = imageLoader.load(titleImagePath.toOSString());
                        if (imageDatas.length > 0) {
                            titleImage = new Image(Display.getDefault(), imageDatas[0]);
                        }
                    } else {
                        Installer.log("Missing title image file: " + titleImagePath.toOSString());
                    }
                }
            }
        } catch (Exception e) {
            Installer.log(e);
        }

        installData = new InstallData();
    }

    /**
     * Returns the install manager.
     * 
     * @return Install manager
     */
    protected IInstallManager getInstallManager() {
        return Installer.getDefault().getInstallManager();
    }

    /**
     * Returns the title image specified in the installer properties.
     * 
     * @return Title image or <code>null</code>
     */
    public Image getTitleImage() {
        return titleImage;
    }

    /**
     * Returns the install data.
     * 
     * @return Install data
     */
    public IInstallData getInstallData() {
        return installData;
    }

    /**
     * Returns if the wizard is for
     * an installation.
     * 
     * @return <code>true</code> if install
     * <code>false</code> if uninstall
     */
    public boolean isInstall() {
        return Installer.getDefault().getInstallManager().getInstallMode().isInstall();
    }

    /**
     * Returns if the wizard is for an upgrade.
     * @return <code>true</code> if upgrade
     */
    public boolean isUpgrade() {
        return Installer.getDefault().getInstallManager().getInstallMode().isUpgrade();
    }

    /**
     * Returns the status of the install operation.
     * 
     * @return Status
     */
    public IStatus getStatus() {
        return status;
    }

    @Override
    public boolean performCancel() {
        // Show cancel confirmation
        if (showCancelConfirmation()) {
            status = new Status(IStatus.CANCEL, Installer.ID, 0, "Cancelled", null);
            // Cleanup any install files
            try {
                if (isInstall())
                    Installer.getDefault().getInstallManager().setInstallLocation(null);
            } catch (CoreException e) {
                Installer.log(e);
            }

            return super.performCancel();
        } else {
            return false;
        }
    }

    /**
     * Shows a cancel confirmation dialog.
     * 
     * @return <code>true</code> to cancel
     */
    public boolean showCancelConfirmation() {
        // Confirmation message
        String confirmationMessage;
        if (isInstall()) {
            confirmationMessage = MessageFormat.format(InstallMessages.CancelInstallConfirmation2,
                    new Object[] {
                            Installer.getDefault().getInstallManager().getInstallDescription().getProductName(),
                            InstallMessages.Resume, InstallMessages.Quit });
        } else {
            confirmationMessage = MessageFormat.format(InstallMessages.CancelUninstallConfirmation1,
                    new Object[] { InstallMessages.Resume, InstallMessages.Quit });
        }
        // Confirm dialog
        MessageDialog confirmationDialog = new MessageDialog(getContainer().getShell(),
                InstallMessages.CancelSetupTitle, null, confirmationMessage, MessageDialog.QUESTION,
                new String[] { InstallMessages.Resume, InstallMessages.Quit }, 0);

        return (confirmationDialog.open() != 0);
    }

    @Override
    public boolean performFinish() {
        boolean complete = true;

        // First time - perform installation/uninstallation
        if (!installed) {
            complete = false;

            // Install
            if (isInstall()) {
                // Save page install data
                for (IInstallWizardPage page : getSupportedPages()) {
                    page.saveInstallData(getInstallData());
                }

                // Show the summary page and validate the installation
                if (summaryPage != null) {
                    getContainer().showPage(summaryPage);
                    // Installation not valid, don't proceed
                    if (!summaryPage.validate()) {
                        return false;
                    }
                }

                // Show installing page 
                getContainer().showPage(progressPage);

                status = install(getInstallData());
            }
            // Uninstall
            else {
                // Show uninstalling page 
                getContainer().showPage(progressPage);

                status = uninstall();
            }

            installed = true;

            // Set result
            if (resultsPage != null) {
                // Success
                if (status.isOK()) {
                    String message = isInstall()
                            ? NLS.bind(InstallMessages.InstallationComplete0,
                                    getInstallManager().getInstallDescription().getProductName())
                            : InstallMessages.UninstallationComplete;
                    resultsPage.setResult(message, true);
                }
                // Cancel
                else if (status.getSeverity() == IStatus.CANCEL) {
                    String message = isInstall()
                            ? NLS.bind(InstallMessages.InstallationCancelled0,
                                    getInstallManager().getInstallDescription().getProductName())
                            : InstallMessages.UninstallationCancelled;
                    resultsPage.setResult(message, false);
                }
                // Error
                else {
                    resultsPage.setError(getStatusMessage(status));
                }

                // Show install complete page
                getContainer().showPage(resultsPage);
            }
        }
        // Second time - installation has
        // been completed
        else {
            // Launch selected product items if no errors at end of installation
            if (isInstall() && (resultsPage != null) && !resultsPage.hasError()) {
                LaunchItem[] launchItems = getInstallManager().getInstallDescription().getLaunchItems();
                if (launchItems != null) {
                    for (LaunchItem launchItem : launchItems) {
                        try {
                            if (resultsPage.isItemChecked(launchItem)) {
                                getInstallManager().launch(launchItem);
                            }
                        } catch (Exception e) {
                            Installer.log(e);
                        }
                    }
                }
            }
        }

        return complete;
    }

    /**
     * Returns a status message.
     * 
     * @param status Status
     * @return Message
     */
    private String getStatusMessage(IStatus status) {
        StringBuilder message = new StringBuilder();
        if (status != null) {
            message.append(status.getMessage());
            IStatus[] children = status.getChildren();
            if (children != null) {
                for (IStatus child : children) {
                    message.append('\n');
                    message.append(child.getMessage());
                }
            }
            Throwable exception = status.getException();
            if (exception instanceof InvocationTargetException) {
                exception = ((InvocationTargetException) exception).getTargetException();
            }

            if (exception != null) {
                message.append('\n');
                message.append(exception.getLocalizedMessage());
            }
        }

        return message.toString();
    }

    /**
     * Performs the uninstallation.
     *
     * @return Status
     * @throws CoreException on failure
     */
    private IStatus uninstall() {
        Throwable error = null;
        final IStatus[] status = new IStatus[] { Status.OK_STATUS };

        final IInstallProduct[] products = productsPage.getSelectedProducts();

        // Install
        try {
            getContainer().run(true, true, new IRunnableWithProgress() {
                @Override
                public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
                    try {
                        // Remove products
                        getInstallManager().uninstall(products, monitor);

                        if (monitor.isCanceled())
                            status[0] = Status.CANCEL_STATUS;
                    } catch (Exception e) {
                        throw new InvocationTargetException(e);
                    }
                }
            });
        } catch (Exception e) {
            error = e;
        }

        // Install operation failed
        if (error != null) {
            status[0] = new Status(IStatus.ERROR, Installer.ID, 0, InstallMessages.UninstallationFailed, error);
        }

        return status[0];
    }

    /**
     * Performs the installation
     * 
     * @param data Install data
     * @return Status
     * @throws CoreException on failure
     */
    private IStatus install(IInstallData data) {
        final IStatus[] status = new IStatus[] { Status.OK_STATUS };
        try {
            // Install
            getContainer().run(true, true, new IRunnableWithProgress() {
                @Override
                public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
                    try {
                        getInstallManager().install(installData, monitor);

                        if (monitor.isCanceled()) {
                            status[0] = Status.CANCEL_STATUS;
                        }
                    } catch (CoreException e) {
                        Installer.log(e);
                        throw new InvocationTargetException(e);
                    }
                }
            });
        } catch (Exception e) {
            status[0] = new Status(IStatus.ERROR, Installer.ID, 0, "", e);
        }

        return status[0];
    }

    /**
     * Returns the progress page.
     * 
     * @return Progress page
     */
    public ProgressPage getProgressPage() {
        return progressPage;
    }

    /**
     * Sets up page navigation.
     */
    public void setupPageNavigation() {
        IWizardPage[] pages = getPages();
        for (IWizardPage page : pages) {
            if (page instanceof InstallWizardPage) {
                InstallWizardPage wizardPage = (InstallWizardPage) page;
                wizardPage.setupNavigation();
            }
        }
    }

    @Override
    public void addPages() {
        // Add install wizard pages from modules
        IInstallWizardPage[] installPages = getInstallManager().getWizardPages();
        for (IInstallWizardPage installPage : installPages) {
            addPage(installPage);
        }

        // Install summary page
        summaryPage = new SummaryPage("summaryPage", InstallMessages.SummaryPageTitle);
        addPage(summaryPage);

        // Uninstall products page
        productsPage = new ProductsPage("productsPage", InstallMessages.ProductsPageTitle,
                InstallMessages.ProductsMessage);
        productsPage.setMessage(InstallMessages.SelectProductsToUninstall);
        addPage(productsPage);

        // Progress page
        progressPage = new ProgressPage("progressPage");
        addPage(progressPage);

        // Results page
        resultsPage = new ResultsPage("resultsPage", InstallMessages.ResultsPageTitle);
        addPage(resultsPage);
    }

    @Override
    public void createPageControls(Composite pageContainer) {
        super.createPageControls(pageContainer);

        // Initialize the wizard pages navigation unless the Setup page is
        // present as it will do it.
        if ((getPageCount() > 0) && !(getPages()[0] instanceof AbstractSetupPage)) {
            setupPageNavigation();
        }
    }

    /**
     * Returns is a page is currently supported.
     * 
     * @param page Page
     * @return <code>true</code> if page is supported
     */
    private boolean isPageSupported(IWizardPage page) {
        boolean supported = true;
        if (page instanceof IInstallWizardPage) {
            supported = ((IInstallWizardPage) page).isSupported();
        }

        return supported;
    }

    @Override
    public IWizardPage getStartingPage() {
        IWizardPage startPage = null;
        IWizardPage[] pages = getPages();
        for (IWizardPage page : pages) {
            if (isPageSupported(page)) {
                startPage = page;
                break;
            }
        }
        if (startPage instanceof IInstallWizardPage) {
            ((IInstallWizardPage) startPage).setActive(getInstallData());
        }

        return startPage;
    }

    @Override
    public IWizardPage getNextPage(IWizardPage page) {
        IWizardPage nextPage = super.getNextPage(page);
        // If page is not supported, get next supported page
        while (!isPageSupported(nextPage)) {
            nextPage = super.getNextPage(nextPage);
        }

        return nextPage;
    }

    /**
     * Runs a long operation and shows a wizard page as busy.
     * 
     * @param wizardPage Wizard page
     * @param message Busy message
     * @param runnable Runnable to execute
     */
    public void runOperation(InstallWizardPage wizardPage, String message, Runnable runnable) {
        // Run job
        OperationJob job = new OperationJob(wizardPage, message, runnable);
        job.schedule();

        // Dispatch UI events until job is complete
        Display display = getShell().getDisplay();
        while ((getShell() != null) && !getShell().isDisposed()) {
            if (!display.readAndDispatch())
                display.sleep();
            if (job.isDone())
                break;
        }
    }

    /**
     * Job to perform long running operation.
     */
    private class OperationJob extends Job {
        /** Wizard page */
        private InstallWizardPage installPage;
        /** Operation to perform */
        private Runnable runnable;
        /** Busy message */
        private String message;
        /** <code>true</code> if operation is complete */
        private boolean done = false;

        /**
         * Constructor
         * 
         * @param installPage Install wizard page
         * @param message Busy message
         * @param runnable Operation to perform
         */
        public OperationJob(InstallWizardPage installPage, String message, Runnable runnable) {
            super("Page Operation Job");
            this.installPage = installPage;
            this.message = message;
            this.runnable = runnable;
            setSystem(true);
        }

        /**
         * Returns if the operation is complete.
         * 
         * @return <code>true</code> if operation is complete
         */
        public boolean isDone() {
            return done;
        }

        @Override
        protected IStatus run(IProgressMonitor monitor) {
            try {
                // Disable buttons
                getShell().getDisplay().syncExec(new Runnable() {
                    @Override
                    public void run() {
                        ((InstallWizardDialog) getContainer()).setButtonsEnabled(false);
                    }
                });
                // Show busy animation if operation takes too long
                Timer busyTimer = new Timer();
                busyTimer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        // Show page busy
                        getShell().getDisplay().syncExec(new Runnable() {
                            @Override
                            public void run() {
                                if (!installPage.isBusy()) {
                                    installPage.showBusy(message);
                                }
                            }
                        });
                    }
                }, BUSY_DELAY);

                // Run operation
                runnable.run();
                busyTimer.cancel();
                done = true;

                // Hide page busy
                getShell().getDisplay().syncExec(new Runnable() {
                    @Override
                    public void run() {
                        installPage.hideBusy();
                        ((InstallWizardDialog) getContainer()).setButtonsEnabled(true);
                    }
                });
            } catch (Exception e) {
                Installer.log(e);
            }
            return Status.OK_STATUS;
        }
    }

    /**
     * Returns all wizard pages that are currently supported.
     * 
     * @return Supported wizard pages
     */
    public IInstallWizardPage[] getSupportedPages() {
        ArrayList<IInstallWizardPage> supportedPages = new ArrayList<IInstallWizardPage>();
        IWizardPage[] pages = getPages();
        for (IWizardPage page : pages) {
            if (page instanceof IInstallWizardPage) {
                IInstallWizardPage wizardPage = (IInstallWizardPage) page;
                if (wizardPage.isSupported()) {
                    supportedPages.add(wizardPage);
                }
            }
        }

        return supportedPages.toArray(new IInstallWizardPage[supportedPages.size()]);
    }

    @Override
    public boolean canFinish() {
        // Check if all pages report can finish
        boolean finish = true;
        for (IInstallWizardPage page : getSupportedPages()) {
            if (!page.isPageComplete()) {
                finish = false;
                break;
            }
        }

        if (finish && isInstall()) {
            // Allow install only if there is an install plan
            finish = RepositoryManager.getDefault().hasInstallUnits();
        }

        return finish;
    }
}