/******************************************************************************* * Copyright (c) 2007 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 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. * * <strong>Please note that this API is experimental and may change before 3.4 * ships.</strong> * * @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. This method will be removed before 3.4 ships. */ 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; } private void updateSelectedWorkingSets() { String item = workingSetCombo.getItem(workingSetCombo .getSelectionIndex()); String[] workingSetNames = item.split(", "); //$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 = strings[i].split(", "); //$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; } }