org.eclipse.equinox.p2.ui.AcceptLicensesWizardPage.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.equinox.p2.ui.AcceptLicensesWizardPage.java

Source

/*******************************************************************************
 * Copyright (c) 2007, 2011 IBM Corporation 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:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.equinox.p2.ui;

import java.util.*;
import java.util.List;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.equinox.internal.p2.metadata.License;
import org.eclipse.equinox.internal.p2.ui.ProvUIActivator;
import org.eclipse.equinox.internal.p2.ui.ProvUIMessages;
import org.eclipse.equinox.internal.p2.ui.dialogs.ILayoutConstants;
import org.eclipse.equinox.internal.p2.ui.viewers.IUColumnConfig;
import org.eclipse.equinox.p2.engine.IProvisioningPlan;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.ILicense;
import org.eclipse.equinox.p2.operations.*;
import org.eclipse.equinox.p2.query.QueryUtil;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.viewers.*;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;

/**
 * AcceptLicensesWizardPage shows a list of the IU's that have
 * licenses that have not been approved by the user, and allows the
 * user to approve them.
 * 
 * @since 2.0
 * @noextend This class is not intended to be subclassed by clients.
 */
public class AcceptLicensesWizardPage extends WizardPage {
    private static final String DIALOG_SETTINGS_SECTION = "LicensessPage"; //$NON-NLS-1$
    private static final String LIST_WEIGHT = "ListSashWeight"; //$NON-NLS-1$
    private static final String LICENSE_WEIGHT = "LicenseSashWeight"; //$NON-NLS-1$
    private static final String NAME_COLUMN_WIDTH = "NameColumnWidth"; //$NON-NLS-1$
    private static final String VERSION_COLUMN_WIDTH = "VersionColumnWidth"; //$NON-NLS-1$

    class IUWithLicenseParent {
        IInstallableUnit iu;
        ILicense license;

        IUWithLicenseParent(ILicense license, IInstallableUnit iu) {
            this.license = license;
            this.iu = iu;
        }
    }

    class LicenseContentProvider implements ITreeContentProvider {
        public Object[] getChildren(Object parentElement) {
            if (!(parentElement instanceof ILicense))
                return new Object[0];

            if (licensesToIUs.containsKey(parentElement)) {
                List<IInstallableUnit> iusWithLicense = licensesToIUs.get(parentElement);
                IInstallableUnit[] ius = iusWithLicense.toArray(new IInstallableUnit[iusWithLicense.size()]);
                IUWithLicenseParent[] children = new IUWithLicenseParent[ius.length];
                for (int i = 0; i < ius.length; i++) {
                    children[i] = new IUWithLicenseParent((ILicense) parentElement, ius[i]);
                }
                return children;
            }
            return null;
        }

        public Object getParent(Object element) {
            if (element instanceof IUWithLicenseParent) {
                return ((IUWithLicenseParent) element).license;
            }
            return null;
        }

        public boolean hasChildren(Object element) {
            return licensesToIUs.containsKey(element);
        }

        public Object[] getElements(Object inputElement) {
            return licensesToIUs.keySet().toArray();
        }

        public void dispose() {
            // Nothing to do
        }

        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
            // Nothing to do
        }
    }

    class LicenseLabelProvider extends LabelProvider {
        public Image getImage(Object element) {
            return null;
        }

        public String getText(Object element) {
            if (element instanceof License) {
                return getFirstLine(((License) element).getBody());
            } else if (element instanceof IUWithLicenseParent) {
                return getIUName(((IUWithLicenseParent) element).iu);
            } else if (element instanceof IInstallableUnit) {
                return getIUName((IInstallableUnit) element);
            }
            return ""; //$NON-NLS-1$
        }

        private String getFirstLine(String body) {
            int i = body.indexOf('\n');
            int j = body.indexOf('\r');
            if (i > 0) {
                if (j > 0)
                    return body.substring(0, i < j ? i : j);
                return body.substring(0, i);
            } else if (j > 0) {
                return body.substring(0, j);
            }
            return body;
        }
    }

    TreeViewer iuViewer;
    Text licenseTextBox;
    Button acceptButton;
    Button declineButton;
    SashForm sashForm;
    private IInstallableUnit[] originalIUs;
    HashMap<ILicense, List<IInstallableUnit>> licensesToIUs; // License -> IU Name
    private LicenseManager manager;
    IUColumnConfig nameColumn;
    IUColumnConfig versionColumn;

    static String getIUName(IInstallableUnit iu) {
        StringBuffer buf = new StringBuffer();
        String name = iu.getProperty(IInstallableUnit.PROP_NAME, null);
        if (name != null)
            buf.append(name);
        else
            buf.append(iu.getId());
        buf.append(" "); //$NON-NLS-1$
        buf.append(iu.getVersion().toString());
        return buf.toString();
    }

    /**
     * Create a license acceptance page for showing licenses to the user.
     * 
     * @param manager the license manager that should be used to check for already accepted licenses.  May be <code>null</code>.
     * @param ius the IInstallableUnits for which licenses should be checked
     * @param operation the provisioning operation describing what changes are to take place on the profile
     */
    public AcceptLicensesWizardPage(LicenseManager manager, IInstallableUnit[] ius,
            ProfileChangeOperation operation) {
        super("AcceptLicenses"); //$NON-NLS-1$
        setTitle(ProvUIMessages.AcceptLicensesWizardPage_Title);
        this.manager = manager;
        update(ius, operation);
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
     */
    public void createControl(Composite parent) {
        initializeDialogUnits(parent);
        List<IInstallableUnit> ius;
        if (licensesToIUs == null || licensesToIUs.size() == 0) {
            Label label = new Label(parent, SWT.NONE);
            setControl(label);
        } else if (licensesToIUs.size() == 1 && (ius = licensesToIUs.values().iterator().next()).size() == 1) {
            createLicenseContentSection(parent, ius.get(0));
        } else {
            sashForm = new SashForm(parent, SWT.HORIZONTAL);
            sashForm.setLayout(new GridLayout());
            GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
            sashForm.setLayoutData(gd);

            createLicenseListSection(sashForm);
            createLicenseContentSection(sashForm, null);
            sashForm.setWeights(getSashWeights());
            setControl(sashForm);
        }
        Dialog.applyDialogFont(getControl());
    }

    private void createLicenseListSection(Composite parent) {
        Composite composite = new Composite(parent, SWT.NONE);
        GridLayout layout = new GridLayout();
        layout.marginWidth = 0;
        layout.marginHeight = 0;
        composite.setLayout(layout);
        GridData gd = new GridData(GridData.FILL_BOTH);
        composite.setLayoutData(gd);

        Label label = new Label(composite, SWT.NONE);
        label.setText(ProvUIMessages.AcceptLicensesWizardPage_ItemsLabel);
        iuViewer = new TreeViewer(composite, SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
        iuViewer.setContentProvider(new LicenseContentProvider());
        iuViewer.setLabelProvider(new LicenseLabelProvider());
        iuViewer.setComparator(new ViewerComparator());
        iuViewer.setInput(licensesToIUs);

        iuViewer.addSelectionChangedListener(new ISelectionChangedListener() {
            public void selectionChanged(SelectionChangedEvent event) {
                handleSelectionChanged((IStructuredSelection) event.getSelection());
            }

        });
        gd = new GridData(GridData.FILL_BOTH);
        gd.widthHint = convertWidthInCharsToPixels(ILayoutConstants.DEFAULT_PRIMARY_COLUMN_WIDTH);
        gd.heightHint = convertHeightInCharsToPixels(ILayoutConstants.DEFAULT_TABLE_HEIGHT);
        iuViewer.getControl().setLayoutData(gd);
    }

    private void createLicenseAcceptSection(Composite parent, boolean multiple) {
        // Buttons for accepting licenses
        Composite buttonContainer = new Composite(parent, SWT.NULL);
        GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
        buttonContainer.setLayout(new GridLayout());
        buttonContainer.setLayoutData(gd);

        acceptButton = new Button(buttonContainer, SWT.RADIO);
        if (multiple)
            acceptButton.setText(ProvUIMessages.AcceptLicensesWizardPage_AcceptMultiple);
        else
            acceptButton.setText(ProvUIMessages.AcceptLicensesWizardPage_AcceptSingle);

        acceptButton.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                setPageComplete(acceptButton.getSelection());
            }
        });
        declineButton = new Button(buttonContainer, SWT.RADIO);
        if (multiple)
            declineButton.setText(ProvUIMessages.AcceptLicensesWizardPage_RejectMultiple);
        else
            declineButton.setText(ProvUIMessages.AcceptLicensesWizardPage_RejectSingle);
        declineButton.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                setPageComplete(!declineButton.getSelection());
            }
        });

        acceptButton.setSelection(false);
        declineButton.setSelection(true);
    }

    private void createLicenseContentSection(Composite parent, IInstallableUnit singleIU) {
        Composite composite = new Composite(parent, SWT.NONE);
        GridLayout layout = new GridLayout();
        layout.marginWidth = 0;
        layout.marginHeight = 0;
        composite.setLayout(layout);
        GridData gd = new GridData(GridData.FILL_BOTH);
        composite.setLayoutData(gd);

        Label label = new Label(composite, SWT.NONE);
        if (singleIU == null)
            label.setText(ProvUIMessages.AcceptLicensesWizardPage_LicenseTextLabel);
        else
            label.setText(
                    NLS.bind(ProvUIMessages.AcceptLicensesWizardPage_SingleLicenseTextLabel, getIUName(singleIU)));
        licenseTextBox = new Text(composite, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.WRAP | SWT.READ_ONLY);
        licenseTextBox.setBackground(licenseTextBox.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
        initializeDialogUnits(licenseTextBox);
        gd = new GridData(SWT.FILL, SWT.FILL, true, true);
        gd.heightHint = convertHeightInCharsToPixels(ILayoutConstants.DEFAULT_TABLE_HEIGHT);
        gd.widthHint = convertWidthInCharsToPixels(ILayoutConstants.DEFAULT_COLUMN_WIDTH);
        licenseTextBox.setLayoutData(gd);

        createLicenseAcceptSection(composite, licensesToIUs.size() > 1);

        if (singleIU != null) {
            String licenseBody = ""; //$NON-NLS-1$
            // We've already established before calling this method that it's a single IU with a single license
            Iterator<ILicense> licenses = singleIU.getLicenses(null).iterator();
            ILicense license = licenses.hasNext() ? licenses.next() : null;
            if (license != null && license.getBody() != null) {
                licenseBody = license.getBody();
            }
            licenseTextBox.setText(licenseBody);
        }
        setControl(composite);
    }

    void handleSelectionChanged(IStructuredSelection selection) {
        if (!selection.isEmpty()) {
            Object selected = selection.getFirstElement();
            if (selected instanceof License)
                licenseTextBox.setText(((License) selected).getBody());
            else if (selected instanceof IUWithLicenseParent)
                licenseTextBox.setText(((IUWithLicenseParent) selected).license.getBody());
        }
    }

    /**
     * The wizard is finishing.  Perform any necessary processing.
     * 
     * @return <code>true</code> if the finish can proceed, 
     * <code>false</code> if it should not.
     */
    public boolean performFinish() {
        rememberAcceptedLicenses();
        return true;
    }

    /**
     * Return a boolean indicating whether there are licenses that must be accepted
     * by the user.
     * 
     * @return <code>true</code> if there are licenses that must be accepted, and
     * <code>false</code> if there are no licenses that must be accepted.
     */
    public boolean hasLicensesToAccept() {
        return licensesToIUs != null && licensesToIUs.size() > 0;
    }

    /**
     * Update the current page to show the licenses that must be approved for the
     * selected IUs and the provisioning plan.  
     * 
     * Clients using this page in conjunction with a {@link ProfileChangeOperation} should
     * instead use {@link #update(IInstallableUnit[], ProfileChangeOperation)}.   This 
     * method is intended for clients who are working with a low-level provisioning plan
     * rather than an {@link InstallOperation} or {@link UpdateOperation}.
     * 
     * @param theIUs the installable units to be installed for which licenses must be checked
     * @param plan the provisioning plan that describes a resolved install operation
     * 
     * @see #update(IInstallableUnit[], ProfileChangeOperation)
     */

    public void updateForPlan(IInstallableUnit[] theIUs, IProvisioningPlan plan) {
        updateLicenses(theIUs, plan);
    }

    private void updateLicenses(IInstallableUnit[] theIUs, IProvisioningPlan plan) {
        this.originalIUs = theIUs;
        if (theIUs == null)
            licensesToIUs = new HashMap<ILicense, List<IInstallableUnit>>();
        else
            findUnacceptedLicenses(theIUs, plan);
        setDescription();
        setPageComplete(licensesToIUs.size() == 0);
        if (getControl() != null) {
            Composite parent = getControl().getParent();
            getControl().dispose();
            iuViewer = null;
            sashForm = null;
            createControl(parent);
            parent.layout(true);
        }
    }

    /**
     * Update the page for the specified IInstallableUnits and operation.
     * 
     * @param theIUs the IInstallableUnits for which licenses should be checked
     * @param operation the operation describing the pending profile change
     */
    public void update(IInstallableUnit[] theIUs, ProfileChangeOperation operation) {
        if (operation != null && operation.hasResolved()) {
            int sev = operation.getResolutionResult().getSeverity();
            if (sev != IStatus.ERROR && sev != IStatus.CANCEL) {
                updateLicenses(theIUs, operation.getProvisioningPlan());
            } else {
                updateLicenses(new IInstallableUnit[0], null);
            }
        }
    }

    private void findUnacceptedLicenses(IInstallableUnit[] selectedIUs, IProvisioningPlan plan) {
        IInstallableUnit[] iusToCheck = selectedIUs;
        if (plan != null) {
            iusToCheck = plan.getAdditions().query(QueryUtil.createIUAnyQuery(), null)
                    .toArray(IInstallableUnit.class);
        }

        // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=218532
        // Current metadata generation can result with a feature group IU and the feature jar IU
        // having the same name and license.  We will weed out duplicates if the license and name are both
        // the same.  
        licensesToIUs = new HashMap<ILicense, List<IInstallableUnit>>();//map of License->ArrayList of IUs with that license
        HashMap<ILicense, HashSet<String>> namesSeen = new HashMap<ILicense, HashSet<String>>(); // map of License->HashSet of names with that license
        for (int i = 0; i < iusToCheck.length; i++) {
            IInstallableUnit iu = iusToCheck[i];
            for (ILicense license : iu.getLicenses(null)) {
                if (manager != null && !manager.isAccepted(license)) {
                    String name = iu.getProperty(IInstallableUnit.PROP_NAME, null);
                    if (name == null)
                        name = iu.getId();
                    // Have we already found this license?  
                    if (licensesToIUs.containsKey(license)) {
                        HashSet<String> names = namesSeen.get(license);
                        if (!names.contains(name)) {
                            names.add(name);
                            ((ArrayList<IInstallableUnit>) licensesToIUs.get(license)).add(iu);
                        }
                    } else {
                        ArrayList<IInstallableUnit> list = new ArrayList<IInstallableUnit>(1);
                        list.add(iu);
                        licensesToIUs.put(license, list);
                        HashSet<String> names = new HashSet<String>(1);
                        names.add(name);
                        namesSeen.put(license, names);
                    }
                }
            }
        }
    }

    private void rememberAcceptedLicenses() {
        if (licensesToIUs == null || manager == null)
            return;
        for (ILicense license : licensesToIUs.keySet())
            manager.accept(license);
    }

    private void setDescription() {
        // No licenses but the page is open.  Shouldn't happen, but just in case...
        if (licensesToIUs == null || licensesToIUs.size() == 0)
            setDescription(ProvUIMessages.AcceptLicensesWizardPage_NoLicensesDescription);
        // We have licenses.  Use a generic message if we think we aren't showing extra
        // licenses from required IU's.  This check is not entirely accurate, for example
        // one root IU could have no license and the next one has two different
        // IU's with different licenses.  But this cheaply catches the common cases.
        else if (licensesToIUs.size() <= originalIUs.length)
            setDescription(ProvUIMessages.AcceptLicensesWizardPage_ReviewLicensesDescription);
        else {
            // Without a doubt we know we are showing extra licenses.
            setDescription(ProvUIMessages.AcceptLicensesWizardPage_ReviewExtraLicensesDescription);
        }
    }

    private String getDialogSettingsName() {
        return getWizard().getClass().getName() + "." + DIALOG_SETTINGS_SECTION; //$NON-NLS-1$
    }

    /**
     * Save any settings related to the current size and location of the wizard page.
     */
    public void saveBoundsRelatedSettings() {
        if (iuViewer == null || iuViewer.getTree().isDisposed())
            return;
        IDialogSettings settings = ProvUIActivator.getDefault().getDialogSettings();
        IDialogSettings section = settings.getSection(getDialogSettingsName());
        if (section == null) {
            section = settings.addNewSection(getDialogSettingsName());
        }
        section.put(NAME_COLUMN_WIDTH, iuViewer.getTree().getColumn(0).getWidth());
        section.put(VERSION_COLUMN_WIDTH, iuViewer.getTree().getColumn(1).getWidth());

        if (sashForm == null || sashForm.isDisposed())
            return;
        int[] weights = sashForm.getWeights();
        section.put(LIST_WEIGHT, weights[0]);
        section.put(LICENSE_WEIGHT, weights[1]);
    }

    private int[] getSashWeights() {
        IDialogSettings settings = ProvUIActivator.getDefault().getDialogSettings();
        IDialogSettings section = settings.getSection(getDialogSettingsName());
        if (section != null) {
            try {
                int[] weights = new int[2];
                if (section.get(LIST_WEIGHT) != null) {
                    weights[0] = section.getInt(LIST_WEIGHT);
                    if (section.get(LICENSE_WEIGHT) != null) {
                        weights[1] = section.getInt(LICENSE_WEIGHT);
                        return weights;
                    }
                }
            } catch (NumberFormatException e) {
                // Ignore if there actually was a value that didn't parse.  
            }
        }
        return new int[] { 55, 45 };
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.jface.dialogs.IDialogPage#setVisible(boolean)
     */
    public void setVisible(boolean visible) {
        super.setVisible(visible);
        if (visible && hasLicensesToAccept() && iuViewer != null) {
            iuViewer.setSelection(new StructuredSelection(iuViewer.getTree().getItem(0).getData()), true);
        }
    }
}