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 111717 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]
Progress patch
clipboard.txt (text/plain), 317.27 KB, created by
Matthew Hall
on 2008-09-04 16:48:38 EDT
(
hide
)
Description:
Progress patch
Filename:
MIME Type:
Creator:
Matthew Hall
Created:
2008-09-04 16:48:38 EDT
Size:
317.27 KB
patch
obsolete
>### Eclipse Workspace Patch 1.0 >#P org.eclipse.jface.tests.databinding >Index: src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableMapTest.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableMapTest.java,v >retrieving revision 1.4 >diff -u -r1.4 JavaBeanObservableMapTest.java >--- src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableMapTest.java 21 Jul 2008 20:59:39 -0000 1.4 >+++ src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableMapTest.java 4 Sep 2008 20:45:16 -0000 >@@ -7,7 +7,7 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >- * Matthew Hall - bugs 213145, 241585 >+ * Matthew Hall - bugs 213145, 241585, 194734 > *******************************************************************************/ > > package org.eclipse.core.tests.internal.databinding.beans; >@@ -19,12 +19,17 @@ > import junit.framework.TestCase; > import junit.framework.TestSuite; > >+import org.eclipse.core.databinding.beans.BeanProperties; >+import org.eclipse.core.databinding.beans.BeansObservables; >+import org.eclipse.core.databinding.beans.IBeanObservable; >+import org.eclipse.core.databinding.beans.IBeanProperty; >+import org.eclipse.core.databinding.beans.PojoObservables; > 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.map.MapDiff; > import org.eclipse.core.databinding.observable.set.WritableSet; >-import org.eclipse.core.internal.databinding.beans.JavaBeanObservableMap; > import org.eclipse.core.tests.databinding.observable.ThreadRealm; > import org.eclipse.jface.databinding.conformance.util.ChangeEventTracker; > import org.eclipse.jface.databinding.conformance.util.CurrentRealm; >@@ -42,7 +47,8 @@ > > private PropertyDescriptor propertyDescriptor; > >- private JavaBeanObservableMap map; >+ private IObservableMap map; >+ private IBeanObservable beanObservable; > > protected void setUp() throws Exception { > ThreadRealm realm = new ThreadRealm(); >@@ -54,8 +60,11 @@ > set.add(model1); > set.add(model2); > >- propertyDescriptor = new PropertyDescriptor("value", Bean.class); >- map = new JavaBeanObservableMap(set, propertyDescriptor); >+ String propertyName = "value"; >+ propertyDescriptor = ((IBeanProperty) BeanProperties.valueProperty( >+ Bean.class, propertyName)).getPropertyDescriptor(); >+ map = BeansObservables.observeMap(set, Bean.class, propertyName); >+ beanObservable = (IBeanObservable) map; > } > > public void testGetValue() throws Exception { >@@ -135,11 +144,11 @@ > } > > public void testGetObserved() throws Exception { >- assertEquals(set, map.getObserved()); >+ assertEquals(set, beanObservable.getObserved()); > } > > public void testGetPropertyDescriptor() throws Exception { >- assertEquals(propertyDescriptor, map.getPropertyDescriptor()); >+ assertEquals(propertyDescriptor, beanObservable.getPropertyDescriptor()); > } > > public void testConstructor_SkipRegisterListeners() throws Exception { >@@ -148,7 +157,9 @@ > Bean bean = new Bean(); > set.add(bean); > >- JavaBeanObservableMap observable = new JavaBeanObservableMap(set, new PropertyDescriptor("value", Bean.class), false); >+ IObservableMap observable = PojoObservables.observeMap(set, Bean.class, >+ "value"); >+ assertFalse(bean.hasListeners("value")); > ChangeEventTracker.observe(observable); > > assertFalse(bean.hasListeners("value")); >@@ -160,7 +171,9 @@ > Bean bean = new Bean(); > set.add(bean); > >- JavaBeanObservableMap observable = new JavaBeanObservableMap(set, new PropertyDescriptor("value", Bean.class)); >+ IObservableMap observable = BeansObservables.observeMap(set, >+ Bean.class, "value"); >+ assertFalse(bean.hasListeners("value")); > ChangeEventTracker.observe(observable); > > assertTrue(bean.hasListeners("value")); >Index: src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableValueTest.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableValueTest.java,v >retrieving revision 1.2 >diff -u -r1.2 JavaBeanObservableValueTest.java >--- src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableValueTest.java 20 Mar 2008 21:16:40 -0000 1.2 >+++ src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableValueTest.java 4 Sep 2008 20:45:16 -0000 >@@ -9,25 +9,27 @@ > * Brad Reynolds - initial API and implementation > * Brad Reynolds - bug 171616 > * Katarzyna Marszalek - test case for bug 198519 >- * Matthew Hall - bug 213145 >+ * Matthew Hall - bugs 213145, 194734 > ******************************************************************************/ > > package org.eclipse.core.tests.internal.databinding.beans; > >-import java.beans.IntrospectionException; > import java.beans.PropertyDescriptor; > > import junit.framework.Test; > import junit.framework.TestSuite; > >+import org.eclipse.core.databinding.beans.BeanProperties; > import org.eclipse.core.databinding.beans.BeansObservables; >+import org.eclipse.core.databinding.beans.IBeanObservable; >+import org.eclipse.core.databinding.beans.IBeanProperty; >+import org.eclipse.core.databinding.beans.PojoObservables; > import org.eclipse.core.databinding.observable.ChangeEvent; > import org.eclipse.core.databinding.observable.IChangeListener; > import org.eclipse.core.databinding.observable.IObservable; > import org.eclipse.core.databinding.observable.Realm; > import org.eclipse.core.databinding.observable.value.ComputedValue; > import org.eclipse.core.databinding.observable.value.IObservableValue; >-import org.eclipse.core.internal.databinding.beans.JavaBeanObservableValue; > import org.eclipse.jface.databinding.conformance.MutableObservableValueContractTest; > import org.eclipse.jface.databinding.conformance.delegate.AbstractObservableValueContractDelegate; > import org.eclipse.jface.databinding.conformance.util.ChangeEventTracker; >@@ -39,35 +41,34 @@ > */ > public class JavaBeanObservableValueTest extends AbstractDefaultRealmTestCase { > private Bean bean; >- private JavaBeanObservableValue observableValue; >+ private IObservableValue observableValue; >+ private IBeanObservable beanObservable; > private PropertyDescriptor propertyDescriptor; > private String propertyName; > >- /* (non-Javadoc) >- * @see junit.framework.TestCase#setUp() >- */ > protected void setUp() throws Exception { > super.setUp(); > > bean = new Bean(); > propertyName = "value"; >- propertyDescriptor = new PropertyDescriptor(propertyName, Bean.class); >- observableValue = new JavaBeanObservableValue(Realm.getDefault(), bean, propertyDescriptor); >+ propertyDescriptor = ((IBeanProperty) BeanProperties.valueProperty( >+ Bean.class, propertyName)).getPropertyDescriptor(); >+ observableValue = BeansObservables.observeValue(bean, propertyName); >+ beanObservable = (IBeanObservable) observableValue; > } > > public void testGetObserved() throws Exception { >- assertEquals(bean, observableValue.getObserved()); >+ assertEquals(bean, beanObservable.getObserved()); > } > > public void testGetPropertyDescriptor() throws Exception { >- assertEquals(propertyDescriptor, observableValue.getPropertyDescriptor()); >+ assertEquals(propertyDescriptor, beanObservable.getPropertyDescriptor()); > } > > public void testSetValueThrowsExceptionThrownByBean() throws Exception { > ThrowsSetException temp = new ThrowsSetException(); >- JavaBeanObservableValue observable = new JavaBeanObservableValue(Realm >- .getDefault(), temp, >- new PropertyDescriptor("value", ThrowsSetException.class)); >+ IObservableValue observable = BeansObservables.observeValue(temp, >+ "value"); > > try { > observable.setValue(""); >@@ -79,9 +80,8 @@ > > public void testGetValueThrowsExceptionThrownByBean() throws Exception { > ThrowsGetException temp = new ThrowsGetException(); >- JavaBeanObservableValue observable = new JavaBeanObservableValue(Realm >- .getDefault(), temp, >- new PropertyDescriptor("value", ThrowsGetException.class)); >+ IObservableValue observable = BeansObservables.observeValue(temp, >+ "value"); > > try { > observable.getValue(); >@@ -108,14 +108,16 @@ > } > > public void testConstructor_RegistersListeners() throws Exception { >- JavaBeanObservableValue observable = new JavaBeanObservableValue(Realm.getDefault(), bean, propertyDescriptor); >+ IObservableValue observable = BeansObservables.observeValue(bean, >+ propertyName); > ChangeEventTracker.observe(observable); > > assertTrue(bean.hasListeners(propertyName)); > } > > public void testConstructor_SkipRegisterListeners() throws Exception { >- JavaBeanObservableValue observable = new JavaBeanObservableValue(Realm.getDefault(), bean, propertyDescriptor, false); >+ IObservableValue observable = PojoObservables.observeValue(bean, >+ propertyName); > ChangeEventTracker.observe(observable); > > assertFalse(bean.hasListeners(propertyName)); >@@ -138,13 +140,7 @@ > } > > public IObservableValue createObservableValue(Realm realm) { >- try { >- PropertyDescriptor propertyDescriptor = new PropertyDescriptor("value", Bean.class); >- return new JavaBeanObservableValue(realm, bean, >- propertyDescriptor); >- } catch (IntrospectionException e) { >- throw new RuntimeException(e); >- } >+ return BeansObservables.observeValue(realm, bean, "value"); > } > > public void change(IObservable observable) { >Index: src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableArrayBasedListTest.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableArrayBasedListTest.java,v >retrieving revision 1.2 >diff -u -r1.2 JavaBeanObservableArrayBasedListTest.java >--- src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableArrayBasedListTest.java 20 Mar 2008 21:16:40 -0000 1.2 >+++ src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableArrayBasedListTest.java 4 Sep 2008 20:45:15 -0000 >@@ -7,12 +7,11 @@ > * > * Contributors: > * Brad Reynolds - initial API and implementation >- * Matthew Hall - bugs 221351, 213145 >+ * Matthew Hall - bugs 221351, 213145, 194734 > ******************************************************************************/ > > package org.eclipse.core.tests.internal.databinding.beans; > >-import java.beans.IntrospectionException; > import java.beans.PropertyChangeEvent; > import java.beans.PropertyChangeListener; > import java.beans.PropertyDescriptor; >@@ -23,13 +22,16 @@ > import junit.framework.Test; > import junit.framework.TestSuite; > >+import org.eclipse.core.databinding.beans.BeanProperties; >+import org.eclipse.core.databinding.beans.BeansObservables; >+import org.eclipse.core.databinding.beans.IBeanObservable; >+import org.eclipse.core.databinding.beans.IBeanProperty; > import org.eclipse.core.databinding.observable.IObservable; > import org.eclipse.core.databinding.observable.IObservableCollection; > import org.eclipse.core.databinding.observable.Realm; > import org.eclipse.core.databinding.observable.list.IObservableList; > import org.eclipse.core.databinding.observable.list.ListChangeEvent; > import org.eclipse.core.databinding.observable.list.ListDiffEntry; >-import org.eclipse.core.internal.databinding.beans.JavaBeanObservableList; > import org.eclipse.jface.databinding.conformance.MutableObservableListContractTest; > import org.eclipse.jface.databinding.conformance.delegate.AbstractObservableCollectionContractDelegate; > import org.eclipse.jface.databinding.conformance.util.ListChangeEventTracker; >@@ -42,7 +44,8 @@ > */ > public class JavaBeanObservableArrayBasedListTest extends > AbstractDefaultRealmTestCase { >- private JavaBeanObservableList list; >+ private IObservableList list; >+ private IBeanObservable beanObservable; > > private PropertyDescriptor propertyDescriptor; > >@@ -59,19 +62,21 @@ > super.setUp(); > > propertyName = "array"; >- propertyDescriptor = new PropertyDescriptor(propertyName, Bean.class); >+ propertyDescriptor = ((IBeanProperty) BeanProperties.listProperty( >+ Bean.class, propertyName)).getPropertyDescriptor(); > bean = new Bean(new Object[0]); > >- list = new JavaBeanObservableList(SWTObservables.getRealm(Display >- .getDefault()), bean, propertyDescriptor, Bean.class); >+ list = BeansObservables.observeList(SWTObservables.getRealm(Display >+ .getDefault()), bean, propertyName); >+ beanObservable = (IBeanObservable) list; > } > > public void testGetObserved() throws Exception { >- assertSame(bean, list.getObserved()); >+ assertSame(bean, beanObservable.getObserved()); > } > > public void testGetPropertyDescriptor() throws Exception { >- assertSame(propertyDescriptor, list.getPropertyDescriptor()); >+ assertEquals(propertyDescriptor, beanObservable.getPropertyDescriptor()); > } > > public void testRegistersListenerAfterFirstListenerIsAdded() >@@ -308,16 +313,14 @@ > } > > public void testRemoveAll() throws Exception { >- List elements = Arrays.asList(new String[] { "1", "2" }); >- list.addAll(elements); >- list.addAll(elements); >- >+ list.addAll(Arrays.asList(new String[] { "1", "2", "3", "4" })); > assertEquals(4, bean.getArray().length); >- list.removeAll(elements); >+ >+ list.removeAll(Arrays.asList(new String[] { "2", "4" })); > > assertEquals(2, bean.getArray().length); >- assertEquals(elements.get(0), bean.getArray()[0]); >- assertEquals(elements.get(1), bean.getArray()[1]); >+ assertEquals("1", bean.getArray()[0]); >+ assertEquals("3", bean.getArray()[1]); > } > > public void testRemoveAllListChangeEvent() throws Exception { >@@ -471,8 +474,10 @@ > PropertyChangeEvent event = listener.evt; > assertEquals("event did not fire", 1, listener.count); > assertEquals("array", event.getPropertyName()); >- assertTrue("old value", Arrays.equals(old, (Object[]) event.getOldValue())); >- assertTrue("new value", Arrays.equals(bean.getArray(), (Object[]) event.getNewValue())); >+ assertTrue("old value", Arrays.equals(old, (Object[]) event >+ .getOldValue())); >+ assertTrue("new value", Arrays.equals(bean.getArray(), (Object[]) event >+ .getNewValue())); > assertFalse("lists are equal", Arrays.equals(bean.getArray(), old)); > } > >@@ -482,11 +487,6 @@ > > PropertyChangeEvent evt; > >- /* >- * (non-Javadoc) >- * >- * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent) >- */ > public void propertyChange(PropertyChangeEvent evt) { > count++; > this.evt = evt; >@@ -504,17 +504,10 @@ > public IObservableCollection createObservableCollection(Realm realm, > int elementCount) { > String propertyName = "array"; >- PropertyDescriptor propertyDescriptor; >- try { >- propertyDescriptor = new PropertyDescriptor(propertyName, >- Bean.class); >- } catch (IntrospectionException e) { >- throw new RuntimeException(e); >- } > Object bean = new Bean(new Object[0]); > >- IObservableList list = new JavaBeanObservableList(realm, bean, >- propertyDescriptor, String.class); >+ IObservableList list = BeansObservables.observeList(realm, bean, >+ propertyName, String.class); > for (int i = 0; i < elementCount; i++) > list.add(createElement(list)); > return list; >Index: src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableSetTest.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableSetTest.java,v >retrieving revision 1.2 >diff -u -r1.2 JavaBeanObservableSetTest.java >--- src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableSetTest.java 20 Mar 2008 21:16:40 -0000 1.2 >+++ src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableSetTest.java 4 Sep 2008 20:45:16 -0000 >@@ -7,12 +7,11 @@ > * > * Contributors: > * Brad Reynolds - initial API and implementation >- * Matthew Hall - bugs 221351, 213145 >+ * Matthew Hall - bugs 221351, 213145, 194734 > ******************************************************************************/ > > package org.eclipse.core.tests.internal.databinding.beans; > >-import java.beans.IntrospectionException; > import java.beans.PropertyDescriptor; > import java.util.Arrays; > import java.util.HashSet; >@@ -21,13 +20,17 @@ > import junit.framework.TestCase; > import junit.framework.TestSuite; > >+import org.eclipse.core.databinding.beans.BeanProperties; >+import org.eclipse.core.databinding.beans.BeansObservables; >+import org.eclipse.core.databinding.beans.IBeanObservable; >+import org.eclipse.core.databinding.beans.IBeanProperty; >+import org.eclipse.core.databinding.beans.PojoObservables; > import org.eclipse.core.databinding.observable.IObservable; > import org.eclipse.core.databinding.observable.IObservableCollection; > import org.eclipse.core.databinding.observable.Realm; > 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.internal.databinding.beans.JavaBeanObservableSet; > import org.eclipse.jface.databinding.conformance.MutableObservableSetContractTest; > import org.eclipse.jface.databinding.conformance.delegate.AbstractObservableCollectionContractDelegate; > import org.eclipse.jface.databinding.conformance.util.ChangeEventTracker; >@@ -39,34 +42,32 @@ > * @since 3.3 > */ > public class JavaBeanObservableSetTest extends TestCase { >- private JavaBeanObservableSet observableSet; >+ private IObservableSet observableSet; >+ private IBeanObservable beanObservable; > private Bean bean; > private PropertyDescriptor propertyDescriptor; > private String propertyName; > private SetChangeListener listener; > >- /* >- * (non-Javadoc) >- * >- * @see junit.framework.TestCase#setUp() >- */ > protected void setUp() throws Exception { > bean = new Bean(); > propertyName = "set"; >- propertyDescriptor = new PropertyDescriptor(propertyName, Bean.class); >+ propertyDescriptor = ((IBeanProperty) BeanProperties.setProperty( >+ Bean.class, propertyName)).getPropertyDescriptor(); > >- observableSet = new JavaBeanObservableSet(SWTObservables >- .getRealm(Display.getDefault()), bean, propertyDescriptor, >- Bean.class); >+ observableSet = BeansObservables >+ .observeSet(SWTObservables.getRealm(Display.getDefault()), >+ bean, propertyName, Bean.class); >+ beanObservable = (IBeanObservable) observableSet; > listener = new SetChangeListener(); > } > > public void testGetObserved() throws Exception { >- assertEquals(bean, observableSet.getObserved()); >+ assertEquals(bean, beanObservable.getObserved()); > } > > public void testGetPropertyDescriptor() throws Exception { >- assertEquals(propertyDescriptor, observableSet.getPropertyDescriptor()); >+ assertEquals(propertyDescriptor, beanObservable.getPropertyDescriptor()); > } > > public void testGetElementType() throws Exception { >@@ -97,8 +98,8 @@ > public void testConstructor_RegisterListeners() throws Exception { > bean = new Bean(); > >- observableSet = new JavaBeanObservableSet(new CurrentRealm(true), bean, >- propertyDescriptor, Bean.class); >+ observableSet = BeansObservables.observeSet(new CurrentRealm(true), >+ bean, propertyName); > assertFalse(bean.hasListeners(propertyName)); > ChangeEventTracker.observe(observableSet); > assertTrue(bean.hasListeners(propertyName)); >@@ -107,8 +108,8 @@ > public void testConstructor_SkipsRegisterListeners() throws Exception { > bean = new Bean(); > >- observableSet = new JavaBeanObservableSet(new CurrentRealm(true), bean, >- propertyDescriptor, Bean.class, false); >+ observableSet = PojoObservables.observeSet(new CurrentRealm(true), >+ bean, propertyName); > assertFalse(bean.hasListeners(propertyName)); > ChangeEventTracker.observe(observableSet); > assertFalse(bean.hasListeners(propertyName)); >@@ -134,16 +135,9 @@ > int elementCount) { > Bean bean = new Bean(); > String propertyName = "set"; >- PropertyDescriptor propertyDescriptor; >- try { >- propertyDescriptor = new PropertyDescriptor(propertyName, >- Bean.class); >- } catch (IntrospectionException e) { >- throw new RuntimeException(e); >- } > >- IObservableSet set = new JavaBeanObservableSet(realm, >- bean, propertyDescriptor, String.class); >+ IObservableSet set = BeansObservables.observeSet(realm, bean, >+ propertyName, String.class); > for (int i = 0; i < elementCount; i++) > set.add(createElement(set)); > return set; >Index: src/org/eclipse/core/tests/internal/databinding/beans/BeanObservableValueDecoratorTest.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/beans/BeanObservableValueDecoratorTest.java,v >retrieving revision 1.2 >diff -u -r1.2 BeanObservableValueDecoratorTest.java >--- src/org/eclipse/core/tests/internal/databinding/beans/BeanObservableValueDecoratorTest.java 20 Mar 2008 21:16:40 -0000 1.2 >+++ src/org/eclipse/core/tests/internal/databinding/beans/BeanObservableValueDecoratorTest.java 4 Sep 2008 20:45:15 -0000 >@@ -7,15 +7,18 @@ > * > * Contributors: > * Brad Reynolds - initial API and implementation >+ * Matthew Hall - bug 194734 > ******************************************************************************/ > > package org.eclipse.core.tests.internal.databinding.beans; > > import java.beans.PropertyDescriptor; > >-import org.eclipse.core.databinding.observable.value.WritableValue; >+import org.eclipse.core.databinding.beans.BeanProperties; >+import org.eclipse.core.databinding.beans.BeansObservables; >+import org.eclipse.core.databinding.beans.IBeanProperty; >+import org.eclipse.core.databinding.observable.value.IObservableValue; > import org.eclipse.core.internal.databinding.beans.BeanObservableValueDecorator; >-import org.eclipse.core.internal.databinding.beans.JavaBeanObservableValue; > import org.eclipse.jface.databinding.swt.SWTObservables; > import org.eclipse.jface.tests.databinding.AbstractDefaultRealmTestCase; > import org.eclipse.swt.widgets.Display; >@@ -25,27 +28,21 @@ > */ > public class BeanObservableValueDecoratorTest extends AbstractDefaultRealmTestCase { > private Bean bean; >- private JavaBeanObservableValue observableValue; >+ private IObservableValue observableValue; > private BeanObservableValueDecorator decorator; > private PropertyDescriptor propertyDescriptor; > >- /* >- * (non-Javadoc) >- * >- * @see junit.framework.TestCase#setUp() >- */ > protected void setUp() throws Exception { > super.setUp(); > > bean = new Bean(); >- propertyDescriptor = new PropertyDescriptor("value", >- Bean.class); >- observableValue = new JavaBeanObservableValue( >- SWTObservables.getRealm(Display.getDefault()), bean, >+ String propertyName = "value"; >+ propertyDescriptor = ((IBeanProperty) BeanProperties.valueProperty( >+ Bean.class, propertyName)).getPropertyDescriptor(); >+ observableValue = BeansObservables.observeValue(SWTObservables >+ .getRealm(Display.getDefault()), bean, propertyName); >+ decorator = new BeanObservableValueDecorator(observableValue, > propertyDescriptor); >- decorator = new BeanObservableValueDecorator( >- observableValue, new WritableValue(bean, Object.class), observableValue >- .getPropertyDescriptor()); > } > > public void testGetDelegate() throws Exception { >Index: src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableArrayBasedSetTest.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableArrayBasedSetTest.java,v >retrieving revision 1.2 >diff -u -r1.2 JavaBeanObservableArrayBasedSetTest.java >--- src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableArrayBasedSetTest.java 20 Mar 2008 21:16:40 -0000 1.2 >+++ src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableArrayBasedSetTest.java 4 Sep 2008 20:45:15 -0000 >@@ -8,12 +8,11 @@ > * Contributors: > * Matthew Hall - initial API and implementation (bug 221351) > * Brad Reynolds - through JavaBeanObservableArrayBasedListTest.java >- * Matthew Hall - bug 213145 >+ * Matthew Hall - bugs 213145, 194734 > ******************************************************************************/ > > package org.eclipse.core.tests.internal.databinding.beans; > >-import java.beans.IntrospectionException; > import java.beans.PropertyChangeEvent; > import java.beans.PropertyChangeListener; > import java.beans.PropertyDescriptor; >@@ -25,12 +24,15 @@ > import junit.framework.Test; > import junit.framework.TestSuite; > >+import org.eclipse.core.databinding.beans.BeanProperties; >+import org.eclipse.core.databinding.beans.BeansObservables; >+import org.eclipse.core.databinding.beans.IBeanObservable; >+import org.eclipse.core.databinding.beans.IBeanProperty; > import org.eclipse.core.databinding.observable.IObservable; > import org.eclipse.core.databinding.observable.IObservableCollection; > import org.eclipse.core.databinding.observable.Realm; > import org.eclipse.core.databinding.observable.set.IObservableSet; > import org.eclipse.core.databinding.observable.set.SetChangeEvent; >-import org.eclipse.core.internal.databinding.beans.JavaBeanObservableSet; > import org.eclipse.jface.databinding.conformance.MutableObservableSetContractTest; > import org.eclipse.jface.databinding.conformance.delegate.AbstractObservableCollectionContractDelegate; > import org.eclipse.jface.databinding.conformance.util.SetChangeEventTracker; >@@ -43,7 +45,8 @@ > */ > public class JavaBeanObservableArrayBasedSetTest extends > AbstractDefaultRealmTestCase { >- private JavaBeanObservableSet set; >+ private IObservableSet set; >+ private IBeanObservable beanObservable; > > private PropertyDescriptor propertyDescriptor; > >@@ -55,19 +58,21 @@ > super.setUp(); > > propertyName = "array"; >- propertyDescriptor = new PropertyDescriptor(propertyName, Bean.class); >+ propertyDescriptor = ((IBeanProperty) BeanProperties.setProperty( >+ Bean.class, propertyName)).getPropertyDescriptor(); > bean = new Bean(new HashSet()); > >- set = new JavaBeanObservableSet(SWTObservables.getRealm(Display >- .getDefault()), bean, propertyDescriptor, String.class); >+ set = BeansObservables.observeSet(SWTObservables.getRealm(Display >+ .getDefault()), bean, propertyName); >+ beanObservable = (IBeanObservable) set; > } > > public void testGetObserved() throws Exception { >- assertEquals(bean, set.getObserved()); >+ assertEquals(bean, beanObservable.getObserved()); > } > > public void testGetPropertyDescriptor() throws Exception { >- assertEquals(propertyDescriptor, set.getPropertyDescriptor()); >+ assertEquals(propertyDescriptor, beanObservable.getPropertyDescriptor()); > } > > public void testRegistersListenerAfterFirstListenerIsAdded() >@@ -292,7 +297,8 @@ > assertEquals("array", event.getPropertyName()); > assertTrue("old value", Arrays.equals(old, (Object[]) event > .getOldValue())); >- assertTrue("new value", Arrays.equals(bean.getArray(), (Object[]) event.getNewValue())); >+ assertTrue("new value", Arrays.equals(bean.getArray(), (Object[]) event >+ .getNewValue())); > assertFalse("lists are equal", Arrays.equals(bean.getArray(), old)); > } > >@@ -302,11 +308,6 @@ > > PropertyChangeEvent evt; > >- /* >- * (non-Javadoc) >- * >- * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent) >- */ > public void propertyChange(PropertyChangeEvent evt) { > count++; > this.evt = evt; >@@ -324,17 +325,10 @@ > public IObservableCollection createObservableCollection(Realm realm, > int elementCount) { > String propertyName = "array"; >- PropertyDescriptor propertyDescriptor; >- try { >- propertyDescriptor = new PropertyDescriptor(propertyName, >- Bean.class); >- } catch (IntrospectionException e) { >- throw new RuntimeException(e); >- } > Object bean = new Bean(new Object[0]); > >- IObservableSet list = new JavaBeanObservableSet(realm, bean, >- propertyDescriptor, String.class); >+ IObservableSet list = BeansObservables.observeSet(realm, bean, >+ propertyName, String.class); > for (int i = 0; i < elementCount; i++) > list.add(createElement(list)); > return list; >Index: src/org/eclipse/core/tests/internal/databinding/beans/BeanObservableSetDecoratorTest.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/beans/BeanObservableSetDecoratorTest.java,v >retrieving revision 1.2 >diff -u -r1.2 BeanObservableSetDecoratorTest.java >--- src/org/eclipse/core/tests/internal/databinding/beans/BeanObservableSetDecoratorTest.java 20 Mar 2008 21:16:40 -0000 1.2 >+++ src/org/eclipse/core/tests/internal/databinding/beans/BeanObservableSetDecoratorTest.java 4 Sep 2008 20:45:15 -0000 >@@ -7,6 +7,7 @@ > * > * Contributors: > * Brad Reynolds - initial API and implementation >+ * Matthew Hall - bug 194734 > ******************************************************************************/ > > package org.eclipse.core.tests.internal.databinding.beans; >@@ -15,8 +16,12 @@ > > import junit.framework.TestCase; > >+import org.eclipse.core.databinding.beans.BeanProperties; >+import org.eclipse.core.databinding.beans.BeansObservables; >+import org.eclipse.core.databinding.beans.IBeanObservable; >+import org.eclipse.core.databinding.beans.IBeanProperty; >+import org.eclipse.core.databinding.observable.set.IObservableSet; > import org.eclipse.core.internal.databinding.beans.BeanObservableSetDecorator; >-import org.eclipse.core.internal.databinding.beans.JavaBeanObservableSet; > import org.eclipse.jface.databinding.swt.SWTObservables; > import org.eclipse.swt.widgets.Display; > >@@ -25,7 +30,8 @@ > */ > public class BeanObservableSetDecoratorTest extends TestCase { > private PropertyDescriptor propertyDescriptor; >- private JavaBeanObservableSet observableSet; >+ private IObservableSet observableSet; >+ private IBeanObservable beanObservable; > private BeanObservableSetDecorator decorator; > > /* >@@ -37,13 +43,14 @@ > super.setUp(); > > Bean bean = new Bean(); >- propertyDescriptor = new PropertyDescriptor("set", >- Bean.class); >- observableSet = new JavaBeanObservableSet( >- SWTObservables.getRealm(Display.getDefault()), bean, >- propertyDescriptor, String.class); >- decorator = new BeanObservableSetDecorator( >- observableSet, observableSet, propertyDescriptor); >+ String propertyName = "set"; >+ propertyDescriptor = ((IBeanProperty) BeanProperties.setProperty( >+ Bean.class, propertyName)).getPropertyDescriptor(); >+ observableSet = BeansObservables.observeSet(SWTObservables >+ .getRealm(Display.getDefault()), bean, propertyName); >+ beanObservable = (IBeanObservable) observableSet; >+ decorator = new BeanObservableSetDecorator(observableSet, >+ propertyDescriptor); > } > > public void testGetDelegate() throws Exception { >@@ -51,7 +58,7 @@ > } > > public void testGetObserved() throws Exception { >- assertEquals(observableSet, decorator.getObserved()); >+ assertEquals(beanObservable.getObserved(), decorator.getObserved()); > } > > public void testGetPropertyDescriptor() throws Exception { >Index: src/org/eclipse/core/tests/internal/databinding/beans/BeanObservableListDecoratorTest.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/beans/BeanObservableListDecoratorTest.java,v >retrieving revision 1.2 >diff -u -r1.2 BeanObservableListDecoratorTest.java >--- src/org/eclipse/core/tests/internal/databinding/beans/BeanObservableListDecoratorTest.java 20 Mar 2008 21:16:40 -0000 1.2 >+++ src/org/eclipse/core/tests/internal/databinding/beans/BeanObservableListDecoratorTest.java 4 Sep 2008 20:45:15 -0000 >@@ -7,7 +7,7 @@ > * > * Contributors: > * Brad Reynolds - initial API and implementation >- * Matthew Hall - bugs 208858, 213145 >+ * Matthew Hall - bugs 208858, 213145, 194734 > ******************************************************************************/ > > package org.eclipse.core.tests.internal.databinding.beans; >@@ -18,13 +18,14 @@ > import junit.framework.TestCase; > import junit.framework.TestSuite; > >+import org.eclipse.core.databinding.beans.BeansObservables; >+import org.eclipse.core.databinding.beans.IBeanObservable; > import org.eclipse.core.databinding.observable.IObservable; > import org.eclipse.core.databinding.observable.IObservableCollection; > import org.eclipse.core.databinding.observable.Realm; > import org.eclipse.core.databinding.observable.list.IObservableList; > import org.eclipse.core.databinding.observable.list.WritableList; > import org.eclipse.core.internal.databinding.beans.BeanObservableListDecorator; >-import org.eclipse.core.internal.databinding.beans.JavaBeanObservableList; > import org.eclipse.jface.databinding.conformance.MutableObservableListContractTest; > import org.eclipse.jface.databinding.conformance.delegate.AbstractObservableCollectionContractDelegate; > import org.eclipse.jface.databinding.swt.SWTObservables; >@@ -35,7 +36,8 @@ > */ > public class BeanObservableListDecoratorTest extends TestCase { > private PropertyDescriptor propertyDescriptor; >- private JavaBeanObservableList observableList; >+ private IObservableList observableList; >+ private IBeanObservable beanObservable; > private BeanObservableListDecorator decorator; > > /* >@@ -49,10 +51,10 @@ > Bean bean = new Bean(); > propertyDescriptor = new PropertyDescriptor( > "list", Bean.class,"getList","setList"); >- observableList = new JavaBeanObservableList( >- SWTObservables.getRealm(Display.getDefault()), bean, >- propertyDescriptor, Bean.class); >- decorator = new BeanObservableListDecorator(observableList, observableList, propertyDescriptor); >+ observableList = BeansObservables.observeList(SWTObservables >+ .getRealm(Display.getDefault()), bean, "list"); >+ beanObservable = (IBeanObservable) observableList; >+ decorator = new BeanObservableListDecorator(observableList, propertyDescriptor); > } > > public void testGetDelegate() throws Exception { >@@ -60,7 +62,7 @@ > } > > public void testGetObserved() throws Exception { >- assertEquals(observableList, decorator.getObserved()); >+ assertEquals(beanObservable.getObserved(), decorator.getObserved()); > } > > public void testGetPropertyDescriptor() throws Exception { >@@ -80,7 +82,7 @@ > final WritableList delegate = new WritableList(realm); > for (int i = 0; i < elementCount; i++) > delegate.add(createElement(delegate)); >- return new BeanObservableListDecorator(delegate, null, null); >+ return new BeanObservableListDecorator(delegate, null); > } > > private int counter; >Index: src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableListTest.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableListTest.java,v >retrieving revision 1.3 >diff -u -r1.3 JavaBeanObservableListTest.java >--- src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableListTest.java 31 Jul 2008 18:37:44 -0000 1.3 >+++ src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableListTest.java 4 Sep 2008 20:45:16 -0000 >@@ -7,12 +7,11 @@ > * > * Contributors: > * Brad Reynolds - initial API and implementation >- * Matthew Hall - bugs 221351, 213145 >+ * Matthew Hall - bugs 221351, 213145, 194734 > ******************************************************************************/ > > package org.eclipse.core.tests.internal.databinding.beans; > >-import java.beans.IntrospectionException; > import java.beans.PropertyChangeEvent; > import java.beans.PropertyChangeListener; > import java.beans.PropertyDescriptor; >@@ -24,13 +23,17 @@ > import junit.framework.Test; > import junit.framework.TestSuite; > >+import org.eclipse.core.databinding.beans.BeanProperties; >+import org.eclipse.core.databinding.beans.BeansObservables; >+import org.eclipse.core.databinding.beans.IBeanObservable; >+import org.eclipse.core.databinding.beans.IBeanProperty; >+import org.eclipse.core.databinding.beans.PojoObservables; > import org.eclipse.core.databinding.observable.IObservable; > import org.eclipse.core.databinding.observable.IObservableCollection; > import org.eclipse.core.databinding.observable.Realm; > import org.eclipse.core.databinding.observable.list.IObservableList; > import org.eclipse.core.databinding.observable.list.ListChangeEvent; > import org.eclipse.core.databinding.observable.list.ListDiffEntry; >-import org.eclipse.core.internal.databinding.beans.JavaBeanObservableList; > import org.eclipse.jface.databinding.conformance.MutableObservableListContractTest; > import org.eclipse.jface.databinding.conformance.delegate.AbstractObservableCollectionContractDelegate; > import org.eclipse.jface.databinding.conformance.util.ChangeEventTracker; >@@ -43,7 +46,8 @@ > * @since 1.1 > */ > public class JavaBeanObservableListTest extends AbstractDefaultRealmTestCase { >- private JavaBeanObservableList list; >+ private IObservableList list; >+ private IBeanObservable beanObservable; > > private PropertyDescriptor propertyDescriptor; > >@@ -60,19 +64,21 @@ > super.setUp(); > > propertyName = "list"; >- propertyDescriptor = new PropertyDescriptor(propertyName, Bean.class); >+ propertyDescriptor = ((IBeanProperty) BeanProperties.listProperty( >+ Bean.class, propertyName)).getPropertyDescriptor(); > bean = new Bean(new ArrayList()); > >- list = new JavaBeanObservableList(SWTObservables.getRealm(Display >- .getDefault()), bean, propertyDescriptor, String.class); >+ list = BeansObservables.observeList(SWTObservables.getRealm(Display >+ .getDefault()), bean, propertyName); >+ beanObservable = (IBeanObservable) list; > } > > public void testGetObserved() throws Exception { >- assertEquals(bean, list.getObserved()); >+ assertEquals(bean, beanObservable.getObserved()); > } > > public void testGetPropertyDescriptor() throws Exception { >- assertEquals(propertyDescriptor, list.getPropertyDescriptor()); >+ assertEquals(propertyDescriptor, beanObservable.getPropertyDescriptor()); > } > > public void testRegistersListenerAfterFirstListenerIsAdded() >@@ -322,16 +328,14 @@ > } > > public void testRemoveAll() throws Exception { >- List elements = Arrays.asList(new String[] { "1", "2" }); >- list.addAll(elements); >- list.addAll(elements); >- >+ list.addAll(Arrays.asList(new String[] { "1", "2", "3", "4" })); > assertEquals(4, bean.getList().size()); >- list.removeAll(elements); >+ >+ list.removeAll(Arrays.asList(new String[] { "2", "4" })); > > assertEquals(2, bean.getList().size()); >- assertEquals(elements.get(0), bean.getList().get(0)); >- assertEquals(elements.get(1), bean.getList().get(1)); >+ assertEquals("1", bean.getList().get(0)); >+ assertEquals("3", bean.getList().get(1)); > } > > public void testRemoveAllListChangeEvent() throws Exception { >@@ -467,9 +471,8 @@ > > public void testConstructor_RegistersListener() throws Exception { > Bean bean = new Bean(); >- JavaBeanObservableList observable = new JavaBeanObservableList(Realm >- .getDefault(), bean, >- new PropertyDescriptor("list", Bean.class), Bean.class); >+ IObservableList observable = BeansObservables.observeList(Realm >+ .getDefault(), bean, "list"); > > assertFalse(bean.hasListeners("list")); > ChangeEventTracker.observe(observable); >@@ -478,9 +481,8 @@ > > public void testConstructor_SkipsRegisterListener() throws Exception { > Bean bean = new Bean(); >- JavaBeanObservableList observable = new JavaBeanObservableList(Realm >- .getDefault(), bean, >- new PropertyDescriptor("list", Bean.class), Bean.class, false); >+ IObservableList observable = PojoObservables.observeList(Realm >+ .getDefault(), bean, "list"); > > assertFalse(bean.hasListeners("list")); > ChangeEventTracker.observe(observable); >@@ -517,11 +519,6 @@ > > PropertyChangeEvent evt; > >- /* >- * (non-Javadoc) >- * >- * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent) >- */ > public void propertyChange(PropertyChangeEvent evt) { > count++; > this.evt = evt; >@@ -539,17 +536,10 @@ > public IObservableCollection createObservableCollection(Realm realm, > int elementCount) { > String propertyName = "list"; >- PropertyDescriptor propertyDescriptor; >- try { >- propertyDescriptor = new PropertyDescriptor(propertyName, >- Bean.class); >- } catch (IntrospectionException e) { >- throw new RuntimeException(e); >- } > Object bean = new Bean(new ArrayList()); > >- IObservableList list = new JavaBeanObservableList(realm, bean, >- propertyDescriptor, String.class); >+ IObservableList list = BeansObservables.observeList(realm, bean, >+ propertyName, String.class); > for (int i = 0; i < elementCount; i++) > list.add(createElement(list)); > return list; >Index: src/org/eclipse/core/tests/databinding/beans/PojoObservablesTest.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/databinding/beans/PojoObservablesTest.java,v >retrieving revision 1.4 >diff -u -r1.4 PojoObservablesTest.java >--- src/org/eclipse/core/tests/databinding/beans/PojoObservablesTest.java 24 Mar 2008 19:13:50 -0000 1.4 >+++ src/org/eclipse/core/tests/databinding/beans/PojoObservablesTest.java 4 Sep 2008 20:45:15 -0000 >@@ -7,10 +7,12 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >+ * Matthew Hall - bug 194734 > *******************************************************************************/ > > package org.eclipse.core.tests.databinding.beans; > >+import org.eclipse.core.databinding.beans.IBeanObservable; > import org.eclipse.core.databinding.beans.PojoObservables; > import org.eclipse.core.databinding.observable.Realm; > import org.eclipse.core.databinding.observable.list.IObservableList; >@@ -19,10 +21,6 @@ > import org.eclipse.core.databinding.observable.set.IObservableSet; > import org.eclipse.core.databinding.observable.set.WritableSet; > import org.eclipse.core.databinding.observable.value.IObservableValue; >-import org.eclipse.core.internal.databinding.beans.JavaBeanObservableList; >-import org.eclipse.core.internal.databinding.beans.JavaBeanObservableMap; >-import org.eclipse.core.internal.databinding.beans.JavaBeanObservableSet; >-import org.eclipse.core.internal.databinding.beans.JavaBeanObservableValue; > import org.eclipse.core.tests.internal.databinding.beans.Bean; > import org.eclipse.jface.databinding.conformance.util.ChangeEventTracker; > import org.eclipse.jface.databinding.conformance.util.CurrentRealm; >@@ -47,12 +45,12 @@ > propertyName = "value"; > } > >- public void testObserveValue_ReturnsJavaBeanObservableValue() >+ public void testObserveValue_ReturnsIBeanObservable() > throws Exception { > IObservableValue value = PojoObservables.observeValue(pojo, propertyName); > > assertNotNull(value); >- assertTrue(value instanceof JavaBeanObservableValue); >+ assertTrue(value instanceof IBeanObservable); > } > > public void testObserveValue_DoesNotAttachListeners() throws Exception { >@@ -62,17 +60,17 @@ > assertFalse(pojo.hasListeners(propertyName)); > } > >- public void testObservableValueWithRealm_ReturnsJavaBeanObservable() >+ public void testObservableValueWithRealm_ReturnsIBeanObservable() > throws Exception { > CurrentRealm realm = new CurrentRealm(true); > IObservableValue value = PojoObservables.observeValue(realm, pojo, > propertyName); > > assertNotNull(value); >- assertTrue(value instanceof JavaBeanObservableValue); >+ assertTrue(value instanceof IBeanObservable); > } > >- public void testObservableMap_ReturnsJavaBeanObservableMap() >+ public void testObservableMap_ReturnsIBeanObservable() > throws Exception { > IObservableSet set = new WritableSet(); > set.add(new Bean()); >@@ -80,7 +78,7 @@ > IObservableMap map = PojoObservables.observeMap(set, Bean.class, > propertyName); > assertNotNull(map); >- assertTrue(map instanceof JavaBeanObservableMap); >+ assertTrue(map instanceof IBeanObservable); > } > > public void testObservableMap_DoesNotAttachListeners() throws Exception { >@@ -101,9 +99,9 @@ > assertEquals(2, maps.length); > } > >- public void testObserveListWithElementType_ReturnsJavaBeanObservableList() throws Exception { >+ public void testObserveListWithElementType_ReturnsIBeanObservable() throws Exception { > IObservableList list = PojoObservables.observeList(Realm.getDefault(), pojo, "list", String.class); >- assertTrue(list instanceof JavaBeanObservableList); >+ assertTrue(list instanceof IBeanObservable); > } > > public void testObserveListWithElementType_DoesNotAttachListeners() throws Exception { >@@ -113,9 +111,9 @@ > assertFalse(pojo.hasListeners("list")); > } > >- public void testObserveList_ReturnsJavaBeanObservableList() throws Exception { >+ public void testObserveList_ReturnsIBeanObservable() throws Exception { > IObservableList observable = PojoObservables.observeList(Realm.getDefault(), pojo, "list"); >- assertTrue(observable instanceof JavaBeanObservableList); >+ assertTrue(observable instanceof IBeanObservable); > } > > public void testObserveList_DoesNotAttachListeners() throws Exception { >@@ -125,9 +123,9 @@ > assertFalse(pojo.hasListeners("list")); > } > >- public void testObserveSetWithElementType_ReturnsJavaBeanObservableList() throws Exception { >+ public void testObserveSetWithElementType_ReturnsIBeanObservable() throws Exception { > IObservableSet list = PojoObservables.observeSet(Realm.getDefault(), pojo, "set", String.class); >- assertTrue(list instanceof JavaBeanObservableSet); >+ assertTrue(list instanceof IBeanObservable); > } > > public void testObserveSetWithElementType_DoesNotAttachListeners() throws Exception { >@@ -137,9 +135,9 @@ > assertFalse(pojo.hasListeners("set")); > } > >- public void testObserveSet_ReturnsJavaBeanObservableList() throws Exception { >+ public void testObserveSet_ReturnsIBeanObservable() throws Exception { > IObservableSet list = PojoObservables.observeSet(Realm.getDefault(), pojo, "set"); >- assertTrue(list instanceof JavaBeanObservableSet); >+ assertTrue(list instanceof IBeanObservable); > } > > public void testObserveSet_DoesNotAttachListeners() throws Exception { >Index: src/org/eclipse/core/tests/databinding/beans/BeansObservablesTest.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/databinding/beans/BeansObservablesTest.java,v >retrieving revision 1.14 >diff -u -r1.14 BeansObservablesTest.java >--- src/org/eclipse/core/tests/databinding/beans/BeansObservablesTest.java 20 Mar 2008 21:16:40 -0000 1.14 >+++ src/org/eclipse/core/tests/databinding/beans/BeansObservablesTest.java 4 Sep 2008 20:45:15 -0000 >@@ -9,7 +9,7 @@ > * IBM Corporation - initial API and implementation > * Brad Reynolds - bug 164268, 171616 > * Mike Evans - bug 217558 >- * Matthew Hall - bug 221351 >+ * Matthew Hall - bugs 221351, 194734 > *******************************************************************************/ > > package org.eclipse.core.tests.databinding.beans; >@@ -121,7 +121,7 @@ > BeanObservableListDecorator beanObservable = (BeanObservableListDecorator) detailList; > assertEquals("property descriptor", Bean.class.getMethod("getList", > null), beanObservable.getPropertyDescriptor().getReadMethod()); >- assertEquals("observed", parent, beanObservable.getObserved()); >+ assertEquals("observed", parent.getValue(), beanObservable.getObserved()); > > // DetailObservableList is package level we can do a straight instanceof > // check >@@ -152,7 +152,7 @@ > assertEquals("property descriptor", Bean.class > .getMethod("getSet", null), beanObservable > .getPropertyDescriptor().getReadMethod()); >- assertEquals("observed", parent, beanObservable.getObserved()); >+ assertEquals("observed", parent.getValue(), beanObservable.getObserved()); > > // DetailObservableSet is package level we can't do a straight > // instanceof check >#P org.eclipse.core.databinding >Index: src/org/eclipse/core/databinding/observable/map/ComputedObservableMap.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.databinding/src/org/eclipse/core/databinding/observable/map/ComputedObservableMap.java,v >retrieving revision 1.6 >diff -u -r1.6 ComputedObservableMap.java >--- src/org/eclipse/core/databinding/observable/map/ComputedObservableMap.java 21 Jul 2008 22:10:28 -0000 1.6 >+++ src/org/eclipse/core/databinding/observable/map/ComputedObservableMap.java 4 Sep 2008 20:45:17 -0000 >@@ -7,7 +7,7 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >- * Matthew Hall - bug 241585 >+ * Matthew Hall - bugs 241585, 194734 > *******************************************************************************/ > > package org.eclipse.core.databinding.observable.map; >@@ -31,7 +31,7 @@ > */ > public abstract class ComputedObservableMap extends AbstractObservableMap { > >- private final IObservableSet keySet; >+ private IObservableSet keySet; > > private ISetChangeListener setChangeListener = new ISetChangeListener() { > public void handleSetChange(SetChangeEvent event) { >@@ -109,10 +109,36 @@ > this.keySet.addSetChangeListener(setChangeListener); > } > >+ /** >+ * @deprecated Subclasses are no longer required to call this method. >+ */ > protected void init() { >- for (Iterator it = this.keySet.iterator(); it.hasNext();) { >- Object key = it.next(); >- hookListener(key); >+ } >+ >+ protected void firstListenerAdded() { >+ hookListeners(); >+ } >+ >+ protected void lastListenerRemoved() { >+ unhookListeners(); >+ } >+ >+ private void hookListeners() { >+ if (keySet != null) { >+ for (Iterator it = this.keySet.iterator(); it.hasNext();) { >+ Object key = it.next(); >+ hookListener(key); >+ } >+ } >+ } >+ >+ private void unhookListeners() { >+ if (keySet != null) { >+ Object[] keys = keySet.toArray(); >+ for (int i = 0; i < keys.length; i++) { >+ unhookListener(keys[i]); >+ } >+ keySet = null; > } > } > >@@ -163,4 +189,10 @@ > * @return the old value for the given key > */ > protected abstract Object doPut(Object key, Object value); >+ >+ public void dispose() { >+ unhookListeners(); >+ entrySet = null; >+ super.dispose(); >+ } > } >Index: src/org/eclipse/core/databinding/observable/list/AbstractObservableList.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.databinding/src/org/eclipse/core/databinding/observable/list/AbstractObservableList.java,v >retrieving revision 1.11 >diff -u -r1.11 AbstractObservableList.java >--- src/org/eclipse/core/databinding/observable/list/AbstractObservableList.java 7 Apr 2008 21:16:18 -0000 1.11 >+++ src/org/eclipse/core/databinding/observable/list/AbstractObservableList.java 4 Sep 2008 20:45:17 -0000 >@@ -7,11 +7,8 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >- * Brad Reynolds - bug 164653 >- * Brad Reynolds - bug 167204 >- * Matthew Hall - bug 118516 >- * Matthew Hall - bug 208858 >- * Matthew Hall - bug 208332 >+ * Brad Reynolds - bugs 164653, 167204 >+ * Matthew Hall - bugs 118516, 208858, 208332, 194734 > *******************************************************************************/ > > package org.eclipse.core.databinding.observable.list; >@@ -76,11 +73,15 @@ > } > > public synchronized void addListChangeListener(IListChangeListener listener) { >- changeSupport.addListener(ListChangeEvent.TYPE, listener); >+ if (changeSupport != null) { >+ changeSupport.addListener(ListChangeEvent.TYPE, listener); >+ } > } > > public synchronized void removeListChangeListener(IListChangeListener listener) { >- changeSupport.removeListener(ListChangeEvent.TYPE, listener); >+ if (changeSupport != null) { >+ changeSupport.removeListener(ListChangeEvent.TYPE, listener); >+ } > } > > protected void fireListChange(ListDiff diff) { >@@ -90,19 +91,27 @@ > } > > public synchronized void addChangeListener(IChangeListener listener) { >- changeSupport.addChangeListener(listener); >+ if (changeSupport != null) { >+ changeSupport.addChangeListener(listener); >+ } > } > > public synchronized void removeChangeListener(IChangeListener listener) { >- changeSupport.removeChangeListener(listener); >+ if (changeSupport != null) { >+ changeSupport.removeChangeListener(listener); >+ } > } > > public synchronized void addStaleListener(IStaleListener listener) { >- changeSupport.addStaleListener(listener); >+ if (changeSupport != null) { >+ changeSupport.addStaleListener(listener); >+ } > } > > public synchronized void removeStaleListener(IStaleListener listener) { >- changeSupport.removeStaleListener(listener); >+ if (changeSupport != null) { >+ changeSupport.removeStaleListener(listener); >+ } > } > > /** >Index: META-INF/MANIFEST.MF >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.databinding/META-INF/MANIFEST.MF,v >retrieving revision 1.15 >diff -u -r1.15 MANIFEST.MF >--- META-INF/MANIFEST.MF 3 Jul 2008 23:47:30 -0000 1.15 >+++ META-INF/MANIFEST.MF 4 Sep 2008 20:45:17 -0000 >@@ -14,6 +14,8 @@ > org.eclipse.core.databinding.observable.masterdetail, > org.eclipse.core.databinding.observable.set;x-internal:=false, > org.eclipse.core.databinding.observable.value;x-internal:=false, >+ org.eclipse.core.databinding.property, >+ org.eclipse.core.databinding.property.masterdetail, > org.eclipse.core.databinding.util, > org.eclipse.core.databinding.validation;x-internal:=false, > org.eclipse.core.internal.databinding;x-friends:="org.eclipse.core.databinding.beans", >@@ -21,6 +23,8 @@ > org.eclipse.core.internal.databinding.observable;x-internal:=true, > org.eclipse.core.internal.databinding.observable.masterdetail;x-friends:="org.eclipse.jface.tests.databinding", > org.eclipse.core.internal.databinding.observable.tree;x-friends:="org.eclipse.jface.databinding,org.eclipse.jface.tests.databinding", >+ org.eclipse.core.internal.databinding.property;x-friends:="org.eclipse.jface.databinding,org.eclipse.jface.tests.databinding", >+ org.eclipse.core.internal.databinding.property.masterdetail;x-friends:="org.eclipse.jface.databinding,org.eclipse.jface.tests.databinding", > org.eclipse.core.internal.databinding.validation;x-friends:="org.eclipse.jface.tests.databinding" > Require-Bundle: org.eclipse.equinox.common;bundle-version="[3.2.0,4.0.0)" > Import-Package-Comment: see http://wiki.eclipse.org/ >Index: src/org/eclipse/core/databinding/property/IListProperty.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/IListProperty.java >diff -N src/org/eclipse/core/databinding/property/IListProperty.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/IListProperty.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,105 @@ >+/******************************************************************************* >+ * 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; >+ >+import java.util.Collection; >+import java.util.List; >+ >+/** >+ * @since 1.2 >+ * >+ */ >+public interface IListProperty extends ICollectionProperty { >+ /** >+ * @param source >+ * @return a List with the current contents of the source's list property >+ */ >+ List getList(Object source); >+ >+ /** >+ * @param source >+ * @param index >+ * @param c >+ * @return whether the source's list property was changed >+ */ >+ boolean addAll(Object source, int index, Collection c); >+ >+ /** >+ * @param source >+ * @param index >+ * @return the element at the given location in the source's list property >+ */ >+ Object get(Object source, int index); >+ >+ /** >+ * @param source >+ * @param index >+ * @param element >+ * @return the element previous at the given location in the source's list >+ * property >+ */ >+ Object set(Object source, int index, Object element); >+ >+ /** >+ * @param source >+ * @param oldIndex >+ * @param newIndex >+ * @return the element that was moved >+ */ >+ Object move(Object source, int oldIndex, int newIndex); >+ >+ /** >+ * @param source >+ * @param index >+ * @param element >+ */ >+ void add(Object source, int index, Object element); >+ >+ /** >+ * @param source >+ * @param index >+ * @return the element that was removed from the source's list property >+ */ >+ Object remove(Object source, int index); >+ >+ /** >+ * @param source >+ * @param o >+ * @return the index of the first location of the given element in the >+ * source's list property, or -1 if the list does not contain the >+ * element >+ */ >+ int indexOf(Object source, Object o); >+ >+ /** >+ * @param source >+ * @param o >+ * @return the index of the last location of the given element in the >+ * source's list property, or -1 if the list does not contain the >+ * element >+ */ >+ int lastIndexOf(Object source, Object o); >+ >+ /** >+ * @param source >+ * @param listener >+ */ >+ public void addListChangeListener(Object source, >+ IListPropertyChangeListener listener); >+ >+ /** >+ * @param source >+ * @param listener >+ */ >+ public void removeListChangeListener(Object source, >+ IListPropertyChangeListener listener); >+} >Index: src/org/eclipse/core/databinding/property/ISetProperty.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/ISetProperty.java >diff -N src/org/eclipse/core/databinding/property/ISetProperty.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/ISetProperty.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,39 @@ >+/******************************************************************************* >+ * 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; >+ >+import java.util.Set; >+ >+/** >+ * @since 1.2 >+ */ >+public interface ISetProperty extends ICollectionProperty { >+ /** >+ * @param source >+ * @return a Set with the current contents of the source's set property >+ */ >+ public Set getSet(Object source); >+ >+ /** >+ * @param source >+ * @param listener >+ */ >+ public void addSetChangeListener(Object source, >+ ISetPropertyChangeListener listener); >+ >+ /** >+ * @param source >+ * @param listener >+ */ >+ public void removeSetChangeListener(Object source, >+ ISetPropertyChangeListener listener); >+} >Index: src/org/eclipse/core/databinding/property/ObservableProperties.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/ObservableProperties.java >diff -N src/org/eclipse/core/databinding/property/ObservableProperties.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/ObservableProperties.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,55 @@ >+/******************************************************************************* >+ * 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; >+ >+import org.eclipse.core.databinding.observable.list.IObservableList; >+import org.eclipse.core.databinding.observable.map.IObservableMap; >+import org.eclipse.core.databinding.observable.set.IObservableSet; >+import org.eclipse.core.databinding.observable.value.IObservableValue; >+ >+/** >+ * @since 1.2 >+ * >+ */ >+public class ObservableProperties { >+ /** >+ * @param observable >+ * @return blah >+ */ >+ public static IValueProperty detailValue(IObservableValue observable) { >+ return null; >+ } >+ >+ /** >+ * @param observable >+ * @return blah >+ */ >+ public static ISetProperty detailSet(IObservableSet observable) { >+ return null; >+ } >+ >+ /** >+ * @param observable >+ * @return blah >+ */ >+ public static IListProperty detailList(IObservableList observable) { >+ return null; >+ } >+ >+ /** >+ * @param observable >+ * @return blah >+ */ >+ public static IMapProperty detailMap(IObservableMap observable) { >+ return null; >+ } >+} >Index: src/org/eclipse/core/databinding/property/ValuePropertyChangeEvent.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/ValuePropertyChangeEvent.java >diff -N src/org/eclipse/core/databinding/property/ValuePropertyChangeEvent.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/ValuePropertyChangeEvent.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,52 @@ >+/******************************************************************************* >+ * 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; >+ >+import org.eclipse.core.databinding.observable.value.ValueDiff; >+import org.eclipse.core.runtime.Assert; >+ >+/** >+ * @since 1.2 >+ * >+ */ >+public class ValuePropertyChangeEvent extends PropertyChangeEvent { >+ private static final long serialVersionUID = 1L; >+ >+ /** >+ * >+ */ >+ public final IValueProperty property; >+ >+ /** >+ * ValueDiff with the old and new values of the property. May be null to >+ * indicate that the details of the value change are unknown. >+ */ >+ public final ValueDiff diff; >+ >+ /** >+ * @param source >+ * @param property >+ * @param diff >+ */ >+ public ValuePropertyChangeEvent(Object source, IValueProperty property, >+ ValueDiff diff) { >+ super(source); >+ this.property = property; >+ Assert.isNotNull(diff, "diff cannot be null"); //$NON-NLS-1$ >+ this.diff = diff; >+ } >+ >+ void dispatch(IPropertyChangeListener listener) { >+ ((IValuePropertyChangeListener) listener) >+ .handleValuePropertyChange(this); >+ } >+} >Index: src/org/eclipse/core/databinding/property/MapProperty.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/MapProperty.java >diff -N src/org/eclipse/core/databinding/property/MapProperty.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/MapProperty.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,62 @@ >+/******************************************************************************* >+ * 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; >+ >+import org.eclipse.core.databinding.observable.map.MapDiff; >+ >+/** >+ * @since 1.2 >+ */ >+public abstract class MapProperty extends Property implements IMapProperty { >+ public boolean containsKey(Object source, Object key) { >+ return getMap(source).containsKey(key); >+ } >+ >+ public boolean containsValue(Object source, Object value) { >+ return getMap(source).containsValue(value); >+ } >+ >+ public boolean equals(Object source, Object o) { >+ return getMap(source).equals(o); >+ } >+ >+ public Object get(Object source, Object key) { >+ return getMap(source).get(key); >+ } >+ >+ public int hashCode(Object source) { >+ return getMap(source).hashCode(); >+ } >+ >+ public boolean isEmpty(Object source) { >+ return getMap(source).isEmpty(); >+ } >+ >+ public int size(Object source) { >+ return getMap(source).size(); >+ } >+ >+ public final void addMapChangeListener(Object source, >+ IMapPropertyChangeListener listener) { >+ getChangeSupport().addListener(source, listener); >+ } >+ >+ public final void removeMapChangeListener(Object source, >+ IMapPropertyChangeListener listener) { >+ getChangeSupport().removeListener(source, listener); >+ } >+ >+ protected final void fireMapChange(Object source, MapDiff diff) { >+ getChangeSupport().firePropertyChange( >+ new MapPropertyChangeEvent(source, this, diff)); >+ } >+} >Index: src/org/eclipse/core/databinding/property/ListProperty.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/ListProperty.java >diff -N src/org/eclipse/core/databinding/property/ListProperty.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/ListProperty.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,53 @@ >+/******************************************************************************* >+ * 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; >+ >+import java.util.Collection; >+ >+import org.eclipse.core.databinding.observable.list.ListDiff; >+ >+/** >+ * @since 1.2 >+ */ >+public abstract class ListProperty extends CollectionProperty implements >+ IListProperty { >+ Collection getCollection(Object source) { >+ return getList(source); >+ } >+ >+ public Object get(Object source, int index) { >+ return getList(source).get(index); >+ } >+ >+ public int indexOf(Object source, Object o) { >+ return getList(source).indexOf(o); >+ } >+ >+ public int lastIndexOf(Object source, Object o) { >+ return getList(source).lastIndexOf(o); >+ } >+ >+ public final void addListChangeListener(Object source, >+ IListPropertyChangeListener listener) { >+ getChangeSupport().addListener(source, listener); >+ } >+ >+ public final void removeListChangeListener(Object source, >+ IListPropertyChangeListener listener) { >+ getChangeSupport().removeListener(source, listener); >+ } >+ >+ protected final void fireListChange(Object source, ListDiff diff) { >+ getChangeSupport().firePropertyChange( >+ new ListPropertyChangeEvent(source, this, diff)); >+ } >+} >Index: src/org/eclipse/core/internal/databinding/property/PropertyObservableMap.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/property/PropertyObservableMap.java >diff -N src/org/eclipse/core/internal/databinding/property/PropertyObservableMap.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/property/PropertyObservableMap.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,172 @@ >+/******************************************************************************* >+ * Copyright (c) 2008 Matthew Hall and others. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * Matthew Hall - initial API and implementation (bug 194734) >+ ******************************************************************************/ >+ >+package org.eclipse.core.internal.databinding.property; >+ >+import java.util.Collection; >+import java.util.Collections; >+import java.util.Map; >+import java.util.Set; >+ >+import org.eclipse.core.databinding.observable.IObserving; >+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.property.IMapProperty; >+import org.eclipse.core.databinding.property.IMapPropertyChangeListener; >+import org.eclipse.core.databinding.property.MapPropertyChangeEvent; >+ >+/** >+ * @since 3.3 >+ * >+ */ >+public class PropertyObservableMap extends AbstractObservableMap implements >+ IObserving { >+ private Object source; >+ private IMapProperty property; >+ >+ private volatile boolean updating = false; >+ >+ private boolean disposed = false; >+ >+ private transient volatile int modCount = 0; >+ >+ private IMapPropertyChangeListener listener = new IMapPropertyChangeListener() { >+ public void handleMapPropertyChange(final MapPropertyChangeEvent event) { >+ if (!disposed && !updating) { >+ getRealm().exec(new Runnable() { >+ public void run() { >+ getRealm().exec(new Runnable() { >+ public void run() { >+ modCount++; >+ fireMapChange(event.diff); >+ } >+ }); >+ } >+ }); >+ } >+ } >+ }; >+ >+ /** >+ * @param realm >+ * @param source >+ * @param property >+ */ >+ public PropertyObservableMap(Realm realm, Object source, >+ IMapProperty property) { >+ super(realm); >+ this.source = source; >+ this.property = property; >+ } >+ >+ private void getterCalled() { >+ ObservableTracker.getterCalled(this); >+ } >+ >+ protected void firstListenerAdded() { >+ if (!disposed) { >+ property.addMapChangeListener(source, listener); >+ } >+ } >+ >+ protected void lastListenerRemoved() { >+ if (!disposed) { >+ property.removeMapChangeListener(source, listener); >+ } >+ } >+ >+ public boolean containsKey(Object key) { >+ getterCalled(); >+ return property.containsKey(source, key); >+ } >+ >+ public boolean containsValue(Object value) { >+ getterCalled(); >+ return property.containsValue(source, value); >+ } >+ >+ public Set entrySet() { >+ getterCalled(); >+ // unmodifiable for now >+ return Collections.unmodifiableSet(property.getMap(source).entrySet()); >+ } >+ >+ public Object get(Object key) { >+ getterCalled(); >+ return property.get(source, key); >+ } >+ >+ public boolean isEmpty() { >+ getterCalled(); >+ return property.isEmpty(source); >+ } >+ >+ public Set keySet() { >+ getterCalled(); >+ return Collections.unmodifiableSet(property.getMap(source).keySet()); >+ } >+ >+ public Object put(Object key, Object value) { >+ checkRealm(); >+ return property.put(source, key, value); >+ } >+ >+ public void putAll(Map m) { >+ checkRealm(); >+ property.putAll(source, m); >+ } >+ >+ public Object remove(Object key) { >+ checkRealm(); >+ return property.remove(source, key); >+ } >+ >+ public int size() { >+ getterCalled(); >+ return property.size(source); >+ } >+ >+ public Collection values() { >+ getterCalled(); >+ return Collections.unmodifiableCollection(property.getMap(source) >+ .values()); >+ } >+ >+ public void clear() { >+ getterCalled(); >+ property.clear(source); >+ } >+ >+ public boolean equals(Object o) { >+ getterCalled(); >+ return property.equals(source, o); >+ } >+ >+ public int hashCode() { >+ getterCalled(); >+ return property.hashCode(source); >+ } >+ >+ public Object getObserved() { >+ return source; >+ } >+ >+ public synchronized void dispose() { >+ if (!disposed) { >+ disposed = true; >+ property.removeMapChangeListener(source, listener); >+ property = null; >+ source = null; >+ } >+ super.dispose(); >+ } >+} >Index: src/org/eclipse/core/databinding/property/SetPropertyChangeEvent.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/SetPropertyChangeEvent.java >diff -N src/org/eclipse/core/databinding/property/SetPropertyChangeEvent.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/SetPropertyChangeEvent.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,50 @@ >+/******************************************************************************* >+ * 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; >+ >+import org.eclipse.core.databinding.observable.set.SetDiff; >+import org.eclipse.core.runtime.Assert; >+ >+/** >+ * @since 1.2 >+ */ >+public class SetPropertyChangeEvent extends PropertyChangeEvent { >+ private static final long serialVersionUID = 1L; >+ >+ /** >+ * >+ */ >+ public final ISetProperty property; >+ >+ /** >+ * SetDiff enumerating the added and removed elements in the set. May be >+ * null to indicate that the details of the set change are unknown. >+ */ >+ public final SetDiff diff; >+ >+ /** >+ * @param source >+ * @param property >+ * @param diff >+ */ >+ public SetPropertyChangeEvent(Object source, ISetProperty property, >+ SetDiff diff) { >+ super(source); >+ this.property = property; >+ Assert.isNotNull(diff, "diff cannot be null"); //$NON-NLS-1$ >+ this.diff = diff; >+ } >+ >+ void dispatch(IPropertyChangeListener listener) { >+ ((ISetPropertyChangeListener) listener).handleSetPropertyChange(this); >+ } >+} >Index: src/org/eclipse/core/databinding/property/IValueProperty.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/IValueProperty.java >diff -N src/org/eclipse/core/databinding/property/IValueProperty.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/IValueProperty.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,49 @@ >+/******************************************************************************* >+ * 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; >+ >+/** >+ * @since 1.2 >+ * >+ */ >+public interface IValueProperty extends IProperty { >+ /** >+ * @param source >+ * @return the property value >+ */ >+ public Object getValue(Object source); >+ >+ /** >+ * @param source >+ * @param value >+ */ >+ public void setValue(Object source, Object value); >+ >+ /** >+ * @return the value type of the property, or <code>null</code> if untyped. >+ */ >+ public Object getValueType(); >+ >+ /** >+ * @param source >+ * @param listener >+ */ >+ public void addValueChangeListener(Object source, >+ IValuePropertyChangeListener listener); >+ >+ /** >+ * @param source >+ * @param listener >+ */ >+ public void removeValueChangeListener(Object source, >+ IValuePropertyChangeListener listener); >+} >Index: src/org/eclipse/core/databinding/property/IMapProperty.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/IMapProperty.java >diff -N src/org/eclipse/core/databinding/property/IMapProperty.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/IMapProperty.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,116 @@ >+/******************************************************************************* >+ * 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; >+ >+import java.util.Map; >+ >+/** >+ * @since 1.2 >+ */ >+public interface IMapProperty extends IProperty { >+ /** >+ * @param source >+ * @return a Map with the current contents of the source's map property >+ */ >+ Map getMap(Object source); >+ >+ /** >+ * @param source >+ * @return the size of the source's map property >+ */ >+ int size(Object source); >+ >+ /** >+ * @param source >+ * @return whether the source's map property is empty >+ */ >+ boolean isEmpty(Object source); >+ >+ /** >+ * @param source >+ * @param key >+ * @return whether the given key is contained in the key set of the source's >+ * map property >+ */ >+ boolean containsKey(Object source, Object key); >+ >+ /** >+ * @param source >+ * @param value >+ * @return whether the given value is contains in the values collection of >+ * the source's map property >+ */ >+ boolean containsValue(Object source, Object value); >+ >+ /** >+ * @param source >+ * @param key >+ * @return the value associated with the given key in the source's map >+ * property >+ */ >+ Object get(Object source, Object key); >+ >+ /** >+ * @param source >+ * @param key >+ * @param value >+ * @return the value that was previously associated with the given key in >+ * the source's map property >+ */ >+ Object put(Object source, Object key, Object value); >+ >+ /** >+ * @param source >+ * @param key >+ * @return the value that was previously associated with the given key in >+ * the source's map property >+ */ >+ Object remove(Object source, Object key); >+ >+ /** >+ * @param source >+ * @param t >+ */ >+ void putAll(Object source, Map t); >+ >+ /** >+ * @param source >+ */ >+ void clear(Object source); >+ >+ /** >+ * @param source >+ * @param o >+ * @return whether the source's map property is equal to the argument >+ */ >+ boolean equals(Object source, Object o); >+ >+ /** >+ * @param source >+ * @return the hash code of the source's map property >+ */ >+ int hashCode(Object source); >+ >+ /** >+ * @param source >+ * @param listener >+ */ >+ public void addMapChangeListener(Object source, >+ IMapPropertyChangeListener listener); >+ >+ /** >+ * @param source >+ * @param listener >+ */ >+ public void removeMapChangeListener(Object source, >+ IMapPropertyChangeListener listener); >+} >Index: src/org/eclipse/core/databinding/property/IMapPropertyChangeListener.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/IMapPropertyChangeListener.java >diff -N src/org/eclipse/core/databinding/property/IMapPropertyChangeListener.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/IMapPropertyChangeListener.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,22 @@ >+/******************************************************************************* >+ * 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; >+ >+/** >+ * @since 1.2 >+ */ >+public interface IMapPropertyChangeListener extends IPropertyChangeListener { >+ /** >+ * @param event >+ */ >+ public void handleMapPropertyChange(MapPropertyChangeEvent event); >+} >Index: src/org/eclipse/core/databinding/property/IValuePropertyChangeListener.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/IValuePropertyChangeListener.java >diff -N src/org/eclipse/core/databinding/property/IValuePropertyChangeListener.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/IValuePropertyChangeListener.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,22 @@ >+/******************************************************************************* >+ * 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; >+ >+/** >+ * @since 1.2 >+ */ >+public interface IValuePropertyChangeListener extends IPropertyChangeListener { >+ /** >+ * @param event >+ */ >+ public void handleValuePropertyChange(ValuePropertyChangeEvent event); >+} >Index: src/org/eclipse/core/databinding/property/ValueProperty.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/ValueProperty.java >diff -N src/org/eclipse/core/databinding/property/ValueProperty.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/ValueProperty.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,34 @@ >+/******************************************************************************* >+ * 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; >+ >+import org.eclipse.core.databinding.observable.value.ValueDiff; >+ >+/** >+ * @since 1.2 >+ */ >+public abstract class ValueProperty extends Property implements IValueProperty { >+ public final void addValueChangeListener(Object source, >+ IValuePropertyChangeListener listener) { >+ getChangeSupport().addListener(source, listener); >+ } >+ >+ public final void removeValueChangeListener(Object source, >+ IValuePropertyChangeListener listener) { >+ getChangeSupport().removeListener(source, listener); >+ } >+ >+ protected final void fireValueChange(Object source, ValueDiff diff) { >+ getChangeSupport().firePropertyChange( >+ new ValuePropertyChangeEvent(source, this, diff)); >+ } >+} >Index: src/org/eclipse/core/databinding/property/masterdetail/MasterDetailProperties.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/masterdetail/MasterDetailProperties.java >diff -N src/org/eclipse/core/databinding/property/masterdetail/MasterDetailProperties.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/masterdetail/MasterDetailProperties.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,107 @@ >+/******************************************************************************* >+ * 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.masterdetail; >+ >+import org.eclipse.core.databinding.property.IListProperty; >+import org.eclipse.core.databinding.property.IMapProperty; >+import org.eclipse.core.databinding.property.ISetProperty; >+import org.eclipse.core.databinding.property.IValueProperty; >+import org.eclipse.core.internal.databinding.property.masterdetail.ListPropertyDetailValueList; >+import org.eclipse.core.internal.databinding.property.masterdetail.MapPropertyDetailValueMap; >+import org.eclipse.core.internal.databinding.property.masterdetail.SetPropertyDetailValueMap; >+import org.eclipse.core.internal.databinding.property.masterdetail.ValuePropertyDetailList; >+import org.eclipse.core.internal.databinding.property.masterdetail.ValuePropertyDetailMap; >+import org.eclipse.core.internal.databinding.property.masterdetail.ValuePropertyDetailSet; >+import org.eclipse.core.internal.databinding.property.masterdetail.ValuePropertyDetailValue; >+ >+/** >+ * @since 1.2 >+ */ >+public class MasterDetailProperties { >+ // Properties of IValueProperty master properties >+ >+ /** >+ * @param masterValue >+ * @param detailValue >+ * @return blah >+ */ >+ public static IValueProperty detailValue(IValueProperty masterValue, >+ IValueProperty detailValue) { >+ return new ValuePropertyDetailValue(masterValue, detailValue); >+ } >+ >+ /** >+ * @param masterValue >+ * @param detailList >+ * @return blah >+ */ >+ public static IListProperty detailList(IValueProperty masterValue, >+ IListProperty detailList) { >+ return new ValuePropertyDetailList(masterValue, detailList); >+ } >+ >+ /** >+ * @param masterValue >+ * @param detailSet >+ * @return blah >+ */ >+ public static ISetProperty detailSet(IValueProperty masterValue, >+ ISetProperty detailSet) { >+ return new ValuePropertyDetailSet(masterValue, detailSet); >+ } >+ >+ /** >+ * @param masterValue >+ * @param detailMap >+ * @return blah >+ */ >+ public static IMapProperty detailMap(IValueProperty masterValue, >+ IMapProperty detailMap) { >+ return new ValuePropertyDetailMap(masterValue, detailMap); >+ } >+ >+ // Properties of IListProperty master properties >+ >+ /** >+ * @param masterList >+ * @param detailValue >+ * @return blah >+ */ >+ public static IListProperty detailList(IListProperty masterList, >+ IValueProperty detailValue) { >+ return new ListPropertyDetailValueList(masterList, detailValue); >+ } >+ >+ // Properties of ISetProperty master properties >+ >+ /** >+ * @param masterKeySet >+ * @param detailValues >+ * @return blah >+ */ >+ public static IMapProperty detailMap(ISetProperty masterKeySet, >+ IValueProperty detailValues) { >+ return new SetPropertyDetailValueMap(masterKeySet, detailValues); >+ } >+ >+ // Properties of IMapProperty master properties >+ >+ /** >+ * @param masterMap >+ * @param detailValues >+ * @return blah >+ */ >+ public static IMapProperty detailMap(IMapProperty masterMap, >+ IValueProperty detailValues) { >+ return new MapPropertyDetailValueMap(masterMap, detailValues); >+ } >+} >Index: src/org/eclipse/core/internal/databinding/property/masterdetail/ValuePropertyDetailValue.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/property/masterdetail/ValuePropertyDetailValue.java >diff -N src/org/eclipse/core/internal/databinding/property/masterdetail/ValuePropertyDetailValue.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/property/masterdetail/ValuePropertyDetailValue.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,123 @@ >+/******************************************************************************* >+ * 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.masterdetail; >+ >+import java.util.HashMap; >+import java.util.Map; >+ >+import org.eclipse.core.databinding.observable.Diffs; >+import org.eclipse.core.databinding.observable.value.ValueDiff; >+import org.eclipse.core.databinding.property.IValueProperty; >+import org.eclipse.core.databinding.property.IValuePropertyChangeListener; >+import org.eclipse.core.databinding.property.ValueProperty; >+import org.eclipse.core.databinding.property.ValuePropertyChangeEvent; >+ >+/** >+ * @since 1.2 >+ * >+ */ >+public class ValuePropertyDetailValue extends ValueProperty implements >+ IValueProperty { >+ private IValueProperty masterProperty; >+ private IValueProperty detailProperty; >+ >+ private Map sourceToDetailListener = new HashMap(); >+ >+ private IValuePropertyChangeListener masterListener = new MasterPropertyListener(); >+ >+ private class MasterPropertyListener implements >+ IValuePropertyChangeListener { >+ public void handleValuePropertyChange(ValuePropertyChangeEvent event) { >+ Object oldSource = event.diff.getOldValue(); >+ Object newSource = event.diff.getNewValue(); >+ >+ Object oldValue = detailProperty.getValue(oldSource); >+ Object newValue = detailProperty.getValue(newSource); >+ >+ ValueDiff diff = Diffs.createValueDiff(oldValue, newValue); >+ >+ Object source = event.getSource(); >+ >+ removeDetailPropertyListener(source); >+ addDetailPropertyListener(source); >+ >+ fireValueChange(source, diff); >+ } >+ } >+ >+ private class DetailPropertyListener implements >+ IValuePropertyChangeListener { >+ private Object source; >+ private Object masterValue; >+ >+ DetailPropertyListener(Object source, Object masterValue) { >+ this.source = source; >+ this.masterValue = masterValue; >+ } >+ >+ public void handleValuePropertyChange(ValuePropertyChangeEvent event) { >+ fireValueChange(source, event.diff); >+ } >+ } >+ >+ /** >+ * @param masterProperty >+ * @param detailProperty >+ */ >+ public ValuePropertyDetailValue(IValueProperty masterProperty, >+ IValueProperty detailProperty) { >+ this.masterProperty = masterProperty; >+ this.detailProperty = detailProperty; >+ } >+ >+ protected void addListenerTo(Object source) { >+ masterProperty.addValueChangeListener(source, masterListener); >+ addDetailPropertyListener(source); >+ } >+ >+ protected void removeListenerFrom(Object source) { >+ masterProperty.removeValueChangeListener(source, masterListener); >+ removeDetailPropertyListener(source); >+ } >+ >+ private void addDetailPropertyListener(Object source) { >+ Object masterValue = masterProperty.getValue(source); >+ DetailPropertyListener detailListener = new DetailPropertyListener( >+ source, masterValue); >+ detailProperty.addValueChangeListener(masterValue, detailListener); >+ sourceToDetailListener.put(source, detailListener); >+ } >+ >+ private void removeDetailPropertyListener(Object source) { >+ DetailPropertyListener detailListener = (DetailPropertyListener) sourceToDetailListener >+ .remove(source); >+ if (detailListener != null) { >+ detailProperty.removeValueChangeListener( >+ detailListener.masterValue, detailListener); >+ } >+ sourceToDetailListener.remove(source); >+ } >+ >+ public Object getValue(Object source) { >+ Object masterValue = masterProperty.getValue(source); >+ return detailProperty.getValue(masterValue); >+ } >+ >+ public Object getValueType() { >+ return detailProperty.getValueType(); >+ } >+ >+ public void setValue(Object source, Object value) { >+ Object masterValue = masterProperty.getValue(source); >+ detailProperty.setValue(masterValue, value); >+ } >+} >Index: src/org/eclipse/core/internal/databinding/property/MapValuePropertyObservableMap.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/property/MapValuePropertyObservableMap.java >diff -N src/org/eclipse/core/internal/databinding/property/MapValuePropertyObservableMap.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/property/MapValuePropertyObservableMap.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,323 @@ >+/******************************************************************************* >+ * 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; >+ >+import java.util.AbstractSet; >+import java.util.HashMap; >+import java.util.HashSet; >+import java.util.IdentityHashMap; >+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.property.IValueProperty; >+import org.eclipse.core.databinding.property.IValuePropertyChangeListener; >+import org.eclipse.core.databinding.property.ValuePropertyChangeEvent; >+import org.eclipse.core.internal.databinding.Util; >+ >+/** >+ * @since 3.3 >+ * >+ */ >+public class MapValuePropertyObservableMap extends AbstractObservableMap >+ implements IObserving { >+ private IObservableMap map; >+ private IValueProperty property; >+ >+ private Map keyToMasterValueListener; >+ >+ private boolean updating = false; >+ private boolean disposed = false; >+ >+ private IMapChangeListener mapListener = new IMapChangeListener() { >+ public void handleMapChange(final MapChangeEvent event) { >+ if (!updating && !disposed) { >+ getRealm().exec(new Runnable() { >+ public void run() { >+ Map oldValues = new HashMap(); >+ Map newValues = new HashMap(); >+ >+ Set addedKeys = event.diff.getAddedKeys(); >+ for (Iterator it = addedKeys.iterator(); it.hasNext();) { >+ Object key = it.next(); >+ Object newSource = event.diff.getNewValue(key); >+ Object newValue = property.getValue(newSource); >+ newValues.put(key, newValue); >+ addPropertySourceListener(key, newSource); >+ } >+ >+ Set removedKeys = event.diff.getRemovedKeys(); >+ for (Iterator it = removedKeys.iterator(); it.hasNext();) { >+ Object key = it.next(); >+ Object oldSource = event.diff.getOldValue(key); >+ Object oldValue = property.getValue(oldSource); >+ oldValues.put(key, oldValue); >+ removePropertySourceListener(key, oldSource); >+ } >+ >+ Set changedKeys = new HashSet(event.diff >+ .getChangedKeys()); >+ for (Iterator it = changedKeys.iterator(); it.hasNext();) { >+ Object key = it.next(); >+ >+ Object oldSource = event.diff.getOldValue(key); >+ Object newSource = event.diff.getNewValue(key); >+ >+ Object oldValue = property.getValue(oldSource); >+ Object newValue = property.getValue(newSource); >+ >+ if (Util.equals(oldValue, newValue)) { >+ it.remove(); >+ } else { >+ oldValues.put(key, oldValue); >+ newValues.put(key, newValue); >+ } >+ >+ removePropertySourceListener(key, oldSource); >+ addPropertySourceListener(key, newSource); >+ } >+ >+ fireMapChange(Diffs.createMapDiff(addedKeys, >+ removedKeys, changedKeys, oldValues, newValues)); >+ } >+ }); >+ } >+ } >+ }; >+ >+ private IStaleListener staleListener = new IStaleListener() { >+ public void handleStale(StaleEvent staleEvent) { >+ fireStale(); >+ } >+ }; >+ >+ /** >+ * @param map >+ * @param valueProperty >+ */ >+ public MapValuePropertyObservableMap(IObservableMap map, >+ IValueProperty valueProperty) { >+ super(map.getRealm()); >+ this.map = map; >+ this.property = valueProperty; >+ >+ this.keyToMasterValueListener = new IdentityHashMap(); >+ } >+ >+ private class ValuePropertySourceChangeListener implements >+ IValuePropertyChangeListener { >+ private final Object key; >+ >+ public ValuePropertySourceChangeListener(Object key) { >+ this.key = key; >+ } >+ >+ public void handleValuePropertyChange(ValuePropertyChangeEvent event) { >+ Object oldSource = event.diff.getOldValue(); >+ Object oldValue = property.getValue(oldSource); >+ property.removeValueChangeListener(oldSource, this); >+ >+ Object newSource = event.diff.getNewValue(); >+ Object newValue = property.getValue(newSource); >+ property.addValueChangeListener(newSource, this); >+ >+ if (!Util.equals(oldValue, newValue)) >+ fireMapChange(Diffs.createMapDiffSingleChange(key, oldValue, >+ newValue)); >+ } >+ } >+ >+ protected void firstListenerAdded() { >+ if (!disposed) { >+ map.addMapChangeListener(mapListener); >+ map.addStaleListener(staleListener); >+ for (Iterator iterator = map.entrySet().iterator(); iterator >+ .hasNext();) { >+ Map.Entry entry = (Map.Entry) iterator.next(); >+ Object key = entry.getKey(); >+ Object masterValue = entry.getValue(); >+ >+ addPropertySourceListener(key, masterValue); >+ } >+ } >+ } >+ >+ protected void lastListenerRemoved() { >+ if (!disposed) { >+ map.removeMapChangeListener(mapListener); >+ map.removeStaleListener(staleListener); >+ for (Iterator iterator = map.entrySet().iterator(); iterator >+ .hasNext();) { >+ Map.Entry entry = (Map.Entry) iterator.next(); >+ Object key = entry.getKey(); >+ Object propertySource = entry.getValue(); >+ >+ removePropertySourceListener(key, propertySource); >+ } >+ } >+ } >+ >+ private void addPropertySourceListener(Object key, Object propertySource) { >+ IValuePropertyChangeListener propertyListener = new ValuePropertySourceChangeListener( >+ key); >+ property.addValueChangeListener(propertySource, propertyListener); >+ keyToMasterValueListener.put(key, propertyListener); >+ } >+ >+ private void removePropertySourceListener(Object key, Object propertySource) { >+ IValuePropertyChangeListener propertyListener = (IValuePropertyChangeListener) keyToMasterValueListener >+ .remove(key); >+ if (propertyListener != null) { >+ property >+ .removeValueChangeListener(propertySource, propertyListener); >+ } >+ } >+ >+ protected Object doGet(Object key) { >+ if (!map.containsKey(key)) >+ return null; >+ return property.getValue(map.get(key)); >+ } >+ >+ protected Object doPut(Object key, Object value) { >+ if (!map.containsKey(key)) >+ return null; >+ Object source = map.get(key); >+ >+ Object oldValue = property.getValue(source); >+ >+ updating = true; >+ try { >+ property.setValue(source, value); >+ } finally { >+ updating = false; >+ } >+ >+ Object newValue = property.getValue(source); >+ >+ if (!Util.equals(oldValue, newValue)) { >+ fireMapChange(Diffs.createMapDiffSingleChange(key, oldValue, >+ newValue)); >+ } >+ >+ return oldValue; >+ } >+ >+ 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 = map.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 map.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(); >+ return get(key); >+ } >+ >+ public Object setValue(Object value) { >+ return 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()); >+ } >+ } >+ >+ public boolean isStale() { >+ getterCalled(); >+ return map.isStale(); >+ } >+ >+ private void getterCalled() { >+ ObservableTracker.getterCalled(this); >+ } >+ >+ public Object getObserved() { >+ return map; >+ } >+ >+ public synchronized void dispose() { >+ if (!disposed) { >+ disposed = true; >+ property = null; >+ } >+ >+ super.dispose(); >+ } >+} >Index: src/org/eclipse/core/internal/databinding/property/masterdetail/SetPropertyDetailValueMap.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/property/masterdetail/SetPropertyDetailValueMap.java >diff -N src/org/eclipse/core/internal/databinding/property/masterdetail/SetPropertyDetailValueMap.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/property/masterdetail/SetPropertyDetailValueMap.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,217 @@ >+/******************************************************************************* >+ * 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.masterdetail; >+ >+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.map.MapDiff; >+import org.eclipse.core.databinding.property.ISetProperty; >+import org.eclipse.core.databinding.property.ISetPropertyChangeListener; >+import org.eclipse.core.databinding.property.IValueProperty; >+import org.eclipse.core.databinding.property.IValuePropertyChangeListener; >+import org.eclipse.core.databinding.property.MapProperty; >+import org.eclipse.core.databinding.property.SetPropertyChangeEvent; >+import org.eclipse.core.databinding.property.ValuePropertyChangeEvent; >+ >+/** >+ * @since 3.3 >+ * >+ */ >+public class SetPropertyDetailValueMap extends MapProperty { >+ private final ISetProperty masterProperty; >+ private final IValueProperty detailProperty; >+ >+ private Map sourceToMasterElementToDetailListener = new HashMap(); >+ >+ private ISetPropertyChangeListener masterListener = new MasterPropertyListener(); >+ >+ private class MasterPropertyListener implements ISetPropertyChangeListener { >+ public void handleSetPropertyChange(final SetPropertyChangeEvent event) { >+ Object source = event.getSource(); >+ >+ MapDiff diff; >+ if (event.diff == null) { >+ diff = null; >+ } else { >+ final Set removals = event.diff.getRemovals(); >+ final Set additions = event.diff.getAdditions(); >+ >+ diff = new MapDiff() { >+ public Set getAddedKeys() { >+ return additions; >+ } >+ >+ public Set getChangedKeys() { >+ return Collections.EMPTY_SET; >+ } >+ >+ public Object getNewValue(Object key) { >+ return getValue(key); >+ } >+ >+ public Object getOldValue(Object key) { >+ return getValue(key); >+ } >+ >+ private Object getValue(Object key) { >+ return detailProperty.getValue(key); >+ } >+ >+ public Set getRemovedKeys() { >+ return removals; >+ } >+ }; >+ >+ for (Iterator it = removals.iterator(); it.hasNext();) { >+ removeElementPropertyListener(source, it.next()); >+ } >+ for (Iterator it = additions.iterator(); it.hasNext();) { >+ addElementPropertyListener(source, it.next()); >+ } >+ } >+ >+ fireMapChange(source, diff); >+ } >+ >+ private void addElementPropertyListener(Object source, Object element) { >+ Map elementToDetailListener = (Map) sourceToMasterElementToDetailListener >+ .get(source); >+ if (elementToDetailListener == null) { >+ sourceToMasterElementToDetailListener.put(source, >+ elementToDetailListener = new HashMap()); >+ } >+ if (!elementToDetailListener.containsKey(element)) { >+ DetailPropertyListener detailListener = new DetailPropertyListener( >+ source, element); >+ detailProperty.addValueChangeListener(element, detailListener); >+ elementToDetailListener.put(element, detailListener); >+ } >+ } >+ >+ private void removeElementPropertyListener(Object source, Object element) { >+ Map elementToDetailListener = (Map) sourceToMasterElementToDetailListener >+ .get(source); >+ if (elementToDetailListener != null >+ && elementToDetailListener.containsKey(element)) { >+ DetailPropertyListener detailListener = (DetailPropertyListener) elementToDetailListener >+ .remove(element); >+ detailProperty.removeValueChangeListener(element, >+ detailListener); >+ } >+ } >+ } >+ >+ private class DetailPropertyListener implements >+ IValuePropertyChangeListener { >+ private Object source; >+ private Object masterValue; >+ >+ DetailPropertyListener(Object source, Object masterValue) { >+ this.source = source; >+ this.masterValue = masterValue; >+ } >+ >+ public void handleValuePropertyChange(ValuePropertyChangeEvent event) { >+ MapDiff diff; >+ if (event.diff == null) { >+ diff = null; >+ } else { >+ diff = Diffs.createMapDiffSingleChange(masterValue, event.diff >+ .getOldValue(), event.diff.getNewValue()); >+ } >+ fireMapChange(source, diff); >+ } >+ } >+ >+ /** >+ * @param masterProperty >+ * @param detailProperty >+ */ >+ public SetPropertyDetailValueMap(ISetProperty masterProperty, >+ IValueProperty detailProperty) { >+ this.masterProperty = masterProperty; >+ this.detailProperty = detailProperty; >+ } >+ >+ protected void addListenerTo(Object source) { >+ masterProperty.addSetChangeListener(source, masterListener); >+ >+ Map masterElementToDetailListener = new HashMap(); >+ for (Iterator it = masterProperty.getSet(source).iterator(); it >+ .hasNext();) { >+ Object masterElement = it.next(); >+ DetailPropertyListener detailListener = new DetailPropertyListener( >+ source, masterElement); >+ detailProperty >+ .addValueChangeListener(masterElement, detailListener); >+ masterElementToDetailListener.put(masterElement, detailListener); >+ } >+ >+ sourceToMasterElementToDetailListener.put(source, >+ masterElementToDetailListener); >+ } >+ >+ protected void removeListenerFrom(Object source) { >+ masterProperty.removeSetChangeListener(source, masterListener); >+ Map masterElementToDetailListener = (Map) sourceToMasterElementToDetailListener >+ .remove(source); >+ if (masterElementToDetailListener != null) { >+ for (Iterator it = masterElementToDetailListener.entrySet() >+ .iterator(); it.hasNext();) { >+ Map.Entry entry = (Map.Entry) it.next(); >+ detailProperty.removeValueChangeListener(entry.getKey(), >+ (DetailPropertyListener) entry.getValue()); >+ } >+ } >+ } >+ >+ public Map getMap(Object source) { >+ Map result = new HashMap(); >+ for (Iterator it = masterProperty.getSet(source).iterator(); it >+ .hasNext();) { >+ Object element = it.next(); >+ result.put(element, detailProperty.getValue(element)); >+ } >+ return result; >+ } >+ >+ public void clear(Object source) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public Object put(Object source, Object key, Object value) { >+ if (!masterProperty.contains(source, key)) >+ return null; >+ Object result = detailProperty.getValue(key); >+ detailProperty.setValue(key, value); >+ return result; >+ } >+ >+ public void putAll(Object source, Map t) { >+ Set masterSet = masterProperty.getSet(source); >+ for (Iterator it = t.entrySet().iterator(); it.hasNext();) { >+ Map.Entry entry = (Map.Entry) it.next(); >+ if (masterSet.contains(entry.getKey())) { >+ detailProperty.setValue(entry.getKey(), entry.getValue()); >+ } >+ } >+ } >+ >+ public Object remove(Object source, Object key) { >+ throw new UnsupportedOperationException(); >+ } >+} >Index: src/org/eclipse/core/databinding/property/IProperty.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/IProperty.java >diff -N src/org/eclipse/core/databinding/property/IProperty.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/IProperty.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,25 @@ >+/******************************************************************************* >+ * 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; >+ >+/** >+ * Interface for observing a property of a source object. >+ * >+ * @noimplement >+ * @since 1.2 >+ */ >+public interface IProperty { >+ /** >+ * Disposes the property, removing all property listeners on source objects. >+ */ >+ public void dispose(); >+} >Index: src/org/eclipse/core/databinding/property/SetProperty.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/SetProperty.java >diff -N src/org/eclipse/core/databinding/property/SetProperty.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/SetProperty.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,41 @@ >+/******************************************************************************* >+ * 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; >+ >+import java.util.Collection; >+ >+import org.eclipse.core.databinding.observable.set.SetDiff; >+ >+/** >+ * @since 1.2 >+ */ >+public abstract class SetProperty extends CollectionProperty implements >+ ISetProperty { >+ Collection getCollection(Object source) { >+ return getSet(source); >+ } >+ >+ public final void addSetChangeListener(Object source, >+ ISetPropertyChangeListener listener) { >+ getChangeSupport().addListener(source, listener); >+ } >+ >+ public final void removeSetChangeListener(Object source, >+ ISetPropertyChangeListener listener) { >+ getChangeSupport().removeListener(source, listener); >+ } >+ >+ protected final void fireSetChange(Object source, SetDiff diff) { >+ getChangeSupport().firePropertyChange( >+ new SetPropertyChangeEvent(source, this, diff)); >+ } >+} >Index: src/org/eclipse/core/internal/databinding/property/masterdetail/ValuePropertyDetailList.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/property/masterdetail/ValuePropertyDetailList.java >diff -N src/org/eclipse/core/internal/databinding/property/masterdetail/ValuePropertyDetailList.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/property/masterdetail/ValuePropertyDetailList.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,173 @@ >+/******************************************************************************* >+ * 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.masterdetail; >+ >+import java.util.Collection; >+import java.util.HashMap; >+import java.util.List; >+import java.util.Map; >+ >+import org.eclipse.core.databinding.observable.Diffs; >+import org.eclipse.core.databinding.property.IListProperty; >+import org.eclipse.core.databinding.property.IListPropertyChangeListener; >+import org.eclipse.core.databinding.property.IValueProperty; >+import org.eclipse.core.databinding.property.IValuePropertyChangeListener; >+import org.eclipse.core.databinding.property.ListProperty; >+import org.eclipse.core.databinding.property.ListPropertyChangeEvent; >+import org.eclipse.core.databinding.property.ValuePropertyChangeEvent; >+ >+/** >+ * @since 3.3 >+ * >+ */ >+public class ValuePropertyDetailList extends ListProperty { >+ private final IValueProperty masterProperty; >+ private final IListProperty detailProperty; >+ >+ private Map sourceToDetailListener = new HashMap(); >+ >+ private IValuePropertyChangeListener masterListener = new MasterPropertyListener(); >+ >+ private class MasterPropertyListener implements >+ IValuePropertyChangeListener { >+ public void handleValuePropertyChange(ValuePropertyChangeEvent event) { >+ Object oldSource = event.diff.getOldValue(); >+ Object newSource = event.diff.getNewValue(); >+ >+ List oldList = detailProperty.getList(oldSource); >+ List newList = detailProperty.getList(newSource); >+ >+ Object source = event.getSource(); >+ >+ removeDetailPropertyListener(source); >+ addDetailPropertyListener(source); >+ >+ fireListChange(source, Diffs.computeListDiff(oldList, newList)); >+ } >+ } >+ >+ private class DetailPropertyListener implements IListPropertyChangeListener { >+ private Object source; >+ private Object masterValue; >+ >+ DetailPropertyListener(Object source, Object masterValue) { >+ this.source = source; >+ this.masterValue = masterValue; >+ } >+ >+ public void handleListPropertyChange(ListPropertyChangeEvent event) { >+ fireListChange(source, event.diff); >+ } >+ } >+ >+ /** >+ * @param masterProperty >+ * @param detailProperty >+ */ >+ public ValuePropertyDetailList(IValueProperty masterProperty, >+ IListProperty detailProperty) { >+ this.masterProperty = masterProperty; >+ this.detailProperty = detailProperty; >+ } >+ >+ protected void addListenerTo(Object source) { >+ masterProperty.addValueChangeListener(source, masterListener); >+ addDetailPropertyListener(source); >+ } >+ >+ protected void removeListenerFrom(Object source) { >+ masterProperty.removeValueChangeListener(source, masterListener); >+ removeDetailPropertyListener(source); >+ } >+ >+ private void addDetailPropertyListener(Object source) { >+ Object masterValue = masterProperty.getValue(source); >+ DetailPropertyListener detailListener = new DetailPropertyListener( >+ source, masterValue); >+ detailProperty.addListChangeListener(masterValue, detailListener); >+ sourceToDetailListener.put(source, detailListener); >+ } >+ >+ private void removeDetailPropertyListener(Object source) { >+ DetailPropertyListener detailListener = (DetailPropertyListener) sourceToDetailListener >+ .remove(source); >+ if (detailListener != null) { >+ detailProperty.removeListChangeListener(detailListener.masterValue, >+ detailListener); >+ } >+ sourceToDetailListener.remove(source); >+ } >+ >+ public List getList(Object source) { >+ Object masterValue = masterProperty.getValue(source); >+ return detailProperty.getList(masterValue); >+ } >+ >+ public boolean add(Object source, Object o) { >+ Object masterValue = masterProperty.getValue(source); >+ return detailProperty.add(masterValue, o); >+ } >+ >+ public boolean addAll(Object source, Collection c) { >+ Object masterValue = masterProperty.getValue(source); >+ return detailProperty.addAll(masterValue, c); >+ } >+ >+ public void clear(Object source) { >+ Object masterValue = masterProperty.getValue(source); >+ detailProperty.clear(masterValue); >+ } >+ >+ public Object getElementType() { >+ return detailProperty.getElementType(); >+ } >+ >+ public boolean remove(Object source, Object o) { >+ Object masterValue = masterProperty.getValue(source); >+ return detailProperty.remove(masterValue, o); >+ } >+ >+ public boolean removeAll(Object source, Collection c) { >+ Object masterValue = masterProperty.getValue(source); >+ return detailProperty.removeAll(masterValue, c); >+ } >+ >+ public boolean retainAll(Object source, Collection c) { >+ Object masterValue = masterProperty.getValue(source); >+ return detailProperty.retainAll(masterValue, c); >+ } >+ >+ public void add(Object source, int index, Object element) { >+ Object masterValue = masterProperty.getValue(source); >+ detailProperty.add(masterValue, index, element); >+ } >+ >+ public boolean addAll(Object source, int index, Collection c) { >+ Object masterValue = masterProperty.getValue(source); >+ return detailProperty.addAll(masterValue, index, c); >+ } >+ >+ public Object move(Object source, int oldIndex, int newIndex) { >+ Object masterValue = masterProperty.getValue(source); >+ return detailProperty.move(masterValue, oldIndex, newIndex); >+ } >+ >+ public Object remove(Object source, int index) { >+ Object masterValue = masterProperty.getValue(source); >+ return detailProperty.remove(masterValue, index); >+ } >+ >+ public Object set(Object source, int index, Object element) { >+ Object masterValue = masterProperty.getValue(source); >+ return detailProperty.set(masterValue, index, element); >+ } >+} >Index: src/org/eclipse/core/internal/databinding/property/masterdetail/ListPropertyDetailValueList.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/property/masterdetail/ListPropertyDetailValueList.java >diff -N src/org/eclipse/core/internal/databinding/property/masterdetail/ListPropertyDetailValueList.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/property/masterdetail/ListPropertyDetailValueList.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,259 @@ >+/******************************************************************************* >+ * 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.masterdetail; >+ >+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.list.ListDiff; >+import org.eclipse.core.databinding.observable.list.ListDiffEntry; >+import org.eclipse.core.databinding.property.IListProperty; >+import org.eclipse.core.databinding.property.IListPropertyChangeListener; >+import org.eclipse.core.databinding.property.IValueProperty; >+import org.eclipse.core.databinding.property.IValuePropertyChangeListener; >+import org.eclipse.core.databinding.property.ListProperty; >+import org.eclipse.core.databinding.property.ListPropertyChangeEvent; >+import org.eclipse.core.databinding.property.ValuePropertyChangeEvent; >+import org.eclipse.core.internal.databinding.Util; >+ >+/** >+ * @since 3.3 >+ * >+ */ >+public class ListPropertyDetailValueList extends ListProperty { >+ private final IListProperty masterProperty; >+ private final IValueProperty detailProperty; >+ >+ private Map sourceToMasterElementToDetailListener = new HashMap(); >+ >+ private IListPropertyChangeListener masterListener = new MasterPropertyListener(); >+ >+ private class MasterPropertyListener implements IListPropertyChangeListener { >+ public void handleListPropertyChange(ListPropertyChangeEvent event) { >+ Object source = event.getSource(); >+ ListDiffEntry[] masterEntries = event.diff.getDifferences(); >+ ListDiffEntry[] detailEntries = new ListDiffEntry[masterEntries.length]; >+ Set masterElementsAdded = new HashSet(); >+ Set masterElementsRemoved = new HashSet(); >+ 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); >+ if (addition) >+ masterElementsAdded.add(masterElement); >+ else >+ masterElementsRemoved.add(masterElement); >+ } >+ >+ ListDiff diff = Diffs.createListDiff(detailEntries); >+ >+ for (Iterator it = masterElementsRemoved.iterator(); it.hasNext();) { >+ Object element = it.next(); >+ if (!masterProperty.contains(source, element)) >+ removeElementPropertyListener(source, element); >+ } >+ for (Iterator it = masterElementsAdded.iterator(); it.hasNext();) { >+ Object element = it.next(); >+ if (masterProperty.contains(source, element)) >+ addElementPropertyListener(source, element); >+ } >+ >+ fireListChange(source, diff); >+ } >+ >+ private void addElementPropertyListener(Object source, Object element) { >+ Map elementToDetailListener = (Map) sourceToMasterElementToDetailListener >+ .get(source); >+ if (elementToDetailListener == null) { >+ sourceToMasterElementToDetailListener.put(source, >+ elementToDetailListener = new HashMap()); >+ } >+ if (!elementToDetailListener.containsKey(element)) { >+ DetailPropertyListener detailListener = new DetailPropertyListener( >+ source, element); >+ detailProperty.addValueChangeListener(element, detailListener); >+ elementToDetailListener.put(element, detailListener); >+ } >+ } >+ >+ private void removeElementPropertyListener(Object source, Object element) { >+ Map elementToDetailListener = (Map) sourceToMasterElementToDetailListener >+ .get(source); >+ if (elementToDetailListener != null >+ && elementToDetailListener.containsKey(element)) { >+ DetailPropertyListener detailListener = (DetailPropertyListener) elementToDetailListener >+ .remove(element); >+ detailProperty.removeValueChangeListener(element, >+ detailListener); >+ } >+ } >+ } >+ >+ private class DetailPropertyListener implements >+ IValuePropertyChangeListener { >+ private Object source; >+ private Object masterElement; >+ >+ DetailPropertyListener(Object source, Object masterElement) { >+ this.source = source; >+ this.masterElement = masterElement; >+ } >+ >+ private int[] findIndices() { >+ List indices = new ArrayList(); >+ >+ List list = masterProperty.getList(source); >+ for (ListIterator it = list.listIterator(); it.hasNext();) { >+ if (Util.equals(masterElement, it.next())) >+ indices.add(Integer.valueOf(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; >+ } >+ >+ public void handleValuePropertyChange(ValuePropertyChangeEvent event) { >+ int[] indices = findIndices(); >+ Object oldValue = event.diff.getOldValue(); >+ Object newValue = event.diff.getNewValue(); >+ ListDiffEntry[] entries = new ListDiffEntry[indices.length * 2]; >+ for (int i = 0; i < indices.length; i++) { >+ int index = indices[i]; >+ entries[i * 2] = Diffs.createListDiffEntry(index, false, >+ oldValue); >+ entries[i * 2 + 1] = Diffs.createListDiffEntry(index, true, >+ newValue); >+ } >+ >+ ListDiff diff = Diffs.createListDiff(entries); >+ fireListChange(source, diff); >+ } >+ } >+ >+ /** >+ * @param masterProperty >+ * @param detailProperty >+ */ >+ public ListPropertyDetailValueList(IListProperty masterProperty, >+ IValueProperty detailProperty) { >+ this.masterProperty = masterProperty; >+ this.detailProperty = detailProperty; >+ } >+ >+ protected void addListenerTo(Object source) { >+ masterProperty.addListChangeListener(source, masterListener); >+ >+ Map masterElementToDetailListener = new HashMap(); >+ for (Iterator it = masterProperty.getList(source).iterator(); it >+ .hasNext();) { >+ Object masterElement = it.next(); >+ DetailPropertyListener detailListener = new DetailPropertyListener( >+ source, masterElement); >+ detailProperty >+ .addValueChangeListener(masterElement, detailListener); >+ masterElementToDetailListener.put(masterElement, detailListener); >+ } >+ >+ sourceToMasterElementToDetailListener.put(source, >+ masterElementToDetailListener); >+ } >+ >+ protected void removeListenerFrom(Object source) { >+ masterProperty.removeListChangeListener(source, masterListener); >+ Map masterElementToDetailListener = (Map) sourceToMasterElementToDetailListener >+ .remove(source); >+ if (masterElementToDetailListener != null) { >+ for (Iterator it = masterElementToDetailListener.entrySet() >+ .iterator(); it.hasNext();) { >+ Map.Entry entry = (Map.Entry) it.next(); >+ detailProperty.removeValueChangeListener(entry.getKey(), >+ (DetailPropertyListener) entry.getValue()); >+ } >+ } >+ } >+ >+ public List getList(Object source) { >+ List result = new ArrayList(); >+ for (Iterator it = masterProperty.getList(source).iterator(); it >+ .hasNext();) { >+ result.add(detailProperty.getValue(it.next())); >+ } >+ return result; >+ } >+ >+ public boolean add(Object source, Object o) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public boolean addAll(Object source, Collection c) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public void clear(Object source) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public Object getElementType() { >+ return detailProperty.getValueType(); >+ } >+ >+ public boolean remove(Object source, Object o) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public boolean removeAll(Object source, Collection c) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public boolean retainAll(Object source, Collection c) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public void add(Object source, int index, Object element) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public boolean addAll(Object source, int index, Collection c) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public Object move(Object source, int oldIndex, int newIndex) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public Object remove(Object source, int index) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public Object set(Object source, int index, Object element) { >+ Object masterElement = masterProperty.get(source, index); >+ Object result = detailProperty.getValue(masterElement); >+ detailProperty.setValue(masterElement, element); >+ return result; >+ } >+} >Index: src/org/eclipse/core/internal/databinding/property/masterdetail/ValuePropertyDetailMap.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/property/masterdetail/ValuePropertyDetailMap.java >diff -N src/org/eclipse/core/internal/databinding/property/masterdetail/ValuePropertyDetailMap.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/property/masterdetail/ValuePropertyDetailMap.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,133 @@ >+/******************************************************************************* >+ * 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.masterdetail; >+ >+import java.util.HashMap; >+import java.util.Map; >+ >+import org.eclipse.core.databinding.observable.Diffs; >+import org.eclipse.core.databinding.observable.map.MapDiff; >+import org.eclipse.core.databinding.property.IMapProperty; >+import org.eclipse.core.databinding.property.IMapPropertyChangeListener; >+import org.eclipse.core.databinding.property.IValueProperty; >+import org.eclipse.core.databinding.property.IValuePropertyChangeListener; >+import org.eclipse.core.databinding.property.MapProperty; >+import org.eclipse.core.databinding.property.MapPropertyChangeEvent; >+import org.eclipse.core.databinding.property.ValuePropertyChangeEvent; >+ >+/** >+ * @since 3.3 >+ * >+ */ >+public class ValuePropertyDetailMap extends MapProperty { >+ private final IValueProperty masterProperty; >+ private final IMapProperty detailProperty; >+ >+ private Map sourceToDetailListener = new HashMap(); >+ >+ private IValuePropertyChangeListener masterListener = new MasterValueListener(); >+ >+ private class MasterValueListener implements IValuePropertyChangeListener { >+ public void handleValuePropertyChange(ValuePropertyChangeEvent event) { >+ Object oldSource = event.diff.getOldValue(); >+ Object newSource = event.diff.getNewValue(); >+ >+ Map oldMap = detailProperty.getMap(oldSource); >+ Map newMap = detailProperty.getMap(newSource); >+ MapDiff diff = Diffs.computeMapDiff(oldMap, newMap); >+ >+ Object source = event.getSource(); >+ >+ removeDetailPropertyListener(source); >+ addDetailPropertyListener(source); >+ >+ fireMapChange(source, diff); >+ } >+ } >+ >+ private class DetailPropertyListener implements IMapPropertyChangeListener { >+ private Object source; >+ private Object masterValue; >+ >+ DetailPropertyListener(Object source, Object masterValue) { >+ this.source = source; >+ this.masterValue = masterValue; >+ } >+ >+ public void handleMapPropertyChange(MapPropertyChangeEvent event) { >+ fireMapChange(source, event.diff); >+ } >+ } >+ >+ /** >+ * @param masterProperty >+ * @param detailProperty >+ */ >+ public ValuePropertyDetailMap(IValueProperty masterProperty, >+ IMapProperty detailProperty) { >+ this.masterProperty = masterProperty; >+ this.detailProperty = detailProperty; >+ } >+ >+ protected void addListenerTo(Object source) { >+ masterProperty.addValueChangeListener(source, masterListener); >+ addDetailPropertyListener(source); >+ } >+ >+ protected void removeListenerFrom(Object source) { >+ masterProperty.removeValueChangeListener(source, masterListener); >+ removeDetailPropertyListener(source); >+ } >+ >+ private void addDetailPropertyListener(Object source) { >+ Object masterValue = masterProperty.getValue(source); >+ DetailPropertyListener detailListener = new DetailPropertyListener( >+ source, masterValue); >+ detailProperty.addMapChangeListener(masterValue, detailListener); >+ sourceToDetailListener.put(source, detailListener); >+ } >+ >+ private void removeDetailPropertyListener(Object source) { >+ DetailPropertyListener detailListener = (DetailPropertyListener) sourceToDetailListener >+ .remove(source); >+ if (detailListener != null) { >+ detailProperty.removeMapChangeListener(detailListener.masterValue, >+ detailListener); >+ } >+ sourceToDetailListener.remove(source); >+ } >+ >+ public Map getMap(Object source) { >+ Object masterValue = masterProperty.getValue(source); >+ return detailProperty.getMap(masterValue); >+ } >+ >+ public void clear(Object source) { >+ Object masterValue = masterProperty.getValue(source); >+ detailProperty.clear(masterValue); >+ } >+ >+ public Object put(Object source, Object key, Object value) { >+ Object masterValue = masterProperty.getValue(source); >+ return detailProperty.put(masterValue, key, value); >+ } >+ >+ public void putAll(Object source, Map t) { >+ Object masterValue = masterProperty.getValue(source); >+ detailProperty.putAll(masterValue, t); >+ } >+ >+ public Object remove(Object source, Object key) { >+ Object masterValue = masterProperty.getValue(source); >+ return detailProperty.remove(masterValue, key); >+ } >+} >Index: src/org/eclipse/core/databinding/property/ISetPropertyChangeListener.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/ISetPropertyChangeListener.java >diff -N src/org/eclipse/core/databinding/property/ISetPropertyChangeListener.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/ISetPropertyChangeListener.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,22 @@ >+/******************************************************************************* >+ * 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; >+ >+/** >+ * @since 1.2 >+ */ >+public interface ISetPropertyChangeListener extends IPropertyChangeListener { >+ /** >+ * @param event >+ */ >+ public void handleSetPropertyChange(SetPropertyChangeEvent event); >+} >Index: src/org/eclipse/core/databinding/property/MapPropertyChangeEvent.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/MapPropertyChangeEvent.java >diff -N src/org/eclipse/core/databinding/property/MapPropertyChangeEvent.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/MapPropertyChangeEvent.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,50 @@ >+/******************************************************************************* >+ * 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; >+ >+import org.eclipse.core.databinding.observable.map.MapDiff; >+import org.eclipse.core.runtime.Assert; >+ >+/** >+ * @since 1.2 >+ */ >+public class MapPropertyChangeEvent extends PropertyChangeEvent { >+ private static final long serialVersionUID = 1L; >+ >+ /** >+ * >+ */ >+ public final IMapProperty property; >+ >+ /** >+ * MapDiff enumerating the added, changed, and removed entries in the map. >+ * May be null to indicate that the details of the map change are unknown. >+ */ >+ public final MapDiff diff; >+ >+ /** >+ * @param source >+ * @param property >+ * @param diff >+ */ >+ public MapPropertyChangeEvent(Object source, IMapProperty property, >+ MapDiff diff) { >+ super(source); >+ this.property = property; >+ Assert.isNotNull(diff, "diff cannot be null"); //$NON-NLS-1$ >+ this.diff = diff; >+ } >+ >+ void dispatch(IPropertyChangeListener listener) { >+ ((IMapPropertyChangeListener) listener).handleMapPropertyChange(this); >+ } >+} >Index: src/org/eclipse/core/databinding/property/ListPropertyChangeEvent.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/ListPropertyChangeEvent.java >diff -N src/org/eclipse/core/databinding/property/ListPropertyChangeEvent.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/ListPropertyChangeEvent.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,50 @@ >+/******************************************************************************* >+ * 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; >+ >+import org.eclipse.core.databinding.observable.list.ListDiff; >+import org.eclipse.core.runtime.Assert; >+ >+/** >+ * @since 1.2 >+ */ >+public class ListPropertyChangeEvent extends PropertyChangeEvent { >+ private static final long serialVersionUID = 1L; >+ >+ /** >+ * >+ */ >+ public final IListProperty property; >+ >+ /** >+ * ListDiff enumerating the added and removed elements in the list. May be >+ * null to indicate that the details of the list change are unknown. >+ */ >+ public final ListDiff diff; >+ >+ /** >+ * @param source >+ * @param property >+ * @param diff >+ */ >+ public ListPropertyChangeEvent(Object source, IListProperty property, >+ ListDiff diff) { >+ super(source); >+ this.property = property; >+ Assert.isNotNull(diff, "diff cannot be null"); //$NON-NLS-1$ >+ this.diff = diff; >+ } >+ >+ void dispatch(IPropertyChangeListener listener) { >+ ((IListPropertyChangeListener) listener).handleListPropertyChange(this); >+ } >+} >Index: src/org/eclipse/core/databinding/property/ICollectionProperty.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/ICollectionProperty.java >diff -N src/org/eclipse/core/databinding/property/ICollectionProperty.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/ICollectionProperty.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,120 @@ >+/******************************************************************************* >+ * 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; >+ >+import java.util.Collection; >+ >+/** >+ * @since 1.2 >+ * >+ */ >+public interface ICollectionProperty extends IProperty { >+ /** >+ * @param source >+ * @return the size of the source's collection property >+ */ >+ int size(Object source); >+ >+ /** >+ * @param source >+ * @return whether the source's collection property is empty >+ */ >+ boolean isEmpty(Object source); >+ >+ /** >+ * @param source >+ * @param o >+ * @return whether the source's collection property contains the given >+ * element >+ */ >+ boolean contains(Object source, Object o); >+ >+ /** >+ * @param source >+ * @return an array of all elements in the source's collection property >+ */ >+ Object[] toArray(Object source); >+ >+ /** >+ * @param source >+ * @param array >+ * @return an array of all elements in the source's collection property >+ */ >+ Object[] toArray(Object source, Object[] array); >+ >+ /** >+ * @param source >+ * @param o >+ * @return whether the element was added to the source's collection property >+ */ >+ boolean add(Object source, Object o); >+ >+ /** >+ * @param source >+ * @param o >+ * @return whether the element was removed from the source's collection >+ * property >+ */ >+ boolean remove(Object source, Object o); >+ >+ /** >+ * @param source >+ * @param c >+ * @return whether the source's collection property contains all elements in >+ * the given collection >+ */ >+ boolean containsAll(Object source, Collection c); >+ >+ /** >+ * @param source >+ * @param c >+ * @return whether the source's collection property was changed >+ */ >+ boolean addAll(Object source, Collection c); >+ >+ /** >+ * @param source >+ * @param c >+ * @return whether the source's collection property was changed >+ */ >+ boolean removeAll(Object source, Collection c); >+ >+ /** >+ * @param source >+ * @param c >+ * @return whether the source's collection property was changed >+ */ >+ boolean retainAll(Object source, Collection c); >+ >+ /** >+ * @param source >+ */ >+ void clear(Object source); >+ >+ /** >+ * @param source >+ * @param o >+ * @return whether the source's collection property is equal to the argument >+ */ >+ boolean equals(Object source, Object o); >+ >+ /** >+ * @param source >+ * @return the hash code of the source's collection property >+ */ >+ int hashCode(Object source); >+ >+ /** >+ * @return the type of the elements or <code>null</code> if untyped >+ */ >+ Object getElementType(); >+} >Index: src/org/eclipse/core/databinding/property/PropertyChangeEvent.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/PropertyChangeEvent.java >diff -N src/org/eclipse/core/databinding/property/PropertyChangeEvent.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/PropertyChangeEvent.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,27 @@ >+/******************************************************************************* >+ * 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; >+ >+import java.util.EventObject; >+ >+/** >+ * @since 1.2 >+ */ >+public abstract class PropertyChangeEvent extends EventObject { >+ private static final long serialVersionUID = 1L; >+ >+ PropertyChangeEvent(Object source) { >+ super(source); >+ } >+ >+ abstract void dispatch(IPropertyChangeListener listener); >+} >Index: src/org/eclipse/core/internal/databinding/property/masterdetail/MapPropertyDetailValueMap.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/property/masterdetail/MapPropertyDetailValueMap.java >diff -N src/org/eclipse/core/internal/databinding/property/masterdetail/MapPropertyDetailValueMap.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/property/masterdetail/MapPropertyDetailValueMap.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,223 @@ >+/******************************************************************************* >+ * 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.masterdetail; >+ >+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.map.MapDiff; >+import org.eclipse.core.databinding.property.IMapProperty; >+import org.eclipse.core.databinding.property.IMapPropertyChangeListener; >+import org.eclipse.core.databinding.property.IValueProperty; >+import org.eclipse.core.databinding.property.IValuePropertyChangeListener; >+import org.eclipse.core.databinding.property.MapProperty; >+import org.eclipse.core.databinding.property.MapPropertyChangeEvent; >+import org.eclipse.core.databinding.property.ValuePropertyChangeEvent; >+import org.eclipse.core.internal.databinding.Util; >+ >+/** >+ * @since 3.3 >+ * >+ */ >+public class MapPropertyDetailValueMap extends MapProperty { >+ private final IMapProperty masterProperty; >+ private final IValueProperty detailProperty; >+ >+ private Map sourceToKeyToDetailListener = new HashMap(); >+ >+ private IMapPropertyChangeListener masterListener = new MasterPropertyListener(); >+ >+ private class MasterPropertyListener implements IMapPropertyChangeListener { >+ public void handleMapPropertyChange(final MapPropertyChangeEvent event) { >+ Object source = event.getSource(); >+ >+ Map oldValues = new HashMap(); >+ Map newValues = new HashMap(); >+ >+ Set addedKeys = event.diff.getAddedKeys(); >+ for (Iterator it = addedKeys.iterator(); it.hasNext();) { >+ Object key = it.next(); >+ Object newMasterValue = event.diff.getNewValue(key); >+ Object newDetailValue = detailProperty.getValue(newMasterValue); >+ newValues.put(key, newDetailValue); >+ addPropertySourceListener(source, key, newMasterValue); >+ } >+ >+ Set removedKeys = event.diff.getRemovedKeys(); >+ for (Iterator it = removedKeys.iterator(); it.hasNext();) { >+ Object key = it.next(); >+ Object oldMasterValue = event.diff.getOldValue(key); >+ Object oldDetailValue = detailProperty.getValue(oldMasterValue); >+ oldValues.put(key, oldDetailValue); >+ removePropertySourceListener(source, key, oldMasterValue); >+ } >+ >+ Set changedKeys = new HashSet(event.diff.getChangedKeys()); >+ for (Iterator it = changedKeys.iterator(); it.hasNext();) { >+ Object key = it.next(); >+ >+ Object oldMasterValue = event.diff.getOldValue(key); >+ Object newMasterValue = event.diff.getNewValue(key); >+ >+ Object oldDetailValue = detailProperty.getValue(oldMasterValue); >+ Object newDetailValue = detailProperty.getValue(newMasterValue); >+ >+ if (Util.equals(oldDetailValue, newDetailValue)) { >+ it.remove(); >+ } else { >+ oldValues.put(key, oldDetailValue); >+ newValues.put(key, newDetailValue); >+ } >+ >+ removePropertySourceListener(source, key, oldMasterValue); >+ addPropertySourceListener(source, key, newMasterValue); >+ } >+ >+ MapDiff diff = Diffs.createMapDiff(addedKeys, removedKeys, >+ changedKeys, oldValues, newValues); >+ >+ fireMapChange(source, diff); >+ } >+ >+ private void addPropertySourceListener(Object source, Object key, >+ Object masterValue) { >+ Map keyToDetailListener = (Map) sourceToKeyToDetailListener >+ .get(source); >+ if (keyToDetailListener == null) { >+ sourceToKeyToDetailListener.put(source, >+ keyToDetailListener = new HashMap()); >+ } >+ if (!keyToDetailListener.containsKey(key)) { >+ DetailPropertyListener detailListener = new DetailPropertyListener( >+ source, key); >+ detailProperty.addValueChangeListener(masterValue, >+ detailListener); >+ keyToDetailListener.put(key, detailListener); >+ } >+ } >+ >+ private void removePropertySourceListener(Object source, Object key, >+ Object masterValue) { >+ Map keyToDetailListener = (Map) sourceToKeyToDetailListener >+ .get(source); >+ if (keyToDetailListener != null >+ && keyToDetailListener.containsKey(key)) { >+ DetailPropertyListener detailListener = (DetailPropertyListener) keyToDetailListener >+ .remove(key); >+ detailProperty.removeValueChangeListener(masterValue, >+ detailListener); >+ } >+ } >+ } >+ >+ private class DetailPropertyListener implements >+ IValuePropertyChangeListener { >+ private Object source; >+ private Object key; >+ >+ DetailPropertyListener(Object source, Object key) { >+ this.source = source; >+ this.key = key; >+ } >+ >+ public void handleValuePropertyChange(ValuePropertyChangeEvent event) { >+ fireMapChange(source, Diffs.createMapDiffSingleChange(key, >+ event.diff.getOldValue(), event.diff.getNewValue())); >+ } >+ } >+ >+ /** >+ * @param masterProperty >+ * @param detailProperty >+ */ >+ public MapPropertyDetailValueMap(IMapProperty masterProperty, >+ IValueProperty detailProperty) { >+ this.masterProperty = masterProperty; >+ this.detailProperty = detailProperty; >+ } >+ >+ protected void addListenerTo(Object source) { >+ masterProperty.addMapChangeListener(source, masterListener); >+ >+ Map keyToDetailListener = new HashMap(); >+ for (Iterator it = masterProperty.getMap(source).entrySet().iterator(); it >+ .hasNext();) { >+ Map.Entry entry = (Map.Entry) it.next(); >+ Object key = entry.getKey(); >+ Object masterValue = entry.getValue(); >+ DetailPropertyListener detailListener = new DetailPropertyListener( >+ source, key); >+ detailProperty.addValueChangeListener(masterValue, detailListener); >+ keyToDetailListener.put(masterValue, detailListener); >+ } >+ >+ sourceToKeyToDetailListener.put(source, keyToDetailListener); >+ } >+ >+ protected void removeListenerFrom(Object source) { >+ masterProperty.removeMapChangeListener(source, masterListener); >+ Map masterElementToDetailListener = (Map) sourceToKeyToDetailListener >+ .remove(source); >+ if (masterElementToDetailListener != null) { >+ for (Iterator it = masterElementToDetailListener.entrySet() >+ .iterator(); it.hasNext();) { >+ Map.Entry entry = (Map.Entry) it.next(); >+ detailProperty.removeValueChangeListener(entry.getKey(), >+ (DetailPropertyListener) entry.getValue()); >+ } >+ } >+ } >+ >+ public Map getMap(Object source) { >+ Map result = new HashMap(); >+ for (Iterator it = masterProperty.getMap(source).entrySet().iterator(); it >+ .hasNext();) { >+ Map.Entry entry = (Map.Entry) it.next(); >+ result.put(entry.getKey(), detailProperty >+ .getValue(entry.getValue())); >+ } >+ return result; >+ } >+ >+ public void clear(Object source) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ public Object put(Object source, Object key, Object value) { >+ if (!masterProperty.containsKey(source, key)) >+ return null; >+ Object masterValue = masterProperty.get(source, key); >+ >+ Object result = detailProperty.getValue(masterValue); >+ detailProperty.setValue(masterValue, value); >+ return result; >+ } >+ >+ public void putAll(Object source, Map t) { >+ for (Iterator it = t.entrySet().iterator(); it.hasNext();) { >+ Map.Entry entry = (Map.Entry) it.next(); >+ Object masterKey = entry.getKey(); >+ Object detailValue = entry.getValue(); >+ if (masterProperty.getMap(source).containsKey(masterKey)) { >+ detailProperty.setValue(masterKey, detailValue); >+ } >+ } >+ } >+ >+ public Object remove(Object source, Object key) { >+ throw new UnsupportedOperationException(); >+ } >+} >Index: src/org/eclipse/core/databinding/property/PropertyChangeSupport.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/PropertyChangeSupport.java >diff -N src/org/eclipse/core/databinding/property/PropertyChangeSupport.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/PropertyChangeSupport.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,121 @@ >+/******************************************************************************* >+ * 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; >+ >+import java.util.Collections; >+import java.util.IdentityHashMap; >+import java.util.Iterator; >+import java.util.Map; >+ >+import org.eclipse.core.runtime.ListenerList; >+ >+/** >+ * @since 1.2 >+ */ >+public class PropertyChangeSupport { >+ private Property property; >+ private Map changeListeners; >+ >+ PropertyChangeSupport(Property property) { >+ this.property = property; >+ this.changeListeners = null; >+ } >+ >+ protected final void addListener(Object source, >+ IPropertyChangeListener listener) { >+ boolean hadListeners = hasListeners(source); >+ >+ if (changeListeners == null) { >+ synchronized (this) { >+ if (changeListeners == null) { >+ changeListeners = Collections >+ .synchronizedMap(new IdentityHashMap()); >+ } >+ } >+ } >+ >+ ListenerList listeners; >+ synchronized (changeListeners) { >+ if (changeListeners.containsKey(source)) { >+ listeners = (ListenerList) changeListeners.get(source); >+ } else { >+ changeListeners.put(source, listeners = new ListenerList()); >+ } >+ } >+ >+ synchronized (listeners) { >+ listeners.add(listener); >+ } >+ >+ if (!hadListeners) >+ property.addListenerTo(source); >+ } >+ >+ /** >+ * Returns whether the change support has listeners registered for the given >+ * property source >+ * >+ * @param source >+ * the property source >+ * @return whether the change support has listeners registered for the given >+ * property source >+ */ >+ public boolean hasListeners(Object source) { >+ return changeListeners != null && changeListeners.containsKey(source); >+ } >+ >+ protected final void removeListener(Object source, >+ IPropertyChangeListener listener) { >+ if (changeListeners != null) { >+ ListenerList listeners = (ListenerList) changeListeners.get(source); >+ if (listeners != null) { >+ listeners.remove(listener); >+ if (listeners.isEmpty()) { >+ synchronized (listeners) { >+ if (listeners.isEmpty()) { >+ changeListeners.remove(source); >+ property.removeListenerFrom(source); >+ } >+ } >+ } >+ } >+ } >+ } >+ >+ protected final void firePropertyChange(PropertyChangeEvent event) { >+ ListenerList listenerList; >+ synchronized (this) { >+ if (changeListeners == null) >+ return; >+ listenerList = (ListenerList) changeListeners >+ .get(event.getSource()); >+ } >+ if (listenerList != null) { >+ Object[] listeners = listenerList.getListeners(); >+ for (int i = 0; i < listeners.length; i++) { >+ event.dispatch((IPropertyChangeListener) listeners[i]); >+ } >+ } >+ } >+ >+ void dispose() { >+ if (changeListeners != null) { >+ for (Iterator iterator = changeListeners.keySet().iterator(); iterator >+ .hasNext();) { >+ Object source = iterator.next(); >+ property.removeListenerFrom(source); >+ iterator.remove(); >+ } >+ changeListeners = null; >+ } >+ } >+} >Index: src/org/eclipse/core/databinding/property/PropertyObservables.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/PropertyObservables.java >diff -N src/org/eclipse/core/databinding/property/PropertyObservables.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/PropertyObservables.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,229 @@ >+/******************************************************************************* >+ * 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; >+ >+import org.eclipse.core.databinding.observable.IObservable; >+import org.eclipse.core.databinding.observable.Realm; >+import org.eclipse.core.databinding.observable.list.IObservableList; >+import org.eclipse.core.databinding.observable.map.IObservableMap; >+import org.eclipse.core.databinding.observable.masterdetail.IObservableFactory; >+import org.eclipse.core.databinding.observable.set.IObservableSet; >+import org.eclipse.core.databinding.observable.value.IObservableValue; >+import org.eclipse.core.internal.databinding.property.PropertyObservableList; >+import org.eclipse.core.internal.databinding.property.PropertyObservableMap; >+import org.eclipse.core.internal.databinding.property.PropertyObservableSet; >+import org.eclipse.core.internal.databinding.property.PropertyObservableValue; >+import org.eclipse.core.internal.databinding.property.SetValuePropertyObservableMap; >+ >+/** >+ * @since 1.2 >+ * >+ */ >+public class PropertyObservables { >+ /** >+ * @param source >+ * @param property >+ * @return an observable value that tracks the given property of the source >+ * object. >+ * @since 1.2 >+ */ >+ public static IObservableValue observeValue(Object source, >+ IValueProperty property) { >+ return observeValue(Realm.getDefault(), source, property); >+ } >+ >+ /** >+ * @param realm >+ * @param source >+ * @param property >+ * @return an observable value that tracks the given property of the source >+ * object >+ * @since 1.2 >+ */ >+ public static IObservableValue observeValue(Realm realm, Object source, >+ IValueProperty property) { >+ return new PropertyObservableValue(realm, source, property); >+ } >+ >+ /** >+ * @param source >+ * @param property >+ * @return an observable set that tracks the given property of the source >+ * object >+ */ >+ public static IObservableSet observeSet(Object source, ISetProperty property) { >+ return observeSet(Realm.getDefault(), source, property); >+ } >+ >+ /** >+ * @param realm >+ * @param source >+ * @param property >+ * @return an observable set that tracks the given property of the source >+ * object >+ */ >+ public static IObservableSet observeSet(Realm realm, Object source, >+ ISetProperty property) { >+ return new PropertyObservableSet(realm, source, property); >+ } >+ >+ /** >+ * @param source >+ * @param property >+ * @return an observable list that tracks the given property of the source >+ * object >+ */ >+ public static IObservableList observeList(Object source, >+ IListProperty property) { >+ return observeList(Realm.getDefault(), source, property); >+ } >+ >+ /** >+ * @param realm >+ * @param source >+ * @param property >+ * @return an observable set that tracks the given property of the source >+ * object >+ */ >+ public static IObservableList observeList(Realm realm, Object source, >+ IListProperty property) { >+ return new PropertyObservableList(realm, source, property); >+ } >+ >+ /** >+ * @param source >+ * @param property >+ * @return an observable map that tracks the given property of the source >+ * object >+ */ >+ public static IObservableMap observeMap(Object source, IMapProperty property) { >+ return observeMap(Realm.getDefault(), source, property); >+ } >+ >+ /** >+ * @param realm >+ * @param source >+ * @param property >+ * @return an observable set that tracks the given property of the source >+ * object >+ */ >+ public static IObservableMap observeMap(Realm realm, Object source, >+ IMapProperty property) { >+ return new PropertyObservableMap(realm, source, property); >+ } >+ >+ /** >+ * Returns an observable map in the default realm tracking the current >+ * values of the named property for the beans in the given set. >+ * >+ * @param keySet >+ * @param valueProperty >+ * @return an observable map >+ */ >+ public static IObservableMap observeMap(IObservableSet keySet, >+ IValueProperty valueProperty) { >+ return new SetValuePropertyObservableMap(keySet, valueProperty); >+ } >+ >+ /** >+ * Returns a factory for creating observable values tracking the given >+ * property of a particular source object >+ * >+ * @param property >+ * the property to be observed >+ * @return an observable value factory on >+ */ >+ public static IObservableFactory valueFactory(IValueProperty property) { >+ return valueFactory(Realm.getDefault(), property); >+ } >+ >+ /** >+ * Returns a factory for creating observable values tracking the given >+ * property of a particular source object >+ * >+ * @param realm >+ * the realm to use >+ * @param property >+ * the property to be observed >+ * @return an observable value factory on >+ */ >+ public static IObservableFactory valueFactory(final Realm realm, >+ final IValueProperty property) { >+ return new IObservableFactory() { >+ public IObservable createObservable(Object target) { >+ return observeValue(realm, target, property); >+ } >+ }; >+ } >+ >+ /** >+ * Returns a factory for creating observable sets tracking the given >+ * property of a particular source object >+ * >+ * @param property >+ * the property to be observed >+ * @return an observable value factory on >+ */ >+ public static IObservableFactory setFactory(ISetProperty property) { >+ return setFactory(Realm.getDefault(), property); >+ } >+ >+ /** >+ * Returns a factory for creating obervable sets tracking the given property >+ * of a particular source object >+ * >+ * @param realm >+ * the realm to use >+ * @param property >+ * the property to be observed >+ * @return an observable value factory on >+ */ >+ public static IObservableFactory setFactory(final Realm realm, >+ final ISetProperty property) { >+ return new IObservableFactory() { >+ public IObservable createObservable(Object target) { >+ return observeSet(realm, target, property); >+ } >+ }; >+ } >+ >+ /** >+ * Returns a factory for creating observable lists tracking the given >+ * property of a particular source object >+ * >+ * @param property >+ * the property to be observed >+ * @return an observable value factory on >+ */ >+ public static IObservableFactory listFactory(IListProperty property) { >+ return listFactory(Realm.getDefault(), property); >+ } >+ >+ /** >+ * Returns a factory for creating obervable lists tracking the given >+ * property of a particular source object >+ * >+ * @param realm >+ * the realm to use >+ * @param property >+ * the property to be observed >+ * @return an observable value factory on >+ */ >+ public static IObservableFactory listFactory(final Realm realm, >+ final IListProperty property) { >+ return new IObservableFactory() { >+ public IObservable createObservable(Object target) { >+ return observeList(realm, target, property); >+ } >+ }; >+ } >+} >Index: src/org/eclipse/core/internal/databinding/property/masterdetail/ValuePropertyDetailSet.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/property/masterdetail/ValuePropertyDetailSet.java >diff -N src/org/eclipse/core/internal/databinding/property/masterdetail/ValuePropertyDetailSet.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/property/masterdetail/ValuePropertyDetailSet.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,150 @@ >+/******************************************************************************* >+ * 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.masterdetail; >+ >+import java.util.Collection; >+import java.util.HashMap; >+import java.util.Map; >+import java.util.Set; >+ >+import org.eclipse.core.databinding.observable.Diffs; >+import org.eclipse.core.databinding.observable.set.SetDiff; >+import org.eclipse.core.databinding.property.ISetProperty; >+import org.eclipse.core.databinding.property.ISetPropertyChangeListener; >+import org.eclipse.core.databinding.property.IValueProperty; >+import org.eclipse.core.databinding.property.IValuePropertyChangeListener; >+import org.eclipse.core.databinding.property.SetProperty; >+import org.eclipse.core.databinding.property.SetPropertyChangeEvent; >+import org.eclipse.core.databinding.property.ValuePropertyChangeEvent; >+ >+/** >+ * @since 3.3 >+ * >+ */ >+public class ValuePropertyDetailSet extends SetProperty { >+ private final IValueProperty masterProperty; >+ private final ISetProperty detailProperty; >+ >+ private Map sourceToDetailListener = new HashMap(); >+ >+ private IValuePropertyChangeListener masterListener = new MasterPropertyListener(); >+ >+ private class MasterPropertyListener implements >+ IValuePropertyChangeListener { >+ public void handleValuePropertyChange(ValuePropertyChangeEvent event) { >+ Object oldSource = event.diff.getOldValue(); >+ Object newSource = event.diff.getNewValue(); >+ >+ Set oldSet = detailProperty.getSet(oldSource); >+ Set newSet = detailProperty.getSet(newSource); >+ SetDiff diff = Diffs.computeSetDiff(oldSet, newSet); >+ >+ Object source = event.getSource(); >+ >+ removeDetailPropertyListener(source); >+ addDetailPropertyListener(source); >+ >+ fireSetChange(source, diff); >+ } >+ } >+ >+ private class DetailPropertyListener implements ISetPropertyChangeListener { >+ private Object source; >+ private Object masterValue; >+ >+ DetailPropertyListener(Object source, Object masterValue) { >+ this.source = source; >+ this.masterValue = masterValue; >+ } >+ >+ public void handleSetPropertyChange(SetPropertyChangeEvent event) { >+ fireSetChange(source, event.diff); >+ } >+ } >+ >+ /** >+ * @param masterProperty >+ * @param detailProperty >+ */ >+ public ValuePropertyDetailSet(IValueProperty masterProperty, >+ ISetProperty detailProperty) { >+ this.masterProperty = masterProperty; >+ this.detailProperty = detailProperty; >+ } >+ >+ protected void addListenerTo(Object source) { >+ masterProperty.addValueChangeListener(source, masterListener); >+ addDetailPropertyListener(source); >+ } >+ >+ protected void removeListenerFrom(Object source) { >+ masterProperty.removeValueChangeListener(source, masterListener); >+ removeDetailPropertyListener(source); >+ } >+ >+ private void addDetailPropertyListener(Object source) { >+ Object masterValue = masterProperty.getValue(source); >+ DetailPropertyListener detailListener = new DetailPropertyListener( >+ source, masterValue); >+ detailProperty.addSetChangeListener(masterValue, detailListener); >+ sourceToDetailListener.put(source, detailListener); >+ } >+ >+ private void removeDetailPropertyListener(Object source) { >+ DetailPropertyListener detailListener = (DetailPropertyListener) sourceToDetailListener >+ .remove(source); >+ if (detailListener != null) { >+ detailProperty.removeSetChangeListener(detailListener.masterValue, >+ detailListener); >+ } >+ sourceToDetailListener.remove(source); >+ } >+ >+ public Set getSet(Object source) { >+ Object masterValue = masterProperty.getValue(source); >+ return detailProperty.getSet(masterValue); >+ } >+ >+ public boolean add(Object source, Object o) { >+ Object masterValue = masterProperty.getValue(source); >+ return detailProperty.add(masterValue, o); >+ } >+ >+ public boolean addAll(Object source, Collection c) { >+ Object masterValue = masterProperty.getValue(source); >+ return detailProperty.addAll(masterValue, c); >+ } >+ >+ public void clear(Object source) { >+ Object masterValue = masterProperty.getValue(source); >+ detailProperty.clear(masterValue); >+ } >+ >+ public Object getElementType() { >+ return detailProperty.getElementType(); >+ } >+ >+ public boolean remove(Object source, Object o) { >+ Object masterValue = masterProperty.getValue(source); >+ return detailProperty.remove(masterValue, o); >+ } >+ >+ public boolean removeAll(Object source, Collection c) { >+ Object masterValue = masterProperty.getValue(source); >+ return detailProperty.removeAll(masterValue, c); >+ } >+ >+ public boolean retainAll(Object source, Collection c) { >+ Object masterValue = masterProperty.getValue(source); >+ return detailProperty.retainAll(masterValue, c); >+ } >+} >Index: src/org/eclipse/core/internal/databinding/property/PropertyObservableList.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/property/PropertyObservableList.java >diff -N src/org/eclipse/core/internal/databinding/property/PropertyObservableList.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/property/PropertyObservableList.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,369 @@ >+/******************************************************************************* >+ * 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; >+ >+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.IObserving; >+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.property.IListProperty; >+import org.eclipse.core.databinding.property.IListPropertyChangeListener; >+import org.eclipse.core.databinding.property.ListPropertyChangeEvent; >+ >+/** >+ * @since 3.3 >+ * >+ */ >+public class PropertyObservableList extends AbstractObservableList implements >+ IObserving { >+ private Object source; >+ private IListProperty property; >+ >+ private volatile boolean updating = false; >+ >+ private boolean disposed = false; >+ >+ private transient volatile int modCount = 0; >+ >+ private IListPropertyChangeListener listener = new IListPropertyChangeListener() { >+ public void handleListPropertyChange(final ListPropertyChangeEvent event) { >+ if (!disposed && !updating) { >+ getRealm().exec(new Runnable() { >+ public void run() { >+ getRealm().exec(new Runnable() { >+ public void run() { >+ modCount++; >+ fireListChange(event.diff); >+ } >+ }); >+ } >+ }); >+ } >+ } >+ }; >+ >+ /** >+ * @param realm >+ * @param source >+ * @param property >+ */ >+ public PropertyObservableList(Realm realm, Object source, >+ IListProperty property) { >+ super(realm); >+ this.source = source; >+ this.property = property; >+ } >+ >+ protected void firstListenerAdded() { >+ if (!disposed) { >+ property.addListChangeListener(source, listener); >+ } >+ } >+ >+ protected void lastListenerRemoved() { >+ if (!disposed) { >+ property.removeListChangeListener(source, listener); >+ } >+ } >+ >+ private void getterCalled() { >+ ObservableTracker.getterCalled(this); >+ } >+ >+ public Object getElementType() { >+ return property.getElementType(); >+ } >+ >+ // Queries >+ >+ protected int doGetSize() { >+ return property.size(source); >+ } >+ >+ public boolean contains(Object o) { >+ getterCalled(); >+ return property.contains(source, o); >+ } >+ >+ public boolean containsAll(Collection c) { >+ getterCalled(); >+ return property.containsAll(source, c); >+ } >+ >+ public Object get(int index) { >+ getterCalled(); >+ return property.get(source, index); >+ } >+ >+ public int indexOf(Object o) { >+ getterCalled(); >+ return property.indexOf(source, o); >+ } >+ >+ public boolean isEmpty() { >+ getterCalled(); >+ return property.isEmpty(source); >+ } >+ >+ public int lastIndexOf(Object o) { >+ getterCalled(); >+ return property.lastIndexOf(source, o); >+ } >+ >+ public Object[] toArray() { >+ getterCalled(); >+ return property.toArray(source); >+ } >+ >+ public Object[] toArray(Object[] a) { >+ getterCalled(); >+ return property.toArray(source, a); >+ } >+ >+ // Single change operations >+ >+ public boolean add(Object o) { >+ checkRealm(); >+ return property.add(source, o); >+ } >+ >+ public Iterator iterator() { >+ getterCalled(); >+ return new Iterator() { >+ int lastReturned = -1; >+ int expectedModCount = modCount; >+ ListIterator delegate = new ArrayList(property.getList(source)) >+ .listIterator(); >+ >+ public boolean hasNext() { >+ getterCalled(); >+ checkForComodification(); >+ return delegate.hasNext(); >+ } >+ >+ public Object next() { >+ getterCalled(); >+ checkForComodification(); >+ Object next = delegate.next(); >+ lastReturned = delegate.previousIndex(); >+ return next; >+ } >+ >+ public void remove() { >+ checkRealm(); >+ checkForComodification(); >+ if (lastReturned == -1) >+ throw new IllegalStateException(); >+ >+ delegate.remove(); // stay in sync >+ >+ property.remove(source, lastReturned); >+ >+ lastReturned = -1; >+ expectedModCount = modCount; >+ } >+ >+ private void checkForComodification() { >+ if (expectedModCount != modCount) >+ throw new ConcurrentModificationException(); >+ } >+ }; >+ } >+ >+ public Object move(int oldIndex, int newIndex) { >+ getterCalled(); >+ return property.move(source, oldIndex, newIndex); >+ } >+ >+ public boolean remove(Object o) { >+ getterCalled(); >+ return property.remove(source, o); >+ } >+ >+ public void add(int index, Object o) { >+ getterCalled(); >+ property.add(source, index, o); >+ } >+ >+ public ListIterator listIterator() { >+ return listIterator(0); >+ } >+ >+ public ListIterator listIterator(final int index) { >+ getterCalled(); >+ return new ListIterator() { >+ int lastReturned = -1; >+ int expectedModCount = modCount; >+ ListIterator delegate = new ArrayList(property.getList(source)) >+ .listIterator(index); >+ >+ public boolean hasNext() { >+ getterCalled(); >+ checkForComodification(); >+ return delegate.hasNext(); >+ } >+ >+ public int nextIndex() { >+ getterCalled(); >+ checkForComodification(); >+ return delegate.nextIndex(); >+ } >+ >+ public Object next() { >+ getterCalled(); >+ checkForComodification(); >+ Object next = delegate.next(); >+ lastReturned = delegate.previousIndex(); >+ return next; >+ } >+ >+ public boolean hasPrevious() { >+ getterCalled(); >+ checkForComodification(); >+ return delegate.hasPrevious(); >+ } >+ >+ public int previousIndex() { >+ getterCalled(); >+ checkForComodification(); >+ return delegate.previousIndex(); >+ } >+ >+ public Object previous() { >+ getterCalled(); >+ checkForComodification(); >+ Object previous = delegate.previous(); >+ lastReturned = delegate.nextIndex(); >+ return previous; >+ } >+ >+ public void add(Object o) { >+ checkRealm(); >+ checkForComodification(); >+ int index = delegate.nextIndex(); >+ >+ delegate.add(o); // keep in sync >+ >+ property.add(source, index, o); >+ >+ lastReturned = -1; >+ expectedModCount = modCount; >+ } >+ >+ public void set(Object o) { >+ checkRealm(); >+ checkForComodification(); >+ >+ delegate.set(o); >+ >+ property.set(source, lastReturned, o); >+ >+ expectedModCount = modCount; >+ } >+ >+ public void remove() { >+ checkRealm(); >+ checkForComodification(); >+ if (lastReturned == -1) >+ throw new IllegalStateException(); >+ >+ delegate.remove(); // keep in sync >+ >+ property.remove(source, lastReturned); >+ >+ lastReturned = -1; >+ expectedModCount = modCount; >+ } >+ >+ private void checkForComodification() { >+ if (expectedModCount != modCount) >+ throw new ConcurrentModificationException(); >+ } >+ >+ }; >+ } >+ >+ public Object remove(int index) { >+ getterCalled(); >+ return property.remove(source, index); >+ } >+ >+ public Object set(int index, Object o) { >+ getterCalled(); >+ return property.set(source, index, o); >+ } >+ >+ public List subList(int fromIndex, int toIndex) { >+ getterCalled(); >+ return Collections.unmodifiableList(property.getList(source).subList( >+ fromIndex, toIndex)); >+ } >+ >+ // Bulk change operations >+ >+ public boolean addAll(Collection c) { >+ getterCalled(); >+ return property.addAll(source, c); >+ } >+ >+ public boolean addAll(int index, Collection c) { >+ getterCalled(); >+ return property.addAll(source, index, c); >+ } >+ >+ public boolean removeAll(Collection c) { >+ getterCalled(); >+ return property.removeAll(source, c); >+ } >+ >+ public boolean retainAll(Collection c) { >+ getterCalled(); >+ return property.retainAll(source, c); >+ } >+ >+ public void clear() { >+ getterCalled(); >+ property.clear(source); >+ } >+ >+ public boolean equals(Object o) { >+ getterCalled(); >+ return property.equals(source, o); >+ } >+ >+ public int hashCode() { >+ getterCalled(); >+ return property.hashCode(source); >+ } >+ >+ public Object getObserved() { >+ return source; >+ } >+ >+ public synchronized void dispose() { >+ if (!disposed) { >+ disposed = true; >+ property.removeListChangeListener(source, listener); >+ property = null; >+ source = null; >+ } >+ super.dispose(); >+ } >+} >Index: src/org/eclipse/core/internal/databinding/property/PropertyObservableSet.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/property/PropertyObservableSet.java >diff -N src/org/eclipse/core/internal/databinding/property/PropertyObservableSet.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/property/PropertyObservableSet.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,192 @@ >+/******************************************************************************* >+ * 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; >+ >+import java.util.Collection; >+import java.util.ConcurrentModificationException; >+import java.util.HashSet; >+import java.util.Iterator; >+import java.util.Set; >+ >+import org.eclipse.core.databinding.observable.IObserving; >+import org.eclipse.core.databinding.observable.Realm; >+import org.eclipse.core.databinding.observable.set.AbstractObservableSet; >+import org.eclipse.core.databinding.property.ISetProperty; >+import org.eclipse.core.databinding.property.ISetPropertyChangeListener; >+import org.eclipse.core.databinding.property.SetPropertyChangeEvent; >+ >+/** >+ * @since 3.3 >+ * >+ */ >+public class PropertyObservableSet extends AbstractObservableSet implements >+ IObserving { >+ private Object source; >+ private ISetProperty property; >+ >+ private boolean updating = false; >+ >+ private boolean disposed = false; >+ >+ private transient volatile int modCount = 0; >+ >+ private ISetPropertyChangeListener listener = new ISetPropertyChangeListener() { >+ public void handleSetPropertyChange(final SetPropertyChangeEvent event) { >+ if (!disposed && !updating) { >+ getRealm().exec(new Runnable() { >+ public void run() { >+ getRealm().exec(new Runnable() { >+ public void run() { >+ modCount++; >+ fireSetChange(event.diff); >+ } >+ }); >+ } >+ }); >+ } >+ } >+ }; >+ >+ /** >+ * @param realm >+ * @param source >+ * @param property >+ */ >+ public PropertyObservableSet(Realm realm, Object source, >+ ISetProperty property) { >+ super(realm); >+ this.source = source; >+ this.property = property; >+ } >+ >+ protected void firstListenerAdded() { >+ if (!disposed) { >+ property.addSetChangeListener(source, listener); >+ } >+ } >+ >+ protected void lastListenerRemoved() { >+ if (!disposed) { >+ property.removeSetChangeListener(source, listener); >+ } >+ } >+ >+ protected Set getWrappedSet() { >+ return property.getSet(source); >+ } >+ >+ public Object getElementType() { >+ return property.getElementType(); >+ } >+ >+ // Queries >+ >+ protected int doGetSize() { >+ return property.size(source); >+ } >+ >+ // Single change operations >+ >+ public boolean add(Object o) { >+ checkRealm(); >+ return property.add(source, o); >+ } >+ >+ public Iterator iterator() { >+ getterCalled(); >+ return new Iterator() { >+ int expectedModCount = modCount; >+ Iterator delegate = new HashSet(property.getSet(source)).iterator(); >+ Object last = null; >+ >+ public boolean hasNext() { >+ getterCalled(); >+ checkForComodification(); >+ return delegate.hasNext(); >+ } >+ >+ public Object next() { >+ getterCalled(); >+ checkForComodification(); >+ Object next = delegate.next(); >+ last = next; >+ return next; >+ } >+ >+ public void remove() { >+ checkRealm(); >+ checkForComodification(); >+ >+ delegate.remove(); // stay in sync >+ >+ property.remove(source, last); >+ >+ last = null; >+ expectedModCount = modCount; >+ } >+ >+ private void checkForComodification() { >+ if (expectedModCount != modCount) >+ throw new ConcurrentModificationException(); >+ } >+ }; >+ } >+ >+ public boolean remove(Object o) { >+ getterCalled(); >+ return property.remove(source, o); >+ } >+ >+ // Bulk change operations >+ >+ public boolean addAll(Collection c) { >+ getterCalled(); >+ return property.addAll(source, c); >+ } >+ >+ public boolean removeAll(Collection c) { >+ getterCalled(); >+ return property.removeAll(source, c); >+ } >+ >+ public boolean retainAll(Collection c) { >+ getterCalled(); >+ return property.retainAll(source, c); >+ } >+ >+ public void clear() { >+ getterCalled(); >+ property.clear(source); >+ } >+ >+ public boolean equals(Object o) { >+ return property.equals(source, o); >+ } >+ >+ public int hashCode() { >+ return property.hashCode(source); >+ } >+ >+ public Object getObserved() { >+ return source; >+ } >+ >+ public synchronized void dispose() { >+ if (!disposed) { >+ disposed = true; >+ property.removeSetChangeListener(source, listener); >+ property = null; >+ source = null; >+ } >+ super.dispose(); >+ } >+} >Index: src/org/eclipse/core/databinding/property/IPropertyChangeListener.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/IPropertyChangeListener.java >diff -N src/org/eclipse/core/databinding/property/IPropertyChangeListener.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/IPropertyChangeListener.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,23 @@ >+/******************************************************************************* >+ * 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; >+ >+/** >+ * Marker interface for all listener types in the properties framework. >+ * >+ * @noimplement This interface is not intended to be implemented by clients. >+ * >+ * @since 1.2 >+ */ >+public interface IPropertyChangeListener { >+ >+} >Index: src/org/eclipse/core/databinding/property/CollectionProperty.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/CollectionProperty.java >diff -N src/org/eclipse/core/databinding/property/CollectionProperty.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/CollectionProperty.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,55 @@ >+/******************************************************************************* >+ * 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; >+ >+import java.util.Collection; >+ >+/** >+ * @since 1.2 >+ * >+ */ >+public abstract class CollectionProperty extends Property implements >+ ICollectionProperty { >+ abstract Collection getCollection(Object source); >+ >+ public boolean contains(Object source, Object o) { >+ return getCollection(source).contains(o); >+ } >+ >+ public boolean containsAll(Object source, Collection c) { >+ return getCollection(source).containsAll(c); >+ } >+ >+ public boolean equals(Object source, Object o) { >+ return getCollection(source).equals(o); >+ } >+ >+ public int hashCode(Object source) { >+ return getCollection(source).hashCode(); >+ } >+ >+ public boolean isEmpty(Object source) { >+ return getCollection(source).isEmpty(); >+ } >+ >+ public int size(Object source) { >+ return getCollection(source).size(); >+ } >+ >+ public Object[] toArray(Object source, Object[] array) { >+ return getCollection(source).toArray(array); >+ } >+ >+ public Object[] toArray(Object source) { >+ return getCollection(source).toArray(); >+ } >+} >Index: src/org/eclipse/core/internal/databinding/property/SetValuePropertyObservableMap.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/property/SetValuePropertyObservableMap.java >diff -N src/org/eclipse/core/internal/databinding/property/SetValuePropertyObservableMap.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/property/SetValuePropertyObservableMap.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,92 @@ >+/******************************************************************************* >+ * 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; >+ >+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.IValueProperty; >+import org.eclipse.core.databinding.property.IValuePropertyChangeListener; >+import org.eclipse.core.databinding.property.ValuePropertyChangeEvent; >+ >+/** >+ * @since 3.3 >+ * >+ */ >+public class SetValuePropertyObservableMap extends ComputedObservableMap >+ implements IObserving { >+ private IValueProperty property; >+ >+ private boolean disposed = false; >+ >+ private IValuePropertyChangeListener listener = new IValuePropertyChangeListener() { >+ public void handleValuePropertyChange( >+ final ValuePropertyChangeEvent event) { >+ if (!disposed) { >+ getRealm().exec(new Runnable() { >+ public void run() { >+ Object key = event.getSource(); >+ Object oldValue = event.diff.getOldValue(); >+ Object newValue = event.diff.getNewValue(); >+ fireMapChange(Diffs.createMapDiffSingleChange(key, >+ oldValue, newValue)); >+ } >+ }); >+ } >+ } >+ }; >+ >+ /** >+ * @param keySet >+ * @param valueProperty >+ */ >+ public SetValuePropertyObservableMap(IObservableSet keySet, >+ IValueProperty valueProperty) { >+ super(keySet); >+ this.property = valueProperty; >+ } >+ >+ protected Object doGet(Object key) { >+ return property.getValue(key); >+ } >+ >+ protected Object doPut(Object key, Object value) { >+ Object result = property.getValue(key); >+ property.setValue(key, value); >+ return result; >+ } >+ >+ protected void hookListener(Object addedKey) { >+ if (!disposed) >+ property.addValueChangeListener(addedKey, listener); >+ } >+ >+ protected void unhookListener(Object removedKey) { >+ if (!disposed) >+ property.removeValueChangeListener(removedKey, listener); >+ } >+ >+ public Object getObserved() { >+ return keySet(); >+ } >+ >+ public synchronized void dispose() { >+ super.dispose(); >+ >+ if (!disposed) { >+ disposed = true; >+ property = null; >+ listener = null; >+ } >+ } >+} >Index: src/org/eclipse/core/internal/databinding/property/PropertyObservableValue.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/property/PropertyObservableValue.java >diff -N src/org/eclipse/core/internal/databinding/property/PropertyObservableValue.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/property/PropertyObservableValue.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,110 @@ >+/******************************************************************************* >+ * 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; >+ >+import org.eclipse.core.databinding.observable.Diffs; >+import org.eclipse.core.databinding.observable.IObserving; >+import org.eclipse.core.databinding.observable.Realm; >+import org.eclipse.core.databinding.observable.value.AbstractObservableValue; >+import org.eclipse.core.databinding.property.IValueProperty; >+import org.eclipse.core.databinding.property.IValuePropertyChangeListener; >+import org.eclipse.core.databinding.property.ValuePropertyChangeEvent; >+import org.eclipse.core.internal.databinding.Util; >+ >+/** >+ * @since 1.2 >+ * >+ */ >+public class PropertyObservableValue extends AbstractObservableValue implements >+ IObserving { >+ private Object source; >+ private IValueProperty property; >+ >+ private boolean updating = false; >+ >+ private boolean disposed = false; >+ >+ private IValuePropertyChangeListener listener = new IValuePropertyChangeListener() { >+ public void handleValuePropertyChange( >+ final ValuePropertyChangeEvent event) { >+ if (!disposed && !updating) { >+ getRealm().exec(new Runnable() { >+ public void run() { >+ fireValueChange(event.diff); >+ } >+ }); >+ } >+ } >+ }; >+ >+ /** >+ * @param realm >+ * @param source >+ * @param property >+ */ >+ public PropertyObservableValue(Realm realm, Object source, >+ IValueProperty property) { >+ super(realm); >+ this.source = source; >+ this.property = property; >+ } >+ >+ protected void firstListenerAdded() { >+ if (!disposed) { >+ property.addValueChangeListener(source, listener); >+ } >+ } >+ >+ protected void lastListenerRemoved() { >+ if (!disposed) { >+ property.removeValueChangeListener(source, listener); >+ } >+ } >+ >+ protected Object doGetValue() { >+ return property.getValue(source); >+ } >+ >+ protected void doSetValue(Object value) { >+ Object oldValue = doGetValue(); >+ >+ updating = true; >+ try { >+ property.setValue(source, value); >+ } finally { >+ updating = false; >+ } >+ >+ Object newValue = doGetValue(); >+ if (!Util.equals(oldValue, newValue)) { >+ fireValueChange(Diffs.createValueDiff(oldValue, newValue)); >+ } >+ } >+ >+ public Object getValueType() { >+ return property.getValueType(); >+ } >+ >+ public Object getObserved() { >+ return source; >+ } >+ >+ public synchronized void dispose() { >+ if (!disposed) { >+ disposed = true; >+ property.removeValueChangeListener(source, listener); >+ property = null; >+ source = null; >+ } >+ super.dispose(); >+ } >+} >Index: src/org/eclipse/core/databinding/property/IListPropertyChangeListener.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/IListPropertyChangeListener.java >diff -N src/org/eclipse/core/databinding/property/IListPropertyChangeListener.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/IListPropertyChangeListener.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,22 @@ >+/******************************************************************************* >+ * 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; >+ >+/** >+ * @since 1.2 >+ */ >+public interface IListPropertyChangeListener extends IPropertyChangeListener { >+ /** >+ * @param event >+ */ >+ public void handleListPropertyChange(ListPropertyChangeEvent event); >+} >Index: src/org/eclipse/core/databinding/property/Property.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/Property.java >diff -N src/org/eclipse/core/databinding/property/Property.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/Property.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,69 @@ >+/******************************************************************************* >+ * 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; >+ >+/** >+ * @since 1.2 >+ * >+ */ >+public abstract class Property implements IProperty { >+ private PropertyChangeSupport changeSupport; >+ >+ synchronized PropertyChangeSupport getChangeSupport() { >+ if (changeSupport == null) >+ changeSupport = new PropertyChangeSupport(this); >+ return changeSupport; >+ } >+ >+ /** >+ * Notifies the property that the first listener has been added for the >+ * given source object. Implementers should register a listener on the >+ * source object which fires an appropriate change event when a property >+ * change is observed on the source. >+ * >+ * @param source >+ * the source object to observe for property changes. >+ * @see #removeListenerFrom(Object) >+ */ >+ protected abstract void addListenerTo(Object source); >+ >+ /** >+ * Notifies the property that the last listener has been removed for the >+ * given source object. Implementers should unregister any previously >+ * registered listeners from the source. >+ * >+ * @param source >+ * the source object to stop observing for property changes. >+ * @see #addListenerTo(Object) >+ */ >+ protected abstract void removeListenerFrom(Object source); >+ >+ /** >+ * Returns whether this property has listeners registered for the given >+ * property source >+ * >+ * @param source >+ * the property source >+ * @return whether this property has listeners registered for the given >+ * property source >+ */ >+ protected boolean hasListeners(Object source) { >+ return changeSupport != null && changeSupport.hasListeners(source); >+ } >+ >+ public synchronized void dispose() { >+ if (changeSupport != null) { >+ changeSupport.dispose(); >+ changeSupport = null; >+ } >+ } >+} >#P org.eclipse.core.databinding.beans >Index: src/org/eclipse/core/internal/databinding/beans/BeanObservableSetDecorator.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.databinding.beans/src/org/eclipse/core/internal/databinding/beans/BeanObservableSetDecorator.java,v >retrieving revision 1.1 >diff -u -r1.1 BeanObservableSetDecorator.java >--- src/org/eclipse/core/internal/databinding/beans/BeanObservableSetDecorator.java 20 Mar 2008 21:16:42 -0000 1.1 >+++ src/org/eclipse/core/internal/databinding/beans/BeanObservableSetDecorator.java 4 Sep 2008 20:45:19 -0000 >@@ -7,6 +7,7 @@ > * > * Contributors: > * Brad Reynolds - initial API and implementation >+ * Matthew Hall - bug 194734 > ******************************************************************************/ > > package org.eclipse.core.internal.databinding.beans; >@@ -17,7 +18,9 @@ > > import org.eclipse.core.databinding.beans.IBeanObservable; > import org.eclipse.core.databinding.observable.IChangeListener; >+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.Realm; > import org.eclipse.core.databinding.observable.set.IObservableSet; > import org.eclipse.core.databinding.observable.set.ISetChangeListener; >@@ -30,28 +33,30 @@ > */ > public class BeanObservableSetDecorator implements IObservableSet, IBeanObservable { > private IObservableSet delegate; >- private Object observed; > private PropertyDescriptor propertyDescriptor; > > /** > * @param delegate >- * @param observed > * @param propertyDescriptor > */ > public BeanObservableSetDecorator(IObservableSet delegate, >- Object observed, > PropertyDescriptor propertyDescriptor) { > > this.delegate = delegate; >- this.observed = observed; > this.propertyDescriptor = propertyDescriptor; > } > > public boolean add(Object o) { >+ getterCalled(); > return delegate.add(o); > } > >+ private void getterCalled() { >+ ObservableTracker.getterCalled(this); >+ } >+ > public boolean addAll(Collection c) { >+ getterCalled(); > return delegate.addAll(c); > } > >@@ -68,14 +73,17 @@ > } > > public void clear() { >+ getterCalled(); > delegate.clear(); > } > > public boolean contains(Object o) { >+ getterCalled(); > return delegate.contains(o); > } > > public boolean containsAll(Collection c) { >+ getterCalled(); > return delegate.containsAll(c); > } > >@@ -84,6 +92,7 @@ > } > > public boolean equals(Object obj) { >+ getterCalled(); > if (obj instanceof BeanObservableSetDecorator) { > BeanObservableSetDecorator other = (BeanObservableSetDecorator) obj; > return Util.equals(other.delegate, delegate); >@@ -100,26 +109,32 @@ > } > > public int hashCode() { >+ getterCalled(); > return delegate.hashCode(); > } > > public boolean isEmpty() { >+ getterCalled(); > return delegate.isEmpty(); > } > > public boolean isStale() { >+ getterCalled(); > return delegate.isStale(); > } > > public Iterator iterator() { >+ getterCalled(); > return delegate.iterator(); > } > > public boolean remove(Object o) { >+ getterCalled(); > return delegate.remove(o); > } > > public boolean removeAll(Collection c) { >+ getterCalled(); > return delegate.removeAll(c); > } > >@@ -136,31 +151,31 @@ > } > > public boolean retainAll(Collection c) { >+ getterCalled(); > return delegate.retainAll(c); > } > > public int size() { >+ getterCalled(); > return delegate.size(); > } > > public Object[] toArray() { >+ getterCalled(); > return delegate.toArray(); > } > > public Object[] toArray(Object[] a) { >+ getterCalled(); > return delegate.toArray(a); > } > >- /* (non-Javadoc) >- * @see org.eclipse.core.databinding.beans.IBeanObservable#getObserved() >- */ > public Object getObserved() { >- return observed; >+ if (delegate instanceof IObserving) >+ return ((IObserving) delegate).getObserved(); >+ return null; > } > >- /* (non-Javadoc) >- * @see org.eclipse.core.databinding.beans.IBeanObservable#getPropertyDescriptor() >- */ > public PropertyDescriptor getPropertyDescriptor() { > return propertyDescriptor; > } >Index: src/org/eclipse/core/internal/databinding/beans/JavaBeanObservableMap.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/beans/JavaBeanObservableMap.java >diff -N src/org/eclipse/core/internal/databinding/beans/JavaBeanObservableMap.java >--- src/org/eclipse/core/internal/databinding/beans/JavaBeanObservableMap.java 21 Jul 2008 22:09:24 -0000 1.4 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,142 +0,0 @@ >-/******************************************************************************* >- * Copyright (c) 2006, 2008 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 >- * Brad Reynolds - bug 171616 >- * Matthew hall - bugs 223164, 241585 >- *******************************************************************************/ >- >-package org.eclipse.core.internal.databinding.beans; >- >-import java.beans.PropertyChangeListener; >-import java.beans.PropertyDescriptor; >-import java.lang.reflect.Method; >- >-import org.eclipse.core.databinding.beans.IBeanObservable; >-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.util.Policy; >-import org.eclipse.core.runtime.IStatus; >-import org.eclipse.core.runtime.Status; >- >-/** >- * @since 1.0 >- * >- */ >-public class JavaBeanObservableMap extends ComputedObservableMap implements >- IBeanObservable { >- >- private PropertyDescriptor propertyDescriptor; >- >- private PropertyChangeListener elementListener = new PropertyChangeListener() { >- public void propertyChange(final java.beans.PropertyChangeEvent event) { >- if (!updating) { >- getRealm().exec(new Runnable() { >- public void run() { >- fireMapChange(Diffs.createMapDiffSingleChange( >- event.getSource(), event.getOldValue(), event >- .getNewValue())); >- } >- }); >- } >- } >- }; >- >- private ListenerSupport listenerSupport; >- >- private boolean updating = false; >- >- private boolean attachListeners; >- >- /** >- * @param domain >- * @param propertyDescriptor >- */ >- public JavaBeanObservableMap(IObservableSet domain, >- PropertyDescriptor propertyDescriptor) { >- this(domain, propertyDescriptor, true); >- } >- >- /** >- * @param domain >- * @param propertyDescriptor >- * @param attachListeners >- */ >- public JavaBeanObservableMap(IObservableSet domain, >- PropertyDescriptor propertyDescriptor, boolean attachListeners) { >- super(domain); >- >- this.propertyDescriptor = propertyDescriptor; >- this.attachListeners = attachListeners; >- if (attachListeners) { >- this.listenerSupport = new ListenerSupport(elementListener, >- propertyDescriptor.getName()); >- } >- init(); >- } >- >- protected void hookListener(Object domainElement) { >- if (attachListeners && domainElement != null) { >- listenerSupport.hookListener(domainElement); >- } >- } >- >- protected void unhookListener(Object domainElement) { >- if (attachListeners && domainElement != null) { >- listenerSupport.unhookListener(domainElement); >- } >- } >- >- protected Object doGet(Object key) { >- if (key == null) { >- return null; >- } >- try { >- Method readMethod = propertyDescriptor.getReadMethod(); >- if (!readMethod.isAccessible()) { >- readMethod.setAccessible(true); >- } >- return readMethod.invoke(key, new Object[0]); >- } catch (Exception e) { >- Policy.getLog().log( >- new Status(IStatus.ERROR, Policy.JFACE_DATABINDING, >- IStatus.ERROR, "cannot get value", e)); //$NON-NLS-1$ >- throw new RuntimeException(e); >- } >- } >- >- protected Object doPut(Object key, Object value) { >- try { >- Object oldValue = get(key); >- propertyDescriptor.getWriteMethod().invoke(key, >- new Object[] { value }); >- keySet().add(key); >- return oldValue; >- } catch (Exception e) { >- Policy.getLog().log( >- new Status(IStatus.ERROR, Policy.JFACE_DATABINDING, >- IStatus.ERROR, "cannot set value", e)); //$NON-NLS-1$ >- throw new RuntimeException(e); >- } >- } >- >- /* (non-Javadoc) >- * @see org.eclipse.core.databinding.beans.IBeanObservable#getObserved() >- */ >- public Object getObserved() { >- return keySet(); >- } >- >- /* (non-Javadoc) >- * @see org.eclipse.core.databinding.beans.IBeanObservable#getPropertyDescriptor() >- */ >- public PropertyDescriptor getPropertyDescriptor() { >- return propertyDescriptor; >- } >-} >Index: src/org/eclipse/core/internal/databinding/beans/JavaBeanObservableList.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/beans/JavaBeanObservableList.java >diff -N src/org/eclipse/core/internal/databinding/beans/JavaBeanObservableList.java >--- src/org/eclipse/core/internal/databinding/beans/JavaBeanObservableList.java 31 Jul 2008 18:37:44 -0000 1.2 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,410 +0,0 @@ >-/******************************************************************************* >- * Copyright (c) 2006-2008 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 >- * Brad Reynolds - bug 171616 >- * Matthew Hall - bugs 208858, 221351, 213145, 223164 >- * Mike Evans - bug 217558 >- *******************************************************************************/ >- >-package org.eclipse.core.internal.databinding.beans; >- >-import java.beans.PropertyChangeListener; >-import java.beans.PropertyDescriptor; >-import java.lang.reflect.Array; >-import java.lang.reflect.InvocationTargetException; >-import java.lang.reflect.Method; >-import java.util.ArrayList; >-import java.util.Arrays; >-import java.util.Collection; >-import java.util.Iterator; >-import java.util.List; >- >-import org.eclipse.core.databinding.BindingException; >-import org.eclipse.core.databinding.beans.IBeanObservable; >-import org.eclipse.core.databinding.observable.Diffs; >-import org.eclipse.core.databinding.observable.Realm; >-import org.eclipse.core.databinding.observable.list.ListDiffEntry; >-import org.eclipse.core.databinding.observable.list.ObservableList; >- >-/** >- * @since 1.0 >- * >- */ >-public class JavaBeanObservableList extends ObservableList implements >- IBeanObservable { >- >- private final Object object; >- >- private PropertyChangeListener collectionListener = new PropertyChangeListener() { >- public void propertyChange(java.beans.PropertyChangeEvent event) { >- if (!updating) { >- getRealm().exec(new Runnable() { >- public void run() { >- updateWrappedList( new ArrayList( Arrays.asList(getValues() ) ) ); >- } >- }); >- } >- } >- }; >- >- private boolean updating = false; >- >- private PropertyDescriptor descriptor; >- >- private ListenerSupport collectionListenSupport; >- >- private boolean attachListeners; >- >- /** >- * @param realm >- * @param object >- * @param descriptor >- * @param elementType >- */ >- public JavaBeanObservableList(Realm realm, Object object, >- PropertyDescriptor descriptor, Class elementType) { >- this(realm, object, descriptor, elementType, true); >- } >- >- /** >- * @param realm >- * @param object >- * @param descriptor >- * @param elementType >- * @param attachListeners >- */ >- public JavaBeanObservableList(Realm realm, Object object, >- PropertyDescriptor descriptor, Class elementType, >- boolean attachListeners) { >- >- super(realm, new ArrayList(), elementType); >- this.object = object; >- this.descriptor = descriptor; >- this.attachListeners = attachListeners; >- >- if (attachListeners) { >- this.collectionListenSupport = new ListenerSupport( >- collectionListener, descriptor.getName()); >- } >- >- // initialize list without firing events >- wrappedList.addAll(Arrays.asList(getValues())); >- } >- >- protected void firstListenerAdded() { >- if (attachListeners) { >- collectionListenSupport.hookListener(this.object); >- } >- } >- >- protected void lastListenerRemoved() { >- if (collectionListenSupport != null) { >- collectionListenSupport.dispose(); >- } >- } >- >- public void dispose() { >- super.dispose(); >- lastListenerRemoved(); >- } >- >- private Object primGetValues() { >- Exception ex = null; >- try { >- Method readMethod = descriptor.getReadMethod(); >- if (!readMethod.isAccessible()) { >- readMethod.setAccessible(true); >- } >- return readMethod.invoke(object, new Object[0]); >- } catch (IllegalArgumentException e) { >- ex = e; >- } catch (IllegalAccessException e) { >- ex = e; >- } catch (InvocationTargetException e) { >- ex = e; >- } >- throw new BindingException("Could not read collection values", ex); //$NON-NLS-1$ >- } >- >- private Object[] getValues() { >- Object[] values = null; >- >- Object result = primGetValues(); >- if (descriptor.getPropertyType().isArray()) >- values = (Object[]) result; >- else { >- // TODO add jUnit for POJO (var. SettableValue) collections >- Collection list = (Collection) result; >- if (list != null) { >- values = list.toArray(); >- } >- } >- if (values == null) >- values = new Object[0]; >- return values; >- } >- >- public Object getObserved() { >- return object; >- } >- >- public PropertyDescriptor getPropertyDescriptor() { >- return descriptor; >- } >- >- private void setValues() { >- if (descriptor.getPropertyType().isArray()) { >- Class componentType = descriptor.getPropertyType() >- .getComponentType(); >- Object[] newArray = (Object[]) Array.newInstance(componentType, >- wrappedList.size()); >- wrappedList.toArray(newArray); >- primSetValues(newArray); >- } else { >- // assume that it is a java.util.List >- primSetValues(new ArrayList(wrappedList)); >- } >- } >- >- private void primSetValues(Object newValue) { >- Exception ex = null; >- try { >- Method writeMethod = descriptor.getWriteMethod(); >- if (!writeMethod.isAccessible()) { >- writeMethod.setAccessible(true); >- } >- writeMethod.invoke(object, new Object[] { newValue }); >- return; >- } catch (IllegalArgumentException e) { >- ex = e; >- } catch (IllegalAccessException e) { >- ex = e; >- } catch (InvocationTargetException e) { >- ex = e; >- } >- throw new BindingException("Could not write collection values", ex); //$NON-NLS-1$ >- } >- >- public Object set(int index, Object element) { >- getterCalled(); >- updating = true; >- try { >- Object oldElement = wrappedList.set(index, element); >- setValues(); >- fireListChange(Diffs.createListDiff(Diffs.createListDiffEntry( >- index, false, oldElement), Diffs.createListDiffEntry(index, >- true, element))); >- return oldElement; >- } finally { >- updating = false; >- } >- } >- >- public Object move(int oldIndex, int newIndex) { >- getterCalled(); >- updating = true; >- try { >- int size = wrappedList.size(); >- if (oldIndex < 0 || oldIndex >= size) >- throw new IndexOutOfBoundsException( >- "oldIndex: " + oldIndex + ", size:" + size); //$NON-NLS-1$ //$NON-NLS-2$ >- if (newIndex < 0 || newIndex >= size) >- throw new IndexOutOfBoundsException( >- "newIndex: " + newIndex + ", size:" + size); //$NON-NLS-1$ //$NON-NLS-2$ >- if (oldIndex == newIndex) >- return wrappedList.get(oldIndex); >- Object element = wrappedList.remove(oldIndex); >- wrappedList.add(newIndex, element); >- setValues(); >- fireListChange(Diffs.createListDiff(Diffs.createListDiffEntry( >- oldIndex, false, element), Diffs.createListDiffEntry( >- newIndex, true, element))); >- return element; >- } finally { >- updating = false; >- } >- } >- >- public Object remove(int index) { >- getterCalled(); >- updating = true; >- try { >- Object oldElement = wrappedList.remove(index); >- setValues(); >- fireListChange(Diffs.createListDiff(Diffs.createListDiffEntry( >- index, false, oldElement))); >- return oldElement; >- } finally { >- updating = false; >- } >- } >- >- public boolean add(Object element) { >- updating = true; >- try { >- int index = wrappedList.size(); >- boolean result = wrappedList.add(element); >- setValues(); >- fireListChange(Diffs.createListDiff(Diffs.createListDiffEntry( >- index, true, element))); >- return result; >- } finally { >- updating = false; >- } >- } >- >- public void add(int index, Object element) { >- updating = true; >- try { >- wrappedList.add(index, element); >- setValues(); >- fireListChange(Diffs.createListDiff(Diffs.createListDiffEntry( >- index, true, element))); >- } finally { >- updating = false; >- } >- } >- >- public boolean addAll(Collection c) { >- if (c.isEmpty()) { >- return false; >- } >- updating = true; >- try { >- int index = wrappedList.size(); >- boolean result = wrappedList.addAll(c); >- setValues(); >- ListDiffEntry[] entries = new ListDiffEntry[c.size()]; >- int i = 0; >- for (Iterator it = c.iterator(); it.hasNext();) { >- Object o = it.next(); >- entries[i++] = Diffs.createListDiffEntry(index++, true, o); >- } >- fireListChange(Diffs.createListDiff(entries)); >- return result; >- } finally { >- updating = false; >- } >- } >- >- public boolean addAll(int index, Collection c) { >- if (c.isEmpty()) { >- return false; >- } >- updating = true; >- try { >- boolean result = wrappedList.addAll(index, c); >- setValues(); >- ListDiffEntry[] entries = new ListDiffEntry[c.size()]; >- int i = 0; >- for (Iterator it = c.iterator(); it.hasNext();) { >- Object o = it.next(); >- entries[i++] = Diffs.createListDiffEntry(index++, true, o); >- } >- fireListChange(Diffs.createListDiff(entries)); >- return result; >- } finally { >- updating = false; >- } >- } >- >- public boolean remove(Object o) { >- getterCalled(); >- int index = wrappedList.indexOf(o); >- if (index == -1) { >- return false; >- } >- updating = true; >- try { >- Object oldElement = wrappedList.remove(index); >- setValues(); >- fireListChange(Diffs.createListDiff(Diffs.createListDiffEntry( >- index, false, oldElement))); >- return true; >- } finally { >- updating = false; >- } >- } >- >- public boolean removeAll(Collection c) { >- getterCalled(); >- boolean changed = false; >- updating = true; >- try { >- List diffEntries = new ArrayList(); >- for (Iterator it = c.iterator(); it.hasNext();) { >- Object o = it.next(); >- int index = wrappedList.indexOf(o); >- if (index != -1) { >- changed = true; >- Object oldElement = wrappedList.remove(index); >- diffEntries.add(Diffs.createListDiffEntry(index, false, >- oldElement)); >- } >- } >- if (changed) { >- setValues(); >- fireListChange(Diffs >- .createListDiff((ListDiffEntry[]) diffEntries >- .toArray(new ListDiffEntry[diffEntries.size()]))); >- } >- return changed; >- } finally { >- updating = false; >- } >- } >- >- public boolean retainAll(Collection c) { >- getterCalled(); >- boolean changed = false; >- updating = true; >- try { >- List diffEntries = new ArrayList(); >- int index = 0; >- for (Iterator it = wrappedList.iterator(); it.hasNext();) { >- Object o = it.next(); >- boolean retain = c.contains(o); >- if (retain) { >- index++; >- } else { >- changed = true; >- it.remove(); >- diffEntries.add(Diffs.createListDiffEntry(index, false, o)); >- } >- } >- if (changed) { >- setValues(); >- fireListChange(Diffs >- .createListDiff((ListDiffEntry[]) diffEntries >- .toArray(new ListDiffEntry[diffEntries.size()]))); >- } >- return changed; >- } finally { >- updating = false; >- } >- } >- >- public void clear() { >- updating = true; >- try { >- List diffEntries = new ArrayList(); >- for (Iterator it = wrappedList.iterator(); it.hasNext();) { >- Object o = it.next(); >- diffEntries.add(Diffs.createListDiffEntry(0, false, o)); >- } >- wrappedList.clear(); >- setValues(); >- fireListChange(Diffs.createListDiff((ListDiffEntry[]) diffEntries >- .toArray(new ListDiffEntry[diffEntries.size()]))); >- } finally { >- updating = false; >- } >- } >- >-} >Index: src/org/eclipse/core/internal/databinding/beans/JavaBeanPropertyObservableMap.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/beans/JavaBeanPropertyObservableMap.java >diff -N src/org/eclipse/core/internal/databinding/beans/JavaBeanPropertyObservableMap.java >--- src/org/eclipse/core/internal/databinding/beans/JavaBeanPropertyObservableMap.java 20 Mar 2008 21:16:42 -0000 1.1 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,241 +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 221704) >- * Matthew Hall - bug 223164 >- *******************************************************************************/ >- >-package org.eclipse.core.internal.databinding.beans; >- >-import java.beans.PropertyChangeEvent; >-import java.beans.PropertyChangeListener; >-import java.beans.PropertyDescriptor; >-import java.lang.reflect.InvocationTargetException; >-import java.lang.reflect.Method; >-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.BindingException; >-import org.eclipse.core.databinding.beans.IBeanObservable; >-import org.eclipse.core.databinding.observable.Diffs; >-import org.eclipse.core.databinding.observable.Realm; >-import org.eclipse.core.databinding.observable.map.ObservableMap; >-import org.eclipse.core.internal.databinding.Util; >-import org.eclipse.core.runtime.Assert; >- >-/** >- * @since 1.0 >- * >- */ >-public class JavaBeanPropertyObservableMap extends ObservableMap implements >- IBeanObservable { >- >- private final Object object; >- >- private PropertyChangeListener mapListener = new PropertyChangeListener() { >- public void propertyChange(final PropertyChangeEvent event) { >- if (!updating) { >- getRealm().exec(new Runnable() { >- public void run() { >- Map oldValue = wrappedMap; >- Map newValue = (Map) event.getNewValue(); >- wrappedMap = new HashMap(newValue); >- >- fireMapChange(Diffs.computeMapDiff(oldValue, newValue)); >- } >- }); >- } >- } >- }; >- >- private boolean updating = false; >- >- private PropertyDescriptor descriptor; >- >- private ListenerSupport collectionListenSupport; >- >- private boolean attachListeners; >- >- /** >- * @param realm >- * @param object >- * @param descriptor >- */ >- public JavaBeanPropertyObservableMap(Realm realm, Object object, >- PropertyDescriptor descriptor) { >- this(realm, object, descriptor, true); >- } >- >- /** >- * @param realm >- * @param object >- * @param descriptor >- * @param attachListeners >- */ >- public JavaBeanPropertyObservableMap(Realm realm, Object object, >- PropertyDescriptor descriptor, boolean attachListeners) { >- super(realm, new HashMap()); >- this.object = object; >- this.descriptor = descriptor; >- this.attachListeners = attachListeners; >- if (attachListeners) { >- this.collectionListenSupport = new ListenerSupport(mapListener, >- descriptor.getName()); >- } >- >- wrappedMap.putAll(getMap()); >- } >- >- protected void firstListenerAdded() { >- if (attachListeners) { >- collectionListenSupport.hookListener(this.object); >- } >- } >- >- protected void lastListenerRemoved() { >- if (collectionListenSupport != null) { >- collectionListenSupport.dispose(); >- } >- } >- >- private Object primGetMap() { >- try { >- Method readMethod = descriptor.getReadMethod(); >- if (!readMethod.isAccessible()) { >- readMethod.setAccessible(true); >- } >- return readMethod.invoke(object, new Object[0]); >- } catch (IllegalArgumentException e) { >- } catch (IllegalAccessException e) { >- } catch (InvocationTargetException e) { >- } >- Assert.isTrue(false, "Could not read collection values"); //$NON-NLS-1$ >- return null; >- } >- >- private void primSetMap(Object newValue) { >- Exception ex = null; >- try { >- Method writeMethod = descriptor.getWriteMethod(); >- if (!writeMethod.isAccessible()) { >- writeMethod.setAccessible(true); >- } >- writeMethod.invoke(object, new Object[] { newValue }); >- return; >- } catch (IllegalArgumentException e) { >- ex = e; >- } catch (IllegalAccessException e) { >- ex = e; >- } catch (InvocationTargetException e) { >- ex = e; >- } >- throw new BindingException("Could not write collection values", ex); //$NON-NLS-1$ >- } >- >- private Map getMap() { >- Map result = (Map) primGetMap(); >- >- if (result == null) >- result = new HashMap(); >- return result; >- } >- >- private void setMap() { >- primSetMap(new HashMap(wrappedMap)); >- } >- >- public Object put(Object key, Object value) { >- checkRealm(); >- updating = true; >- try { >- Object result = wrappedMap.put(key, value); >- if (!Util.equals(result, value)) { >- setMap(); >- if (result == null) { >- fireMapChange(Diffs.createMapDiffSingleAdd(key, value)); >- } else { >- fireMapChange(Diffs.createMapDiffSingleChange(key, result, >- value)); >- } >- } >- return result; >- } finally { >- updating = false; >- } >- } >- >- public void putAll(Map map) { >- checkRealm(); >- updating = true; >- try { >- Set addedKeys = new HashSet(map.size()); >- Map changes = new HashMap(map.size()); >- for (Iterator it = map.entrySet().iterator(); it.hasNext();) { >- Map.Entry entry = (Entry) it.next(); >- Object key = entry.getKey(); >- Object newValue = entry.getValue(); >- Object oldValue = wrappedMap.put(key, newValue); >- if (oldValue == null) { >- addedKeys.add(key); >- } else if (!Util.equals(oldValue, newValue)) { >- changes.put(key, oldValue); >- } >- } >- if (!addedKeys.isEmpty() || !changes.isEmpty()) { >- setMap(); >- fireMapChange(Diffs.createMapDiff(addedKeys, >- Collections.EMPTY_SET, changes.keySet(), changes, >- wrappedMap)); >- } >- } finally { >- updating = false; >- } >- } >- >- public Object remove(Object key) { >- checkRealm(); >- updating = true; >- try { >- Object result = wrappedMap.remove(key); >- if (result!=null) { >- setMap(); >- fireMapChange(Diffs.createMapDiffSingleRemove(key, result)); >- } >- return result; >- } finally { >- updating = false; >- } >- } >- >- public void clear() { >- checkRealm(); >- if (wrappedMap.isEmpty()) >- return; >- updating = true; >- try { >- Map oldMap = wrappedMap; >- wrappedMap = new HashMap(); >- setMap(); >- fireMapChange(Diffs.computeMapDiff(oldMap, Collections.EMPTY_MAP)); >- } finally { >- updating = false; >- } >- } >- >- public Object getObserved() { >- return object; >- } >- >- public PropertyDescriptor getPropertyDescriptor() { >- return descriptor; >- } >-} >Index: src/org/eclipse/core/internal/databinding/beans/JavaBeanObservableSet.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/beans/JavaBeanObservableSet.java >diff -N src/org/eclipse/core/internal/databinding/beans/JavaBeanObservableSet.java >--- src/org/eclipse/core/internal/databinding/beans/JavaBeanObservableSet.java 20 Mar 2008 21:16:42 -0000 1.1 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,306 +0,0 @@ >-/******************************************************************************* >- * Copyright (c) 2006-2008 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 >- * Brad Reynolds - bug 171616 >- * Matthew Hall - bug 221351, 223164 >- *******************************************************************************/ >- >-package org.eclipse.core.internal.databinding.beans; >- >-import java.beans.PropertyChangeListener; >-import java.beans.PropertyDescriptor; >-import java.lang.reflect.Array; >-import java.lang.reflect.InvocationTargetException; >-import java.lang.reflect.Method; >-import java.util.Arrays; >-import java.util.Collection; >-import java.util.Collections; >-import java.util.HashSet; >-import java.util.Iterator; >-import java.util.Set; >- >-import org.eclipse.core.databinding.BindingException; >-import org.eclipse.core.databinding.beans.IBeanObservable; >-import org.eclipse.core.databinding.observable.Diffs; >-import org.eclipse.core.databinding.observable.Realm; >-import org.eclipse.core.databinding.observable.set.ObservableSet; >-import org.eclipse.core.runtime.Assert; >- >-/** >- * @since 1.0 >- * >- */ >-public class JavaBeanObservableSet extends ObservableSet implements IBeanObservable { >- >- private final Object object; >- >- private PropertyChangeListener collectionListener = new PropertyChangeListener() { >- public void propertyChange(java.beans.PropertyChangeEvent event) { >- if (!updating) { >- getRealm().exec(new Runnable() { >- public void run() { >- Set newElements = new HashSet(Arrays >- .asList(getValues())); >- Set addedElements = new HashSet(newElements); >- Set removedElements = new HashSet(wrappedSet); >- // remove all new elements from old elements to compute >- // the removed elements >- removedElements.removeAll(newElements); >- addedElements.removeAll(wrappedSet); >- wrappedSet = newElements; >- fireSetChange(Diffs.createSetDiff(addedElements, >- removedElements)); >- } >- }); >- } >- } >- }; >- >- private boolean updating = false; >- >- private PropertyDescriptor descriptor; >- >- private ListenerSupport collectionListenSupport; >- >- private boolean attachListeners; >- >- /** >- * @param realm >- * @param object >- * @param descriptor >- * @param elementType >- */ >- public JavaBeanObservableSet(Realm realm, Object object, >- PropertyDescriptor descriptor, Class elementType) { >- this(realm, object, descriptor, elementType, true); >- } >- >- /** >- * @param realm >- * @param object >- * @param descriptor >- * @param elementType >- * @param attachListeners >- */ >- public JavaBeanObservableSet(Realm realm, Object object, >- PropertyDescriptor descriptor, Class elementType, >- boolean attachListeners) { >- super(realm, new HashSet(), elementType); >- this.object = object; >- this.descriptor = descriptor; >- this.attachListeners = attachListeners; >- if (attachListeners) { >- this.collectionListenSupport = new ListenerSupport( >- collectionListener, descriptor.getName()); >- } >- >- wrappedSet.addAll(Arrays.asList(getValues())); >- } >- >- protected void firstListenerAdded() { >- if (attachListeners) { >- collectionListenSupport.hookListener(this.object); >- } >- } >- >- protected void lastListenerRemoved() { >- if (collectionListenSupport != null) { >- collectionListenSupport.dispose(); >- } >- } >- >- private Object primGetValues() { >- try { >- Method readMethod = descriptor.getReadMethod(); >- if (!readMethod.isAccessible()) { >- readMethod.setAccessible(true); >- } >- return readMethod.invoke(object, new Object[0]); >- } catch (IllegalArgumentException e) { >- } catch (IllegalAccessException e) { >- } catch (InvocationTargetException e) { >- } >- Assert.isTrue(false, "Could not read collection values"); //$NON-NLS-1$ >- return null; >- } >- >- private Object[] getValues() { >- Object[] values = null; >- >- Object result = primGetValues(); >- if (descriptor.getPropertyType().isArray()) >- values = (Object[]) result; >- else { >- // TODO add jUnit for POJO (var. SettableValue) collections >- Collection list = (Collection) result; >- if (list != null) >- values = list.toArray(); >- } >- if (values == null) >- values = new Object[0]; >- return values; >- } >- >- private void setValues() { >- if (descriptor.getPropertyType().isArray()) { >- Class componentType = descriptor.getPropertyType() >- .getComponentType(); >- Object[] newArray = (Object[]) Array.newInstance(componentType, >- wrappedSet.size()); >- wrappedSet.toArray(newArray); >- primSetValues(newArray); >- } else { >- // assume that it is a java.util.Set >- primSetValues(new HashSet(wrappedSet)); >- } >- } >- >- public boolean add(Object o) { >- getterCalled(); >- updating = true; >- try { >- boolean added = wrappedSet.add(o); >- if (added) { >- setValues(); >- fireSetChange(Diffs.createSetDiff(Collections.singleton(o), >- Collections.EMPTY_SET)); >- } >- return added; >- } finally { >- updating = false; >- } >- } >- >- public boolean remove(Object o) { >- getterCalled(); >- updating = true; >- try { >- boolean removed = wrappedSet.remove(o); >- if (removed) { >- setValues(); >- fireSetChange(Diffs.createSetDiff(Collections.EMPTY_SET, >- Collections.singleton(o))); >- } >- return removed; >- } finally { >- updating = false; >- } >- } >- >- public boolean addAll(Collection c) { >- getterCalled(); >- updating = true; >- try { >- Set additions = new HashSet(); >- for (Iterator iterator = c.iterator(); iterator.hasNext();) { >- Object element = iterator.next(); >- if (wrappedSet.add(element)) >- additions.add(element); >- } >- boolean changed = !additions.isEmpty(); >- if (changed) { >- setValues(); >- fireSetChange(Diffs.createSetDiff(additions, >- Collections.EMPTY_SET)); >- } >- return changed; >- } finally { >- updating = false; >- } >- } >- >- public boolean removeAll(Collection c) { >- getterCalled(); >- updating = true; >- try { >- Set removals = new HashSet(); >- for (Iterator iterator = c.iterator(); iterator.hasNext();) { >- Object element = iterator.next(); >- if (wrappedSet.remove(element)) >- removals.add(element); >- } >- boolean changed = !removals.isEmpty(); >- if (changed) { >- setValues(); >- fireSetChange(Diffs.createSetDiff(Collections.EMPTY_SET, >- removals)); >- } >- return changed; >- } finally { >- updating = false; >- } >- } >- >- public boolean retainAll(Collection c) { >- getterCalled(); >- updating = true; >- try { >- Set removals = new HashSet(); >- for (Iterator iterator = wrappedSet.iterator(); iterator.hasNext();) { >- Object element = iterator.next(); >- if (!c.contains(element)) { >- iterator.remove(); >- removals.add(element); >- } >- } >- boolean changed = !removals.isEmpty(); >- if (changed) { >- setValues(); >- fireSetChange(Diffs.createSetDiff(Collections.EMPTY_SET, >- removals)); >- } >- return changed; >- } finally { >- updating = false; >- } >- } >- >- public void clear() { >- getterCalled(); >- if (wrappedSet.isEmpty()) >- return; >- >- updating = true; >- try { >- Set removals = new HashSet(wrappedSet); >- wrappedSet.clear(); >- setValues(); >- fireSetChange(Diffs.createSetDiff(Collections.EMPTY_SET, removals)); >- } finally { >- updating = false; >- } >- } >- >- private void primSetValues(Object newValue) { >- Exception ex = null; >- try { >- Method writeMethod = descriptor.getWriteMethod(); >- if (!writeMethod.isAccessible()) { >- writeMethod.setAccessible(true); >- } >- writeMethod.invoke(object, new Object[] { newValue }); >- return; >- } catch (IllegalArgumentException e) { >- ex = e; >- } catch (IllegalAccessException e) { >- ex = e; >- } catch (InvocationTargetException e) { >- ex = e; >- } >- throw new BindingException("Could not write collection values", ex); //$NON-NLS-1$ >- } >- >- public Object getObserved() { >- return object; >- } >- >- public PropertyDescriptor getPropertyDescriptor() { >- return descriptor; >- } >-} >Index: src/org/eclipse/core/internal/databinding/beans/BeanObservableMapDecorator.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.databinding.beans/src/org/eclipse/core/internal/databinding/beans/BeanObservableMapDecorator.java,v >retrieving revision 1.1 >diff -u -r1.1 BeanObservableMapDecorator.java >--- src/org/eclipse/core/internal/databinding/beans/BeanObservableMapDecorator.java 20 Mar 2008 21:16:42 -0000 1.1 >+++ src/org/eclipse/core/internal/databinding/beans/BeanObservableMapDecorator.java 4 Sep 2008 20:45:19 -0000 >@@ -7,6 +7,7 @@ > * > * Contributors: > * Matthew Hall - initial API and implementation (bug 221704) >+ * Matthew Hall - bug 194734 > ******************************************************************************/ > > package org.eclipse.core.internal.databinding.beans; >@@ -18,6 +19,7 @@ > > import org.eclipse.core.databinding.beans.IBeanObservable; > import org.eclipse.core.databinding.observable.IChangeListener; >+import org.eclipse.core.databinding.observable.IObserving; > import org.eclipse.core.databinding.observable.IStaleListener; > import org.eclipse.core.databinding.observable.Realm; > import org.eclipse.core.databinding.observable.map.IMapChangeListener; >@@ -31,20 +33,16 @@ > */ > public class BeanObservableMapDecorator implements IObservableMap, IBeanObservable { > private IObservableMap delegate; >- private Object observed; > private PropertyDescriptor propertyDescriptor; > > /** > * @param delegate >- * @param observed > * @param propertyDescriptor > */ > public BeanObservableMapDecorator(IObservableMap delegate, >- Object observed, > PropertyDescriptor propertyDescriptor) { > > this.delegate = delegate; >- this.observed = observed; > this.propertyDescriptor = propertyDescriptor; > } > >@@ -105,7 +103,9 @@ > } > > public Object getObserved() { >- return observed; >+ if (delegate instanceof IObserving) >+ return ((IObserving) delegate).getObserved(); >+ return null; > } > > public PropertyDescriptor getPropertyDescriptor() { >Index: src/org/eclipse/core/internal/databinding/beans/BeanObservableValueDecorator.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.databinding.beans/src/org/eclipse/core/internal/databinding/beans/BeanObservableValueDecorator.java,v >retrieving revision 1.1 >diff -u -r1.1 BeanObservableValueDecorator.java >--- src/org/eclipse/core/internal/databinding/beans/BeanObservableValueDecorator.java 20 Mar 2008 21:16:42 -0000 1.1 >+++ src/org/eclipse/core/internal/databinding/beans/BeanObservableValueDecorator.java 4 Sep 2008 20:45:19 -0000 >@@ -7,6 +7,7 @@ > * > * Contributors: > * Brad Reynolds - initial API and implementation >+ * Matthew Hall - bug 194734 > ******************************************************************************/ > > package org.eclipse.core.internal.databinding.beans; >@@ -15,7 +16,9 @@ > > import org.eclipse.core.databinding.beans.IBeanObservable; > import org.eclipse.core.databinding.observable.IChangeListener; >+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.Realm; > import org.eclipse.core.databinding.observable.value.IObservableValue; > import org.eclipse.core.databinding.observable.value.IValueChangeListener; >@@ -30,17 +33,14 @@ > IBeanObservable { > private final IObservableValue delegate; > private final PropertyDescriptor descriptor; >- private final IObservableValue observed; > > /** > * @param delegate >- * @param observed > * @param descriptor > */ >- public BeanObservableValueDecorator(IObservableValue delegate, IObservableValue observed, >+ public BeanObservableValueDecorator(IObservableValue delegate, > PropertyDescriptor descriptor) { > this.delegate = delegate; >- this.observed = observed; > this.descriptor = descriptor; > } > >@@ -73,9 +73,14 @@ > } > > public Object getValue() { >+ getterCalled(); > return delegate.getValue(); > } > >+ private void getterCalled() { >+ ObservableTracker.getterCalled(this); >+ } >+ > public Object getValueType() { > return delegate.getValueType(); > } >@@ -85,6 +90,7 @@ > } > > public boolean isStale() { >+ getterCalled(); > return delegate.isStale(); > } > >@@ -104,20 +110,12 @@ > delegate.setValue(value); > } > >- /* >- * (non-Javadoc) >- * >- * @see org.eclipse.core.databinding.beans.IBeanObservable#getObserved() >- */ > public Object getObserved() { >- return observed.getValue(); >+ if (delegate instanceof IObserving) >+ return ((IObserving) delegate).getObserved(); >+ return null; > } > >- /* >- * (non-Javadoc) >- * >- * @see org.eclipse.core.databinding.beans.IBeanObservable#getPropertyDescriptor() >- */ > public PropertyDescriptor getPropertyDescriptor() { > return descriptor; > } >Index: src/org/eclipse/core/internal/databinding/beans/JavaBeanObservableValue.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/beans/JavaBeanObservableValue.java >diff -N src/org/eclipse/core/internal/databinding/beans/JavaBeanObservableValue.java >--- src/org/eclipse/core/internal/databinding/beans/JavaBeanObservableValue.java 24 Mar 2008 19:13:25 -0000 1.2 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,190 +0,0 @@ >-/******************************************************************************* >- * Copyright (c) 2005, 2008 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 >- * Brad Reynolds - bug 164653 >- * Brad Reynolds - bug 164134, 171616 >- *******************************************************************************/ >-package org.eclipse.core.internal.databinding.beans; >- >-import java.beans.PropertyChangeListener; >-import java.beans.PropertyDescriptor; >-import java.lang.reflect.InvocationTargetException; >-import java.lang.reflect.Method; >- >-import org.eclipse.core.databinding.BindingException; >-import org.eclipse.core.databinding.beans.BeansObservables; >-import org.eclipse.core.databinding.beans.IBeanObservable; >-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.util.Policy; >-import org.eclipse.core.internal.databinding.Util; >-import org.eclipse.core.runtime.IStatus; >-import org.eclipse.core.runtime.Status; >- >-/** >- * @since 1.0 >- * >- */ >-public class JavaBeanObservableValue extends AbstractObservableValue implements IBeanObservable { >- private final Object object; >- private boolean updating = false; >- >- private final PropertyDescriptor propertyDescriptor; >- private ListenerSupport listenerSupport; >- >- private boolean attachListeners; >- >- /** >- * @param realm >- * @param object >- * @param descriptor >- */ >- public JavaBeanObservableValue(Realm realm, Object object, >- PropertyDescriptor descriptor) { >- this(realm, object, descriptor, true); >- } >- >- /** >- * @param realm >- * @param object >- * @param descriptor >- * @param attachListeners >- */ >- public JavaBeanObservableValue(Realm realm, Object object, >- PropertyDescriptor descriptor, boolean attachListeners) { >- super(realm); >- this.object = object; >- this.propertyDescriptor = descriptor; >- this.attachListeners = attachListeners; >- } >- >- protected void firstListenerAdded() { >- if (!attachListeners) { >- return; >- } >- >- PropertyChangeListener listener = new PropertyChangeListener() { >- public void propertyChange(java.beans.PropertyChangeEvent event) { >- if (!updating) { >- final ValueDiff diff = Diffs.createValueDiff(event.getOldValue(), >- event.getNewValue()); >- getRealm().exec(new Runnable(){ >- public void run() { >- fireValueChange(diff); >- }}); >- } >- } >- }; >- >- if (listenerSupport == null) { >- listenerSupport = new ListenerSupport(listener, propertyDescriptor.getName()); >- } >- >- listenerSupport.hookListener(object); >- } >- >- public void doSetValue(Object value) { >- updating = true; >- try { >- Object oldValue = doGetValue(); >- >- if (Util.equals(oldValue, value)) { >- return; >- } >- >- Method writeMethod = propertyDescriptor.getWriteMethod(); >- if (!writeMethod.isAccessible()) { >- writeMethod.setAccessible(true); >- } >- writeMethod.invoke(object, new Object[] { value }); >- fireValueChange(Diffs.createValueDiff(oldValue, doGetValue())); >- } catch (InvocationTargetException e) { >- /* >- * InvocationTargetException wraps any exception thrown by the >- * invoked method. >- */ >- throw new RuntimeException(e.getCause()); >- } catch (Exception e) { >- if (BeansObservables.DEBUG) { >- Policy >- .getLog() >- .log( >- new Status( >- IStatus.WARNING, >- Policy.JFACE_DATABINDING, >- IStatus.OK, >- "Could not change value of " + object + "." + propertyDescriptor.getName(), e)); //$NON-NLS-1$ //$NON-NLS-2$ >- } >- } finally { >- updating = false; >- } >- } >- >- public Object doGetValue() { >- try { >- Method readMethod = propertyDescriptor.getReadMethod(); >- if (readMethod == null) { >- throw new BindingException(propertyDescriptor.getName() >- + " property does not have a read method."); //$NON-NLS-1$ >- } >- if (!readMethod.isAccessible()) { >- readMethod.setAccessible(true); >- } >- return readMethod.invoke(object, null); >- } catch (InvocationTargetException e) { >- /* >- * InvocationTargetException wraps any exception thrown by the >- * invoked method. >- */ >- throw new RuntimeException(e.getCause()); >- } catch (Exception e) { >- if (BeansObservables.DEBUG) { >- Policy >- .getLog() >- .log( >- new Status( >- IStatus.WARNING, >- Policy.JFACE_DATABINDING, >- IStatus.OK, >- "Could not read value of " + object + "." + propertyDescriptor.getName(), e)); //$NON-NLS-1$ //$NON-NLS-2$ >- } >- return null; >- } >- } >- >- protected void lastListenerRemoved() { >- unhookListener(); >- } >- >- private void unhookListener() { >- if (listenerSupport != null) { >- listenerSupport.dispose(); >- listenerSupport = null; >- } >- } >- >- public Object getValueType() { >- return propertyDescriptor.getPropertyType(); >- } >- >- public Object getObserved() { >- return object; >- } >- >- public PropertyDescriptor getPropertyDescriptor() { >- return propertyDescriptor; >- } >- >- public synchronized void dispose() { >- unhookListener(); >- super.dispose(); >- } >-} >Index: src/org/eclipse/core/internal/databinding/beans/BeanObservableListDecorator.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.databinding.beans/src/org/eclipse/core/internal/databinding/beans/BeanObservableListDecorator.java,v >retrieving revision 1.1 >diff -u -r1.1 BeanObservableListDecorator.java >--- src/org/eclipse/core/internal/databinding/beans/BeanObservableListDecorator.java 20 Mar 2008 21:16:42 -0000 1.1 >+++ src/org/eclipse/core/internal/databinding/beans/BeanObservableListDecorator.java 4 Sep 2008 20:45:19 -0000 >@@ -7,7 +7,7 @@ > * > * Contributors: > * Brad Reynolds - initial API and implementation >- * Matthew Hall - bug 208858 >+ * Matthew Hall - bugs 208858, 194734 > ******************************************************************************/ > > package org.eclipse.core.internal.databinding.beans; >@@ -19,6 +19,7 @@ > import java.util.ListIterator; > > import org.eclipse.core.databinding.beans.IBeanObservable; >+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; >@@ -39,19 +40,16 @@ > private IStaleListener delegateStaleListener; > private IListChangeListener delegateListChangeListener; > >- private Object observed; > private PropertyDescriptor propertyDescriptor; > > /** > * @param delegate >- * @param observed > * @param propertyDescriptor > */ > public BeanObservableListDecorator(IObservableList delegate, >- Object observed, PropertyDescriptor propertyDescriptor) { >+ PropertyDescriptor propertyDescriptor) { > super(delegate.getRealm()); > this.delegate = delegate; >- this.observed = observed; > this.propertyDescriptor = propertyDescriptor; > } > >@@ -205,20 +203,12 @@ > return delegate; > } > >- /* >- * (non-Javadoc) >- * >- * @see org.eclipse.core.databinding.beans.IBeanObservable#getObserved() >- */ > public Object getObserved() { >- return observed; >+ if (delegate instanceof IObserving) >+ return ((IObserving) delegate).getObserved(); >+ return null; > } > >- /* >- * (non-Javadoc) >- * >- * @see org.eclipse.core.databinding.beans.IBeanObservable#getPropertyDescriptor() >- */ > public PropertyDescriptor getPropertyDescriptor() { > return propertyDescriptor; > } >Index: src/org/eclipse/core/databinding/beans/BeansObservables.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.databinding.beans/src/org/eclipse/core/databinding/beans/BeansObservables.java,v >retrieving revision 1.19 >diff -u -r1.19 BeansObservables.java >--- src/org/eclipse/core/databinding/beans/BeansObservables.java 7 Jul 2008 15:33:17 -0000 1.19 >+++ src/org/eclipse/core/databinding/beans/BeansObservables.java 4 Sep 2008 20:45:18 -0000 >@@ -8,17 +8,13 @@ > * Contributors: > * IBM Corporation - initial API and implementation > * Brad Reynolds - bugs 164268, 171616, 147515 >- * Matthew Hall - bug 221704, 234686 >+ * Matthew Hall - bugs 221704, 234686, 194734 > * Thomas Kratz - bug 213787 > *******************************************************************************/ > package org.eclipse.core.databinding.beans; > >-import java.beans.BeanInfo; >-import java.beans.IntrospectionException; >-import java.beans.Introspector; > import java.beans.PropertyDescriptor; > >-import org.eclipse.core.databinding.BindingException; > import org.eclipse.core.databinding.observable.IObservable; > import org.eclipse.core.databinding.observable.Realm; > import org.eclipse.core.databinding.observable.list.IObservableList; >@@ -27,15 +23,16 @@ > import org.eclipse.core.databinding.observable.masterdetail.MasterDetailObservables; > import org.eclipse.core.databinding.observable.set.IObservableSet; > import org.eclipse.core.databinding.observable.value.IObservableValue; >+import org.eclipse.core.databinding.property.IListProperty; >+import org.eclipse.core.databinding.property.IMapProperty; >+import org.eclipse.core.databinding.property.ISetProperty; >+import org.eclipse.core.databinding.property.IValueProperty; >+import org.eclipse.core.databinding.property.PropertyObservables; > import org.eclipse.core.internal.databinding.beans.BeanObservableListDecorator; > import org.eclipse.core.internal.databinding.beans.BeanObservableMapDecorator; > import org.eclipse.core.internal.databinding.beans.BeanObservableSetDecorator; > import org.eclipse.core.internal.databinding.beans.BeanObservableValueDecorator; >-import org.eclipse.core.internal.databinding.beans.JavaBeanObservableList; >-import org.eclipse.core.internal.databinding.beans.JavaBeanObservableMap; >-import org.eclipse.core.internal.databinding.beans.JavaBeanObservableSet; >-import org.eclipse.core.internal.databinding.beans.JavaBeanObservableValue; >-import org.eclipse.core.internal.databinding.beans.JavaBeanPropertyObservableMap; >+import org.eclipse.core.internal.databinding.beans.BeanPropertyHelper; > import org.eclipse.core.runtime.Assert; > > /** >@@ -83,9 +80,12 @@ > */ > public static IObservableValue observeValue(Realm realm, Object bean, > String propertyName) { >- PropertyDescriptor descriptor = getPropertyDescriptor(bean.getClass(), >+ IValueProperty property = BeanProperties.valueProperty(bean.getClass(), > propertyName); >- return new JavaBeanObservableValue(realm, bean, descriptor); >+ PropertyDescriptor propertyDescriptor = ((IBeanProperty) property) >+ .getPropertyDescriptor(); >+ return new BeanObservableValueDecorator(PropertyObservables >+ .observeValue(realm, bean, property), propertyDescriptor); > } > > /** >@@ -103,9 +103,12 @@ > */ > public static IObservableMap observeMap(IObservableSet domain, > Class beanClass, String propertyName) { >- PropertyDescriptor descriptor = getPropertyDescriptor(beanClass, >+ IValueProperty property = BeanProperties.valueProperty(beanClass, > propertyName); >- return new JavaBeanObservableMap(domain, descriptor); >+ PropertyDescriptor propertyDescriptor = ((IBeanProperty) property) >+ .getPropertyDescriptor(); >+ return new BeanObservableMapDecorator(PropertyObservables.observeMap( >+ domain, property), propertyDescriptor); > } > > /** >@@ -124,9 +127,12 @@ > */ > public static IObservableMap observeMap(Realm realm, Object bean, > String propertyName) { >- PropertyDescriptor descriptor = getPropertyDescriptor(bean.getClass(), >+ IMapProperty property = BeanProperties.mapProperty(bean.getClass(), > propertyName); >- return new JavaBeanPropertyObservableMap(realm, bean, descriptor); >+ PropertyDescriptor propertyDescriptor = ((IBeanProperty) property) >+ .getPropertyDescriptor(); >+ return new BeanObservableMapDecorator(PropertyObservables.observeMap( >+ realm, bean, property), propertyDescriptor); > } > > /** >@@ -145,27 +151,6 @@ > return observeMap(Realm.getDefault(), bean, propertyName); > } > >- /*package*/ static PropertyDescriptor getPropertyDescriptor(Class beanClass, >- String propertyName) { >- BeanInfo beanInfo; >- try { >- beanInfo = Introspector.getBeanInfo(beanClass); >- } catch (IntrospectionException e) { >- // cannot introspect, give up >- return null; >- } >- PropertyDescriptor[] propertyDescriptors = beanInfo >- .getPropertyDescriptors(); >- for (int i = 0; i < propertyDescriptors.length; i++) { >- PropertyDescriptor descriptor = propertyDescriptors[i]; >- if (descriptor.getName().equals(propertyName)) { >- return descriptor; >- } >- } >- throw new BindingException( >- "Could not find property with name " + propertyName + " in class " + beanClass); //$NON-NLS-1$ //$NON-NLS-2$ >- } >- > /** > * Returns an array of observable maps in the default realm tracking the > * current values of the named propertys for the beans in the given set. >@@ -251,12 +236,13 @@ > */ > public static IObservableList observeList(Realm realm, Object bean, > String propertyName, Class elementType) { >- PropertyDescriptor propertyDescriptor = getPropertyDescriptor(bean >- .getClass(), propertyName); >- elementType = getCollectionElementType(elementType, propertyDescriptor); >+ IListProperty property = BeanProperties.listProperty(bean.getClass(), >+ propertyName, elementType); >+ PropertyDescriptor propertyDescriptor = ((IBeanProperty) property) >+ .getPropertyDescriptor(); > >- return new JavaBeanObservableList(realm, bean, propertyDescriptor, >- elementType); >+ return new BeanObservableListDecorator(PropertyObservables.observeList( >+ realm, bean, property), propertyDescriptor); > } > > /** >@@ -439,11 +425,8 @@ > > IObservableValue value = MasterDetailObservables.detailValue(master, > valueFactory(realm, propertyName), propertyType); >- BeanObservableValueDecorator decorator = new BeanObservableValueDecorator( >- value, master, getValueTypePropertyDescriptor(master, >- propertyName)); >- >- return decorator; >+ return new BeanObservableValueDecorator(value, BeanPropertyHelper >+ .getValueTypePropertyDescriptor(master, propertyName)); > } > > /** >@@ -492,15 +475,13 @@ > * @since 1.1 > */ > public static IObservableValue observeDetailValue(Realm realm, >- IObservableValue master, Class masterType, String propertyName, Class propertyType) { >+ IObservableValue master, Class masterType, String propertyName, >+ Class propertyType) { > Assert.isNotNull(masterType, "masterType cannot be null"); //$NON-NLS-1$ > IObservableValue value = MasterDetailObservables.detailValue(master, > valueFactory(realm, propertyName), propertyType); >- BeanObservableValueDecorator decorator = new BeanObservableValueDecorator( >- value, master, getPropertyDescriptor(masterType, >- propertyName)); >- >- return decorator; >+ return new BeanObservableValueDecorator(value, BeanPropertyHelper >+ .getPropertyDescriptor(masterType, propertyName)); > } > > /** >@@ -551,11 +532,9 @@ > IObservableList observableList = MasterDetailObservables.detailList( > master, listFactory(realm, propertyName, propertyType), > propertyType); >- BeanObservableListDecorator decorator = new BeanObservableListDecorator( >- observableList, master, getValueTypePropertyDescriptor(master, >+ return new BeanObservableListDecorator(observableList, >+ BeanPropertyHelper.getValueTypePropertyDescriptor(master, > propertyName)); >- >- return decorator; > } > > /** >@@ -599,11 +578,8 @@ > IObservableSet observableSet = MasterDetailObservables.detailSet( > master, setFactory(realm, propertyName, propertyType), > propertyType); >- BeanObservableSetDecorator decorator = new BeanObservableSetDecorator( >- observableSet, master, getValueTypePropertyDescriptor(master, >- propertyName)); >- >- return decorator; >+ return new BeanObservableSetDecorator(observableSet, BeanPropertyHelper >+ .getValueTypePropertyDescriptor(master, propertyName)); > } > > /** >@@ -642,10 +618,8 @@ > IObservableValue master, String propertyName) { > IObservableMap observableMap = MasterDetailObservables.detailMap( > master, mapPropertyFactory(realm, propertyName)); >- BeanObservableMapDecorator decorator = new BeanObservableMapDecorator( >- observableMap, master, getValueTypePropertyDescriptor(master, >- propertyName)); >- return decorator; >+ return new BeanObservableMapDecorator(observableMap, BeanPropertyHelper >+ .getValueTypePropertyDescriptor(master, propertyName)); > } > > /** >@@ -688,12 +662,13 @@ > */ > public static IObservableSet observeSet(Realm realm, Object bean, > String propertyName, Class elementType) { >- PropertyDescriptor propertyDescriptor = getPropertyDescriptor(bean >- .getClass(), propertyName); >- elementType = getCollectionElementType(elementType, propertyDescriptor); >+ ISetProperty property = BeanProperties.setProperty(bean.getClass(), >+ propertyName, elementType); >+ PropertyDescriptor propertyDescriptor = ((IBeanProperty) property) >+ .getPropertyDescriptor(); > >- return new JavaBeanObservableSet(realm, bean, propertyDescriptor, >- elementType); >+ return new BeanObservableSetDecorator(PropertyObservables.observeSet( >+ realm, bean, property), propertyDescriptor); > } > > /** >@@ -828,32 +803,4 @@ > public static IObservableFactory mapPropertyFactory(String propertyName) { > return mapPropertyFactory(Realm.getDefault(), propertyName); > } >- >- /** >- * @param elementType >- * can be <code>null</code> >- * @param propertyDescriptor >- * @return type of the items in a collection/array property >- */ >- /*package*/ static Class getCollectionElementType(Class elementType, >- PropertyDescriptor propertyDescriptor) { >- if (elementType == null) { >- Class propertyType = propertyDescriptor.getPropertyType(); >- elementType = propertyType.isArray() ? propertyType >- .getComponentType() : Object.class; >- } >- >- return elementType; >- } >- >- /** >- * @param observable >- * @param propertyName >- * @return property descriptor or <code>null</code> >- */ >- /* package*/ static PropertyDescriptor getValueTypePropertyDescriptor( >- IObservableValue observable, String propertyName) { >- return (observable.getValueType() != null) ? getPropertyDescriptor( >- (Class) observable.getValueType(), propertyName) : null; >- } > } >Index: src/org/eclipse/core/databinding/beans/PojoObservables.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.core.databinding.beans/src/org/eclipse/core/databinding/beans/PojoObservables.java,v >retrieving revision 1.6 >diff -u -r1.6 PojoObservables.java >--- src/org/eclipse/core/databinding/beans/PojoObservables.java 7 Jul 2008 15:33:17 -0000 1.6 >+++ src/org/eclipse/core/databinding/beans/PojoObservables.java 4 Sep 2008 20:45:19 -0000 >@@ -7,7 +7,7 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >- * Matthew Hall - bugs 221704, 234686 >+ * Matthew Hall - bugs 221704, 234686, 194734 > *******************************************************************************/ > > package org.eclipse.core.databinding.beans; >@@ -23,15 +23,16 @@ > import org.eclipse.core.databinding.observable.masterdetail.MasterDetailObservables; > import org.eclipse.core.databinding.observable.set.IObservableSet; > import org.eclipse.core.databinding.observable.value.IObservableValue; >+import org.eclipse.core.databinding.property.IListProperty; >+import org.eclipse.core.databinding.property.IMapProperty; >+import org.eclipse.core.databinding.property.ISetProperty; >+import org.eclipse.core.databinding.property.IValueProperty; >+import org.eclipse.core.databinding.property.PropertyObservables; > import org.eclipse.core.internal.databinding.beans.BeanObservableListDecorator; > import org.eclipse.core.internal.databinding.beans.BeanObservableMapDecorator; > import org.eclipse.core.internal.databinding.beans.BeanObservableSetDecorator; > import org.eclipse.core.internal.databinding.beans.BeanObservableValueDecorator; >-import org.eclipse.core.internal.databinding.beans.JavaBeanObservableList; >-import org.eclipse.core.internal.databinding.beans.JavaBeanObservableMap; >-import org.eclipse.core.internal.databinding.beans.JavaBeanObservableSet; >-import org.eclipse.core.internal.databinding.beans.JavaBeanObservableValue; >-import org.eclipse.core.internal.databinding.beans.JavaBeanPropertyObservableMap; >+import org.eclipse.core.internal.databinding.beans.BeanPropertyHelper; > > /** > * A factory for creating observable objects for POJOs (plain old java objects) >@@ -73,10 +74,12 @@ > */ > public static IObservableValue observeValue(Realm realm, Object pojo, > String propertyName) { >- >- PropertyDescriptor descriptor = BeansObservables.getPropertyDescriptor( >- pojo.getClass(), propertyName); >- return new JavaBeanObservableValue(realm, pojo, descriptor, false); >+ IValueProperty property = PojoProperties.valueProperty(pojo.getClass(), >+ propertyName); >+ PropertyDescriptor propertyDescriptor = ((IBeanProperty) property) >+ .getPropertyDescriptor(); >+ return new BeanObservableValueDecorator(PropertyObservables >+ .observeValue(realm, pojo, property), propertyDescriptor); > } > > /** >@@ -94,9 +97,12 @@ > */ > public static IObservableMap observeMap(IObservableSet domain, > Class pojoClass, String propertyName) { >- PropertyDescriptor descriptor = BeansObservables.getPropertyDescriptor( >- pojoClass, propertyName); >- return new JavaBeanObservableMap(domain, descriptor, false); >+ IValueProperty property = PojoProperties.valueProperty(pojoClass, >+ propertyName); >+ PropertyDescriptor propertyDescriptor = ((IBeanProperty) property) >+ .getPropertyDescriptor(); >+ return new BeanObservableMapDecorator(PropertyObservables.observeMap( >+ domain, property), propertyDescriptor); > } > > /** >@@ -136,9 +142,12 @@ > */ > public static IObservableMap observeMap(Realm realm, Object pojo, > String propertyName) { >- PropertyDescriptor descriptor = BeansObservables.getPropertyDescriptor( >- pojo.getClass(), propertyName); >- return new JavaBeanPropertyObservableMap(realm, pojo, descriptor, false); >+ IMapProperty property = PojoProperties.mapProperty(pojo.getClass(), >+ propertyName); >+ PropertyDescriptor propertyDescriptor = ((IBeanProperty) property) >+ .getPropertyDescriptor(); >+ return new BeanObservableMapDecorator(PropertyObservables.observeMap( >+ realm, pojo, property), propertyDescriptor); > } > > /** >@@ -220,13 +229,12 @@ > */ > public static IObservableList observeList(Realm realm, Object pojo, > String propertyName, Class elementType) { >- PropertyDescriptor propertyDescriptor = BeansObservables >- .getPropertyDescriptor(pojo.getClass(), propertyName); >- elementType = BeansObservables.getCollectionElementType(elementType, >- propertyDescriptor); >- >- return new JavaBeanObservableList(realm, pojo, propertyDescriptor, >- elementType, false); >+ IListProperty property = PojoProperties.listProperty(pojo.getClass(), >+ propertyName, elementType); >+ PropertyDescriptor propertyDescriptor = ((IBeanProperty) property) >+ .getPropertyDescriptor(); >+ return new BeanObservableListDecorator(PropertyObservables.observeList( >+ realm, pojo, property), propertyDescriptor); > } > > /** >@@ -310,13 +318,12 @@ > */ > public static IObservableSet observeSet(Realm realm, Object pojo, > String propertyName, Class elementType) { >- PropertyDescriptor propertyDescriptor = BeansObservables >- .getPropertyDescriptor(pojo.getClass(), propertyName); >- elementType = BeansObservables.getCollectionElementType(elementType, >- propertyDescriptor); >- >- return new JavaBeanObservableSet(realm, pojo, propertyDescriptor, >- elementType, false); >+ ISetProperty property = PojoProperties.setProperty(pojo.getClass(), >+ propertyName, elementType); >+ PropertyDescriptor propertyDescriptor = ((IBeanProperty) property) >+ .getPropertyDescriptor(); >+ return new BeanObservableSetDecorator(PropertyObservables.observeSet( >+ realm, pojo, property), propertyDescriptor); > } > > /** >@@ -540,11 +547,8 @@ > > IObservableValue value = MasterDetailObservables.detailValue(master, > valueFactory(realm, propertyName), propertyType); >- BeanObservableValueDecorator decorator = new BeanObservableValueDecorator( >- value, master, BeansObservables.getValueTypePropertyDescriptor( >- master, propertyName)); >- >- return decorator; >+ return new BeanObservableValueDecorator(value, BeanPropertyHelper >+ .getValueTypePropertyDescriptor(master, propertyName)); > } > > /** >@@ -587,11 +591,9 @@ > IObservableList observableList = MasterDetailObservables.detailList( > master, listFactory(realm, propertyName, propertyType), > propertyType); >- BeanObservableListDecorator decorator = new BeanObservableListDecorator( >- observableList, master, BeansObservables >- .getValueTypePropertyDescriptor(master, propertyName)); >- >- return decorator; >+ return new BeanObservableListDecorator(observableList, >+ BeanPropertyHelper.getValueTypePropertyDescriptor(master, >+ propertyName)); > } > > /** >@@ -635,11 +637,8 @@ > IObservableSet observableSet = MasterDetailObservables.detailSet( > master, setFactory(realm, propertyName, propertyType), > propertyType); >- BeanObservableSetDecorator decorator = new BeanObservableSetDecorator( >- observableSet, master, BeansObservables >- .getValueTypePropertyDescriptor(master, propertyName)); >- >- return decorator; >+ return new BeanObservableSetDecorator(observableSet, BeanPropertyHelper >+ .getValueTypePropertyDescriptor(master, propertyName)); > } > > /** >@@ -676,10 +675,8 @@ > IObservableValue master, String propertyName) { > IObservableMap observableMap = MasterDetailObservables.detailMap( > master, mapPropertyFactory(realm, propertyName)); >- BeanObservableMapDecorator decorator = new BeanObservableMapDecorator( >- observableMap, master, BeansObservables >- .getValueTypePropertyDescriptor(master, propertyName)); >- return decorator; >+ return new BeanObservableMapDecorator(observableMap, BeanPropertyHelper >+ .getValueTypePropertyDescriptor(master, propertyName)); > } > > /** >Index: src/org/eclipse/core/databinding/beans/IBeanProperty.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/beans/IBeanProperty.java >diff -N src/org/eclipse/core/databinding/beans/IBeanProperty.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/beans/IBeanProperty.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,27 @@ >+/******************************************************************************* >+ * 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.beans; >+ >+import java.beans.PropertyDescriptor; >+ >+import org.eclipse.core.databinding.property.IProperty; >+ >+/** >+ * @since 1.2 >+ * >+ */ >+public interface IBeanProperty extends IProperty { >+ /** >+ * @return property descriptor for the bean property >+ */ >+ public PropertyDescriptor getPropertyDescriptor(); >+} >Index: src/org/eclipse/core/internal/databinding/beans/PropertyUpdateHelper.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/beans/PropertyUpdateHelper.java >diff -N src/org/eclipse/core/internal/databinding/beans/PropertyUpdateHelper.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/beans/PropertyUpdateHelper.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,54 @@ >+/******************************************************************************* >+ * 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.beans; >+ >+import java.util.HashMap; >+import java.util.Map; >+ >+/** >+ * @since 3.3 >+ * >+ */ >+public class PropertyUpdateHelper { >+ private ThreadLocal localMap = new ThreadLocal() { >+ protected Object initialValue() { >+ return new HashMap(); >+ } >+ }; >+ >+ boolean isUpdating(Object source) { >+ Map map = (Map) localMap.get(); >+ return map.containsKey(source); >+ } >+ >+ void setUpdating(Object source, boolean state) { >+ Map map = (Map) localMap.get(); >+ Integer count = (Integer) map.get(source); >+ int newCount = (count == null ? 0 : count.intValue()) >+ + (state ? 1 : -1); >+ if (newCount > 0) >+ map.put(source, new Integer(newCount)); >+ else >+ map.remove(source); >+ } >+ >+ void dispose() { >+ if (localMap != null) { >+ Map map = (Map) localMap.get(); >+ if (map != null) { >+ map.clear(); >+ localMap.set(null); >+ } >+ localMap = null; >+ } >+ } >+} >Index: src/org/eclipse/core/internal/databinding/beans/BeanMapProperty.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/beans/BeanMapProperty.java >diff -N src/org/eclipse/core/internal/databinding/beans/BeanMapProperty.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/beans/BeanMapProperty.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,214 @@ >+/******************************************************************************* >+ * 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.beans; >+ >+import java.beans.PropertyChangeEvent; >+import java.beans.PropertyChangeListener; >+import java.beans.PropertyDescriptor; >+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.beans.IBeanProperty; >+import org.eclipse.core.databinding.observable.Diffs; >+import org.eclipse.core.databinding.observable.map.MapDiff; >+import org.eclipse.core.databinding.property.MapProperty; >+ >+/** >+ * @since 3.3 >+ * >+ */ >+public class BeanMapProperty extends MapProperty implements IBeanProperty { >+ private PropertyDescriptor propertyDescriptor; >+ private boolean attachListener; >+ >+ private ListenerSupport listenerSupport; >+ >+ private PropertyUpdateHelper updateHelper = new PropertyUpdateHelper(); >+ >+ private Map sourceToCachedMap = Collections.synchronizedMap(new HashMap()); >+ >+ /** >+ * @param propertyDescriptor >+ * @param attachListener >+ */ >+ public BeanMapProperty(PropertyDescriptor propertyDescriptor, >+ boolean attachListener) { >+ this.propertyDescriptor = propertyDescriptor; >+ this.attachListener = attachListener; >+ } >+ >+ private void initListenerSupport() { >+ if (listenerSupport == null) { >+ synchronized (this) { >+ if (listenerSupport == null) { >+ PropertyChangeListener propertyChangeListener = new PropertyChangeListener() { >+ public void propertyChange(PropertyChangeEvent evt) { >+ Object source = evt.getSource(); >+ if (!updateHelper.isUpdating(source)) { >+ Object oldValue = evt.getOldValue(); >+ Object newValue = evt.getNewValue(); >+ if (oldValue == null && newValue == null) { >+ // Obscure condition indicating new and old >+ // values are unknown >+ oldValue = sourceToCachedMap.get(source); >+ newValue = BeanPropertyHelper.getProperty( >+ source, propertyDescriptor); >+ } >+ sourceToCachedMap.put(source, newValue); >+ fireMapChange(source, Diffs.computeMapDiff( >+ asMap(oldValue), asMap(newValue))); >+ } >+ } >+ }; >+ listenerSupport = new ListenerSupport( >+ propertyChangeListener, propertyDescriptor >+ .getName()); >+ } >+ } >+ } >+ } >+ >+ protected void addListenerTo(Object source) { >+ if (source != null && attachListener) { >+ initListenerSupport(); >+ listenerSupport.hookListener(source); >+ sourceToCachedMap.put(source, BeanPropertyHelper.getProperty( >+ source, propertyDescriptor)); >+ } >+ } >+ >+ protected void removeListenerFrom(Object source) { >+ if (source != null && attachListener && listenerSupport != null) { >+ listenerSupport.unhookListener(source); >+ sourceToCachedMap.remove(source); >+ } >+ } >+ >+ public Map getMap(Object source) { >+ if (source == null) >+ return Collections.EMPTY_MAP; >+ Object propertyValue = BeanPropertyHelper.getProperty(source, >+ propertyDescriptor); >+ return asMap(propertyValue); >+ } >+ >+ private Map asMap(Object propertyValue) { >+ if (propertyValue == null) >+ return new HashMap(); >+ return (Map) propertyValue; >+ } >+ >+ private void setMap(Object source, Map map, MapDiff diff) { >+ if (source == null) >+ return; >+ >+ if (diff == null) { >+ diff = Diffs.computeMapDiff(getMap(source), map); >+ } >+ >+ updateHelper.setUpdating(source, true); >+ try { >+ BeanPropertyHelper.setProperty(source, propertyDescriptor, map); >+ } finally { >+ updateHelper.setUpdating(source, false); >+ } >+ >+ if (hasListeners(source)) { >+ sourceToCachedMap.put(source, map); >+ fireMapChange(source, diff); >+ } >+ } >+ >+ public void clear(Object source) { >+ setMap(source, new HashMap(), Diffs.createMapDiffRemoveAll(new HashMap( >+ getMap(source)))); >+ } >+ >+ public Object put(Object source, Object key, Object value) { >+ Map map = new HashMap(getMap(source)); >+ boolean addition = !map.containsKey(key); >+ Object result = map.put(key, value); >+ MapDiff diff; >+ if (addition) { >+ diff = Diffs.createMapDiffSingleAdd(key, value); >+ } else { >+ diff = Diffs.createMapDiffSingleChange(key, result, value); >+ } >+ setMap(source, map, diff); >+ return result; >+ } >+ >+ public void putAll(Object source, Map t) { >+ Map map = new HashMap(getMap(source)); >+ Set addedKeys = new HashSet(); >+ Set changedKeys = new HashSet(); >+ Map oldValues = new HashMap(); >+ Map newValues = new HashMap(); >+ for (Iterator it = t.entrySet().iterator(); it.hasNext();) { >+ Map.Entry entry = (Map.Entry) it.next(); >+ Object key = entry.getKey(); >+ Object newValue = entry.getValue(); >+ boolean addition = !map.containsKey(key); >+ Object oldValue = map.put(key, newValue); >+ if (addition) { >+ addedKeys.add(key); >+ } else { >+ changedKeys.add(key); >+ oldValues.put(key, oldValue); >+ } >+ newValues.put(key, newValue); >+ } >+ setMap(source, map, Diffs.createMapDiff(addedKeys, >+ Collections.EMPTY_SET, changedKeys, oldValues, newValues)); >+ } >+ >+ public Object remove(Object source, Object key) { >+ Map map = getMap(source); >+ if (map.containsKey(key)) { >+ map = new HashMap(map); >+ Object result = map.remove(key); >+ setMap(source, map, Diffs.createMapDiffSingleRemove(key, result)); >+ return result; >+ } >+ return null; >+ } >+ >+ public int size(Object source) { >+ return getMap(source).size(); >+ } >+ >+ public synchronized void dispose() { >+ propertyDescriptor = null; >+ attachListener = false; >+ if (listenerSupport != null) { >+ listenerSupport.dispose(); >+ listenerSupport = null; >+ } >+ if (updateHelper != null) { >+ updateHelper.dispose(); >+ updateHelper = null; >+ } >+ if (sourceToCachedMap != null) { >+ sourceToCachedMap.clear(); >+ sourceToCachedMap = null; >+ } >+ super.dispose(); >+ } >+ >+ public PropertyDescriptor getPropertyDescriptor() { >+ return propertyDescriptor; >+ } >+} >Index: src/org/eclipse/core/internal/databinding/beans/BeanValueProperty.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/beans/BeanValueProperty.java >diff -N src/org/eclipse/core/internal/databinding/beans/BeanValueProperty.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/beans/BeanValueProperty.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,155 @@ >+/******************************************************************************* >+ * 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.beans; >+ >+import java.beans.PropertyChangeEvent; >+import java.beans.PropertyChangeListener; >+import java.beans.PropertyDescriptor; >+import java.util.Collections; >+import java.util.HashMap; >+import java.util.Map; >+ >+import org.eclipse.core.databinding.beans.IBeanProperty; >+import org.eclipse.core.databinding.observable.Diffs; >+import org.eclipse.core.databinding.property.ValueProperty; >+import org.eclipse.core.internal.databinding.Util; >+ >+/** >+ * @since 3.3 >+ * >+ */ >+public class BeanValueProperty extends ValueProperty implements IBeanProperty { >+ private PropertyDescriptor propertyDescriptor; >+ private Class valueType; >+ private boolean attachListener; >+ >+ private ListenerSupport listenerSupport; >+ >+ private PropertyUpdateHelper updateHelper = new PropertyUpdateHelper(); >+ >+ private Map sourceToCachedValue = Collections >+ .synchronizedMap(new HashMap()); >+ >+ /** >+ * @param propertyDescriptor >+ * @param valueType >+ * @param attachListener >+ */ >+ public BeanValueProperty(PropertyDescriptor propertyDescriptor, >+ Class valueType, boolean attachListener) { >+ this.propertyDescriptor = propertyDescriptor; >+ this.valueType = valueType == null ? propertyDescriptor >+ .getPropertyType() : valueType; >+ this.attachListener = attachListener; >+ } >+ >+ private void initListenerSupport() { >+ if (listenerSupport == null) { >+ synchronized (this) { >+ if (listenerSupport == null) { >+ PropertyChangeListener propertyChangeListener = new PropertyChangeListener() { >+ public void propertyChange(PropertyChangeEvent evt) { >+ Object source = evt.getSource(); >+ if (!updateHelper.isUpdating(source)) { >+ Object oldValue = evt.getOldValue(); >+ Object newValue = evt.getNewValue(); >+ if (oldValue == null && newValue == null) { >+ // Obscure condition indicating new and old >+ // values are unknown >+ oldValue = sourceToCachedValue.get(source); >+ newValue = getValue(source); >+ } >+ sourceToCachedValue.put(source, newValue); >+ fireValueChange(source, Diffs.createValueDiff( >+ oldValue, newValue)); >+ } >+ } >+ }; >+ listenerSupport = new ListenerSupport( >+ propertyChangeListener, propertyDescriptor >+ .getName()); >+ } >+ } >+ } >+ } >+ >+ protected void addListenerTo(Object source) { >+ if (source != null && attachListener) { >+ initListenerSupport(); >+ listenerSupport.hookListener(source); >+ sourceToCachedValue.put(source, getValue(source)); >+ } >+ } >+ >+ protected void removeListenerFrom(Object source) { >+ if (source != null && attachListener && listenerSupport != null) { >+ listenerSupport.unhookListener(source); >+ sourceToCachedValue.remove(source); >+ } >+ } >+ >+ public Object getValue(Object source) { >+ if (source == null) >+ return null; >+ return BeanPropertyHelper.getProperty(source, propertyDescriptor); >+ } >+ >+ public void setValue(Object source, Object value) { >+ if (source == null) >+ return; >+ >+ Object oldValue = getValue(source); >+ >+ updateHelper.setUpdating(source, true); >+ try { >+ BeanPropertyHelper.setProperty(source, propertyDescriptor, value); >+ } finally { >+ updateHelper.setUpdating(source, false); >+ } >+ >+ if (hasListeners(source)) { >+ Object newValue = getValue(source); >+ if (!Util.equals(oldValue, newValue)) { >+ sourceToCachedValue.put(source, newValue); >+ fireValueChange(source, Diffs.createValueDiff(oldValue, >+ newValue)); >+ } >+ } >+ } >+ >+ public Object getValueType() { >+ return valueType; >+ } >+ >+ public PropertyDescriptor getPropertyDescriptor() { >+ return propertyDescriptor; >+ } >+ >+ public synchronized void dispose() { >+ propertyDescriptor = null; >+ valueType = null; >+ attachListener = false; >+ if (listenerSupport != null) { >+ listenerSupport.dispose(); >+ listenerSupport = null; >+ } >+ if (updateHelper != null) { >+ updateHelper.dispose(); >+ updateHelper = null; >+ } >+ if (sourceToCachedValue != null) { >+ sourceToCachedValue.clear(); >+ sourceToCachedValue = null; >+ } >+ super.dispose(); >+ } >+} >Index: src/org/eclipse/core/databinding/beans/PojoProperties.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/beans/PojoProperties.java >diff -N src/org/eclipse/core/databinding/beans/PojoProperties.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/beans/PojoProperties.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,109 @@ >+/******************************************************************************* >+ * 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.beans; >+ >+import org.eclipse.core.databinding.property.IListProperty; >+import org.eclipse.core.databinding.property.IMapProperty; >+import org.eclipse.core.databinding.property.ISetProperty; >+import org.eclipse.core.databinding.property.IValueProperty; >+import org.eclipse.core.internal.databinding.beans.BeanListProperty; >+import org.eclipse.core.internal.databinding.beans.BeanMapProperty; >+import org.eclipse.core.internal.databinding.beans.BeanPropertyHelper; >+import org.eclipse.core.internal.databinding.beans.BeanSetProperty; >+import org.eclipse.core.internal.databinding.beans.BeanValueProperty; >+ >+/** >+ * @since 1.2 >+ */ >+public class PojoProperties { >+ /** >+ * @param beanClass >+ * @param propertyName >+ * @return a value property for the given property name of the given bean >+ * class. >+ */ >+ public static IValueProperty valueProperty(Class beanClass, >+ String propertyName) { >+ return valueProperty(beanClass, propertyName, null); >+ } >+ >+ /** >+ * @param beanClass >+ * @param propertyName >+ * @param valueType >+ * @return a value property for the given property name of the given bean >+ * class. >+ */ >+ public static IValueProperty valueProperty(Class beanClass, >+ String propertyName, Class valueType) { >+ return new BeanValueProperty(BeanPropertyHelper.getPropertyDescriptor( >+ beanClass, propertyName), valueType, false); >+ } >+ >+ /** >+ * @param beanClass >+ * @param propertyName >+ * @return a list property for the given property name of the given bean >+ * class. >+ */ >+ public static ISetProperty setProperty(Class beanClass, String propertyName) { >+ return setProperty(beanClass, propertyName, null); >+ } >+ >+ /** >+ * @param beanClass >+ * @param propertyName >+ * @param elementType >+ * @return a list property for the given property name of the given bean >+ * class. >+ */ >+ public static ISetProperty setProperty(Class beanClass, >+ String propertyName, Class elementType) { >+ return new BeanSetProperty(BeanPropertyHelper.getPropertyDescriptor( >+ beanClass, propertyName), elementType, false); >+ } >+ >+ /** >+ * @param beanClass >+ * @param propertyName >+ * @return a list property for the given property name of the given bean >+ * class. >+ */ >+ public static IListProperty listProperty(Class beanClass, >+ String propertyName) { >+ return listProperty(beanClass, propertyName, null); >+ } >+ >+ /** >+ * @param beanClass >+ * @param propertyName >+ * @param elementType >+ * @return a list property for the given property name of the given bean >+ * class. >+ */ >+ public static IListProperty listProperty(Class beanClass, >+ String propertyName, Class elementType) { >+ return new BeanListProperty(BeanPropertyHelper.getPropertyDescriptor( >+ beanClass, propertyName), elementType, false); >+ } >+ >+ /** >+ * @param beanClass >+ * @param propertyName >+ * @return a map property for the given property name of the given bean >+ * class. >+ */ >+ public static IMapProperty mapProperty(Class beanClass, String propertyName) { >+ return new BeanMapProperty(BeanPropertyHelper.getPropertyDescriptor( >+ beanClass, propertyName), false); >+ } >+} >Index: src/org/eclipse/core/internal/databinding/beans/BeanListProperty.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/beans/BeanListProperty.java >diff -N src/org/eclipse/core/internal/databinding/beans/BeanListProperty.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/beans/BeanListProperty.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,330 @@ >+/******************************************************************************* >+ * 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.beans; >+ >+import java.beans.PropertyChangeEvent; >+import java.beans.PropertyChangeListener; >+import java.beans.PropertyDescriptor; >+import java.lang.reflect.Array; >+import java.util.ArrayList; >+import java.util.Arrays; >+import java.util.Collection; >+import java.util.Collections; >+import java.util.HashMap; >+import java.util.Iterator; >+import java.util.List; >+import java.util.ListIterator; >+import java.util.Map; >+ >+import org.eclipse.core.databinding.beans.IBeanProperty; >+import org.eclipse.core.databinding.observable.Diffs; >+import org.eclipse.core.databinding.observable.list.ListDiff; >+import org.eclipse.core.databinding.observable.list.ListDiffEntry; >+import org.eclipse.core.databinding.property.ListProperty; >+ >+/** >+ * @since 3.3 >+ * >+ */ >+public class BeanListProperty extends ListProperty implements IBeanProperty { >+ private PropertyDescriptor propertyDescriptor; >+ private Class elementType; >+ private boolean attachListener; >+ >+ private ListenerSupport listenerSupport; >+ >+ private PropertyUpdateHelper updateHelper = new PropertyUpdateHelper(); >+ >+ private Map sourceToCachedList = Collections.synchronizedMap(new HashMap()); >+ >+ /** >+ * @param propertyDescriptor >+ * @param elementType >+ * @param attachListener >+ */ >+ public BeanListProperty(PropertyDescriptor propertyDescriptor, >+ Class elementType, boolean attachListener) { >+ this.propertyDescriptor = propertyDescriptor; >+ this.elementType = elementType == null ? BeanPropertyHelper >+ .getCollectionPropertyElementType(propertyDescriptor) >+ : elementType; >+ this.attachListener = attachListener; >+ } >+ >+ private void initListenerSupport() { >+ if (listenerSupport == null) { >+ synchronized (this) { >+ if (listenerSupport == null) { >+ PropertyChangeListener propertyChangeListener = new PropertyChangeListener() { >+ public void propertyChange(PropertyChangeEvent evt) { >+ Object source = evt.getSource(); >+ if (!updateHelper.isUpdating(source)) { >+ Object oldValue = evt.getOldValue(); >+ Object newValue = evt.getNewValue(); >+ if (oldValue == null && newValue == null) { >+ // Obscure condition indicating new and old >+ // values are unknown >+ oldValue = sourceToCachedList.get(source); >+ newValue = BeanPropertyHelper.getProperty( >+ source, propertyDescriptor); >+ } >+ sourceToCachedList.put(source, newValue); >+ fireListChange(source, Diffs.computeListDiff( >+ asList(oldValue), asList(newValue))); >+ } >+ } >+ }; >+ listenerSupport = new ListenerSupport( >+ propertyChangeListener, propertyDescriptor >+ .getName()); >+ } >+ } >+ } >+ } >+ >+ protected void addListenerTo(Object source) { >+ if (source != null && attachListener) { >+ initListenerSupport(); >+ listenerSupport.hookListener(source); >+ sourceToCachedList.put(source, BeanPropertyHelper.getProperty( >+ source, propertyDescriptor)); >+ } >+ } >+ >+ protected void removeListenerFrom(Object source) { >+ if (source != null && attachListener && listenerSupport != null) { >+ listenerSupport.unhookListener(source); >+ sourceToCachedList.remove(source); >+ } >+ } >+ >+ public List getList(Object source) { >+ if (source == null) >+ return Collections.EMPTY_LIST; >+ Object propertyValue = BeanPropertyHelper.getProperty(source, >+ propertyDescriptor); >+ return asList(propertyValue); >+ } >+ >+ private List asList(Object propertyValue) { >+ if (propertyValue == null) >+ return new ArrayList(); >+ if (propertyDescriptor.getPropertyType().isArray()) >+ return new ArrayList(Arrays.asList((Object[]) propertyValue)); >+ return (List) propertyValue; >+ } >+ >+ private void setList(Object source, List list, ListDiff diff) { >+ if (source == null) >+ return; >+ >+ if (diff == null) { >+ diff = Diffs.computeListDiff(getList(source), list); >+ } >+ >+ updateHelper.setUpdating(source, true); >+ try { >+ BeanPropertyHelper.setProperty(source, propertyDescriptor, >+ convertListToBeanPropertyType(list)); >+ } finally { >+ updateHelper.setUpdating(source, false); >+ } >+ >+ if (hasListeners(source)) { >+ sourceToCachedList.put(source, list); >+ fireListChange(source, diff); >+ } >+ } >+ >+ private Object convertListToBeanPropertyType(List list) { >+ Object propertyValue = list; >+ if (propertyDescriptor.getPropertyType().isArray()) { >+ Class componentType = propertyDescriptor.getPropertyType() >+ .getComponentType(); >+ Object[] array = (Object[]) Array.newInstance(componentType, list >+ .size()); >+ list.toArray(array); >+ propertyValue = array; >+ } >+ return propertyValue; >+ } >+ >+ public boolean add(Object source, Object o) { >+ add(source, size(source), o); >+ return true; >+ } >+ >+ public boolean addAll(Object source, Collection c) { >+ if (c.isEmpty()) >+ return false; >+ addAll(source, size(source), c); >+ return true; >+ } >+ >+ public void clear(Object source) { >+ if (isEmpty(source)) >+ return; >+ List list = getList(source); >+ ListDiffEntry[] entries = new ListDiffEntry[list.size()]; >+ int i = 0; >+ for (Iterator it = getList(source).iterator(); it.hasNext(); i++) { >+ entries[i] = Diffs.createListDiffEntry(0, false, it.next()); >+ } >+ setList(source, new ArrayList(), Diffs.createListDiff(entries)); >+ } >+ >+ public boolean remove(Object source, Object o) { >+ int i = indexOf(source, o); >+ if (i == -1) >+ return false; >+ remove(source, i); >+ return true; >+ } >+ >+ public boolean removeAll(Object source, Collection c) { >+ if (isEmpty(source)) { >+ return false; >+ } >+ if (c.isEmpty()) { >+ return false; >+ } >+ List list = new ArrayList(getList(source)); >+ List entries = new ArrayList(); >+ for (ListIterator it = list.listIterator(); it.hasNext();) { >+ Object o = it.next(); >+ if (c.contains(o)) { >+ entries.add(Diffs.createListDiffEntry(it.previousIndex(), >+ false, o)); >+ it.remove(); >+ } >+ } >+ boolean changed = !entries.isEmpty(); >+ if (changed) { >+ ListDiffEntry[] ea = (ListDiffEntry[]) entries >+ .toArray(new ListDiffEntry[entries.size()]); >+ setList(source, list, Diffs.createListDiff(ea)); >+ } >+ return changed; >+ } >+ >+ public boolean retainAll(Object source, Collection c) { >+ if (isEmpty(source)) { >+ return false; >+ } >+ if (c.isEmpty()) { >+ clear(source); >+ return true; >+ } >+ List list = new ArrayList(getList(source)); >+ List entries = new ArrayList(); >+ for (ListIterator it = list.listIterator(); it.hasNext();) { >+ Object o = it.next(); >+ if (!c.contains(o)) { >+ entries.add(Diffs.createListDiffEntry(it.previousIndex(), >+ false, o)); >+ it.remove(); >+ } >+ } >+ boolean changed = !entries.isEmpty(); >+ if (changed) { >+ ListDiffEntry[] ea = (ListDiffEntry[]) entries >+ .toArray(new ListDiffEntry[entries.size()]); >+ setList(source, list, Diffs.createListDiff(ea)); >+ } >+ return changed; >+ } >+ >+ public void add(Object source, int index, Object element) { >+ List list = new ArrayList(getList(source)); >+ list.add(index, element); >+ setList(source, list, Diffs.createListDiff(Diffs.createListDiffEntry( >+ index, true, element))); >+ } >+ >+ public boolean addAll(Object source, int index, Collection c) { >+ if (c.isEmpty()) { >+ return false; >+ } >+ >+ List list = new ArrayList(getList(source)); >+ List entries = new ArrayList(); >+ int i = index; >+ for (Iterator it = c.iterator(); it.hasNext(); i++) { >+ Object o = it.next(); >+ list.add(i, o); >+ entries.add(Diffs.createListDiffEntry(i, true, o)); >+ } >+ boolean changed = !entries.isEmpty(); >+ if (changed) { >+ ListDiffEntry[] ea = (ListDiffEntry[]) entries >+ .toArray(new ListDiffEntry[entries.size()]); >+ setList(source, list, Diffs.createListDiff(ea)); >+ } >+ return changed; >+ } >+ >+ public Object remove(Object source, int index) { >+ List list = new ArrayList(getList(source)); >+ Object result = list.remove(index); >+ setList(source, list, Diffs.createListDiff(Diffs.createListDiffEntry( >+ index, false, result))); >+ return result; >+ } >+ >+ public Object set(Object source, int index, Object element) { >+ List list = new ArrayList(getList(source)); >+ Object result = list.set(index, element); >+ setList(source, list, Diffs.createListDiff(Diffs.createListDiffEntry( >+ index, false, result), Diffs.createListDiffEntry(index, true, >+ element))); >+ return result; >+ } >+ >+ public Object move(Object source, int oldIndex, int newIndex) { >+ if (oldIndex == newIndex) >+ return get(source, oldIndex); >+ List list = new ArrayList(getList(source)); >+ Object result = list.remove(oldIndex); >+ list.add(newIndex, result); >+ setList(source, list, Diffs.createListDiff(Diffs.createListDiffEntry( >+ oldIndex, false, result), Diffs.createListDiffEntry(newIndex, >+ true, result))); >+ return result; >+ } >+ >+ public Object getElementType() { >+ return elementType; >+ } >+ >+ public PropertyDescriptor getPropertyDescriptor() { >+ return propertyDescriptor; >+ } >+ >+ public synchronized void dispose() { >+ propertyDescriptor = null; >+ elementType = null; >+ attachListener = false; >+ if (listenerSupport != null) { >+ listenerSupport.dispose(); >+ listenerSupport = null; >+ } >+ if (updateHelper != null) { >+ updateHelper.dispose(); >+ updateHelper = null; >+ } >+ if (sourceToCachedList != null) { >+ sourceToCachedList.clear(); >+ sourceToCachedList = null; >+ } >+ super.dispose(); >+ } >+} >Index: src/org/eclipse/core/internal/databinding/beans/BeanSetProperty.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/beans/BeanSetProperty.java >diff -N src/org/eclipse/core/internal/databinding/beans/BeanSetProperty.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/beans/BeanSetProperty.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,271 @@ >+/******************************************************************************* >+ * 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.beans; >+ >+import java.beans.PropertyChangeEvent; >+import java.beans.PropertyChangeListener; >+import java.beans.PropertyDescriptor; >+import java.lang.reflect.Array; >+import java.util.Arrays; >+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.beans.IBeanProperty; >+import org.eclipse.core.databinding.observable.Diffs; >+import org.eclipse.core.databinding.observable.set.SetDiff; >+import org.eclipse.core.databinding.property.SetProperty; >+ >+/** >+ * @since 3.3 >+ * >+ */ >+public class BeanSetProperty extends SetProperty implements IBeanProperty { >+ private PropertyDescriptor propertyDescriptor; >+ private Class elementType; >+ private boolean attachListener; >+ >+ private ListenerSupport listenerSupport; >+ >+ private PropertyUpdateHelper updateHelper = new PropertyUpdateHelper(); >+ >+ private Map sourceToCachedSet = Collections.synchronizedMap(new HashMap()); >+ >+ /** >+ * @param propertyDescriptor >+ * @param elementType >+ * @param attachListener >+ */ >+ public BeanSetProperty(PropertyDescriptor propertyDescriptor, >+ Class elementType, boolean attachListener) { >+ this.propertyDescriptor = propertyDescriptor; >+ this.elementType = elementType == null ? BeanPropertyHelper >+ .getCollectionPropertyElementType(propertyDescriptor) >+ : elementType; >+ this.attachListener = attachListener; >+ } >+ >+ private void initListenerSupport() { >+ if (listenerSupport == null) { >+ synchronized (this) { >+ if (listenerSupport == null) { >+ PropertyChangeListener propertyChangeListener = new PropertyChangeListener() { >+ public void propertyChange(PropertyChangeEvent evt) { >+ Object source = evt.getSource(); >+ if (!updateHelper.isUpdating(source)) { >+ Object oldValue = evt.getOldValue(); >+ Object newValue = evt.getNewValue(); >+ if (oldValue == null && newValue == null) { >+ // Obscure condition indicating new and old >+ // values are unknown >+ oldValue = sourceToCachedSet.get(source); >+ newValue = BeanPropertyHelper.getProperty( >+ source, propertyDescriptor); >+ } >+ sourceToCachedSet.put(source, newValue); >+ fireSetChange(source, Diffs.computeSetDiff( >+ asSet(oldValue), asSet(newValue))); >+ } >+ } >+ }; >+ listenerSupport = new ListenerSupport( >+ propertyChangeListener, propertyDescriptor >+ .getName()); >+ } >+ } >+ } >+ } >+ >+ protected void addListenerTo(Object source) { >+ if (source != null && attachListener) { >+ initListenerSupport(); >+ listenerSupport.hookListener(source); >+ sourceToCachedSet.put(source, BeanPropertyHelper.getProperty( >+ source, propertyDescriptor)); >+ } >+ } >+ >+ protected void removeListenerFrom(Object source) { >+ if (source != null && attachListener && listenerSupport != null) { >+ listenerSupport.unhookListener(source); >+ sourceToCachedSet.remove(source); >+ } >+ } >+ >+ public Set getSet(Object source) { >+ if (source == null) >+ return Collections.EMPTY_SET; >+ Object propertyValue = BeanPropertyHelper.getProperty(source, >+ propertyDescriptor); >+ return asSet(propertyValue); >+ } >+ >+ private Set asSet(Object propertyValue) { >+ if (propertyValue == null) >+ return Collections.EMPTY_SET; >+ if (propertyDescriptor.getPropertyType().isArray()) >+ return new HashSet(Arrays.asList((Object[]) propertyValue)); >+ return (Set) propertyValue; >+ } >+ >+ private void setSet(Object source, Set set, SetDiff diff) { >+ if (source == null) >+ return; >+ >+ if (diff == null) { >+ diff = Diffs.computeSetDiff(getSet(source), set); >+ } >+ >+ updateHelper.setUpdating(source, true); >+ try { >+ BeanPropertyHelper.setProperty(source, propertyDescriptor, >+ convertSetToBeanPropertyType(set)); >+ } finally { >+ updateHelper.setUpdating(source, false); >+ } >+ >+ if (hasListeners(source)) { >+ sourceToCachedSet.put(source, set); >+ fireSetChange(source, diff); >+ } >+ } >+ >+ private Object convertSetToBeanPropertyType(Set set) { >+ Object propertyValue = set; >+ if (propertyDescriptor.getPropertyType().isArray()) { >+ Class componentType = propertyDescriptor.getPropertyType() >+ .getComponentType(); >+ Object[] array = (Object[]) Array.newInstance(componentType, set >+ .size()); >+ set.toArray(array); >+ propertyValue = array; >+ } >+ return propertyValue; >+ } >+ >+ public boolean add(Object source, Object o) { >+ Set set = getSet(source); >+ if (!set.contains(o)) { >+ set = new HashSet(set); >+ boolean added = set.add(o); >+ if (added) >+ setSet(source, set, Diffs.createSetDiff(Collections >+ .singleton(o), Collections.EMPTY_SET)); >+ return added; >+ } >+ return false; >+ } >+ >+ public boolean addAll(Object source, Collection c) { >+ Set set = getSet(source); >+ Set additions = new HashSet(); >+ for (Iterator it = c.iterator(); it.hasNext();) { >+ Object o = it.next(); >+ if (!set.contains(o)) { >+ additions.add(o); >+ } >+ } >+ boolean changed = !additions.isEmpty(); >+ if (changed) { >+ set = new HashSet(set); >+ set.addAll(additions); >+ setSet(source, set, Diffs.createSetDiff(additions, >+ Collections.EMPTY_SET)); >+ } >+ return changed; >+ } >+ >+ public void clear(Object source) { >+ setSet(source, new HashSet(), Diffs.createSetDiff( >+ Collections.EMPTY_SET, getSet(source))); >+ } >+ >+ public boolean remove(Object source, Object o) { >+ Set set = getSet(source); >+ if (set.contains(o)) { >+ set = new HashSet(set); >+ boolean removed = set.remove(o); >+ if (removed) >+ setSet(source, set, Diffs.createSetDiff(Collections.EMPTY_SET, >+ Collections.singleton(o))); >+ return removed; >+ } >+ return false; >+ } >+ >+ public boolean removeAll(Object source, Collection c) { >+ Set set = new HashSet(getSet(source)); >+ Set removals = new HashSet(); >+ for (Iterator it = set.iterator(); it.hasNext();) { >+ Object o = it.next(); >+ if (c.contains(o)) { >+ removals.add(o); >+ it.remove(); >+ } >+ } >+ boolean changed = !removals.isEmpty(); >+ if (changed) { >+ setSet(source, set, Diffs.createSetDiff(Collections.EMPTY_SET, >+ removals)); >+ } >+ return changed; >+ } >+ >+ public boolean retainAll(Object source, Collection c) { >+ Set set = new HashSet(getSet(source)); >+ Set removals = new HashSet(); >+ for (Iterator it = set.iterator(); it.hasNext();) { >+ Object o = it.next(); >+ if (!c.contains(o)) { >+ removals.add(o); >+ it.remove(); >+ } >+ } >+ boolean changed = !removals.isEmpty(); >+ if (changed) { >+ setSet(source, set, Diffs.createSetDiff(Collections.EMPTY_SET, >+ removals)); >+ } >+ return changed; >+ } >+ >+ public Object getElementType() { >+ return elementType; >+ } >+ >+ public PropertyDescriptor getPropertyDescriptor() { >+ return propertyDescriptor; >+ } >+ >+ public synchronized void dispose() { >+ propertyDescriptor = null; >+ elementType = null; >+ attachListener = false; >+ if (listenerSupport != null) { >+ listenerSupport.dispose(); >+ listenerSupport = null; >+ } >+ if (updateHelper != null) { >+ updateHelper.dispose(); >+ updateHelper = null; >+ } >+ if (sourceToCachedSet != null) { >+ sourceToCachedSet.clear(); >+ sourceToCachedSet = null; >+ } >+ super.dispose(); >+ } >+} >Index: src/org/eclipse/core/databinding/beans/BeanProperties.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/beans/BeanProperties.java >diff -N src/org/eclipse/core/databinding/beans/BeanProperties.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/beans/BeanProperties.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,110 @@ >+/******************************************************************************* >+ * 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.beans; >+ >+import org.eclipse.core.databinding.property.IListProperty; >+import org.eclipse.core.databinding.property.IMapProperty; >+import org.eclipse.core.databinding.property.ISetProperty; >+import org.eclipse.core.databinding.property.IValueProperty; >+import org.eclipse.core.internal.databinding.beans.BeanListProperty; >+import org.eclipse.core.internal.databinding.beans.BeanMapProperty; >+import org.eclipse.core.internal.databinding.beans.BeanPropertyHelper; >+import org.eclipse.core.internal.databinding.beans.BeanSetProperty; >+import org.eclipse.core.internal.databinding.beans.BeanValueProperty; >+ >+/** >+ * @since 1.2 >+ * >+ */ >+public class BeanProperties { >+ /** >+ * @param beanClass >+ * @param propertyName >+ * @return a value property for the given property name of the given bean >+ * class. >+ */ >+ public static IValueProperty valueProperty(Class beanClass, >+ String propertyName) { >+ return valueProperty(beanClass, propertyName, null); >+ } >+ >+ /** >+ * @param beanClass >+ * @param propertyName >+ * @param valueType >+ * @return a value property for the given property name of the given bean >+ * class. >+ */ >+ public static IValueProperty valueProperty(Class beanClass, >+ String propertyName, Class valueType) { >+ return new BeanValueProperty(BeanPropertyHelper.getPropertyDescriptor( >+ beanClass, propertyName), valueType, true); >+ } >+ >+ /** >+ * @param beanClass >+ * @param propertyName >+ * @return a list property for the given property name of the given bean >+ * class. >+ */ >+ public static ISetProperty setProperty(Class beanClass, String propertyName) { >+ return setProperty(beanClass, propertyName, null); >+ } >+ >+ /** >+ * @param beanClass >+ * @param propertyName >+ * @param elementType >+ * @return a list property for the given property name of the given bean >+ * class. >+ */ >+ public static ISetProperty setProperty(Class beanClass, >+ String propertyName, Class elementType) { >+ return new BeanSetProperty(BeanPropertyHelper.getPropertyDescriptor( >+ beanClass, propertyName), elementType, true); >+ } >+ >+ /** >+ * @param beanClass >+ * @param propertyName >+ * @return a list property for the given property name of the given bean >+ * class. >+ */ >+ public static IListProperty listProperty(Class beanClass, >+ String propertyName) { >+ return listProperty(beanClass, propertyName, null); >+ } >+ >+ /** >+ * @param beanClass >+ * @param propertyName >+ * @param elementType >+ * @return a list property for the given property name of the given bean >+ * class. >+ */ >+ public static IListProperty listProperty(Class beanClass, >+ String propertyName, Class elementType) { >+ return new BeanListProperty(BeanPropertyHelper.getPropertyDescriptor( >+ beanClass, propertyName), elementType, true); >+ } >+ >+ /** >+ * @param beanClass >+ * @param propertyName >+ * @return a map property for the given property name of the given bean >+ * class. >+ */ >+ public static IMapProperty mapProperty(Class beanClass, String propertyName) { >+ return new BeanMapProperty(BeanPropertyHelper.getPropertyDescriptor( >+ beanClass, propertyName), true); >+ } >+} >Index: src/org/eclipse/core/internal/databinding/beans/BeanPropertyHelper.java >=================================================================== >RCS file: src/org/eclipse/core/internal/databinding/beans/BeanPropertyHelper.java >diff -N src/org/eclipse/core/internal/databinding/beans/BeanPropertyHelper.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/internal/databinding/beans/BeanPropertyHelper.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,169 @@ >+/******************************************************************************* >+ * 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.beans; >+ >+import java.beans.BeanInfo; >+import java.beans.IntrospectionException; >+import java.beans.Introspector; >+import java.beans.PropertyDescriptor; >+import java.lang.reflect.InvocationTargetException; >+import java.lang.reflect.Method; >+ >+import org.eclipse.core.databinding.BindingException; >+import org.eclipse.core.databinding.beans.BeansObservables; >+import org.eclipse.core.databinding.observable.value.IObservableValue; >+import org.eclipse.core.databinding.util.Policy; >+import org.eclipse.core.runtime.IStatus; >+import org.eclipse.core.runtime.Status; >+ >+/** >+ * @since 1.2 >+ * >+ */ >+public class BeanPropertyHelper { >+ /** >+ * Sets the contents of the given property on the given source object to the >+ * given value. >+ * >+ * @param source >+ * the source object which has the property being updated >+ * @param propertyDescriptor >+ * the property being changed >+ * @param value >+ * the new value of the property >+ */ >+ public static void setProperty(Object source, >+ PropertyDescriptor propertyDescriptor, Object value) { >+ try { >+ Method writeMethod = propertyDescriptor.getWriteMethod(); >+ if (!writeMethod.isAccessible()) { >+ writeMethod.setAccessible(true); >+ } >+ writeMethod.invoke(source, new Object[] { value }); >+ } catch (InvocationTargetException e) { >+ /* >+ * InvocationTargetException wraps any exception thrown by the >+ * invoked method. >+ */ >+ throw new RuntimeException(e.getCause()); >+ } catch (Exception e) { >+ if (BeansObservables.DEBUG) { >+ Policy >+ .getLog() >+ .log( >+ new Status( >+ IStatus.WARNING, >+ Policy.JFACE_DATABINDING, >+ IStatus.OK, >+ "Could not change value of " + source + "." + propertyDescriptor.getName(), e)); //$NON-NLS-1$ //$NON-NLS-2$ >+ } >+ } >+ } >+ >+ /** >+ * Returns the contents of the given property for the given bean. >+ * >+ * @param source >+ * the source bean >+ * @param propertyDescriptor >+ * the property to retrieve >+ * @return the contents of the given property for the given bean. >+ */ >+ public static Object getProperty(Object source, >+ PropertyDescriptor propertyDescriptor) { >+ try { >+ Method readMethod = propertyDescriptor.getReadMethod(); >+ if (readMethod == null) { >+ throw new BindingException(propertyDescriptor.getName() >+ + " property does not have a read method."); //$NON-NLS-1$ >+ } >+ if (!readMethod.isAccessible()) { >+ readMethod.setAccessible(true); >+ } >+ return readMethod.invoke(source, null); >+ } catch (InvocationTargetException e) { >+ /* >+ * InvocationTargetException wraps any exception thrown by the >+ * invoked method. >+ */ >+ throw new RuntimeException(e.getCause()); >+ } catch (Exception e) { >+ if (BeansObservables.DEBUG) { >+ Policy >+ .getLog() >+ .log( >+ new Status( >+ IStatus.WARNING, >+ Policy.JFACE_DATABINDING, >+ IStatus.OK, >+ "Could not read value of " + source + "." + propertyDescriptor.getName(), e)); //$NON-NLS-1$ //$NON-NLS-2$ >+ } >+ return null; >+ } >+ } >+ >+ /** >+ * Returns the element type of the given collection-typed property for the >+ * given bean. >+ * >+ * @param descriptor >+ * the property being inspected >+ * @return the element type of the given collection-typed property if it is >+ * an array property, or Object.class otherwise. >+ */ >+ public static Class getCollectionPropertyElementType( >+ PropertyDescriptor descriptor) { >+ Class propertyType = descriptor.getPropertyType(); >+ return propertyType.isArray() ? propertyType.getComponentType() >+ : Object.class; >+ } >+ >+ /** >+ * @param beanClass >+ * @param propertyName >+ * @return the PropertyDescriptor for the named property on the given bean >+ * class >+ */ >+ public static PropertyDescriptor getPropertyDescriptor(Class beanClass, >+ String propertyName) { >+ BeanInfo beanInfo; >+ try { >+ beanInfo = Introspector.getBeanInfo(beanClass); >+ } catch (IntrospectionException e) { >+ // cannot introspect, give up >+ return null; >+ } >+ PropertyDescriptor[] propertyDescriptors = beanInfo >+ .getPropertyDescriptors(); >+ for (int i = 0; i < propertyDescriptors.length; i++) { >+ PropertyDescriptor descriptor = propertyDescriptors[i]; >+ if (descriptor.getName().equals(propertyName)) { >+ return descriptor; >+ } >+ } >+ throw new BindingException( >+ "Could not find property with name " + propertyName + " in class " + beanClass); //$NON-NLS-1$ //$NON-NLS-2$ >+ } >+ >+ /** >+ * @param observable >+ * @param propertyName >+ * @return property descriptor or <code>null</code> >+ */ >+ /* package */public static PropertyDescriptor getValueTypePropertyDescriptor( >+ IObservableValue observable, String propertyName) { >+ if (observable.getValueType() != null) >+ return getPropertyDescriptor((Class) observable.getValueType(), >+ propertyName); >+ return null; >+ } >+}
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