### Eclipse Workspace Patch 1.0
#P org.eclipse.core.databinding
Index: src/org/eclipse/core/databinding/util/IFilter.java
===================================================================
RCS file: src/org/eclipse/core/databinding/util/IFilter.java
diff -N src/org/eclipse/core/databinding/util/IFilter.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/core/databinding/util/IFilter.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2006 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.core.databinding.util;
+
+/**
+ * Interface for filters. Can accept or reject items.
+ *
+ * @since 1.0
+ */
+public interface IFilter {
+ /**
+ * Determines if the given object passes this filter.
+ *
+ * @param toTest object to compare against the filter
+ *
+ * @return true iff the object is accepted by the filter.
+ */
+ public boolean select(Object toTest);
+}
Index: src/org/eclipse/core/databinding/observable/set/FilteringSet.java
===================================================================
RCS file: src/org/eclipse/core/databinding/observable/set/FilteringSet.java
diff -N src/org/eclipse/core/databinding/observable/set/FilteringSet.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/core/databinding/observable/set/FilteringSet.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,155 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.core.databinding.observable.set;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.core.databinding.observable.Diffs;
+import org.eclipse.core.databinding.util.IFilter;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * @since 3.3
+ *
+ */
+public abstract class FilteringSet extends ObservableSet {
+
+ private IObservableSet set;
+
+ private IFilter filter;
+
+ private ISetChangeListener setChangeListener = new ISetChangeListener() {
+ public void handleSetChange(IObservableSet source, SetDiff diff) {
+ if (filter == null) {
+ fireSetChange(diff);
+ return;
+ }
+ Set removals = new HashSet();
+ Set additions = new HashSet();
+ for (Iterator it = diff.getRemovals().iterator(); it.hasNext();) {
+ Object removedElement = it.next();
+ if (filter.select(removedElement)) {
+ wrappedSet.remove(removedElement);
+ removals.add(removedElement);
+ }
+ }
+ for (Iterator it = diff.getAdditions().iterator(); it.hasNext();) {
+ Object addedElement = it.next();
+ if (filter.select(addedElement)) {
+ wrappedSet.add(addedElement);
+ additions.add(addedElement);
+ }
+ }
+ fireSetChange(Diffs.createSetDiff(additions, removals));
+ }
+ };
+
+ /**
+ * @param set
+ */
+ public FilteringSet(IObservableSet set) {
+ super(set.getRealm(), set, set.getElementType());
+ this.set = set;
+ set.addSetChangeListener(setChangeListener);
+ }
+
+ /**
+ * @param filter
+ * @param monitor
+ * @param incrementalEvents
+ */
+ public void init(IFilter filter, IProgressMonitor monitor,
+ boolean incrementalEvents) {
+ Assert.isTrue(this.filter == null);
+ Assert.isTrue(filter != null);
+ wrappedSet = new HashSet(set);
+ this.filter = filter;
+ refilter(monitor, incrementalEvents, true);
+ }
+
+ /**
+ * Clients should call this method to cause the elements to be refiltered
+ * after a change to the filter criteria.
+ *
+ * @param monitor
+ * progress monitor for reporting progress and cancellation
+ * @param incrementalEvents
+ * true
if change events should be fired
+ * incrementally, false
if just one combined
+ * change event at the end should be fired
+ * @param narrowing
+ * true
if the result of the refilter will be a
+ * subset of the current set
+ *
+ */
+ public void refilter(IProgressMonitor monitor, boolean incrementalEvents,
+ boolean narrowing) {
+ setStale(true);
+ monitor.beginTask("NON-NLSed: Filtering", set.size()); //$NON-NLS-1$
+ Set additions = new HashSet();
+ Set removals = new HashSet();
+ // Delay firing of incremental events by one iteration so that we have
+ // one event left at the end. This allows us to call setStale(false)
+ // before firing the last event.
+ SetDiff nextDiff = null;
+ Iterator it = narrowing ? wrappedSet.iterator() : set.iterator();
+ while (!monitor.isCanceled() && it.hasNext()) {
+ Object element = it.next();
+ if (filter == null || filter.select(element)) {
+ if (!narrowing && wrappedSet.add(element)) {
+ if (incrementalEvents) {
+ if (nextDiff != null) {
+ fireSetChange(nextDiff);
+ }
+ nextDiff = Diffs.createSetDiff(Collections
+ .singleton(element), Collections.EMPTY_SET);
+ } else {
+ additions.add(element);
+ }
+ }
+ } else {
+ if (wrappedSet.remove(element)) {
+ if (incrementalEvents) {
+ if (nextDiff != null) {
+ fireSetChange(nextDiff);
+ }
+ nextDiff = Diffs.createSetDiff(Collections.EMPTY_SET,
+ Collections.singleton(element));
+ } else {
+ removals.add(element);
+ }
+ }
+ }
+ monitor.worked(1);
+ }
+ setStale(false);
+ if (incrementalEvents) {
+ if (nextDiff != null) {
+ fireSetChange(nextDiff);
+ } else {
+ // This is needed in order to notify clients that track
+ // staleness.
+ fireSetChange(Diffs.createSetDiff(Collections.EMPTY_SET,
+ Collections.EMPTY_SET));
+ }
+ } else {
+ SetDiff diff = Diffs.createSetDiff(additions, removals);
+ fireSetChange(diff);
+ }
+ monitor.done();
+ }
+
+}
Index: src/org/eclipse/core/databinding/observable/list/FilteringList.java
===================================================================
RCS file: src/org/eclipse/core/databinding/observable/list/FilteringList.java
diff -N src/org/eclipse/core/databinding/observable/list/FilteringList.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/core/databinding/observable/list/FilteringList.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,142 @@
+package org.eclipse.core.databinding.observable.list;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.core.databinding.observable.Diffs;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+
+/**
+ * @since 1.0
+ *
+ */
+public abstract class FilteringList extends ObservableList {
+
+ private final IObservableList unfiltered;
+
+ private final IObservableValue textObservable;
+
+ private IListChangeListener listChangeListener = new IListChangeListener() {
+ public void handleListChange(IObservableList source, ListDiff diff) {
+ ListDiffEntry[] differences = diff.getDifferences();
+ List listDiffEntries = new ArrayList();
+ for (int i = 0; i < differences.length; i++) {
+ ListDiffEntry diffEntry = differences[i];
+ Object element = diffEntry.getElement();
+ if (diffEntry.isAddition()) {
+ if (select(element)) {
+ int index = internalAddElement(element, diffEntry
+ .getPosition());
+ if (index >= 0) {
+ listDiffEntries.add(Diffs.createListDiffEntry(
+ index, true, element));
+ }
+ }
+ } else {
+ if (select(element)) {
+ int index = internalRemoveElement(element, diffEntry
+ .getPosition());
+ if (index >= 0) {
+ listDiffEntries.add(Diffs.createListDiffEntry(
+ index, false, element));
+ }
+ }
+ }
+ }
+ fireListChange(Diffs
+ .createListDiff((ListDiffEntry[]) listDiffEntries
+ .toArray(new ListDiffEntry[listDiffEntries.size()])));
+ }
+ };
+
+ protected FilteringList(IObservableList list,
+ IObservableValue textObservable) {
+ super(list.getRealm(), new ArrayList(), list.getElementType());
+ this.unfiltered = list;
+ unfiltered.addListChangeListener(listChangeListener);
+ refilter();
+ }
+
+ protected void refilter() {
+ List listDiffEntries = new ArrayList();
+ for (int i = 0; i < unfiltered.size(); i++) {
+ Object element = unfiltered.get(i);
+ if (select(element)) {
+ int newIndex = internalAddElement(element, i);
+ if (newIndex >= 0) {
+ listDiffEntries.add(Diffs.createListDiffEntry(newIndex,
+ true, element));
+ }
+ } else {
+ int oldIndex = internalRemoveElement(element, i);
+ if (oldIndex >= 0) {
+ listDiffEntries.add(Diffs.createListDiffEntry(oldIndex,
+ false, element));
+ }
+ }
+ }
+ fireListChange(Diffs.createListDiff((ListDiffEntry[]) listDiffEntries
+ .toArray(new ListDiffEntry[listDiffEntries.size()])));
+ }
+
+ private int internalRemoveElement(Object element, int childIndex) {
+ int location = Arrays.binarySearch(filteredIndices, childIndex);
+ if (location >= 0) {
+ wrappedList.remove(location);
+ if (location == 0) {
+ if (filteredIndices.length == 1) {
+ filteredIndices = new int[0];
+ } else {
+ int[] next = new int[filteredIndices.length - 1];
+ System.arraycopy(filteredIndices, 1, next, 0, next.length);
+ filteredIndices = next;
+ }
+ } else if (location == (filteredIndices.length - 1)) {
+ int[] next = new int[filteredIndices.length - 1];
+ System.arraycopy(filteredIndices, 0, next, 0, location);
+ filteredIndices = next;
+ } else {
+ int[] next = new int[filteredIndices.length - 1];
+ System.arraycopy(filteredIndices, 0, next, 0, location);
+ System.arraycopy(filteredIndices, location + 1, next, location,
+ next.length - location);
+ filteredIndices = next;
+ }
+ }
+ return location;
+ }
+
+ private int internalAddElement(Object element, int index) {
+ int location = Arrays.binarySearch(filteredIndices, index);
+ if (location >= 0) {
+ return -1;
+ }
+ location = 0 - (location + 1);
+ wrappedList.add(location, element);
+ int[] next = new int[filteredIndices.length + 1];
+ if (location == 0) {
+ next[0] = index;
+ System.arraycopy(filteredIndices, 0, next, 1,
+ filteredIndices.length);
+ } else if (location == filteredIndices.length) {
+ next[filteredIndices.length] = index;
+ System.arraycopy(filteredIndices, 0, next, 0,
+ filteredIndices.length);
+ } else {
+ System.arraycopy(filteredIndices, 0, next, 0, location);
+ next[location] = index;
+ System.arraycopy(filteredIndices, location, next, location + 1,
+ filteredIndices.length - location);
+ }
+ filteredIndices = next;
+ return location;
+ }
+
+ protected boolean select(Object element) {
+ return stringMatcher.match(getText(element));
+ }
+
+ protected abstract String getText(Object element);
+
+}