org.rssowl.ui.internal.dialogs.UpdateDialog.java Source code

Java tutorial

Introduction

Here is the source code for org.rssowl.ui.internal.dialogs.UpdateDialog.java

Source

/*   **********************************************************************  **
 **   Copyright notice                                                       **
 **                                                                          **
 **   (c) 2005-2009 RSSOwl Development Team                                  **
 **   http://www.rssowl.org/                                                 **
 **                                                                          **
 **   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.rssowl.org/legal/epl-v10.html                               **
 **                                                                          **
 **   A copy is found in the file epl-v10.html and important notices to the  **
 **   license from the team is found in the textfile LICENSE.txt distributed **
 **   in this package.                                                       **
 **                                                                          **
 **   This copyright notice MUST APPEAR in all copies of the file!           **
 **                                                                          **
 **   Contributors:                                                          **
 **     RSSOwl Development Team - initial API and implementation             **
 **                                                                          **
 **  **********************************************************************  */

package org.rssowl.ui.internal.dialogs;

import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
import org.eclipse.jface.util.SafeRunnable;
import org.eclipse.osgi.service.datalocation.Location;
import org.eclipse.swt.SWT;
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.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.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.update.core.ICategory;
import org.eclipse.update.core.IFeature;
import org.eclipse.update.core.IURLEntry;
import org.eclipse.update.operations.IInstallFeatureOperation;
import org.rssowl.core.Owl;
import org.rssowl.core.internal.persist.pref.DefaultPreferences;
import org.rssowl.core.persist.pref.IPreferenceScope;
import org.rssowl.core.util.LoggingSafeRunnable;
import org.rssowl.core.util.StringUtils;
import org.rssowl.ui.internal.OwlUI;
import org.rssowl.ui.internal.util.BrowserUtils;
import org.rssowl.ui.internal.util.LayoutUtils;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * The <code>UpdateDialog</code> shows when updates are available and will show
 * a description of the update.
 *
 * @author bpasero
 */
public class UpdateDialog extends TitleAreaDialog {
    private static final String PLUGINS = "plugins"; //$NON-NLS-1$
    private static final String FEATURES = "features"; //$NON-NLS-1$

    private LocalResourceManager fResources;
    private final IInstallFeatureOperation[] fUpdates;
    private StyledText fUpdateInfoTextRight;
    private StyledText fUpdateInfoTextLeft;
    private StyledText fUpdateInfoTextBottom;
    private Button fUpdateOnStartupCheck;
    private IPreferenceScope fPreferences;
    private final boolean fCanUpdate;

    /**
     * @param parentShell
     * @param updates
     */
    public UpdateDialog(Shell parentShell, IInstallFeatureOperation[] updates) {
        super(parentShell);
        fResources = new LocalResourceManager(JFaceResources.getResources());
        fPreferences = Owl.getPreferenceService().getGlobalScope();
        fUpdates = updates;
        fCanUpdate = canUpdate();
    }

    /*
     * @see org.eclipse.jface.dialogs.TitleAreaDialog#close()
     */
    @Override
    public boolean close() {
        if (!fUpdateOnStartupCheck.isDisposed())
            fPreferences.putBoolean(DefaultPreferences.UPDATE_ON_STARTUP, fUpdateOnStartupCheck.getSelection());
        fResources.dispose();
        return super.close();
    }

    /*
     * @see org.eclipse.jface.dialogs.Dialog#okPressed()
     */
    @Override
    protected void okPressed() {

        /* Show an Extra Warning if Update will Fail due to missing write Permissions */
        if (!fCanUpdate) {
            MessageDialog dialog = new MessageDialog(getShell(), Messages.UpdateDialog_WARNING, null,
                    Messages.UpdateDialog_MISSING_PERMISSIONS_WARNING, MessageDialog.WARNING,
                    new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL }, 0);
            if (dialog.open() != 0)
                return;
        }

        super.okPressed();
    }

    /*
     * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell)
     */
    @Override
    protected void configureShell(Shell shell) {
        super.configureShell(shell);
        shell.setText(Messages.UpdateDialog_UPDATE_AVAILABLE);
    }

    /*
     * @see org.eclipse.jface.dialogs.TitleAreaDialog#createDialogArea(org.eclipse.swt.widgets.Composite)
     */
    @Override
    protected Control createDialogArea(Composite parent) {

        /* Title */
        setTitle(Messages.UpdateDialog_UPDATE_AVAILABLE);

        /* Title Image */
        setTitleImage(OwlUI.getImage(fResources, "icons/wizban/update_wiz.png")); //$NON-NLS-1$

        /* Title Message */
        setMessage(Messages.UpdateDialog_NEW_VERSION_MSG);

        /* Separator */
        new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL)
                .setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));

        /* Composite to hold all components */
        Composite composite = new Composite(parent, SWT.NONE);
        composite.setLayout(LayoutUtils.createGridLayout(1, 5, 5));
        composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

        Composite updateInfoContainer = new Composite(composite, SWT.BORDER);
        updateInfoContainer.setLayout(LayoutUtils.createGridLayout(2, 5, 5, 0, 5, false));
        updateInfoContainer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        updateInfoContainer.setBackground(composite.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));

        fUpdateInfoTextLeft = new StyledText(updateInfoContainer, SWT.READ_ONLY | SWT.MULTI | SWT.WRAP);
        fUpdateInfoTextLeft.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
        fUpdateInfoTextLeft.setLineSpacing(5);
        fUpdateInfoTextLeft.setEnabled(false);
        fUpdateInfoTextLeft.setBackground(composite.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));

        fUpdateInfoTextRight = new StyledText(updateInfoContainer, SWT.READ_ONLY | SWT.MULTI | SWT.WRAP);
        fUpdateInfoTextRight.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
        fUpdateInfoTextRight.setLineSpacing(5);
        fUpdateInfoTextRight.setEnabled(false);
        fUpdateInfoTextRight.setBackground(composite.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));

        fUpdateInfoTextBottom = new StyledText(updateInfoContainer, SWT.READ_ONLY | SWT.MULTI | SWT.WRAP);
        fUpdateInfoTextBottom.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
        ((GridData) fUpdateInfoTextBottom.getLayoutData()).widthHint = 300;
        fUpdateInfoTextBottom.setLineSpacing(5);
        fUpdateInfoTextBottom.setEnabled(false);
        fUpdateInfoTextBottom.setBackground(composite.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));

        /* Fill in Update Details */
        showUpdateDescription();

        /* Link to open RSSOwl.org */
        Link link = new Link(updateInfoContainer, SWT.NONE);
        link.setBackground(updateInfoContainer.getBackground());
        link.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 2, 1));
        link.setText(Messages.UpdateDialog_VISIT_HP);
        link.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                BrowserUtils.openLinkExternal("http://www.rssowl.org"); //$NON-NLS-1$
            }
        });

        /* Add Option to Control Checking for Updates Automatically */
        fUpdateOnStartupCheck = new Button(composite, SWT.CHECK);
        fUpdateOnStartupCheck.setText(Messages.UpdateDialog_UPDATE_ON_STARTUP);
        fUpdateOnStartupCheck.setSelection(fPreferences.getBoolean(DefaultPreferences.UPDATE_ON_STARTUP));

        /* Show Error if Update will Fail due to missing Write Permissions */
        if (!fCanUpdate)
            setErrorMessage(Messages.UpdateDialog_MISSING_PERMISSIONS_ERROR);

        /* Separator */
        new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL)
                .setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));

        applyDialogFont(composite);

        return composite;
    }

    /* Create a temporary file in the install location to check if write permissions are qualified */
    private boolean canUpdate() {
        final AtomicBoolean canUpdate = new AtomicBoolean(true);

        SafeRunnable.run(new LoggingSafeRunnable() {
            public void run() throws Exception {
                Location installLocation = Platform.getInstallLocation();
                if (installLocation != null && installLocation.getURL() != null) {
                    File installDirectory = toFile(installLocation.getURL());
                    if (!installDirectory.isFile()) {
                        File pluginsDir = new File(installDirectory, PLUGINS);
                        File featuresDir = new File(installDirectory, FEATURES);
                        if (pluginsDir.isDirectory() && featuresDir.isDirectory()) {
                            try {

                                /* Check Write Permission in Plugins Directory */
                                writeTempFile(canUpdate, pluginsDir);

                                /* Check Write Permission in Features Directory */
                                if (canUpdate.get())
                                    writeTempFile(canUpdate, featuresDir);
                            } catch (IOException e) {
                                canUpdate.set(false);
                            } catch (SecurityException e) {
                                canUpdate.set(false);
                            }
                        }
                    }
                }
            }

            private void writeTempFile(AtomicBoolean canUpdate, File dir) throws IOException {
                File tmpFile = File.createTempFile("permcheck", ".tmp", dir); //$NON-NLS-1$ //$NON-NLS-2$
                tmpFile.deleteOnExit();
                canUpdate.set(tmpFile.exists() && tmpFile.canWrite());
                tmpFile.delete();
            }
        });

        return canUpdate.get();
    }

    private static File toFile(URL url) {
        try {
            return new File(url.toURI());
        } catch (URISyntaxException e) {
            return new File(url.getPath());
        }
    }

    @SuppressWarnings("deprecation")
    private void showUpdateDescription() {
        String oldVer = null;
        String newVer = null;
        long dlSize = 0;
        String provider = null;
        String description = null;

        if (fUpdates != null && fUpdates.length > 0) {
            IFeature oldFeature = fUpdates[0].getOldFeature();
            IFeature newFeature = fUpdates[0].getFeature();

            /* Versions */
            org.eclipse.core.runtime.PluginVersionIdentifier oldVersion = (oldFeature != null)
                    ? oldFeature.getVersionedIdentifier().getVersion()
                    : null;
            org.eclipse.core.runtime.PluginVersionIdentifier newVersion = newFeature.getVersionedIdentifier()
                    .getVersion();
            if (oldVersion != null)
                oldVer = oldVersion.getMajorComponent() + "." + oldVersion.getMinorComponent() + "." //$NON-NLS-1$//$NON-NLS-2$
                        + oldVersion.getServiceComponent();
            newVer = newVersion.getMajorComponent() + "." + newVersion.getMinorComponent() + "." //$NON-NLS-1$//$NON-NLS-2$
                    + newVersion.getServiceComponent();

            /* Special Treat Case of a Qualifier Update */
            if (newVer.equals(oldVer) && oldVersion != null) {
                String newQualifierComponent = newVersion.getQualifierComponent();
                String oldQualifierComponent = oldVersion.getQualifierComponent();
                if (newQualifierComponent.length() == 12 && oldQualifierComponent.length() == 12) {
                    newVer += " (" + formatQualifier(newQualifierComponent) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
                    oldVer += " (" + formatQualifier(oldQualifierComponent) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
                } else {
                    newVer += "." + newQualifierComponent; //$NON-NLS-1$
                    oldVer += "." + oldQualifierComponent; //$NON-NLS-1$
                }
            }

            /* Other */
            dlSize = newFeature.getDownloadSize() * 1000;
            provider = newFeature.getProvider();

            /* Description (if present) */
            ICategory[] categories = newFeature.getSite().getCategories();
            if (categories.length > 0) {
                IURLEntry descriptionEntry = categories[0].getDescription();
                if (descriptionEntry != null)
                    description = descriptionEntry.getAnnotation();
            }

            if (!StringUtils.isSet(description))
                description = Messages.UpdateDialog_QUALIFIER_UPDATE_DESCRIPTION;

            showUpdateDescription(oldVer, newVer, dlSize, provider, description);
        }
    }

    private String formatQualifier(String qualifier) {
        if (qualifier.length() == 12)
            return qualifier.substring(0, 4) + "-" + qualifier.substring(4, 6) + "-" + qualifier.substring(6, 8); //$NON-NLS-1$ //$NON-NLS-2$

        return qualifier;
    }

    private void showUpdateDescription(String oldVer, String newVer, long dlSize, String provider,
            String description) {

        /* Old Version */
        if (StringUtils.isSet(oldVer)) {
            int offset = fUpdateInfoTextLeft.getText().length();
            fUpdateInfoTextLeft.append(Messages.UpdateDialog_CURRENT_VERSION);
            fUpdateInfoTextLeft.setStyleRange(
                    new StyleRange(offset, fUpdateInfoTextLeft.getText().length() - offset, null, null, SWT.BOLD));
            fUpdateInfoTextRight.append(oldVer);
            fUpdateInfoTextLeft.append("\n"); //$NON-NLS-1$
            fUpdateInfoTextRight.append("\n"); //$NON-NLS-1$
        }

        /* New Version */
        if (StringUtils.isSet(newVer)) {
            int offset = fUpdateInfoTextLeft.getText().length();
            fUpdateInfoTextLeft.append(Messages.UpdateDialog_NEW_VERSION);
            fUpdateInfoTextLeft.setStyleRange(
                    new StyleRange(offset, fUpdateInfoTextLeft.getText().length() - offset, null, null, SWT.BOLD));
            fUpdateInfoTextRight.append(newVer);
            fUpdateInfoTextLeft.append("\n"); //$NON-NLS-1$
            fUpdateInfoTextRight.append("\n"); //$NON-NLS-1$
        }

        /* Provider */
        if (StringUtils.isSet(provider)) {
            int offset = fUpdateInfoTextLeft.getText().length();
            fUpdateInfoTextLeft.append(Messages.UpdateDialog_UPDATE_PROVIDER);
            fUpdateInfoTextLeft.setStyleRange(
                    new StyleRange(offset, fUpdateInfoTextLeft.getText().length() - offset, null, null, SWT.BOLD));
            fUpdateInfoTextRight.append(provider);
            fUpdateInfoTextLeft.append("\n"); //$NON-NLS-1$
            fUpdateInfoTextRight.append("\n"); //$NON-NLS-1$
        }

        /* Size */
        if (dlSize > 0) {
            int offset = fUpdateInfoTextLeft.getText().length();
            fUpdateInfoTextLeft.append(Messages.UpdateDialog_DL_SIZE);
            fUpdateInfoTextLeft.setStyleRange(
                    new StyleRange(offset, fUpdateInfoTextLeft.getText().length() - offset, null, null, SWT.BOLD));
            fUpdateInfoTextRight.append(OwlUI.getSize((int) dlSize));
            fUpdateInfoTextLeft.append("\n"); //$NON-NLS-1$
            fUpdateInfoTextRight.append("\n"); //$NON-NLS-1$
        }

        /* Description */
        if (StringUtils.isSet(description)) {
            int offset = fUpdateInfoTextBottom.getText().length();
            fUpdateInfoTextBottom.append(Messages.UpdateDialog_DESCRIPTION);
            fUpdateInfoTextBottom.append("\n"); //$NON-NLS-1$
            fUpdateInfoTextBottom.setStyleRange(new StyleRange(offset,
                    fUpdateInfoTextBottom.getText().length() - offset, null, null, SWT.BOLD));
            fUpdateInfoTextBottom.append(description);
        }
    }

    /*
     * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite)
     */
    @Override
    protected void createButtonsForButtonBar(Composite parent) {
        createButton(parent, IDialogConstants.OK_ID, Messages.UpdateDialog_DOWNLOAD_INSTALL, true).setFocus();
        createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
    }

    /*
     * @see org.eclipse.jface.window.Window#getShellStyle()
     */
    @Override
    protected int getShellStyle() {
        int style = SWT.TITLE | SWT.BORDER | SWT.APPLICATION_MODAL | SWT.RESIZE | SWT.CLOSE
                | getDefaultOrientation();

        return style;
    }

    /*
     * @see org.eclipse.jface.dialogs.Dialog#initializeBounds()
     */
    @Override
    protected void initializeBounds() {
        super.initializeBounds();

        Shell shell = getShell();

        /* Minimum Size */
        int minWidth = convertHorizontalDLUsToPixels(OwlUI.MIN_DIALOG_WIDTH_DLU);
        int minHeight = shell.computeSize(minWidth, SWT.DEFAULT).y;

        /* Required Size */
        Point requiredSize = shell.computeSize(SWT.DEFAULT, SWT.DEFAULT);

        shell.setSize(Math.max(minWidth, requiredSize.x), Math.max(minHeight, requiredSize.y));
        LayoutUtils.positionShell(shell);
    }
}