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 111448 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]
Added experimental MasterDetailProperties
clipboard.txt (text/plain), 139.01 KB, created by
Matthew Hall
on 2008-09-02 01:11:34 EDT
(
hide
)
Description:
Added experimental MasterDetailProperties
Filename:
MIME Type:
Creator:
Matthew Hall
Created:
2008-09-02 01:11:34 EDT
Size:
139.01 KB
patch
obsolete
>### Eclipse Workspace Patch 1.0 >#P org.eclipse.core.databinding.beans >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 2 Sep 2008 04:58:13 -0000 >@@ -27,15 +27,11 @@ > 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.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.runtime.Assert; > > /** >@@ -83,9 +79,8 @@ > */ > public static IObservableValue observeValue(Realm realm, Object bean, > String propertyName) { >- PropertyDescriptor descriptor = getPropertyDescriptor(bean.getClass(), >- propertyName); >- return new JavaBeanObservableValue(realm, bean, descriptor); >+ return PropertyObservables.observeValue(realm, bean, BeanProperties >+ .valueProperty(bean.getClass(), propertyName)); > } > > /** >@@ -103,9 +98,8 @@ > */ > public static IObservableMap observeMap(IObservableSet domain, > Class beanClass, String propertyName) { >- PropertyDescriptor descriptor = getPropertyDescriptor(beanClass, >- propertyName); >- return new JavaBeanObservableMap(domain, descriptor); >+ return PropertyObservables.observeMap(domain, BeanProperties >+ .valueProperty(beanClass, propertyName)); > } > > /** >@@ -124,9 +118,8 @@ > */ > public static IObservableMap observeMap(Realm realm, Object bean, > String propertyName) { >- PropertyDescriptor descriptor = getPropertyDescriptor(bean.getClass(), >- propertyName); >- return new JavaBeanPropertyObservableMap(realm, bean, descriptor); >+ return PropertyObservables.observeMap(realm, bean, BeanProperties >+ .mapProperty(bean.getClass(), propertyName)); > } > > /** >@@ -145,8 +138,8 @@ > return observeMap(Realm.getDefault(), bean, propertyName); > } > >- /*package*/ static PropertyDescriptor getPropertyDescriptor(Class beanClass, >- String propertyName) { >+ /* package */static PropertyDescriptor getPropertyDescriptor( >+ Class beanClass, String propertyName) { > BeanInfo beanInfo; > try { > beanInfo = Introspector.getBeanInfo(beanClass); >@@ -231,9 +224,9 @@ > * collection-typed named property of the given bean object. The returned > * list is mutable. When an item is added or removed the setter is invoked > * for the list on the parent bean to provide notification to other >- * listeners via <code>PropertyChangeEvents</code>. This is done to >- * provide the same behavior as is expected from arrays as specified in the >- * bean spec in section 7.2. >+ * listeners via <code>PropertyChangeEvents</code>. This is done to provide >+ * the same behavior as is expected from arrays as specified in the bean >+ * spec in section 7.2. > * > * @param realm > * the realm >@@ -242,8 +235,8 @@ > * @param propertyName > * the name of the property > * @param elementType >- * type of the elements in the list. If <code>null</code> and >- * the property is an array the type will be inferred. If >+ * type of the elements in the list. If <code>null</code> and the >+ * property is an array the type will be inferred. If > * <code>null</code> and the property type cannot be inferred > * element type will be <code>null</code>. > * @return an observable list tracking the collection-typed named property >@@ -251,12 +244,8 @@ > */ > public static IObservableList observeList(Realm realm, Object bean, > String propertyName, Class elementType) { >- PropertyDescriptor propertyDescriptor = getPropertyDescriptor(bean >- .getClass(), propertyName); >- elementType = getCollectionElementType(elementType, propertyDescriptor); >- >- return new JavaBeanObservableList(realm, bean, propertyDescriptor, >- elementType); >+ return PropertyObservables.observeList(realm, bean, BeanProperties >+ .listProperty(bean.getClass(), propertyName, elementType)); > } > > /** >@@ -439,11 +428,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, master, >+ getValueTypePropertyDescriptor(master, propertyName)); > } > > /** >@@ -469,10 +455,9 @@ > /** > * Helper method for > * <code>MasterDetailObservables.detailValue(master, valueFactory(realm, >- * propertyName), propertyType)</code>. >- * This method returns an {@link IBeanObservable} with a >- * {@link PropertyDescriptor} based on the given master type and property >- * name. >+ * propertyName), propertyType)</code>. This method returns an >+ * {@link IBeanObservable} with a {@link PropertyDescriptor} based on the >+ * given master type and property name. > * > * @param realm > * the realm >@@ -492,15 +477,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, master, >+ getPropertyDescriptor(masterType, propertyName)); > } > > /** >@@ -551,11 +534,8 @@ > IObservableList observableList = MasterDetailObservables.detailList( > master, listFactory(realm, propertyName, propertyType), > propertyType); >- BeanObservableListDecorator decorator = new BeanObservableListDecorator( >- observableList, master, getValueTypePropertyDescriptor(master, >- propertyName)); >- >- return decorator; >+ return new BeanObservableListDecorator(observableList, master, >+ getValueTypePropertyDescriptor(master, propertyName)); > } > > /** >@@ -599,11 +579,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, master, >+ getValueTypePropertyDescriptor(master, propertyName)); > } > > /** >@@ -642,10 +619,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, master, >+ getValueTypePropertyDescriptor(master, propertyName)); > } > > /** >@@ -688,12 +663,8 @@ > */ > public static IObservableSet observeSet(Realm realm, Object bean, > String propertyName, Class elementType) { >- PropertyDescriptor propertyDescriptor = getPropertyDescriptor(bean >- .getClass(), propertyName); >- elementType = getCollectionElementType(elementType, propertyDescriptor); >- >- return new JavaBeanObservableSet(realm, bean, propertyDescriptor, >- elementType); >+ return PropertyObservables.observeSet(realm, bean, BeanProperties >+ .setProperty(bean.getClass(), propertyName, elementType)); > } > > /** >@@ -780,17 +751,19 @@ > * @param propertyName > * the name of the property > * @return a factory for creating {@link IObservableMap} objects >- * >+ * > * @since 1.1 > */ >- public static IObservableFactory setToMapFactory(final Class beanClass, final String propertyName) { >+ public static IObservableFactory setToMapFactory(final Class beanClass, >+ final String propertyName) { > return new IObservableFactory() { > public IObservable createObservable(Object target) { >- return observeMap((IObservableSet) target, beanClass, propertyName); >+ return observeMap((IObservableSet) target, beanClass, >+ propertyName); > } > }; > } >- >+ > /** > * Returns a factory for creating an observable map. The factory, when > * provided with a bean object, will create an {@link IObservableMap} in the >@@ -830,28 +803,11 @@ > } > > /** >- * @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( >+ /* 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 2 Sep 2008 04:58:13 -0000 >@@ -13,7 +13,6 @@ > package org.eclipse.core.databinding.beans; > > import java.beans.PropertyChangeEvent; >-import java.beans.PropertyDescriptor; > > import org.eclipse.core.databinding.observable.IObservable; > import org.eclipse.core.databinding.observable.Realm; >@@ -23,15 +22,11 @@ > 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.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; > > /** > * A factory for creating observable objects for POJOs (plain old java objects) >@@ -73,10 +68,8 @@ > */ > public static IObservableValue observeValue(Realm realm, Object pojo, > String propertyName) { >- >- PropertyDescriptor descriptor = BeansObservables.getPropertyDescriptor( >- pojo.getClass(), propertyName); >- return new JavaBeanObservableValue(realm, pojo, descriptor, false); >+ return PropertyObservables.observeValue(realm, pojo, PojoProperties >+ .valueProperty(pojo.getClass(), propertyName)); > } > > /** >@@ -94,9 +87,8 @@ > */ > public static IObservableMap observeMap(IObservableSet domain, > Class pojoClass, String propertyName) { >- PropertyDescriptor descriptor = BeansObservables.getPropertyDescriptor( >- pojoClass, propertyName); >- return new JavaBeanObservableMap(domain, descriptor, false); >+ return PropertyObservables.observeMap(domain, PojoProperties >+ .valueProperty(pojoClass, propertyName)); > } > > /** >@@ -136,9 +128,8 @@ > */ > public static IObservableMap observeMap(Realm realm, Object pojo, > String propertyName) { >- PropertyDescriptor descriptor = BeansObservables.getPropertyDescriptor( >- pojo.getClass(), propertyName); >- return new JavaBeanPropertyObservableMap(realm, pojo, descriptor, false); >+ return PropertyObservables.observeMap(realm, pojo, PojoProperties >+ .mapProperty(pojo.getClass(), propertyName)); > } > > /** >@@ -200,9 +191,9 @@ > * collection-typed named property of the given bean object. The returned > * list is mutable. When an item is added or removed the setter is invoked > * for the list on the parent bean to provide notification to other >- * listeners via <code>PropertyChangeEvents</code>. This is done to >- * provide the same behavior as is expected from arrays as specified in the >- * bean spec in section 7.2. >+ * listeners via <code>PropertyChangeEvents</code>. This is done to provide >+ * the same behavior as is expected from arrays as specified in the bean >+ * spec in section 7.2. > * > * @param realm > * the realm >@@ -211,8 +202,8 @@ > * @param propertyName > * the name of the property > * @param elementType >- * type of the elements in the list. If <code>null</code> and >- * the property is an array the type will be inferred. If >+ * type of the elements in the list. If <code>null</code> and the >+ * property is an array the type will be inferred. If > * <code>null</code> and the property type cannot be inferred > * element type will be <code>null</code>. > * @return an observable list tracking the collection-typed named property >@@ -220,13 +211,8 @@ > */ > 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); >+ return PropertyObservables.observeList(realm, pojo, PojoProperties >+ .listProperty(pojo.getClass(), propertyName, elementType)); > } > > /** >@@ -310,13 +296,8 @@ > */ > 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); >+ return PropertyObservables.observeSet(realm, pojo, PojoProperties >+ .setProperty(pojo.getClass(), propertyName, elementType)); > } > > /** >@@ -540,11 +521,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, master, BeansObservables >+ .getValueTypePropertyDescriptor(master, propertyName)); > } > > /** >@@ -587,11 +565,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, master, >+ BeansObservables.getValueTypePropertyDescriptor(master, >+ propertyName)); > } > > /** >@@ -635,11 +611,9 @@ > 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, master, >+ BeansObservables.getValueTypePropertyDescriptor(master, >+ propertyName)); > } > > /** >@@ -676,10 +650,9 @@ > 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, master, >+ BeansObservables.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 IBM Corporation and others. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * IBM Corporation - initial API and implementation >+ ******************************************************************************/ >+ >+package org.eclipse.core.databinding.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/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,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 >+ ******************************************************************************/ >+ >+package org.eclipse.core.internal.databinding.beans; >+ >+import java.beans.PropertyChangeEvent; >+import java.beans.PropertyChangeListener; >+import java.beans.PropertyDescriptor; >+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.observable.map.MapDiff; >+import org.eclipse.core.databinding.property.MapProperty; >+import org.eclipse.core.internal.databinding.Util; >+ >+/** >+ * @since 3.3 >+ * >+ */ >+public class BeanMapProperty extends MapProperty implements IBeanProperty { >+ private PropertyDescriptor propertyDescriptor; >+ private boolean attachListener; >+ >+ private boolean updating; >+ >+ private ListenerSupport listenerSupport; >+ >+ /** >+ * @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) { >+ if (!updating) { >+ MapDiff diff; >+ if (evt.getOldValue() == null >+ && evt.getNewValue() == null) { >+ // Obscure condition indicating new and old >+ // values are unknown >+ diff = null; >+ } else { >+ diff = Diffs.computeMapDiff(asMap(evt >+ .getOldValue()), asMap(evt >+ .getNewValue())); >+ } >+ fireMapChange(evt.getSource(), diff); >+ } >+ } >+ }; >+ listenerSupport = new ListenerSupport( >+ propertyChangeListener, propertyDescriptor >+ .getName()); >+ } >+ } >+ } >+ } >+ >+ protected void addListenerTo(Object source) { >+ if (attachListener) { >+ initListenerSupport(); >+ listenerSupport.hookListener(source); >+ } >+ } >+ >+ protected void removeListenerFrom(Object source) { >+ if (attachListener && listenerSupport != null) { >+ listenerSupport.unhookListener(source); >+ } >+ } >+ >+ public Map getMap(Object source) { >+ return asMap(BeanPropertyHelper.getProperty(source, propertyDescriptor)); >+ } >+ >+ private Map asMap(Object propertyValue) { >+ if (propertyValue == null) >+ return new HashMap(); >+ return (Map) propertyValue; >+ } >+ >+ public void setMap(Object source, Map map) { >+ Map oldMap = getMap(source); >+ >+ if (Util.equals(oldMap, map)) { >+ return; >+ } >+ >+ updating = true; >+ try { >+ BeanPropertyHelper.setProperty(source, propertyDescriptor, map); >+ } finally { >+ updating = false; >+ } >+ >+ Map newMap = getMap(source); >+ if (!Util.equals(oldMap, newMap)) { >+ fireMapChange(source, Diffs.computeMapDiff(oldMap, newMap)); >+ } >+ } >+ >+ public synchronized void dispose() { >+ if (listenerSupport != null) { >+ listenerSupport.dispose(); >+ listenerSupport = null; >+ } >+ propertyDescriptor = 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,135 @@ >+/******************************************************************************* >+ * Copyright (c) 2008 Matthew Hall and others. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * Matthew Hall - initial API and implementation >+ ******************************************************************************/ >+ >+package org.eclipse.core.internal.databinding.beans; >+ >+import java.beans.PropertyChangeEvent; >+import java.beans.PropertyChangeListener; >+import java.beans.PropertyDescriptor; >+ >+import org.eclipse.core.databinding.beans.IBeanProperty; >+import org.eclipse.core.databinding.observable.Diffs; >+import org.eclipse.core.databinding.observable.value.ValueDiff; >+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 boolean updating; >+ >+ private ListenerSupport listenerSupport; >+ >+ /** >+ * @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) { >+ if (!updating) { >+ ValueDiff diff; >+ if (evt.getOldValue() == null >+ && evt.getOldValue() == null) { >+ // Obscure condition indicating new and old >+ // values are unknown >+ diff = null; >+ } else { >+ diff = Diffs.createValueDiff(evt >+ .getOldValue(), evt.getNewValue()); >+ } >+ fireValueChange(evt.getSource(), diff); >+ } >+ } >+ }; >+ listenerSupport = new ListenerSupport( >+ propertyChangeListener, propertyDescriptor >+ .getName()); >+ } >+ } >+ } >+ } >+ >+ protected void addListenerTo(Object source) { >+ if (attachListener) { >+ initListenerSupport(); >+ listenerSupport.hookListener(source); >+ } >+ } >+ >+ protected void removeListenerFrom(Object source) { >+ if (attachListener && listenerSupport != null) { >+ listenerSupport.unhookListener(source); >+ } >+ } >+ >+ public Object getValue(Object source) { >+ return BeanPropertyHelper.getProperty(source, propertyDescriptor); >+ } >+ >+ public void setValue(Object source, Object value) { >+ Object oldValue = getValue(source); >+ >+ if (Util.equals(oldValue, value)) { >+ return; >+ } >+ >+ updating = true; >+ try { >+ BeanPropertyHelper.setProperty(source, propertyDescriptor, value); >+ } finally { >+ updating = false; >+ } >+ >+ Object newValue = getValue(source); >+ if (!Util.equals(oldValue, newValue)) { >+ fireValueChange(source, Diffs.createValueDiff(oldValue, newValue)); >+ } >+ } >+ >+ public Object getValueType() { >+ return valueType; >+ } >+ >+ public synchronized void dispose() { >+ if (listenerSupport != null) { >+ listenerSupport.dispose(); >+ listenerSupport = null; >+ } >+ propertyDescriptor = null; >+ super.dispose(); >+ } >+ >+ public PropertyDescriptor getPropertyDescriptor() { >+ return propertyDescriptor; >+ } >+} >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,108 @@ >+/******************************************************************************* >+ * Copyright (c) 2008 Matthew Hall and others. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * Matthew Hall - initial API and implementation >+ ******************************************************************************/ >+ >+package org.eclipse.core.databinding.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.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(BeansObservables.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(BeansObservables.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(BeansObservables.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(BeansObservables.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,157 @@ >+/******************************************************************************* >+ * Copyright (c) 2008 Matthew Hall and others. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * Matthew Hall - initial API and implementation >+ ******************************************************************************/ >+ >+package org.eclipse.core.internal.databinding.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.List; >+ >+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.property.ListProperty; >+import org.eclipse.core.internal.databinding.Util; >+ >+/** >+ * @since 3.3 >+ * >+ */ >+public class BeanListProperty extends ListProperty implements IBeanProperty { >+ private PropertyDescriptor propertyDescriptor; >+ private Class elementType; >+ private boolean attachListener; >+ >+ private boolean updating; >+ >+ private ListenerSupport listenerSupport; >+ >+ /** >+ * @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) { >+ if (!updating) { >+ ListDiff diff; >+ if (evt.getOldValue() == null >+ && evt.getOldValue() == null) { >+ // Obscure condition indicating new and old >+ // values are unknown >+ diff = null; >+ } else { >+ diff = Diffs.computeListDiff(asList(evt >+ .getOldValue()), asList(evt >+ .getNewValue())); >+ } >+ fireListChange(evt.getSource(), diff); >+ } >+ } >+ }; >+ listenerSupport = new ListenerSupport( >+ propertyChangeListener, propertyDescriptor >+ .getName()); >+ } >+ } >+ } >+ } >+ >+ protected void addListenerTo(Object source) { >+ if (attachListener) { >+ initListenerSupport(); >+ listenerSupport.hookListener(source); >+ } >+ } >+ >+ protected void removeListenerFrom(Object source) { >+ if (attachListener && listenerSupport != null) { >+ listenerSupport.unhookListener(source); >+ } >+ } >+ >+ public List getList(Object source) { >+ 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; >+ } >+ >+ public void setList(Object source, List list) { >+ List oldList = getList(source); >+ >+ if (Util.equals(oldList, list)) >+ return; >+ >+ updating = true; >+ try { >+ 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; >+ } >+ BeanPropertyHelper.setProperty(source, propertyDescriptor, >+ propertyValue); >+ } finally { >+ updating = false; >+ } >+ >+ List newList = getList(source); >+ if (!Util.equals(oldList, newList)) { >+ fireListChange(source, Diffs.computeListDiff(oldList, newList)); >+ } >+ } >+ >+ public Object getElementType() { >+ return elementType; >+ } >+ >+ public synchronized void dispose() { >+ if (listenerSupport != null) { >+ listenerSupport.dispose(); >+ listenerSupport = null; >+ } >+ propertyDescriptor = null; >+ super.dispose(); >+ } >+ >+ public PropertyDescriptor getPropertyDescriptor() { >+ return propertyDescriptor; >+ } >+} >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,157 @@ >+/******************************************************************************* >+ * Copyright (c) 2008 Matthew Hall and others. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * Matthew Hall - initial API and implementation >+ ******************************************************************************/ >+ >+package org.eclipse.core.internal.databinding.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.HashSet; >+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; >+import org.eclipse.core.internal.databinding.Util; >+ >+/** >+ * @since 3.3 >+ * >+ */ >+public class BeanSetProperty extends SetProperty implements IBeanProperty { >+ private PropertyDescriptor propertyDescriptor; >+ private Class elementType; >+ private boolean attachListener; >+ >+ private boolean updating; >+ >+ private ListenerSupport listenerSupport; >+ >+ /** >+ * @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) { >+ if (!updating) { >+ SetDiff diff; >+ if (evt.getOldValue() == null >+ && evt.getOldValue() == null) { >+ // Obscure condition indicating new and old >+ // values are unknown >+ diff = null; >+ } else { >+ diff = Diffs.computeSetDiff(asSet(evt >+ .getOldValue()), asSet(evt >+ .getNewValue())); >+ } >+ fireSetChange(evt.getSource(), diff); >+ } >+ } >+ }; >+ listenerSupport = new ListenerSupport( >+ propertyChangeListener, propertyDescriptor >+ .getName()); >+ } >+ } >+ } >+ } >+ >+ protected void addListenerTo(Object source) { >+ if (attachListener) { >+ initListenerSupport(); >+ listenerSupport.hookListener(source); >+ } >+ } >+ >+ protected void removeListenerFrom(Object source) { >+ if (attachListener && listenerSupport != null) { >+ listenerSupport.unhookListener(source); >+ } >+ } >+ >+ public Set getSet(Object source) { >+ Object propertyValue = BeanPropertyHelper.getProperty(source, >+ propertyDescriptor); >+ return asSet(propertyValue); >+ } >+ >+ private Set asSet(Object propertyValue) { >+ if (propertyValue == null) >+ return new HashSet(); >+ if (propertyDescriptor.getPropertyType().isArray()) >+ return new HashSet(Arrays.asList((Object[]) propertyValue)); >+ return (Set) propertyValue; >+ } >+ >+ public void setSet(Object source, Set set) { >+ Set oldSet = getSet(source); >+ >+ if (Util.equals(oldSet, set)) >+ return; >+ >+ updating = true; >+ try { >+ 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; >+ } >+ BeanPropertyHelper.setProperty(source, propertyDescriptor, >+ propertyValue); >+ } finally { >+ updating = false; >+ } >+ >+ Set newSet = new HashSet(getSet(source)); >+ if (!Util.equals(oldSet, newSet)) { >+ fireSetChange(source, Diffs.computeSetDiff(oldSet, newSet)); >+ } >+ } >+ >+ public Object getElementType() { >+ return elementType; >+ } >+ >+ public synchronized void dispose() { >+ if (listenerSupport != null) { >+ listenerSupport.dispose(); >+ listenerSupport = null; >+ } >+ propertyDescriptor = null; >+ super.dispose(); >+ } >+ >+ public PropertyDescriptor getPropertyDescriptor() { >+ return propertyDescriptor; >+ } >+} >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,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 >+ ******************************************************************************/ >+ >+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.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(BeansObservables.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(BeansObservables.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(BeansObservables.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(BeansObservables.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,124 @@ >+/******************************************************************************* >+ * Copyright (c) 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 >+ ******************************************************************************/ >+ >+package org.eclipse.core.internal.databinding.beans; >+ >+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.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; >+ } >+} >#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 2 Sep 2008 04:58:14 -0000 >@@ -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) { >@@ -163,4 +163,16 @@ > * @return the old value for the given key > */ > protected abstract Object doPut(Object key, Object value); >+ >+ public void dispose() { >+ if (keySet != null) { >+ Object[] keys = keySet.toArray(); >+ for (int i = 0; i < keys.length; i++) { >+ unhookListener(keys[i]); >+ } >+ keySet = null; >+ } >+ entrySet = null; >+ super.dispose(); >+ } > } >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 2 Sep 2008 04:58:14 -0000 >@@ -14,6 +14,7 @@ > 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.util, > org.eclipse.core.databinding.validation;x-internal:=false, > org.eclipse.core.internal.databinding;x-friends:="org.eclipse.core.databinding.beans", >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,51 @@ >+/******************************************************************************* >+ * Copyright (c) 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 >+ ******************************************************************************/ >+ >+package org.eclipse.core.databinding.property; >+ >+import java.util.List; >+ >+/** >+ * @since 1.2 >+ * >+ */ >+public interface IListProperty extends IProperty { >+ /** >+ * @param source >+ * @return the list property of the given source >+ */ >+ public List getList(Object source); >+ >+ /** >+ * @param source >+ * @param list >+ */ >+ public void setList(Object source, List list); >+ >+ /** >+ * @return the type of the elements or <code>null</code> if untyped >+ */ >+ public Object getElementType(); >+ >+ /** >+ * @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,51 @@ >+/******************************************************************************* >+ * Copyright (c) 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 >+ ******************************************************************************/ >+ >+package org.eclipse.core.databinding.property; >+ >+import java.util.Set; >+ >+/** >+ * @since 1.2 >+ * >+ */ >+public interface ISetProperty extends IProperty { >+ /** >+ * @param source >+ * @return the list property of the given source >+ */ >+ public Set getSet(Object source); >+ >+ /** >+ * @param source >+ * @param set >+ */ >+ public void setSet(Object source, Set set); >+ >+ /** >+ * @return the type of the elements or <code>null</code> if untyped >+ */ >+ public Object getElementType(); >+ >+ /** >+ * @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/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,50 @@ >+/******************************************************************************* >+ * Copyright (c) 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 >+ ******************************************************************************/ >+ >+package org.eclipse.core.databinding.property; >+ >+import org.eclipse.core.databinding.observable.value.ValueDiff; >+ >+/** >+ * @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; >+ 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,34 @@ >+/******************************************************************************* >+ * Copyright (c) 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 >+ ******************************************************************************/ >+ >+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 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,34 @@ >+/******************************************************************************* >+ * Copyright (c) 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 >+ ******************************************************************************/ >+ >+package org.eclipse.core.databinding.property; >+ >+import org.eclipse.core.databinding.observable.list.ListDiff; >+ >+/** >+ * @since 1.2 >+ */ >+public abstract class ListProperty extends Property implements IListProperty { >+ 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,208 @@ >+/******************************************************************************* >+ * Copyright (c) 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 >+ ******************************************************************************/ >+ >+package org.eclipse.core.internal.databinding.property; >+ >+import java.util.Collection; >+import java.util.Collections; >+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.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 { >+ private Object source; >+ private IMapProperty property; >+ >+ private Map cachedMap; >+ >+ 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++; >+ if (event.diff == null) { >+ Map oldMap = cachedMap; >+ Map newMap = cachedMap = property >+ .getMap(source); >+ fireMapChange(Diffs.computeMapDiff(oldMap, >+ newMap)); >+ } else { >+ 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; >+ >+ this.cachedMap = property.getMap(source); >+ } >+ >+ private void getterCalled() { >+ ObservableTracker.getterCalled(this); >+ } >+ >+ protected void firstListenerAdded() { >+ if (!disposed) { >+ property.addMapChangeListener(source, listener); >+ } >+ } >+ >+ protected void lastListenerRemoved() { >+ if (!disposed) { >+ property.removeMapChangeListener(source, listener); >+ } >+ } >+ >+ private Map getMap() { >+ return property.getMap(source); >+ } >+ >+ private void setMap(Map set) { >+ Map oldMap = cachedMap; >+ >+ updating = true; >+ try { >+ property.setMap(source, new HashMap(set)); >+ modCount++; >+ } finally { >+ updating = false; >+ } >+ >+ Map newMap = cachedMap = getMap(); >+ if (!oldMap.equals(newMap)) { >+ fireMapChange(Diffs.computeMapDiff(oldMap, newMap)); >+ } >+ } >+ >+ public boolean containsKey(Object key) { >+ getterCalled(); >+ return getMap().containsKey(key); >+ } >+ >+ public boolean containsValue(Object value) { >+ getterCalled(); >+ return getMap().containsValue(value); >+ } >+ >+ public Set entrySet() { >+ getterCalled(); >+ // unmodifiable for now >+ return Collections.unmodifiableSet(getMap().entrySet()); >+ } >+ >+ public boolean equals(Object o) { >+ getterCalled(); >+ return getMap().equals(o); >+ } >+ >+ public Object get(Object key) { >+ getterCalled(); >+ return getMap().get(key); >+ } >+ >+ public int hashCode() { >+ getterCalled(); >+ return getMap().hashCode(); >+ } >+ >+ public boolean isEmpty() { >+ getterCalled(); >+ return getMap().isEmpty(); >+ } >+ >+ public Set keySet() { >+ getterCalled(); >+ return Collections.unmodifiableSet(getMap().keySet()); >+ } >+ >+ public Object put(Object key, Object value) { >+ checkRealm(); >+ Map map = new HashMap(getMap()); >+ Object result = map.put(key, value); >+ setMap(map); >+ return result; >+ } >+ >+ public void putAll(Map m) { >+ checkRealm(); >+ Map map = new HashMap(getMap()); >+ map.putAll(m); >+ setMap(map); >+ } >+ >+ public Object remove(Object key) { >+ checkRealm(); >+ Map map = new HashMap(getMap()); >+ Object result = map.remove(key); >+ setMap(map); >+ return result; >+ } >+ >+ public int size() { >+ getterCalled(); >+ return getMap().size(); >+ } >+ >+ public Collection values() { >+ getterCalled(); >+ return Collections.unmodifiableCollection(getMap().values()); >+ } >+ >+ public void clear() { >+ getterCalled(); >+ setMap(new HashMap()); >+ } >+ >+ 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,48 @@ >+/******************************************************************************* >+ * Copyright (c) 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 >+ ******************************************************************************/ >+ >+package org.eclipse.core.databinding.property; >+ >+import org.eclipse.core.databinding.observable.set.SetDiff; >+ >+/** >+ * @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; >+ 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 IBM Corporation and others. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * IBM Corporation - initial API and implementation >+ ******************************************************************************/ >+ >+package org.eclipse.core.databinding.property; >+ >+/** >+ * @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,46 @@ >+/******************************************************************************* >+ * Copyright (c) 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 >+ ******************************************************************************/ >+ >+package org.eclipse.core.databinding.property; >+ >+import java.util.Map; >+ >+/** >+ * @since 1.2 >+ * >+ */ >+public interface IMapProperty extends IProperty { >+ /** >+ * @param source >+ * @return the list property of the given source >+ */ >+ public Map getMap(Object source); >+ >+ /** >+ * @param source >+ * @param map >+ */ >+ public void setMap(Object source, Map map); >+ >+ /** >+ * @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 IBM Corporation and others. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * IBM Corporation - initial API and implementation >+ ******************************************************************************/ >+ >+package org.eclipse.core.databinding.property; >+ >+/** >+ * @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 IBM Corporation and others. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * IBM Corporation - initial API and implementation >+ ******************************************************************************/ >+ >+package org.eclipse.core.databinding.property; >+ >+/** >+ * @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 IBM Corporation and others. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * IBM Corporation - initial API and implementation >+ ******************************************************************************/ >+ >+package org.eclipse.core.databinding.property; >+ >+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/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,319 @@ >+/******************************************************************************* >+ * Copyright (c) 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 >+ ******************************************************************************/ >+ >+package org.eclipse.core.internal.databinding.property; >+ >+import java.util.AbstractSet; >+import java.util.HashMap; >+import java.util.HashSet; >+import java.util.Iterator; >+import java.util.Map; >+import java.util.Set; >+ >+import org.eclipse.core.databinding.observable.Diffs; >+import org.eclipse.core.databinding.observable.IStaleListener; >+import org.eclipse.core.databinding.observable.ObservableTracker; >+import org.eclipse.core.databinding.observable.StaleEvent; >+import org.eclipse.core.databinding.observable.map.AbstractObservableMap; >+import org.eclipse.core.databinding.observable.map.IMapChangeListener; >+import org.eclipse.core.databinding.observable.map.IObservableMap; >+import org.eclipse.core.databinding.observable.map.MapChangeEvent; >+import org.eclipse.core.databinding.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 { >+ private IObservableMap map; >+ private IValueProperty property; >+ >+ private Map keyToPropertySourceListener; >+ >+ 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 newPropertySource = event.diff >+ .getNewValue(key); >+ Object newValue = property >+ .getValue(newPropertySource); >+ newValues.put(key, newValue); >+ addPropertySourceListener(key, newPropertySource); >+ } >+ >+ Set removedKeys = event.diff.getRemovedKeys(); >+ for (Iterator it = removedKeys.iterator(); it.hasNext();) { >+ Object key = it.next(); >+ Object oldPropertySource = event.diff >+ .getOldValue(key); >+ Object oldValue = property >+ .getValue(oldPropertySource); >+ oldValues.put(key, oldValue); >+ removePropertySourceListener(key, oldPropertySource); >+ } >+ >+ Set changedKeys = new HashSet(event.diff >+ .getChangedKeys()); >+ for (Iterator it = changedKeys.iterator(); it.hasNext();) { >+ Object key = it.next(); >+ Object oldPropertySource = event.diff >+ .getOldValue(key); >+ Object oldValue = property >+ .getValue(oldPropertySource); >+ Object newPropertySource = event.diff >+ .getNewValue(key); >+ Object newValue = property >+ .getValue(newPropertySource); >+ if (Util.equals(oldValue, newValue)) { >+ it.remove(); >+ } else { >+ oldValues.put(key, oldValue); >+ newValues.put(key, newValue); >+ } >+ addPropertySourceListener(key, newPropertySource); >+ removePropertySourceListener(key, oldPropertySource); >+ } >+ >+ 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.keyToPropertySourceListener = new HashMap(); >+ } >+ >+ 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); >+ >+ 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 propertySource = entry.getValue(); >+ >+ addPropertySourceListener(key, propertySource); >+ } >+ } >+ } >+ >+ 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); >+ keyToPropertySourceListener.put(key, propertyListener); >+ } >+ >+ private void removePropertySourceListener(Object key, Object propertySource) { >+ IValuePropertyChangeListener propertyListener = (IValuePropertyChangeListener) keyToPropertySourceListener >+ .get(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 propertySource = map.get(key); >+ >+ Object oldValue = property.getValue(propertySource); >+ >+ updating = true; >+ try { >+ property.setValue(propertySource, value); >+ } finally { >+ updating = false; >+ } >+ >+ Object newValue = property.getValue(propertySource); >+ >+ 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 synchronized void dispose() { >+ if (!disposed) { >+ disposed = true; >+ property = null; >+ } >+ >+ super.dispose(); >+ } >+} >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 >+ ******************************************************************************/ >+ >+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,34 @@ >+/******************************************************************************* >+ * Copyright (c) 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 >+ ******************************************************************************/ >+ >+package org.eclipse.core.databinding.property; >+ >+import org.eclipse.core.databinding.observable.set.SetDiff; >+ >+/** >+ * @since 1.2 >+ */ >+public abstract class SetProperty extends Property implements ISetProperty { >+ 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/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 IBM Corporation and others. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * IBM Corporation - initial API and implementation >+ ******************************************************************************/ >+ >+package org.eclipse.core.databinding.property; >+ >+/** >+ * @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,48 @@ >+/******************************************************************************* >+ * Copyright (c) 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 >+ ******************************************************************************/ >+ >+package org.eclipse.core.databinding.property; >+ >+import org.eclipse.core.databinding.observable.map.MapDiff; >+ >+/** >+ * @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; >+ this.diff = diff; >+ } >+ >+ void dispatch(IPropertyChangeListener listener) { >+ ((IMapPropertyChangeListener) listener).handleMapPropertyChange(this); >+ } >+} >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 IBM Corporation and others. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * IBM Corporation - initial API and implementation >+ ******************************************************************************/ >+ >+package org.eclipse.core.databinding.property; >+ >+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/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,48 @@ >+/******************************************************************************* >+ * Copyright (c) 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 >+ ******************************************************************************/ >+ >+package org.eclipse.core.databinding.property; >+ >+import org.eclipse.core.databinding.observable.list.ListDiff; >+ >+/** >+ * @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; >+ this.diff = diff; >+ } >+ >+ void dispatch(IPropertyChangeListener listener) { >+ ((IListPropertyChangeListener) listener).handleListPropertyChange(this); >+ } >+} >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,109 @@ >+/******************************************************************************* >+ * Copyright (c) 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 >+ ******************************************************************************/ >+ >+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 wasListening = changeListeners != null >+ && changeListeners.containsKey(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 (!wasListening) >+ property.addListenerTo(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 >+ ******************************************************************************/ >+ >+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/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,439 @@ >+/******************************************************************************* >+ * Copyright (c) 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 >+ ******************************************************************************/ >+ >+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.Diffs; >+import org.eclipse.core.databinding.observable.ObservableTracker; >+import org.eclipse.core.databinding.observable.Realm; >+import org.eclipse.core.databinding.observable.list.AbstractObservableList; >+import org.eclipse.core.databinding.property.IListProperty; >+import org.eclipse.core.databinding.property.IListPropertyChangeListener; >+import org.eclipse.core.databinding.property.ListPropertyChangeEvent; >+ >+/** >+ * @since 3.3 >+ * >+ */ >+public class PropertyObservableList extends AbstractObservableList { >+ private Object source; >+ private IListProperty property; >+ >+ private List cachedList; >+ >+ 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++; >+ if (event.diff == null) { >+ List oldList = cachedList; >+ List newList = cachedList = property >+ .getList(source); >+ fireListChange(Diffs.computeListDiff( >+ oldList, newList)); >+ } else { >+ 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; >+ >+ this.cachedList = property.getList(source); >+ } >+ >+ protected void firstListenerAdded() { >+ if (!disposed) { >+ property.addListChangeListener(source, listener); >+ } >+ } >+ >+ protected void lastListenerRemoved() { >+ if (!disposed) { >+ property.removeListChangeListener(source, listener); >+ } >+ } >+ >+ private List getList() { >+ return property.getList(source); >+ } >+ >+ private void setList(List list) { >+ List oldList = cachedList; >+ >+ updating = true; >+ try { >+ property.setList(source, new ArrayList(list)); >+ modCount++; >+ } finally { >+ updating = false; >+ } >+ >+ List newList = cachedList = getList(); >+ if (!oldList.equals(newList)) { >+ fireListChange(Diffs.computeListDiff(oldList, newList)); >+ } >+ } >+ >+ private void getterCalled() { >+ ObservableTracker.getterCalled(this); >+ } >+ >+ public Object getElementType() { >+ return property.getElementType(); >+ } >+ >+ // Queries >+ >+ protected int doGetSize() { >+ return getList().size(); >+ } >+ >+ public boolean contains(Object o) { >+ getterCalled(); >+ return getList().contains(o); >+ } >+ >+ public boolean containsAll(Collection c) { >+ getterCalled(); >+ return getList().containsAll(c); >+ } >+ >+ public Object get(int index) { >+ getterCalled(); >+ return getList().get(index); >+ } >+ >+ public int indexOf(Object o) { >+ getterCalled(); >+ return getList().indexOf(o); >+ } >+ >+ public boolean isEmpty() { >+ getterCalled(); >+ return getList().isEmpty(); >+ } >+ >+ public int lastIndexOf(Object o) { >+ getterCalled(); >+ return getList().lastIndexOf(o); >+ } >+ >+ public Object[] toArray() { >+ getterCalled(); >+ return getList().toArray(); >+ } >+ >+ public Object[] toArray(Object[] a) { >+ getterCalled(); >+ return getList().toArray(a); >+ } >+ >+ // Single change operations >+ >+ public boolean add(Object o) { >+ List list = new ArrayList(getList()); >+ boolean result = list.add(o); >+ setList(list); >+ return result; >+ } >+ >+ public Iterator iterator() { >+ getterCalled(); >+ return new Iterator() { >+ int lastReturned = -1; >+ int expectedModCount = modCount; >+ ListIterator delegate = new ArrayList(getList()).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(); >+ >+ List list = new ArrayList(getList()); >+ list.remove(lastReturned); >+ setList(list); >+ delegate.remove(); // stay in sync >+ lastReturned = -1; >+ expectedModCount = modCount; >+ } >+ >+ private void checkForComodification() { >+ if (expectedModCount != modCount) >+ throw new ConcurrentModificationException(); >+ } >+ }; >+ } >+ >+ public Object move(int oldIndex, int newIndex) { >+ getterCalled(); >+ List list = new ArrayList(getList()); >+ Object result = list.remove(oldIndex); >+ list.add(newIndex, result); >+ setList(list); >+ return result; >+ } >+ >+ public boolean remove(Object o) { >+ getterCalled(); >+ List list = new ArrayList(getList()); >+ boolean result = list.remove(o); >+ if (result) { >+ setList(list); >+ } >+ return result; >+ } >+ >+ public void add(int index, Object o) { >+ getterCalled(); >+ List list = new ArrayList(getList()); >+ list.add(index, o); >+ setList(list); >+ } >+ >+ 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(getList()) >+ .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 >+ >+ List list = new ArrayList(getList()); >+ list.add(index, o); >+ setList(list); >+ >+ lastReturned = -1; >+ expectedModCount = modCount; >+ } >+ >+ public void set(Object o) { >+ checkRealm(); >+ checkForComodification(); >+ >+ delegate.set(o); >+ >+ List list = new ArrayList(getList()); >+ list.set(lastReturned, o); >+ setList(list); >+ expectedModCount = modCount; >+ } >+ >+ public void remove() { >+ checkRealm(); >+ checkForComodification(); >+ if (lastReturned == -1) >+ throw new IllegalStateException(); >+ >+ delegate.remove(); // keep in sync >+ >+ List list = new ArrayList(getList()); >+ list.remove(lastReturned); >+ setList(list); >+ lastReturned = -1; >+ expectedModCount = modCount; >+ } >+ >+ private void checkForComodification() { >+ if (expectedModCount != modCount) >+ throw new ConcurrentModificationException(); >+ } >+ >+ }; >+ } >+ >+ public Object remove(int index) { >+ getterCalled(); >+ List list = new ArrayList(getList()); >+ Object result = list.remove(index); >+ setList(list); >+ return result; >+ } >+ >+ public Object set(int index, Object o) { >+ getterCalled(); >+ List list = new ArrayList(getList()); >+ Object result = list.set(index, o); >+ setList(list); >+ return result; >+ } >+ >+ public List subList(int fromIndex, int toIndex) { >+ getterCalled(); >+ return Collections.unmodifiableList(getList().subList(fromIndex, >+ toIndex)); >+ } >+ >+ // Bulk change operations >+ >+ public boolean addAll(Collection c) { >+ getterCalled(); >+ List list = new ArrayList(getList()); >+ boolean result = list.addAll(c); >+ if (result) { >+ setList(list); >+ } >+ return result; >+ } >+ >+ public boolean addAll(int index, Collection c) { >+ getterCalled(); >+ List list = new ArrayList(getList()); >+ boolean result = list.addAll(index, c); >+ if (result) { >+ setList(list); >+ } >+ return result; >+ } >+ >+ public boolean removeAll(Collection c) { >+ getterCalled(); >+ List list = new ArrayList(getList()); >+ boolean result = list.removeAll(c); >+ if (result) { >+ setList(list); >+ } >+ return result; >+ } >+ >+ public boolean retainAll(Collection c) { >+ getterCalled(); >+ List list = new ArrayList(getList()); >+ boolean result = retainAll(c); >+ if (result) { >+ setList(list); >+ } >+ return result; >+ } >+ >+ public void clear() { >+ getterCalled(); >+ setList(new ArrayList()); >+ } >+ >+ public synchronized void dispose() { >+ if (!disposed) { >+ disposed = true; >+ property.removeListChangeListener(source, listener); >+ property = null; >+ source = null; >+ } >+ super.dispose(); >+ } >+ >+ public boolean equals(Object o) { >+ getterCalled(); >+ return getList().equals(o); >+ } >+ >+ public int hashCode() { >+ getterCalled(); >+ return getList().hashCode(); >+ } >+} >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) 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 >+ *******************************************************************************/ >+ >+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/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,236 @@ >+/******************************************************************************* >+ * Copyright (c) 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 >+ ******************************************************************************/ >+ >+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.Diffs; >+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 { >+ private Object source; >+ private ISetProperty property; >+ >+ private Set cachedSet; >+ >+ 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++; >+ if (event.diff == null) { >+ Set oldSet = cachedSet; >+ Set newSet = cachedSet = property >+ .getSet(source); >+ fireSetChange(Diffs.computeSetDiff(oldSet, >+ newSet)); >+ } else { >+ 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; >+ >+ this.cachedSet = property.getSet(source); >+ } >+ >+ protected void firstListenerAdded() { >+ if (!disposed) { >+ property.addSetChangeListener(source, listener); >+ } >+ } >+ >+ protected void lastListenerRemoved() { >+ if (!disposed) { >+ property.removeSetChangeListener(source, listener); >+ } >+ } >+ >+ protected Set getWrappedSet() { >+ return getSet(); >+ } >+ >+ private Set getSet() { >+ return property.getSet(source); >+ } >+ >+ private void setSet(Set set) { >+ Set oldSet = cachedSet; >+ >+ updating = true; >+ try { >+ property.setSet(source, new HashSet(set)); >+ modCount++; >+ } finally { >+ updating = false; >+ } >+ >+ Set newSet = cachedSet = getSet(); >+ if (!oldSet.equals(newSet)) { >+ fireSetChange(Diffs.computeSetDiff(oldSet, newSet)); >+ } >+ } >+ >+ public Object getElementType() { >+ return property.getElementType(); >+ } >+ >+ // Queries >+ >+ protected int doGetSize() { >+ return getSet().size(); >+ } >+ >+ // Single change operations >+ >+ public boolean add(Object o) { >+ Set set = new HashSet(getSet()); >+ boolean result = set.add(o); >+ setSet(set); >+ return result; >+ } >+ >+ public Iterator iterator() { >+ getterCalled(); >+ return new Iterator() { >+ int expectedModCount = modCount; >+ Iterator delegate = new HashSet(getSet()).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 >+ >+ Set set = new HashSet(getSet()); >+ set.remove(last); >+ setSet(set); >+ >+ last = null; >+ expectedModCount = modCount; >+ } >+ >+ private void checkForComodification() { >+ if (expectedModCount != modCount) >+ throw new ConcurrentModificationException(); >+ } >+ }; >+ } >+ >+ public boolean remove(Object o) { >+ getterCalled(); >+ Set set = new HashSet(getSet()); >+ boolean result = set.remove(o); >+ if (result) { >+ setSet(set); >+ } >+ return result; >+ } >+ >+ // Bulk change operations >+ >+ public boolean addAll(Collection c) { >+ getterCalled(); >+ Set set = new HashSet(getSet()); >+ boolean result = set.addAll(c); >+ if (result) { >+ setSet(set); >+ } >+ return result; >+ } >+ >+ public boolean removeAll(Collection c) { >+ getterCalled(); >+ Set set = new HashSet(getSet()); >+ boolean result = set.removeAll(c); >+ if (result) { >+ setSet(set); >+ } >+ return result; >+ } >+ >+ public boolean retainAll(Collection c) { >+ getterCalled(); >+ Set set = new HashSet(getSet()); >+ boolean result = retainAll(c); >+ if (result) { >+ setSet(set); >+ } >+ return result; >+ } >+ >+ public void clear() { >+ getterCalled(); >+ setSet(new HashSet()); >+ } >+ >+ public synchronized void dispose() { >+ if (!disposed) { >+ disposed = true; >+ property.removeSetChangeListener(source, listener); >+ property = null; >+ source = null; >+ } >+ super.dispose(); >+ } >+} >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,86 @@ >+/******************************************************************************* >+ * Copyright (c) 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 >+ ******************************************************************************/ >+ >+package org.eclipse.core.internal.databinding.property; >+ >+import org.eclipse.core.databinding.observable.Diffs; >+import org.eclipse.core.databinding.observable.map.ComputedObservableMap; >+import org.eclipse.core.databinding.observable.set.IObservableSet; >+import org.eclipse.core.databinding.property.IValueProperty; >+import org.eclipse.core.databinding.property.IValuePropertyChangeListener; >+import org.eclipse.core.databinding.property.ValuePropertyChangeEvent; >+ >+/** >+ * @since 3.3 >+ * >+ */ >+public class SetValuePropertyObservableMap extends ComputedObservableMap { >+ 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() { >+ fireMapChange(Diffs.createMapDiffSingleChange(event >+ .getSource(), event.diff.getOldValue(), >+ event.diff.getNewValue())); >+ } >+ }); >+ } >+ } >+ }; >+ >+ /** >+ * @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); >+ keySet().add(key); >+ 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 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,117 @@ >+/******************************************************************************* >+ * Copyright (c) 2008 Matthew Hall and others. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * Matthew Hall - initial API and implementation >+ ******************************************************************************/ >+ >+package org.eclipse.core.internal.databinding.property; >+ >+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.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 { >+ private Object source; >+ private IValueProperty property; >+ >+ private Object cachedValue; >+ >+ 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() { >+ if (event.diff == null) { >+ Object oldValue = cachedValue; >+ Object newValue = cachedValue = property >+ .getValue(source); >+ fireValueChange(Diffs.createValueDiff(oldValue, >+ newValue)); >+ } else { >+ 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; >+ >+ this.cachedValue = property.getValue(source); >+ } >+ >+ 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 = cachedValue; >+ >+ updating = true; >+ try { >+ property.setValue(source, value); >+ } finally { >+ updating = false; >+ } >+ >+ Object newValue = cachedValue = doGetValue(); >+ if (!Util.equals(oldValue, newValue)) { >+ fireValueChange(Diffs.createValueDiff(oldValue, newValue)); >+ } >+ } >+ >+ public Object getValueType() { >+ return property.getValueType(); >+ } >+ >+ public synchronized void dispose() { >+ if (!disposed) { >+ disposed = true; >+ property.removeValueChangeListener(source, listener); >+ cachedValue = null; >+ property = null; >+ source = null; >+ } >+ super.dispose(); >+ } >+} >Index: src/org/eclipse/core/databinding/property/MasterDetailProperties.java >=================================================================== >RCS file: src/org/eclipse/core/databinding/property/MasterDetailProperties.java >diff -N src/org/eclipse/core/databinding/property/MasterDetailProperties.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/core/databinding/property/MasterDetailProperties.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,87 @@ >+/******************************************************************************* >+ * Copyright (c) 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 >+ ******************************************************************************/ >+ >+package org.eclipse.core.databinding.property; >+ >+/** >+ * @since 1.2 >+ */ >+public class MasterDetailProperties { >+ /** >+ * @param masterValue >+ * @param detailValue >+ * @return blah >+ */ >+ public static IValueProperty detailValue(IValueProperty masterValue, >+ IValueProperty detailValue) { >+ return null; >+ } >+ >+ /** >+ * @param masterList >+ * @param detailValue >+ * @return blah >+ */ >+ public static IListProperty detailList(IListProperty masterList, >+ IValueProperty detailValue) { >+ return null; >+ } >+ >+ /** >+ * @param masterValue >+ * @param detailList >+ * @return blah >+ */ >+ public static IListProperty detailList(IValueProperty masterValue, >+ IListProperty detailList) { >+ return null; >+ } >+ >+ /** >+ * @param masterValue >+ * @param detailSet >+ * @return blah >+ */ >+ public static ISetProperty detailSet(IValueProperty masterValue, >+ ISetProperty detailSet) { >+ return null; >+ } >+ >+ /** >+ * @param masterValue >+ * @param detailMap >+ * @return blah >+ */ >+ public static IMapProperty detailMap(IValueProperty masterValue, >+ IMapProperty detailMap) { >+ return null; >+ } >+ >+ /** >+ * @param masterKeySet >+ * @param detailValues >+ * @return blah >+ */ >+ public static IMapProperty detailMap(ISetProperty masterKeySet, >+ IValueProperty detailValues) { >+ return null; >+ } >+ >+ /** >+ * @param masterMap >+ * @param detailValues >+ * @return blah >+ */ >+ public static IMapProperty detailMap(IMapProperty masterMap, >+ IValueProperty detailValues) { >+ return null; >+ } >+} >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 IBM Corporation and others. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * IBM Corporation - initial API and implementation >+ ******************************************************************************/ >+ >+package org.eclipse.core.databinding.property; >+ >+/** >+ * @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,57 @@ >+/******************************************************************************* >+ * Copyright (c) 2008 Matthew Hall and others. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * Matthew Hall - initial API and implementation >+ ******************************************************************************/ >+ >+package org.eclipse.core.databinding.property; >+ >+ >+/** >+ * @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); >+ >+ public synchronized void dispose() { >+ if (changeSupport != null) { >+ changeSupport.dispose(); >+ changeSupport = 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