org.eclipse.ui.dialogs.WorkingSetConfigurationBlock.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.ui.dialogs.WorkingSetConfigurationBlock.java

Source

/*******************************************************************************
 * Copyright (c) 2007, 2009 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
 *     Remy Chi Jian Suen <remy.suen@gmail.com> - bug 201661
 *******************************************************************************/
package org.eclipse.ui.dialogs;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;

import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.IWorkingSet;
import org.eclipse.ui.IWorkingSetManager;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.WorkbenchMessages;
import org.eclipse.ui.internal.dialogs.SimpleWorkingSetSelectionDialog;

import com.ibm.icu.text.Collator;

/**
 * Instances of this class provide a reusable composite with controls that allow
 * the selection of working sets. This class is most useful in
 * {@link IWizardPage} instances that wish to create resources and pre-install
 * them into particular working sets.
 *
 * @since 3.4
 * 
 */
public class WorkingSetConfigurationBlock {

    /**
     * Filters the given working sets such that the following is true: for each
     * IWorkingSet s in result: s.getId() is element of workingSetIds
     * 
     * @param workingSets
     *            the array to filter
     * @param workingSetIds
     *            the acceptable working set ids
     * @return the filtered elements
     */
    public static IWorkingSet[] filter(IWorkingSet[] workingSets, String[] workingSetIds) {

        // create a copy so we can sort the array without mucking it up for clients.
        String[] workingSetIdsCopy = new String[workingSetIds.length];
        System.arraycopy(workingSetIds, 0, workingSetIdsCopy, 0, workingSetIds.length);
        Arrays.sort(workingSetIdsCopy);

        ArrayList result = new ArrayList();

        for (int i = 0; i < workingSets.length; i++) {
            if (Arrays.binarySearch(workingSetIdsCopy, workingSets[i].getId()) >= 0)
                result.add(workingSets[i]);
        }

        return (IWorkingSet[]) result.toArray(new IWorkingSet[result.size()]);
    }

    /**
     * Empty working set array constant.
     */
    private static final IWorkingSet[] EMPTY_WORKING_SET_ARRAY = new IWorkingSet[0];

    private static final String WORKINGSET_SELECTION_HISTORY = "workingset_selection_history"; //$NON-NLS-1$
    private static final int MAX_HISTORY_SIZE = 5;

    private Label workingSetLabel;
    private Combo workingSetCombo;
    private Button selectButton;
    private Button enableButton;

    private IWorkingSet[] selectedWorkingSets;
    private ArrayList selectionHistory;
    private final IDialogSettings dialogSettings;
    private final String[] workingSetTypeIds;

    private final String selectLabel;

    private final String comboLabel;

    private final String addButtonLabel;

    /**
     * Create a new instance of this working set block using default labels.
     * 
     * @param workingSetIds
     *            working set ids from which the user can choose
     * @param settings
     *            to store/load the selection history
     */
    public WorkingSetConfigurationBlock(String[] workingSetIds, IDialogSettings settings) {
        this(workingSetIds, settings, null, null, null);
    }

    /**
     * Create a new instance of this working set block using custom labels.
     * 
     * @param workingSetIds
     *            working set ids from which the user can choose
     * @param settings
     *            to store/load the selection history
     * @param addButtonLabel
     *            the label to use for the checkable enablement button. May be
     *            <code>null</code> to use the default value.
     * @param comboLabel
     *            the label to use for the recent working set combo. May be
     *            <code>null</code> to use the default value.
     * @param selectLabel
     *            the label to use for the select button. May be
     *            <code>null</code> to use the default value.
     */
    public WorkingSetConfigurationBlock(String[] workingSetIds, IDialogSettings settings, String addButtonLabel,
            String comboLabel, String selectLabel) {
        Assert.isNotNull(workingSetIds);
        Assert.isNotNull(settings);

        workingSetTypeIds = workingSetIds;
        Arrays.sort(workingSetIds); // we'll be performing some searches with these later - presort them
        selectedWorkingSets = EMPTY_WORKING_SET_ARRAY;
        dialogSettings = settings;
        selectionHistory = loadSelectionHistory(settings, workingSetIds);

        this.addButtonLabel = addButtonLabel == null ? WorkbenchMessages.WorkingSetGroup_EnableWorkingSet_button
                : addButtonLabel;
        this.comboLabel = comboLabel == null ? WorkbenchMessages.WorkingSetConfigurationBlock_WorkingSetText_name
                : comboLabel;
        this.selectLabel = selectLabel == null
                ? WorkbenchMessages.WorkingSetConfigurationBlock_SelectWorkingSet_button
                : selectLabel;
    }

    /**
     * Set the current selection in the workbench.
     * 
     * @param selection
     *            the selection to present in the UI or <b>null</b>
     * @deprecated use
     *             {@link #setWorkingSets(IWorkingSet[])} and {@link #findApplicableWorkingSets(IStructuredSelection)}
     *             instead.
     */
    public void setSelection(IStructuredSelection selection) {
        selectedWorkingSets = findApplicableWorkingSets(selection);

        if (workingSetCombo != null)
            updateSelectedWorkingSets();
    }

    /**
     * Set the current selection of working sets. This array will be filtered to
     * contain only working sets that are applicable to this instance.
     * 
     * @param workingSets
     *            the working sets
     */
    public void setWorkingSets(IWorkingSet[] workingSets) {
        selectedWorkingSets = filterWorkingSets(Arrays.asList(workingSets));
        if (workingSetCombo != null)
            updateSelectedWorkingSets();
    }

    /**
     * Retrieves a working set from the given <code>selection</code> or an
     * empty array if no working set could be retrieved. This selection is
     * filtered based on the criteria used to construct this instance.
     * 
     * @param selection
     *            the selection to retrieve the working set from
     * @return the selected working set or an empty array
     */
    public IWorkingSet[] findApplicableWorkingSets(IStructuredSelection selection) {
        if (selection == null)
            return EMPTY_WORKING_SET_ARRAY;

        return filterWorkingSets(selection.toList());
    }

    /**
     * Prune a list of working sets such that they all match the criteria set
     * out by this block.
     * 
     * @param elements
     *            the elements to filter
     * @return the filtered elements
     */
    private IWorkingSet[] filterWorkingSets(Collection elements) {
        ArrayList result = new ArrayList();
        for (Iterator iterator = elements.iterator(); iterator.hasNext();) {
            Object element = iterator.next();
            if (element instanceof IWorkingSet && verifyWorkingSet((IWorkingSet) element)) {
                result.add(element);
            }
        }
        return (IWorkingSet[]) result.toArray(new IWorkingSet[result.size()]);
    }

    /**
     * Verifies that the given working set is suitable for selection in this
     * block.
     * 
     * @param workingSetCandidate
     *            the candidate to test
     * @return whether it is suitable
     */
    private boolean verifyWorkingSet(IWorkingSet workingSetCandidate) {
        return !workingSetCandidate.isAggregateWorkingSet()
                && Arrays.binarySearch(workingSetTypeIds, workingSetCandidate.getId()) >= 0;
    }

    /**
     * Return the currently selected working sets. If the controls representing
     * this block are disabled this array will be empty regardless of the
     * currently selected values.
     * 
     * @return the selected working sets
     */
    public IWorkingSet[] getSelectedWorkingSets() {
        if (enableButton.getSelection()) {
            return selectedWorkingSets;
        }
        return EMPTY_WORKING_SET_ARRAY;
    }

    /**
     * Add this block to the <code>parent</parent>
     * 
     * @param parent the parent to add the block to
     */
    public void createContent(final Composite parent) {
        int numColumn = 3;

        Composite composite = new Composite(parent, SWT.NONE);
        composite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
        composite.setLayout(new GridLayout(numColumn, false));

        enableButton = new Button(composite, SWT.CHECK);
        enableButton.setText(addButtonLabel);
        GridData enableData = new GridData(SWT.FILL, SWT.CENTER, true, false);
        enableData.horizontalSpan = numColumn;
        enableButton.setLayoutData(enableData);
        enableButton.setSelection(selectedWorkingSets.length > 0);

        workingSetLabel = new Label(composite, SWT.NONE);
        workingSetLabel.setText(comboLabel);

        workingSetCombo = new Combo(composite, SWT.READ_ONLY | SWT.BORDER);
        GridData textData = new GridData(SWT.FILL, SWT.CENTER, true, false);
        textData.horizontalSpan = numColumn - 2;
        textData.horizontalIndent = 0;
        workingSetCombo.setLayoutData(textData);

        selectButton = new Button(composite, SWT.PUSH);
        selectButton.setText(selectLabel);
        setButtonLayoutData(selectButton);
        selectButton.addSelectionListener(new SelectionAdapter() {

            public void widgetSelected(SelectionEvent e) {
                SimpleWorkingSetSelectionDialog dialog = new SimpleWorkingSetSelectionDialog(parent.getShell(),
                        workingSetTypeIds, selectedWorkingSets, false);
                dialog.setMessage(WorkbenchMessages.WorkingSetGroup_WorkingSetSelection_message);

                if (dialog.open() == Window.OK) {
                    IWorkingSet[] result = dialog.getSelection();
                    if (result != null && result.length > 0) {
                        selectedWorkingSets = result;
                        PlatformUI.getWorkbench().getWorkingSetManager().addRecentWorkingSet(result[0]);
                    } else {
                        selectedWorkingSets = EMPTY_WORKING_SET_ARRAY;
                    }
                    updateWorkingSetSelection();
                }
            }
        });

        enableButton.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                updateEnableState(enableButton.getSelection());
            }
        });
        updateEnableState(enableButton.getSelection());

        workingSetCombo.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                updateSelectedWorkingSets();
            }
        });

        workingSetCombo.setItems(getHistoryEntries());
        if (selectedWorkingSets.length == 0 && selectionHistory.size() > 0) {
            workingSetCombo.select(historyIndex((String) selectionHistory.get(0)));
            updateSelectedWorkingSets();
        } else {
            updateWorkingSetSelection();
        }
    }

    private void updateEnableState(boolean enabled) {
        workingSetLabel.setEnabled(enabled);
        workingSetCombo.setEnabled(enabled && (selectedWorkingSets.length > 0 || getHistoryEntries().length > 0));
        selectButton.setEnabled(enabled);
    }

    private void updateWorkingSetSelection() {
        if (selectedWorkingSets.length > 0) {
            workingSetCombo.setEnabled(true);
            StringBuffer buf = new StringBuffer();

            buf.append(selectedWorkingSets[0].getLabel());
            for (int i = 1; i < selectedWorkingSets.length; i++) {
                IWorkingSet ws = selectedWorkingSets[i];
                buf.append(',').append(' ');
                buf.append(ws.getLabel());
            }

            String currentSelection = buf.toString();
            int index = historyIndex(currentSelection);
            historyInsert(currentSelection);
            if (index >= 0) {
                workingSetCombo.select(index);
            } else {
                workingSetCombo.setItems(getHistoryEntries());
                workingSetCombo.select(historyIndex(currentSelection));
            }
        } else {
            enableButton.setSelection(false);
            updateEnableState(false);
        }
    }

    private String[] getHistoryEntries() {
        String[] history = (String[]) selectionHistory.toArray(new String[selectionHistory.size()]);
        Arrays.sort(history, new Comparator() {
            public int compare(Object o1, Object o2) {
                return Collator.getInstance().compare(o1, o2);
            }
        });
        return history;
    }

    private void historyInsert(String entry) {
        selectionHistory.remove(entry);
        selectionHistory.add(0, entry);
        storeSelectionHistory(dialogSettings);
    }

    private int historyIndex(String entry) {
        for (int i = 0; i < workingSetCombo.getItemCount(); i++) {
            if (workingSetCombo.getItem(i).equals(entry))
                return i;
        }

        return -1;
    }

    // copied from org.eclipse.jdt.internal.ui.text.JavaCommentScanner
    private String[] split(String value, String delimiters) {
        StringTokenizer tokenizer = new StringTokenizer(value, delimiters);
        int size = tokenizer.countTokens();
        String[] tokens = new String[size];
        int i = 0;
        while (i < size)
            tokens[i++] = tokenizer.nextToken();
        return tokens;
    }

    private void updateSelectedWorkingSets() {
        String item = workingSetCombo.getItem(workingSetCombo.getSelectionIndex());
        String[] workingSetNames = split(item, ", "); //$NON-NLS-1$

        IWorkingSetManager workingSetManager = PlatformUI.getWorkbench().getWorkingSetManager();
        selectedWorkingSets = new IWorkingSet[workingSetNames.length];
        for (int i = 0; i < workingSetNames.length; i++) {
            IWorkingSet set = workingSetManager.getWorkingSet(workingSetNames[i]);
            Assert.isNotNull(set);
            selectedWorkingSets[i] = set;
        }
    }

    private void storeSelectionHistory(IDialogSettings settings) {
        String[] history;
        if (selectionHistory.size() > MAX_HISTORY_SIZE) {
            List subList = selectionHistory.subList(0, MAX_HISTORY_SIZE);
            history = (String[]) subList.toArray(new String[subList.size()]);
        } else {
            history = (String[]) selectionHistory.toArray(new String[selectionHistory.size()]);
        }
        settings.put(WORKINGSET_SELECTION_HISTORY, history);
    }

    private ArrayList loadSelectionHistory(IDialogSettings settings, String[] workingSetIds) {
        String[] strings = settings.getArray(WORKINGSET_SELECTION_HISTORY);
        if (strings == null || strings.length == 0)
            return new ArrayList();

        ArrayList result = new ArrayList();

        HashSet workingSetIdsSet = new HashSet(Arrays.asList(workingSetIds));

        IWorkingSetManager workingSetManager = PlatformUI.getWorkbench().getWorkingSetManager();
        for (int i = 0; i < strings.length; i++) {
            String[] workingSetNames = split(strings[i], ", "); //$NON-NLS-1$
            boolean valid = true;
            for (int j = 0; j < workingSetNames.length && valid; j++) {
                IWorkingSet workingSet = workingSetManager.getWorkingSet(workingSetNames[j]);
                if (workingSet == null) {
                    valid = false;
                } else {
                    if (!workingSetIdsSet.contains(workingSet.getId()))
                        valid = false;
                }
            }
            if (valid) {
                result.add(strings[i]);
            }
        }

        return result;
    }

    /*
     * Copy from DialogPage with changes to accomodate the lack of a Dialog context.
     */
    private GridData setButtonLayoutData(Button button) {
        button.setFont(JFaceResources.getDialogFont());

        GC gc = new GC(button);
        gc.setFont(button.getFont());
        FontMetrics fontMetrics = gc.getFontMetrics();
        gc.dispose();

        GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
        int widthHint = Dialog.convertHorizontalDLUsToPixels(fontMetrics, IDialogConstants.BUTTON_WIDTH);
        Point minSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
        data.widthHint = Math.max(widthHint, minSize.x);
        button.setLayoutData(data);
        return data;
    }
}