diff options
author | Matthew Hall | 2009-01-24 23:42:58 +0000 |
---|---|---|
committer | Matthew Hall | 2009-01-24 23:42:58 +0000 |
commit | e59897c0e41b5f9a235952756fb2d3a4581a7fb6 (patch) | |
tree | 371ae11d2d4538d774b0709cd7138d0816fd2ed4 /bundles/org.eclipse.core.databinding/src/org/eclipse | |
parent | 7fd0132b2f61f92953408a92423c9e5e65d38714 (diff) | |
download | org.eclipse.e4.databinding-e59897c0e41b5f9a235952756fb2d3a4581a7fb6.tar.gz org.eclipse.e4.databinding-e59897c0e41b5f9a235952756fb2d3a4581a7fb6.tar.xz org.eclipse.e4.databinding-e59897c0e41b5f9a235952756fb2d3a4581a7fb6.zip |
FIXED - bug 262269: [DataBinding] Need IdentitySet, IdentityMap and IdentityObservableSet classes
https://bugs.eclipse.org/bugs/show_bug.cgi?id=262269
Diffstat (limited to 'bundles/org.eclipse.core.databinding/src/org/eclipse')
10 files changed, 842 insertions, 153 deletions
diff --git a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/databinding/observable/ObservableTracker.java b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/databinding/observable/ObservableTracker.java index 3f228939..91f1c5fb 100644 --- a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/databinding/observable/ObservableTracker.java +++ b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/databinding/observable/ObservableTracker.java @@ -7,15 +7,13 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Matthew Hall - bugs 210115, 146397, 249526 + * Matthew Hall - bugs 210115, 146397, 249526, 262269 *******************************************************************************/ package org.eclipse.core.databinding.observable; -import java.util.HashSet; -import java.util.Iterator; import java.util.Set; -import org.eclipse.core.internal.databinding.IdentityWrapper; +import org.eclipse.core.internal.databinding.IdentitySet; import org.eclipse.core.runtime.Assert; /** @@ -96,7 +94,7 @@ public class ObservableTracker { IStaleListener lastStaleListener = (IStaleListener) currentStaleListener .get(); - Set observableSet = new HashSet(); + Set observableSet = new IdentitySet(); // Push the new listeners to the top of the stack currentGetterCalledSet.set(observableSet); currentChangeListener.set(changeListener); @@ -111,14 +109,8 @@ public class ObservableTracker { currentStaleListener.set(lastStaleListener); } - int i = 0; - IObservable[] result = new IObservable[observableSet.size()]; - for (Iterator it = observableSet.iterator(); it.hasNext();) { - IdentityWrapper wrapper = (IdentityWrapper) it.next(); - result[i++] = (IObservable) wrapper.unwrap(); - } - - return result; + return (IObservable[]) observableSet + .toArray(new IObservable[observableSet.size()]); } /** @@ -135,7 +127,7 @@ public class ObservableTracker { public static IObservable[] runAndCollect(Runnable runnable) { Set lastObservableCreatedSet = (Set) currentObservableCreatedSet.get(); - Set observableSet = new HashSet(); + Set observableSet = new IdentitySet(); // Push the new listeners to the top of the stack currentObservableCreatedSet.set(observableSet); try { @@ -146,14 +138,8 @@ public class ObservableTracker { currentObservableCreatedSet.set(lastObservableCreatedSet); } - int i = 0; - IObservable[] result = new IObservable[observableSet.size()]; - for (Iterator it = observableSet.iterator(); it.hasNext();) { - IdentityWrapper wrapper = (IdentityWrapper) it.next(); - result[i++] = (IObservable) wrapper.unwrap(); - } - - return result; + return (IObservable[]) observableSet + .toArray(new IObservable[observableSet.size()]); } /** @@ -215,26 +201,17 @@ public class ObservableTracker { Assert.isTrue(false, "Getter called outside realm of observable " //$NON-NLS-1$ + toString(observable)); - Set lastGetterCalledSet = (Set) currentGetterCalledSet.get(); - if (lastGetterCalledSet == null) { - return; - } - IChangeListener lastChangeListener = (IChangeListener) currentChangeListener - .get(); - IStaleListener lastStaleListener = (IStaleListener) currentStaleListener - .get(); - - boolean added = false; - if (lastGetterCalledSet != null) { - added = lastGetterCalledSet.add(new IdentityWrapper(observable)); - } - - // If anyone is listening for observable usage... - if (added && lastChangeListener != null) { - observable.addChangeListener(lastChangeListener); - } - if (added && lastStaleListener != null) { - observable.addStaleListener(lastStaleListener); + Set getterCalledSet = (Set) currentGetterCalledSet.get(); + if (getterCalledSet != null && getterCalledSet.add(observable)) { + // If anyone is listening for observable usage... + IChangeListener changeListener = (IChangeListener) currentChangeListener + .get(); + if (changeListener != null) + observable.addChangeListener(changeListener); + IStaleListener staleListener = (IStaleListener) currentStaleListener + .get(); + if (staleListener != null) + observable.addStaleListener(staleListener); } } @@ -246,9 +223,9 @@ public class ObservableTracker { * @since 1.2 */ public static void observableCreated(IObservable observable) { - Set lastObservableCreatedSet = (Set) currentObservableCreatedSet.get(); - if (lastObservableCreatedSet != null) { - lastObservableCreatedSet.add(new IdentityWrapper(observable)); + Set observableCreatedSet = (Set) currentObservableCreatedSet.get(); + if (observableCreatedSet != null) { + observableCreatedSet.add(observable); } } } diff --git a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/IdentityMap.java b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/IdentityMap.java new file mode 100644 index 00000000..97c92538 --- /dev/null +++ b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/IdentityMap.java @@ -0,0 +1,406 @@ +/******************************************************************************* + * Copyright (c) 2008 Matthew Hall 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: + * Matthew Hall - initial API and implementation (bug 215531) + * Matthew Hall - bug 228125 + * (through ViewerElementMap.java) + * Matthew Hall - bug 262269 + ******************************************************************************/ + +package org.eclipse.core.internal.databinding; + +import java.lang.reflect.Array; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.eclipse.core.runtime.Assert; + +/** + * A {@link Map} whose keys are added, removed and compared by identity. The + * keys in the map are compared using <code>==</code> instead of + * {@link #equals(Object)}. + * <p> + * This class is <i>not</i> a strict implementation the {@link Map} interface. + * It intentionally violates the {@link Map} contract, which requires the use of + * {@link #equals(Object)} when comparing keys. + * + * @since 1.2 + */ +public class IdentityMap implements Map { + private Map wrappedMap; + + /** + * Constructs an IdentityMap. + */ + public IdentityMap() { + this.wrappedMap = new HashMap(); + } + + /** + * Constructs an IdentityMap containing all the entries in the specified + * map. + * + * @param map + * the map whose entries are to be added to this map. + */ + public IdentityMap(Map map) { + this(); + Assert.isNotNull(map); + putAll(map); + } + + public void clear() { + wrappedMap.clear(); + } + + public boolean containsKey(Object key) { + return wrappedMap.containsKey(new IdentityWrapper(key)); + } + + public boolean containsValue(Object value) { + return wrappedMap.containsValue(value); + } + + public Set entrySet() { + final Set wrappedEntrySet = wrappedMap.entrySet(); + return new Set() { + public boolean add(Object o) { + throw new UnsupportedOperationException(); + } + + public boolean addAll(Collection c) { + throw new UnsupportedOperationException(); + } + + public void clear() { + wrappedEntrySet.clear(); + } + + public boolean contains(Object o) { + for (Iterator iterator = iterator(); iterator.hasNext();) + if (iterator.next().equals(o)) + return true; + return false; + } + + public boolean containsAll(Collection c) { + for (Iterator iterator = c.iterator(); iterator.hasNext();) + if (!contains(iterator.next())) + return false; + return true; + } + + public boolean isEmpty() { + return wrappedEntrySet.isEmpty(); + } + + public Iterator iterator() { + final Iterator wrappedIterator = wrappedEntrySet.iterator(); + return new Iterator() { + public boolean hasNext() { + return wrappedIterator.hasNext(); + } + + public Object next() { + final Map.Entry wrappedEntry = (Map.Entry) wrappedIterator + .next(); + return new Map.Entry() { + public Object getKey() { + return ((IdentityWrapper) wrappedEntry.getKey()) + .unwrap(); + } + + public Object getValue() { + return wrappedEntry.getValue(); + } + + public Object setValue(Object value) { + return wrappedEntry.setValue(value); + } + + public boolean equals(Object obj) { + if (obj == this) + return true; + if (obj == null || !(obj instanceof Map.Entry)) + return false; + Map.Entry that = (Map.Entry) obj; + return this.getKey() == that.getKey() + && Util.equals(this.getValue(), that + .getValue()); + } + + public int hashCode() { + return wrappedEntry.hashCode(); + } + }; + } + + public void remove() { + wrappedIterator.remove(); + } + }; + } + + public boolean remove(Object o) { + final Map.Entry unwrappedEntry = (Map.Entry) o; + final IdentityWrapper wrappedKey = new IdentityWrapper( + unwrappedEntry.getKey()); + Map.Entry wrappedEntry = new Map.Entry() { + public Object getKey() { + return wrappedKey; + } + + public Object getValue() { + return unwrappedEntry.getValue(); + } + + public Object setValue(Object value) { + throw new UnsupportedOperationException(); + } + + public boolean equals(Object obj) { + if (obj == this) + return true; + if (obj == null || !(obj instanceof Map.Entry)) + return false; + Map.Entry that = (Map.Entry) obj; + return Util.equals(wrappedKey, that.getKey()) + && Util + .equals(this.getValue(), that + .getValue()); + } + + public int hashCode() { + return wrappedKey.hashCode() + ^ (getValue() == null ? 0 : getValue() + .hashCode()); + } + }; + return wrappedEntrySet.remove(wrappedEntry); + } + + public boolean removeAll(Collection c) { + boolean changed = false; + for (Iterator iterator = c.iterator(); iterator.hasNext();) + changed |= remove(iterator.next()); + return changed; + } + + public boolean retainAll(Collection c) { + boolean changed = false; + Object[] toRetain = c.toArray(); + outer: for (Iterator iterator = iterator(); iterator.hasNext();) { + Object entry = iterator.next(); + for (int i = 0; i < toRetain.length; i++) + if (entry.equals(toRetain[i])) + continue outer; + iterator.remove(); + changed = true; + } + return changed; + } + + public int size() { + return wrappedEntrySet.size(); + } + + public Object[] toArray() { + return toArray(new Object[size()]); + } + + public Object[] toArray(Object[] a) { + int size = size(); + if (a.length < size) { + a = (Object[]) Array.newInstance(a.getClass() + .getComponentType(), size); + } + int i = 0; + for (Iterator iterator = iterator(); iterator.hasNext();) { + a[i] = iterator.next(); + i++; + } + return a; + } + + public boolean equals(Object obj) { + if (obj == this) + return true; + if (obj == null || !(obj instanceof Set)) + return false; + Set that = (Set) obj; + return this.size() == that.size() && containsAll(that); + } + + public int hashCode() { + return wrappedEntrySet.hashCode(); + } + }; + } + + public Object get(Object key) { + return wrappedMap.get(new IdentityWrapper(key)); + } + + public boolean isEmpty() { + return wrappedMap.isEmpty(); + } + + public Set keySet() { + final Set wrappedKeySet = wrappedMap.keySet(); + return new Set() { + public boolean add(Object o) { + throw new UnsupportedOperationException(); + } + + public boolean addAll(Collection c) { + throw new UnsupportedOperationException(); + } + + public void clear() { + wrappedKeySet.clear(); + } + + public boolean contains(Object o) { + return wrappedKeySet.contains(new IdentityWrapper(o)); + } + + public boolean containsAll(Collection c) { + for (Iterator iterator = c.iterator(); iterator.hasNext();) + if (!wrappedKeySet.contains(new IdentityWrapper(iterator + .next()))) + return false; + return true; + } + + public boolean isEmpty() { + return wrappedKeySet.isEmpty(); + } + + public Iterator iterator() { + final Iterator wrappedIterator = wrappedKeySet.iterator(); + return new Iterator() { + public boolean hasNext() { + return wrappedIterator.hasNext(); + } + + public Object next() { + return ((IdentityWrapper) wrappedIterator.next()) + .unwrap(); + } + + public void remove() { + wrappedIterator.remove(); + } + }; + } + + public boolean remove(Object o) { + return wrappedKeySet.remove(new IdentityWrapper(o)); + } + + public boolean removeAll(Collection c) { + boolean changed = false; + for (Iterator iterator = c.iterator(); iterator.hasNext();) + changed |= wrappedKeySet.remove(new IdentityWrapper( + iterator.next())); + return changed; + } + + public boolean retainAll(Collection c) { + boolean changed = false; + Object[] toRetain = c.toArray(); + outer: for (Iterator iterator = iterator(); iterator.hasNext();) { + Object element = iterator.next(); + for (int i = 0; i < toRetain.length; i++) + if (element == toRetain[i]) + continue outer; + // element not contained in collection, remove. + remove(element); + changed = true; + } + return changed; + } + + public int size() { + return wrappedKeySet.size(); + } + + public Object[] toArray() { + return toArray(new Object[wrappedKeySet.size()]); + } + + public Object[] toArray(Object[] a) { + int size = wrappedKeySet.size(); + IdentityWrapper[] wrappedArray = (IdentityWrapper[]) wrappedKeySet + .toArray(new IdentityWrapper[size]); + Object[] result = a; + if (a.length < size) { + result = (Object[]) Array.newInstance(a.getClass() + .getComponentType(), size); + } + for (int i = 0; i < size; i++) + result[i] = wrappedArray[i].unwrap(); + return result; + } + + public boolean equals(Object obj) { + if (obj == this) + return true; + if (obj == null || !(obj instanceof Set)) + return false; + Set that = (Set) obj; + return this.size() == that.size() && containsAll(that); + } + + public int hashCode() { + return wrappedKeySet.hashCode(); + } + }; + } + + public Object put(Object key, Object value) { + return wrappedMap.put(new IdentityWrapper(key), value); + } + + public void putAll(Map other) { + for (Iterator iterator = other.entrySet().iterator(); iterator + .hasNext();) { + Map.Entry entry = (Map.Entry) iterator.next(); + wrappedMap.put(new IdentityWrapper(entry.getKey()), entry + .getValue()); + } + } + + public Object remove(Object key) { + return wrappedMap.remove(new IdentityWrapper(key)); + } + + public int size() { + return wrappedMap.size(); + } + + public Collection values() { + return wrappedMap.values(); + } + + public boolean equals(Object obj) { + if (obj == this) + return true; + if (obj == null || !(obj instanceof Map)) + return false; + Map that = (Map) obj; + return this.entrySet().equals(that.entrySet()); + } + + public int hashCode() { + return wrappedMap.hashCode(); + } +} diff --git a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/IdentitySet.java b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/IdentitySet.java new file mode 100644 index 00000000..f7f0079e --- /dev/null +++ b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/IdentitySet.java @@ -0,0 +1,172 @@ +/******************************************************************************* + * Copyright (c) 2008 Matthew Hall 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: + * Matthew Hall - initial API and implementation (bug 215531) + * Matthew Hall - bug 124684 + * (through ViewerElementSet.java) + * Matthew Hall - bug 262269 + ******************************************************************************/ + +package org.eclipse.core.internal.databinding; + +import java.lang.reflect.Array; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + * A {@link Set} of elements where elements are added, removed and compared by + * identity. Elements of the set are compared using <code>==</code> instead of + * {@link #equals(Object)}. + * <p> + * This class is <i>not</i> a strict implementation the {@link Set} interface. + * It intentionally violates the {@link Set} contract, which requires the use of + * {@link #equals(Object)} when comparing elements. + * + * @since 1.2 + */ +public class IdentitySet implements Set { + private final Set wrappedSet; + + /** + * Constructs an IdentitySet. + */ + public IdentitySet() { + this.wrappedSet = new HashSet(); + } + + /** + * Constructs an IdentitySet containing all the unique instances in the + * specified collection. + * + * @param collection + * the collection whose elements are to be added to this set. + */ + public IdentitySet(Collection collection) { + this(); + addAll(collection); + } + + public boolean add(Object o) { + return wrappedSet.add(new IdentityWrapper(o)); + } + + public boolean addAll(Collection c) { + boolean changed = false; + for (Iterator iterator = c.iterator(); iterator.hasNext();) + changed |= wrappedSet.add(new IdentityWrapper(iterator.next())); + return changed; + } + + public void clear() { + wrappedSet.clear(); + } + + public boolean contains(Object o) { + return wrappedSet.contains(new IdentityWrapper(o)); + } + + public boolean containsAll(Collection c) { + for (Iterator iterator = c.iterator(); iterator.hasNext();) + if (!wrappedSet.contains(new IdentityWrapper(iterator.next()))) + return false; + return true; + } + + public boolean isEmpty() { + return wrappedSet.isEmpty(); + } + + public Iterator iterator() { + final Iterator wrappedIterator = wrappedSet.iterator(); + return new Iterator() { + public boolean hasNext() { + return wrappedIterator.hasNext(); + } + + public Object next() { + return ((IdentityWrapper) wrappedIterator.next()).unwrap(); + } + + public void remove() { + wrappedIterator.remove(); + } + }; + } + + public boolean remove(Object o) { + return wrappedSet.remove(new IdentityWrapper(o)); + } + + public boolean removeAll(Collection c) { + boolean changed = false; + for (Iterator iterator = c.iterator(); iterator.hasNext();) + changed |= remove(iterator.next()); + return changed; + } + + public boolean retainAll(Collection c) { + // Have to do this the slow way to ensure correct comparisons. i.e. + // cannot delegate to c.contains(it) since we can't be sure will + // compare elements the way we want. + boolean changed = false; + Object[] retainAll = c.toArray(); + outer: for (Iterator iterator = iterator(); iterator.hasNext();) { + Object element = iterator.next(); + for (int i = 0; i < retainAll.length; i++) { + if (element == retainAll[i]) { + continue outer; + } + } + iterator.remove(); + changed = true; + } + return changed; + } + + public int size() { + return wrappedSet.size(); + } + + public Object[] toArray() { + return toArray(new Object[wrappedSet.size()]); + } + + public Object[] toArray(Object[] a) { + int size = wrappedSet.size(); + IdentityWrapper[] wrappedArray = (IdentityWrapper[]) wrappedSet + .toArray(new IdentityWrapper[size]); + Object[] result = a; + if (a.length < size) { + result = (Object[]) Array.newInstance(a.getClass() + .getComponentType(), size); + } + for (int i = 0; i < size; i++) + result[i] = wrappedArray[i].unwrap(); + return result; + } + + public boolean equals(Object obj) { + if (obj == this) + return true; + if (!(obj instanceof Set)) + return false; + Set that = (Set) obj; + return size() == that.size() && containsAll(that); + } + + public int hashCode() { + int hash = 0; + for (Iterator iterator = iterator(); iterator.hasNext();) { + Object element = iterator.next(); + hash += element == null ? 0 : element.hashCode(); + } + return hash; + } +} diff --git a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/observable/IdentityObservableSet.java b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/observable/IdentityObservableSet.java new file mode 100644 index 00000000..ca4c6ae7 --- /dev/null +++ b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/observable/IdentityObservableSet.java @@ -0,0 +1,167 @@ +/******************************************************************************* + * Copyright (c) 2008 Matthew Hall 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: + * Matthew Hall - initial API and implementation (bug 215531) + * Matthew Hall - bug 230267 + * (through ObservableViewerElementSet.java) + * Matthew Hall - bug 262269 + ******************************************************************************/ + +package org.eclipse.core.internal.databinding.observable; + +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.Set; + +import org.eclipse.core.databinding.observable.Diffs; +import org.eclipse.core.databinding.observable.Realm; +import org.eclipse.core.databinding.observable.set.AbstractObservableSet; +import org.eclipse.core.databinding.observable.set.IObservableSet; +import org.eclipse.core.internal.databinding.IdentitySet; + +/** + * An {@link IObservableSet} of elements where elements are added, removed and + * compared by identity. Elements of the set are compared using <code>==</code> + * instead of {@link #equals(Object)}. + * <p> + * This class is <i>not</i> a strict implementation the {@link IObservableSet} + * interface. It intentionally violates the {@link Set} contract, which requires + * the use of {@link #equals(Object)} when comparing elements. + * + * @since 1.2 + */ +public class IdentityObservableSet extends AbstractObservableSet { + private Set wrappedSet; + private Object elementType; + + /** + * Constructs an IdentityObservableSet on the given {@link Realm}. + * + * @param realm + * the realm of the constructed set. + * @param elementType + * the element type of the constructed set. + */ + public IdentityObservableSet(Realm realm, Object elementType) { + super(realm); + + this.wrappedSet = new IdentitySet(); + this.elementType = elementType; + } + + protected Set getWrappedSet() { + return wrappedSet; + } + + public Object getElementType() { + return elementType; + } + + public Iterator iterator() { + getterCalled(); + final Iterator wrappedIterator = wrappedSet.iterator(); + return new Iterator() { + Object last; + + public boolean hasNext() { + getterCalled(); + return wrappedIterator.hasNext(); + } + + public Object next() { + getterCalled(); + return last = wrappedIterator.next(); + } + + public void remove() { + getterCalled(); + wrappedIterator.remove(); + fireSetChange(Diffs.createSetDiff(Collections.EMPTY_SET, + Collections.singleton(last))); + } + }; + } + + public boolean add(Object o) { + getterCalled(); + boolean changed = wrappedSet.add(o); + if (changed) + fireSetChange(Diffs.createSetDiff(Collections.singleton(o), + Collections.EMPTY_SET)); + return changed; + } + + public boolean addAll(Collection c) { + getterCalled(); + Set additions = new IdentitySet(); + for (Iterator iterator = c.iterator(); iterator.hasNext();) { + Object element = iterator.next(); + if (wrappedSet.add(element)) + additions.add(element); + } + boolean changed = !additions.isEmpty(); + if (changed) + fireSetChange(Diffs.createSetDiff(additions, Collections.EMPTY_SET)); + return changed; + } + + public boolean remove(Object o) { + getterCalled(); + boolean changed = wrappedSet.remove(o); + if (changed) + fireSetChange(Diffs.createSetDiff(Collections.EMPTY_SET, + Collections.singleton(o))); + return changed; + } + + public boolean removeAll(Collection c) { + getterCalled(); + Set removals = new IdentitySet(); + for (Iterator iterator = c.iterator(); iterator.hasNext();) { + Object element = iterator.next(); + if (wrappedSet.remove(element)) + removals.add(element); + } + boolean changed = !removals.isEmpty(); + if (changed) + fireSetChange(Diffs.createSetDiff(Collections.EMPTY_SET, removals)); + return changed; + } + + public boolean retainAll(Collection c) { + getterCalled(); + Set removals = new IdentitySet(); + Object[] toRetain = c.toArray(); + outer: for (Iterator iterator = wrappedSet.iterator(); iterator + .hasNext();) { + Object element = iterator.next(); + // Cannot rely on c.contains(element) because we must compare + // elements using IElementComparer. + for (int i = 0; i < toRetain.length; i++) { + if (element == toRetain[i]) + continue outer; + } + iterator.remove(); + removals.add(element); + } + boolean changed = !removals.isEmpty(); + if (changed) + fireSetChange(Diffs.createSetDiff(Collections.EMPTY_SET, removals)); + return changed; + } + + public void clear() { + getterCalled(); + if (!wrappedSet.isEmpty()) { + Set removals = wrappedSet; + wrappedSet = new IdentitySet(); + fireSetChange(Diffs.createSetDiff(Collections.EMPTY_SET, removals)); + } + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/observable/StalenessTracker.java b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/observable/StalenessTracker.java index 6324325e..7b0d4b25 100644 --- a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/observable/StalenessTracker.java +++ b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/observable/StalenessTracker.java @@ -7,11 +7,11 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Matthew Hall - bug 262269 ******************************************************************************/ package org.eclipse.core.internal.databinding.observable; -import java.util.HashMap; import java.util.Map; import org.eclipse.core.databinding.observable.ChangeEvent; @@ -19,7 +19,7 @@ import org.eclipse.core.databinding.observable.IChangeListener; import org.eclipse.core.databinding.observable.IObservable; import org.eclipse.core.databinding.observable.IStaleListener; import org.eclipse.core.databinding.observable.StaleEvent; -import org.eclipse.core.internal.databinding.IdentityWrapper; +import org.eclipse.core.internal.databinding.IdentityMap; /** * @since 1.0 @@ -27,7 +27,7 @@ import org.eclipse.core.internal.databinding.IdentityWrapper; */ public class StalenessTracker { - private Map staleMap = new HashMap(); + private Map staleMap = new IdentityMap(); private int staleCount = 0; @@ -65,8 +65,7 @@ public class StalenessTracker { */ public void processStalenessChange(IObservable child, boolean callback) { boolean oldStale = staleCount > 0; - IdentityWrapper wrappedChild = new IdentityWrapper(child); - boolean oldChildStale = getOldChildStale(wrappedChild); + boolean oldChildStale = getOldChildStale(child); boolean newChildStale = child.isStale(); if (oldChildStale != newChildStale) { if (oldChildStale) { @@ -74,7 +73,7 @@ public class StalenessTracker { } else { staleCount++; } - staleMap.put(wrappedChild, newChildStale ? Boolean.TRUE : Boolean.FALSE); + staleMap.put(child, newChildStale ? Boolean.TRUE : Boolean.FALSE); } boolean newStale = staleCount > 0; if (callback && (newStale != oldStale)) { @@ -83,10 +82,10 @@ public class StalenessTracker { } /** - * @param wrappedChild + * @param child */ - private boolean getOldChildStale(IdentityWrapper wrappedChild) { - Object oldChildValue = staleMap.get(wrappedChild); + private boolean getOldChildStale(IObservable child) { + Object oldChildValue = staleMap.get(child); boolean oldChildStale = oldChildValue == null ? false : ((Boolean) oldChildValue).booleanValue(); return oldChildStale; @@ -110,12 +109,11 @@ public class StalenessTracker { */ public void removeObservable(IObservable observable) { boolean oldStale = staleCount > 0; - IdentityWrapper wrappedChild = new IdentityWrapper(observable); - boolean oldChildStale = getOldChildStale(wrappedChild); + boolean oldChildStale = getOldChildStale(observable); if (oldChildStale) { staleCount--; } - staleMap.remove(wrappedChild); + staleMap.remove(observable); observable.removeChangeListener(childListener); observable.removeStaleListener(childListener); boolean newStale = staleCount > 0; diff --git a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/property/value/DelegatingCache.java b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/property/value/DelegatingCache.java index 64ac6a11..db1d1634 100644 --- a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/property/value/DelegatingCache.java +++ b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/property/value/DelegatingCache.java @@ -1,20 +1,19 @@ /******************************************************************************* - * Copyright (c) 2009 IBM Corporation and others. + * Copyright (c) 2009 Matthew Hall 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 + * Matthew Hall - initial API and implementation (bug 194734) + * Matthew Hall - bug 262269 ******************************************************************************/ package org.eclipse.core.internal.databinding.property.value; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; @@ -26,11 +25,10 @@ import org.eclipse.core.databinding.observable.map.MapChangeEvent; import org.eclipse.core.databinding.observable.set.IObservableSet; import org.eclipse.core.databinding.observable.set.ISetChangeListener; import org.eclipse.core.databinding.observable.set.SetChangeEvent; -import org.eclipse.core.databinding.observable.set.WritableSet; import org.eclipse.core.databinding.property.value.DelegatingValueProperty; import org.eclipse.core.databinding.property.value.IValueProperty; -import org.eclipse.core.internal.databinding.IdentityWrapper; -import org.eclipse.core.internal.databinding.Util; +import org.eclipse.core.internal.databinding.IdentityMap; +import org.eclipse.core.internal.databinding.observable.IdentityObservableSet; /** * @since 3.3 @@ -50,8 +48,8 @@ abstract class DelegatingCache { DelegateCache(IValueProperty delegate) { this.delegate = delegate; - this.masterElements = new WritableSet(realm, Collections.EMPTY_SET, - elements.getElementType()); + this.masterElements = new IdentityObservableSet(realm, elements + .getElementType()); this.masterElementValues = delegate.observeDetail(masterElements); this.cachedValues = new HashMap(); @@ -62,22 +60,22 @@ abstract class DelegatingCache { boolean wasEmpty = masterElements.isEmpty(); masterElements.add(masterElement); - cachedValues.put(new IdentityWrapper(masterElement), - masterElementValues.get(masterElement)); + cachedValues.put(masterElement, masterElementValues + .get(masterElement)); if (wasEmpty) delegateCaches.put(delegate, this); } void remove(Object masterElement) { - cachedValues.remove(new IdentityWrapper(masterElement)); + cachedValues.remove(masterElement); masterElements.remove(masterElement); if (cachedValues.isEmpty()) dispose(); } Object get(Object masterElement) { - return cachedValues.get(new IdentityWrapper(masterElement)); + return cachedValues.get(masterElement); } Object put(Object masterElement, Object detailValue) { @@ -98,11 +96,10 @@ abstract class DelegatingCache { } private void notifyIfChanged(Object masterElement) { - Object oldValue = cachedValues.get(new IdentityWrapper( - masterElement)); + Object oldValue = cachedValues.get(masterElement); Object newValue = masterElementValues.get(masterElement); - if (!Util.equals(oldValue, newValue)) { - cachedValues.put(new IdentityWrapper(masterElement), newValue); + if (oldValue != newValue) { + cachedValues.put(masterElement, newValue); handleValueChange(masterElement, oldValue, newValue); } } @@ -125,22 +122,20 @@ abstract class DelegatingCache { this.realm = realm; this.detailProperty = detailProperty; - this.elements = new WritableSet(realm); - this.delegateCaches = new HashMap(); + this.elements = new IdentityObservableSet(realm, null); + this.delegateCaches = new IdentityMap(); elements.addSetChangeListener(new ISetChangeListener() { public void handleSetChange(SetChangeEvent event) { for (Iterator it = event.diff.getRemovals().iterator(); it .hasNext();) { - IdentityWrapper wrapper = (IdentityWrapper) it.next(); - Object element = wrapper.unwrap(); + Object element = it.next(); getCache(element).remove(element); } for (Iterator it = event.diff.getAdditions().iterator(); it .hasNext();) { - IdentityWrapper wrapper = (IdentityWrapper) it.next(); - Object element = wrapper.unwrap(); + Object element = it.next(); getCache(element).add(element); } } @@ -163,7 +158,7 @@ abstract class DelegatingCache { return getCache(element).put(element, value); } - boolean contains(Object value) { + boolean containsValue(Object value) { for (Iterator it = delegateCaches.values().iterator(); it.hasNext();) { DelegateCache cache = (DelegateCache) it.next(); if (cache.containsValue(value)) @@ -172,20 +167,12 @@ abstract class DelegatingCache { return false; } - private Set identitySet(Collection elements) { - Set result = new HashSet(); - for (Iterator it = elements.iterator(); it.hasNext();) { - result.add(new IdentityWrapper(it.next())); - } - return result; - } - void addAll(Collection elements) { - this.elements.addAll(identitySet(elements)); + this.elements.addAll(elements); } void retainAll(Collection elements) { - this.elements.retainAll(identitySet(elements)); + this.elements.retainAll(elements); } abstract void handleValueChange(Object masterElement, Object oldValue, diff --git a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/property/value/ListDelegatingValueObservableList.java b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/property/value/ListDelegatingValueObservableList.java index ab56c145..f67c5742 100644 --- a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/property/value/ListDelegatingValueObservableList.java +++ b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/property/value/ListDelegatingValueObservableList.java @@ -6,7 +6,8 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Matthew Hall - initial API and implementation + * Matthew Hall - initial API and implementation (bug 194734) + * Matthew Hall - bug 262269 ******************************************************************************/ package org.eclipse.core.internal.databinding.property.value; @@ -130,7 +131,7 @@ public class ListDelegatingValueObservableList extends AbstractObservableList public boolean contains(Object o) { getterCalled(); - return cache.contains(o); + return cache.containsValue(o); } public boolean isEmpty() { diff --git a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/property/value/ListSimpleValueObservableList.java b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/property/value/ListSimpleValueObservableList.java index aebbb311..4076a861 100644 --- a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/property/value/ListSimpleValueObservableList.java +++ b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/property/value/ListSimpleValueObservableList.java @@ -7,6 +7,7 @@ * * Contributors: * Matthew Hall - initial API and implementation (bug 194734) + * Matthew Hall - bug 262269 ******************************************************************************/ package org.eclipse.core.internal.databinding.property.value; @@ -14,8 +15,6 @@ package org.eclipse.core.internal.databinding.property.value; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.ListIterator; @@ -35,15 +34,16 @@ import org.eclipse.core.databinding.observable.list.ListDiffEntry; import org.eclipse.core.databinding.observable.set.IObservableSet; import org.eclipse.core.databinding.observable.set.ISetChangeListener; import org.eclipse.core.databinding.observable.set.SetChangeEvent; -import org.eclipse.core.databinding.observable.set.WritableSet; import org.eclipse.core.databinding.property.INativePropertyListener; import org.eclipse.core.databinding.property.IProperty; import org.eclipse.core.databinding.property.IPropertyObservable; import org.eclipse.core.databinding.property.ISimplePropertyListener; import org.eclipse.core.databinding.property.SimplePropertyEvent; import org.eclipse.core.databinding.property.value.SimpleValueProperty; -import org.eclipse.core.internal.databinding.IdentityWrapper; +import org.eclipse.core.internal.databinding.IdentityMap; +import org.eclipse.core.internal.databinding.IdentitySet; import org.eclipse.core.internal.databinding.Util; +import org.eclipse.core.internal.databinding.observable.IdentityObservableSet; /** * @since 1.2 @@ -67,11 +67,7 @@ public class ListSimpleValueObservableList extends AbstractObservableList } private void updateKnownElements() { - Set identityKnownElements = new HashSet(); - for (Iterator it = masterList.iterator(); it.hasNext();) { - identityKnownElements.add(new IdentityWrapper(it.next())); - } - + Set identityKnownElements = new IdentitySet(masterList); knownMasterElements.retainAll(identityKnownElements); knownMasterElements.addAll(identityKnownElements); } @@ -123,29 +119,25 @@ public class ListSimpleValueObservableList extends AbstractObservableList } protected void firstListenerAdded() { - knownMasterElements = new WritableSet(getRealm()); - cachedValues = new HashMap(); + knownMasterElements = new IdentityObservableSet(getRealm(), null); + cachedValues = new IdentityMap(); knownMasterElements.addSetChangeListener(new ISetChangeListener() { public void handleSetChange(SetChangeEvent event) { for (Iterator it = event.diff.getRemovals().iterator(); it .hasNext();) { - IdentityWrapper wrapper = (IdentityWrapper) it.next(); - Object key = wrapper.unwrap(); + Object key = it.next(); detailProperty.removeListener(key, detailListener); - cachedValues.remove(wrapper); + cachedValues.remove(key); } for (Iterator it = event.diff.getAdditions().iterator(); it .hasNext();) { - IdentityWrapper wrapper = (IdentityWrapper) it.next(); - Object key = wrapper.unwrap(); - cachedValues.put(wrapper, detailProperty.getValue(key)); + Object key = it.next(); + cachedValues.put(key, detailProperty.getValue(key)); detailProperty.addListener(key, detailListener); } } }); - for (Iterator it = masterList.iterator(); it.hasNext();) { - knownMasterElements.add(new IdentityWrapper(it.next())); - } + knownMasterElements.addAll(masterList); masterList.addListChangeListener(masterListener); masterList.addStaleListener(staleListener); @@ -360,11 +352,10 @@ public class ListSimpleValueObservableList extends AbstractObservableList private void notifyIfChanged(Object masterElement) { if (cachedValues != null) { - Object oldValue = cachedValues.get(new IdentityWrapper( - masterElement)); + Object oldValue = cachedValues.get(masterElement); Object newValue = detailProperty.getValue(masterElement); if (!Util.equals(oldValue, newValue)) { - cachedValues.put(new IdentityWrapper(masterElement), newValue); + cachedValues.put(masterElement, newValue); fireListChange(indicesOf(masterElement), oldValue, newValue); } } diff --git a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/property/value/MapSimpleValueObservableMap.java b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/property/value/MapSimpleValueObservableMap.java index ee4ba4b3..48729b9d 100644 --- a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/property/value/MapSimpleValueObservableMap.java +++ b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/property/value/MapSimpleValueObservableMap.java @@ -7,14 +7,13 @@ * * Contributors: * Matthew Hall - initial API and implementation (bug 194734) + * Matthew Hall - bug 262269 ******************************************************************************/ package org.eclipse.core.internal.databinding.property.value; import java.util.AbstractSet; import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; @@ -31,15 +30,16 @@ import org.eclipse.core.databinding.observable.map.MapDiff; import org.eclipse.core.databinding.observable.set.IObservableSet; import org.eclipse.core.databinding.observable.set.ISetChangeListener; import org.eclipse.core.databinding.observable.set.SetChangeEvent; -import org.eclipse.core.databinding.observable.set.WritableSet; import org.eclipse.core.databinding.property.INativePropertyListener; import org.eclipse.core.databinding.property.IProperty; import org.eclipse.core.databinding.property.IPropertyObservable; import org.eclipse.core.databinding.property.ISimplePropertyListener; import org.eclipse.core.databinding.property.SimplePropertyEvent; import org.eclipse.core.databinding.property.value.SimpleValueProperty; -import org.eclipse.core.internal.databinding.IdentityWrapper; +import org.eclipse.core.internal.databinding.IdentityMap; +import org.eclipse.core.internal.databinding.IdentitySet; import org.eclipse.core.internal.databinding.Util; +import org.eclipse.core.internal.databinding.observable.IdentityObservableSet; /** * @since 1.2 @@ -65,18 +65,14 @@ public class MapSimpleValueObservableMap extends AbstractObservableMap } private void updateKnownValues() { - Set identityKnownValues = new HashSet(); - for (Iterator it = masterMap.values().iterator(); it.hasNext();) { - identityKnownValues.add(new IdentityWrapper(it.next())); - } - - knownMasterValues.retainAll(identityKnownValues); - knownMasterValues.addAll(identityKnownValues); + Set knownValues = new IdentitySet(masterMap.values()); + knownMasterValues.retainAll(knownValues); + knownMasterValues.addAll(knownValues); } private MapDiff convertDiff(MapDiff diff) { - Map oldValues = new HashMap(); - Map newValues = new HashMap(); + Map oldValues = new IdentityMap(); + Map newValues = new IdentityMap(); Set addedKeys = diff.getAddedKeys(); for (Iterator it = addedKeys.iterator(); it.hasNext();) { @@ -94,7 +90,7 @@ public class MapSimpleValueObservableMap extends AbstractObservableMap oldValues.put(key, oldValue); } - Set changedKeys = new HashSet(diff.getChangedKeys()); + Set changedKeys = new IdentitySet(diff.getChangedKeys()); for (Iterator it = changedKeys.iterator(); it.hasNext();) { Object key = it.next(); @@ -144,29 +140,25 @@ public class MapSimpleValueObservableMap extends AbstractObservableMap } protected void firstListenerAdded() { - knownMasterValues = new WritableSet(getRealm()); - cachedValues = new HashMap(); + knownMasterValues = new IdentityObservableSet(getRealm(), null); + cachedValues = new IdentityMap(); knownMasterValues.addSetChangeListener(new ISetChangeListener() { public void handleSetChange(SetChangeEvent event) { for (Iterator it = event.diff.getRemovals().iterator(); it .hasNext();) { - IdentityWrapper wrapper = (IdentityWrapper) it.next(); - Object key = wrapper.unwrap(); + Object key = it.next(); detailProperty.removeListener(key, detailListener); - cachedValues.remove(wrapper); + cachedValues.remove(key); } for (Iterator it = event.diff.getAdditions().iterator(); it .hasNext();) { - IdentityWrapper wrapper = (IdentityWrapper) it.next(); - Object key = wrapper.unwrap(); - cachedValues.put(wrapper, detailProperty.getValue(key)); + Object key = it.next(); + cachedValues.put(key, detailProperty.getValue(key)); detailProperty.addListener(key, detailListener); } } }); - for (Iterator it = masterMap.values().iterator(); it.hasNext();) { - knownMasterValues.add(new IdentityWrapper(it.next())); - } + knownMasterValues.addAll(masterMap.values()); masterMap.addMapChangeListener(masterListener); masterMap.addStaleListener(staleListener); @@ -293,12 +285,11 @@ public class MapSimpleValueObservableMap extends AbstractObservableMap if (cachedValues != null) { final Set keys = keysFor(masterValue); - final Object oldValue = cachedValues.get(new IdentityWrapper( - masterValue)); + final Object oldValue = cachedValues.get(masterValue); final Object newValue = detailProperty.getValue(masterValue); if (!Util.equals(oldValue, newValue)) { - cachedValues.put(new IdentityWrapper(masterValue), newValue); + cachedValues.put(masterValue, newValue); fireMapChange(new MapDiff() { public Set getAddedKeys() { return Collections.EMPTY_SET; @@ -325,7 +316,7 @@ public class MapSimpleValueObservableMap extends AbstractObservableMap } private Set keysFor(Object value) { - Set keys = new HashSet(); + Set keys = new IdentitySet(); for (Iterator it = masterMap.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Entry) it.next(); diff --git a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/property/value/SetSimpleValueObservableMap.java b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/property/value/SetSimpleValueObservableMap.java index cd20d51b..37d331cb 100644 --- a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/property/value/SetSimpleValueObservableMap.java +++ b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/property/value/SetSimpleValueObservableMap.java @@ -7,11 +7,11 @@ * * Contributors: * Matthew Hall - initial API and implementation (bug 194734) + * Matthew Hall - bug 262269 ******************************************************************************/ package org.eclipse.core.internal.databinding.property.value; -import java.util.HashMap; import java.util.Iterator; import java.util.Map; @@ -24,7 +24,7 @@ import org.eclipse.core.databinding.property.IPropertyObservable; import org.eclipse.core.databinding.property.ISimplePropertyListener; import org.eclipse.core.databinding.property.SimplePropertyEvent; import org.eclipse.core.databinding.property.value.SimpleValueProperty; -import org.eclipse.core.internal.databinding.IdentityWrapper; +import org.eclipse.core.internal.databinding.IdentityMap; import org.eclipse.core.internal.databinding.Util; /** @@ -51,7 +51,7 @@ public class SetSimpleValueObservableMap extends ComputedObservableMap } protected void firstListenerAdded() { - cachedValues = new HashMap(); + cachedValues = new IdentityMap(); if (listener == null) { listener = detailProperty .adaptListener(new ISimplePropertyListener() { @@ -78,8 +78,7 @@ public class SetSimpleValueObservableMap extends ComputedObservableMap protected void hookListener(Object addedKey) { if (cachedValues != null) { - cachedValues.put(new IdentityWrapper(addedKey), detailProperty - .getValue(addedKey)); + cachedValues.put(addedKey, detailProperty.getValue(addedKey)); detailProperty.addListener(addedKey, listener); } } @@ -87,7 +86,7 @@ public class SetSimpleValueObservableMap extends ComputedObservableMap protected void unhookListener(Object removedKey) { if (cachedValues != null) { detailProperty.removeListener(removedKey, listener); - cachedValues.remove(new IdentityWrapper(removedKey)); + cachedValues.remove(removedKey); } } @@ -112,10 +111,10 @@ public class SetSimpleValueObservableMap extends ComputedObservableMap private void notifyIfChanged(Object key) { if (cachedValues != null) { - Object oldValue = cachedValues.get(new IdentityWrapper(key)); + Object oldValue = cachedValues.get(key); Object newValue = detailProperty.getValue(key); if (!Util.equals(oldValue, newValue)) { - cachedValues.put(new IdentityWrapper(key), newValue); + cachedValues.put(key, newValue); fireMapChange(Diffs.createMapDiffSingleChange(key, oldValue, newValue)); } |