Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 122813 Details for
Bug 194734
[Databinding] Property-based observables
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read
this important communication.
[patch]
Make methods public in Simple*Property and Delegating*Property
clipboard.txt (text/plain), 224.03 KB, created by
Matthew Hall
on 2009-01-16 10:34:24 EST
(
hide
)
Description:
Make methods public in Simple*Property and Delegating*Property
Filename:
MIME Type:
Creator:
Matthew Hall
Created:
2009-01-16 10:34:24 EST
Size:
224.03 KB
patch
obsolete
>### Eclipse Workspace Patch 1.0 >#P org.eclipse.jface.examples.databinding >Index: src/org/eclipse/jface/examples/databinding/snippets/Snippet026AnonymousBeanProperties.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/snippets/Attic/Snippet026AnonymousBeanProperties.java,v >retrieving revision 1.1.2.2 >diff -u -r1.1.2.2 Snippet026AnonymousBeanProperties.java >--- src/org/eclipse/jface/examples/databinding/snippets/Snippet026AnonymousBeanProperties.java 14 Jan 2009 23:51:07 -0000 1.1.2.2 >+++ src/org/eclipse/jface/examples/databinding/snippets/Snippet026AnonymousBeanProperties.java 16 Jan 2009 15:28:49 -0000 >@@ -242,7 +242,7 @@ > } > } > >- protected INativePropertyListener adaptListener( >+ public INativePropertyListener adaptListener( > final IPropertyChangeListener listener) { > return new Listener(listener); > } >#P org.eclipse.core.databinding.beans >Index: src/org/eclipse/core/internal/databinding/beans/BeanListProperty.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.databinding.beans/src/org/eclipse/core/internal/databinding/beans/Attic/BeanListProperty.java,v >retrieving revision 1.1.2.6 >diff -u -r1.1.2.6 BeanListProperty.java >--- src/org/eclipse/core/internal/databinding/beans/BeanListProperty.java 14 Jan 2009 23:51:09 -0000 1.1.2.6 >+++ src/org/eclipse/core/internal/databinding/beans/BeanListProperty.java 16 Jan 2009 15:28:50 -0000 >@@ -81,7 +81,7 @@ > return propertyValue; > } > >- protected INativePropertyListener adaptListener( >+ public INativePropertyListener adaptListener( > final IPropertyChangeListener listener) { > return new Listener(listener); > } >#P org.eclipse.jface.databinding >Index: src/org/eclipse/jface/internal/databinding/viewers/ViewerInputProperty.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/viewers/Attic/ViewerInputProperty.java,v >retrieving revision 1.1.2.6 >diff -u -r1.1.2.6 ViewerInputProperty.java >--- src/org/eclipse/jface/internal/databinding/viewers/ViewerInputProperty.java 6 Jan 2009 06:21:04 -0000 1.1.2.6 >+++ src/org/eclipse/jface/internal/databinding/viewers/ViewerInputProperty.java 16 Jan 2009 15:28:51 -0000 >@@ -33,7 +33,7 @@ > ((Viewer) source).setInput(value); > } > >- protected INativePropertyListener adaptListener( >+ public INativePropertyListener adaptListener( > IPropertyChangeListener listener) { > return null; > } >Index: src/org/eclipse/jface/internal/databinding/swt/WidgetValueProperty.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/swt/Attic/WidgetValueProperty.java,v >retrieving revision 1.1.2.8 >diff -u -r1.1.2.8 WidgetValueProperty.java >--- src/org/eclipse/jface/internal/databinding/swt/WidgetValueProperty.java 14 Jan 2009 23:51:12 -0000 1.1.2.8 >+++ src/org/eclipse/jface/internal/databinding/swt/WidgetValueProperty.java 16 Jan 2009 15:28:51 -0000 >@@ -39,7 +39,7 @@ > this.events = events; > } > >- protected INativePropertyListener adaptListener( >+ public INativePropertyListener adaptListener( > IPropertyChangeListener listener) { > return new WidgetListener(listener); > } >#P org.eclipse.core.databinding >Index: src/org/eclipse/core/databinding/property/map/SimpleMapProperty.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.databinding/src/org/eclipse/core/databinding/property/map/Attic/SimpleMapProperty.java,v >retrieving revision 1.1.2.8 >diff -u -r1.1.2.8 SimpleMapProperty.java >--- src/org/eclipse/core/databinding/property/map/SimpleMapProperty.java 8 Jan 2009 01:24:50 -0000 1.1.2.8 >+++ src/org/eclipse/core/databinding/property/map/SimpleMapProperty.java 16 Jan 2009 15:28:52 -0000 >@@ -20,6 +20,7 @@ > import org.eclipse.core.databinding.observable.map.MapDiff; > import org.eclipse.core.databinding.property.INativePropertyListener; > import org.eclipse.core.databinding.property.IPropertyChangeListener; >+import org.eclipse.core.internal.databinding.property.map.SimpleMapPropertyObservableMap; > > /** > * Simplified abstract implementation of IMapProperty. This class takes care of >@@ -59,7 +60,7 @@ > * @return a Map with the current contents of the source's map property > * @noreference This method is not intended to be referenced by clients. > */ >- protected final Map getMap(Object source) { >+ public final Map getMap(Object source) { > if (source == null) > return Collections.EMPTY_MAP; > return Collections.unmodifiableMap(doGetMap(source)); >@@ -88,7 +89,7 @@ > * a diff describing the change > * @noreference This method is not intended to be referenced by clients. > */ >- protected final void setMap(Object source, Map map, MapDiff diff) { >+ public final void setMap(Object source, Map map, MapDiff diff) { > if (source != null && !diff.isEmpty()) > doSetMap(source, map, diff); > } >@@ -124,7 +125,7 @@ > * ISetProperty or IMapProperty) depending on the property. > * @noreference This method is not intended to be referenced by clients. > */ >- protected abstract INativePropertyListener adaptListener( >+ public abstract INativePropertyListener adaptListener( > IPropertyChangeListener listener); > > /** >@@ -140,7 +141,7 @@ > * {@link #adaptListener(IPropertyChangeListener)} . > * @noreference This method is not intended to be referenced by clients. > */ >- protected final void addListener(Object source, >+ public final void addListener(Object source, > INativePropertyListener listener) { > if (source != null) > doAddListener(source, listener); >@@ -175,7 +176,7 @@ > * {@link #adaptListener(IPropertyChangeListener)} . > * @noreference This method is not intended to be referenced by clients. > */ >- protected final void removeListener(Object source, >+ public final void removeListener(Object source, > INativePropertyListener listener) { > if (source != null) > doRemoveListener(source, listener); >Index: src/org/eclipse/core/databinding/property/map/DelegatingMapProperty.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.databinding/src/org/eclipse/core/databinding/property/map/Attic/DelegatingMapProperty.java,v >retrieving revision 1.1.2.2 >diff -u -r1.1.2.2 DelegatingMapProperty.java >--- src/org/eclipse/core/databinding/property/map/DelegatingMapProperty.java 14 Jan 2009 23:51:11 -0000 1.1.2.2 >+++ src/org/eclipse/core/databinding/property/map/DelegatingMapProperty.java 16 Jan 2009 15:28:52 -0000 >@@ -38,7 +38,16 @@ > this.valueType = valueType; > } > >- protected final IMapProperty getDelegate(Object source) { >+ /** >+ * Returns the property to delegate to for the specified source object. >+ * Repeated calls to this method with the same source object returns the >+ * same delegate instance. >+ * >+ * @param source >+ * the property source (may be null) >+ * @return the property to delegate to for the specified source object. >+ */ >+ public final IMapProperty getDelegate(Object source) { > if (source == null) > return null; > IMapProperty delegate = doGetDelegate(source); >@@ -47,6 +56,15 @@ > return delegate; > } > >+ /** >+ * Returns the property to delegate to for the specified source object. >+ * Implementers must ensure that repeated calls to this method with the same >+ * source object returns the same delegate instance. >+ * >+ * @param source >+ * the property source >+ * @return the property to delegate to for the specified source object. >+ */ > protected abstract IMapProperty doGetDelegate(Object source); > > public Object getKeyType() { >@@ -69,7 +87,7 @@ > protected void doSetMap(Object source, Map map, MapDiff diff) { > } > >- protected INativePropertyListener adaptListener( >+ public INativePropertyListener adaptListener( > IPropertyChangeListener listener) { > return null; > } >Index: src/org/eclipse/core/databinding/property/map/SimpleMapPropertyObservableMap.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/map/SimpleMapPropertyObservableMap.java >diff -N src/org/eclipse/core/databinding/property/map/SimpleMapPropertyObservableMap.java >--- src/org/eclipse/core/databinding/property/map/SimpleMapPropertyObservableMap.java 14 Jan 2009 23:51:11 -0000 1.1.2.5 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,296 +0,0 @@ >-/******************************************************************************* >- * 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 194734) >- ******************************************************************************/ >- >-package org.eclipse.core.databinding.property.map; >- >-import java.util.AbstractSet; >-import java.util.Collection; >-import java.util.Collections; >-import java.util.ConcurrentModificationException; >-import java.util.HashMap; >-import java.util.HashSet; >-import java.util.Iterator; >-import java.util.Map; >-import java.util.Set; >- >-import org.eclipse.core.databinding.observable.Diffs; >-import org.eclipse.core.databinding.observable.ObservableTracker; >-import org.eclipse.core.databinding.observable.Realm; >-import org.eclipse.core.databinding.observable.map.AbstractObservableMap; >-import org.eclipse.core.databinding.observable.map.MapDiff; >-import org.eclipse.core.databinding.property.INativePropertyListener; >-import org.eclipse.core.databinding.property.IProperty; >-import org.eclipse.core.databinding.property.IPropertyChangeListener; >-import org.eclipse.core.databinding.property.IPropertyObservable; >-import org.eclipse.core.databinding.property.PropertyChangeEvent; >- >-/** >- * @since 1.2 >- */ >-class SimpleMapPropertyObservableMap extends AbstractObservableMap implements >- IPropertyObservable { >- private Object source; >- private SimpleMapProperty property; >- >- private volatile boolean updating = false; >- >- private volatile int modCount = 0; >- >- private INativePropertyListener listener; >- >- private Map cachedMap; >- >- /** >- * @param realm >- * @param source >- * @param property >- */ >- public SimpleMapPropertyObservableMap(Realm realm, Object source, >- SimpleMapProperty property) { >- super(realm); >- this.source = source; >- this.property = property; >- } >- >- public Object getKeyType() { >- return property.getKeyType(); >- } >- >- public Object getValueType() { >- return property.getValueType(); >- } >- >- private void getterCalled() { >- ObservableTracker.getterCalled(this); >- } >- >- protected void firstListenerAdded() { >- if (!isDisposed()) { >- cachedMap = new HashMap(this); >- >- if (listener == null) { >- listener = property >- .adaptListener(new IPropertyChangeListener() { >- public void handlePropertyChange( >- final PropertyChangeEvent event) { >- modCount++; >- if (!isDisposed() && !updating) { >- getRealm().exec(new Runnable() { >- public void run() { >- notifyIfChanged((MapDiff) event.diff); >- } >- }); >- } >- } >- }); >- } >- property.addListener(source, listener); >- } >- } >- >- protected void lastListenerRemoved() { >- if (listener != null) { >- property.removeListener(source, listener); >- } >- >- cachedMap.clear(); >- cachedMap = null; >- } >- >- // Queries >- >- private Map getMap() { >- return property.getMap(source); >- } >- >- // Single change operations >- >- private EntrySet es = new EntrySet(); >- >- public Set entrySet() { >- getterCalled(); >- return es; >- } >- >- private class EntrySet extends AbstractSet { >- public Iterator iterator() { >- return new EntrySetIterator(); >- } >- >- public int size() { >- return getMap().size(); >- } >- } >- >- private class EntrySetIterator implements Iterator { >- private volatile int expectedModCount = modCount; >- Map map = new HashMap(getMap()); >- Iterator iterator = map.entrySet().iterator(); >- Map.Entry last = null; >- >- public boolean hasNext() { >- getterCalled(); >- checkForComodification(); >- return iterator.hasNext(); >- } >- >- public Object next() { >- getterCalled(); >- checkForComodification(); >- last = (Map.Entry) iterator.next(); >- return last; >- } >- >- public void remove() { >- getterCalled(); >- checkForComodification(); >- >- iterator.remove(); // stay in sync >- MapDiff diff = Diffs.createMapDiffSingleRemove(last.getKey(), last >- .getValue()); >- >- boolean wasUpdating = updating; >- updating = true; >- try { >- property.setMap(source, map, diff); >- } finally { >- updating = wasUpdating; >- } >- >- notifyIfChanged(null); >- >- last = null; >- expectedModCount = modCount; >- } >- >- private void checkForComodification() { >- if (expectedModCount != modCount) >- throw new ConcurrentModificationException(); >- } >- } >- >- public Set keySet() { >- getterCalled(); >- // AbstractMap depends on entrySet() to fulfil keySet() API, so all >- // getterCalled() and comodification checks will still be handled >- return super.keySet(); >- } >- >- public Object put(Object key, Object value) { >- checkRealm(); >- >- Map map = new HashMap(getMap()); >- >- boolean add = !map.containsKey(key); >- >- Object oldValue = map.put(key, value); >- >- MapDiff diff; >- if (add) >- diff = Diffs.createMapDiffSingleAdd(key, value); >- else >- diff = Diffs.createMapDiffSingleChange(key, oldValue, value); >- >- boolean wasUpdating = updating; >- updating = true; >- try { >- property.setMap(source, map, diff); >- modCount++; >- } finally { >- updating = wasUpdating; >- } >- >- notifyIfChanged(null); >- >- return oldValue; >- } >- >- public void putAll(Map m) { >- checkRealm(); >- >- Map map = new HashMap(getMap()); >- >- Map oldValues = new HashMap(); >- Map newValues = new HashMap(); >- Set changedKeys = new HashSet(); >- Set addedKeys = new HashSet(); >- for (Iterator it = m.entrySet().iterator(); it.hasNext();) { >- Map.Entry entry = (Entry) it.next(); >- Object key = entry.getKey(); >- Object newValue = entry.getValue(); >- if (map.containsKey(key)) { >- changedKeys.add(key); >- oldValues.put(key, map.get(key)); >- } else { >- addedKeys.add(key); >- } >- map.put(key, newValue); >- >- newValues.put(key, newValue); >- } >- >- MapDiff diff = Diffs.createMapDiff(addedKeys, Collections.EMPTY_SET, >- changedKeys, oldValues, newValues); >- >- boolean wasUpdating = updating; >- updating = true; >- try { >- property.setMap(source, map, diff); >- modCount++; >- } finally { >- updating = wasUpdating; >- } >- >- notifyIfChanged(null); >- } >- >- public Object remove(Object key) { >- checkRealm(); >- return super.remove(key); >- } >- >- public Collection values() { >- getterCalled(); >- // AbstractMap depends on entrySet() to fulfil values() API, so all >- // getterCalled() and comodification checks will still be handled >- return super.values(); >- } >- >- private void notifyIfChanged(MapDiff diff) { >- if (hasListeners()) { >- Map oldMap = cachedMap; >- Map newMap = cachedMap = property.getMap(source); >- if (diff == null) >- diff = Diffs.computeMapDiff(oldMap, newMap); >- if (!diff.isEmpty()) >- fireMapChange(diff); >- } >- } >- >- public Object getObserved() { >- return source; >- } >- >- public IProperty getProperty() { >- return property; >- } >- >- public synchronized void dispose() { >- if (!isDisposed()) { >- if (listener != null) >- property.removeListener(source, listener); >- property = null; >- source = null; >- listener = null; >- } >- super.dispose(); >- } >-} >Index: src/org/eclipse/core/databinding/property/value/ObservableSetDelegatingValuePropertyObservableMap.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/value/ObservableSetDelegatingValuePropertyObservableMap.java >diff -N src/org/eclipse/core/databinding/property/value/ObservableSetDelegatingValuePropertyObservableMap.java >--- src/org/eclipse/core/databinding/property/value/ObservableSetDelegatingValuePropertyObservableMap.java 8 Jan 2009 01:24:49 -0000 1.1.2.1 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,235 +0,0 @@ >-/******************************************************************************* >- * 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 194734) >- ******************************************************************************/ >- >-package org.eclipse.core.databinding.property.value; >- >-import java.util.AbstractSet; >-import java.util.Collections; >-import java.util.HashMap; >-import java.util.Iterator; >-import java.util.Map; >-import java.util.Set; >- >-import org.eclipse.core.databinding.observable.Diffs; >-import org.eclipse.core.databinding.observable.IObserving; >-import org.eclipse.core.databinding.observable.IStaleListener; >-import org.eclipse.core.databinding.observable.ObservableTracker; >-import org.eclipse.core.databinding.observable.StaleEvent; >-import org.eclipse.core.databinding.observable.map.AbstractObservableMap; >-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.SetDiff; >-import org.eclipse.core.internal.databinding.Util; >- >-/** >- * @since 1.2 >- */ >-class ObservableSetDelegatingValuePropertyObservableMap extends >- AbstractObservableMap implements IObserving { >- private IObservableSet masterSet; >- private DelegatingValueProperty detailProperty; >- private DelegatingCache cache; >- >- private Set entrySet; >- >- class EntrySet extends AbstractSet { >- public Iterator iterator() { >- return new Iterator() { >- final Iterator it = masterSet.iterator(); >- >- public boolean hasNext() { >- return it.hasNext(); >- } >- >- public Object next() { >- return new MapEntry(it.next()); >- } >- >- public void remove() { >- it.remove(); >- } >- }; >- } >- >- public int size() { >- return masterSet.size(); >- } >- } >- >- class MapEntry implements Map.Entry { >- private final Object key; >- >- MapEntry(Object key) { >- this.key = key; >- } >- >- public Object getKey() { >- getterCalled(); >- return key; >- } >- >- public Object getValue() { >- getterCalled(); >- >- if (!masterSet.contains(key)) >- return null; >- >- return cache.get(key); >- } >- >- public Object setValue(Object value) { >- checkRealm(); >- >- if (!masterSet.contains(key)) >- return null; >- >- return cache.put(key, value); >- } >- >- public boolean equals(Object o) { >- getterCalled(); >- if (o == this) >- return true; >- if (o == null) >- return false; >- if (!(o instanceof Map.Entry)) >- return false; >- Map.Entry that = (Map.Entry) o; >- return Util.equals(this.getKey(), that.getKey()) >- && Util.equals(this.getValue(), that.getValue()); >- } >- >- public int hashCode() { >- getterCalled(); >- Object value = getValue(); >- return (key == null ? 0 : key.hashCode()) >- ^ (value == null ? 0 : value.hashCode()); >- } >- } >- >- private ISetChangeListener masterListener = new ISetChangeListener() { >- public void handleSetChange(SetChangeEvent event) { >- if (isDisposed()) >- return; >- >- cache.addAll(masterSet); >- >- // Need both obsolete and new elements to convert diff >- MapDiff diff = convertDiff(event.diff); >- >- cache.retainAll(masterSet); >- >- fireMapChange(diff); >- } >- >- private MapDiff convertDiff(SetDiff diff) { >- // Convert diff to detail value >- Map oldValues = new HashMap(); >- Map newValues = new HashMap(); >- >- for (Iterator it = diff.getRemovals().iterator(); it.hasNext();) { >- Object masterElement = it.next(); >- oldValues.put(masterElement, cache.get(masterElement)); >- } >- for (Iterator it = diff.getAdditions().iterator(); it.hasNext();) { >- Object masterElement = it.next(); >- newValues.put(masterElement, cache.get(masterElement)); >- } >- return Diffs.createMapDiff(diff.getAdditions(), diff.getRemovals(), >- Collections.EMPTY_SET, oldValues, newValues); >- } >- }; >- >- private IStaleListener staleListener = new IStaleListener() { >- public void handleStale(StaleEvent staleEvent) { >- fireStale(); >- } >- }; >- >- /** >- * @param keySet >- * @param valueProperty >- */ >- public ObservableSetDelegatingValuePropertyObservableMap( >- IObservableSet keySet, DelegatingValueProperty valueProperty) { >- super(keySet.getRealm()); >- this.masterSet = keySet; >- this.detailProperty = valueProperty; >- this.cache = new DelegatingCache(getRealm(), valueProperty) { >- void handleValueChange(Object masterElement, Object oldValue, >- Object newValue) { >- fireMapChange(Diffs.createMapDiffSingleChange(masterElement, >- oldValue, newValue)); >- } >- }; >- cache.addAll(masterSet); >- >- masterSet.addSetChangeListener(masterListener); >- masterSet.addStaleListener(staleListener); >- } >- >- public Set entrySet() { >- getterCalled(); >- if (entrySet == null) >- entrySet = new EntrySet(); >- return entrySet; >- } >- >- private void getterCalled() { >- ObservableTracker.getterCalled(this); >- } >- >- public Object get(Object key) { >- getterCalled(); >- return cache.get(key); >- } >- >- public Object put(Object key, Object value) { >- checkRealm(); >- return cache.put(key, value); >- } >- >- public boolean isStale() { >- return masterSet.isStale(); >- } >- >- public Object getObserved() { >- return masterSet; >- } >- >- public Object getKeyType() { >- return masterSet.getElementType(); >- } >- >- public Object getValueType() { >- return detailProperty.getValueType(); >- } >- >- public synchronized void dispose() { >- if (masterSet != null) { >- masterSet.removeSetChangeListener(masterListener); >- masterSet.removeStaleListener(staleListener); >- masterSet = null; >- } >- >- if (cache != null) { >- cache.dispose(); >- cache = null; >- } >- >- masterListener = null; >- detailProperty = null; >- >- super.dispose(); >- } >-} >Index: src/org/eclipse/core/databinding/property/value/DelegatingCache.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/value/DelegatingCache.java >diff -N src/org/eclipse/core/databinding/property/value/DelegatingCache.java >--- src/org/eclipse/core/databinding/property/value/DelegatingCache.java 8 Jan 2009 01:24:49 -0000 1.1.2.1 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,208 +0,0 @@ >-/******************************************************************************* >- * Copyright (c) 2009 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.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; >- >-import org.eclipse.core.databinding.observable.Realm; >-import org.eclipse.core.databinding.observable.map.IMapChangeListener; >-import org.eclipse.core.databinding.observable.map.IObservableMap; >-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.internal.databinding.IdentityWrapper; >-import org.eclipse.core.internal.databinding.Util; >- >-/** >- * @since 3.3 >- * >- */ >-abstract class DelegatingCache { >- private Realm realm; >- private DelegatingValueProperty detailProperty; >- private IObservableSet elements; >- private Map delegateCaches; >- >- private class DelegateCache implements IMapChangeListener { >- private final IValueProperty delegate; >- private final IObservableSet masterElements; >- private final IObservableMap masterElementValues; >- private final Map cachedValues; >- >- DelegateCache(IValueProperty delegate) { >- this.delegate = delegate; >- this.masterElements = new WritableSet(realm, Collections.EMPTY_SET, >- elements.getElementType()); >- this.masterElementValues = delegate.observeDetail(masterElements); >- this.cachedValues = new HashMap(); >- >- masterElementValues.addMapChangeListener(this); >- } >- >- void add(Object masterElement) { >- boolean wasEmpty = masterElements.isEmpty(); >- >- masterElements.add(masterElement); >- cachedValues.put(new IdentityWrapper(masterElement), >- masterElementValues.get(masterElement)); >- >- if (wasEmpty) >- delegateCaches.put(delegate, this); >- } >- >- void remove(Object masterElement) { >- cachedValues.remove(new IdentityWrapper(masterElement)); >- masterElements.remove(masterElement); >- if (cachedValues.isEmpty()) >- dispose(); >- } >- >- Object get(Object masterElement) { >- return cachedValues.get(new IdentityWrapper(masterElement)); >- } >- >- Object put(Object masterElement, Object detailValue) { >- Object oldValue = masterElementValues.put(masterElement, >- detailValue); >- notifyIfChanged(masterElement); >- return oldValue; >- } >- >- boolean containsValue(Object detailValue) { >- return cachedValues.containsValue(detailValue); >- } >- >- public void handleMapChange(MapChangeEvent event) { >- Set changedKeys = event.diff.getChangedKeys(); >- for (Iterator it = changedKeys.iterator(); it.hasNext();) >- notifyIfChanged(it.next()); >- } >- >- private void notifyIfChanged(Object masterElement) { >- Object oldValue = cachedValues.get(new IdentityWrapper( >- masterElement)); >- Object newValue = masterElementValues.get(masterElement); >- if (!Util.equals(oldValue, newValue)) { >- cachedValues.put(new IdentityWrapper(masterElement), newValue); >- handleValueChange(masterElement, oldValue, newValue); >- } >- } >- >- void handleValueChange(Object masterElement, Object oldValue, >- Object newValue) { >- DelegatingCache.this.handleValueChange(masterElement, oldValue, >- newValue); >- } >- >- void dispose() { >- delegateCaches.remove(delegate); >- masterElementValues.dispose(); >- masterElements.dispose(); >- cachedValues.clear(); >- } >- } >- >- DelegatingCache(Realm realm, DelegatingValueProperty detailProperty) { >- this.realm = realm; >- this.detailProperty = detailProperty; >- >- this.elements = new WritableSet(realm); >- this.delegateCaches = new HashMap(); >- >- 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(); >- getCache(element).remove(element); >- >- } >- for (Iterator it = event.diff.getAdditions().iterator(); it >- .hasNext();) { >- IdentityWrapper wrapper = (IdentityWrapper) it.next(); >- Object element = wrapper.unwrap(); >- getCache(element).add(element); >- } >- } >- }); >- } >- >- private DelegateCache getCache(Object masterElement) { >- IValueProperty delegate = detailProperty.getDelegate(masterElement); >- if (delegateCaches.containsKey(delegate)) { >- return (DelegateCache) delegateCaches.get(delegate); >- } >- return new DelegateCache(delegate); >- } >- >- Object get(Object element) { >- return getCache(element).get(element); >- } >- >- Object put(Object element, Object value) { >- return getCache(element).put(element, value); >- } >- >- boolean contains(Object value) { >- for (Iterator it = delegateCaches.values().iterator(); it.hasNext();) { >- DelegateCache cache = (DelegateCache) it.next(); >- if (cache.containsValue(value)) >- return true; >- } >- 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)); >- } >- >- void retainAll(Collection elements) { >- this.elements.retainAll(identitySet(elements)); >- } >- >- abstract void handleValueChange(Object masterElement, Object oldValue, >- Object newValue); >- >- void dispose() { >- if (elements != null) { >- elements.clear(); // clears caches >- elements.dispose(); >- elements = null; >- } >- >- if (delegateCaches != null) { >- for (Iterator it = delegateCaches.values().iterator(); it.hasNext();) { >- DelegateCache cache = (DelegateCache) it.next(); >- cache.dispose(); >- } >- delegateCaches.clear(); >- delegateCaches = null; >- } >- } >-} >Index: src/org/eclipse/core/databinding/property/value/ObservableListSimpleValuePropertyObservableList.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/value/ObservableListSimpleValuePropertyObservableList.java >diff -N src/org/eclipse/core/databinding/property/value/ObservableListSimpleValuePropertyObservableList.java >--- src/org/eclipse/core/databinding/property/value/ObservableListSimpleValuePropertyObservableList.java 23 Dec 2008 18:24:44 -0000 1.1.2.4 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,443 +0,0 @@ >-/******************************************************************************* >- * 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 194734) >- ******************************************************************************/ >- >-package org.eclipse.core.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; >-import java.util.Map; >-import java.util.Set; >- >-import org.eclipse.core.databinding.observable.Diffs; >-import org.eclipse.core.databinding.observable.IObserving; >-import org.eclipse.core.databinding.observable.IStaleListener; >-import org.eclipse.core.databinding.observable.ObservableTracker; >-import org.eclipse.core.databinding.observable.StaleEvent; >-import org.eclipse.core.databinding.observable.list.AbstractObservableList; >-import org.eclipse.core.databinding.observable.list.IListChangeListener; >-import org.eclipse.core.databinding.observable.list.IObservableList; >-import org.eclipse.core.databinding.observable.list.ListChangeEvent; >-import org.eclipse.core.databinding.observable.list.ListDiff; >-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.IPropertyChangeListener; >-import org.eclipse.core.databinding.property.PropertyChangeEvent; >-import org.eclipse.core.internal.databinding.IdentityWrapper; >-import org.eclipse.core.internal.databinding.Util; >- >-/** >- * @since 1.2 >- */ >-class ObservableListSimpleValuePropertyObservableList extends >- AbstractObservableList implements IObserving { >- private IObservableList masterList; >- private SimpleValueProperty detailProperty; >- >- private IObservableSet knownMasterElements; >- private Map cachedValues; >- >- private boolean updating; >- >- private IListChangeListener masterListener = new IListChangeListener() { >- public void handleListChange(ListChangeEvent event) { >- if (!isDisposed()) { >- updateKnownElements(); >- fireListChange(convertDiff(event.diff)); >- } >- } >- >- private void updateKnownElements() { >- Set identityKnownElements = new HashSet(); >- for (Iterator it = masterList.iterator(); it.hasNext();) { >- identityKnownElements.add(new IdentityWrapper(it.next())); >- } >- >- knownMasterElements.retainAll(identityKnownElements); >- knownMasterElements.addAll(identityKnownElements); >- } >- >- private ListDiff convertDiff(ListDiff diff) { >- // Convert diff to detail value >- ListDiffEntry[] masterEntries = diff.getDifferences(); >- ListDiffEntry[] detailEntries = new ListDiffEntry[masterEntries.length]; >- for (int i = 0; i < masterEntries.length; i++) { >- ListDiffEntry masterDifference = masterEntries[i]; >- int index = masterDifference.getPosition(); >- boolean addition = masterDifference.isAddition(); >- Object masterElement = masterDifference.getElement(); >- Object elementDetailValue = detailProperty >- .getValue(masterElement); >- detailEntries[i] = Diffs.createListDiffEntry(index, addition, >- elementDetailValue); >- } >- return Diffs.createListDiff(detailEntries); >- } >- }; >- >- private IStaleListener staleListener = new IStaleListener() { >- public void handleStale(StaleEvent staleEvent) { >- fireStale(); >- } >- }; >- >- private INativePropertyListener detailListener; >- >- /** >- * @param masterList >- * @param valueProperty >- */ >- public ObservableListSimpleValuePropertyObservableList( >- IObservableList masterList, SimpleValueProperty valueProperty) { >- super(masterList.getRealm()); >- this.masterList = masterList; >- this.detailProperty = valueProperty; >- >- IPropertyChangeListener listener = new IPropertyChangeListener() { >- public void handlePropertyChange(PropertyChangeEvent event) { >- if (!isDisposed() && !updating) { >- notifyIfChanged(event.getSource()); >- } >- } >- }; >- this.detailListener = detailProperty.adaptListener(listener); >- } >- >- protected void firstListenerAdded() { >- knownMasterElements = new WritableSet(getRealm()); >- cachedValues = new HashMap(); >- 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(); >- detailProperty.removeListener(key, detailListener); >- cachedValues.remove(wrapper); >- } >- for (Iterator it = event.diff.getAdditions().iterator(); it >- .hasNext();) { >- IdentityWrapper wrapper = (IdentityWrapper) it.next(); >- Object key = wrapper.unwrap(); >- cachedValues.put(wrapper, detailProperty.getValue(key)); >- detailProperty.addListener(key, detailListener); >- } >- } >- }); >- for (Iterator it = masterList.iterator(); it.hasNext();) { >- knownMasterElements.add(new IdentityWrapper(it.next())); >- } >- >- masterList.addListChangeListener(masterListener); >- masterList.addStaleListener(staleListener); >- } >- >- protected void lastListenerRemoved() { >- masterList.removeListChangeListener(masterListener); >- masterList.removeStaleListener(staleListener); >- if (knownMasterElements != null) { >- knownMasterElements.clear(); // clears cachedValues >- knownMasterElements.dispose(); >- knownMasterElements = null; >- } >- cachedValues.clear(); >- cachedValues = null; >- } >- >- protected int doGetSize() { >- getterCalled(); >- return masterList.size(); >- } >- >- private void getterCalled() { >- ObservableTracker.getterCalled(this); >- } >- >- public Object getElementType() { >- return detailProperty.getValueType(); >- } >- >- public Object get(int index) { >- getterCalled(); >- Object masterElement = masterList.get(index); >- return detailProperty.getValue(masterElement); >- } >- >- public boolean add(Object o) { >- throw new UnsupportedOperationException(); >- } >- >- public boolean addAll(Collection c) { >- throw new UnsupportedOperationException(); >- } >- >- public boolean addAll(int index, Collection c) { >- throw new UnsupportedOperationException(); >- } >- >- public boolean contains(Object o) { >- getterCalled(); >- >- for (Iterator it = masterList.iterator(); it.hasNext();) { >- if (Util.equals(detailProperty.getValue(it.next()), o)) >- return true; >- } >- return false; >- } >- >- public boolean isEmpty() { >- getterCalled(); >- return masterList.isEmpty(); >- } >- >- public boolean isStale() { >- getterCalled(); >- return masterList.isStale(); >- } >- >- public Iterator iterator() { >- getterCalled(); >- return new Iterator() { >- Iterator it = masterList.iterator(); >- >- public boolean hasNext() { >- getterCalled(); >- return it.hasNext(); >- } >- >- public Object next() { >- getterCalled(); >- Object masterElement = it.next(); >- return detailProperty.getValue(masterElement); >- } >- >- public void remove() { >- throw new UnsupportedOperationException(); >- } >- }; >- } >- >- public Object move(int oldIndex, int newIndex) { >- throw new UnsupportedOperationException(); >- } >- >- public boolean remove(Object o) { >- throw new UnsupportedOperationException(); >- } >- >- public boolean removeAll(Collection c) { >- throw new UnsupportedOperationException(); >- } >- >- public boolean retainAll(Collection c) { >- throw new UnsupportedOperationException(); >- } >- >- public Object[] toArray() { >- getterCalled(); >- Object[] masterElements = masterList.toArray(); >- Object[] result = new Object[masterElements.length]; >- for (int i = 0; i < result.length; i++) { >- result[i] = detailProperty.getValue(masterElements[i]); >- } >- return result; >- } >- >- public Object[] toArray(Object[] a) { >- getterCalled(); >- Object[] masterElements = masterList.toArray(); >- if (a.length < masterElements.length) >- a = (Object[]) Array.newInstance(a.getClass().getComponentType(), >- masterElements.length); >- for (int i = 0; i < masterElements.length; i++) { >- a[i] = detailProperty.getValue(masterElements[i]); >- } >- return a; >- } >- >- public void add(int index, Object o) { >- throw new UnsupportedOperationException(); >- } >- >- public void clear() { >- throw new UnsupportedOperationException(); >- } >- >- public ListIterator listIterator() { >- return listIterator(0); >- } >- >- public ListIterator listIterator(final int index) { >- getterCalled(); >- return new ListIterator() { >- ListIterator it = masterList.listIterator(index); >- Object lastMasterElement; >- Object lastElement; >- boolean haveIterated = false; >- >- public void add(Object arg0) { >- throw new UnsupportedOperationException(); >- } >- >- public boolean hasNext() { >- getterCalled(); >- return it.hasNext(); >- } >- >- public boolean hasPrevious() { >- getterCalled(); >- return it.hasPrevious(); >- } >- >- public Object next() { >- getterCalled(); >- lastMasterElement = it.next(); >- lastElement = detailProperty.getValue(lastMasterElement); >- haveIterated = true; >- return lastElement; >- } >- >- public int nextIndex() { >- getterCalled(); >- return it.nextIndex(); >- } >- >- public Object previous() { >- getterCalled(); >- lastMasterElement = it.previous(); >- lastElement = detailProperty.getValue(lastMasterElement); >- haveIterated = true; >- return lastElement; >- } >- >- public int previousIndex() { >- getterCalled(); >- return it.previousIndex(); >- } >- >- public void remove() { >- throw new UnsupportedOperationException(); >- } >- >- public void set(Object o) { >- checkRealm(); >- if (!haveIterated) >- throw new IllegalStateException(); >- >- boolean wasUpdating = updating; >- updating = true; >- try { >- detailProperty.setValue(lastElement, o); >- } finally { >- updating = wasUpdating; >- } >- >- notifyIfChanged(lastMasterElement); >- >- lastElement = o; >- } >- }; >- } >- >- private void notifyIfChanged(Object masterElement) { >- if (cachedValues != null) { >- Object oldValue = cachedValues.get(new IdentityWrapper( >- masterElement)); >- Object newValue = detailProperty.getValue(masterElement); >- if (!Util.equals(oldValue, newValue)) { >- cachedValues.put(new IdentityWrapper(masterElement), newValue); >- fireListChange(indicesOf(masterElement), oldValue, newValue); >- } >- } >- } >- >- private int[] indicesOf(Object masterElement) { >- List indices = new ArrayList(); >- >- for (ListIterator it = ObservableListSimpleValuePropertyObservableList.this.masterList >- .listIterator(); it.hasNext();) { >- if (masterElement == it.next()) >- indices.add(new Integer(it.previousIndex())); >- } >- >- int[] result = new int[indices.size()]; >- for (int i = 0; i < result.length; i++) { >- result[i] = ((Integer) indices.get(i)).intValue(); >- } >- return result; >- } >- >- private void fireListChange(int[] indices, Object oldValue, Object newValue) { >- ListDiffEntry[] differences = new ListDiffEntry[indices.length * 2]; >- for (int i = 0; i < indices.length; i++) { >- int index = indices[i]; >- differences[i * 2] = Diffs.createListDiffEntry(index, false, >- oldValue); >- differences[i * 2 + 1] = Diffs.createListDiffEntry(index, true, >- newValue); >- } >- fireListChange(Diffs.createListDiff(differences)); >- } >- >- public Object remove(int index) { >- throw new UnsupportedOperationException(); >- } >- >- public Object set(int index, Object o) { >- checkRealm(); >- Object masterElement = masterList.get(index); >- Object oldValue = detailProperty.getValue(masterElement); >- >- boolean wasUpdating = updating; >- updating = true; >- try { >- detailProperty.setValue(masterElement, o); >- } finally { >- updating = wasUpdating; >- } >- >- notifyIfChanged(masterElement); >- >- return oldValue; >- } >- >- public Object getObserved() { >- return masterList; >- } >- >- public synchronized void dispose() { >- if (masterList != null) { >- masterList.removeListChangeListener(masterListener); >- masterList = null; >- } >- if (knownMasterElements != null) { >- knownMasterElements.clear(); // detaches listeners >- knownMasterElements.dispose(); >- knownMasterElements = null; >- } >- >- masterListener = null; >- detailListener = null; >- detailProperty = null; >- cachedValues = null; >- >- super.dispose(); >- } >-} >\ No newline at end of file >Index: src/org/eclipse/core/databinding/property/value/ObservableMapDelegatingValuePropertyObservableMap.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/value/ObservableMapDelegatingValuePropertyObservableMap.java >diff -N src/org/eclipse/core/databinding/property/value/ObservableMapDelegatingValuePropertyObservableMap.java >--- src/org/eclipse/core/databinding/property/value/ObservableMapDelegatingValuePropertyObservableMap.java 8 Jan 2009 01:24:49 -0000 1.1.2.1 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,310 +0,0 @@ >-/******************************************************************************* >- * 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 194734) >- ******************************************************************************/ >- >-package org.eclipse.core.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; >- >-import org.eclipse.core.databinding.observable.Diffs; >-import org.eclipse.core.databinding.observable.IObserving; >-import org.eclipse.core.databinding.observable.IStaleListener; >-import org.eclipse.core.databinding.observable.ObservableTracker; >-import org.eclipse.core.databinding.observable.StaleEvent; >-import org.eclipse.core.databinding.observable.map.AbstractObservableMap; >-import org.eclipse.core.databinding.observable.map.IMapChangeListener; >-import org.eclipse.core.databinding.observable.map.IObservableMap; >-import org.eclipse.core.databinding.observable.map.MapChangeEvent; >-import org.eclipse.core.databinding.observable.map.MapDiff; >-import org.eclipse.core.internal.databinding.Util; >- >-/** >- * @since 1.2 >- */ >-class ObservableMapDelegatingValuePropertyObservableMap extends >- AbstractObservableMap implements IObserving { >- private IObservableMap masterMap; >- private DelegatingValueProperty detailProperty; >- private DelegatingCache cache; >- >- private Set entrySet; >- >- class EntrySet extends AbstractSet { >- public Iterator iterator() { >- return new Iterator() { >- Iterator it = masterMap.entrySet().iterator(); >- >- public boolean hasNext() { >- getterCalled(); >- return it.hasNext(); >- } >- >- public Object next() { >- getterCalled(); >- Map.Entry next = (Map.Entry) it.next(); >- return new MapEntry(next.getKey()); >- } >- >- public void remove() { >- it.remove(); >- } >- }; >- } >- >- public int size() { >- return masterMap.size(); >- } >- } >- >- class MapEntry implements Map.Entry { >- private Object key; >- >- MapEntry(Object key) { >- this.key = key; >- } >- >- public Object getKey() { >- getterCalled(); >- return key; >- } >- >- public Object getValue() { >- getterCalled(); >- >- if (!masterMap.containsKey(key)) >- return null; >- >- Object masterValue = masterMap.get(key); >- return cache.get(masterValue); >- } >- >- public Object setValue(Object value) { >- checkRealm(); >- >- if (!masterMap.containsKey(key)) >- return null; >- >- Object masterValue = masterMap.get(key); >- return cache.put(masterValue, value); >- } >- >- public boolean equals(Object o) { >- getterCalled(); >- if (o == this) >- return true; >- if (o == null) >- return false; >- if (!(o instanceof Map.Entry)) >- return false; >- Map.Entry that = (Map.Entry) o; >- return Util.equals(this.getKey(), that.getKey()) >- && Util.equals(this.getValue(), that.getValue()); >- } >- >- public int hashCode() { >- getterCalled(); >- Object value = getValue(); >- return (key == null ? 0 : key.hashCode()) >- ^ (value == null ? 0 : value.hashCode()); >- } >- } >- >- private IMapChangeListener masterListener = new IMapChangeListener() { >- public void handleMapChange(final MapChangeEvent event) { >- if (isDisposed()) >- return; >- >- cache.addAll(masterMap.values()); >- >- // Need both obsolete and new master values to convert diff >- MapDiff diff = convertDiff(event.diff); >- >- cache.retainAll(masterMap.values()); >- >- fireMapChange(diff); >- } >- >- private MapDiff convertDiff(MapDiff diff) { >- Map oldValues = new HashMap(); >- Map newValues = new HashMap(); >- >- Set addedKeys = diff.getAddedKeys(); >- for (Iterator it = addedKeys.iterator(); it.hasNext();) { >- Object key = it.next(); >- Object masterValue = diff.getNewValue(key); >- Object newValue = cache.get(masterValue); >- newValues.put(key, newValue); >- } >- >- Set removedKeys = diff.getRemovedKeys(); >- for (Iterator it = removedKeys.iterator(); it.hasNext();) { >- Object key = it.next(); >- Object masterValue = diff.getOldValue(key); >- Object oldValue = cache.get(masterValue); >- oldValues.put(key, oldValue); >- } >- >- Set changedKeys = new HashSet(diff.getChangedKeys()); >- for (Iterator it = changedKeys.iterator(); it.hasNext();) { >- Object key = it.next(); >- >- Object oldMasterValue = diff.getOldValue(key); >- Object newMasterValue = diff.getNewValue(key); >- >- Object oldValue = cache.get(oldMasterValue); >- Object newValue = cache.get(newMasterValue); >- >- if (Util.equals(oldValue, newValue)) { >- it.remove(); >- } else { >- oldValues.put(key, oldValue); >- newValues.put(key, newValue); >- } >- } >- >- return Diffs.createMapDiff(addedKeys, removedKeys, changedKeys, >- oldValues, newValues); >- } >- }; >- >- private IStaleListener staleListener = new IStaleListener() { >- public void handleStale(StaleEvent staleEvent) { >- fireStale(); >- } >- }; >- >- /** >- * @param map >- * @param valueProperty >- */ >- public ObservableMapDelegatingValuePropertyObservableMap( >- IObservableMap map, DelegatingValueProperty valueProperty) { >- super(map.getRealm()); >- this.masterMap = map; >- this.detailProperty = valueProperty; >- this.cache = new DelegatingCache(getRealm(), valueProperty) { >- void handleValueChange(Object masterElement, Object oldValue, >- Object newValue) { >- fireMapChange(keysFor(masterElement), oldValue, newValue); >- } >- }; >- cache.addAll(masterMap.values()); >- >- masterMap.addMapChangeListener(masterListener); >- masterMap.addStaleListener(staleListener); >- } >- >- public Set entrySet() { >- getterCalled(); >- if (entrySet == null) >- entrySet = new EntrySet(); >- return entrySet; >- } >- >- private void getterCalled() { >- ObservableTracker.getterCalled(this); >- } >- >- public Object get(Object key) { >- getterCalled(); >- Object masterValue = masterMap.get(key); >- return cache.get(masterValue); >- } >- >- public Object put(Object key, Object value) { >- if (!masterMap.containsKey(key)) >- return null; >- Object masterValue = masterMap.get(key); >- return cache.put(masterValue, value); >- } >- >- public boolean isStale() { >- getterCalled(); >- return masterMap.isStale(); >- } >- >- public Object getObserved() { >- return masterMap; >- } >- >- public Object getKeyType() { >- return masterMap.getKeyType(); >- } >- >- public Object getValueType() { >- return detailProperty.getValueType(); >- } >- >- private Set keysFor(Object masterValue) { >- Set keys = new HashSet(); >- >- for (Iterator it = masterMap.entrySet().iterator(); it.hasNext();) { >- Map.Entry entry = (Entry) it.next(); >- if (entry.getValue() == masterValue) { >- keys.add(entry.getKey()); >- } >- } >- >- return keys; >- } >- >- private void fireMapChange(final Set changedKeys, final Object oldValue, >- final Object newValue) { >- fireMapChange(new MapDiff() { >- public Set getAddedKeys() { >- return Collections.EMPTY_SET; >- } >- >- public Set getRemovedKeys() { >- return Collections.EMPTY_SET; >- } >- >- public Set getChangedKeys() { >- return Collections.unmodifiableSet(changedKeys); >- } >- >- public Object getOldValue(Object key) { >- if (changedKeys.contains(key)) >- return oldValue; >- return null; >- } >- >- public Object getNewValue(Object key) { >- if (changedKeys.contains(key)) >- return newValue; >- return null; >- } >- }); >- } >- >- public synchronized void dispose() { >- if (masterMap != null) { >- masterMap.removeMapChangeListener(masterListener); >- masterMap.removeStaleListener(staleListener); >- masterMap = null; >- } >- >- if (cache != null) { >- cache.dispose(); >- cache = null; >- } >- >- masterListener = null; >- detailProperty = null; >- >- super.dispose(); >- } >-} >Index: src/org/eclipse/core/databinding/property/value/ObservableSetSimpleValuePropertyObservableMap.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/value/ObservableSetSimpleValuePropertyObservableMap.java >diff -N src/org/eclipse/core/databinding/property/value/ObservableSetSimpleValuePropertyObservableMap.java >--- src/org/eclipse/core/databinding/property/value/ObservableSetSimpleValuePropertyObservableMap.java 23 Dec 2008 18:30:30 -0000 1.1.2.5 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,138 +0,0 @@ >-/******************************************************************************* >- * 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 194734) >- ******************************************************************************/ >- >-package org.eclipse.core.databinding.property.value; >- >-import java.util.HashMap; >-import java.util.Iterator; >-import java.util.Map; >- >-import org.eclipse.core.databinding.observable.Diffs; >-import org.eclipse.core.databinding.observable.IObserving; >-import org.eclipse.core.databinding.observable.map.ComputedObservableMap; >-import org.eclipse.core.databinding.observable.set.IObservableSet; >-import org.eclipse.core.databinding.property.INativePropertyListener; >-import org.eclipse.core.databinding.property.IPropertyChangeListener; >-import org.eclipse.core.databinding.property.PropertyChangeEvent; >-import org.eclipse.core.internal.databinding.Util; >- >-/** >- * @since 1.2 >- */ >-class ObservableSetSimpleValuePropertyObservableMap extends >- ComputedObservableMap implements IObserving { >- private SimpleValueProperty detailProperty; >- >- private INativePropertyListener listener; >- >- private Map cachedValues; >- >- private boolean updating; >- >- /** >- * @param keySet >- * @param valueProperty >- */ >- public ObservableSetSimpleValuePropertyObservableMap(IObservableSet keySet, >- SimpleValueProperty valueProperty) { >- super(keySet); >- this.detailProperty = valueProperty; >- } >- >- protected void firstListenerAdded() { >- cachedValues = new HashMap(this); >- if (listener == null) { >- listener = detailProperty >- .adaptListener(new IPropertyChangeListener() { >- public void handlePropertyChange( >- final PropertyChangeEvent event) { >- if (!isDisposed() && !updating) { >- getRealm().exec(new Runnable() { >- public void run() { >- notifyIfChanged(event.getSource()); >- } >- }); >- } >- } >- }); >- } >- super.firstListenerAdded(); >- } >- >- protected void lastListenerRemoved() { >- super.lastListenerRemoved(); >- cachedValues.clear(); >- cachedValues = null; >- } >- >- protected void hookListener(Object addedKey) { >- if (listener != null) { >- cachedValues.put(addedKey, detailProperty.getValue(addedKey)); >- detailProperty.addListener(addedKey, listener); >- } >- } >- >- protected void unhookListener(Object removedKey) { >- if (listener != null) { >- detailProperty.removeListener(removedKey, listener); >- cachedValues.remove(removedKey); >- } >- } >- >- protected Object doGet(Object key) { >- return detailProperty.getValue(key); >- } >- >- protected Object doPut(Object key, Object value) { >- Object oldValue = detailProperty.getValue(key); >- >- updating = true; >- try { >- detailProperty.setValue(key, value); >- } finally { >- updating = false; >- } >- >- notifyIfChanged(key); >- >- return oldValue; >- } >- >- private void notifyIfChanged(Object key) { >- if (cachedValues != null) { >- Object oldValue = cachedValues.get(key); >- Object newValue = detailProperty.getValue(key); >- if (!Util.equals(oldValue, newValue)) { >- cachedValues.put(key, newValue); >- fireMapChange(Diffs.createMapDiffSingleChange(key, oldValue, >- newValue)); >- } >- } >- } >- >- public Object getObserved() { >- return keySet(); >- } >- >- public synchronized void dispose() { >- if (!isDisposed()) { >- if (listener != null) { >- for (Iterator it = values().iterator(); it.hasNext();) { >- unhookListener(it.next()); >- } >- listener = null; >- } >- detailProperty = null; >- } >- >- super.dispose(); >- } >-} >Index: src/org/eclipse/core/databinding/property/value/ObservableListDelegatingValuePropertyObservableList.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/value/ObservableListDelegatingValuePropertyObservableList.java >diff -N src/org/eclipse/core/databinding/property/value/ObservableListDelegatingValuePropertyObservableList.java >--- src/org/eclipse/core/databinding/property/value/ObservableListDelegatingValuePropertyObservableList.java 8 Jan 2009 01:24:49 -0000 1.1.2.1 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,341 +0,0 @@ >-/******************************************************************************* >- * 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 >- ******************************************************************************/ >- >-package org.eclipse.core.databinding.property.value; >- >-import java.lang.reflect.Array; >-import java.util.ArrayList; >-import java.util.Collection; >-import java.util.Iterator; >-import java.util.List; >-import java.util.ListIterator; >- >-import org.eclipse.core.databinding.observable.Diffs; >-import org.eclipse.core.databinding.observable.IStaleListener; >-import org.eclipse.core.databinding.observable.ObservableTracker; >-import org.eclipse.core.databinding.observable.StaleEvent; >-import org.eclipse.core.databinding.observable.list.AbstractObservableList; >-import org.eclipse.core.databinding.observable.list.IListChangeListener; >-import org.eclipse.core.databinding.observable.list.IObservableList; >-import org.eclipse.core.databinding.observable.list.ListChangeEvent; >-import org.eclipse.core.databinding.observable.list.ListDiff; >-import org.eclipse.core.databinding.observable.list.ListDiffEntry; >- >-/** >- * @since 1.2 >- */ >-class ObservableListDelegatingValuePropertyObservableList extends >- AbstractObservableList { >- private IObservableList masterList; >- private DelegatingValueProperty detailProperty; >- private DelegatingCache cache; >- >- private IListChangeListener masterListener = new IListChangeListener() { >- public void handleListChange(ListChangeEvent event) { >- if (isDisposed()) >- return; >- >- cache.addAll(masterList); >- >- // Need both obsolete and new elements to convert diff >- ListDiff diff = convertDiff(event.diff); >- >- cache.retainAll(masterList); >- >- fireListChange(diff); >- } >- >- private ListDiff convertDiff(ListDiff diff) { >- // Convert diff to detail value >- ListDiffEntry[] masterEntries = diff.getDifferences(); >- ListDiffEntry[] detailEntries = new ListDiffEntry[masterEntries.length]; >- for (int i = 0; i < masterEntries.length; i++) { >- ListDiffEntry masterDifference = masterEntries[i]; >- int index = masterDifference.getPosition(); >- boolean addition = masterDifference.isAddition(); >- Object masterElement = masterDifference.getElement(); >- Object detailValue = cache.get(masterElement); >- >- detailEntries[i] = Diffs.createListDiffEntry(index, addition, >- detailValue); >- } >- return Diffs.createListDiff(detailEntries); >- } >- }; >- >- private IStaleListener staleListener = new IStaleListener() { >- public void handleStale(StaleEvent staleEvent) { >- fireStale(); >- } >- }; >- >- /** >- * @param masterList >- * @param valueProperty >- */ >- public ObservableListDelegatingValuePropertyObservableList( >- IObservableList masterList, DelegatingValueProperty valueProperty) { >- super(masterList.getRealm()); >- this.masterList = masterList; >- this.detailProperty = valueProperty; >- this.cache = new DelegatingCache(getRealm(), valueProperty) { >- void handleValueChange(Object masterElement, Object oldValue, >- Object newValue) { >- fireListChange(indicesOf(masterElement), oldValue, newValue); >- } >- }; >- cache.addAll(masterList); >- >- masterList.addListChangeListener(masterListener); >- masterList.addStaleListener(staleListener); >- } >- >- protected int doGetSize() { >- getterCalled(); >- return masterList.size(); >- } >- >- private void getterCalled() { >- ObservableTracker.getterCalled(this); >- } >- >- public Object get(int index) { >- getterCalled(); >- Object masterElement = masterList.get(index); >- return cache.get(masterElement); >- } >- >- public boolean add(Object o) { >- throw new UnsupportedOperationException(); >- } >- >- public boolean addAll(Collection c) { >- throw new UnsupportedOperationException(); >- } >- >- public boolean addAll(int index, Collection c) { >- throw new UnsupportedOperationException(); >- } >- >- public boolean contains(Object o) { >- getterCalled(); >- return cache.contains(o); >- } >- >- public boolean isEmpty() { >- getterCalled(); >- return masterList.isEmpty(); >- } >- >- public boolean isStale() { >- getterCalled(); >- return masterList.isStale(); >- } >- >- public Iterator iterator() { >- getterCalled(); >- return new Iterator() { >- Iterator it = masterList.iterator(); >- >- public boolean hasNext() { >- getterCalled(); >- return it.hasNext(); >- } >- >- public Object next() { >- getterCalled(); >- Object masterElement = it.next(); >- return cache.get(masterElement); >- } >- >- public void remove() { >- throw new UnsupportedOperationException(); >- } >- }; >- } >- >- public Object move(int oldIndex, int newIndex) { >- throw new UnsupportedOperationException(); >- } >- >- public boolean remove(Object o) { >- throw new UnsupportedOperationException(); >- } >- >- public boolean removeAll(Collection c) { >- throw new UnsupportedOperationException(); >- } >- >- public boolean retainAll(Collection c) { >- throw new UnsupportedOperationException(); >- } >- >- public Object[] toArray() { >- getterCalled(); >- Object[] masterElements = masterList.toArray(); >- Object[] result = new Object[masterElements.length]; >- for (int i = 0; i < result.length; i++) { >- result[i] = cache.get(masterElements[i]); >- } >- return result; >- } >- >- public Object[] toArray(Object[] a) { >- getterCalled(); >- Object[] masterElements = masterList.toArray(); >- if (a.length < masterElements.length) >- a = (Object[]) Array.newInstance(a.getClass().getComponentType(), >- masterElements.length); >- for (int i = 0; i < masterElements.length; i++) { >- a[i] = cache.get(masterElements[i]); >- } >- return a; >- } >- >- public void add(int index, Object o) { >- throw new UnsupportedOperationException(); >- } >- >- public void clear() { >- throw new UnsupportedOperationException(); >- } >- >- public ListIterator listIterator() { >- return listIterator(0); >- } >- >- public ListIterator listIterator(final int index) { >- getterCalled(); >- return new ListIterator() { >- ListIterator it = masterList.listIterator(index); >- Object lastMasterElement; >- Object lastElement; >- boolean haveIterated = false; >- >- public void add(Object arg0) { >- throw new UnsupportedOperationException(); >- } >- >- public boolean hasNext() { >- getterCalled(); >- return it.hasNext(); >- } >- >- public boolean hasPrevious() { >- getterCalled(); >- return it.hasPrevious(); >- } >- >- public Object next() { >- getterCalled(); >- lastMasterElement = it.next(); >- lastElement = cache.get(lastMasterElement); >- haveIterated = true; >- return lastElement; >- } >- >- public int nextIndex() { >- getterCalled(); >- return it.nextIndex(); >- } >- >- public Object previous() { >- getterCalled(); >- lastMasterElement = it.previous(); >- lastElement = cache.get(lastMasterElement); >- haveIterated = true; >- return lastElement; >- } >- >- public int previousIndex() { >- getterCalled(); >- return it.previousIndex(); >- } >- >- public void remove() { >- throw new UnsupportedOperationException(); >- } >- >- public void set(Object o) { >- checkRealm(); >- if (!haveIterated) >- throw new IllegalStateException(); >- >- cache.put(lastMasterElement, o); >- >- lastElement = o; >- } >- }; >- } >- >- private int[] indicesOf(Object masterElement) { >- List indices = new ArrayList(); >- >- for (ListIterator it = masterList.listIterator(); it.hasNext();) { >- if (masterElement == it.next()) >- indices.add(new Integer(it.previousIndex())); >- } >- >- int[] result = new int[indices.size()]; >- for (int i = 0; i < result.length; i++) { >- result[i] = ((Integer) indices.get(i)).intValue(); >- } >- return result; >- } >- >- private void fireListChange(int[] indices, Object oldValue, Object newValue) { >- ListDiffEntry[] differences = new ListDiffEntry[indices.length * 2]; >- for (int i = 0; i < indices.length; i++) { >- int index = indices[i]; >- differences[i * 2] = Diffs.createListDiffEntry(index, false, >- oldValue); >- differences[i * 2 + 1] = Diffs.createListDiffEntry(index, true, >- newValue); >- } >- fireListChange(Diffs.createListDiff(differences)); >- } >- >- public Object remove(int index) { >- throw new UnsupportedOperationException(); >- } >- >- public Object set(int index, Object o) { >- checkRealm(); >- Object masterElement = masterList.get(index); >- return cache.put(masterElement, o); >- } >- >- public Object getObserved() { >- return masterList; >- } >- >- public Object getElementType() { >- return detailProperty.getValueType(); >- } >- >- public synchronized void dispose() { >- if (masterList != null) { >- masterList.removeListChangeListener(masterListener); >- masterList.removeStaleListener(staleListener); >- masterList = null; >- } >- >- if (cache != null) { >- cache.dispose(); >- cache = null; >- } >- >- masterListener = null; >- detailProperty = null; >- >- super.dispose(); >- } >-} >Index: src/org/eclipse/core/databinding/property/value/ObservableMapSimpleValuePropertyObservableMap.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/value/ObservableMapSimpleValuePropertyObservableMap.java >diff -N src/org/eclipse/core/databinding/property/value/ObservableMapSimpleValuePropertyObservableMap.java >--- src/org/eclipse/core/databinding/property/value/ObservableMapSimpleValuePropertyObservableMap.java 23 Dec 2008 18:24:44 -0000 1.1.2.4 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,369 +0,0 @@ >-/******************************************************************************* >- * 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 194734) >- ******************************************************************************/ >- >-package org.eclipse.core.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; >- >-import org.eclipse.core.databinding.observable.Diffs; >-import org.eclipse.core.databinding.observable.IObserving; >-import org.eclipse.core.databinding.observable.IStaleListener; >-import org.eclipse.core.databinding.observable.ObservableTracker; >-import org.eclipse.core.databinding.observable.StaleEvent; >-import org.eclipse.core.databinding.observable.map.AbstractObservableMap; >-import org.eclipse.core.databinding.observable.map.IMapChangeListener; >-import org.eclipse.core.databinding.observable.map.IObservableMap; >-import org.eclipse.core.databinding.observable.map.MapChangeEvent; >-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.IPropertyChangeListener; >-import org.eclipse.core.databinding.property.PropertyChangeEvent; >-import org.eclipse.core.internal.databinding.IdentityWrapper; >-import org.eclipse.core.internal.databinding.Util; >- >-/** >- * @since 1.2 >- * >- */ >-class ObservableMapSimpleValuePropertyObservableMap extends >- AbstractObservableMap implements IObserving { >- private IObservableMap masterMap; >- private SimpleValueProperty detailProperty; >- >- private IObservableSet knownMasterValues; >- private Map cachedValues; >- >- private boolean updating = false; >- >- private IMapChangeListener masterListener = new IMapChangeListener() { >- public void handleMapChange(final MapChangeEvent event) { >- if (!isDisposed()) { >- updateKnownValues(); >- if (!updating) >- fireMapChange(convertDiff(event.diff)); >- } >- } >- >- 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); >- } >- >- private MapDiff convertDiff(MapDiff diff) { >- Map oldValues = new HashMap(); >- Map newValues = new HashMap(); >- >- Set addedKeys = diff.getAddedKeys(); >- for (Iterator it = addedKeys.iterator(); it.hasNext();) { >- Object key = it.next(); >- Object newSource = diff.getNewValue(key); >- Object newValue = detailProperty.getValue(newSource); >- newValues.put(key, newValue); >- } >- >- Set removedKeys = diff.getRemovedKeys(); >- for (Iterator it = removedKeys.iterator(); it.hasNext();) { >- Object key = it.next(); >- Object oldSource = diff.getOldValue(key); >- Object oldValue = detailProperty.getValue(oldSource); >- oldValues.put(key, oldValue); >- } >- >- Set changedKeys = new HashSet(diff.getChangedKeys()); >- for (Iterator it = changedKeys.iterator(); it.hasNext();) { >- Object key = it.next(); >- >- Object oldSource = diff.getOldValue(key); >- Object newSource = diff.getNewValue(key); >- >- Object oldValue = detailProperty.getValue(oldSource); >- Object newValue = detailProperty.getValue(newSource); >- >- if (Util.equals(oldValue, newValue)) { >- it.remove(); >- } else { >- oldValues.put(key, oldValue); >- newValues.put(key, newValue); >- } >- } >- >- return Diffs.createMapDiff(addedKeys, removedKeys, changedKeys, >- oldValues, newValues); >- } >- }; >- >- private IStaleListener staleListener = new IStaleListener() { >- public void handleStale(StaleEvent staleEvent) { >- fireStale(); >- } >- }; >- >- private INativePropertyListener detailListener; >- >- /** >- * @param map >- * @param valueProperty >- */ >- public ObservableMapSimpleValuePropertyObservableMap(IObservableMap map, >- SimpleValueProperty valueProperty) { >- super(map.getRealm()); >- this.masterMap = map; >- this.detailProperty = valueProperty; >- >- IPropertyChangeListener listener = new IPropertyChangeListener() { >- public void handlePropertyChange(PropertyChangeEvent event) { >- notifyIfChanged(event.getSource()); >- } >- }; >- this.detailListener = detailProperty.adaptListener(listener); >- } >- >- protected void firstListenerAdded() { >- knownMasterValues = new WritableSet(getRealm()); >- cachedValues = new HashMap(); >- 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(); >- detailProperty.removeListener(key, detailListener); >- cachedValues.remove(wrapper); >- } >- for (Iterator it = event.diff.getAdditions().iterator(); it >- .hasNext();) { >- IdentityWrapper wrapper = (IdentityWrapper) it.next(); >- Object key = wrapper.unwrap(); >- cachedValues.put(wrapper, detailProperty.getValue(key)); >- detailProperty.addListener(key, detailListener); >- } >- } >- }); >- for (Iterator it = masterMap.values().iterator(); it.hasNext();) { >- knownMasterValues.add(new IdentityWrapper(it.next())); >- } >- >- masterMap.addMapChangeListener(masterListener); >- masterMap.addStaleListener(staleListener); >- } >- >- protected void lastListenerRemoved() { >- masterMap.removeMapChangeListener(masterListener); >- masterMap.removeStaleListener(staleListener); >- if (knownMasterValues != null) { >- knownMasterValues.clear(); // removes attached listeners >- knownMasterValues.dispose(); >- knownMasterValues = null; >- } >- cachedValues.clear(); >- cachedValues = null; >- } >- >- private Set entrySet; >- >- public Set entrySet() { >- getterCalled(); >- if (entrySet == null) >- entrySet = new EntrySet(); >- return entrySet; >- } >- >- class EntrySet extends AbstractSet { >- public Iterator iterator() { >- return new Iterator() { >- Iterator it = masterMap.entrySet().iterator(); >- >- public boolean hasNext() { >- getterCalled(); >- return it.hasNext(); >- } >- >- public Object next() { >- getterCalled(); >- Map.Entry next = (Map.Entry) it.next(); >- return new MapEntry(next.getKey()); >- } >- >- public void remove() { >- it.remove(); >- } >- }; >- } >- >- public int size() { >- return masterMap.size(); >- } >- } >- >- class MapEntry implements Map.Entry { >- private Object key; >- >- MapEntry(Object key) { >- this.key = key; >- } >- >- public Object getKey() { >- getterCalled(); >- return key; >- } >- >- public Object getValue() { >- getterCalled(); >- if (!masterMap.containsKey(key)) >- return null; >- return detailProperty.getValue(masterMap.get(key)); >- } >- >- public Object setValue(Object value) { >- if (!masterMap.containsKey(key)) >- return null; >- Object source = masterMap.get(key); >- >- Object oldValue = detailProperty.getValue(source); >- >- updating = true; >- try { >- detailProperty.setValue(source, value); >- } finally { >- updating = false; >- } >- >- notifyIfChanged(source); >- >- return oldValue; >- } >- >- public boolean equals(Object o) { >- getterCalled(); >- if (o == this) >- return true; >- if (o == null) >- return false; >- if (!(o instanceof Map.Entry)) >- return false; >- Map.Entry that = (Map.Entry) o; >- return Util.equals(this.getKey(), that.getKey()) >- && Util.equals(this.getValue(), that.getValue()); >- } >- >- public int hashCode() { >- getterCalled(); >- Object value = getValue(); >- return (key == null ? 0 : key.hashCode()) >- ^ (value == null ? 0 : value.hashCode()); >- } >- } >- >- public Object put(Object key, Object value) { >- if (!masterMap.containsKey(key)) >- return null; >- Object masterValue = masterMap.get(key); >- Object oldValue = detailProperty.getValue(key); >- detailProperty.setValue(masterValue, value); >- notifyIfChanged(masterValue); >- return oldValue; >- } >- >- private void notifyIfChanged(Object masterValue) { >- if (cachedValues != null) { >- final Set keys = keysFor(masterValue); >- >- final Object oldValue = cachedValues.get(new IdentityWrapper( >- masterValue)); >- final Object newValue = detailProperty.getValue(masterValue); >- >- if (!Util.equals(oldValue, newValue)) { >- cachedValues.put(new IdentityWrapper(masterValue), newValue); >- fireMapChange(new MapDiff() { >- public Set getAddedKeys() { >- return Collections.EMPTY_SET; >- } >- >- public Set getChangedKeys() { >- return keys; >- } >- >- public Set getRemovedKeys() { >- return Collections.EMPTY_SET; >- } >- >- public Object getNewValue(Object key) { >- return newValue; >- } >- >- public Object getOldValue(Object key) { >- return oldValue; >- } >- }); >- } >- } >- } >- >- private Set keysFor(Object value) { >- Set keys = new HashSet(); >- >- for (Iterator it = masterMap.entrySet().iterator(); it.hasNext();) { >- Map.Entry entry = (Entry) it.next(); >- if (entry.getValue() == value) { >- keys.add(entry.getKey()); >- } >- } >- >- return keys; >- } >- >- public boolean isStale() { >- getterCalled(); >- return masterMap.isStale(); >- } >- >- private void getterCalled() { >- ObservableTracker.getterCalled(this); >- } >- >- public Object getObserved() { >- return masterMap; >- } >- >- public synchronized void dispose() { >- if (masterMap != null) { >- masterMap.removeMapChangeListener(masterListener); >- masterMap = null; >- } >- if (knownMasterValues != null) { >- knownMasterValues.clear(); // detaches listeners >- knownMasterValues.dispose(); >- knownMasterValues = null; >- } >- >- masterListener = null; >- detailListener = null; >- detailProperty = null; >- cachedValues = null; >- >- super.dispose(); >- } >-} >Index: src/org/eclipse/core/databinding/property/value/SimpleValueProperty.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.databinding/src/org/eclipse/core/databinding/property/value/Attic/SimpleValueProperty.java,v >retrieving revision 1.1.2.8 >diff -u -r1.1.2.8 SimpleValueProperty.java >--- src/org/eclipse/core/databinding/property/value/SimpleValueProperty.java 8 Jan 2009 01:24:49 -0000 1.1.2.8 >+++ src/org/eclipse/core/databinding/property/value/SimpleValueProperty.java 16 Jan 2009 15:28:52 -0000 >@@ -19,6 +19,10 @@ > import org.eclipse.core.databinding.observable.value.IObservableValue; > import org.eclipse.core.databinding.property.INativePropertyListener; > import org.eclipse.core.databinding.property.IPropertyChangeListener; >+import org.eclipse.core.internal.databinding.property.value.ObservableListSimpleValuePropertyObservableList; >+import org.eclipse.core.internal.databinding.property.value.ObservableMapSimpleValuePropertyObservableMap; >+import org.eclipse.core.internal.databinding.property.value.ObservableSetSimpleValuePropertyObservableMap; >+import org.eclipse.core.internal.databinding.property.value.SimpleValuePropertyObservableValue; > > /** > * Simplified abstract implementation of IValueProperty. This class takes care >@@ -49,7 +53,7 @@ > * @return the current value of the source's value property > * @noreference This method is not intended to be referenced by clients. > */ >- protected final Object getValue(Object source) { >+ public final Object getValue(Object source) { > return source == null ? null : doGetValue(source); > } > >@@ -72,7 +76,7 @@ > * the new value > * @noreference This method is not intended to be referenced by clients. > */ >- protected final void setValue(Object source, Object value) { >+ public final void setValue(Object source, Object value) { > if (source != null) > doSetValue(source, value); > } >@@ -95,7 +99,7 @@ > * ISetProperty or IMapProperty) depending on the property. > * @noreference This method is not intended to be referenced by clients. > */ >- protected abstract INativePropertyListener adaptListener( >+ public abstract INativePropertyListener adaptListener( > IPropertyChangeListener listener); > > /** >@@ -111,7 +115,7 @@ > * {@link #adaptListener(IPropertyChangeListener)}. > * @noreference This method is not intended to be referenced by clients. > */ >- protected final void addListener(Object source, >+ public final void addListener(Object source, > INativePropertyListener listener) { > if (source != null) > doAddListener(source, listener); >@@ -146,7 +150,7 @@ > * {@link #adaptListener(IPropertyChangeListener)}. > * @noreference This method is not intended to be referenced by clients. > */ >- protected final void removeListener(Object source, >+ public final void removeListener(Object source, > INativePropertyListener listener) { > if (source != null) > doRemoveListener(source, listener); >Index: src/org/eclipse/core/databinding/property/value/SimpleValuePropertyObservableValue.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/value/SimpleValuePropertyObservableValue.java >diff -N src/org/eclipse/core/databinding/property/value/SimpleValuePropertyObservableValue.java >--- src/org/eclipse/core/databinding/property/value/SimpleValuePropertyObservableValue.java 14 Jan 2009 23:51:10 -0000 1.1.2.5 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,130 +0,0 @@ >-/******************************************************************************* >- * 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 194734) >- ******************************************************************************/ >- >-package org.eclipse.core.databinding.property.value; >- >-import org.eclipse.core.databinding.observable.Diffs; >-import org.eclipse.core.databinding.observable.Realm; >-import org.eclipse.core.databinding.observable.value.AbstractObservableValue; >-import org.eclipse.core.databinding.observable.value.ValueDiff; >-import org.eclipse.core.databinding.property.INativePropertyListener; >-import org.eclipse.core.databinding.property.IProperty; >-import org.eclipse.core.databinding.property.IPropertyChangeListener; >-import org.eclipse.core.databinding.property.IPropertyObservable; >-import org.eclipse.core.databinding.property.PropertyChangeEvent; >-import org.eclipse.core.internal.databinding.Util; >- >-/** >- * @since 1.2 >- * >- */ >-class SimpleValuePropertyObservableValue extends AbstractObservableValue >- implements IPropertyObservable { >- private Object source; >- private SimpleValueProperty property; >- >- private boolean updating = false; >- private Object cachedValue; >- >- private INativePropertyListener listener; >- >- /** >- * @param realm >- * @param source >- * @param property >- */ >- public SimpleValuePropertyObservableValue(Realm realm, Object source, >- SimpleValueProperty property) { >- super(realm); >- this.source = source; >- this.property = property; >- } >- >- protected void firstListenerAdded() { >- if (!isDisposed()) { >- cachedValue = property.getValue(source); >- if (listener == null) { >- listener = property >- .adaptListener(new IPropertyChangeListener() { >- public void handlePropertyChange( >- final PropertyChangeEvent event) { >- if (!isDisposed() && !updating) { >- getRealm().exec(new Runnable() { >- public void run() { >- notifyIfChanged((ValueDiff) event.diff); >- } >- }); >- } >- } >- }); >- } >- property.addListener(source, listener); >- } >- } >- >- protected void lastListenerRemoved() { >- if (listener != null) { >- property.removeListener(source, listener); >- } >- cachedValue = null; >- } >- >- protected Object doGetValue() { >- notifyIfChanged(null); >- return property.getValue(source); >- } >- >- protected void doSetValue(Object value) { >- updating = true; >- try { >- property.setValue(source, value); >- } finally { >- updating = false; >- } >- >- notifyIfChanged(null); >- } >- >- private void notifyIfChanged(ValueDiff diff) { >- if (hasListeners()) { >- Object oldValue = cachedValue; >- Object newValue = cachedValue = property.getValue(source); >- if (diff == null) >- diff = Diffs.createValueDiff(oldValue, newValue); >- if (hasListeners() && !Util.equals(oldValue, newValue)) { >- fireValueChange(diff); >- } >- } >- } >- >- public Object getValueType() { >- return property.getValueType(); >- } >- >- public Object getObserved() { >- return source; >- } >- >- public IProperty getProperty() { >- return property; >- } >- >- public synchronized void dispose() { >- if (!isDisposed()) { >- if (listener != null) >- property.removeListener(source, listener); >- source = null; >- property = null; >- listener = null; >- } >- super.dispose(); >- } >-} >Index: src/org/eclipse/core/databinding/property/value/DelegatingValueProperty.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.databinding/src/org/eclipse/core/databinding/property/value/Attic/DelegatingValueProperty.java,v >retrieving revision 1.1.2.2 >diff -u -r1.1.2.2 DelegatingValueProperty.java >--- src/org/eclipse/core/databinding/property/value/DelegatingValueProperty.java 14 Jan 2009 23:51:10 -0000 1.1.2.2 >+++ src/org/eclipse/core/databinding/property/value/DelegatingValueProperty.java 16 Jan 2009 15:28:52 -0000 >@@ -18,6 +18,9 @@ > import org.eclipse.core.databinding.observable.value.IObservableValue; > import org.eclipse.core.databinding.property.INativePropertyListener; > import org.eclipse.core.databinding.property.IPropertyChangeListener; >+import org.eclipse.core.internal.databinding.property.value.ObservableListDelegatingValuePropertyObservableList; >+import org.eclipse.core.internal.databinding.property.value.ObservableMapDelegatingValuePropertyObservableMap; >+import org.eclipse.core.internal.databinding.property.value.ObservableSetDelegatingValuePropertyObservableMap; > > /** > * @since 1.2 >@@ -35,7 +38,16 @@ > this.valueType = valueType; > } > >- protected final IValueProperty getDelegate(Object source) { >+ /** >+ * Returns the property to delegate to for the specified source object. >+ * Repeated calls to this method with the same source object returns the >+ * same delegate instance. >+ * >+ * @param source >+ * the property source (may be null) >+ * @return the property to delegate to for the specified source object. >+ */ >+ public final IValueProperty getDelegate(Object source) { > if (source == null) > return null; > IValueProperty delegate = doGetDelegate(source); >@@ -90,7 +102,7 @@ > protected void doSetValue(Object source, Object value) { > } > >- protected INativePropertyListener adaptListener( >+ public INativePropertyListener adaptListener( > IPropertyChangeListener listener) { > return null; > } >Index: src/org/eclipse/core/databinding/property/list/DelegatingListProperty.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.databinding/src/org/eclipse/core/databinding/property/list/Attic/DelegatingListProperty.java,v >retrieving revision 1.1.2.2 >diff -u -r1.1.2.2 DelegatingListProperty.java >--- src/org/eclipse/core/databinding/property/list/DelegatingListProperty.java 14 Jan 2009 23:51:10 -0000 1.1.2.2 >+++ src/org/eclipse/core/databinding/property/list/DelegatingListProperty.java 16 Jan 2009 15:28:52 -0000 >@@ -37,7 +37,16 @@ > this.nullProperty = new NullListProperty(); > } > >- protected final IListProperty getDelegate(Object source) { >+ /** >+ * Returns the property to delegate to for the specified source object. >+ * Repeated calls to this method with the same source object returns the >+ * same delegate instance. >+ * >+ * @param source >+ * the property source (may be null) >+ * @return the property to delegate to for the specified source object. >+ */ >+ public final IListProperty getDelegate(Object source) { > if (source == null) > return null; > IListProperty delegate = doGetDelegate(source); >@@ -46,6 +55,15 @@ > return delegate; > } > >+ /** >+ * Returns the property to delegate to for the specified source object. >+ * Implementers must ensure that repeated calls to this method with the same >+ * source object returns the same delegate instance. >+ * >+ * @param source >+ * the property source >+ * @return the property to delegate to for the specified source object. >+ */ > protected abstract IListProperty doGetDelegate(Object source); > > public Object getElementType() { >@@ -68,7 +86,7 @@ > protected void doSetList(Object source, List list, ListDiff diff) { > } > >- protected INativePropertyListener adaptListener( >+ public INativePropertyListener adaptListener( > IPropertyChangeListener listener) { > return null; > } >Index: src/org/eclipse/core/databinding/property/list/SimpleListPropertyObservableList.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/list/SimpleListPropertyObservableList.java >diff -N src/org/eclipse/core/databinding/property/list/SimpleListPropertyObservableList.java >--- src/org/eclipse/core/databinding/property/list/SimpleListPropertyObservableList.java 14 Jan 2009 23:51:10 -0000 1.1.2.5 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,666 +0,0 @@ >-/******************************************************************************* >- * 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 194734) >- ******************************************************************************/ >- >-package org.eclipse.core.databinding.property.list; >- >-import java.util.ArrayList; >-import java.util.Collection; >-import java.util.Collections; >-import java.util.ConcurrentModificationException; >-import java.util.Iterator; >-import java.util.List; >-import java.util.ListIterator; >- >-import org.eclipse.core.databinding.observable.Diffs; >-import org.eclipse.core.databinding.observable.ObservableTracker; >-import org.eclipse.core.databinding.observable.Realm; >-import org.eclipse.core.databinding.observable.list.AbstractObservableList; >-import org.eclipse.core.databinding.observable.list.ListDiff; >-import org.eclipse.core.databinding.observable.list.ListDiffEntry; >-import org.eclipse.core.databinding.property.IProperty; >-import org.eclipse.core.databinding.property.INativePropertyListener; >-import org.eclipse.core.databinding.property.IPropertyChangeListener; >-import org.eclipse.core.databinding.property.IPropertyObservable; >-import org.eclipse.core.databinding.property.PropertyChangeEvent; >- >-/** >- * @since 1.2 >- * >- */ >-class SimpleListPropertyObservableList extends AbstractObservableList implements >- IPropertyObservable { >- private Object source; >- private SimpleListProperty property; >- >- private volatile boolean updating = false; >- >- private volatile int modCount = 0; >- >- private INativePropertyListener listener; >- >- private List cachedList; >- >- /** >- * @param realm >- * @param source >- * @param property >- */ >- public SimpleListPropertyObservableList(Realm realm, Object source, >- SimpleListProperty property) { >- super(realm); >- this.source = source; >- this.property = property; >- } >- >- protected void firstListenerAdded() { >- if (!isDisposed()) { >- cachedList = getList(); >- >- if (listener == null) { >- listener = property >- .adaptListener(new IPropertyChangeListener() { >- public void handlePropertyChange( >- final PropertyChangeEvent event) { >- modCount++; >- if (!isDisposed() && !updating) { >- getRealm().exec(new Runnable() { >- public void run() { >- notifyIfChanged((ListDiff) event.diff); >- } >- }); >- } >- } >- }); >- } >- property.addListener(source, listener); >- } >- } >- >- protected void lastListenerRemoved() { >- if (listener != null) { >- property.removeListener(source, listener); >- } >- >- cachedList = null; >- } >- >- private void getterCalled() { >- ObservableTracker.getterCalled(this); >- } >- >- public Object getElementType() { >- return property.getElementType(); >- } >- >- // Queries >- >- private List getList() { >- return property.getList(source); >- } >- >- protected int doGetSize() { >- return getList().size(); >- } >- >- public boolean contains(Object o) { >- getterCalled(); >- return getList().contains(o); >- } >- >- public boolean containsAll(Collection c) { >- getterCalled(); >- return getList().containsAll(c); >- } >- >- public Object get(int index) { >- getterCalled(); >- return getList().get(index); >- } >- >- public int indexOf(Object o) { >- getterCalled(); >- return getList().indexOf(o); >- } >- >- public boolean isEmpty() { >- getterCalled(); >- return getList().isEmpty(); >- } >- >- public int lastIndexOf(Object o) { >- getterCalled(); >- return getList().lastIndexOf(o); >- } >- >- public Object[] toArray() { >- getterCalled(); >- return getList().toArray(); >- } >- >- public Object[] toArray(Object[] a) { >- getterCalled(); >- return getList().toArray(a); >- } >- >- // Single change operations >- >- public boolean add(Object o) { >- checkRealm(); >- add(getList().size(), o); >- return true; >- } >- >- public void add(int index, Object o) { >- checkRealm(); >- boolean wasUpdating = updating; >- updating = true; >- List list = new ArrayList(getList()); >- list.add(index, o); >- ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry(index, >- true, o)); >- try { >- property.setList(source, list, diff); >- modCount++; >- } finally { >- updating = wasUpdating; >- } >- >- notifyIfChanged(null); >- } >- >- public Iterator iterator() { >- getterCalled(); >- return new Iterator() { >- int expectedModCount = modCount; >- List list = new ArrayList(getList()); >- ListIterator iterator = list.listIterator(); >- >- Object lastElement = null; >- int lastIndex = -1; >- >- public boolean hasNext() { >- getterCalled(); >- checkForComodification(); >- return iterator.hasNext(); >- } >- >- public Object next() { >- getterCalled(); >- checkForComodification(); >- Object next = lastElement = iterator.next(); >- lastIndex = iterator.previousIndex(); >- return next; >- } >- >- public void remove() { >- checkRealm(); >- checkForComodification(); >- if (lastIndex == -1) >- throw new IllegalStateException(); >- >- iterator.remove(); // stay in sync >- ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry( >- lastIndex, false, lastElement)); >- >- boolean wasUpdating = updating; >- updating = true; >- try { >- property.setList(source, list, diff); >- modCount++; >- } finally { >- updating = wasUpdating; >- } >- >- notifyIfChanged(null); >- >- lastElement = null; >- lastIndex = -1; >- >- expectedModCount = modCount; >- } >- >- private void checkForComodification() { >- if (expectedModCount != modCount) >- throw new ConcurrentModificationException(); >- } >- }; >- } >- >- public Object move(int oldIndex, int newIndex) { >- checkRealm(); >- >- List list = getList(); >- int size = list.size(); >- if (oldIndex < 0 || oldIndex >= size || newIndex < 0 >- || newIndex >= size) >- throw new IndexOutOfBoundsException(); >- >- if (oldIndex == newIndex) >- return list.get(oldIndex); >- >- list = new ArrayList(list); >- Object element = list.remove(oldIndex); >- list.add(newIndex, element); >- >- ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry( >- oldIndex, false, element), Diffs.createListDiffEntry(newIndex, >- true, element)); >- >- boolean wasUpdating = updating; >- updating = true; >- try { >- property.setList(source, list, diff); >- modCount++; >- } finally { >- updating = wasUpdating; >- } >- >- notifyIfChanged(null); >- >- return element; >- } >- >- public boolean remove(Object o) { >- checkRealm(); >- >- int index = getList().indexOf(o); >- if (index == -1) >- return false; >- >- remove(index); >- >- return true; >- } >- >- public ListIterator listIterator() { >- return listIterator(0); >- } >- >- public ListIterator listIterator(final int index) { >- getterCalled(); >- return new ListIterator() { >- int expectedModCount = modCount; >- List list = new ArrayList(getList()); >- ListIterator iterator = list.listIterator(index); >- >- Object lastElement = null; >- int lastIndex = -1; >- >- public boolean hasNext() { >- getterCalled(); >- checkForComodification(); >- return iterator.hasNext(); >- } >- >- public int nextIndex() { >- getterCalled(); >- checkForComodification(); >- return iterator.nextIndex(); >- } >- >- public Object next() { >- getterCalled(); >- checkForComodification(); >- lastElement = iterator.next(); >- lastIndex = iterator.previousIndex(); >- return lastElement; >- } >- >- public boolean hasPrevious() { >- getterCalled(); >- checkForComodification(); >- return iterator.hasPrevious(); >- } >- >- public int previousIndex() { >- getterCalled(); >- checkForComodification(); >- return iterator.previousIndex(); >- } >- >- public Object previous() { >- getterCalled(); >- checkForComodification(); >- lastElement = iterator.previous(); >- lastIndex = iterator.nextIndex(); >- return lastElement; >- } >- >- public void add(Object o) { >- checkRealm(); >- checkForComodification(); >- int index = iterator.nextIndex(); >- >- iterator.add(o); // keep in sync >- >- List list = getList(); >- list.add(index, o); >- ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry( >- index, true, o)); >- boolean wasUpdating = updating; >- updating = true; >- try { >- property.setList(source, list, diff); >- modCount++; >- } finally { >- updating = wasUpdating; >- } >- >- notifyIfChanged(null); >- >- lastElement = null; >- lastIndex = -1; >- expectedModCount = modCount; >- } >- >- public void set(Object o) { >- checkRealm(); >- checkForComodification(); >- >- iterator.set(o); >- ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry( >- lastIndex, false, lastElement), Diffs >- .createListDiffEntry(lastIndex, true, o)); >- >- boolean wasUpdating = updating; >- updating = true; >- try { >- property.setList(source, list, diff); >- modCount++; >- } finally { >- updating = wasUpdating; >- } >- >- notifyIfChanged(null); >- >- lastElement = o; >- expectedModCount = modCount; >- } >- >- public void remove() { >- checkRealm(); >- checkForComodification(); >- if (lastIndex == -1) >- throw new IllegalStateException(); >- >- iterator.remove(); // keep in sync >- ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry( >- lastIndex, false, lastElement)); >- >- boolean wasUpdating = updating; >- updating = true; >- try { >- property.setList(source, list, diff); >- modCount++; >- } finally { >- updating = wasUpdating; >- } >- >- notifyIfChanged(null); >- >- lastElement = null; >- lastIndex = -1; >- expectedModCount = modCount; >- } >- >- private void checkForComodification() { >- if (expectedModCount != modCount) >- throw new ConcurrentModificationException(); >- } >- }; >- } >- >- public Object remove(int index) { >- checkRealm(); >- >- List list = new ArrayList(getList()); >- Object element = list.remove(index); >- ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry(index, >- false, element)); >- >- boolean wasUpdating = updating; >- updating = true; >- try { >- property.setList(source, list, diff); >- modCount++; >- } finally { >- updating = wasUpdating; >- } >- >- notifyIfChanged(null); >- >- return element; >- } >- >- public Object set(int index, Object o) { >- checkRealm(); >- >- List list = new ArrayList(getList()); >- Object oldElement = list.set(index, o); >- >- ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry(index, >- false, oldElement), Diffs.createListDiffEntry(index, true, o)); >- >- boolean wasUpdating = updating; >- updating = true; >- try { >- property.setList(source, list, diff); >- modCount++; >- } finally { >- updating = wasUpdating; >- } >- >- notifyIfChanged(null); >- >- return oldElement; >- } >- >- public List subList(int fromIndex, int toIndex) { >- getterCalled(); >- return Collections.unmodifiableList(getList().subList(fromIndex, >- toIndex)); >- } >- >- // Bulk change operations >- >- public boolean addAll(Collection c) { >- checkRealm(); >- >- return addAll(getList().size(), c); >- } >- >- public boolean addAll(int index, Collection c) { >- checkRealm(); >- >- if (c.isEmpty()) >- return false; >- >- List list = new ArrayList(getList()); >- list.addAll(index, c); >- >- ListDiffEntry[] entries = new ListDiffEntry[c.size()]; >- int offsetIndex = 0; >- for (Iterator it = c.iterator(); it.hasNext();) { >- Object element = it.next(); >- entries[offsetIndex] = Diffs.createListDiffEntry(index >- + offsetIndex, true, element); >- offsetIndex++; >- } >- ListDiff diff = Diffs.createListDiff(entries); >- >- boolean wasUpdating = updating; >- updating = true; >- try { >- property.setList(source, list, diff); >- modCount++; >- } finally { >- updating = wasUpdating; >- } >- >- notifyIfChanged(null); >- >- return true; >- } >- >- public boolean removeAll(Collection c) { >- checkRealm(); >- >- if (c.isEmpty()) >- return false; >- >- List list = getList(); >- if (list.isEmpty()) >- return false; >- >- list = new ArrayList(list); >- List entries = new ArrayList(); >- ListDiff diff; >- >- boolean wasUpdating = updating; >- updating = true; >- try { >- for (ListIterator it = list.listIterator(); it.hasNext();) { >- Object element = it.next(); >- int index = it.previousIndex(); >- if (c.contains(element)) { >- it.remove(); >- entries.add(Diffs >- .createListDiffEntry(index, false, element)); >- } >- } >- if (entries.isEmpty()) >- return false; >- >- diff = Diffs.createListDiff((ListDiffEntry[]) entries >- .toArray(new ListDiffEntry[entries.size()])); >- property.setList(source, list, diff); >- modCount++; >- } finally { >- updating = wasUpdating; >- } >- >- notifyIfChanged(null); >- >- return !diff.isEmpty(); >- } >- >- public boolean retainAll(Collection c) { >- checkRealm(); >- >- List list = getList(); >- if (list.isEmpty()) >- return false; >- >- if (c.isEmpty()) { >- clear(); >- return true; >- } >- >- list = new ArrayList(list); >- List entries = new ArrayList(); >- ListDiff diff; >- >- boolean wasUpdating = updating; >- updating = true; >- try { >- for (ListIterator it = list.listIterator(); it.hasNext();) { >- Object element = it.next(); >- int index = it.previousIndex(); >- if (!c.contains(element)) { >- it.remove(); >- entries.add(Diffs >- .createListDiffEntry(index, false, element)); >- } >- } >- if (entries.isEmpty()) >- return false; >- >- diff = Diffs.createListDiff((ListDiffEntry[]) entries >- .toArray(new ListDiffEntry[entries.size()])); >- property.setList(source, list, diff); >- modCount++; >- } finally { >- updating = wasUpdating; >- } >- >- notifyIfChanged(null); >- >- return !diff.isEmpty(); >- } >- >- public void clear() { >- checkRealm(); >- >- List list = getList(); >- if (list.isEmpty()) >- return; >- >- List entries = new ArrayList(); >- for (Iterator it = list.iterator(); it.hasNext();) { >- // always report 0 as the remove index >- entries.add(Diffs.createListDiffEntry(0, false, it.next())); >- } >- >- ListDiff diff = Diffs.createListDiff((ListDiffEntry[]) entries >- .toArray(new ListDiffEntry[entries.size()])); >- boolean wasUpdating = updating; >- updating = true; >- try { >- property.setList(source, Collections.EMPTY_LIST, diff); >- modCount++; >- } finally { >- updating = wasUpdating; >- } >- >- notifyIfChanged(null); >- } >- >- private void notifyIfChanged(ListDiff diff) { >- if (hasListeners()) { >- List oldList = cachedList; >- List newList = cachedList = property.getList(source); >- if (diff == null) >- diff = Diffs.computeListDiff(oldList, newList); >- if (!diff.isEmpty()) { >- fireListChange(diff); >- } >- } >- } >- >- public boolean equals(Object o) { >- getterCalled(); >- return getList().equals(o); >- } >- >- public int hashCode() { >- getterCalled(); >- return getList().hashCode(); >- } >- >- public Object getObserved() { >- return source; >- } >- >- public IProperty getProperty() { >- return property; >- } >- >- public synchronized void dispose() { >- if (!isDisposed()) { >- if (listener != null) >- property.removeListener(source, listener); >- property = null; >- source = null; >- listener = null; >- } >- super.dispose(); >- } >-} >Index: src/org/eclipse/core/databinding/property/list/SimpleListProperty.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.databinding/src/org/eclipse/core/databinding/property/list/Attic/SimpleListProperty.java,v >retrieving revision 1.1.2.8 >diff -u -r1.1.2.8 SimpleListProperty.java >--- src/org/eclipse/core/databinding/property/list/SimpleListProperty.java 8 Jan 2009 01:24:50 -0000 1.1.2.8 >+++ src/org/eclipse/core/databinding/property/list/SimpleListProperty.java 16 Jan 2009 15:28:52 -0000 >@@ -20,6 +20,7 @@ > import org.eclipse.core.databinding.observable.list.ListDiff; > import org.eclipse.core.databinding.property.INativePropertyListener; > import org.eclipse.core.databinding.property.IPropertyChangeListener; >+import org.eclipse.core.internal.databinding.property.list.SimpleListPropertyObservableList; > > /** > * Simplified abstract implementation of IListProperty. This class takes care of >@@ -58,7 +59,7 @@ > * list property > * @noreference This method is not intended to be referenced by clients. > */ >- protected final List getList(Object source) { >+ public final List getList(Object source) { > if (source == null) > return Collections.EMPTY_LIST; > return Collections.unmodifiableList(doGetList(source)); >@@ -87,7 +88,7 @@ > * a diff describing the change > * @noreference This method is not intended to be referenced by clients. > */ >- protected final void setList(Object source, List list, ListDiff diff) { >+ public final void setList(Object source, List list, ListDiff diff) { > if (source != null && !diff.isEmpty()) > doSetList(source, list, diff); > } >@@ -122,7 +123,7 @@ > * @noreference This method is not intended to be referenced by clients. > * @noreference This method is not intended to be referenced by clients. > */ >- protected abstract INativePropertyListener adaptListener( >+ public abstract INativePropertyListener adaptListener( > IPropertyChangeListener listener); > > /** >@@ -138,7 +139,7 @@ > * {@link #adaptListener(IPropertyChangeListener)}. > * @noreference This method is not intended to be referenced by clients. > */ >- protected final void addListener(Object source, >+ public final void addListener(Object source, > INativePropertyListener listener) { > if (source != null) > doAddListener(source, listener); >@@ -173,7 +174,7 @@ > * {@link #adaptListener(IPropertyChangeListener)}. > * @noreference This method is not intended to be referenced by clients. > */ >- protected final void removeListener(Object source, >+ public final void removeListener(Object source, > INativePropertyListener listener) { > if (source != null) > doRemoveListener(source, listener); >Index: src/org/eclipse/core/databinding/property/set/SimpleSetPropertyObservableSet.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/set/SimpleSetPropertyObservableSet.java >diff -N src/org/eclipse/core/databinding/property/set/SimpleSetPropertyObservableSet.java >--- src/org/eclipse/core/databinding/property/set/SimpleSetPropertyObservableSet.java 14 Jan 2009 23:51:10 -0000 1.1.2.5 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,407 +0,0 @@ >-/******************************************************************************* >- * 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 194734) >- ******************************************************************************/ >- >-package org.eclipse.core.databinding.property.set; >- >-import java.util.Collection; >-import java.util.Collections; >-import java.util.ConcurrentModificationException; >-import java.util.HashSet; >-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.SetDiff; >-import org.eclipse.core.databinding.property.IProperty; >-import org.eclipse.core.databinding.property.INativePropertyListener; >-import org.eclipse.core.databinding.property.IPropertyChangeListener; >-import org.eclipse.core.databinding.property.IPropertyObservable; >-import org.eclipse.core.databinding.property.PropertyChangeEvent; >- >-/** >- * @since 1.2 >- * >- */ >-class SimpleSetPropertyObservableSet extends AbstractObservableSet implements >- IPropertyObservable { >- private Object source; >- private SimpleSetProperty property; >- >- private volatile boolean updating = false; >- >- private volatile int modCount = 0; >- >- private INativePropertyListener listener; >- >- private Set cachedSet; >- >- /** >- * @param realm >- * @param source >- * @param property >- */ >- public SimpleSetPropertyObservableSet(Realm realm, Object source, >- SimpleSetProperty property) { >- super(realm); >- this.source = source; >- this.property = property; >- } >- >- protected void firstListenerAdded() { >- if (!isDisposed()) { >- cachedSet = getSet(); >- >- if (listener == null) { >- listener = property >- .adaptListener(new IPropertyChangeListener() { >- public void handlePropertyChange( >- final PropertyChangeEvent event) { >- modCount++; >- if (!isDisposed() && !updating) { >- getRealm().exec(new Runnable() { >- public void run() { >- notifyIfChanged((SetDiff) event.diff); >- } >- }); >- } >- } >- }); >- } >- property.addListener(source, listener); >- } >- } >- >- protected void lastListenerRemoved() { >- if (listener != null) { >- property.removeListener(source, listener); >- } >- >- cachedSet = null; >- } >- >- protected Set getWrappedSet() { >- return getSet(); >- } >- >- public Object getElementType() { >- return property.getElementType(); >- } >- >- // Queries >- >- private Set getSet() { >- return property.getSet(source); >- } >- >- public boolean contains(Object o) { >- getterCalled(); >- return getSet().contains(o); >- } >- >- public boolean containsAll(Collection c) { >- getterCalled(); >- return getSet().containsAll(c); >- } >- >- public boolean isEmpty() { >- getterCalled(); >- return getSet().isEmpty(); >- } >- >- public Object[] toArray() { >- getterCalled(); >- return getSet().toArray(); >- } >- >- public Object[] toArray(Object[] a) { >- getterCalled(); >- return getSet().toArray(a); >- } >- >- // Single change operations >- >- public boolean add(Object o) { >- checkRealm(); >- >- Set set = new HashSet(getSet()); >- if (!set.add(o)) >- return false; >- >- SetDiff diff = Diffs.createSetDiff(Collections.singleton(o), >- Collections.EMPTY_SET); >- >- boolean wasUpdating = updating; >- updating = true; >- try { >- property.setSet(source, set, diff); >- modCount++; >- } finally { >- updating = wasUpdating; >- } >- >- notifyIfChanged(null); >- >- return true; >- } >- >- public Iterator iterator() { >- getterCalled(); >- return new Iterator() { >- int expectedModCount = modCount; >- Set set = new HashSet(getSet()); >- Iterator iterator = set.iterator(); >- Object last = null; >- >- public boolean hasNext() { >- getterCalled(); >- checkForComodification(); >- return iterator.hasNext(); >- } >- >- public Object next() { >- getterCalled(); >- checkForComodification(); >- last = iterator.next(); >- return last; >- } >- >- public void remove() { >- checkRealm(); >- checkForComodification(); >- >- iterator.remove(); // stay in sync >- SetDiff diff = Diffs.createSetDiff(Collections.EMPTY_SET, >- Collections.singleton(last)); >- >- boolean wasUpdating = updating; >- updating = true; >- try { >- property.setSet(source, set, diff); >- modCount++; >- } finally { >- updating = wasUpdating; >- } >- >- notifyIfChanged(null); >- >- last = null; >- expectedModCount = modCount; >- } >- >- private void checkForComodification() { >- if (expectedModCount != modCount) >- throw new ConcurrentModificationException(); >- } >- }; >- } >- >- public boolean remove(Object o) { >- getterCalled(); >- >- Set set = new HashSet(getSet()); >- if (!set.remove(o)) >- return false; >- >- SetDiff diff = Diffs.createSetDiff(Collections.EMPTY_SET, Collections >- .singleton(o)); >- >- boolean wasUpdating = updating; >- updating = true; >- try { >- property.setSet(source, set, diff); >- modCount++; >- } finally { >- updating = wasUpdating; >- } >- >- notifyIfChanged(null); >- >- return true; >- } >- >- // Bulk change operations >- >- public boolean addAll(Collection c) { >- getterCalled(); >- >- if (c.isEmpty()) >- return false; >- >- Set set = new HashSet(getSet()); >- >- Set additions = new HashSet(c); >- for (Iterator it = c.iterator(); it.hasNext();) { >- Object element = it.next(); >- if (set.add(element)) >- additions.add(element); >- } >- >- if (additions.isEmpty()) >- return false; >- >- SetDiff diff = Diffs.createSetDiff(additions, Collections.EMPTY_SET); >- >- boolean wasUpdating = updating; >- updating = true; >- try { >- property.setSet(source, set, diff); >- modCount++; >- } finally { >- updating = wasUpdating; >- } >- >- notifyIfChanged(null); >- >- return true; >- } >- >- public boolean removeAll(Collection c) { >- getterCalled(); >- >- Set set = getSet(); >- if (set.isEmpty()) >- return false; >- if (c.isEmpty()) >- return false; >- >- set = new HashSet(set); >- >- Set removals = new HashSet(c); >- for (Iterator it = c.iterator(); it.hasNext();) { >- Object element = it.next(); >- if (set.remove(element)) >- removals.add(element); >- } >- >- if (removals.isEmpty()) >- return false; >- >- SetDiff diff = Diffs.createSetDiff(Collections.EMPTY_SET, removals); >- >- boolean wasUpdating = updating; >- updating = true; >- try { >- property.setSet(source, set, diff); >- modCount++; >- } finally { >- updating = wasUpdating; >- } >- >- notifyIfChanged(null); >- >- return true; >- } >- >- public boolean retainAll(Collection c) { >- getterCalled(); >- >- Set set = getSet(); >- if (set.isEmpty()) >- return false; >- >- if (c.isEmpty()) { >- clear(); >- return true; >- } >- >- set = new HashSet(set); >- >- Set removals = new HashSet(); >- for (Iterator it = set.iterator(); it.hasNext();) { >- Object element = it.next(); >- if (!c.contains(element)) { >- it.remove(); >- removals.add(element); >- } >- } >- >- if (removals.isEmpty()) >- return false; >- >- SetDiff diff = Diffs.createSetDiff(Collections.EMPTY_SET, removals); >- >- boolean wasUpdating = updating; >- updating = true; >- try { >- property.setSet(source, set, diff); >- modCount++; >- } finally { >- updating = wasUpdating; >- } >- >- notifyIfChanged(null); >- >- return true; >- } >- >- public void clear() { >- getterCalled(); >- >- Set set = getSet(); >- if (set.isEmpty()) >- return; >- >- SetDiff diff = Diffs.createSetDiff(Collections.EMPTY_SET, set); >- >- boolean wasUpdating = updating; >- updating = true; >- try { >- property.setSet(source, Collections.EMPTY_SET, diff); >- modCount++; >- } finally { >- updating = wasUpdating; >- } >- >- notifyIfChanged(null); >- } >- >- private void notifyIfChanged(SetDiff diff) { >- if (hasListeners()) { >- Set oldSet = cachedSet; >- Set newSet = cachedSet = property.getSet(source); >- if (diff == null) >- diff = Diffs.computeSetDiff(oldSet, newSet); >- if (!diff.isEmpty()) >- fireSetChange(diff); >- } >- } >- >- public boolean equals(Object o) { >- getterCalled(); >- return getSet().equals(o); >- } >- >- public int hashCode() { >- getterCalled(); >- return getSet().hashCode(); >- } >- >- public Object getObserved() { >- return source; >- } >- >- public IProperty getProperty() { >- return property; >- } >- >- public synchronized void dispose() { >- if (!isDisposed()) { >- if (listener != null) >- property.removeListener(source, listener); >- property = null; >- source = null; >- listener = null; >- } >- super.dispose(); >- } >-} >Index: src/org/eclipse/core/databinding/property/set/DelegatingSetProperty.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.databinding/src/org/eclipse/core/databinding/property/set/Attic/DelegatingSetProperty.java,v >retrieving revision 1.1.2.2 >diff -u -r1.1.2.2 DelegatingSetProperty.java >--- src/org/eclipse/core/databinding/property/set/DelegatingSetProperty.java 14 Jan 2009 23:51:11 -0000 1.1.2.2 >+++ src/org/eclipse/core/databinding/property/set/DelegatingSetProperty.java 16 Jan 2009 15:28:52 -0000 >@@ -36,6 +36,15 @@ > this.elementType = elementType; > } > >+ /** >+ * Returns the property to delegate to for the specified source object. >+ * Repeated calls to this method with the same source object returns the >+ * same delegate instance. >+ * >+ * @param source >+ * the property source (may be null) >+ * @return the property to delegate to for the specified source object. >+ */ > protected final ISetProperty getDelegate(Object source) { > if (source == null) > return null; >@@ -45,6 +54,15 @@ > return delegate; > } > >+ /** >+ * Returns the property to delegate to for the specified source object. >+ * Implementers must ensure that repeated calls to this method with the same >+ * source object returns the same delegate instance. >+ * >+ * @param source >+ * the property source >+ * @return the property to delegate to for the specified source object. >+ */ > protected abstract ISetProperty doGetDelegate(Object source); > > public Object getElementType() { >@@ -67,7 +85,7 @@ > protected void doSetSet(Object source, Set set, SetDiff diff) { > } > >- protected INativePropertyListener adaptListener( >+ public INativePropertyListener adaptListener( > IPropertyChangeListener listener) { > return null; > } >Index: src/org/eclipse/core/databinding/property/set/SimpleSetProperty.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.databinding/src/org/eclipse/core/databinding/property/set/Attic/SimpleSetProperty.java,v >retrieving revision 1.1.2.7 >diff -u -r1.1.2.7 SimpleSetProperty.java >--- src/org/eclipse/core/databinding/property/set/SimpleSetProperty.java 8 Jan 2009 01:24:50 -0000 1.1.2.7 >+++ src/org/eclipse/core/databinding/property/set/SimpleSetProperty.java 16 Jan 2009 15:28:52 -0000 >@@ -20,6 +20,7 @@ > import org.eclipse.core.databinding.observable.set.SetDiff; > import org.eclipse.core.databinding.property.INativePropertyListener; > import org.eclipse.core.databinding.property.IPropertyChangeListener; >+import org.eclipse.core.internal.databinding.property.set.SimpleSetPropertyObservableSet; > > /** > * Simplified abstract implementation of ISetProperty. This class takes care of >@@ -56,7 +57,7 @@ > * @return a Set with the current contents of the source's set property > * @noreference This method is not intended to be referenced by clients. > */ >- protected final Set getSet(Object source) { >+ public final Set getSet(Object source) { > if (source == null) > return Collections.EMPTY_SET; > return Collections.unmodifiableSet(doGetSet(source)); >@@ -87,7 +88,7 @@ > * a diff describing the change > * @noreference This method is not intended to be referenced by clients. > */ >- protected final void setSet(Object source, Set set, SetDiff diff) { >+ public final void setSet(Object source, Set set, SetDiff diff) { > if (source != null && !diff.isEmpty()) > doSetSet(source, set, diff); > } >@@ -124,7 +125,7 @@ > * @noreference This method is not intended to be referenced by clients. > * @noreference This method is not intended to be referenced by clients. > */ >- protected abstract INativePropertyListener adaptListener( >+ public abstract INativePropertyListener adaptListener( > IPropertyChangeListener listener); > > /** >@@ -140,7 +141,7 @@ > * {@link #adaptListener(IPropertyChangeListener)}. > * @noreference This method is not intended to be referenced by clients. > */ >- protected final void addListener(Object source, >+ public final void addListener(Object source, > INativePropertyListener listener) { > if (source != null) > doAddListener(source, listener); >@@ -175,7 +176,7 @@ > * {@link #adaptListener(IPropertyChangeListener)} . > * @noreference This method is not intended to be referenced by clients. > */ >- protected final void removeListener(Object source, >+ public final void removeListener(Object source, > INativePropertyListener listener) { > if (source != null) > doRemoveListener(source, listener); >Index: src/org/eclipse/core/internal/databinding/property/map/SimpleMapPropertyObservableMap.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/property/map/SimpleMapPropertyObservableMap.java >diff -N src/org/eclipse/core/internal/databinding/property/map/SimpleMapPropertyObservableMap.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/property/map/SimpleMapPropertyObservableMap.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,297 @@ >+/******************************************************************************* >+ * 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 194734) >+ ******************************************************************************/ >+ >+package org.eclipse.core.internal.databinding.property.map; >+ >+import java.util.AbstractSet; >+import java.util.Collection; >+import java.util.Collections; >+import java.util.ConcurrentModificationException; >+import java.util.HashMap; >+import java.util.HashSet; >+import java.util.Iterator; >+import java.util.Map; >+import java.util.Set; >+ >+import org.eclipse.core.databinding.observable.Diffs; >+import org.eclipse.core.databinding.observable.ObservableTracker; >+import org.eclipse.core.databinding.observable.Realm; >+import org.eclipse.core.databinding.observable.map.AbstractObservableMap; >+import org.eclipse.core.databinding.observable.map.MapDiff; >+import org.eclipse.core.databinding.property.INativePropertyListener; >+import org.eclipse.core.databinding.property.IProperty; >+import org.eclipse.core.databinding.property.IPropertyChangeListener; >+import org.eclipse.core.databinding.property.IPropertyObservable; >+import org.eclipse.core.databinding.property.PropertyChangeEvent; >+import org.eclipse.core.databinding.property.map.SimpleMapProperty; >+ >+/** >+ * @since 1.2 >+ */ >+public class SimpleMapPropertyObservableMap extends AbstractObservableMap >+ implements IPropertyObservable { >+ private Object source; >+ private SimpleMapProperty property; >+ >+ private volatile boolean updating = false; >+ >+ private volatile int modCount = 0; >+ >+ private INativePropertyListener listener; >+ >+ private Map cachedMap; >+ >+ /** >+ * @param realm >+ * @param source >+ * @param property >+ */ >+ public SimpleMapPropertyObservableMap(Realm realm, Object source, >+ SimpleMapProperty property) { >+ super(realm); >+ this.source = source; >+ this.property = property; >+ } >+ >+ public Object getKeyType() { >+ return property.getKeyType(); >+ } >+ >+ public Object getValueType() { >+ return property.getValueType(); >+ } >+ >+ private void getterCalled() { >+ ObservableTracker.getterCalled(this); >+ } >+ >+ protected void firstListenerAdded() { >+ if (!isDisposed()) { >+ cachedMap = new HashMap(this); >+ >+ if (listener == null) { >+ listener = property >+ .adaptListener(new IPropertyChangeListener() { >+ public void handlePropertyChange( >+ final PropertyChangeEvent event) { >+ modCount++; >+ if (!isDisposed() && !updating) { >+ getRealm().exec(new Runnable() { >+ public void run() { >+ notifyIfChanged((MapDiff) event.diff); >+ } >+ }); >+ } >+ } >+ }); >+ } >+ property.addListener(source, listener); >+ } >+ } >+ >+ protected void lastListenerRemoved() { >+ if (listener != null) { >+ property.removeListener(source, listener); >+ } >+ >+ cachedMap.clear(); >+ cachedMap = null; >+ } >+ >+ // Queries >+ >+ private Map getMap() { >+ return property.getMap(source); >+ } >+ >+ // Single change operations >+ >+ private EntrySet es = new EntrySet(); >+ >+ public Set entrySet() { >+ getterCalled(); >+ return es; >+ } >+ >+ private class EntrySet extends AbstractSet { >+ public Iterator iterator() { >+ return new EntrySetIterator(); >+ } >+ >+ public int size() { >+ return getMap().size(); >+ } >+ } >+ >+ private class EntrySetIterator implements Iterator { >+ private volatile int expectedModCount = modCount; >+ Map map = new HashMap(getMap()); >+ Iterator iterator = map.entrySet().iterator(); >+ Map.Entry last = null; >+ >+ public boolean hasNext() { >+ getterCalled(); >+ checkForComodification(); >+ return iterator.hasNext(); >+ } >+ >+ public Object next() { >+ getterCalled(); >+ checkForComodification(); >+ last = (Map.Entry) iterator.next(); >+ return last; >+ } >+ >+ public void remove() { >+ getterCalled(); >+ checkForComodification(); >+ >+ iterator.remove(); // stay in sync >+ MapDiff diff = Diffs.createMapDiffSingleRemove(last.getKey(), last >+ .getValue()); >+ >+ boolean wasUpdating = updating; >+ updating = true; >+ try { >+ property.setMap(source, map, diff); >+ } finally { >+ updating = wasUpdating; >+ } >+ >+ notifyIfChanged(null); >+ >+ last = null; >+ expectedModCount = modCount; >+ } >+ >+ private void checkForComodification() { >+ if (expectedModCount != modCount) >+ throw new ConcurrentModificationException(); >+ } >+ } >+ >+ public Set keySet() { >+ getterCalled(); >+ // AbstractMap depends on entrySet() to fulfil keySet() API, so all >+ // getterCalled() and comodification checks will still be handled >+ return super.keySet(); >+ } >+ >+ public Object put(Object key, Object value) { >+ checkRealm(); >+ >+ Map map = new HashMap(getMap()); >+ >+ boolean add = !map.containsKey(key); >+ >+ Object oldValue = map.put(key, value); >+ >+ MapDiff diff; >+ if (add) >+ diff = Diffs.createMapDiffSingleAdd(key, value); >+ else >+ diff = Diffs.createMapDiffSingleChange(key, oldValue, value); >+ >+ boolean wasUpdating = updating; >+ updating = true; >+ try { >+ property.setMap(source, map, diff); >+ modCount++; >+ } finally { >+ updating = wasUpdating; >+ } >+ >+ notifyIfChanged(null); >+ >+ return oldValue; >+ } >+ >+ public void putAll(Map m) { >+ checkRealm(); >+ >+ Map map = new HashMap(getMap()); >+ >+ Map oldValues = new HashMap(); >+ Map newValues = new HashMap(); >+ Set changedKeys = new HashSet(); >+ Set addedKeys = new HashSet(); >+ for (Iterator it = m.entrySet().iterator(); it.hasNext();) { >+ Map.Entry entry = (Entry) it.next(); >+ Object key = entry.getKey(); >+ Object newValue = entry.getValue(); >+ if (map.containsKey(key)) { >+ changedKeys.add(key); >+ oldValues.put(key, map.get(key)); >+ } else { >+ addedKeys.add(key); >+ } >+ map.put(key, newValue); >+ >+ newValues.put(key, newValue); >+ } >+ >+ MapDiff diff = Diffs.createMapDiff(addedKeys, Collections.EMPTY_SET, >+ changedKeys, oldValues, newValues); >+ >+ boolean wasUpdating = updating; >+ updating = true; >+ try { >+ property.setMap(source, map, diff); >+ modCount++; >+ } finally { >+ updating = wasUpdating; >+ } >+ >+ notifyIfChanged(null); >+ } >+ >+ public Object remove(Object key) { >+ checkRealm(); >+ return super.remove(key); >+ } >+ >+ public Collection values() { >+ getterCalled(); >+ // AbstractMap depends on entrySet() to fulfil values() API, so all >+ // getterCalled() and comodification checks will still be handled >+ return super.values(); >+ } >+ >+ private void notifyIfChanged(MapDiff diff) { >+ if (hasListeners()) { >+ Map oldMap = cachedMap; >+ Map newMap = cachedMap = property.getMap(source); >+ if (diff == null) >+ diff = Diffs.computeMapDiff(oldMap, newMap); >+ if (!diff.isEmpty()) >+ fireMapChange(diff); >+ } >+ } >+ >+ public Object getObserved() { >+ return source; >+ } >+ >+ public IProperty getProperty() { >+ return property; >+ } >+ >+ public synchronized void dispose() { >+ if (!isDisposed()) { >+ if (listener != null) >+ property.removeListener(source, listener); >+ property = null; >+ source = null; >+ listener = null; >+ } >+ super.dispose(); >+ } >+} >Index: src/org/eclipse/core/internal/databinding/property/set/SimpleSetPropertyObservableSet.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/property/set/SimpleSetPropertyObservableSet.java >diff -N src/org/eclipse/core/internal/databinding/property/set/SimpleSetPropertyObservableSet.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/property/set/SimpleSetPropertyObservableSet.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,408 @@ >+/******************************************************************************* >+ * 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 194734) >+ ******************************************************************************/ >+ >+package org.eclipse.core.internal.databinding.property.set; >+ >+import java.util.Collection; >+import java.util.Collections; >+import java.util.ConcurrentModificationException; >+import java.util.HashSet; >+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.SetDiff; >+import org.eclipse.core.databinding.property.IProperty; >+import org.eclipse.core.databinding.property.INativePropertyListener; >+import org.eclipse.core.databinding.property.IPropertyChangeListener; >+import org.eclipse.core.databinding.property.IPropertyObservable; >+import org.eclipse.core.databinding.property.PropertyChangeEvent; >+import org.eclipse.core.databinding.property.set.SimpleSetProperty; >+ >+/** >+ * @since 1.2 >+ * >+ */ >+public class SimpleSetPropertyObservableSet extends AbstractObservableSet implements >+ IPropertyObservable { >+ private Object source; >+ private SimpleSetProperty property; >+ >+ private volatile boolean updating = false; >+ >+ private volatile int modCount = 0; >+ >+ private INativePropertyListener listener; >+ >+ private Set cachedSet; >+ >+ /** >+ * @param realm >+ * @param source >+ * @param property >+ */ >+ public SimpleSetPropertyObservableSet(Realm realm, Object source, >+ SimpleSetProperty property) { >+ super(realm); >+ this.source = source; >+ this.property = property; >+ } >+ >+ protected void firstListenerAdded() { >+ if (!isDisposed()) { >+ cachedSet = getSet(); >+ >+ if (listener == null) { >+ listener = property >+ .adaptListener(new IPropertyChangeListener() { >+ public void handlePropertyChange( >+ final PropertyChangeEvent event) { >+ modCount++; >+ if (!isDisposed() && !updating) { >+ getRealm().exec(new Runnable() { >+ public void run() { >+ notifyIfChanged((SetDiff) event.diff); >+ } >+ }); >+ } >+ } >+ }); >+ } >+ property.addListener(source, listener); >+ } >+ } >+ >+ protected void lastListenerRemoved() { >+ if (listener != null) { >+ property.removeListener(source, listener); >+ } >+ >+ cachedSet = null; >+ } >+ >+ protected Set getWrappedSet() { >+ return getSet(); >+ } >+ >+ public Object getElementType() { >+ return property.getElementType(); >+ } >+ >+ // Queries >+ >+ private Set getSet() { >+ return property.getSet(source); >+ } >+ >+ public boolean contains(Object o) { >+ getterCalled(); >+ return getSet().contains(o); >+ } >+ >+ public boolean containsAll(Collection c) { >+ getterCalled(); >+ return getSet().containsAll(c); >+ } >+ >+ public boolean isEmpty() { >+ getterCalled(); >+ return getSet().isEmpty(); >+ } >+ >+ public Object[] toArray() { >+ getterCalled(); >+ return getSet().toArray(); >+ } >+ >+ public Object[] toArray(Object[] a) { >+ getterCalled(); >+ return getSet().toArray(a); >+ } >+ >+ // Single change operations >+ >+ public boolean add(Object o) { >+ checkRealm(); >+ >+ Set set = new HashSet(getSet()); >+ if (!set.add(o)) >+ return false; >+ >+ SetDiff diff = Diffs.createSetDiff(Collections.singleton(o), >+ Collections.EMPTY_SET); >+ >+ boolean wasUpdating = updating; >+ updating = true; >+ try { >+ property.setSet(source, set, diff); >+ modCount++; >+ } finally { >+ updating = wasUpdating; >+ } >+ >+ notifyIfChanged(null); >+ >+ return true; >+ } >+ >+ public Iterator iterator() { >+ getterCalled(); >+ return new Iterator() { >+ int expectedModCount = modCount; >+ Set set = new HashSet(getSet()); >+ Iterator iterator = set.iterator(); >+ Object last = null; >+ >+ public boolean hasNext() { >+ getterCalled(); >+ checkForComodification(); >+ return iterator.hasNext(); >+ } >+ >+ public Object next() { >+ getterCalled(); >+ checkForComodification(); >+ last = iterator.next(); >+ return last; >+ } >+ >+ public void remove() { >+ checkRealm(); >+ checkForComodification(); >+ >+ iterator.remove(); // stay in sync >+ SetDiff diff = Diffs.createSetDiff(Collections.EMPTY_SET, >+ Collections.singleton(last)); >+ >+ boolean wasUpdating = updating; >+ updating = true; >+ try { >+ property.setSet(source, set, diff); >+ modCount++; >+ } finally { >+ updating = wasUpdating; >+ } >+ >+ notifyIfChanged(null); >+ >+ last = null; >+ expectedModCount = modCount; >+ } >+ >+ private void checkForComodification() { >+ if (expectedModCount != modCount) >+ throw new ConcurrentModificationException(); >+ } >+ }; >+ } >+ >+ public boolean remove(Object o) { >+ getterCalled(); >+ >+ Set set = new HashSet(getSet()); >+ if (!set.remove(o)) >+ return false; >+ >+ SetDiff diff = Diffs.createSetDiff(Collections.EMPTY_SET, Collections >+ .singleton(o)); >+ >+ boolean wasUpdating = updating; >+ updating = true; >+ try { >+ property.setSet(source, set, diff); >+ modCount++; >+ } finally { >+ updating = wasUpdating; >+ } >+ >+ notifyIfChanged(null); >+ >+ return true; >+ } >+ >+ // Bulk change operations >+ >+ public boolean addAll(Collection c) { >+ getterCalled(); >+ >+ if (c.isEmpty()) >+ return false; >+ >+ Set set = new HashSet(getSet()); >+ >+ Set additions = new HashSet(c); >+ for (Iterator it = c.iterator(); it.hasNext();) { >+ Object element = it.next(); >+ if (set.add(element)) >+ additions.add(element); >+ } >+ >+ if (additions.isEmpty()) >+ return false; >+ >+ SetDiff diff = Diffs.createSetDiff(additions, Collections.EMPTY_SET); >+ >+ boolean wasUpdating = updating; >+ updating = true; >+ try { >+ property.setSet(source, set, diff); >+ modCount++; >+ } finally { >+ updating = wasUpdating; >+ } >+ >+ notifyIfChanged(null); >+ >+ return true; >+ } >+ >+ public boolean removeAll(Collection c) { >+ getterCalled(); >+ >+ Set set = getSet(); >+ if (set.isEmpty()) >+ return false; >+ if (c.isEmpty()) >+ return false; >+ >+ set = new HashSet(set); >+ >+ Set removals = new HashSet(c); >+ for (Iterator it = c.iterator(); it.hasNext();) { >+ Object element = it.next(); >+ if (set.remove(element)) >+ removals.add(element); >+ } >+ >+ if (removals.isEmpty()) >+ return false; >+ >+ SetDiff diff = Diffs.createSetDiff(Collections.EMPTY_SET, removals); >+ >+ boolean wasUpdating = updating; >+ updating = true; >+ try { >+ property.setSet(source, set, diff); >+ modCount++; >+ } finally { >+ updating = wasUpdating; >+ } >+ >+ notifyIfChanged(null); >+ >+ return true; >+ } >+ >+ public boolean retainAll(Collection c) { >+ getterCalled(); >+ >+ Set set = getSet(); >+ if (set.isEmpty()) >+ return false; >+ >+ if (c.isEmpty()) { >+ clear(); >+ return true; >+ } >+ >+ set = new HashSet(set); >+ >+ Set removals = new HashSet(); >+ for (Iterator it = set.iterator(); it.hasNext();) { >+ Object element = it.next(); >+ if (!c.contains(element)) { >+ it.remove(); >+ removals.add(element); >+ } >+ } >+ >+ if (removals.isEmpty()) >+ return false; >+ >+ SetDiff diff = Diffs.createSetDiff(Collections.EMPTY_SET, removals); >+ >+ boolean wasUpdating = updating; >+ updating = true; >+ try { >+ property.setSet(source, set, diff); >+ modCount++; >+ } finally { >+ updating = wasUpdating; >+ } >+ >+ notifyIfChanged(null); >+ >+ return true; >+ } >+ >+ public void clear() { >+ getterCalled(); >+ >+ Set set = getSet(); >+ if (set.isEmpty()) >+ return; >+ >+ SetDiff diff = Diffs.createSetDiff(Collections.EMPTY_SET, set); >+ >+ boolean wasUpdating = updating; >+ updating = true; >+ try { >+ property.setSet(source, Collections.EMPTY_SET, diff); >+ modCount++; >+ } finally { >+ updating = wasUpdating; >+ } >+ >+ notifyIfChanged(null); >+ } >+ >+ private void notifyIfChanged(SetDiff diff) { >+ if (hasListeners()) { >+ Set oldSet = cachedSet; >+ Set newSet = cachedSet = property.getSet(source); >+ if (diff == null) >+ diff = Diffs.computeSetDiff(oldSet, newSet); >+ if (!diff.isEmpty()) >+ fireSetChange(diff); >+ } >+ } >+ >+ public boolean equals(Object o) { >+ getterCalled(); >+ return getSet().equals(o); >+ } >+ >+ public int hashCode() { >+ getterCalled(); >+ return getSet().hashCode(); >+ } >+ >+ public Object getObserved() { >+ return source; >+ } >+ >+ public IProperty getProperty() { >+ return property; >+ } >+ >+ public synchronized void dispose() { >+ if (!isDisposed()) { >+ if (listener != null) >+ property.removeListener(source, listener); >+ property = null; >+ source = null; >+ listener = null; >+ } >+ super.dispose(); >+ } >+} >Index: src/org/eclipse/core/internal/databinding/property/value/ObservableSetSimpleValuePropertyObservableMap.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/property/value/ObservableSetSimpleValuePropertyObservableMap.java >diff -N src/org/eclipse/core/internal/databinding/property/value/ObservableSetSimpleValuePropertyObservableMap.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/property/value/ObservableSetSimpleValuePropertyObservableMap.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,144 @@ >+/******************************************************************************* >+ * 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 194734) >+ ******************************************************************************/ >+ >+package org.eclipse.core.internal.databinding.property.value; >+ >+import java.util.HashMap; >+import java.util.Iterator; >+import java.util.Map; >+ >+import org.eclipse.core.databinding.observable.Diffs; >+import org.eclipse.core.databinding.observable.map.ComputedObservableMap; >+import org.eclipse.core.databinding.observable.set.IObservableSet; >+import org.eclipse.core.databinding.property.INativePropertyListener; >+import org.eclipse.core.databinding.property.IProperty; >+import org.eclipse.core.databinding.property.IPropertyChangeListener; >+import org.eclipse.core.databinding.property.IPropertyObservable; >+import org.eclipse.core.databinding.property.PropertyChangeEvent; >+import org.eclipse.core.databinding.property.value.SimpleValueProperty; >+import org.eclipse.core.internal.databinding.Util; >+ >+/** >+ * @since 1.2 >+ */ >+public class ObservableSetSimpleValuePropertyObservableMap extends >+ ComputedObservableMap implements IPropertyObservable { >+ private SimpleValueProperty detailProperty; >+ >+ private INativePropertyListener listener; >+ >+ private Map cachedValues; >+ >+ private boolean updating; >+ >+ /** >+ * @param keySet >+ * @param valueProperty >+ */ >+ public ObservableSetSimpleValuePropertyObservableMap(IObservableSet keySet, >+ SimpleValueProperty valueProperty) { >+ super(keySet); >+ this.detailProperty = valueProperty; >+ } >+ >+ protected void firstListenerAdded() { >+ cachedValues = new HashMap(this); >+ if (listener == null) { >+ listener = detailProperty >+ .adaptListener(new IPropertyChangeListener() { >+ public void handlePropertyChange( >+ final PropertyChangeEvent event) { >+ if (!isDisposed() && !updating) { >+ getRealm().exec(new Runnable() { >+ public void run() { >+ notifyIfChanged(event.getSource()); >+ } >+ }); >+ } >+ } >+ }); >+ } >+ super.firstListenerAdded(); >+ } >+ >+ protected void lastListenerRemoved() { >+ super.lastListenerRemoved(); >+ cachedValues.clear(); >+ cachedValues = null; >+ } >+ >+ protected void hookListener(Object addedKey) { >+ if (listener != null) { >+ cachedValues.put(addedKey, detailProperty.getValue(addedKey)); >+ detailProperty.addListener(addedKey, listener); >+ } >+ } >+ >+ protected void unhookListener(Object removedKey) { >+ if (listener != null) { >+ detailProperty.removeListener(removedKey, listener); >+ cachedValues.remove(removedKey); >+ } >+ } >+ >+ protected Object doGet(Object key) { >+ return detailProperty.getValue(key); >+ } >+ >+ protected Object doPut(Object key, Object value) { >+ Object oldValue = detailProperty.getValue(key); >+ >+ updating = true; >+ try { >+ detailProperty.setValue(key, value); >+ } finally { >+ updating = false; >+ } >+ >+ notifyIfChanged(key); >+ >+ return oldValue; >+ } >+ >+ private void notifyIfChanged(Object key) { >+ if (cachedValues != null) { >+ Object oldValue = cachedValues.get(key); >+ Object newValue = detailProperty.getValue(key); >+ if (!Util.equals(oldValue, newValue)) { >+ cachedValues.put(key, newValue); >+ fireMapChange(Diffs.createMapDiffSingleChange(key, oldValue, >+ newValue)); >+ } >+ } >+ } >+ >+ public Object getObserved() { >+ return keySet(); >+ } >+ >+ public IProperty getProperty() { >+ return detailProperty; >+ } >+ >+ public synchronized void dispose() { >+ if (!isDisposed()) { >+ if (listener != null) { >+ for (Iterator it = values().iterator(); it.hasNext();) { >+ unhookListener(it.next()); >+ } >+ listener = null; >+ } >+ detailProperty = null; >+ } >+ >+ super.dispose(); >+ } >+} >Index: src/org/eclipse/core/internal/databinding/property/value/ObservableListDelegatingValuePropertyObservableList.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/property/value/ObservableListDelegatingValuePropertyObservableList.java >diff -N src/org/eclipse/core/internal/databinding/property/value/ObservableListDelegatingValuePropertyObservableList.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/property/value/ObservableListDelegatingValuePropertyObservableList.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,348 @@ >+/******************************************************************************* >+ * 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 >+ ******************************************************************************/ >+ >+package org.eclipse.core.internal.databinding.property.value; >+ >+import java.lang.reflect.Array; >+import java.util.ArrayList; >+import java.util.Collection; >+import java.util.Iterator; >+import java.util.List; >+import java.util.ListIterator; >+ >+import org.eclipse.core.databinding.observable.Diffs; >+import org.eclipse.core.databinding.observable.IStaleListener; >+import org.eclipse.core.databinding.observable.ObservableTracker; >+import org.eclipse.core.databinding.observable.StaleEvent; >+import org.eclipse.core.databinding.observable.list.AbstractObservableList; >+import org.eclipse.core.databinding.observable.list.IListChangeListener; >+import org.eclipse.core.databinding.observable.list.IObservableList; >+import org.eclipse.core.databinding.observable.list.ListChangeEvent; >+import org.eclipse.core.databinding.observable.list.ListDiff; >+import org.eclipse.core.databinding.observable.list.ListDiffEntry; >+import org.eclipse.core.databinding.property.IProperty; >+import org.eclipse.core.databinding.property.IPropertyObservable; >+import org.eclipse.core.databinding.property.value.DelegatingValueProperty; >+ >+/** >+ * @since 1.2 >+ */ >+public class ObservableListDelegatingValuePropertyObservableList extends >+ AbstractObservableList implements IPropertyObservable { >+ private IObservableList masterList; >+ private DelegatingValueProperty detailProperty; >+ private DelegatingCache cache; >+ >+ private IListChangeListener masterListener = new IListChangeListener() { >+ public void handleListChange(ListChangeEvent event) { >+ if (isDisposed()) >+ return; >+ >+ cache.addAll(masterList); >+ >+ // Need both obsolete and new elements to convert diff >+ ListDiff diff = convertDiff(event.diff); >+ >+ cache.retainAll(masterList); >+ >+ fireListChange(diff); >+ } >+ >+ private ListDiff convertDiff(ListDiff diff) { >+ // Convert diff to detail value >+ ListDiffEntry[] masterEntries = diff.getDifferences(); >+ ListDiffEntry[] detailEntries = new ListDiffEntry[masterEntries.length]; >+ for (int i = 0; i < masterEntries.length; i++) { >+ ListDiffEntry masterDifference = masterEntries[i]; >+ int index = masterDifference.getPosition(); >+ boolean addition = masterDifference.isAddition(); >+ Object masterElement = masterDifference.getElement(); >+ Object detailValue = cache.get(masterElement); >+ >+ detailEntries[i] = Diffs.createListDiffEntry(index, addition, >+ detailValue); >+ } >+ return Diffs.createListDiff(detailEntries); >+ } >+ }; >+ >+ private IStaleListener staleListener = new IStaleListener() { >+ public void handleStale(StaleEvent staleEvent) { >+ fireStale(); >+ } >+ }; >+ >+ /** >+ * @param masterList >+ * @param valueProperty >+ */ >+ public ObservableListDelegatingValuePropertyObservableList( >+ IObservableList masterList, DelegatingValueProperty valueProperty) { >+ super(masterList.getRealm()); >+ this.masterList = masterList; >+ this.detailProperty = valueProperty; >+ this.cache = new DelegatingCache(getRealm(), valueProperty) { >+ void handleValueChange(Object masterElement, Object oldValue, >+ Object newValue) { >+ fireListChange(indicesOf(masterElement), oldValue, newValue); >+ } >+ }; >+ cache.addAll(masterList); >+ >+ masterList.addListChangeListener(masterListener); >+ masterList.addStaleListener(staleListener); >+ } >+ >+ protected int doGetSize() { >+ getterCalled(); >+ return masterList.size(); >+ } >+ >+ private void getterCalled() { >+ ObservableTracker.getterCalled(this); >+ } >+ >+ public Object get(int index) { >+ getterCalled(); >+ Object masterElement = masterList.get(index); >+ return cache.get(masterElement); >+ } >+ >+ public boolean add(Object o) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public boolean addAll(Collection c) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public boolean addAll(int index, Collection c) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public boolean contains(Object o) { >+ getterCalled(); >+ return cache.contains(o); >+ } >+ >+ public boolean isEmpty() { >+ getterCalled(); >+ return masterList.isEmpty(); >+ } >+ >+ public boolean isStale() { >+ getterCalled(); >+ return masterList.isStale(); >+ } >+ >+ public Iterator iterator() { >+ getterCalled(); >+ return new Iterator() { >+ Iterator it = masterList.iterator(); >+ >+ public boolean hasNext() { >+ getterCalled(); >+ return it.hasNext(); >+ } >+ >+ public Object next() { >+ getterCalled(); >+ Object masterElement = it.next(); >+ return cache.get(masterElement); >+ } >+ >+ public void remove() { >+ throw new UnsupportedOperationException(); >+ } >+ }; >+ } >+ >+ public Object move(int oldIndex, int newIndex) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public boolean remove(Object o) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public boolean removeAll(Collection c) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public boolean retainAll(Collection c) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public Object[] toArray() { >+ getterCalled(); >+ Object[] masterElements = masterList.toArray(); >+ Object[] result = new Object[masterElements.length]; >+ for (int i = 0; i < result.length; i++) { >+ result[i] = cache.get(masterElements[i]); >+ } >+ return result; >+ } >+ >+ public Object[] toArray(Object[] a) { >+ getterCalled(); >+ Object[] masterElements = masterList.toArray(); >+ if (a.length < masterElements.length) >+ a = (Object[]) Array.newInstance(a.getClass().getComponentType(), >+ masterElements.length); >+ for (int i = 0; i < masterElements.length; i++) { >+ a[i] = cache.get(masterElements[i]); >+ } >+ return a; >+ } >+ >+ public void add(int index, Object o) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public void clear() { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public ListIterator listIterator() { >+ return listIterator(0); >+ } >+ >+ public ListIterator listIterator(final int index) { >+ getterCalled(); >+ return new ListIterator() { >+ ListIterator it = masterList.listIterator(index); >+ Object lastMasterElement; >+ Object lastElement; >+ boolean haveIterated = false; >+ >+ public void add(Object arg0) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public boolean hasNext() { >+ getterCalled(); >+ return it.hasNext(); >+ } >+ >+ public boolean hasPrevious() { >+ getterCalled(); >+ return it.hasPrevious(); >+ } >+ >+ public Object next() { >+ getterCalled(); >+ lastMasterElement = it.next(); >+ lastElement = cache.get(lastMasterElement); >+ haveIterated = true; >+ return lastElement; >+ } >+ >+ public int nextIndex() { >+ getterCalled(); >+ return it.nextIndex(); >+ } >+ >+ public Object previous() { >+ getterCalled(); >+ lastMasterElement = it.previous(); >+ lastElement = cache.get(lastMasterElement); >+ haveIterated = true; >+ return lastElement; >+ } >+ >+ public int previousIndex() { >+ getterCalled(); >+ return it.previousIndex(); >+ } >+ >+ public void remove() { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public void set(Object o) { >+ checkRealm(); >+ if (!haveIterated) >+ throw new IllegalStateException(); >+ >+ cache.put(lastMasterElement, o); >+ >+ lastElement = o; >+ } >+ }; >+ } >+ >+ private int[] indicesOf(Object masterElement) { >+ List indices = new ArrayList(); >+ >+ for (ListIterator it = masterList.listIterator(); it.hasNext();) { >+ if (masterElement == it.next()) >+ indices.add(new Integer(it.previousIndex())); >+ } >+ >+ int[] result = new int[indices.size()]; >+ for (int i = 0; i < result.length; i++) { >+ result[i] = ((Integer) indices.get(i)).intValue(); >+ } >+ return result; >+ } >+ >+ private void fireListChange(int[] indices, Object oldValue, Object newValue) { >+ ListDiffEntry[] differences = new ListDiffEntry[indices.length * 2]; >+ for (int i = 0; i < indices.length; i++) { >+ int index = indices[i]; >+ differences[i * 2] = Diffs.createListDiffEntry(index, false, >+ oldValue); >+ differences[i * 2 + 1] = Diffs.createListDiffEntry(index, true, >+ newValue); >+ } >+ fireListChange(Diffs.createListDiff(differences)); >+ } >+ >+ public Object remove(int index) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public Object set(int index, Object o) { >+ checkRealm(); >+ Object masterElement = masterList.get(index); >+ return cache.put(masterElement, o); >+ } >+ >+ public Object getObserved() { >+ return masterList; >+ } >+ >+ public IProperty getProperty() { >+ return detailProperty; >+ } >+ >+ public Object getElementType() { >+ return detailProperty.getValueType(); >+ } >+ >+ public synchronized void dispose() { >+ if (masterList != null) { >+ masterList.removeListChangeListener(masterListener); >+ masterList.removeStaleListener(staleListener); >+ masterList = null; >+ } >+ >+ if (cache != null) { >+ cache.dispose(); >+ cache = null; >+ } >+ >+ masterListener = null; >+ detailProperty = null; >+ >+ super.dispose(); >+ } >+} >Index: src/org/eclipse/core/internal/databinding/property/list/SimpleListPropertyObservableList.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/property/list/SimpleListPropertyObservableList.java >diff -N src/org/eclipse/core/internal/databinding/property/list/SimpleListPropertyObservableList.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/property/list/SimpleListPropertyObservableList.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,667 @@ >+/******************************************************************************* >+ * 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 194734) >+ ******************************************************************************/ >+ >+package org.eclipse.core.internal.databinding.property.list; >+ >+import java.util.ArrayList; >+import java.util.Collection; >+import java.util.Collections; >+import java.util.ConcurrentModificationException; >+import java.util.Iterator; >+import java.util.List; >+import java.util.ListIterator; >+ >+import org.eclipse.core.databinding.observable.Diffs; >+import org.eclipse.core.databinding.observable.ObservableTracker; >+import org.eclipse.core.databinding.observable.Realm; >+import org.eclipse.core.databinding.observable.list.AbstractObservableList; >+import org.eclipse.core.databinding.observable.list.ListDiff; >+import org.eclipse.core.databinding.observable.list.ListDiffEntry; >+import org.eclipse.core.databinding.property.IProperty; >+import org.eclipse.core.databinding.property.INativePropertyListener; >+import org.eclipse.core.databinding.property.IPropertyChangeListener; >+import org.eclipse.core.databinding.property.IPropertyObservable; >+import org.eclipse.core.databinding.property.PropertyChangeEvent; >+import org.eclipse.core.databinding.property.list.SimpleListProperty; >+ >+/** >+ * @since 1.2 >+ * >+ */ >+public class SimpleListPropertyObservableList extends AbstractObservableList >+ implements IPropertyObservable { >+ private Object source; >+ private SimpleListProperty property; >+ >+ private volatile boolean updating = false; >+ >+ private volatile int modCount = 0; >+ >+ private INativePropertyListener listener; >+ >+ private List cachedList; >+ >+ /** >+ * @param realm >+ * @param source >+ * @param property >+ */ >+ public SimpleListPropertyObservableList(Realm realm, Object source, >+ SimpleListProperty property) { >+ super(realm); >+ this.source = source; >+ this.property = property; >+ } >+ >+ protected void firstListenerAdded() { >+ if (!isDisposed()) { >+ cachedList = getList(); >+ >+ if (listener == null) { >+ listener = property >+ .adaptListener(new IPropertyChangeListener() { >+ public void handlePropertyChange( >+ final PropertyChangeEvent event) { >+ modCount++; >+ if (!isDisposed() && !updating) { >+ getRealm().exec(new Runnable() { >+ public void run() { >+ notifyIfChanged((ListDiff) event.diff); >+ } >+ }); >+ } >+ } >+ }); >+ } >+ property.addListener(source, listener); >+ } >+ } >+ >+ protected void lastListenerRemoved() { >+ if (listener != null) { >+ property.removeListener(source, listener); >+ } >+ >+ cachedList = null; >+ } >+ >+ private void getterCalled() { >+ ObservableTracker.getterCalled(this); >+ } >+ >+ public Object getElementType() { >+ return property.getElementType(); >+ } >+ >+ // Queries >+ >+ private List getList() { >+ return property.getList(source); >+ } >+ >+ protected int doGetSize() { >+ return getList().size(); >+ } >+ >+ public boolean contains(Object o) { >+ getterCalled(); >+ return getList().contains(o); >+ } >+ >+ public boolean containsAll(Collection c) { >+ getterCalled(); >+ return getList().containsAll(c); >+ } >+ >+ public Object get(int index) { >+ getterCalled(); >+ return getList().get(index); >+ } >+ >+ public int indexOf(Object o) { >+ getterCalled(); >+ return getList().indexOf(o); >+ } >+ >+ public boolean isEmpty() { >+ getterCalled(); >+ return getList().isEmpty(); >+ } >+ >+ public int lastIndexOf(Object o) { >+ getterCalled(); >+ return getList().lastIndexOf(o); >+ } >+ >+ public Object[] toArray() { >+ getterCalled(); >+ return getList().toArray(); >+ } >+ >+ public Object[] toArray(Object[] a) { >+ getterCalled(); >+ return getList().toArray(a); >+ } >+ >+ // Single change operations >+ >+ public boolean add(Object o) { >+ checkRealm(); >+ add(getList().size(), o); >+ return true; >+ } >+ >+ public void add(int index, Object o) { >+ checkRealm(); >+ boolean wasUpdating = updating; >+ updating = true; >+ List list = new ArrayList(getList()); >+ list.add(index, o); >+ ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry(index, >+ true, o)); >+ try { >+ property.setList(source, list, diff); >+ modCount++; >+ } finally { >+ updating = wasUpdating; >+ } >+ >+ notifyIfChanged(null); >+ } >+ >+ public Iterator iterator() { >+ getterCalled(); >+ return new Iterator() { >+ int expectedModCount = modCount; >+ List list = new ArrayList(getList()); >+ ListIterator iterator = list.listIterator(); >+ >+ Object lastElement = null; >+ int lastIndex = -1; >+ >+ public boolean hasNext() { >+ getterCalled(); >+ checkForComodification(); >+ return iterator.hasNext(); >+ } >+ >+ public Object next() { >+ getterCalled(); >+ checkForComodification(); >+ Object next = lastElement = iterator.next(); >+ lastIndex = iterator.previousIndex(); >+ return next; >+ } >+ >+ public void remove() { >+ checkRealm(); >+ checkForComodification(); >+ if (lastIndex == -1) >+ throw new IllegalStateException(); >+ >+ iterator.remove(); // stay in sync >+ ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry( >+ lastIndex, false, lastElement)); >+ >+ boolean wasUpdating = updating; >+ updating = true; >+ try { >+ property.setList(source, list, diff); >+ modCount++; >+ } finally { >+ updating = wasUpdating; >+ } >+ >+ notifyIfChanged(null); >+ >+ lastElement = null; >+ lastIndex = -1; >+ >+ expectedModCount = modCount; >+ } >+ >+ private void checkForComodification() { >+ if (expectedModCount != modCount) >+ throw new ConcurrentModificationException(); >+ } >+ }; >+ } >+ >+ public Object move(int oldIndex, int newIndex) { >+ checkRealm(); >+ >+ List list = getList(); >+ int size = list.size(); >+ if (oldIndex < 0 || oldIndex >= size || newIndex < 0 >+ || newIndex >= size) >+ throw new IndexOutOfBoundsException(); >+ >+ if (oldIndex == newIndex) >+ return list.get(oldIndex); >+ >+ list = new ArrayList(list); >+ Object element = list.remove(oldIndex); >+ list.add(newIndex, element); >+ >+ ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry( >+ oldIndex, false, element), Diffs.createListDiffEntry(newIndex, >+ true, element)); >+ >+ boolean wasUpdating = updating; >+ updating = true; >+ try { >+ property.setList(source, list, diff); >+ modCount++; >+ } finally { >+ updating = wasUpdating; >+ } >+ >+ notifyIfChanged(null); >+ >+ return element; >+ } >+ >+ public boolean remove(Object o) { >+ checkRealm(); >+ >+ int index = getList().indexOf(o); >+ if (index == -1) >+ return false; >+ >+ remove(index); >+ >+ return true; >+ } >+ >+ public ListIterator listIterator() { >+ return listIterator(0); >+ } >+ >+ public ListIterator listIterator(final int index) { >+ getterCalled(); >+ return new ListIterator() { >+ int expectedModCount = modCount; >+ List list = new ArrayList(getList()); >+ ListIterator iterator = list.listIterator(index); >+ >+ Object lastElement = null; >+ int lastIndex = -1; >+ >+ public boolean hasNext() { >+ getterCalled(); >+ checkForComodification(); >+ return iterator.hasNext(); >+ } >+ >+ public int nextIndex() { >+ getterCalled(); >+ checkForComodification(); >+ return iterator.nextIndex(); >+ } >+ >+ public Object next() { >+ getterCalled(); >+ checkForComodification(); >+ lastElement = iterator.next(); >+ lastIndex = iterator.previousIndex(); >+ return lastElement; >+ } >+ >+ public boolean hasPrevious() { >+ getterCalled(); >+ checkForComodification(); >+ return iterator.hasPrevious(); >+ } >+ >+ public int previousIndex() { >+ getterCalled(); >+ checkForComodification(); >+ return iterator.previousIndex(); >+ } >+ >+ public Object previous() { >+ getterCalled(); >+ checkForComodification(); >+ lastElement = iterator.previous(); >+ lastIndex = iterator.nextIndex(); >+ return lastElement; >+ } >+ >+ public void add(Object o) { >+ checkRealm(); >+ checkForComodification(); >+ int index = iterator.nextIndex(); >+ >+ iterator.add(o); // keep in sync >+ >+ List list = getList(); >+ list.add(index, o); >+ ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry( >+ index, true, o)); >+ boolean wasUpdating = updating; >+ updating = true; >+ try { >+ property.setList(source, list, diff); >+ modCount++; >+ } finally { >+ updating = wasUpdating; >+ } >+ >+ notifyIfChanged(null); >+ >+ lastElement = null; >+ lastIndex = -1; >+ expectedModCount = modCount; >+ } >+ >+ public void set(Object o) { >+ checkRealm(); >+ checkForComodification(); >+ >+ iterator.set(o); >+ ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry( >+ lastIndex, false, lastElement), Diffs >+ .createListDiffEntry(lastIndex, true, o)); >+ >+ boolean wasUpdating = updating; >+ updating = true; >+ try { >+ property.setList(source, list, diff); >+ modCount++; >+ } finally { >+ updating = wasUpdating; >+ } >+ >+ notifyIfChanged(null); >+ >+ lastElement = o; >+ expectedModCount = modCount; >+ } >+ >+ public void remove() { >+ checkRealm(); >+ checkForComodification(); >+ if (lastIndex == -1) >+ throw new IllegalStateException(); >+ >+ iterator.remove(); // keep in sync >+ ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry( >+ lastIndex, false, lastElement)); >+ >+ boolean wasUpdating = updating; >+ updating = true; >+ try { >+ property.setList(source, list, diff); >+ modCount++; >+ } finally { >+ updating = wasUpdating; >+ } >+ >+ notifyIfChanged(null); >+ >+ lastElement = null; >+ lastIndex = -1; >+ expectedModCount = modCount; >+ } >+ >+ private void checkForComodification() { >+ if (expectedModCount != modCount) >+ throw new ConcurrentModificationException(); >+ } >+ }; >+ } >+ >+ public Object remove(int index) { >+ checkRealm(); >+ >+ List list = new ArrayList(getList()); >+ Object element = list.remove(index); >+ ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry(index, >+ false, element)); >+ >+ boolean wasUpdating = updating; >+ updating = true; >+ try { >+ property.setList(source, list, diff); >+ modCount++; >+ } finally { >+ updating = wasUpdating; >+ } >+ >+ notifyIfChanged(null); >+ >+ return element; >+ } >+ >+ public Object set(int index, Object o) { >+ checkRealm(); >+ >+ List list = new ArrayList(getList()); >+ Object oldElement = list.set(index, o); >+ >+ ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry(index, >+ false, oldElement), Diffs.createListDiffEntry(index, true, o)); >+ >+ boolean wasUpdating = updating; >+ updating = true; >+ try { >+ property.setList(source, list, diff); >+ modCount++; >+ } finally { >+ updating = wasUpdating; >+ } >+ >+ notifyIfChanged(null); >+ >+ return oldElement; >+ } >+ >+ public List subList(int fromIndex, int toIndex) { >+ getterCalled(); >+ return Collections.unmodifiableList(getList().subList(fromIndex, >+ toIndex)); >+ } >+ >+ // Bulk change operations >+ >+ public boolean addAll(Collection c) { >+ checkRealm(); >+ >+ return addAll(getList().size(), c); >+ } >+ >+ public boolean addAll(int index, Collection c) { >+ checkRealm(); >+ >+ if (c.isEmpty()) >+ return false; >+ >+ List list = new ArrayList(getList()); >+ list.addAll(index, c); >+ >+ ListDiffEntry[] entries = new ListDiffEntry[c.size()]; >+ int offsetIndex = 0; >+ for (Iterator it = c.iterator(); it.hasNext();) { >+ Object element = it.next(); >+ entries[offsetIndex] = Diffs.createListDiffEntry(index >+ + offsetIndex, true, element); >+ offsetIndex++; >+ } >+ ListDiff diff = Diffs.createListDiff(entries); >+ >+ boolean wasUpdating = updating; >+ updating = true; >+ try { >+ property.setList(source, list, diff); >+ modCount++; >+ } finally { >+ updating = wasUpdating; >+ } >+ >+ notifyIfChanged(null); >+ >+ return true; >+ } >+ >+ public boolean removeAll(Collection c) { >+ checkRealm(); >+ >+ if (c.isEmpty()) >+ return false; >+ >+ List list = getList(); >+ if (list.isEmpty()) >+ return false; >+ >+ list = new ArrayList(list); >+ List entries = new ArrayList(); >+ ListDiff diff; >+ >+ boolean wasUpdating = updating; >+ updating = true; >+ try { >+ for (ListIterator it = list.listIterator(); it.hasNext();) { >+ Object element = it.next(); >+ int index = it.previousIndex(); >+ if (c.contains(element)) { >+ it.remove(); >+ entries.add(Diffs >+ .createListDiffEntry(index, false, element)); >+ } >+ } >+ if (entries.isEmpty()) >+ return false; >+ >+ diff = Diffs.createListDiff((ListDiffEntry[]) entries >+ .toArray(new ListDiffEntry[entries.size()])); >+ property.setList(source, list, diff); >+ modCount++; >+ } finally { >+ updating = wasUpdating; >+ } >+ >+ notifyIfChanged(null); >+ >+ return !diff.isEmpty(); >+ } >+ >+ public boolean retainAll(Collection c) { >+ checkRealm(); >+ >+ List list = getList(); >+ if (list.isEmpty()) >+ return false; >+ >+ if (c.isEmpty()) { >+ clear(); >+ return true; >+ } >+ >+ list = new ArrayList(list); >+ List entries = new ArrayList(); >+ ListDiff diff; >+ >+ boolean wasUpdating = updating; >+ updating = true; >+ try { >+ for (ListIterator it = list.listIterator(); it.hasNext();) { >+ Object element = it.next(); >+ int index = it.previousIndex(); >+ if (!c.contains(element)) { >+ it.remove(); >+ entries.add(Diffs >+ .createListDiffEntry(index, false, element)); >+ } >+ } >+ if (entries.isEmpty()) >+ return false; >+ >+ diff = Diffs.createListDiff((ListDiffEntry[]) entries >+ .toArray(new ListDiffEntry[entries.size()])); >+ property.setList(source, list, diff); >+ modCount++; >+ } finally { >+ updating = wasUpdating; >+ } >+ >+ notifyIfChanged(null); >+ >+ return !diff.isEmpty(); >+ } >+ >+ public void clear() { >+ checkRealm(); >+ >+ List list = getList(); >+ if (list.isEmpty()) >+ return; >+ >+ List entries = new ArrayList(); >+ for (Iterator it = list.iterator(); it.hasNext();) { >+ // always report 0 as the remove index >+ entries.add(Diffs.createListDiffEntry(0, false, it.next())); >+ } >+ >+ ListDiff diff = Diffs.createListDiff((ListDiffEntry[]) entries >+ .toArray(new ListDiffEntry[entries.size()])); >+ boolean wasUpdating = updating; >+ updating = true; >+ try { >+ property.setList(source, Collections.EMPTY_LIST, diff); >+ modCount++; >+ } finally { >+ updating = wasUpdating; >+ } >+ >+ notifyIfChanged(null); >+ } >+ >+ private void notifyIfChanged(ListDiff diff) { >+ if (hasListeners()) { >+ List oldList = cachedList; >+ List newList = cachedList = property.getList(source); >+ if (diff == null) >+ diff = Diffs.computeListDiff(oldList, newList); >+ if (!diff.isEmpty()) { >+ fireListChange(diff); >+ } >+ } >+ } >+ >+ public boolean equals(Object o) { >+ getterCalled(); >+ return getList().equals(o); >+ } >+ >+ public int hashCode() { >+ getterCalled(); >+ return getList().hashCode(); >+ } >+ >+ public Object getObserved() { >+ return source; >+ } >+ >+ public IProperty getProperty() { >+ return property; >+ } >+ >+ public synchronized void dispose() { >+ if (!isDisposed()) { >+ if (listener != null) >+ property.removeListener(source, listener); >+ property = null; >+ source = null; >+ listener = null; >+ } >+ super.dispose(); >+ } >+} >Index: src/org/eclipse/core/internal/databinding/property/value/ObservableSetDelegatingValuePropertyObservableMap.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/property/value/ObservableSetDelegatingValuePropertyObservableMap.java >diff -N src/org/eclipse/core/internal/databinding/property/value/ObservableSetDelegatingValuePropertyObservableMap.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/property/value/ObservableSetDelegatingValuePropertyObservableMap.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,241 @@ >+/******************************************************************************* >+ * 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 194734) >+ ******************************************************************************/ >+ >+package org.eclipse.core.internal.databinding.property.value; >+ >+import java.util.AbstractSet; >+import java.util.Collections; >+import java.util.HashMap; >+import java.util.Iterator; >+import java.util.Map; >+import java.util.Set; >+ >+import org.eclipse.core.databinding.observable.Diffs; >+import org.eclipse.core.databinding.observable.IStaleListener; >+import org.eclipse.core.databinding.observable.ObservableTracker; >+import org.eclipse.core.databinding.observable.StaleEvent; >+import org.eclipse.core.databinding.observable.map.AbstractObservableMap; >+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.SetDiff; >+import org.eclipse.core.databinding.property.IProperty; >+import org.eclipse.core.databinding.property.IPropertyObservable; >+import org.eclipse.core.databinding.property.value.DelegatingValueProperty; >+import org.eclipse.core.internal.databinding.Util; >+ >+/** >+ * @since 1.2 >+ */ >+public class ObservableSetDelegatingValuePropertyObservableMap extends >+ AbstractObservableMap implements IPropertyObservable { >+ private IObservableSet masterSet; >+ private DelegatingValueProperty detailProperty; >+ private DelegatingCache cache; >+ >+ private Set entrySet; >+ >+ class EntrySet extends AbstractSet { >+ public Iterator iterator() { >+ return new Iterator() { >+ final Iterator it = masterSet.iterator(); >+ >+ public boolean hasNext() { >+ return it.hasNext(); >+ } >+ >+ public Object next() { >+ return new MapEntry(it.next()); >+ } >+ >+ public void remove() { >+ it.remove(); >+ } >+ }; >+ } >+ >+ public int size() { >+ return masterSet.size(); >+ } >+ } >+ >+ class MapEntry implements Map.Entry { >+ private final Object key; >+ >+ MapEntry(Object key) { >+ this.key = key; >+ } >+ >+ public Object getKey() { >+ getterCalled(); >+ return key; >+ } >+ >+ public Object getValue() { >+ getterCalled(); >+ >+ if (!masterSet.contains(key)) >+ return null; >+ >+ return cache.get(key); >+ } >+ >+ public Object setValue(Object value) { >+ checkRealm(); >+ >+ if (!masterSet.contains(key)) >+ return null; >+ >+ return cache.put(key, value); >+ } >+ >+ public boolean equals(Object o) { >+ getterCalled(); >+ if (o == this) >+ return true; >+ if (o == null) >+ return false; >+ if (!(o instanceof Map.Entry)) >+ return false; >+ Map.Entry that = (Map.Entry) o; >+ return Util.equals(this.getKey(), that.getKey()) >+ && Util.equals(this.getValue(), that.getValue()); >+ } >+ >+ public int hashCode() { >+ getterCalled(); >+ Object value = getValue(); >+ return (key == null ? 0 : key.hashCode()) >+ ^ (value == null ? 0 : value.hashCode()); >+ } >+ } >+ >+ private ISetChangeListener masterListener = new ISetChangeListener() { >+ public void handleSetChange(SetChangeEvent event) { >+ if (isDisposed()) >+ return; >+ >+ cache.addAll(masterSet); >+ >+ // Need both obsolete and new elements to convert diff >+ MapDiff diff = convertDiff(event.diff); >+ >+ cache.retainAll(masterSet); >+ >+ fireMapChange(diff); >+ } >+ >+ private MapDiff convertDiff(SetDiff diff) { >+ // Convert diff to detail value >+ Map oldValues = new HashMap(); >+ Map newValues = new HashMap(); >+ >+ for (Iterator it = diff.getRemovals().iterator(); it.hasNext();) { >+ Object masterElement = it.next(); >+ oldValues.put(masterElement, cache.get(masterElement)); >+ } >+ for (Iterator it = diff.getAdditions().iterator(); it.hasNext();) { >+ Object masterElement = it.next(); >+ newValues.put(masterElement, cache.get(masterElement)); >+ } >+ return Diffs.createMapDiff(diff.getAdditions(), diff.getRemovals(), >+ Collections.EMPTY_SET, oldValues, newValues); >+ } >+ }; >+ >+ private IStaleListener staleListener = new IStaleListener() { >+ public void handleStale(StaleEvent staleEvent) { >+ fireStale(); >+ } >+ }; >+ >+ /** >+ * @param keySet >+ * @param valueProperty >+ */ >+ public ObservableSetDelegatingValuePropertyObservableMap( >+ IObservableSet keySet, DelegatingValueProperty valueProperty) { >+ super(keySet.getRealm()); >+ this.masterSet = keySet; >+ this.detailProperty = valueProperty; >+ this.cache = new DelegatingCache(getRealm(), valueProperty) { >+ void handleValueChange(Object masterElement, Object oldValue, >+ Object newValue) { >+ fireMapChange(Diffs.createMapDiffSingleChange(masterElement, >+ oldValue, newValue)); >+ } >+ }; >+ cache.addAll(masterSet); >+ >+ masterSet.addSetChangeListener(masterListener); >+ masterSet.addStaleListener(staleListener); >+ } >+ >+ public Set entrySet() { >+ getterCalled(); >+ if (entrySet == null) >+ entrySet = new EntrySet(); >+ return entrySet; >+ } >+ >+ private void getterCalled() { >+ ObservableTracker.getterCalled(this); >+ } >+ >+ public Object get(Object key) { >+ getterCalled(); >+ return cache.get(key); >+ } >+ >+ public Object put(Object key, Object value) { >+ checkRealm(); >+ return cache.put(key, value); >+ } >+ >+ public boolean isStale() { >+ return masterSet.isStale(); >+ } >+ >+ public Object getObserved() { >+ return masterSet; >+ } >+ >+ public IProperty getProperty() { >+ return detailProperty; >+ } >+ >+ public Object getKeyType() { >+ return masterSet.getElementType(); >+ } >+ >+ public Object getValueType() { >+ return detailProperty.getValueType(); >+ } >+ >+ public synchronized void dispose() { >+ if (masterSet != null) { >+ masterSet.removeSetChangeListener(masterListener); >+ masterSet.removeStaleListener(staleListener); >+ masterSet = null; >+ } >+ >+ if (cache != null) { >+ cache.dispose(); >+ cache = null; >+ } >+ >+ masterListener = null; >+ detailProperty = null; >+ >+ super.dispose(); >+ } >+} >Index: src/org/eclipse/core/internal/databinding/property/value/ObservableMapDelegatingValuePropertyObservableMap.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/property/value/ObservableMapDelegatingValuePropertyObservableMap.java >diff -N src/org/eclipse/core/internal/databinding/property/value/ObservableMapDelegatingValuePropertyObservableMap.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/property/value/ObservableMapDelegatingValuePropertyObservableMap.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,316 @@ >+/******************************************************************************* >+ * 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 194734) >+ ******************************************************************************/ >+ >+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; >+ >+import org.eclipse.core.databinding.observable.Diffs; >+import org.eclipse.core.databinding.observable.IStaleListener; >+import org.eclipse.core.databinding.observable.ObservableTracker; >+import org.eclipse.core.databinding.observable.StaleEvent; >+import org.eclipse.core.databinding.observable.map.AbstractObservableMap; >+import org.eclipse.core.databinding.observable.map.IMapChangeListener; >+import org.eclipse.core.databinding.observable.map.IObservableMap; >+import org.eclipse.core.databinding.observable.map.MapChangeEvent; >+import org.eclipse.core.databinding.observable.map.MapDiff; >+import org.eclipse.core.databinding.property.IProperty; >+import org.eclipse.core.databinding.property.IPropertyObservable; >+import org.eclipse.core.databinding.property.value.DelegatingValueProperty; >+import org.eclipse.core.internal.databinding.Util; >+ >+/** >+ * @since 1.2 >+ */ >+public class ObservableMapDelegatingValuePropertyObservableMap extends >+ AbstractObservableMap implements IPropertyObservable { >+ private IObservableMap masterMap; >+ private DelegatingValueProperty detailProperty; >+ private DelegatingCache cache; >+ >+ private Set entrySet; >+ >+ class EntrySet extends AbstractSet { >+ public Iterator iterator() { >+ return new Iterator() { >+ Iterator it = masterMap.entrySet().iterator(); >+ >+ public boolean hasNext() { >+ getterCalled(); >+ return it.hasNext(); >+ } >+ >+ public Object next() { >+ getterCalled(); >+ Map.Entry next = (Map.Entry) it.next(); >+ return new MapEntry(next.getKey()); >+ } >+ >+ public void remove() { >+ it.remove(); >+ } >+ }; >+ } >+ >+ public int size() { >+ return masterMap.size(); >+ } >+ } >+ >+ class MapEntry implements Map.Entry { >+ private Object key; >+ >+ MapEntry(Object key) { >+ this.key = key; >+ } >+ >+ public Object getKey() { >+ getterCalled(); >+ return key; >+ } >+ >+ public Object getValue() { >+ getterCalled(); >+ >+ if (!masterMap.containsKey(key)) >+ return null; >+ >+ Object masterValue = masterMap.get(key); >+ return cache.get(masterValue); >+ } >+ >+ public Object setValue(Object value) { >+ checkRealm(); >+ >+ if (!masterMap.containsKey(key)) >+ return null; >+ >+ Object masterValue = masterMap.get(key); >+ return cache.put(masterValue, value); >+ } >+ >+ public boolean equals(Object o) { >+ getterCalled(); >+ if (o == this) >+ return true; >+ if (o == null) >+ return false; >+ if (!(o instanceof Map.Entry)) >+ return false; >+ Map.Entry that = (Map.Entry) o; >+ return Util.equals(this.getKey(), that.getKey()) >+ && Util.equals(this.getValue(), that.getValue()); >+ } >+ >+ public int hashCode() { >+ getterCalled(); >+ Object value = getValue(); >+ return (key == null ? 0 : key.hashCode()) >+ ^ (value == null ? 0 : value.hashCode()); >+ } >+ } >+ >+ private IMapChangeListener masterListener = new IMapChangeListener() { >+ public void handleMapChange(final MapChangeEvent event) { >+ if (isDisposed()) >+ return; >+ >+ cache.addAll(masterMap.values()); >+ >+ // Need both obsolete and new master values to convert diff >+ MapDiff diff = convertDiff(event.diff); >+ >+ cache.retainAll(masterMap.values()); >+ >+ fireMapChange(diff); >+ } >+ >+ private MapDiff convertDiff(MapDiff diff) { >+ Map oldValues = new HashMap(); >+ Map newValues = new HashMap(); >+ >+ Set addedKeys = diff.getAddedKeys(); >+ for (Iterator it = addedKeys.iterator(); it.hasNext();) { >+ Object key = it.next(); >+ Object masterValue = diff.getNewValue(key); >+ Object newValue = cache.get(masterValue); >+ newValues.put(key, newValue); >+ } >+ >+ Set removedKeys = diff.getRemovedKeys(); >+ for (Iterator it = removedKeys.iterator(); it.hasNext();) { >+ Object key = it.next(); >+ Object masterValue = diff.getOldValue(key); >+ Object oldValue = cache.get(masterValue); >+ oldValues.put(key, oldValue); >+ } >+ >+ Set changedKeys = new HashSet(diff.getChangedKeys()); >+ for (Iterator it = changedKeys.iterator(); it.hasNext();) { >+ Object key = it.next(); >+ >+ Object oldMasterValue = diff.getOldValue(key); >+ Object newMasterValue = diff.getNewValue(key); >+ >+ Object oldValue = cache.get(oldMasterValue); >+ Object newValue = cache.get(newMasterValue); >+ >+ if (Util.equals(oldValue, newValue)) { >+ it.remove(); >+ } else { >+ oldValues.put(key, oldValue); >+ newValues.put(key, newValue); >+ } >+ } >+ >+ return Diffs.createMapDiff(addedKeys, removedKeys, changedKeys, >+ oldValues, newValues); >+ } >+ }; >+ >+ private IStaleListener staleListener = new IStaleListener() { >+ public void handleStale(StaleEvent staleEvent) { >+ fireStale(); >+ } >+ }; >+ >+ /** >+ * @param map >+ * @param valueProperty >+ */ >+ public ObservableMapDelegatingValuePropertyObservableMap( >+ IObservableMap map, DelegatingValueProperty valueProperty) { >+ super(map.getRealm()); >+ this.masterMap = map; >+ this.detailProperty = valueProperty; >+ this.cache = new DelegatingCache(getRealm(), valueProperty) { >+ void handleValueChange(Object masterElement, Object oldValue, >+ Object newValue) { >+ fireMapChange(keysFor(masterElement), oldValue, newValue); >+ } >+ }; >+ cache.addAll(masterMap.values()); >+ >+ masterMap.addMapChangeListener(masterListener); >+ masterMap.addStaleListener(staleListener); >+ } >+ >+ public Set entrySet() { >+ getterCalled(); >+ if (entrySet == null) >+ entrySet = new EntrySet(); >+ return entrySet; >+ } >+ >+ private void getterCalled() { >+ ObservableTracker.getterCalled(this); >+ } >+ >+ public Object get(Object key) { >+ getterCalled(); >+ Object masterValue = masterMap.get(key); >+ return cache.get(masterValue); >+ } >+ >+ public Object put(Object key, Object value) { >+ if (!masterMap.containsKey(key)) >+ return null; >+ Object masterValue = masterMap.get(key); >+ return cache.put(masterValue, value); >+ } >+ >+ public boolean isStale() { >+ getterCalled(); >+ return masterMap.isStale(); >+ } >+ >+ public Object getObserved() { >+ return masterMap; >+ } >+ >+ public IProperty getProperty() { >+ return detailProperty; >+ } >+ >+ public Object getKeyType() { >+ return masterMap.getKeyType(); >+ } >+ >+ public Object getValueType() { >+ return detailProperty.getValueType(); >+ } >+ >+ private Set keysFor(Object masterValue) { >+ Set keys = new HashSet(); >+ >+ for (Iterator it = masterMap.entrySet().iterator(); it.hasNext();) { >+ Map.Entry entry = (Entry) it.next(); >+ if (entry.getValue() == masterValue) { >+ keys.add(entry.getKey()); >+ } >+ } >+ >+ return keys; >+ } >+ >+ private void fireMapChange(final Set changedKeys, final Object oldValue, >+ final Object newValue) { >+ fireMapChange(new MapDiff() { >+ public Set getAddedKeys() { >+ return Collections.EMPTY_SET; >+ } >+ >+ public Set getRemovedKeys() { >+ return Collections.EMPTY_SET; >+ } >+ >+ public Set getChangedKeys() { >+ return Collections.unmodifiableSet(changedKeys); >+ } >+ >+ public Object getOldValue(Object key) { >+ if (changedKeys.contains(key)) >+ return oldValue; >+ return null; >+ } >+ >+ public Object getNewValue(Object key) { >+ if (changedKeys.contains(key)) >+ return newValue; >+ return null; >+ } >+ }); >+ } >+ >+ public synchronized void dispose() { >+ if (masterMap != null) { >+ masterMap.removeMapChangeListener(masterListener); >+ masterMap.removeStaleListener(staleListener); >+ masterMap = null; >+ } >+ >+ if (cache != null) { >+ cache.dispose(); >+ cache = null; >+ } >+ >+ masterListener = null; >+ detailProperty = null; >+ >+ super.dispose(); >+ } >+} >Index: src/org/eclipse/core/internal/databinding/property/value/ObservableMapSimpleValuePropertyObservableMap.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/property/value/ObservableMapSimpleValuePropertyObservableMap.java >diff -N src/org/eclipse/core/internal/databinding/property/value/ObservableMapSimpleValuePropertyObservableMap.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/property/value/ObservableMapSimpleValuePropertyObservableMap.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,375 @@ >+/******************************************************************************* >+ * 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 194734) >+ ******************************************************************************/ >+ >+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; >+ >+import org.eclipse.core.databinding.observable.Diffs; >+import org.eclipse.core.databinding.observable.IStaleListener; >+import org.eclipse.core.databinding.observable.ObservableTracker; >+import org.eclipse.core.databinding.observable.StaleEvent; >+import org.eclipse.core.databinding.observable.map.AbstractObservableMap; >+import org.eclipse.core.databinding.observable.map.IMapChangeListener; >+import org.eclipse.core.databinding.observable.map.IObservableMap; >+import org.eclipse.core.databinding.observable.map.MapChangeEvent; >+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.IPropertyChangeListener; >+import org.eclipse.core.databinding.property.IPropertyObservable; >+import org.eclipse.core.databinding.property.PropertyChangeEvent; >+import org.eclipse.core.databinding.property.value.SimpleValueProperty; >+import org.eclipse.core.internal.databinding.IdentityWrapper; >+import org.eclipse.core.internal.databinding.Util; >+ >+/** >+ * @since 1.2 >+ * >+ */ >+public class ObservableMapSimpleValuePropertyObservableMap extends >+ AbstractObservableMap implements IPropertyObservable { >+ private IObservableMap masterMap; >+ private SimpleValueProperty detailProperty; >+ >+ private IObservableSet knownMasterValues; >+ private Map cachedValues; >+ >+ private boolean updating = false; >+ >+ private IMapChangeListener masterListener = new IMapChangeListener() { >+ public void handleMapChange(final MapChangeEvent event) { >+ if (!isDisposed()) { >+ updateKnownValues(); >+ if (!updating) >+ fireMapChange(convertDiff(event.diff)); >+ } >+ } >+ >+ 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); >+ } >+ >+ private MapDiff convertDiff(MapDiff diff) { >+ Map oldValues = new HashMap(); >+ Map newValues = new HashMap(); >+ >+ Set addedKeys = diff.getAddedKeys(); >+ for (Iterator it = addedKeys.iterator(); it.hasNext();) { >+ Object key = it.next(); >+ Object newSource = diff.getNewValue(key); >+ Object newValue = detailProperty.getValue(newSource); >+ newValues.put(key, newValue); >+ } >+ >+ Set removedKeys = diff.getRemovedKeys(); >+ for (Iterator it = removedKeys.iterator(); it.hasNext();) { >+ Object key = it.next(); >+ Object oldSource = diff.getOldValue(key); >+ Object oldValue = detailProperty.getValue(oldSource); >+ oldValues.put(key, oldValue); >+ } >+ >+ Set changedKeys = new HashSet(diff.getChangedKeys()); >+ for (Iterator it = changedKeys.iterator(); it.hasNext();) { >+ Object key = it.next(); >+ >+ Object oldSource = diff.getOldValue(key); >+ Object newSource = diff.getNewValue(key); >+ >+ Object oldValue = detailProperty.getValue(oldSource); >+ Object newValue = detailProperty.getValue(newSource); >+ >+ if (Util.equals(oldValue, newValue)) { >+ it.remove(); >+ } else { >+ oldValues.put(key, oldValue); >+ newValues.put(key, newValue); >+ } >+ } >+ >+ return Diffs.createMapDiff(addedKeys, removedKeys, changedKeys, >+ oldValues, newValues); >+ } >+ }; >+ >+ private IStaleListener staleListener = new IStaleListener() { >+ public void handleStale(StaleEvent staleEvent) { >+ fireStale(); >+ } >+ }; >+ >+ private INativePropertyListener detailListener; >+ >+ /** >+ * @param map >+ * @param valueProperty >+ */ >+ public ObservableMapSimpleValuePropertyObservableMap(IObservableMap map, >+ SimpleValueProperty valueProperty) { >+ super(map.getRealm()); >+ this.masterMap = map; >+ this.detailProperty = valueProperty; >+ >+ IPropertyChangeListener listener = new IPropertyChangeListener() { >+ public void handlePropertyChange(PropertyChangeEvent event) { >+ notifyIfChanged(event.getSource()); >+ } >+ }; >+ this.detailListener = detailProperty.adaptListener(listener); >+ } >+ >+ protected void firstListenerAdded() { >+ knownMasterValues = new WritableSet(getRealm()); >+ cachedValues = new HashMap(); >+ 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(); >+ detailProperty.removeListener(key, detailListener); >+ cachedValues.remove(wrapper); >+ } >+ for (Iterator it = event.diff.getAdditions().iterator(); it >+ .hasNext();) { >+ IdentityWrapper wrapper = (IdentityWrapper) it.next(); >+ Object key = wrapper.unwrap(); >+ cachedValues.put(wrapper, detailProperty.getValue(key)); >+ detailProperty.addListener(key, detailListener); >+ } >+ } >+ }); >+ for (Iterator it = masterMap.values().iterator(); it.hasNext();) { >+ knownMasterValues.add(new IdentityWrapper(it.next())); >+ } >+ >+ masterMap.addMapChangeListener(masterListener); >+ masterMap.addStaleListener(staleListener); >+ } >+ >+ protected void lastListenerRemoved() { >+ masterMap.removeMapChangeListener(masterListener); >+ masterMap.removeStaleListener(staleListener); >+ if (knownMasterValues != null) { >+ knownMasterValues.clear(); // removes attached listeners >+ knownMasterValues.dispose(); >+ knownMasterValues = null; >+ } >+ cachedValues.clear(); >+ cachedValues = null; >+ } >+ >+ private Set entrySet; >+ >+ public Set entrySet() { >+ getterCalled(); >+ if (entrySet == null) >+ entrySet = new EntrySet(); >+ return entrySet; >+ } >+ >+ class EntrySet extends AbstractSet { >+ public Iterator iterator() { >+ return new Iterator() { >+ Iterator it = masterMap.entrySet().iterator(); >+ >+ public boolean hasNext() { >+ getterCalled(); >+ return it.hasNext(); >+ } >+ >+ public Object next() { >+ getterCalled(); >+ Map.Entry next = (Map.Entry) it.next(); >+ return new MapEntry(next.getKey()); >+ } >+ >+ public void remove() { >+ it.remove(); >+ } >+ }; >+ } >+ >+ public int size() { >+ return masterMap.size(); >+ } >+ } >+ >+ class MapEntry implements Map.Entry { >+ private Object key; >+ >+ MapEntry(Object key) { >+ this.key = key; >+ } >+ >+ public Object getKey() { >+ getterCalled(); >+ return key; >+ } >+ >+ public Object getValue() { >+ getterCalled(); >+ if (!masterMap.containsKey(key)) >+ return null; >+ return detailProperty.getValue(masterMap.get(key)); >+ } >+ >+ public Object setValue(Object value) { >+ if (!masterMap.containsKey(key)) >+ return null; >+ Object source = masterMap.get(key); >+ >+ Object oldValue = detailProperty.getValue(source); >+ >+ updating = true; >+ try { >+ detailProperty.setValue(source, value); >+ } finally { >+ updating = false; >+ } >+ >+ notifyIfChanged(source); >+ >+ return oldValue; >+ } >+ >+ public boolean equals(Object o) { >+ getterCalled(); >+ if (o == this) >+ return true; >+ if (o == null) >+ return false; >+ if (!(o instanceof Map.Entry)) >+ return false; >+ Map.Entry that = (Map.Entry) o; >+ return Util.equals(this.getKey(), that.getKey()) >+ && Util.equals(this.getValue(), that.getValue()); >+ } >+ >+ public int hashCode() { >+ getterCalled(); >+ Object value = getValue(); >+ return (key == null ? 0 : key.hashCode()) >+ ^ (value == null ? 0 : value.hashCode()); >+ } >+ } >+ >+ public Object put(Object key, Object value) { >+ if (!masterMap.containsKey(key)) >+ return null; >+ Object masterValue = masterMap.get(key); >+ Object oldValue = detailProperty.getValue(key); >+ detailProperty.setValue(masterValue, value); >+ notifyIfChanged(masterValue); >+ return oldValue; >+ } >+ >+ private void notifyIfChanged(Object masterValue) { >+ if (cachedValues != null) { >+ final Set keys = keysFor(masterValue); >+ >+ final Object oldValue = cachedValues.get(new IdentityWrapper( >+ masterValue)); >+ final Object newValue = detailProperty.getValue(masterValue); >+ >+ if (!Util.equals(oldValue, newValue)) { >+ cachedValues.put(new IdentityWrapper(masterValue), newValue); >+ fireMapChange(new MapDiff() { >+ public Set getAddedKeys() { >+ return Collections.EMPTY_SET; >+ } >+ >+ public Set getChangedKeys() { >+ return keys; >+ } >+ >+ public Set getRemovedKeys() { >+ return Collections.EMPTY_SET; >+ } >+ >+ public Object getNewValue(Object key) { >+ return newValue; >+ } >+ >+ public Object getOldValue(Object key) { >+ return oldValue; >+ } >+ }); >+ } >+ } >+ } >+ >+ private Set keysFor(Object value) { >+ Set keys = new HashSet(); >+ >+ for (Iterator it = masterMap.entrySet().iterator(); it.hasNext();) { >+ Map.Entry entry = (Entry) it.next(); >+ if (entry.getValue() == value) { >+ keys.add(entry.getKey()); >+ } >+ } >+ >+ return keys; >+ } >+ >+ public boolean isStale() { >+ getterCalled(); >+ return masterMap.isStale(); >+ } >+ >+ private void getterCalled() { >+ ObservableTracker.getterCalled(this); >+ } >+ >+ public Object getObserved() { >+ return masterMap; >+ } >+ >+ public IProperty getProperty() { >+ return detailProperty; >+ } >+ >+ public synchronized void dispose() { >+ if (masterMap != null) { >+ masterMap.removeMapChangeListener(masterListener); >+ masterMap = null; >+ } >+ if (knownMasterValues != null) { >+ knownMasterValues.clear(); // detaches listeners >+ knownMasterValues.dispose(); >+ knownMasterValues = null; >+ } >+ >+ masterListener = null; >+ detailListener = null; >+ detailProperty = null; >+ cachedValues = null; >+ >+ super.dispose(); >+ } >+} >Index: src/org/eclipse/core/internal/databinding/property/value/ObservableListSimpleValuePropertyObservableList.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/property/value/ObservableListSimpleValuePropertyObservableList.java >diff -N src/org/eclipse/core/internal/databinding/property/value/ObservableListSimpleValuePropertyObservableList.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/property/value/ObservableListSimpleValuePropertyObservableList.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,449 @@ >+/******************************************************************************* >+ * 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 194734) >+ ******************************************************************************/ >+ >+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; >+import java.util.Map; >+import java.util.Set; >+ >+import org.eclipse.core.databinding.observable.Diffs; >+import org.eclipse.core.databinding.observable.IStaleListener; >+import org.eclipse.core.databinding.observable.ObservableTracker; >+import org.eclipse.core.databinding.observable.StaleEvent; >+import org.eclipse.core.databinding.observable.list.AbstractObservableList; >+import org.eclipse.core.databinding.observable.list.IListChangeListener; >+import org.eclipse.core.databinding.observable.list.IObservableList; >+import org.eclipse.core.databinding.observable.list.ListChangeEvent; >+import org.eclipse.core.databinding.observable.list.ListDiff; >+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.IPropertyChangeListener; >+import org.eclipse.core.databinding.property.IPropertyObservable; >+import org.eclipse.core.databinding.property.PropertyChangeEvent; >+import org.eclipse.core.databinding.property.value.SimpleValueProperty; >+import org.eclipse.core.internal.databinding.IdentityWrapper; >+import org.eclipse.core.internal.databinding.Util; >+ >+/** >+ * @since 1.2 >+ */ >+public class ObservableListSimpleValuePropertyObservableList extends >+ AbstractObservableList implements IPropertyObservable { >+ private IObservableList masterList; >+ private SimpleValueProperty detailProperty; >+ >+ private IObservableSet knownMasterElements; >+ private Map cachedValues; >+ >+ private boolean updating; >+ >+ private IListChangeListener masterListener = new IListChangeListener() { >+ public void handleListChange(ListChangeEvent event) { >+ if (!isDisposed()) { >+ updateKnownElements(); >+ fireListChange(convertDiff(event.diff)); >+ } >+ } >+ >+ private void updateKnownElements() { >+ Set identityKnownElements = new HashSet(); >+ for (Iterator it = masterList.iterator(); it.hasNext();) { >+ identityKnownElements.add(new IdentityWrapper(it.next())); >+ } >+ >+ knownMasterElements.retainAll(identityKnownElements); >+ knownMasterElements.addAll(identityKnownElements); >+ } >+ >+ private ListDiff convertDiff(ListDiff diff) { >+ // Convert diff to detail value >+ ListDiffEntry[] masterEntries = diff.getDifferences(); >+ ListDiffEntry[] detailEntries = new ListDiffEntry[masterEntries.length]; >+ for (int i = 0; i < masterEntries.length; i++) { >+ ListDiffEntry masterDifference = masterEntries[i]; >+ int index = masterDifference.getPosition(); >+ boolean addition = masterDifference.isAddition(); >+ Object masterElement = masterDifference.getElement(); >+ Object elementDetailValue = detailProperty >+ .getValue(masterElement); >+ detailEntries[i] = Diffs.createListDiffEntry(index, addition, >+ elementDetailValue); >+ } >+ return Diffs.createListDiff(detailEntries); >+ } >+ }; >+ >+ private IStaleListener staleListener = new IStaleListener() { >+ public void handleStale(StaleEvent staleEvent) { >+ fireStale(); >+ } >+ }; >+ >+ private INativePropertyListener detailListener; >+ >+ /** >+ * @param masterList >+ * @param valueProperty >+ */ >+ public ObservableListSimpleValuePropertyObservableList( >+ IObservableList masterList, SimpleValueProperty valueProperty) { >+ super(masterList.getRealm()); >+ this.masterList = masterList; >+ this.detailProperty = valueProperty; >+ >+ IPropertyChangeListener listener = new IPropertyChangeListener() { >+ public void handlePropertyChange(PropertyChangeEvent event) { >+ if (!isDisposed() && !updating) { >+ notifyIfChanged(event.getSource()); >+ } >+ } >+ }; >+ this.detailListener = detailProperty.adaptListener(listener); >+ } >+ >+ protected void firstListenerAdded() { >+ knownMasterElements = new WritableSet(getRealm()); >+ cachedValues = new HashMap(); >+ 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(); >+ detailProperty.removeListener(key, detailListener); >+ cachedValues.remove(wrapper); >+ } >+ for (Iterator it = event.diff.getAdditions().iterator(); it >+ .hasNext();) { >+ IdentityWrapper wrapper = (IdentityWrapper) it.next(); >+ Object key = wrapper.unwrap(); >+ cachedValues.put(wrapper, detailProperty.getValue(key)); >+ detailProperty.addListener(key, detailListener); >+ } >+ } >+ }); >+ for (Iterator it = masterList.iterator(); it.hasNext();) { >+ knownMasterElements.add(new IdentityWrapper(it.next())); >+ } >+ >+ masterList.addListChangeListener(masterListener); >+ masterList.addStaleListener(staleListener); >+ } >+ >+ protected void lastListenerRemoved() { >+ masterList.removeListChangeListener(masterListener); >+ masterList.removeStaleListener(staleListener); >+ if (knownMasterElements != null) { >+ knownMasterElements.clear(); // clears cachedValues >+ knownMasterElements.dispose(); >+ knownMasterElements = null; >+ } >+ cachedValues.clear(); >+ cachedValues = null; >+ } >+ >+ protected int doGetSize() { >+ getterCalled(); >+ return masterList.size(); >+ } >+ >+ private void getterCalled() { >+ ObservableTracker.getterCalled(this); >+ } >+ >+ public Object getElementType() { >+ return detailProperty.getValueType(); >+ } >+ >+ public Object get(int index) { >+ getterCalled(); >+ Object masterElement = masterList.get(index); >+ return detailProperty.getValue(masterElement); >+ } >+ >+ public boolean add(Object o) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public boolean addAll(Collection c) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public boolean addAll(int index, Collection c) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public boolean contains(Object o) { >+ getterCalled(); >+ >+ for (Iterator it = masterList.iterator(); it.hasNext();) { >+ if (Util.equals(detailProperty.getValue(it.next()), o)) >+ return true; >+ } >+ return false; >+ } >+ >+ public boolean isEmpty() { >+ getterCalled(); >+ return masterList.isEmpty(); >+ } >+ >+ public boolean isStale() { >+ getterCalled(); >+ return masterList.isStale(); >+ } >+ >+ public Iterator iterator() { >+ getterCalled(); >+ return new Iterator() { >+ Iterator it = masterList.iterator(); >+ >+ public boolean hasNext() { >+ getterCalled(); >+ return it.hasNext(); >+ } >+ >+ public Object next() { >+ getterCalled(); >+ Object masterElement = it.next(); >+ return detailProperty.getValue(masterElement); >+ } >+ >+ public void remove() { >+ throw new UnsupportedOperationException(); >+ } >+ }; >+ } >+ >+ public Object move(int oldIndex, int newIndex) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public boolean remove(Object o) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public boolean removeAll(Collection c) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public boolean retainAll(Collection c) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public Object[] toArray() { >+ getterCalled(); >+ Object[] masterElements = masterList.toArray(); >+ Object[] result = new Object[masterElements.length]; >+ for (int i = 0; i < result.length; i++) { >+ result[i] = detailProperty.getValue(masterElements[i]); >+ } >+ return result; >+ } >+ >+ public Object[] toArray(Object[] a) { >+ getterCalled(); >+ Object[] masterElements = masterList.toArray(); >+ if (a.length < masterElements.length) >+ a = (Object[]) Array.newInstance(a.getClass().getComponentType(), >+ masterElements.length); >+ for (int i = 0; i < masterElements.length; i++) { >+ a[i] = detailProperty.getValue(masterElements[i]); >+ } >+ return a; >+ } >+ >+ public void add(int index, Object o) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public void clear() { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public ListIterator listIterator() { >+ return listIterator(0); >+ } >+ >+ public ListIterator listIterator(final int index) { >+ getterCalled(); >+ return new ListIterator() { >+ ListIterator it = masterList.listIterator(index); >+ Object lastMasterElement; >+ Object lastElement; >+ boolean haveIterated = false; >+ >+ public void add(Object arg0) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public boolean hasNext() { >+ getterCalled(); >+ return it.hasNext(); >+ } >+ >+ public boolean hasPrevious() { >+ getterCalled(); >+ return it.hasPrevious(); >+ } >+ >+ public Object next() { >+ getterCalled(); >+ lastMasterElement = it.next(); >+ lastElement = detailProperty.getValue(lastMasterElement); >+ haveIterated = true; >+ return lastElement; >+ } >+ >+ public int nextIndex() { >+ getterCalled(); >+ return it.nextIndex(); >+ } >+ >+ public Object previous() { >+ getterCalled(); >+ lastMasterElement = it.previous(); >+ lastElement = detailProperty.getValue(lastMasterElement); >+ haveIterated = true; >+ return lastElement; >+ } >+ >+ public int previousIndex() { >+ getterCalled(); >+ return it.previousIndex(); >+ } >+ >+ public void remove() { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public void set(Object o) { >+ checkRealm(); >+ if (!haveIterated) >+ throw new IllegalStateException(); >+ >+ boolean wasUpdating = updating; >+ updating = true; >+ try { >+ detailProperty.setValue(lastElement, o); >+ } finally { >+ updating = wasUpdating; >+ } >+ >+ notifyIfChanged(lastMasterElement); >+ >+ lastElement = o; >+ } >+ }; >+ } >+ >+ private void notifyIfChanged(Object masterElement) { >+ if (cachedValues != null) { >+ Object oldValue = cachedValues.get(new IdentityWrapper( >+ masterElement)); >+ Object newValue = detailProperty.getValue(masterElement); >+ if (!Util.equals(oldValue, newValue)) { >+ cachedValues.put(new IdentityWrapper(masterElement), newValue); >+ fireListChange(indicesOf(masterElement), oldValue, newValue); >+ } >+ } >+ } >+ >+ private int[] indicesOf(Object masterElement) { >+ List indices = new ArrayList(); >+ >+ for (ListIterator it = ObservableListSimpleValuePropertyObservableList.this.masterList >+ .listIterator(); it.hasNext();) { >+ if (masterElement == it.next()) >+ indices.add(new Integer(it.previousIndex())); >+ } >+ >+ int[] result = new int[indices.size()]; >+ for (int i = 0; i < result.length; i++) { >+ result[i] = ((Integer) indices.get(i)).intValue(); >+ } >+ return result; >+ } >+ >+ private void fireListChange(int[] indices, Object oldValue, Object newValue) { >+ ListDiffEntry[] differences = new ListDiffEntry[indices.length * 2]; >+ for (int i = 0; i < indices.length; i++) { >+ int index = indices[i]; >+ differences[i * 2] = Diffs.createListDiffEntry(index, false, >+ oldValue); >+ differences[i * 2 + 1] = Diffs.createListDiffEntry(index, true, >+ newValue); >+ } >+ fireListChange(Diffs.createListDiff(differences)); >+ } >+ >+ public Object remove(int index) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public Object set(int index, Object o) { >+ checkRealm(); >+ Object masterElement = masterList.get(index); >+ Object oldValue = detailProperty.getValue(masterElement); >+ >+ boolean wasUpdating = updating; >+ updating = true; >+ try { >+ detailProperty.setValue(masterElement, o); >+ } finally { >+ updating = wasUpdating; >+ } >+ >+ notifyIfChanged(masterElement); >+ >+ return oldValue; >+ } >+ >+ public Object getObserved() { >+ return masterList; >+ } >+ >+ public IProperty getProperty() { >+ return detailProperty; >+ } >+ >+ public synchronized void dispose() { >+ if (masterList != null) { >+ masterList.removeListChangeListener(masterListener); >+ masterList = null; >+ } >+ if (knownMasterElements != null) { >+ knownMasterElements.clear(); // detaches listeners >+ knownMasterElements.dispose(); >+ knownMasterElements = null; >+ } >+ >+ masterListener = null; >+ detailListener = null; >+ detailProperty = null; >+ cachedValues = null; >+ >+ super.dispose(); >+ } >+} >\ No newline at end of file >Index: src/org/eclipse/core/internal/databinding/property/value/DelegatingCache.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/property/value/DelegatingCache.java >diff -N src/org/eclipse/core/internal/databinding/property/value/DelegatingCache.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/property/value/DelegatingCache.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,210 @@ >+/******************************************************************************* >+ * Copyright (c) 2009 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.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; >+ >+import org.eclipse.core.databinding.observable.Realm; >+import org.eclipse.core.databinding.observable.map.IMapChangeListener; >+import org.eclipse.core.databinding.observable.map.IObservableMap; >+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; >+ >+/** >+ * @since 3.3 >+ * >+ */ >+abstract class DelegatingCache { >+ private Realm realm; >+ private DelegatingValueProperty detailProperty; >+ private IObservableSet elements; >+ private Map delegateCaches; >+ >+ private class DelegateCache implements IMapChangeListener { >+ private final IValueProperty delegate; >+ private final IObservableSet masterElements; >+ private final IObservableMap masterElementValues; >+ private final Map cachedValues; >+ >+ DelegateCache(IValueProperty delegate) { >+ this.delegate = delegate; >+ this.masterElements = new WritableSet(realm, Collections.EMPTY_SET, >+ elements.getElementType()); >+ this.masterElementValues = delegate.observeDetail(masterElements); >+ this.cachedValues = new HashMap(); >+ >+ masterElementValues.addMapChangeListener(this); >+ } >+ >+ void add(Object masterElement) { >+ boolean wasEmpty = masterElements.isEmpty(); >+ >+ masterElements.add(masterElement); >+ cachedValues.put(new IdentityWrapper(masterElement), >+ masterElementValues.get(masterElement)); >+ >+ if (wasEmpty) >+ delegateCaches.put(delegate, this); >+ } >+ >+ void remove(Object masterElement) { >+ cachedValues.remove(new IdentityWrapper(masterElement)); >+ masterElements.remove(masterElement); >+ if (cachedValues.isEmpty()) >+ dispose(); >+ } >+ >+ Object get(Object masterElement) { >+ return cachedValues.get(new IdentityWrapper(masterElement)); >+ } >+ >+ Object put(Object masterElement, Object detailValue) { >+ Object oldValue = masterElementValues.put(masterElement, >+ detailValue); >+ notifyIfChanged(masterElement); >+ return oldValue; >+ } >+ >+ boolean containsValue(Object detailValue) { >+ return cachedValues.containsValue(detailValue); >+ } >+ >+ public void handleMapChange(MapChangeEvent event) { >+ Set changedKeys = event.diff.getChangedKeys(); >+ for (Iterator it = changedKeys.iterator(); it.hasNext();) >+ notifyIfChanged(it.next()); >+ } >+ >+ private void notifyIfChanged(Object masterElement) { >+ Object oldValue = cachedValues.get(new IdentityWrapper( >+ masterElement)); >+ Object newValue = masterElementValues.get(masterElement); >+ if (!Util.equals(oldValue, newValue)) { >+ cachedValues.put(new IdentityWrapper(masterElement), newValue); >+ handleValueChange(masterElement, oldValue, newValue); >+ } >+ } >+ >+ void handleValueChange(Object masterElement, Object oldValue, >+ Object newValue) { >+ DelegatingCache.this.handleValueChange(masterElement, oldValue, >+ newValue); >+ } >+ >+ void dispose() { >+ delegateCaches.remove(delegate); >+ masterElementValues.dispose(); >+ masterElements.dispose(); >+ cachedValues.clear(); >+ } >+ } >+ >+ DelegatingCache(Realm realm, DelegatingValueProperty detailProperty) { >+ this.realm = realm; >+ this.detailProperty = detailProperty; >+ >+ this.elements = new WritableSet(realm); >+ this.delegateCaches = new HashMap(); >+ >+ 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(); >+ getCache(element).remove(element); >+ >+ } >+ for (Iterator it = event.diff.getAdditions().iterator(); it >+ .hasNext();) { >+ IdentityWrapper wrapper = (IdentityWrapper) it.next(); >+ Object element = wrapper.unwrap(); >+ getCache(element).add(element); >+ } >+ } >+ }); >+ } >+ >+ private DelegateCache getCache(Object masterElement) { >+ IValueProperty delegate = detailProperty.getDelegate(masterElement); >+ if (delegateCaches.containsKey(delegate)) { >+ return (DelegateCache) delegateCaches.get(delegate); >+ } >+ return new DelegateCache(delegate); >+ } >+ >+ Object get(Object element) { >+ return getCache(element).get(element); >+ } >+ >+ Object put(Object element, Object value) { >+ return getCache(element).put(element, value); >+ } >+ >+ boolean contains(Object value) { >+ for (Iterator it = delegateCaches.values().iterator(); it.hasNext();) { >+ DelegateCache cache = (DelegateCache) it.next(); >+ if (cache.containsValue(value)) >+ return true; >+ } >+ 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)); >+ } >+ >+ void retainAll(Collection elements) { >+ this.elements.retainAll(identitySet(elements)); >+ } >+ >+ abstract void handleValueChange(Object masterElement, Object oldValue, >+ Object newValue); >+ >+ void dispose() { >+ if (elements != null) { >+ elements.clear(); // clears caches >+ elements.dispose(); >+ elements = null; >+ } >+ >+ if (delegateCaches != null) { >+ for (Iterator it = delegateCaches.values().iterator(); it.hasNext();) { >+ DelegateCache cache = (DelegateCache) it.next(); >+ cache.dispose(); >+ } >+ delegateCaches.clear(); >+ delegateCaches = null; >+ } >+ } >+} >Index: src/org/eclipse/core/internal/databinding/property/value/SimpleValuePropertyObservableValue.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/property/value/SimpleValuePropertyObservableValue.java >diff -N src/org/eclipse/core/internal/databinding/property/value/SimpleValuePropertyObservableValue.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/property/value/SimpleValuePropertyObservableValue.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,131 @@ >+/******************************************************************************* >+ * 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 194734) >+ ******************************************************************************/ >+ >+package org.eclipse.core.internal.databinding.property.value; >+ >+import org.eclipse.core.databinding.observable.Diffs; >+import org.eclipse.core.databinding.observable.Realm; >+import org.eclipse.core.databinding.observable.value.AbstractObservableValue; >+import org.eclipse.core.databinding.observable.value.ValueDiff; >+import org.eclipse.core.databinding.property.INativePropertyListener; >+import org.eclipse.core.databinding.property.IProperty; >+import org.eclipse.core.databinding.property.IPropertyChangeListener; >+import org.eclipse.core.databinding.property.IPropertyObservable; >+import org.eclipse.core.databinding.property.PropertyChangeEvent; >+import org.eclipse.core.databinding.property.value.SimpleValueProperty; >+import org.eclipse.core.internal.databinding.Util; >+ >+/** >+ * @since 1.2 >+ * >+ */ >+public class SimpleValuePropertyObservableValue extends AbstractObservableValue >+ implements IPropertyObservable { >+ private Object source; >+ private SimpleValueProperty property; >+ >+ private boolean updating = false; >+ private Object cachedValue; >+ >+ private INativePropertyListener listener; >+ >+ /** >+ * @param realm >+ * @param source >+ * @param property >+ */ >+ public SimpleValuePropertyObservableValue(Realm realm, Object source, >+ SimpleValueProperty property) { >+ super(realm); >+ this.source = source; >+ this.property = property; >+ } >+ >+ protected void firstListenerAdded() { >+ if (!isDisposed()) { >+ cachedValue = property.getValue(source); >+ if (listener == null) { >+ listener = property >+ .adaptListener(new IPropertyChangeListener() { >+ public void handlePropertyChange( >+ final PropertyChangeEvent event) { >+ if (!isDisposed() && !updating) { >+ getRealm().exec(new Runnable() { >+ public void run() { >+ notifyIfChanged((ValueDiff) event.diff); >+ } >+ }); >+ } >+ } >+ }); >+ } >+ property.addListener(source, listener); >+ } >+ } >+ >+ protected void lastListenerRemoved() { >+ if (listener != null) { >+ property.removeListener(source, listener); >+ } >+ cachedValue = null; >+ } >+ >+ protected Object doGetValue() { >+ notifyIfChanged(null); >+ return property.getValue(source); >+ } >+ >+ protected void doSetValue(Object value) { >+ updating = true; >+ try { >+ property.setValue(source, value); >+ } finally { >+ updating = false; >+ } >+ >+ notifyIfChanged(null); >+ } >+ >+ private void notifyIfChanged(ValueDiff diff) { >+ if (hasListeners()) { >+ Object oldValue = cachedValue; >+ Object newValue = cachedValue = property.getValue(source); >+ if (diff == null) >+ diff = Diffs.createValueDiff(oldValue, newValue); >+ if (hasListeners() && !Util.equals(oldValue, newValue)) { >+ fireValueChange(diff); >+ } >+ } >+ } >+ >+ public Object getValueType() { >+ return property.getValueType(); >+ } >+ >+ public Object getObserved() { >+ return source; >+ } >+ >+ public IProperty getProperty() { >+ return property; >+ } >+ >+ public synchronized void dispose() { >+ if (!isDisposed()) { >+ if (listener != null) >+ property.removeListener(source, listener); >+ source = null; >+ property = null; >+ listener = null; >+ } >+ super.dispose(); >+ } >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 194734
:
106529
|
107000
|
107001
|
107041
|
107042
|
111164
|
111165
|
111335
|
111336
|
111448
|
111449
|
111640
|
111641
|
111717
|
111719
|
111845
|
111846
|
111897
|
111898
|
111993
|
111994
|
112161
|
112162
|
112268
|
112269
|
112360
|
112361
|
112370
|
112371
|
112471
|
112472
|
112606
|
112607
|
112629
|
112630
|
113149
|
113150
|
113165
|
113166
|
114858
|
114859
|
115196
|
115197
|
115284
|
115458
|
115459
|
117500
|
117501
|
117990
|
117991
|
119231
|
119232
|
119274
|
120541
|
120542
|
120651
|
120652
|
120653
|
120654
|
120914
|
120915
|
120989
|
120990
|
121020
|
121021
|
121141
|
121142
|
122228
|
122229
|
122234
|
122235
|
122288
|
122289
|
122609
|
122610
|
122613
|
122614
|
122775
|
122776
| 122813 |
122814
|
122852
|
122853
|
122864
|
122865
|
123137
|
123138