View | Details | Raw Unified | Return to bug 167436
Collapse All | Expand All

(-)src/org/eclipse/core/databinding/util/IFilter.java (+27 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2004, 2006 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.core.databinding.util;
12
13
/**
14
 * Interface for filters. Can accept or reject items.
15
 * 
16
 * @since 1.0
17
 */
18
public interface IFilter {
19
	/**
20
	 * Determines if the given object passes this filter.
21
	 * 
22
	 * @param toTest object to compare against the filter 
23
	 * 
24
	 * @return true iff the object is accepted by the filter.
25
	 */
26
	public boolean select(Object toTest);
27
}
(-)src/org/eclipse/core/databinding/observable/set/FilteringSet.java (+155 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.observable.set;
13
14
import java.util.Collections;
15
import java.util.HashSet;
16
import java.util.Iterator;
17
import java.util.Set;
18
19
import org.eclipse.core.databinding.observable.Diffs;
20
import org.eclipse.core.databinding.util.IFilter;
21
import org.eclipse.core.runtime.Assert;
22
import org.eclipse.core.runtime.IProgressMonitor;
23
24
/**
25
 * @since 3.3
26
 * 
27
 */
28
public abstract class FilteringSet extends ObservableSet {
29
30
	private IObservableSet set;
31
32
	private IFilter filter;
33
34
	private ISetChangeListener setChangeListener = new ISetChangeListener() {
35
		public void handleSetChange(IObservableSet source, SetDiff diff) {
36
			if (filter == null) {
37
				fireSetChange(diff);
38
				return;
39
			}
40
			Set removals = new HashSet();
41
			Set additions = new HashSet();
42
			for (Iterator it = diff.getRemovals().iterator(); it.hasNext();) {
43
				Object removedElement = it.next();
44
				if (filter.select(removedElement)) {
45
					wrappedSet.remove(removedElement);
46
					removals.add(removedElement);
47
				}
48
			}
49
			for (Iterator it = diff.getAdditions().iterator(); it.hasNext();) {
50
				Object addedElement = it.next();
51
				if (filter.select(addedElement)) {
52
					wrappedSet.add(addedElement);
53
					additions.add(addedElement);
54
				}
55
			}
56
			fireSetChange(Diffs.createSetDiff(additions, removals));
57
		}
58
	};
59
60
	/**
61
	 * @param set
62
	 */
63
	public FilteringSet(IObservableSet set) {
64
		super(set.getRealm(), set, set.getElementType());
65
		this.set = set;
66
		set.addSetChangeListener(setChangeListener);
67
	}
68
69
	/**
70
	 * @param filter
71
	 * @param monitor
72
	 * @param incrementalEvents
73
	 */
74
	public void init(IFilter filter, IProgressMonitor monitor,
75
			boolean incrementalEvents) {
76
		Assert.isTrue(this.filter == null);
77
		Assert.isTrue(filter != null);
78
		wrappedSet = new HashSet(set);
79
		this.filter = filter;
80
		refilter(monitor, incrementalEvents, true);
81
	}
82
83
	/**
84
	 * Clients should call this method to cause the elements to be refiltered
85
	 * after a change to the filter criteria.
86
	 * 
87
	 * @param monitor
88
	 *            progress monitor for reporting progress and cancellation
89
	 * @param incrementalEvents
90
	 *            <code>true</code> if change events should be fired
91
	 *            incrementally, <code>false</code> if just one combined
92
	 *            change event at the end should be fired
93
	 * @param narrowing
94
	 *            <code>true</code> if the result of the refilter will be a
95
	 *            subset of the current set
96
	 * 
97
	 */
98
	public void refilter(IProgressMonitor monitor, boolean incrementalEvents,
99
			boolean narrowing) {
100
		setStale(true);
101
		monitor.beginTask("NON-NLSed: Filtering", set.size()); //$NON-NLS-1$
102
		Set additions = new HashSet();
103
		Set removals = new HashSet();
104
		// Delay firing of incremental events by one iteration so that we have
105
		// one event left at the end. This allows us to call setStale(false)
106
		// before firing the last event.
107
		SetDiff nextDiff = null;
108
		Iterator it = narrowing ? wrappedSet.iterator() : set.iterator();
109
		while (!monitor.isCanceled() && it.hasNext()) {
110
			Object element = it.next();
111
			if (filter == null || filter.select(element)) {
112
				if (!narrowing && wrappedSet.add(element)) {
113
					if (incrementalEvents) {
114
						if (nextDiff != null) {
115
							fireSetChange(nextDiff);
116
						}
117
						nextDiff = Diffs.createSetDiff(Collections
118
								.singleton(element), Collections.EMPTY_SET);
119
					} else {
120
						additions.add(element);
121
					}
122
				}
123
			} else {
124
				if (wrappedSet.remove(element)) {
125
					if (incrementalEvents) {
126
						if (nextDiff != null) {
127
							fireSetChange(nextDiff);
128
						}
129
						nextDiff = Diffs.createSetDiff(Collections.EMPTY_SET,
130
								Collections.singleton(element));
131
					} else {
132
						removals.add(element);
133
					}
134
				}
135
			}
136
			monitor.worked(1);
137
		}
138
		setStale(false);
139
		if (incrementalEvents) {
140
			if (nextDiff != null) {
141
				fireSetChange(nextDiff);
142
			} else {
143
				// This is needed in order to notify clients that track
144
				// staleness.
145
				fireSetChange(Diffs.createSetDiff(Collections.EMPTY_SET,
146
						Collections.EMPTY_SET));
147
			}
148
		} else {
149
			SetDiff diff = Diffs.createSetDiff(additions, removals);
150
			fireSetChange(diff);
151
		}
152
		monitor.done();
153
	}
154
155
}
(-)src/org/eclipse/core/databinding/observable/list/FilteringList.java (+142 lines)
Added Link Here
1
package org.eclipse.core.databinding.observable.list;
2
3
import java.util.ArrayList;
4
import java.util.Arrays;
5
import java.util.List;
6
7
import org.eclipse.core.databinding.observable.Diffs;
8
import org.eclipse.core.databinding.observable.value.IObservableValue;
9
10
/**
11
 * @since 1.0
12
 * 
13
 */
14
public abstract class FilteringList extends ObservableList {
15
16
	private final IObservableList unfiltered;
17
18
	private final IObservableValue textObservable;
19
20
	private IListChangeListener listChangeListener = new IListChangeListener() {
21
		public void handleListChange(IObservableList source, ListDiff diff) {
22
			ListDiffEntry[] differences = diff.getDifferences();
23
			List listDiffEntries = new ArrayList();
24
			for (int i = 0; i < differences.length; i++) {
25
				ListDiffEntry diffEntry = differences[i];
26
				Object element = diffEntry.getElement();
27
				if (diffEntry.isAddition()) {
28
					if (select(element)) {
29
						int index = internalAddElement(element, diffEntry
30
								.getPosition());
31
						if (index >= 0) {
32
							listDiffEntries.add(Diffs.createListDiffEntry(
33
									index, true, element));
34
						}
35
					}
36
				} else {
37
					if (select(element)) {
38
						int index = internalRemoveElement(element, diffEntry
39
								.getPosition());
40
						if (index >= 0) {
41
							listDiffEntries.add(Diffs.createListDiffEntry(
42
									index, false, element));
43
						}
44
					}
45
				}
46
			}
47
			fireListChange(Diffs
48
					.createListDiff((ListDiffEntry[]) listDiffEntries
49
							.toArray(new ListDiffEntry[listDiffEntries.size()])));
50
		}
51
	};
52
53
	protected FilteringList(IObservableList list,
54
			IObservableValue textObservable) {
55
		super(list.getRealm(), new ArrayList(), list.getElementType());
56
		this.unfiltered = list;
57
		unfiltered.addListChangeListener(listChangeListener);
58
		refilter();
59
	}
60
61
	protected void refilter() {
62
		List listDiffEntries = new ArrayList();
63
		for (int i = 0; i < unfiltered.size(); i++) {
64
			Object element = unfiltered.get(i);
65
			if (select(element)) {
66
				int newIndex = internalAddElement(element, i);
67
				if (newIndex >= 0) {
68
					listDiffEntries.add(Diffs.createListDiffEntry(newIndex,
69
							true, element));
70
				}
71
			} else {
72
				int oldIndex = internalRemoveElement(element, i);
73
				if (oldIndex >= 0) {
74
					listDiffEntries.add(Diffs.createListDiffEntry(oldIndex,
75
							false, element));
76
				}
77
			}
78
		}
79
		fireListChange(Diffs.createListDiff((ListDiffEntry[]) listDiffEntries
80
				.toArray(new ListDiffEntry[listDiffEntries.size()])));
81
	}
82
83
	private int internalRemoveElement(Object element, int childIndex) {
84
		int location = Arrays.binarySearch(filteredIndices, childIndex);
85
		if (location >= 0) {
86
			wrappedList.remove(location);
87
			if (location == 0) {
88
				if (filteredIndices.length == 1) {
89
					filteredIndices = new int[0];
90
				} else {
91
					int[] next = new int[filteredIndices.length - 1];
92
					System.arraycopy(filteredIndices, 1, next, 0, next.length);
93
					filteredIndices = next;
94
				}
95
			} else if (location == (filteredIndices.length - 1)) {
96
				int[] next = new int[filteredIndices.length - 1];
97
				System.arraycopy(filteredIndices, 0, next, 0, location);
98
				filteredIndices = next;
99
			} else {
100
				int[] next = new int[filteredIndices.length - 1];
101
				System.arraycopy(filteredIndices, 0, next, 0, location);
102
				System.arraycopy(filteredIndices, location + 1, next, location,
103
						next.length - location);
104
				filteredIndices = next;
105
			}
106
		}
107
		return location;
108
	}
109
110
	private int internalAddElement(Object element, int index) {
111
		int location = Arrays.binarySearch(filteredIndices, index);
112
		if (location >= 0) {
113
			return -1;
114
		}
115
		location = 0 - (location + 1);
116
		wrappedList.add(location, element);
117
		int[] next = new int[filteredIndices.length + 1];
118
		if (location == 0) {
119
			next[0] = index;
120
			System.arraycopy(filteredIndices, 0, next, 1,
121
					filteredIndices.length);
122
		} else if (location == filteredIndices.length) {
123
			next[filteredIndices.length] = index;
124
			System.arraycopy(filteredIndices, 0, next, 0,
125
					filteredIndices.length);
126
		} else {
127
			System.arraycopy(filteredIndices, 0, next, 0, location);
128
			next[location] = index;
129
			System.arraycopy(filteredIndices, location, next, location + 1,
130
					filteredIndices.length - location);
131
		}
132
		filteredIndices = next;
133
		return location;
134
	}
135
136
	protected boolean select(Object element) {
137
		return stringMatcher.match(getText(element));
138
	}
139
140
	protected abstract String getText(Object element);
141
142
}

Return to bug 167436