+++ /dev/null
-package net.sourceforge.phpdt.internal.ui.util;
-
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.Vector;
-
-import org.eclipse.jface.util.Assert;
-import org.eclipse.jface.viewers.ILabelProvider;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.DisposeEvent;
-import org.eclipse.swt.events.DisposeListener;
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.TableItem;
-
-/**
- * A composite widget which holds a list of elements for user selection.
- * The elements are sorted alphabetically.
- * Optionally, the elements can be filtered and duplicate entries can
- * be hidden (folding).
- */
-public class FilteredList extends Composite {
-
- public interface FilterMatcher {
- /**
- * Sets the filter.
- *
- * @param pattern the filter pattern.
- * @param ignoreCase a flag indicating whether pattern matching is case insensitive or not.
- * @param ignoreWildCards a flag indicating whether wildcard characters are interpreted or not.
- */
- void setFilter(String pattern, boolean ignoreCase, boolean ignoreWildCards);
-
- /**
- * Returns <code>true</code> if the object matches the pattern, <code>false</code> otherwise.
- * <code>setFilter()</code> must have been called at least once prior to a call to this method.
- */
- boolean match(Object element);
- }
-
- private class DefaultFilterMatcher implements FilterMatcher {
- private StringMatcher fMatcher;
-
- public void setFilter(String pattern, boolean ignoreCase, boolean ignoreWildCards) {
- fMatcher= new StringMatcher(pattern + '*', ignoreCase, ignoreWildCards);
- }
-
- public boolean match(Object element) {
- return fMatcher.match(fRenderer.getText(element));
- }
- }
-
- private Table fList;
- private ILabelProvider fRenderer;
- private boolean fMatchEmtpyString= true;
- private boolean fIgnoreCase;
- private boolean fAllowDuplicates;
- private String fFilter= ""; //$NON-NLS-1$
- private TwoArrayQuickSorter fSorter;
-
- private Object[] fElements= new Object[0];
- private Label[] fLabels;
- private Vector fImages= new Vector();
-
- private int[] fFoldedIndices;
- private int fFoldedCount;
-
- private int[] fFilteredIndices;
- private int fFilteredCount;
-
- private FilterMatcher fFilterMatcher= new DefaultFilterMatcher();
- private Comparator fComparator;
-
- private static class Label {
- public final String string;
- public final Image image;
-
- public Label(String string, Image image) {
- this.string= string;
- this.image= image;
- }
-
- public boolean equals(Label label) {
- if (label == null)
- return false;
-
- return
- string.equals(label.string) &&
- image.equals(label.image);
- }
- }
-
- private final class LabelComparator implements Comparator {
- private boolean fIgnoreCase;
-
- LabelComparator(boolean ignoreCase) {
- fIgnoreCase= ignoreCase;
- }
-
- public int compare(Object left, Object right) {
- Label leftLabel= (Label) left;
- Label rightLabel= (Label) right;
-
- int value;
-
- if (fComparator == null) {
- value= fIgnoreCase
- ? leftLabel.string.compareToIgnoreCase(rightLabel.string)
- : leftLabel.string.compareTo(rightLabel.string);
- } else {
- value= fComparator.compare(leftLabel.string, rightLabel.string);
- }
-
- if (value != 0)
- return value;
-
- // images are allowed to be null
- if (leftLabel.image == null) {
- return (rightLabel.image == null) ? 0 : -1;
- } else if (rightLabel.image == null) {
- return +1;
- } else {
- return
- fImages.indexOf(leftLabel.image) -
- fImages.indexOf(rightLabel.image);
- }
- }
-
- }
-
- /**
- * Constructs a new instance of a filtered list.
- * @param parent the parent composite.
- * @param style the widget style.
- * @param renderer the label renderer.
- * @param ignoreCase specifies whether sorting and folding is case sensitive.
- * @param allowDuplicates specifies whether folding of duplicates is desired.
- * @param matchEmptyString specifies whether empty filter strings should filter everything or nothing.
- */
- public FilteredList(Composite parent, int style, ILabelProvider renderer,
- boolean ignoreCase, boolean allowDuplicates, boolean matchEmptyString)
- {
- super(parent, SWT.NONE);
-
- GridLayout layout= new GridLayout();
- layout.marginHeight= 0;
- layout.marginWidth= 0;
- setLayout(layout);
-
- fList= new Table(this, style);
- fList.setLayoutData(new GridData(GridData.FILL_BOTH));
- fList.addDisposeListener(new DisposeListener() {
- public void widgetDisposed(DisposeEvent e) {
- fRenderer.dispose();
- }
- });
-
- fRenderer= renderer;
- fIgnoreCase= ignoreCase;
- fSorter= new TwoArrayQuickSorter(new LabelComparator(ignoreCase));
- fAllowDuplicates= allowDuplicates;
- fMatchEmtpyString= matchEmptyString;
- }
-
- /**
- * Sets the list of elements.
- * @param elements the elements to be shown in the list.
- */
- public void setElements(Object[] elements) {
- if (elements == null) {
- fElements= new Object[0];
- } else {
- // copy list for sorting
- fElements= new Object[elements.length];
- System.arraycopy(elements, 0, fElements, 0, elements.length);
- }
-
- int length= fElements.length;
-
- // fill labels
- fLabels= new Label[length];
- Set imageSet= new HashSet();
- for (int i= 0; i != length; i++) {
- String text= fRenderer.getText(fElements[i]);
- Image image= fRenderer.getImage(fElements[i]);
-
- fLabels[i]= new Label(text, image);
- imageSet.add(image);
- }
- fImages.clear();
- fImages.addAll(imageSet);
-
- fSorter.sort(fLabels, fElements);
-
- fFilteredIndices= new int[length];
- fFilteredCount= filter();
-
- fFoldedIndices= new int[length];
- fFoldedCount= fold();
-
- updateList();
- }
-
- /**
- * Tests if the list (before folding and filtering) is empty.
- * @return returns <code>true</code> if the list is empty, <code>false</code> otherwise.
- */
- public boolean isEmpty() {
- return (fElements == null) || (fElements.length == 0);
- }
-
- /**
- * Sets the filter matcher.
- */
- public void setFilterMatcher(FilterMatcher filterMatcher) {
- Assert.isNotNull(filterMatcher);
- fFilterMatcher= filterMatcher;
- }
-
- /**
- * Sets a custom comparator for sorting the list.
- */
- public void setComparator(Comparator comparator) {
- Assert.isNotNull(comparator);
- fComparator= comparator;
- }
-
- /**
- * Adds a selection listener to the list.
- * @param listener the selection listener to be added.
- */
- public void addSelectionListener(SelectionListener listener) {
- fList.addSelectionListener(listener);
- }
-
- /**
- * Removes a selection listener from the list.
- * @param listener the selection listener to be removed.
- */
- public void removeSelectionListener(SelectionListener listener) {
- fList.removeSelectionListener(listener);
- }
-
- /**
- * Sets the selection of the list.
- * @param selection an array of indices specifying the selection.
- */
- public void setSelection(int[] selection) {
- fList.setSelection(selection);
- }
-
- /**
- * Returns the selection of the list.
- * @return returns an array of indices specifying the current selection.
- */
- public int[] getSelectionIndices() {
- return fList.getSelectionIndices();
- }
-
- /**
- * Returns the selection of the list.
- * This is a convenience function for <code>getSelectionIndices()</code>.
- * @return returns the index of the selection, -1 for no selection.
- */
- public int getSelectionIndex() {
- return fList.getSelectionIndex();
- }
-
- /**
- * Sets the selection of the list.
- * @param elements the array of elements to be selected.
- */
- public void setSelection(Object[] elements) {
- if ((elements == null) || (fElements == null))
- return;
-
- // fill indices
- int[] indices= new int[elements.length];
- for (int i= 0; i != elements.length; i++) {
- int j;
- for (j= 0; j != fFoldedCount; j++) {
- int max= (j == fFoldedCount - 1)
- ? fFilteredCount
- : fFoldedIndices[j + 1];
-
- int l;
- for (l= fFoldedIndices[j]; l != max; l++) {
- // found matching element?
- if (fElements[fFilteredIndices[l]].equals(elements[i])) {
- indices[i]= j;
- break;
- }
- }
-
- if (l != max)
- break;
- }
-
- // not found
- if (j == fFoldedCount)
- indices[i] = 0;
- }
-
- fList.setSelection(indices);
- }
-
- /**
- * Returns an array of the selected elements. The type of the elements
- * returned in the list are the same as the ones passed with
- * <code>setElements</code>. The array does not contain the rendered strings.
- * @return returns the array of selected elements.
- */
- public Object[] getSelection() {
- if (fList.isDisposed() || (fList.getSelectionCount() == 0))
- return new Object[0];
-
- int[] indices= fList.getSelectionIndices();
- Object[] elements= new Object[indices.length];
-
- for (int i= 0; i != indices.length; i++)
- elements[i]= fElements[fFilteredIndices[fFoldedIndices[indices[i]]]];
-
- return elements;
- }
-
- /**
- * Sets the filter pattern. Current only prefix filter patterns are supported.
- * @param filter the filter pattern.
- */
- public void setFilter(String filter) {
- fFilter= (filter == null) ? "" : filter; //$NON-NLS-1$
-
- fFilteredCount= filter();
- fFoldedCount= fold();
- updateList();
- }
-
- /**
- * Returns the filter pattern.
- * @return returns the filter pattern.
- */
- public String getFilter() {
- return fFilter;
- }
-
- /**
- * Returns all elements which are folded together to one entry in the list.
- * @param index the index selecting the entry in the list.
- * @return returns an array of elements folded together, <code>null</code> if index is out of range.
- */
- public Object[] getFoldedElements(int index) {
- if ((index < 0) || (index >= fFoldedCount))
- return null;
-
- int start= fFoldedIndices[index];
- int count= (index == fFoldedCount - 1)
- ? fFilteredCount - start
- : fFoldedIndices[index + 1] - start;
-
- Object[] elements= new Object[count];
- for (int i= 0; i != count; i++)
- elements[i]= fElements[fFilteredIndices[start + i]];
-
- return elements;
- }
-
- /*
- * Folds duplicate entries. Two elements are considered as a pair of
- * duplicates if they coiincide in the rendered string and image.
- * @return returns the number of elements after folding.
- */
- private int fold() {
- if (fAllowDuplicates) {
- for (int i= 0; i != fFilteredCount; i++)
- fFoldedIndices[i]= i; // identity mapping
-
- return fFilteredCount;
-
- } else {
- int k= 0;
- Label last= null;
- for (int i= 0; i != fFilteredCount; i++) {
- int j= fFilteredIndices[i];
-
- Label current= fLabels[j];
- if (! current.equals(last)) {
- fFoldedIndices[k]= i;
- k++;
- last= current;
- }
- }
- return k;
- }
- }
-
- /*
- * Filters the list with the filter pattern.
- * @return returns the number of elements after filtering.
- */
- private int filter() {
- if (((fFilter == null) || (fFilter.length() == 0)) && !fMatchEmtpyString)
- return 0;
-
- fFilterMatcher.setFilter(fFilter.trim(), fIgnoreCase, false);
-
- int k= 0;
- for (int i= 0; i != fElements.length; i++) {
- if (fFilterMatcher.match(fElements[i]))
- fFilteredIndices[k++]= i;
- }
-
- return k;
- }
-
- /*
- * Updates the list widget.
- */
- private void updateList() {
- if (fList.isDisposed())
- return;
-
- fList.setRedraw(false);
-
- // resize table
- int itemCount= fList.getItemCount();
- if (fFoldedCount < itemCount)
- fList.remove(0, itemCount - fFoldedCount - 1);
- else if (fFoldedCount > itemCount)
- for (int i= 0; i != fFoldedCount - itemCount; i++)
- new TableItem(fList, SWT.NONE);
-
- // fill table
- TableItem[] items= fList.getItems();
- for (int i= 0; i != fFoldedCount; i++) {
- TableItem item= items[i];
- Label label= fLabels[fFilteredIndices[fFoldedIndices[i]]];
-
- item.setText(label.string);
- item.setImage(label.image);
- }
-
- // select first item if any
- if (fList.getItemCount() > 0)
- fList.setSelection(0);
-
- fList.setRedraw(true);
- fList.notifyListeners(SWT.Selection, new Event());
- }
-
-}
\ No newline at end of file