Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 194734 | Differences between
and this patch

Collapse All | Expand All

(-)src/org/eclipse/core/databinding/beans/BeansObservables.java (-84 / +40 lines)
Lines 27-41 Link Here
27
import org.eclipse.core.databinding.observable.masterdetail.MasterDetailObservables;
27
import org.eclipse.core.databinding.observable.masterdetail.MasterDetailObservables;
28
import org.eclipse.core.databinding.observable.set.IObservableSet;
28
import org.eclipse.core.databinding.observable.set.IObservableSet;
29
import org.eclipse.core.databinding.observable.value.IObservableValue;
29
import org.eclipse.core.databinding.observable.value.IObservableValue;
30
import org.eclipse.core.databinding.property.PropertyObservables;
30
import org.eclipse.core.internal.databinding.beans.BeanObservableListDecorator;
31
import org.eclipse.core.internal.databinding.beans.BeanObservableListDecorator;
31
import org.eclipse.core.internal.databinding.beans.BeanObservableMapDecorator;
32
import org.eclipse.core.internal.databinding.beans.BeanObservableMapDecorator;
32
import org.eclipse.core.internal.databinding.beans.BeanObservableSetDecorator;
33
import org.eclipse.core.internal.databinding.beans.BeanObservableSetDecorator;
33
import org.eclipse.core.internal.databinding.beans.BeanObservableValueDecorator;
34
import org.eclipse.core.internal.databinding.beans.BeanObservableValueDecorator;
34
import org.eclipse.core.internal.databinding.beans.JavaBeanObservableList;
35
import org.eclipse.core.internal.databinding.beans.JavaBeanObservableMap;
36
import org.eclipse.core.internal.databinding.beans.JavaBeanObservableSet;
37
import org.eclipse.core.internal.databinding.beans.JavaBeanObservableValue;
38
import org.eclipse.core.internal.databinding.beans.JavaBeanPropertyObservableMap;
39
import org.eclipse.core.runtime.Assert;
35
import org.eclipse.core.runtime.Assert;
40
36
41
/**
37
/**
Lines 83-91 Link Here
83
	 */
79
	 */
84
	public static IObservableValue observeValue(Realm realm, Object bean,
80
	public static IObservableValue observeValue(Realm realm, Object bean,
85
			String propertyName) {
81
			String propertyName) {
86
		PropertyDescriptor descriptor = getPropertyDescriptor(bean.getClass(),
82
		return PropertyObservables.observeValue(realm, bean, BeanProperties
87
				propertyName);
83
				.valueProperty(bean.getClass(), propertyName));
88
		return new JavaBeanObservableValue(realm, bean, descriptor);
89
	}
84
	}
90
85
91
	/**
86
	/**
Lines 103-111 Link Here
103
	 */
98
	 */
104
	public static IObservableMap observeMap(IObservableSet domain,
99
	public static IObservableMap observeMap(IObservableSet domain,
105
			Class beanClass, String propertyName) {
100
			Class beanClass, String propertyName) {
106
		PropertyDescriptor descriptor = getPropertyDescriptor(beanClass,
101
		return PropertyObservables.observeMap(domain, BeanProperties
107
				propertyName);
102
				.valueProperty(beanClass, propertyName));
108
		return new JavaBeanObservableMap(domain, descriptor);
109
	}
103
	}
110
104
111
	/**
105
	/**
Lines 124-132 Link Here
124
	 */
118
	 */
125
	public static IObservableMap observeMap(Realm realm, Object bean,
119
	public static IObservableMap observeMap(Realm realm, Object bean,
126
			String propertyName) {
120
			String propertyName) {
127
		PropertyDescriptor descriptor = getPropertyDescriptor(bean.getClass(),
121
		return PropertyObservables.observeMap(realm, bean, BeanProperties
128
				propertyName);
122
				.mapProperty(bean.getClass(), propertyName));
129
		return new JavaBeanPropertyObservableMap(realm, bean, descriptor);
130
	}
123
	}
131
124
132
	/**
125
	/**
Lines 145-152 Link Here
145
		return observeMap(Realm.getDefault(), bean, propertyName);
138
		return observeMap(Realm.getDefault(), bean, propertyName);
146
	}
139
	}
147
140
148
	/*package*/ static PropertyDescriptor getPropertyDescriptor(Class beanClass,
141
	/* package */static PropertyDescriptor getPropertyDescriptor(
149
			String propertyName) {
142
			Class beanClass, String propertyName) {
150
		BeanInfo beanInfo;
143
		BeanInfo beanInfo;
151
		try {
144
		try {
152
			beanInfo = Introspector.getBeanInfo(beanClass);
145
			beanInfo = Introspector.getBeanInfo(beanClass);
Lines 231-239 Link Here
231
	 * collection-typed named property of the given bean object. The returned
224
	 * collection-typed named property of the given bean object. The returned
232
	 * list is mutable. When an item is added or removed the setter is invoked
225
	 * list is mutable. When an item is added or removed the setter is invoked
233
	 * for the list on the parent bean to provide notification to other
226
	 * for the list on the parent bean to provide notification to other
234
	 * listeners via <code>PropertyChangeEvents</code>. This is done to
227
	 * listeners via <code>PropertyChangeEvents</code>. This is done to provide
235
	 * provide the same behavior as is expected from arrays as specified in the
228
	 * the same behavior as is expected from arrays as specified in the bean
236
	 * bean spec in section 7.2.
229
	 * spec in section 7.2.
237
	 * 
230
	 * 
238
	 * @param realm
231
	 * @param realm
239
	 *            the realm
232
	 *            the realm
Lines 242-249 Link Here
242
	 * @param propertyName
235
	 * @param propertyName
243
	 *            the name of the property
236
	 *            the name of the property
244
	 * @param elementType
237
	 * @param elementType
245
	 *            type of the elements in the list. If <code>null</code> and
238
	 *            type of the elements in the list. If <code>null</code> and the
246
	 *            the property is an array the type will be inferred. If
239
	 *            property is an array the type will be inferred. If
247
	 *            <code>null</code> and the property type cannot be inferred
240
	 *            <code>null</code> and the property type cannot be inferred
248
	 *            element type will be <code>null</code>.
241
	 *            element type will be <code>null</code>.
249
	 * @return an observable list tracking the collection-typed named property
242
	 * @return an observable list tracking the collection-typed named property
Lines 251-262 Link Here
251
	 */
244
	 */
252
	public static IObservableList observeList(Realm realm, Object bean,
245
	public static IObservableList observeList(Realm realm, Object bean,
253
			String propertyName, Class elementType) {
246
			String propertyName, Class elementType) {
254
		PropertyDescriptor propertyDescriptor = getPropertyDescriptor(bean
247
		return PropertyObservables.observeList(realm, bean, BeanProperties
255
				.getClass(), propertyName);
248
				.listProperty(bean.getClass(), propertyName, elementType));
256
		elementType = getCollectionElementType(elementType, propertyDescriptor);
257
258
		return new JavaBeanObservableList(realm, bean, propertyDescriptor,
259
				elementType);
260
	}
249
	}
261
250
262
	/**
251
	/**
Lines 439-449 Link Here
439
428
440
		IObservableValue value = MasterDetailObservables.detailValue(master,
429
		IObservableValue value = MasterDetailObservables.detailValue(master,
441
				valueFactory(realm, propertyName), propertyType);
430
				valueFactory(realm, propertyName), propertyType);
442
		BeanObservableValueDecorator decorator = new BeanObservableValueDecorator(
431
		return new BeanObservableValueDecorator(value, master,
443
				value, master, getValueTypePropertyDescriptor(master,
432
				getValueTypePropertyDescriptor(master, propertyName));
444
						propertyName));
445
446
		return decorator;
447
	}
433
	}
448
434
449
	/**
435
	/**
Lines 469-478 Link Here
469
	/**
455
	/**
470
	 * Helper method for
456
	 * Helper method for
471
	 * <code>MasterDetailObservables.detailValue(master, valueFactory(realm,
457
	 * <code>MasterDetailObservables.detailValue(master, valueFactory(realm,
472
	 * propertyName), propertyType)</code>.
458
	 * propertyName), propertyType)</code>. This method returns an
473
	 * This method returns an {@link IBeanObservable} with a
459
	 * {@link IBeanObservable} with a {@link PropertyDescriptor} based on the
474
	 * {@link PropertyDescriptor} based on the given master type and property
460
	 * given master type and property name.
475
	 * name.
476
	 * 
461
	 * 
477
	 * @param realm
462
	 * @param realm
478
	 *            the realm
463
	 *            the realm
Lines 492-506 Link Here
492
	 * @since 1.1
477
	 * @since 1.1
493
	 */
478
	 */
494
	public static IObservableValue observeDetailValue(Realm realm,
479
	public static IObservableValue observeDetailValue(Realm realm,
495
			IObservableValue master, Class masterType, String propertyName, Class propertyType) {
480
			IObservableValue master, Class masterType, String propertyName,
481
			Class propertyType) {
496
		Assert.isNotNull(masterType, "masterType cannot be null"); //$NON-NLS-1$
482
		Assert.isNotNull(masterType, "masterType cannot be null"); //$NON-NLS-1$
497
		IObservableValue value = MasterDetailObservables.detailValue(master,
483
		IObservableValue value = MasterDetailObservables.detailValue(master,
498
				valueFactory(realm, propertyName), propertyType);
484
				valueFactory(realm, propertyName), propertyType);
499
		BeanObservableValueDecorator decorator = new BeanObservableValueDecorator(
485
		return new BeanObservableValueDecorator(value, master,
500
				value, master, getPropertyDescriptor(masterType,
486
				getPropertyDescriptor(masterType, propertyName));
501
						propertyName));
502
503
		return decorator;
504
	}
487
	}
505
488
506
	/**
489
	/**
Lines 551-561 Link Here
551
		IObservableList observableList = MasterDetailObservables.detailList(
534
		IObservableList observableList = MasterDetailObservables.detailList(
552
				master, listFactory(realm, propertyName, propertyType),
535
				master, listFactory(realm, propertyName, propertyType),
553
				propertyType);
536
				propertyType);
554
		BeanObservableListDecorator decorator = new BeanObservableListDecorator(
537
		return new BeanObservableListDecorator(observableList, master,
555
				observableList, master, getValueTypePropertyDescriptor(master,
538
				getValueTypePropertyDescriptor(master, propertyName));
556
						propertyName));
557
558
		return decorator;
559
	}
539
	}
560
540
561
	/**
541
	/**
Lines 599-609 Link Here
599
		IObservableSet observableSet = MasterDetailObservables.detailSet(
579
		IObservableSet observableSet = MasterDetailObservables.detailSet(
600
				master, setFactory(realm, propertyName, propertyType),
580
				master, setFactory(realm, propertyName, propertyType),
601
				propertyType);
581
				propertyType);
602
		BeanObservableSetDecorator decorator = new BeanObservableSetDecorator(
582
		return new BeanObservableSetDecorator(observableSet, master,
603
				observableSet, master, getValueTypePropertyDescriptor(master,
583
				getValueTypePropertyDescriptor(master, propertyName));
604
						propertyName));
605
606
		return decorator;
607
	}
584
	}
608
585
609
	/**
586
	/**
Lines 642-651 Link Here
642
			IObservableValue master, String propertyName) {
619
			IObservableValue master, String propertyName) {
643
		IObservableMap observableMap = MasterDetailObservables.detailMap(
620
		IObservableMap observableMap = MasterDetailObservables.detailMap(
644
				master, mapPropertyFactory(realm, propertyName));
621
				master, mapPropertyFactory(realm, propertyName));
645
		BeanObservableMapDecorator decorator = new BeanObservableMapDecorator(
622
		return new BeanObservableMapDecorator(observableMap, master,
646
				observableMap, master, getValueTypePropertyDescriptor(master,
623
				getValueTypePropertyDescriptor(master, propertyName));
647
						propertyName));
648
		return decorator;
649
	}
624
	}
650
625
651
	/**
626
	/**
Lines 688-699 Link Here
688
	 */
663
	 */
689
	public static IObservableSet observeSet(Realm realm, Object bean,
664
	public static IObservableSet observeSet(Realm realm, Object bean,
690
			String propertyName, Class elementType) {
665
			String propertyName, Class elementType) {
691
		PropertyDescriptor propertyDescriptor = getPropertyDescriptor(bean
666
		return PropertyObservables.observeSet(realm, bean, BeanProperties
692
				.getClass(), propertyName);
667
				.setProperty(bean.getClass(), propertyName, elementType));
693
		elementType = getCollectionElementType(elementType, propertyDescriptor);
694
695
		return new JavaBeanObservableSet(realm, bean, propertyDescriptor,
696
				elementType);
697
	}
668
	}
698
669
699
	/**
670
	/**
Lines 780-796 Link Here
780
	 * @param propertyName
751
	 * @param propertyName
781
	 *            the name of the property
752
	 *            the name of the property
782
	 * @return a factory for creating {@link IObservableMap} objects
753
	 * @return a factory for creating {@link IObservableMap} objects
783
	 *
754
	 * 
784
	 * @since 1.1
755
	 * @since 1.1
785
	 */
756
	 */
786
	public static IObservableFactory setToMapFactory(final Class beanClass, final String propertyName) {
757
	public static IObservableFactory setToMapFactory(final Class beanClass,
758
			final String propertyName) {
787
		return new IObservableFactory() {
759
		return new IObservableFactory() {
788
			public IObservable createObservable(Object target) {
760
			public IObservable createObservable(Object target) {
789
				return observeMap((IObservableSet) target, beanClass, propertyName);
761
				return observeMap((IObservableSet) target, beanClass,
762
						propertyName);
790
			}
763
			}
791
		};
764
		};
792
	}
765
	}
793
	
766
794
	/**
767
	/**
795
	 * Returns a factory for creating an observable map. The factory, when
768
	 * Returns a factory for creating an observable map. The factory, when
796
	 * provided with a bean object, will create an {@link IObservableMap} in the
769
	 * provided with a bean object, will create an {@link IObservableMap} in the
Lines 830-857 Link Here
830
	}
803
	}
831
804
832
	/**
805
	/**
833
	 * @param elementType
834
	 *            can be <code>null</code>
835
	 * @param propertyDescriptor
836
	 * @return type of the items in a collection/array property
837
	 */
838
	/*package*/ static Class getCollectionElementType(Class elementType,
839
			PropertyDescriptor propertyDescriptor) {
840
		if (elementType == null) {
841
			Class propertyType = propertyDescriptor.getPropertyType();
842
			elementType = propertyType.isArray() ? propertyType
843
					.getComponentType() : Object.class;
844
		}
845
846
		return elementType;
847
	}
848
849
	/**
850
	 * @param observable
806
	 * @param observable
851
	 * @param propertyName
807
	 * @param propertyName
852
	 * @return property descriptor or <code>null</code>
808
	 * @return property descriptor or <code>null</code>
853
	 */
809
	 */
854
	/* package*/ static PropertyDescriptor getValueTypePropertyDescriptor(
810
	/* package */static PropertyDescriptor getValueTypePropertyDescriptor(
855
			IObservableValue observable, String propertyName) {
811
			IObservableValue observable, String propertyName) {
856
		return (observable.getValueType() != null) ? getPropertyDescriptor(
812
		return (observable.getValueType() != null) ? getPropertyDescriptor(
857
				(Class) observable.getValueType(), propertyName) : null;
813
				(Class) observable.getValueType(), propertyName) : null;
(-)src/org/eclipse/core/databinding/beans/PojoObservables.java (-54 / +27 lines)
Lines 13-19 Link Here
13
package org.eclipse.core.databinding.beans;
13
package org.eclipse.core.databinding.beans;
14
14
15
import java.beans.PropertyChangeEvent;
15
import java.beans.PropertyChangeEvent;
16
import java.beans.PropertyDescriptor;
17
16
18
import org.eclipse.core.databinding.observable.IObservable;
17
import org.eclipse.core.databinding.observable.IObservable;
19
import org.eclipse.core.databinding.observable.Realm;
18
import org.eclipse.core.databinding.observable.Realm;
Lines 23-37 Link Here
23
import org.eclipse.core.databinding.observable.masterdetail.MasterDetailObservables;
22
import org.eclipse.core.databinding.observable.masterdetail.MasterDetailObservables;
24
import org.eclipse.core.databinding.observable.set.IObservableSet;
23
import org.eclipse.core.databinding.observable.set.IObservableSet;
25
import org.eclipse.core.databinding.observable.value.IObservableValue;
24
import org.eclipse.core.databinding.observable.value.IObservableValue;
25
import org.eclipse.core.databinding.property.PropertyObservables;
26
import org.eclipse.core.internal.databinding.beans.BeanObservableListDecorator;
26
import org.eclipse.core.internal.databinding.beans.BeanObservableListDecorator;
27
import org.eclipse.core.internal.databinding.beans.BeanObservableMapDecorator;
27
import org.eclipse.core.internal.databinding.beans.BeanObservableMapDecorator;
28
import org.eclipse.core.internal.databinding.beans.BeanObservableSetDecorator;
28
import org.eclipse.core.internal.databinding.beans.BeanObservableSetDecorator;
29
import org.eclipse.core.internal.databinding.beans.BeanObservableValueDecorator;
29
import org.eclipse.core.internal.databinding.beans.BeanObservableValueDecorator;
30
import org.eclipse.core.internal.databinding.beans.JavaBeanObservableList;
31
import org.eclipse.core.internal.databinding.beans.JavaBeanObservableMap;
32
import org.eclipse.core.internal.databinding.beans.JavaBeanObservableSet;
33
import org.eclipse.core.internal.databinding.beans.JavaBeanObservableValue;
34
import org.eclipse.core.internal.databinding.beans.JavaBeanPropertyObservableMap;
35
30
36
/**
31
/**
37
 * A factory for creating observable objects for POJOs (plain old java objects)
32
 * A factory for creating observable objects for POJOs (plain old java objects)
Lines 73-82 Link Here
73
	 */
68
	 */
74
	public static IObservableValue observeValue(Realm realm, Object pojo,
69
	public static IObservableValue observeValue(Realm realm, Object pojo,
75
			String propertyName) {
70
			String propertyName) {
76
71
		return PropertyObservables.observeValue(realm, pojo, PojoProperties
77
		PropertyDescriptor descriptor = BeansObservables.getPropertyDescriptor(
72
				.valueProperty(pojo.getClass(), propertyName));
78
				pojo.getClass(), propertyName);
79
		return new JavaBeanObservableValue(realm, pojo, descriptor, false);
80
	}
73
	}
81
74
82
	/**
75
	/**
Lines 94-102 Link Here
94
	 */
87
	 */
95
	public static IObservableMap observeMap(IObservableSet domain,
88
	public static IObservableMap observeMap(IObservableSet domain,
96
			Class pojoClass, String propertyName) {
89
			Class pojoClass, String propertyName) {
97
		PropertyDescriptor descriptor = BeansObservables.getPropertyDescriptor(
90
		return PropertyObservables.observeMap(domain, PojoProperties
98
				pojoClass, propertyName);
91
				.valueProperty(pojoClass, propertyName));
99
		return new JavaBeanObservableMap(domain, descriptor, false);
100
	}
92
	}
101
93
102
	/**
94
	/**
Lines 136-144 Link Here
136
	 */
128
	 */
137
	public static IObservableMap observeMap(Realm realm, Object pojo,
129
	public static IObservableMap observeMap(Realm realm, Object pojo,
138
			String propertyName) {
130
			String propertyName) {
139
		PropertyDescriptor descriptor = BeansObservables.getPropertyDescriptor(
131
		return PropertyObservables.observeMap(realm, pojo, PojoProperties
140
				pojo.getClass(), propertyName);
132
				.mapProperty(pojo.getClass(), propertyName));
141
		return new JavaBeanPropertyObservableMap(realm, pojo, descriptor, false);
142
	}
133
	}
143
134
144
	/**
135
	/**
Lines 200-208 Link Here
200
	 * collection-typed named property of the given bean object. The returned
191
	 * collection-typed named property of the given bean object. The returned
201
	 * list is mutable. When an item is added or removed the setter is invoked
192
	 * list is mutable. When an item is added or removed the setter is invoked
202
	 * for the list on the parent bean to provide notification to other
193
	 * for the list on the parent bean to provide notification to other
203
	 * listeners via <code>PropertyChangeEvents</code>. This is done to
194
	 * listeners via <code>PropertyChangeEvents</code>. This is done to provide
204
	 * provide the same behavior as is expected from arrays as specified in the
195
	 * the same behavior as is expected from arrays as specified in the bean
205
	 * bean spec in section 7.2.
196
	 * spec in section 7.2.
206
	 * 
197
	 * 
207
	 * @param realm
198
	 * @param realm
208
	 *            the realm
199
	 *            the realm
Lines 211-218 Link Here
211
	 * @param propertyName
202
	 * @param propertyName
212
	 *            the name of the property
203
	 *            the name of the property
213
	 * @param elementType
204
	 * @param elementType
214
	 *            type of the elements in the list. If <code>null</code> and
205
	 *            type of the elements in the list. If <code>null</code> and the
215
	 *            the property is an array the type will be inferred. If
206
	 *            property is an array the type will be inferred. If
216
	 *            <code>null</code> and the property type cannot be inferred
207
	 *            <code>null</code> and the property type cannot be inferred
217
	 *            element type will be <code>null</code>.
208
	 *            element type will be <code>null</code>.
218
	 * @return an observable list tracking the collection-typed named property
209
	 * @return an observable list tracking the collection-typed named property
Lines 220-232 Link Here
220
	 */
211
	 */
221
	public static IObservableList observeList(Realm realm, Object pojo,
212
	public static IObservableList observeList(Realm realm, Object pojo,
222
			String propertyName, Class elementType) {
213
			String propertyName, Class elementType) {
223
		PropertyDescriptor propertyDescriptor = BeansObservables
214
		return PropertyObservables.observeList(realm, pojo, PojoProperties
224
				.getPropertyDescriptor(pojo.getClass(), propertyName);
215
				.listProperty(pojo.getClass(), propertyName, elementType));
225
		elementType = BeansObservables.getCollectionElementType(elementType,
226
				propertyDescriptor);
227
228
		return new JavaBeanObservableList(realm, pojo, propertyDescriptor,
229
				elementType, false);
230
	}
216
	}
231
217
232
	/**
218
	/**
Lines 310-322 Link Here
310
	 */
296
	 */
311
	public static IObservableSet observeSet(Realm realm, Object pojo,
297
	public static IObservableSet observeSet(Realm realm, Object pojo,
312
			String propertyName, Class elementType) {
298
			String propertyName, Class elementType) {
313
		PropertyDescriptor propertyDescriptor = BeansObservables
299
		return PropertyObservables.observeSet(realm, pojo, PojoProperties
314
				.getPropertyDescriptor(pojo.getClass(), propertyName);
300
				.setProperty(pojo.getClass(), propertyName, elementType));
315
		elementType = BeansObservables.getCollectionElementType(elementType,
316
				propertyDescriptor);
317
318
		return new JavaBeanObservableSet(realm, pojo, propertyDescriptor,
319
				elementType, false);
320
	}
301
	}
321
302
322
	/**
303
	/**
Lines 540-550 Link Here
540
521
541
		IObservableValue value = MasterDetailObservables.detailValue(master,
522
		IObservableValue value = MasterDetailObservables.detailValue(master,
542
				valueFactory(realm, propertyName), propertyType);
523
				valueFactory(realm, propertyName), propertyType);
543
		BeanObservableValueDecorator decorator = new BeanObservableValueDecorator(
524
		return new BeanObservableValueDecorator(value, master, BeansObservables
544
				value, master, BeansObservables.getValueTypePropertyDescriptor(
525
				.getValueTypePropertyDescriptor(master, propertyName));
545
						master, propertyName));
546
547
		return decorator;
548
	}
526
	}
549
527
550
	/**
528
	/**
Lines 587-597 Link Here
587
		IObservableList observableList = MasterDetailObservables.detailList(
565
		IObservableList observableList = MasterDetailObservables.detailList(
588
				master, listFactory(realm, propertyName, propertyType),
566
				master, listFactory(realm, propertyName, propertyType),
589
				propertyType);
567
				propertyType);
590
		BeanObservableListDecorator decorator = new BeanObservableListDecorator(
568
		return new BeanObservableListDecorator(observableList, master,
591
				observableList, master, BeansObservables
569
				BeansObservables.getValueTypePropertyDescriptor(master,
592
						.getValueTypePropertyDescriptor(master, propertyName));
570
						propertyName));
593
594
		return decorator;
595
	}
571
	}
596
572
597
	/**
573
	/**
Lines 635-645 Link Here
635
		IObservableSet observableSet = MasterDetailObservables.detailSet(
611
		IObservableSet observableSet = MasterDetailObservables.detailSet(
636
				master, setFactory(realm, propertyName, propertyType),
612
				master, setFactory(realm, propertyName, propertyType),
637
				propertyType);
613
				propertyType);
638
		BeanObservableSetDecorator decorator = new BeanObservableSetDecorator(
614
		return new BeanObservableSetDecorator(observableSet, master,
639
				observableSet, master, BeansObservables
615
				BeansObservables.getValueTypePropertyDescriptor(master,
640
						.getValueTypePropertyDescriptor(master, propertyName));
616
						propertyName));
641
642
		return decorator;
643
	}
617
	}
644
618
645
	/**
619
	/**
Lines 676-685 Link Here
676
			IObservableValue master, String propertyName) {
650
			IObservableValue master, String propertyName) {
677
		IObservableMap observableMap = MasterDetailObservables.detailMap(
651
		IObservableMap observableMap = MasterDetailObservables.detailMap(
678
				master, mapPropertyFactory(realm, propertyName));
652
				master, mapPropertyFactory(realm, propertyName));
679
		BeanObservableMapDecorator decorator = new BeanObservableMapDecorator(
653
		return new BeanObservableMapDecorator(observableMap, master,
680
				observableMap, master, BeansObservables
654
				BeansObservables.getValueTypePropertyDescriptor(master,
681
						.getValueTypePropertyDescriptor(master, propertyName));
655
						propertyName));
682
		return decorator;
683
	}
656
	}
684
657
685
	/**
658
	/**
(-)src/org/eclipse/core/databinding/beans/IBeanProperty.java (+27 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.beans;
13
14
import java.beans.PropertyDescriptor;
15
16
import org.eclipse.core.databinding.property.IProperty;
17
18
/**
19
 * @since 1.2
20
 * 
21
 */
22
public interface IBeanProperty extends IProperty {
23
	/**
24
	 * @return property descriptor for the bean property
25
	 */
26
	public PropertyDescriptor getPropertyDescriptor();
27
}
(-)src/org/eclipse/core/internal/databinding/beans/BeanMapProperty.java (+133 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 Matthew Hall and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Matthew Hall - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.beans;
13
14
import java.beans.PropertyChangeEvent;
15
import java.beans.PropertyChangeListener;
16
import java.beans.PropertyDescriptor;
17
import java.util.HashMap;
18
import java.util.Map;
19
20
import org.eclipse.core.databinding.beans.IBeanProperty;
21
import org.eclipse.core.databinding.observable.Diffs;
22
import org.eclipse.core.databinding.observable.map.MapDiff;
23
import org.eclipse.core.databinding.property.MapProperty;
24
import org.eclipse.core.internal.databinding.Util;
25
26
/**
27
 * @since 3.3
28
 * 
29
 */
30
public class BeanMapProperty extends MapProperty implements IBeanProperty {
31
	private PropertyDescriptor propertyDescriptor;
32
	private boolean attachListener;
33
34
	private boolean updating;
35
36
	private ListenerSupport listenerSupport;
37
38
	/**
39
	 * @param propertyDescriptor
40
	 * @param attachListener
41
	 */
42
	public BeanMapProperty(PropertyDescriptor propertyDescriptor,
43
			boolean attachListener) {
44
		this.propertyDescriptor = propertyDescriptor;
45
		this.attachListener = attachListener;
46
	}
47
48
	private void initListenerSupport() {
49
		if (listenerSupport == null) {
50
			synchronized (this) {
51
				if (listenerSupport == null) {
52
					PropertyChangeListener propertyChangeListener = new PropertyChangeListener() {
53
						public void propertyChange(PropertyChangeEvent evt) {
54
							if (!updating) {
55
								MapDiff diff;
56
								if (evt.getOldValue() == null
57
										&& evt.getNewValue() == null) {
58
									// Obscure condition indicating new and old
59
									// values are unknown
60
									diff = null;
61
								} else {
62
									diff = Diffs.computeMapDiff(asMap(evt
63
											.getOldValue()), asMap(evt
64
											.getNewValue()));
65
								}
66
								fireMapChange(evt.getSource(), diff);
67
							}
68
						}
69
					};
70
					listenerSupport = new ListenerSupport(
71
							propertyChangeListener, propertyDescriptor
72
									.getName());
73
				}
74
			}
75
		}
76
	}
77
78
	protected void addListenerTo(Object source) {
79
		if (attachListener) {
80
			initListenerSupport();
81
			listenerSupport.hookListener(source);
82
		}
83
	}
84
85
	protected void removeListenerFrom(Object source) {
86
		if (attachListener && listenerSupport != null) {
87
			listenerSupport.unhookListener(source);
88
		}
89
	}
90
91
	public Map getMap(Object source) {
92
		return asMap(BeanPropertyHelper.getProperty(source, propertyDescriptor));
93
	}
94
95
	private Map asMap(Object propertyValue) {
96
		if (propertyValue == null)
97
			return new HashMap();
98
		return (Map) propertyValue;
99
	}
100
101
	public void setMap(Object source, Map map) {
102
		Map oldMap = getMap(source);
103
104
		if (Util.equals(oldMap, map)) {
105
			return;
106
		}
107
108
		updating = true;
109
		try {
110
			BeanPropertyHelper.setProperty(source, propertyDescriptor, map);
111
		} finally {
112
			updating = false;
113
		}
114
115
		Map newMap = getMap(source);
116
		if (!Util.equals(oldMap, newMap)) {
117
			fireMapChange(source, Diffs.computeMapDiff(oldMap, newMap));
118
		}
119
	}
120
121
	public synchronized void dispose() {
122
		if (listenerSupport != null) {
123
			listenerSupport.dispose();
124
			listenerSupport = null;
125
		}
126
		propertyDescriptor = null;
127
		super.dispose();
128
	}
129
130
	public PropertyDescriptor getPropertyDescriptor() {
131
		return propertyDescriptor;
132
	}
133
}
(-)src/org/eclipse/core/internal/databinding/beans/BeanValueProperty.java (+135 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 Matthew Hall and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Matthew Hall - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.beans;
13
14
import java.beans.PropertyChangeEvent;
15
import java.beans.PropertyChangeListener;
16
import java.beans.PropertyDescriptor;
17
18
import org.eclipse.core.databinding.beans.IBeanProperty;
19
import org.eclipse.core.databinding.observable.Diffs;
20
import org.eclipse.core.databinding.observable.value.ValueDiff;
21
import org.eclipse.core.databinding.property.ValueProperty;
22
import org.eclipse.core.internal.databinding.Util;
23
24
/**
25
 * @since 3.3
26
 * 
27
 */
28
public class BeanValueProperty extends ValueProperty implements IBeanProperty {
29
	private PropertyDescriptor propertyDescriptor;
30
	private Class valueType;
31
32
	private boolean attachListener;
33
34
	private boolean updating;
35
36
	private ListenerSupport listenerSupport;
37
38
	/**
39
	 * @param propertyDescriptor
40
	 * @param valueType
41
	 * @param attachListener
42
	 */
43
	public BeanValueProperty(PropertyDescriptor propertyDescriptor,
44
			Class valueType, boolean attachListener) {
45
		this.propertyDescriptor = propertyDescriptor;
46
		this.valueType = valueType == null ? propertyDescriptor
47
				.getPropertyType() : valueType;
48
49
		this.attachListener = attachListener;
50
51
	}
52
53
	private void initListenerSupport() {
54
		if (listenerSupport == null) {
55
			synchronized (this) {
56
				if (listenerSupport == null) {
57
					PropertyChangeListener propertyChangeListener = new PropertyChangeListener() {
58
						public void propertyChange(PropertyChangeEvent evt) {
59
							if (!updating) {
60
								ValueDiff diff;
61
								if (evt.getOldValue() == null
62
										&& evt.getOldValue() == null) {
63
									// Obscure condition indicating new and old
64
									// values are unknown
65
									diff = null;
66
								} else {
67
									diff = Diffs.createValueDiff(evt
68
											.getOldValue(), evt.getNewValue());
69
								}
70
								fireValueChange(evt.getSource(), diff);
71
							}
72
						}
73
					};
74
					listenerSupport = new ListenerSupport(
75
							propertyChangeListener, propertyDescriptor
76
									.getName());
77
				}
78
			}
79
		}
80
	}
81
82
	protected void addListenerTo(Object source) {
83
		if (attachListener) {
84
			initListenerSupport();
85
			listenerSupport.hookListener(source);
86
		}
87
	}
88
89
	protected void removeListenerFrom(Object source) {
90
		if (attachListener && listenerSupport != null) {
91
			listenerSupport.unhookListener(source);
92
		}
93
	}
94
95
	public Object getValue(Object source) {
96
		return BeanPropertyHelper.getProperty(source, propertyDescriptor);
97
	}
98
99
	public void setValue(Object source, Object value) {
100
		Object oldValue = getValue(source);
101
102
		if (Util.equals(oldValue, value)) {
103
			return;
104
		}
105
106
		updating = true;
107
		try {
108
			BeanPropertyHelper.setProperty(source, propertyDescriptor, value);
109
		} finally {
110
			updating = false;
111
		}
112
113
		Object newValue = getValue(source);
114
		if (!Util.equals(oldValue, newValue)) {
115
			fireValueChange(source, Diffs.createValueDiff(oldValue, newValue));
116
		}
117
	}
118
119
	public Object getValueType() {
120
		return valueType;
121
	}
122
123
	public synchronized void dispose() {
124
		if (listenerSupport != null) {
125
			listenerSupport.dispose();
126
			listenerSupport = null;
127
		}
128
		propertyDescriptor = null;
129
		super.dispose();
130
	}
131
132
	public PropertyDescriptor getPropertyDescriptor() {
133
		return propertyDescriptor;
134
	}
135
}
(-)src/org/eclipse/core/databinding/beans/PojoProperties.java (+108 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 Matthew Hall and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Matthew Hall - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.beans;
13
14
import org.eclipse.core.databinding.property.IListProperty;
15
import org.eclipse.core.databinding.property.IMapProperty;
16
import org.eclipse.core.databinding.property.ISetProperty;
17
import org.eclipse.core.databinding.property.IValueProperty;
18
import org.eclipse.core.internal.databinding.beans.BeanListProperty;
19
import org.eclipse.core.internal.databinding.beans.BeanMapProperty;
20
import org.eclipse.core.internal.databinding.beans.BeanSetProperty;
21
import org.eclipse.core.internal.databinding.beans.BeanValueProperty;
22
23
/**
24
 * @since 1.2
25
 */
26
public class PojoProperties {
27
	/**
28
	 * @param beanClass
29
	 * @param propertyName
30
	 * @return a value property for the given property name of the given bean
31
	 *         class.
32
	 */
33
	public static IValueProperty valueProperty(Class beanClass,
34
			String propertyName) {
35
		return valueProperty(beanClass, propertyName, null);
36
	}
37
38
	/**
39
	 * @param beanClass
40
	 * @param propertyName
41
	 * @param valueType
42
	 * @return a value property for the given property name of the given bean
43
	 *         class.
44
	 */
45
	public static IValueProperty valueProperty(Class beanClass,
46
			String propertyName, Class valueType) {
47
		return new BeanValueProperty(BeansObservables.getPropertyDescriptor(
48
				beanClass, propertyName), valueType, false);
49
	}
50
51
	/**
52
	 * @param beanClass
53
	 * @param propertyName
54
	 * @return a list property for the given property name of the given bean
55
	 *         class.
56
	 */
57
	public static ISetProperty setProperty(Class beanClass, String propertyName) {
58
		return setProperty(beanClass, propertyName, null);
59
	}
60
61
	/**
62
	 * @param beanClass
63
	 * @param propertyName
64
	 * @param elementType
65
	 * @return a list property for the given property name of the given bean
66
	 *         class.
67
	 */
68
	public static ISetProperty setProperty(Class beanClass,
69
			String propertyName, Class elementType) {
70
		return new BeanSetProperty(BeansObservables.getPropertyDescriptor(
71
				beanClass, propertyName), elementType, false);
72
	}
73
74
	/**
75
	 * @param beanClass
76
	 * @param propertyName
77
	 * @return a list property for the given property name of the given bean
78
	 *         class.
79
	 */
80
	public static IListProperty listProperty(Class beanClass,
81
			String propertyName) {
82
		return listProperty(beanClass, propertyName, null);
83
	}
84
85
	/**
86
	 * @param beanClass
87
	 * @param propertyName
88
	 * @param elementType
89
	 * @return a list property for the given property name of the given bean
90
	 *         class.
91
	 */
92
	public static IListProperty listProperty(Class beanClass,
93
			String propertyName, Class elementType) {
94
		return new BeanListProperty(BeansObservables.getPropertyDescriptor(
95
				beanClass, propertyName), elementType, false);
96
	}
97
98
	/**
99
	 * @param beanClass
100
	 * @param propertyName
101
	 * @return a map property for the given property name of the given bean
102
	 *         class.
103
	 */
104
	public static IMapProperty mapProperty(Class beanClass, String propertyName) {
105
		return new BeanMapProperty(BeansObservables.getPropertyDescriptor(
106
				beanClass, propertyName), false);
107
	}
108
}
(-)src/org/eclipse/core/internal/databinding/beans/BeanListProperty.java (+157 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 Matthew Hall and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Matthew Hall - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.beans;
13
14
import java.beans.PropertyChangeEvent;
15
import java.beans.PropertyChangeListener;
16
import java.beans.PropertyDescriptor;
17
import java.lang.reflect.Array;
18
import java.util.ArrayList;
19
import java.util.Arrays;
20
import java.util.List;
21
22
import org.eclipse.core.databinding.beans.IBeanProperty;
23
import org.eclipse.core.databinding.observable.Diffs;
24
import org.eclipse.core.databinding.observable.list.ListDiff;
25
import org.eclipse.core.databinding.property.ListProperty;
26
import org.eclipse.core.internal.databinding.Util;
27
28
/**
29
 * @since 3.3
30
 * 
31
 */
32
public class BeanListProperty extends ListProperty implements IBeanProperty {
33
	private PropertyDescriptor propertyDescriptor;
34
	private Class elementType;
35
	private boolean attachListener;
36
37
	private boolean updating;
38
39
	private ListenerSupport listenerSupport;
40
41
	/**
42
	 * @param propertyDescriptor
43
	 * @param elementType
44
	 * @param attachListener
45
	 */
46
	public BeanListProperty(PropertyDescriptor propertyDescriptor,
47
			Class elementType, boolean attachListener) {
48
		this.propertyDescriptor = propertyDescriptor;
49
		this.elementType = elementType == null ? BeanPropertyHelper
50
				.getCollectionPropertyElementType(propertyDescriptor)
51
				: elementType;
52
		this.attachListener = attachListener;
53
	}
54
55
	private void initListenerSupport() {
56
		if (listenerSupport == null) {
57
			synchronized (this) {
58
				if (listenerSupport == null) {
59
					PropertyChangeListener propertyChangeListener = new PropertyChangeListener() {
60
						public void propertyChange(PropertyChangeEvent evt) {
61
							if (!updating) {
62
								ListDiff diff;
63
								if (evt.getOldValue() == null
64
										&& evt.getOldValue() == null) {
65
									// Obscure condition indicating new and old
66
									// values are unknown
67
									diff = null;
68
								} else {
69
									diff = Diffs.computeListDiff(asList(evt
70
											.getOldValue()), asList(evt
71
											.getNewValue()));
72
								}
73
								fireListChange(evt.getSource(), diff);
74
							}
75
						}
76
					};
77
					listenerSupport = new ListenerSupport(
78
							propertyChangeListener, propertyDescriptor
79
									.getName());
80
				}
81
			}
82
		}
83
	}
84
85
	protected void addListenerTo(Object source) {
86
		if (attachListener) {
87
			initListenerSupport();
88
			listenerSupport.hookListener(source);
89
		}
90
	}
91
92
	protected void removeListenerFrom(Object source) {
93
		if (attachListener && listenerSupport != null) {
94
			listenerSupport.unhookListener(source);
95
		}
96
	}
97
98
	public List getList(Object source) {
99
		Object propertyValue = BeanPropertyHelper.getProperty(source,
100
				propertyDescriptor);
101
		return asList(propertyValue);
102
	}
103
104
	private List asList(Object propertyValue) {
105
		if (propertyValue == null)
106
			return new ArrayList();
107
		if (propertyDescriptor.getPropertyType().isArray())
108
			return new ArrayList(Arrays.asList((Object[]) propertyValue));
109
		return (List) propertyValue;
110
	}
111
112
	public void setList(Object source, List list) {
113
		List oldList = getList(source);
114
115
		if (Util.equals(oldList, list))
116
			return;
117
118
		updating = true;
119
		try {
120
			Object propertyValue = list;
121
			if (propertyDescriptor.getPropertyType().isArray()) {
122
				Class componentType = propertyDescriptor.getPropertyType()
123
						.getComponentType();
124
				Object[] array = (Object[]) Array.newInstance(componentType,
125
						list.size());
126
				list.toArray(array);
127
				propertyValue = array;
128
			}
129
			BeanPropertyHelper.setProperty(source, propertyDescriptor,
130
					propertyValue);
131
		} finally {
132
			updating = false;
133
		}
134
135
		List newList = getList(source);
136
		if (!Util.equals(oldList, newList)) {
137
			fireListChange(source, Diffs.computeListDiff(oldList, newList));
138
		}
139
	}
140
141
	public Object getElementType() {
142
		return elementType;
143
	}
144
145
	public synchronized void dispose() {
146
		if (listenerSupport != null) {
147
			listenerSupport.dispose();
148
			listenerSupport = null;
149
		}
150
		propertyDescriptor = null;
151
		super.dispose();
152
	}
153
154
	public PropertyDescriptor getPropertyDescriptor() {
155
		return propertyDescriptor;
156
	}
157
}
(-)src/org/eclipse/core/internal/databinding/beans/BeanSetProperty.java (+157 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 Matthew Hall and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Matthew Hall - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.beans;
13
14
import java.beans.PropertyChangeEvent;
15
import java.beans.PropertyChangeListener;
16
import java.beans.PropertyDescriptor;
17
import java.lang.reflect.Array;
18
import java.util.Arrays;
19
import java.util.HashSet;
20
import java.util.Set;
21
22
import org.eclipse.core.databinding.beans.IBeanProperty;
23
import org.eclipse.core.databinding.observable.Diffs;
24
import org.eclipse.core.databinding.observable.set.SetDiff;
25
import org.eclipse.core.databinding.property.SetProperty;
26
import org.eclipse.core.internal.databinding.Util;
27
28
/**
29
 * @since 3.3
30
 * 
31
 */
32
public class BeanSetProperty extends SetProperty implements IBeanProperty {
33
	private PropertyDescriptor propertyDescriptor;
34
	private Class elementType;
35
	private boolean attachListener;
36
37
	private boolean updating;
38
39
	private ListenerSupport listenerSupport;
40
41
	/**
42
	 * @param propertyDescriptor
43
	 * @param elementType
44
	 * @param attachListener
45
	 */
46
	public BeanSetProperty(PropertyDescriptor propertyDescriptor,
47
			Class elementType, boolean attachListener) {
48
		this.propertyDescriptor = propertyDescriptor;
49
		this.elementType = elementType == null ? BeanPropertyHelper
50
				.getCollectionPropertyElementType(propertyDescriptor)
51
				: elementType;
52
		this.attachListener = attachListener;
53
	}
54
55
	private void initListenerSupport() {
56
		if (listenerSupport == null) {
57
			synchronized (this) {
58
				if (listenerSupport == null) {
59
					PropertyChangeListener propertyChangeListener = new PropertyChangeListener() {
60
						public void propertyChange(PropertyChangeEvent evt) {
61
							if (!updating) {
62
								SetDiff diff;
63
								if (evt.getOldValue() == null
64
										&& evt.getOldValue() == null) {
65
									// Obscure condition indicating new and old
66
									// values are unknown
67
									diff = null;
68
								} else {
69
									diff = Diffs.computeSetDiff(asSet(evt
70
											.getOldValue()), asSet(evt
71
											.getNewValue()));
72
								}
73
								fireSetChange(evt.getSource(), diff);
74
							}
75
						}
76
					};
77
					listenerSupport = new ListenerSupport(
78
							propertyChangeListener, propertyDescriptor
79
									.getName());
80
				}
81
			}
82
		}
83
	}
84
85
	protected void addListenerTo(Object source) {
86
		if (attachListener) {
87
			initListenerSupport();
88
			listenerSupport.hookListener(source);
89
		}
90
	}
91
92
	protected void removeListenerFrom(Object source) {
93
		if (attachListener && listenerSupport != null) {
94
			listenerSupport.unhookListener(source);
95
		}
96
	}
97
98
	public Set getSet(Object source) {
99
		Object propertyValue = BeanPropertyHelper.getProperty(source,
100
				propertyDescriptor);
101
		return asSet(propertyValue);
102
	}
103
104
	private Set asSet(Object propertyValue) {
105
		if (propertyValue == null)
106
			return new HashSet();
107
		if (propertyDescriptor.getPropertyType().isArray())
108
			return new HashSet(Arrays.asList((Object[]) propertyValue));
109
		return (Set) propertyValue;
110
	}
111
112
	public void setSet(Object source, Set set) {
113
		Set oldSet = getSet(source);
114
115
		if (Util.equals(oldSet, set))
116
			return;
117
118
		updating = true;
119
		try {
120
			Object propertyValue = set;
121
			if (propertyDescriptor.getPropertyType().isArray()) {
122
				Class componentType = propertyDescriptor.getPropertyType()
123
						.getComponentType();
124
				Object[] array = (Object[]) Array.newInstance(componentType,
125
						set.size());
126
				set.toArray(array);
127
				propertyValue = array;
128
			}
129
			BeanPropertyHelper.setProperty(source, propertyDescriptor,
130
					propertyValue);
131
		} finally {
132
			updating = false;
133
		}
134
135
		Set newSet = new HashSet(getSet(source));
136
		if (!Util.equals(oldSet, newSet)) {
137
			fireSetChange(source, Diffs.computeSetDiff(oldSet, newSet));
138
		}
139
	}
140
141
	public Object getElementType() {
142
		return elementType;
143
	}
144
145
	public synchronized void dispose() {
146
		if (listenerSupport != null) {
147
			listenerSupport.dispose();
148
			listenerSupport = null;
149
		}
150
		propertyDescriptor = null;
151
		super.dispose();
152
	}
153
154
	public PropertyDescriptor getPropertyDescriptor() {
155
		return propertyDescriptor;
156
	}
157
}
(-)src/org/eclipse/core/databinding/beans/BeanProperties.java (+109 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 Matthew Hall and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Matthew Hall - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.beans;
13
14
import org.eclipse.core.databinding.property.IListProperty;
15
import org.eclipse.core.databinding.property.IMapProperty;
16
import org.eclipse.core.databinding.property.ISetProperty;
17
import org.eclipse.core.databinding.property.IValueProperty;
18
import org.eclipse.core.internal.databinding.beans.BeanListProperty;
19
import org.eclipse.core.internal.databinding.beans.BeanMapProperty;
20
import org.eclipse.core.internal.databinding.beans.BeanSetProperty;
21
import org.eclipse.core.internal.databinding.beans.BeanValueProperty;
22
23
/**
24
 * @since 1.2
25
 * 
26
 */
27
public class BeanProperties {
28
	/**
29
	 * @param beanClass
30
	 * @param propertyName
31
	 * @return a value property for the given property name of the given bean
32
	 *         class.
33
	 */
34
	public static IValueProperty valueProperty(Class beanClass,
35
			String propertyName) {
36
		return valueProperty(beanClass, propertyName, null);
37
	}
38
39
	/**
40
	 * @param beanClass
41
	 * @param propertyName
42
	 * @param valueType
43
	 * @return a value property for the given property name of the given bean
44
	 *         class.
45
	 */
46
	public static IValueProperty valueProperty(Class beanClass,
47
			String propertyName, Class valueType) {
48
		return new BeanValueProperty(BeansObservables.getPropertyDescriptor(
49
				beanClass, propertyName), valueType, true);
50
	}
51
52
	/**
53
	 * @param beanClass
54
	 * @param propertyName
55
	 * @return a list property for the given property name of the given bean
56
	 *         class.
57
	 */
58
	public static ISetProperty setProperty(Class beanClass, String propertyName) {
59
		return setProperty(beanClass, propertyName, null);
60
	}
61
62
	/**
63
	 * @param beanClass
64
	 * @param propertyName
65
	 * @param elementType
66
	 * @return a list property for the given property name of the given bean
67
	 *         class.
68
	 */
69
	public static ISetProperty setProperty(Class beanClass,
70
			String propertyName, Class elementType) {
71
		return new BeanSetProperty(BeansObservables.getPropertyDescriptor(
72
				beanClass, propertyName), elementType, true);
73
	}
74
75
	/**
76
	 * @param beanClass
77
	 * @param propertyName
78
	 * @return a list property for the given property name of the given bean
79
	 *         class.
80
	 */
81
	public static IListProperty listProperty(Class beanClass,
82
			String propertyName) {
83
		return listProperty(beanClass, propertyName, null);
84
	}
85
86
	/**
87
	 * @param beanClass
88
	 * @param propertyName
89
	 * @param elementType
90
	 * @return a list property for the given property name of the given bean
91
	 *         class.
92
	 */
93
	public static IListProperty listProperty(Class beanClass,
94
			String propertyName, Class elementType) {
95
		return new BeanListProperty(BeansObservables.getPropertyDescriptor(
96
				beanClass, propertyName), elementType, true);
97
	}
98
99
	/**
100
	 * @param beanClass
101
	 * @param propertyName
102
	 * @return a map property for the given property name of the given bean
103
	 *         class.
104
	 */
105
	public static IMapProperty mapProperty(Class beanClass, String propertyName) {
106
		return new BeanMapProperty(BeansObservables.getPropertyDescriptor(
107
				beanClass, propertyName), true);
108
	}
109
}
(-)src/org/eclipse/core/internal/databinding/beans/BeanPropertyHelper.java (+124 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.beans;
13
14
import java.beans.PropertyDescriptor;
15
import java.lang.reflect.InvocationTargetException;
16
import java.lang.reflect.Method;
17
18
import org.eclipse.core.databinding.BindingException;
19
import org.eclipse.core.databinding.beans.BeansObservables;
20
import org.eclipse.core.databinding.util.Policy;
21
import org.eclipse.core.runtime.IStatus;
22
import org.eclipse.core.runtime.Status;
23
24
/**
25
 * @since 1.2
26
 * 
27
 */
28
public class BeanPropertyHelper {
29
	/**
30
	 * Sets the contents of the given property on the given source object to the
31
	 * given value.
32
	 * 
33
	 * @param source
34
	 *            the source object which has the property being updated
35
	 * @param propertyDescriptor
36
	 *            the property being changed
37
	 * @param value
38
	 *            the new value of the property
39
	 */
40
	public static void setProperty(Object source,
41
			PropertyDescriptor propertyDescriptor, Object value) {
42
		try {
43
			Method writeMethod = propertyDescriptor.getWriteMethod();
44
			if (!writeMethod.isAccessible()) {
45
				writeMethod.setAccessible(true);
46
			}
47
			writeMethod.invoke(source, new Object[] { value });
48
		} catch (InvocationTargetException e) {
49
			/*
50
			 * InvocationTargetException wraps any exception thrown by the
51
			 * invoked method.
52
			 */
53
			throw new RuntimeException(e.getCause());
54
		} catch (Exception e) {
55
			if (BeansObservables.DEBUG) {
56
				Policy
57
						.getLog()
58
						.log(
59
								new Status(
60
										IStatus.WARNING,
61
										Policy.JFACE_DATABINDING,
62
										IStatus.OK,
63
										"Could not change value of " + source + "." + propertyDescriptor.getName(), e)); //$NON-NLS-1$ //$NON-NLS-2$
64
			}
65
		}
66
	}
67
68
	/**
69
	 * Returns the contents of the given property for the given bean.
70
	 * 
71
	 * @param source
72
	 *            the source bean
73
	 * @param propertyDescriptor
74
	 *            the property to retrieve
75
	 * @return the contents of the given property for the given bean.
76
	 */
77
	public static Object getProperty(Object source,
78
			PropertyDescriptor propertyDescriptor) {
79
		try {
80
			Method readMethod = propertyDescriptor.getReadMethod();
81
			if (readMethod == null) {
82
				throw new BindingException(propertyDescriptor.getName()
83
						+ " property does not have a read method."); //$NON-NLS-1$
84
			}
85
			if (!readMethod.isAccessible()) {
86
				readMethod.setAccessible(true);
87
			}
88
			return readMethod.invoke(source, null);
89
		} catch (InvocationTargetException e) {
90
			/*
91
			 * InvocationTargetException wraps any exception thrown by the
92
			 * invoked method.
93
			 */
94
			throw new RuntimeException(e.getCause());
95
		} catch (Exception e) {
96
			if (BeansObservables.DEBUG) {
97
				Policy
98
						.getLog()
99
						.log(
100
								new Status(
101
										IStatus.WARNING,
102
										Policy.JFACE_DATABINDING,
103
										IStatus.OK,
104
										"Could not read value of " + source + "." + propertyDescriptor.getName(), e)); //$NON-NLS-1$ //$NON-NLS-2$
105
			}
106
			return null;
107
		}
108
	}
109
110
	/**
111
	 * Returns the element type of the given collection-typed property for the
112
	 * given bean.
113
	 * 
114
	 * @param descriptor
115
	 *            the property being inspected
116
	 * @return the element type of the given collection-typed property if it is
117
	 *         an array property, or Object.class otherwise.
118
	 */
119
	public static Class getCollectionPropertyElementType(PropertyDescriptor descriptor) {
120
		Class propertyType = descriptor.getPropertyType();
121
		return propertyType.isArray() ? propertyType.getComponentType()
122
				: Object.class;
123
	}
124
}
(-)src/org/eclipse/core/databinding/observable/map/ComputedObservableMap.java (-1 / +13 lines)
Lines 31-37 Link Here
31
 */
31
 */
32
public abstract class ComputedObservableMap extends AbstractObservableMap {
32
public abstract class ComputedObservableMap extends AbstractObservableMap {
33
33
34
	private final IObservableSet keySet;
34
	private IObservableSet keySet;
35
35
36
	private ISetChangeListener setChangeListener = new ISetChangeListener() {
36
	private ISetChangeListener setChangeListener = new ISetChangeListener() {
37
		public void handleSetChange(SetChangeEvent event) {
37
		public void handleSetChange(SetChangeEvent event) {
Lines 163-166 Link Here
163
	 * @return the old value for the given key
163
	 * @return the old value for the given key
164
	 */
164
	 */
165
	protected abstract Object doPut(Object key, Object value);
165
	protected abstract Object doPut(Object key, Object value);
166
167
	public void dispose() {
168
		if (keySet != null) {
169
			Object[] keys = keySet.toArray();
170
			for (int i = 0; i < keys.length; i++) {
171
				unhookListener(keys[i]);
172
			}
173
			keySet = null;
174
		}
175
		entrySet = null;
176
		super.dispose();
177
	}
166
}
178
}
(-)META-INF/MANIFEST.MF (+1 lines)
Lines 14-19 Link Here
14
 org.eclipse.core.databinding.observable.masterdetail,
14
 org.eclipse.core.databinding.observable.masterdetail,
15
 org.eclipse.core.databinding.observable.set;x-internal:=false,
15
 org.eclipse.core.databinding.observable.set;x-internal:=false,
16
 org.eclipse.core.databinding.observable.value;x-internal:=false,
16
 org.eclipse.core.databinding.observable.value;x-internal:=false,
17
 org.eclipse.core.databinding.property,
17
 org.eclipse.core.databinding.util,
18
 org.eclipse.core.databinding.util,
18
 org.eclipse.core.databinding.validation;x-internal:=false,
19
 org.eclipse.core.databinding.validation;x-internal:=false,
19
 org.eclipse.core.internal.databinding;x-friends:="org.eclipse.core.databinding.beans",
20
 org.eclipse.core.internal.databinding;x-friends:="org.eclipse.core.databinding.beans",
(-)src/org/eclipse/core/databinding/property/IListProperty.java (+51 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import java.util.List;
15
16
/**
17
 * @since 1.2
18
 * 
19
 */
20
public interface IListProperty extends IProperty {
21
	/**
22
	 * @param source
23
	 * @return the list property of the given source
24
	 */
25
	public List getList(Object source);
26
27
	/**
28
	 * @param source
29
	 * @param list
30
	 */
31
	public void setList(Object source, List list);
32
33
	/**
34
	 * @return the type of the elements or <code>null</code> if untyped
35
	 */
36
	public Object getElementType();
37
38
	/**
39
	 * @param source
40
	 * @param listener
41
	 */
42
	public void addListChangeListener(Object source,
43
			IListPropertyChangeListener listener);
44
45
	/**
46
	 * @param source
47
	 * @param listener
48
	 */
49
	public void removeListChangeListener(Object source,
50
			IListPropertyChangeListener listener);
51
}
(-)src/org/eclipse/core/databinding/property/ISetProperty.java (+51 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import java.util.Set;
15
16
/**
17
 * @since 1.2
18
 * 
19
 */
20
public interface ISetProperty extends IProperty {
21
	/**
22
	 * @param source
23
	 * @return the list property of the given source
24
	 */
25
	public Set getSet(Object source);
26
27
	/**
28
	 * @param source
29
	 * @param set
30
	 */
31
	public void setSet(Object source, Set set);
32
33
	/**
34
	 * @return the type of the elements or <code>null</code> if untyped
35
	 */
36
	public Object getElementType();
37
38
	/**
39
	 * @param source
40
	 * @param listener
41
	 */
42
	public void addSetChangeListener(Object source,
43
			ISetPropertyChangeListener listener);
44
45
	/**
46
	 * @param source
47
	 * @param listener
48
	 */
49
	public void removeSetChangeListener(Object source,
50
			ISetPropertyChangeListener listener);
51
}
(-)src/org/eclipse/core/databinding/property/ValuePropertyChangeEvent.java (+50 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import org.eclipse.core.databinding.observable.value.ValueDiff;
15
16
/**
17
 * @since 1.2
18
 * 
19
 */
20
public class ValuePropertyChangeEvent extends PropertyChangeEvent {
21
	private static final long serialVersionUID = 1L;
22
23
	/**
24
	 * 
25
	 */
26
	public final IValueProperty property;
27
28
	/**
29
	 * ValueDiff with the old and new values of the property. May be null to
30
	 * indicate that the details of the value change are unknown.
31
	 */
32
	public final ValueDiff diff;
33
	
34
	/**
35
	 * @param source
36
	 * @param property
37
	 * @param diff
38
	 */
39
	public ValuePropertyChangeEvent(Object source, IValueProperty property,
40
			ValueDiff diff) {
41
		super(source);
42
		this.property = property;
43
		this.diff = diff;
44
	}
45
46
	void dispatch(IPropertyChangeListener listener) {
47
		((IValuePropertyChangeListener) listener)
48
				.handleValuePropertyChange(this);
49
	}
50
}
(-)src/org/eclipse/core/databinding/property/MapProperty.java (+34 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import org.eclipse.core.databinding.observable.map.MapDiff;
15
16
/**
17
 * @since 1.2
18
 */
19
public abstract class MapProperty extends Property implements IMapProperty {
20
	public final void addMapChangeListener(Object source,
21
			IMapPropertyChangeListener listener) {
22
		getChangeSupport().addListener(source, listener);
23
	}
24
25
	public final void removeMapChangeListener(Object source,
26
			IMapPropertyChangeListener listener) {
27
		getChangeSupport().removeListener(source, listener);
28
	}
29
30
	protected final void fireMapChange(Object source, MapDiff diff) {
31
		getChangeSupport().firePropertyChange(
32
				new MapPropertyChangeEvent(source, this, diff));
33
	}
34
}
(-)src/org/eclipse/core/databinding/property/ListProperty.java (+34 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import org.eclipse.core.databinding.observable.list.ListDiff;
15
16
/**
17
 * @since 1.2
18
 */
19
public abstract class ListProperty extends Property implements IListProperty {
20
	public final void addListChangeListener(Object source,
21
			IListPropertyChangeListener listener) {
22
		getChangeSupport().addListener(source, listener);
23
	}
24
25
	public final void removeListChangeListener(Object source,
26
			IListPropertyChangeListener listener) {
27
		getChangeSupport().removeListener(source, listener);
28
	}
29
30
	protected final void fireListChange(Object source, ListDiff diff) {
31
		getChangeSupport().firePropertyChange(
32
				new ListPropertyChangeEvent(source, this, diff));
33
	}
34
}
(-)src/org/eclipse/core/internal/databinding/property/PropertyObservableMap.java (+208 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.property;
13
14
import java.util.Collection;
15
import java.util.Collections;
16
import java.util.HashMap;
17
import java.util.Map;
18
import java.util.Set;
19
20
import org.eclipse.core.databinding.observable.Diffs;
21
import org.eclipse.core.databinding.observable.ObservableTracker;
22
import org.eclipse.core.databinding.observable.Realm;
23
import org.eclipse.core.databinding.observable.map.AbstractObservableMap;
24
import org.eclipse.core.databinding.property.IMapProperty;
25
import org.eclipse.core.databinding.property.IMapPropertyChangeListener;
26
import org.eclipse.core.databinding.property.MapPropertyChangeEvent;
27
28
/**
29
 * @since 3.3
30
 * 
31
 */
32
public class PropertyObservableMap extends AbstractObservableMap {
33
	private Object source;
34
	private IMapProperty property;
35
36
	private Map cachedMap;
37
38
	private volatile boolean updating = false;
39
40
	private boolean disposed = false;
41
42
	private transient volatile int modCount = 0;
43
44
	private IMapPropertyChangeListener listener = new IMapPropertyChangeListener() {
45
		public void handleMapPropertyChange(final MapPropertyChangeEvent event) {
46
			if (!disposed && !updating) {
47
				getRealm().exec(new Runnable() {
48
					public void run() {
49
						getRealm().exec(new Runnable() {
50
							public void run() {
51
								modCount++;
52
								if (event.diff == null) {
53
									Map oldMap = cachedMap;
54
									Map newMap = cachedMap = property
55
											.getMap(source);
56
									fireMapChange(Diffs.computeMapDiff(oldMap,
57
											newMap));
58
								} else {
59
									fireMapChange(event.diff);
60
								}
61
							}
62
						});
63
					}
64
				});
65
			}
66
		}
67
	};
68
69
	/**
70
	 * @param realm
71
	 * @param source
72
	 * @param property
73
	 */
74
	public PropertyObservableMap(Realm realm, Object source,
75
			IMapProperty property) {
76
		super(realm);
77
		this.source = source;
78
		this.property = property;
79
80
		this.cachedMap = property.getMap(source);
81
	}
82
83
	private void getterCalled() {
84
		ObservableTracker.getterCalled(this);
85
	}
86
87
	protected void firstListenerAdded() {
88
		if (!disposed) {
89
			property.addMapChangeListener(source, listener);
90
		}
91
	}
92
93
	protected void lastListenerRemoved() {
94
		if (!disposed) {
95
			property.removeMapChangeListener(source, listener);
96
		}
97
	}
98
99
	private Map getMap() {
100
		return property.getMap(source);
101
	}
102
103
	private void setMap(Map set) {
104
		Map oldMap = cachedMap;
105
106
		updating = true;
107
		try {
108
			property.setMap(source, new HashMap(set));
109
			modCount++;
110
		} finally {
111
			updating = false;
112
		}
113
114
		Map newMap = cachedMap = getMap();
115
		if (!oldMap.equals(newMap)) {
116
			fireMapChange(Diffs.computeMapDiff(oldMap, newMap));
117
		}
118
	}
119
120
	public boolean containsKey(Object key) {
121
		getterCalled();
122
		return getMap().containsKey(key);
123
	}
124
125
	public boolean containsValue(Object value) {
126
		getterCalled();
127
		return getMap().containsValue(value);
128
	}
129
130
	public Set entrySet() {
131
		getterCalled();
132
		// unmodifiable for now
133
		return Collections.unmodifiableSet(getMap().entrySet());
134
	}
135
136
	public boolean equals(Object o) {
137
		getterCalled();
138
		return getMap().equals(o);
139
	}
140
141
	public Object get(Object key) {
142
		getterCalled();
143
		return getMap().get(key);
144
	}
145
146
	public int hashCode() {
147
		getterCalled();
148
		return getMap().hashCode();
149
	}
150
151
	public boolean isEmpty() {
152
		getterCalled();
153
		return getMap().isEmpty();
154
	}
155
156
	public Set keySet() {
157
		getterCalled();
158
		return Collections.unmodifiableSet(getMap().keySet());
159
	}
160
161
	public Object put(Object key, Object value) {
162
		checkRealm();
163
		Map map = new HashMap(getMap());
164
		Object result = map.put(key, value);
165
		setMap(map);
166
		return result;
167
	}
168
169
	public void putAll(Map m) {
170
		checkRealm();
171
		Map map = new HashMap(getMap());
172
		map.putAll(m);
173
		setMap(map);
174
	}
175
176
	public Object remove(Object key) {
177
		checkRealm();
178
		Map map = new HashMap(getMap());
179
		Object result = map.remove(key);
180
		setMap(map);
181
		return result;
182
	}
183
184
	public int size() {
185
		getterCalled();
186
		return getMap().size();
187
	}
188
189
	public Collection values() {
190
		getterCalled();
191
		return Collections.unmodifiableCollection(getMap().values());
192
	}
193
194
	public void clear() {
195
		getterCalled();
196
		setMap(new HashMap());
197
	}
198
199
	public synchronized void dispose() {
200
		if (!disposed) {
201
			disposed = true;
202
			property.removeMapChangeListener(source, listener);
203
			property = null;
204
			source = null;
205
		}
206
		super.dispose();
207
	}
208
}
(-)src/org/eclipse/core/databinding/property/SetPropertyChangeEvent.java (+48 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import org.eclipse.core.databinding.observable.set.SetDiff;
15
16
/**
17
 * @since 1.2
18
 */
19
public class SetPropertyChangeEvent extends PropertyChangeEvent {
20
	private static final long serialVersionUID = 1L;
21
22
	/**
23
	 * 
24
	 */
25
	public final ISetProperty property;
26
27
	/**
28
	 * SetDiff enumerating the added and removed elements in the set. May be
29
	 * null to indicate that the details of the set change are unknown.
30
	 */
31
	public final SetDiff diff;
32
33
	/**
34
	 * @param source
35
	 * @param property
36
	 * @param diff
37
	 */
38
	public SetPropertyChangeEvent(Object source, ISetProperty property,
39
			SetDiff diff) {
40
		super(source);
41
		this.property = property;
42
		this.diff = diff;
43
	}
44
45
	void dispatch(IPropertyChangeListener listener) {
46
		((ISetPropertyChangeListener) listener).handleSetPropertyChange(this);
47
	}
48
}
(-)src/org/eclipse/core/databinding/property/IValueProperty.java (+49 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
/**
15
 * @since 1.2
16
 * 
17
 */
18
public interface IValueProperty extends IProperty {
19
	/**
20
	 * @param source
21
	 * @return the property value
22
	 */
23
	public Object getValue(Object source);
24
25
	/**
26
	 * @param source
27
	 * @param value
28
	 */
29
	public void setValue(Object source, Object value);
30
31
	/**
32
	 * @return the value type of the property, or <code>null</code> if untyped.
33
	 */
34
	public Object getValueType();
35
36
	/**
37
	 * @param source
38
	 * @param listener
39
	 */
40
	public void addValueChangeListener(Object source,
41
			IValuePropertyChangeListener listener);
42
43
	/**
44
	 * @param source
45
	 * @param listener
46
	 */
47
	public void removeValueChangeListener(Object source,
48
			IValuePropertyChangeListener listener);
49
}
(-)src/org/eclipse/core/databinding/property/IMapProperty.java (+46 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import java.util.Map;
15
16
/**
17
 * @since 1.2
18
 * 
19
 */
20
public interface IMapProperty extends IProperty {
21
	/**
22
	 * @param source
23
	 * @return the list property of the given source
24
	 */
25
	public Map getMap(Object source);
26
27
	/**
28
	 * @param source
29
	 * @param map
30
	 */
31
	public void setMap(Object source, Map map);
32
33
	/**
34
	 * @param source
35
	 * @param listener
36
	 */
37
	public void addMapChangeListener(Object source,
38
			IMapPropertyChangeListener listener);
39
40
	/**
41
	 * @param source
42
	 * @param listener
43
	 */
44
	public void removeMapChangeListener(Object source,
45
			IMapPropertyChangeListener listener);
46
}
(-)src/org/eclipse/core/databinding/property/IMapPropertyChangeListener.java (+22 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
/**
15
 * @since 1.2
16
 */
17
public interface IMapPropertyChangeListener extends IPropertyChangeListener {
18
	/**
19
	 * @param event
20
	 */
21
	public void handleMapPropertyChange(MapPropertyChangeEvent event);
22
}
(-)src/org/eclipse/core/databinding/property/IValuePropertyChangeListener.java (+22 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
/**
15
 * @since 1.2
16
 */
17
public interface IValuePropertyChangeListener extends IPropertyChangeListener {
18
	/**
19
	 * @param event
20
	 */
21
	public void handleValuePropertyChange(ValuePropertyChangeEvent event);
22
}
(-)src/org/eclipse/core/databinding/property/ValueProperty.java (+34 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import org.eclipse.core.databinding.observable.value.ValueDiff;
15
16
/**
17
 * @since 1.2
18
 */
19
public abstract class ValueProperty extends Property implements IValueProperty {
20
	public final void addValueChangeListener(Object source,
21
			IValuePropertyChangeListener listener) {
22
		getChangeSupport().addListener(source, listener);
23
	}
24
25
	public final void removeValueChangeListener(Object source,
26
			IValuePropertyChangeListener listener) {
27
		getChangeSupport().removeListener(source, listener);
28
	}
29
30
	protected final void fireValueChange(Object source, ValueDiff diff) {
31
		getChangeSupport().firePropertyChange(
32
				new ValuePropertyChangeEvent(source, this, diff));
33
	}
34
}
(-)src/org/eclipse/core/internal/databinding/property/MapValuePropertyObservableMap.java (+319 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.property;
13
14
import java.util.AbstractSet;
15
import java.util.HashMap;
16
import java.util.HashSet;
17
import java.util.Iterator;
18
import java.util.Map;
19
import java.util.Set;
20
21
import org.eclipse.core.databinding.observable.Diffs;
22
import org.eclipse.core.databinding.observable.IStaleListener;
23
import org.eclipse.core.databinding.observable.ObservableTracker;
24
import org.eclipse.core.databinding.observable.StaleEvent;
25
import org.eclipse.core.databinding.observable.map.AbstractObservableMap;
26
import org.eclipse.core.databinding.observable.map.IMapChangeListener;
27
import org.eclipse.core.databinding.observable.map.IObservableMap;
28
import org.eclipse.core.databinding.observable.map.MapChangeEvent;
29
import org.eclipse.core.databinding.property.IValueProperty;
30
import org.eclipse.core.databinding.property.IValuePropertyChangeListener;
31
import org.eclipse.core.databinding.property.ValuePropertyChangeEvent;
32
import org.eclipse.core.internal.databinding.Util;
33
34
/**
35
 * @since 3.3
36
 * 
37
 */
38
public class MapValuePropertyObservableMap extends AbstractObservableMap {
39
	private IObservableMap map;
40
	private IValueProperty property;
41
42
	private Map keyToPropertySourceListener;
43
44
	private boolean updating = false;
45
	private boolean disposed = false;
46
47
	private IMapChangeListener mapListener = new IMapChangeListener() {
48
		public void handleMapChange(final MapChangeEvent event) {
49
			if (!updating && !disposed) {
50
				getRealm().exec(new Runnable() {
51
					public void run() {
52
						Map oldValues = new HashMap();
53
						Map newValues = new HashMap();
54
55
						Set addedKeys = event.diff.getAddedKeys();
56
						for (Iterator it = addedKeys.iterator(); it.hasNext();) {
57
							Object key = it.next();
58
							Object newPropertySource = event.diff
59
									.getNewValue(key);
60
							Object newValue = property
61
									.getValue(newPropertySource);
62
							newValues.put(key, newValue);
63
							addPropertySourceListener(key, newPropertySource);
64
						}
65
66
						Set removedKeys = event.diff.getRemovedKeys();
67
						for (Iterator it = removedKeys.iterator(); it.hasNext();) {
68
							Object key = it.next();
69
							Object oldPropertySource = event.diff
70
									.getOldValue(key);
71
							Object oldValue = property
72
									.getValue(oldPropertySource);
73
							oldValues.put(key, oldValue);
74
							removePropertySourceListener(key, oldPropertySource);
75
						}
76
77
						Set changedKeys = new HashSet(event.diff
78
								.getChangedKeys());
79
						for (Iterator it = changedKeys.iterator(); it.hasNext();) {
80
							Object key = it.next();
81
							Object oldPropertySource = event.diff
82
									.getOldValue(key);
83
							Object oldValue = property
84
									.getValue(oldPropertySource);
85
							Object newPropertySource = event.diff
86
									.getNewValue(key);
87
							Object newValue = property
88
									.getValue(newPropertySource);
89
							if (Util.equals(oldValue, newValue)) {
90
								it.remove();
91
							} else {
92
								oldValues.put(key, oldValue);
93
								newValues.put(key, newValue);
94
							}
95
							addPropertySourceListener(key, newPropertySource);
96
							removePropertySourceListener(key, oldPropertySource);
97
						}
98
99
						fireMapChange(Diffs.createMapDiff(addedKeys,
100
								removedKeys, changedKeys, oldValues, newValues));
101
					}
102
				});
103
			}
104
		}
105
	};
106
107
	private IStaleListener staleListener = new IStaleListener() {
108
		public void handleStale(StaleEvent staleEvent) {
109
			fireStale();
110
		}
111
	};
112
113
	/**
114
	 * @param map
115
	 * @param valueProperty
116
	 */
117
	public MapValuePropertyObservableMap(IObservableMap map,
118
			IValueProperty valueProperty) {
119
		super(map.getRealm());
120
		this.map = map;
121
		this.property = valueProperty;
122
123
		this.keyToPropertySourceListener = new HashMap();
124
	}
125
126
	private class ValuePropertySourceChangeListener implements
127
			IValuePropertyChangeListener {
128
		private final Object key;
129
130
		public ValuePropertySourceChangeListener(Object key) {
131
			this.key = key;
132
		}
133
134
		public void handleValuePropertyChange(ValuePropertyChangeEvent event) {
135
			Object oldSource = event.diff.getOldValue();
136
			Object oldValue = property.getValue(oldSource);
137
			property.removeValueChangeListener(oldSource, this);
138
139
			Object newSource = event.diff.getNewValue();
140
			Object newValue = property.getValue(newSource);
141
			property.addValueChangeListener(newSource, this);
142
143
			fireMapChange(Diffs.createMapDiffSingleChange(key, oldValue,
144
					newValue));
145
		}
146
	}
147
148
	protected void firstListenerAdded() {
149
		if (!disposed) {
150
			map.addMapChangeListener(mapListener);
151
			map.addStaleListener(staleListener);
152
			for (Iterator iterator = map.entrySet().iterator(); iterator
153
					.hasNext();) {
154
				Map.Entry entry = (Map.Entry) iterator.next();
155
				Object key = entry.getKey();
156
				Object propertySource = entry.getValue();
157
158
				addPropertySourceListener(key, propertySource);
159
			}
160
		}
161
	}
162
163
	protected void lastListenerRemoved() {
164
		if (!disposed) {
165
			map.removeMapChangeListener(mapListener);
166
			map.removeStaleListener(staleListener);
167
			for (Iterator iterator = map.entrySet().iterator(); iterator
168
					.hasNext();) {
169
				Map.Entry entry = (Map.Entry) iterator.next();
170
				Object key = entry.getKey();
171
				Object propertySource = entry.getValue();
172
173
				removePropertySourceListener(key, propertySource);
174
			}
175
		}
176
	}
177
178
	private void addPropertySourceListener(Object key, Object propertySource) {
179
		IValuePropertyChangeListener propertyListener = new ValuePropertySourceChangeListener(
180
				key);
181
		property.addValueChangeListener(propertySource, propertyListener);
182
		keyToPropertySourceListener.put(key, propertyListener);
183
	}
184
185
	private void removePropertySourceListener(Object key, Object propertySource) {
186
		IValuePropertyChangeListener propertyListener = (IValuePropertyChangeListener) keyToPropertySourceListener
187
				.get(key);
188
		if (propertyListener != null) {
189
			property
190
					.removeValueChangeListener(propertySource, propertyListener);
191
		}
192
	}
193
194
	protected Object doGet(Object key) {
195
		if (!map.containsKey(key))
196
			return null;
197
		return property.getValue(map.get(key));
198
	}
199
200
	protected Object doPut(Object key, Object value) {
201
		if (!map.containsKey(key))
202
			return null;
203
		Object propertySource = map.get(key);
204
205
		Object oldValue = property.getValue(propertySource);
206
207
		updating = true;
208
		try {
209
			property.setValue(propertySource, value);
210
		} finally {
211
			updating = false;
212
		}
213
214
		Object newValue = property.getValue(propertySource);
215
216
		if (!Util.equals(oldValue, newValue)) {
217
			fireMapChange(Diffs.createMapDiffSingleChange(key, oldValue,
218
					newValue));
219
		}
220
221
		return oldValue;
222
	}
223
224
	private Set entrySet;
225
226
	public Set entrySet() {
227
		getterCalled();
228
		if (entrySet == null)
229
			entrySet = new EntrySet();
230
		return entrySet;
231
	}
232
233
	class EntrySet extends AbstractSet {
234
		public Iterator iterator() {
235
			return new Iterator() {
236
				Iterator it = map.entrySet().iterator();
237
238
				public boolean hasNext() {
239
					getterCalled();
240
					return it.hasNext();
241
				}
242
243
				public Object next() {
244
					getterCalled();
245
					Map.Entry next = (Map.Entry) it.next();
246
					return new MapEntry(next.getKey());
247
				}
248
249
				public void remove() {
250
					it.remove();
251
				}
252
			};
253
		}
254
255
		public int size() {
256
			return map.size();
257
		}
258
	}
259
260
	class MapEntry implements Map.Entry {
261
		private Object key;
262
263
		MapEntry(Object key) {
264
			this.key = key;
265
		}
266
267
		public Object getKey() {
268
			getterCalled();
269
			return key;
270
		}
271
272
		public Object getValue() {
273
			getterCalled();
274
			return get(key);
275
		}
276
277
		public Object setValue(Object value) {
278
			return put(key, value);
279
		}
280
281
		public boolean equals(Object o) {
282
			getterCalled();
283
			if (o == this)
284
				return true;
285
			if (o == null)
286
				return false;
287
			if (!(o instanceof Map.Entry))
288
				return false;
289
			Map.Entry that = (Map.Entry) o;
290
			return Util.equals(this.getKey(), that.getKey())
291
					&& Util.equals(this.getValue(), that.getValue());
292
		}
293
294
		public int hashCode() {
295
			getterCalled();
296
			Object value = getValue();
297
			return (key == null ? 0 : key.hashCode())
298
					^ (value == null ? 0 : value.hashCode());
299
		}
300
	}
301
302
	public boolean isStale() {
303
		getterCalled();
304
		return map.isStale();
305
	}
306
307
	private void getterCalled() {
308
		ObservableTracker.getterCalled(this);
309
	}
310
311
	public synchronized void dispose() {
312
		if (!disposed) {
313
			disposed = true;
314
			property = null;
315
		}
316
317
		super.dispose();
318
	}
319
}
(-)src/org/eclipse/core/databinding/property/IProperty.java (+25 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 Matthew Hall and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Matthew Hall - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
/**
15
 * Interface for observing a property of a source object.
16
 * 
17
 * @noimplement
18
 * @since 1.2
19
 */
20
public interface IProperty {
21
	/**
22
	 * Disposes the property, removing all property listeners on source objects.
23
	 */
24
	public void dispose();
25
}
(-)src/org/eclipse/core/databinding/property/SetProperty.java (+34 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import org.eclipse.core.databinding.observable.set.SetDiff;
15
16
/**
17
 * @since 1.2
18
 */
19
public abstract class SetProperty extends Property implements ISetProperty {
20
	public final void addSetChangeListener(Object source,
21
			ISetPropertyChangeListener listener) {
22
		getChangeSupport().addListener(source, listener);
23
	}
24
25
	public final void removeSetChangeListener(Object source,
26
			ISetPropertyChangeListener listener) {
27
		getChangeSupport().removeListener(source, listener);
28
	}
29
30
	protected final void fireSetChange(Object source, SetDiff diff) {
31
		getChangeSupport().firePropertyChange(
32
				new SetPropertyChangeEvent(source, this, diff));
33
	}
34
}
(-)src/org/eclipse/core/databinding/property/ISetPropertyChangeListener.java (+22 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
/**
15
 * @since 1.2
16
 */
17
public interface ISetPropertyChangeListener extends IPropertyChangeListener {
18
	/**
19
	 * @param event
20
	 */
21
	public void handleSetPropertyChange(SetPropertyChangeEvent event);
22
}
(-)src/org/eclipse/core/databinding/property/MapPropertyChangeEvent.java (+48 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import org.eclipse.core.databinding.observable.map.MapDiff;
15
16
/**
17
 * @since 1.2
18
 */
19
public class MapPropertyChangeEvent extends PropertyChangeEvent {
20
	private static final long serialVersionUID = 1L;
21
22
	/**
23
	 * 
24
	 */
25
	public final IMapProperty property;
26
27
	/**
28
	 * MapDiff enumerating the added, changed, and removed entries in the map.
29
	 * May be null to indicate that the details of the map change are unknown.
30
	 */
31
	public final MapDiff diff;
32
33
	/**
34
	 * @param source
35
	 * @param property
36
	 * @param diff
37
	 */
38
	public MapPropertyChangeEvent(Object source, IMapProperty property,
39
			MapDiff diff) {
40
		super(source);
41
		this.property = property;
42
		this.diff = diff;
43
	}
44
45
	void dispatch(IPropertyChangeListener listener) {
46
		((IMapPropertyChangeListener) listener).handleMapPropertyChange(this);
47
	}
48
}
(-)src/org/eclipse/core/databinding/property/PropertyChangeEvent.java (+27 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import java.util.EventObject;
15
16
/**
17
 * @since 1.2
18
 */
19
public abstract class PropertyChangeEvent extends EventObject {
20
	private static final long serialVersionUID = 1L;
21
22
	PropertyChangeEvent(Object source) {
23
		super(source);
24
	}
25
26
	abstract void dispatch(IPropertyChangeListener listener);
27
}
(-)src/org/eclipse/core/databinding/property/ListPropertyChangeEvent.java (+48 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import org.eclipse.core.databinding.observable.list.ListDiff;
15
16
/**
17
 * @since 1.2
18
 */
19
public class ListPropertyChangeEvent extends PropertyChangeEvent {
20
	private static final long serialVersionUID = 1L;
21
22
	/**
23
	 * 
24
	 */
25
	public final IListProperty property;
26
27
	/**
28
	 * ListDiff enumerating the added and removed elements in the list. May be
29
	 * null to indicate that the details of the list change are unknown.
30
	 */
31
	public final ListDiff diff;
32
33
	/**
34
	 * @param source
35
	 * @param property
36
	 * @param diff
37
	 */
38
	public ListPropertyChangeEvent(Object source, IListProperty property,
39
			ListDiff diff) {
40
		super(source);
41
		this.property = property;
42
		this.diff = diff;
43
	}
44
45
	void dispatch(IPropertyChangeListener listener) {
46
		((IListPropertyChangeListener) listener).handleListPropertyChange(this);
47
	}
48
}
(-)src/org/eclipse/core/databinding/property/PropertyChangeSupport.java (+109 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import java.util.Collections;
15
import java.util.IdentityHashMap;
16
import java.util.Iterator;
17
import java.util.Map;
18
19
import org.eclipse.core.runtime.ListenerList;
20
21
/**
22
 * @since 1.2
23
 */
24
public class PropertyChangeSupport {
25
	private Property property;
26
	private Map changeListeners;
27
28
	PropertyChangeSupport(Property property) {
29
		this.property = property;
30
		this.changeListeners = null;
31
	}
32
33
	protected final void addListener(Object source,
34
			IPropertyChangeListener listener) {
35
		boolean wasListening = changeListeners != null
36
				&& changeListeners.containsKey(source);
37
38
		if (changeListeners == null) {
39
			synchronized (this) {
40
				if (changeListeners == null) {
41
					changeListeners = Collections
42
							.synchronizedMap(new IdentityHashMap());
43
				}
44
			}
45
		}
46
47
		ListenerList listeners;
48
		synchronized (changeListeners) {
49
			if (changeListeners.containsKey(source)) {
50
				listeners = (ListenerList) changeListeners.get(source);
51
			} else {
52
				changeListeners.put(source, listeners = new ListenerList());
53
			}
54
		}
55
56
		synchronized (listeners) {
57
			listeners.add(listener);
58
		}
59
60
		if (!wasListening)
61
			property.addListenerTo(source);
62
	}
63
64
	protected final void removeListener(Object source,
65
			IPropertyChangeListener listener) {
66
		if (changeListeners != null) {
67
			ListenerList listeners = (ListenerList) changeListeners.get(source);
68
			if (listeners != null) {
69
				listeners.remove(listener);
70
				if (listeners.isEmpty()) {
71
					synchronized (listeners) {
72
						if (listeners.isEmpty()) {
73
							changeListeners.remove(source);
74
							property.removeListenerFrom(source);
75
						}
76
					}
77
				}
78
			}
79
		}
80
	}
81
82
	protected final void firePropertyChange(PropertyChangeEvent event) {
83
		ListenerList listenerList;
84
		synchronized (this) {
85
			if (changeListeners == null)
86
				return;
87
			listenerList = (ListenerList) changeListeners
88
					.get(event.getSource());
89
		}
90
		if (listenerList != null) {
91
			Object[] listeners = listenerList.getListeners();
92
			for (int i = 0; i < listeners.length; i++) {
93
				event.dispatch((IPropertyChangeListener) listeners[i]);
94
			}
95
		}
96
	}
97
98
	void dispose() {
99
		if (changeListeners != null) {
100
			for (Iterator iterator = changeListeners.keySet().iterator(); iterator
101
					.hasNext();) {
102
				Object source = iterator.next();
103
				property.removeListenerFrom(source);
104
				iterator.remove();
105
			}
106
			changeListeners = null;
107
		}
108
	}
109
}
(-)src/org/eclipse/core/databinding/property/PropertyObservables.java (+229 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 Matthew Hall and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Matthew Hall - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import org.eclipse.core.databinding.observable.IObservable;
15
import org.eclipse.core.databinding.observable.Realm;
16
import org.eclipse.core.databinding.observable.list.IObservableList;
17
import org.eclipse.core.databinding.observable.map.IObservableMap;
18
import org.eclipse.core.databinding.observable.masterdetail.IObservableFactory;
19
import org.eclipse.core.databinding.observable.set.IObservableSet;
20
import org.eclipse.core.databinding.observable.value.IObservableValue;
21
import org.eclipse.core.internal.databinding.property.PropertyObservableList;
22
import org.eclipse.core.internal.databinding.property.PropertyObservableMap;
23
import org.eclipse.core.internal.databinding.property.PropertyObservableSet;
24
import org.eclipse.core.internal.databinding.property.PropertyObservableValue;
25
import org.eclipse.core.internal.databinding.property.SetValuePropertyObservableMap;
26
27
/**
28
 * @since 1.2
29
 * 
30
 */
31
public class PropertyObservables {
32
	/**
33
	 * @param source
34
	 * @param property
35
	 * @return an observable value that tracks the given property of the source
36
	 *         object.
37
	 * @since 1.2
38
	 */
39
	public static IObservableValue observeValue(Object source,
40
			IValueProperty property) {
41
		return observeValue(Realm.getDefault(), source, property);
42
	}
43
44
	/**
45
	 * @param realm
46
	 * @param source
47
	 * @param property
48
	 * @return an observable value that tracks the given property of the source
49
	 *         object
50
	 * @since 1.2
51
	 */
52
	public static IObservableValue observeValue(Realm realm, Object source,
53
			IValueProperty property) {
54
		return new PropertyObservableValue(realm, source, property);
55
	}
56
57
	/**
58
	 * @param source
59
	 * @param property
60
	 * @return an observable set that tracks the given property of the source
61
	 *         object
62
	 */
63
	public static IObservableSet observeSet(Object source, ISetProperty property) {
64
		return observeSet(Realm.getDefault(), source, property);
65
	}
66
67
	/**
68
	 * @param realm
69
	 * @param source
70
	 * @param property
71
	 * @return an observable set that tracks the given property of the source
72
	 *         object
73
	 */
74
	public static IObservableSet observeSet(Realm realm, Object source,
75
			ISetProperty property) {
76
		return new PropertyObservableSet(realm, source, property);
77
	}
78
79
	/**
80
	 * @param source
81
	 * @param property
82
	 * @return an observable list that tracks the given property of the source
83
	 *         object
84
	 */
85
	public static IObservableList observeList(Object source,
86
			IListProperty property) {
87
		return observeList(Realm.getDefault(), source, property);
88
	}
89
90
	/**
91
	 * @param realm
92
	 * @param source
93
	 * @param property
94
	 * @return an observable set that tracks the given property of the source
95
	 *         object
96
	 */
97
	public static IObservableList observeList(Realm realm, Object source,
98
			IListProperty property) {
99
		return new PropertyObservableList(realm, source, property);
100
	}
101
102
	/**
103
	 * @param source
104
	 * @param property
105
	 * @return an observable map that tracks the given property of the source
106
	 *         object
107
	 */
108
	public static IObservableMap observeMap(Object source, IMapProperty property) {
109
		return observeMap(Realm.getDefault(), source, property);
110
	}
111
112
	/**
113
	 * @param realm
114
	 * @param source
115
	 * @param property
116
	 * @return an observable set that tracks the given property of the source
117
	 *         object
118
	 */
119
	public static IObservableMap observeMap(Realm realm, Object source,
120
			IMapProperty property) {
121
		return new PropertyObservableMap(realm, source, property);
122
	}
123
124
	/**
125
	 * Returns an observable map in the default realm tracking the current
126
	 * values of the named property for the beans in the given set.
127
	 * 
128
	 * @param keySet
129
	 * @param valueProperty
130
	 * @return an observable map 
131
	 */
132
	public static IObservableMap observeMap(IObservableSet keySet,
133
			IValueProperty valueProperty) {
134
		return new SetValuePropertyObservableMap(keySet, valueProperty);
135
	}
136
137
	/**
138
	 * Returns a factory for creating observable values tracking the given
139
	 * property of a particular source object
140
	 * 
141
	 * @param property
142
	 *            the property to be observed
143
	 * @return an observable value factory on
144
	 */
145
	public static IObservableFactory valueFactory(IValueProperty property) {
146
		return valueFactory(Realm.getDefault(), property);
147
	}
148
149
	/**
150
	 * Returns a factory for creating observable values tracking the given
151
	 * property of a particular source object
152
	 * 
153
	 * @param realm
154
	 *            the realm to use
155
	 * @param property
156
	 *            the property to be observed
157
	 * @return an observable value factory on
158
	 */
159
	public static IObservableFactory valueFactory(final Realm realm,
160
			final IValueProperty property) {
161
		return new IObservableFactory() {
162
			public IObservable createObservable(Object target) {
163
				return observeValue(realm, target, property);
164
			}
165
		};
166
	}
167
168
	/**
169
	 * Returns a factory for creating observable sets tracking the given
170
	 * property of a particular source object
171
	 * 
172
	 * @param property
173
	 *            the property to be observed
174
	 * @return an observable value factory on
175
	 */
176
	public static IObservableFactory setFactory(ISetProperty property) {
177
		return setFactory(Realm.getDefault(), property);
178
	}
179
180
	/**
181
	 * Returns a factory for creating obervable sets tracking the given property
182
	 * of a particular source object
183
	 * 
184
	 * @param realm
185
	 *            the realm to use
186
	 * @param property
187
	 *            the property to be observed
188
	 * @return an observable value factory on
189
	 */
190
	public static IObservableFactory setFactory(final Realm realm,
191
			final ISetProperty property) {
192
		return new IObservableFactory() {
193
			public IObservable createObservable(Object target) {
194
				return observeSet(realm, target, property);
195
			}
196
		};
197
	}
198
199
	/**
200
	 * Returns a factory for creating observable lists tracking the given
201
	 * property of a particular source object
202
	 * 
203
	 * @param property
204
	 *            the property to be observed
205
	 * @return an observable value factory on
206
	 */
207
	public static IObservableFactory listFactory(IListProperty property) {
208
		return listFactory(Realm.getDefault(), property);
209
	}
210
211
	/**
212
	 * Returns a factory for creating obervable lists tracking the given
213
	 * property of a particular source object
214
	 * 
215
	 * @param realm
216
	 *            the realm to use
217
	 * @param property
218
	 *            the property to be observed
219
	 * @return an observable value factory on
220
	 */
221
	public static IObservableFactory listFactory(final Realm realm,
222
			final IListProperty property) {
223
		return new IObservableFactory() {
224
			public IObservable createObservable(Object target) {
225
				return observeList(realm, target, property);
226
			}
227
		};
228
	}
229
}
(-)src/org/eclipse/core/internal/databinding/property/PropertyObservableList.java (+439 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.property;
13
14
import java.util.ArrayList;
15
import java.util.Collection;
16
import java.util.Collections;
17
import java.util.ConcurrentModificationException;
18
import java.util.Iterator;
19
import java.util.List;
20
import java.util.ListIterator;
21
22
import org.eclipse.core.databinding.observable.Diffs;
23
import org.eclipse.core.databinding.observable.ObservableTracker;
24
import org.eclipse.core.databinding.observable.Realm;
25
import org.eclipse.core.databinding.observable.list.AbstractObservableList;
26
import org.eclipse.core.databinding.property.IListProperty;
27
import org.eclipse.core.databinding.property.IListPropertyChangeListener;
28
import org.eclipse.core.databinding.property.ListPropertyChangeEvent;
29
30
/**
31
 * @since 3.3
32
 * 
33
 */
34
public class PropertyObservableList extends AbstractObservableList {
35
	private Object source;
36
	private IListProperty property;
37
38
	private List cachedList;
39
40
	private volatile boolean updating = false;
41
42
	private boolean disposed = false;
43
44
	private transient volatile int modCount = 0;
45
46
	private IListPropertyChangeListener listener = new IListPropertyChangeListener() {
47
		public void handleListPropertyChange(final ListPropertyChangeEvent event) {
48
			if (!disposed && !updating) {
49
				getRealm().exec(new Runnable() {
50
					public void run() {
51
						getRealm().exec(new Runnable() {
52
							public void run() {
53
								modCount++;
54
								if (event.diff == null) {
55
									List oldList = cachedList;
56
									List newList = cachedList = property
57
											.getList(source);
58
									fireListChange(Diffs.computeListDiff(
59
											oldList, newList));
60
								} else {
61
									fireListChange(event.diff);
62
								}
63
							}
64
						});
65
					}
66
				});
67
			}
68
		}
69
	};
70
71
	/**
72
	 * @param realm
73
	 * @param source
74
	 * @param property
75
	 */
76
	public PropertyObservableList(Realm realm, Object source,
77
			IListProperty property) {
78
		super(realm);
79
		this.source = source;
80
		this.property = property;
81
82
		this.cachedList = property.getList(source);
83
	}
84
85
	protected void firstListenerAdded() {
86
		if (!disposed) {
87
			property.addListChangeListener(source, listener);
88
		}
89
	}
90
91
	protected void lastListenerRemoved() {
92
		if (!disposed) {
93
			property.removeListChangeListener(source, listener);
94
		}
95
	}
96
97
	private List getList() {
98
		return property.getList(source);
99
	}
100
101
	private void setList(List list) {
102
		List oldList = cachedList;
103
104
		updating = true;
105
		try {
106
			property.setList(source, new ArrayList(list));
107
			modCount++;
108
		} finally {
109
			updating = false;
110
		}
111
112
		List newList = cachedList = getList();
113
		if (!oldList.equals(newList)) {
114
			fireListChange(Diffs.computeListDiff(oldList, newList));
115
		}
116
	}
117
118
	private void getterCalled() {
119
		ObservableTracker.getterCalled(this);
120
	}
121
122
	public Object getElementType() {
123
		return property.getElementType();
124
	}
125
126
	// Queries
127
128
	protected int doGetSize() {
129
		return getList().size();
130
	}
131
132
	public boolean contains(Object o) {
133
		getterCalled();
134
		return getList().contains(o);
135
	}
136
137
	public boolean containsAll(Collection c) {
138
		getterCalled();
139
		return getList().containsAll(c);
140
	}
141
142
	public Object get(int index) {
143
		getterCalled();
144
		return getList().get(index);
145
	}
146
147
	public int indexOf(Object o) {
148
		getterCalled();
149
		return getList().indexOf(o);
150
	}
151
152
	public boolean isEmpty() {
153
		getterCalled();
154
		return getList().isEmpty();
155
	}
156
157
	public int lastIndexOf(Object o) {
158
		getterCalled();
159
		return getList().lastIndexOf(o);
160
	}
161
162
	public Object[] toArray() {
163
		getterCalled();
164
		return getList().toArray();
165
	}
166
167
	public Object[] toArray(Object[] a) {
168
		getterCalled();
169
		return getList().toArray(a);
170
	}
171
172
	// Single change operations
173
174
	public boolean add(Object o) {
175
		List list = new ArrayList(getList());
176
		boolean result = list.add(o);
177
		setList(list);
178
		return result;
179
	}
180
181
	public Iterator iterator() {
182
		getterCalled();
183
		return new Iterator() {
184
			int lastReturned = -1;
185
			int expectedModCount = modCount;
186
			ListIterator delegate = new ArrayList(getList()).listIterator();
187
188
			public boolean hasNext() {
189
				getterCalled();
190
				checkForComodification();
191
				return delegate.hasNext();
192
			}
193
194
			public Object next() {
195
				getterCalled();
196
				checkForComodification();
197
				Object next = delegate.next();
198
				lastReturned = delegate.previousIndex();
199
				return next;
200
			}
201
202
			public void remove() {
203
				checkRealm();
204
				checkForComodification();
205
				if (lastReturned == -1)
206
					throw new IllegalStateException();
207
208
				List list = new ArrayList(getList());
209
				list.remove(lastReturned);
210
				setList(list);
211
				delegate.remove(); // stay in sync
212
				lastReturned = -1;
213
				expectedModCount = modCount;
214
			}
215
216
			private void checkForComodification() {
217
				if (expectedModCount != modCount)
218
					throw new ConcurrentModificationException();
219
			}
220
		};
221
	}
222
223
	public Object move(int oldIndex, int newIndex) {
224
		getterCalled();
225
		List list = new ArrayList(getList());
226
		Object result = list.remove(oldIndex);
227
		list.add(newIndex, result);
228
		setList(list);
229
		return result;
230
	}
231
232
	public boolean remove(Object o) {
233
		getterCalled();
234
		List list = new ArrayList(getList());
235
		boolean result = list.remove(o);
236
		if (result) {
237
			setList(list);
238
		}
239
		return result;
240
	}
241
242
	public void add(int index, Object o) {
243
		getterCalled();
244
		List list = new ArrayList(getList());
245
		list.add(index, o);
246
		setList(list);
247
	}
248
249
	public ListIterator listIterator() {
250
		return listIterator(0);
251
	}
252
253
	public ListIterator listIterator(final int index) {
254
		getterCalled();
255
		return new ListIterator() {
256
			int lastReturned = -1;
257
			int expectedModCount = modCount;
258
			ListIterator delegate = new ArrayList(getList())
259
					.listIterator(index);
260
261
			public boolean hasNext() {
262
				getterCalled();
263
				checkForComodification();
264
				return delegate.hasNext();
265
			}
266
267
			public int nextIndex() {
268
				getterCalled();
269
				checkForComodification();
270
				return delegate.nextIndex();
271
			}
272
273
			public Object next() {
274
				getterCalled();
275
				checkForComodification();
276
				Object next = delegate.next();
277
				lastReturned = delegate.previousIndex();
278
				return next;
279
			}
280
281
			public boolean hasPrevious() {
282
				getterCalled();
283
				checkForComodification();
284
				return delegate.hasPrevious();
285
			}
286
287
			public int previousIndex() {
288
				getterCalled();
289
				checkForComodification();
290
				return delegate.previousIndex();
291
			}
292
293
			public Object previous() {
294
				getterCalled();
295
				checkForComodification();
296
				Object previous = delegate.previous();
297
				lastReturned = delegate.nextIndex();
298
				return previous;
299
			}
300
301
			public void add(Object o) {
302
				checkRealm();
303
				checkForComodification();
304
				int index = delegate.nextIndex();
305
306
				delegate.add(o); // keep in sync
307
308
				List list = new ArrayList(getList());
309
				list.add(index, o);
310
				setList(list);
311
312
				lastReturned = -1;
313
				expectedModCount = modCount;
314
			}
315
316
			public void set(Object o) {
317
				checkRealm();
318
				checkForComodification();
319
320
				delegate.set(o);
321
322
				List list = new ArrayList(getList());
323
				list.set(lastReturned, o);
324
				setList(list);
325
				expectedModCount = modCount;
326
			}
327
328
			public void remove() {
329
				checkRealm();
330
				checkForComodification();
331
				if (lastReturned == -1)
332
					throw new IllegalStateException();
333
334
				delegate.remove(); // keep in sync
335
336
				List list = new ArrayList(getList());
337
				list.remove(lastReturned);
338
				setList(list);
339
				lastReturned = -1;
340
				expectedModCount = modCount;
341
			}
342
343
			private void checkForComodification() {
344
				if (expectedModCount != modCount)
345
					throw new ConcurrentModificationException();
346
			}
347
348
		};
349
	}
350
351
	public Object remove(int index) {
352
		getterCalled();
353
		List list = new ArrayList(getList());
354
		Object result = list.remove(index);
355
		setList(list);
356
		return result;
357
	}
358
359
	public Object set(int index, Object o) {
360
		getterCalled();
361
		List list = new ArrayList(getList());
362
		Object result = list.set(index, o);
363
		setList(list);
364
		return result;
365
	}
366
367
	public List subList(int fromIndex, int toIndex) {
368
		getterCalled();
369
		return Collections.unmodifiableList(getList().subList(fromIndex,
370
				toIndex));
371
	}
372
373
	// Bulk change operations
374
375
	public boolean addAll(Collection c) {
376
		getterCalled();
377
		List list = new ArrayList(getList());
378
		boolean result = list.addAll(c);
379
		if (result) {
380
			setList(list);
381
		}
382
		return result;
383
	}
384
385
	public boolean addAll(int index, Collection c) {
386
		getterCalled();
387
		List list = new ArrayList(getList());
388
		boolean result = list.addAll(index, c);
389
		if (result) {
390
			setList(list);
391
		}
392
		return result;
393
	}
394
395
	public boolean removeAll(Collection c) {
396
		getterCalled();
397
		List list = new ArrayList(getList());
398
		boolean result = list.removeAll(c);
399
		if (result) {
400
			setList(list);
401
		}
402
		return result;
403
	}
404
405
	public boolean retainAll(Collection c) {
406
		getterCalled();
407
		List list = new ArrayList(getList());
408
		boolean result = retainAll(c);
409
		if (result) {
410
			setList(list);
411
		}
412
		return result;
413
	}
414
415
	public void clear() {
416
		getterCalled();
417
		setList(new ArrayList());
418
	}
419
420
	public synchronized void dispose() {
421
		if (!disposed) {
422
			disposed = true;
423
			property.removeListChangeListener(source, listener);
424
			property = null;
425
			source = null;
426
		}
427
		super.dispose();
428
	}
429
430
	public boolean equals(Object o) {
431
		getterCalled();
432
		return getList().equals(o);
433
	}
434
435
	public int hashCode() {
436
		getterCalled();
437
		return getList().hashCode();
438
	}
439
}
(-)src/org/eclipse/core/databinding/property/IPropertyChangeListener.java (+23 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006, 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
/**
15
 * Marker interface for all listener types in the properties framework.
16
 * 
17
 * @noimplement This interface is not intended to be implemented by clients.
18
 * 
19
 * @since 1.2
20
 */
21
public interface IPropertyChangeListener {
22
23
}
(-)src/org/eclipse/core/internal/databinding/property/PropertyObservableSet.java (+236 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.property;
13
14
import java.util.Collection;
15
import java.util.ConcurrentModificationException;
16
import java.util.HashSet;
17
import java.util.Iterator;
18
import java.util.Set;
19
20
import org.eclipse.core.databinding.observable.Diffs;
21
import org.eclipse.core.databinding.observable.Realm;
22
import org.eclipse.core.databinding.observable.set.AbstractObservableSet;
23
import org.eclipse.core.databinding.property.ISetProperty;
24
import org.eclipse.core.databinding.property.ISetPropertyChangeListener;
25
import org.eclipse.core.databinding.property.SetPropertyChangeEvent;
26
27
/**
28
 * @since 3.3
29
 * 
30
 */
31
public class PropertyObservableSet extends AbstractObservableSet {
32
	private Object source;
33
	private ISetProperty property;
34
35
	private Set cachedSet;
36
37
	private boolean updating = false;
38
39
	private boolean disposed = false;
40
41
	private transient volatile int modCount = 0;
42
43
	private ISetPropertyChangeListener listener = new ISetPropertyChangeListener() {
44
		public void handleSetPropertyChange(final SetPropertyChangeEvent event) {
45
			if (!disposed && !updating) {
46
				getRealm().exec(new Runnable() {
47
					public void run() {
48
						getRealm().exec(new Runnable() {
49
							public void run() {
50
								modCount++;
51
								if (event.diff == null) {
52
									Set oldSet = cachedSet;
53
									Set newSet = cachedSet = property
54
											.getSet(source);
55
									fireSetChange(Diffs.computeSetDiff(oldSet,
56
											newSet));
57
								} else {
58
									fireSetChange(event.diff);
59
								}
60
							}
61
						});
62
					}
63
				});
64
			}
65
		}
66
	};
67
68
	/**
69
	 * @param realm
70
	 * @param source
71
	 * @param property
72
	 */
73
	public PropertyObservableSet(Realm realm, Object source,
74
			ISetProperty property) {
75
		super(realm);
76
		this.source = source;
77
		this.property = property;
78
79
		this.cachedSet = property.getSet(source);
80
	}
81
82
	protected void firstListenerAdded() {
83
		if (!disposed) {
84
			property.addSetChangeListener(source, listener);
85
		}
86
	}
87
88
	protected void lastListenerRemoved() {
89
		if (!disposed) {
90
			property.removeSetChangeListener(source, listener);
91
		}
92
	}
93
94
	protected Set getWrappedSet() {
95
		return getSet();
96
	}
97
98
	private Set getSet() {
99
		return property.getSet(source);
100
	}
101
102
	private void setSet(Set set) {
103
		Set oldSet = cachedSet;
104
105
		updating = true;
106
		try {
107
			property.setSet(source, new HashSet(set));
108
			modCount++;
109
		} finally {
110
			updating = false;
111
		}
112
113
		Set newSet = cachedSet = getSet();
114
		if (!oldSet.equals(newSet)) {
115
			fireSetChange(Diffs.computeSetDiff(oldSet, newSet));
116
		}
117
	}
118
119
	public Object getElementType() {
120
		return property.getElementType();
121
	}
122
123
	// Queries
124
125
	protected int doGetSize() {
126
		return getSet().size();
127
	}
128
129
	// Single change operations
130
131
	public boolean add(Object o) {
132
		Set set = new HashSet(getSet());
133
		boolean result = set.add(o);
134
		setSet(set);
135
		return result;
136
	}
137
138
	public Iterator iterator() {
139
		getterCalled();
140
		return new Iterator() {
141
			int expectedModCount = modCount;
142
			Iterator delegate = new HashSet(getSet()).iterator();
143
			Object last = null;
144
145
			public boolean hasNext() {
146
				getterCalled();
147
				checkForComodification();
148
				return delegate.hasNext();
149
			}
150
151
			public Object next() {
152
				getterCalled();
153
				checkForComodification();
154
				Object next = delegate.next();
155
				last = next;
156
				return next;
157
			}
158
159
			public void remove() {
160
				checkRealm();
161
				checkForComodification();
162
163
				delegate.remove(); // stay in sync
164
165
				Set set = new HashSet(getSet());
166
				set.remove(last);
167
				setSet(set);
168
169
				last = null;
170
				expectedModCount = modCount;
171
			}
172
173
			private void checkForComodification() {
174
				if (expectedModCount != modCount)
175
					throw new ConcurrentModificationException();
176
			}
177
		};
178
	}
179
180
	public boolean remove(Object o) {
181
		getterCalled();
182
		Set set = new HashSet(getSet());
183
		boolean result = set.remove(o);
184
		if (result) {
185
			setSet(set);
186
		}
187
		return result;
188
	}
189
190
	// Bulk change operations
191
192
	public boolean addAll(Collection c) {
193
		getterCalled();
194
		Set set = new HashSet(getSet());
195
		boolean result = set.addAll(c);
196
		if (result) {
197
			setSet(set);
198
		}
199
		return result;
200
	}
201
202
	public boolean removeAll(Collection c) {
203
		getterCalled();
204
		Set set = new HashSet(getSet());
205
		boolean result = set.removeAll(c);
206
		if (result) {
207
			setSet(set);
208
		}
209
		return result;
210
	}
211
212
	public boolean retainAll(Collection c) {
213
		getterCalled();
214
		Set set = new HashSet(getSet());
215
		boolean result = retainAll(c);
216
		if (result) {
217
			setSet(set);
218
		}
219
		return result;
220
	}
221
222
	public void clear() {
223
		getterCalled();
224
		setSet(new HashSet());
225
	}
226
227
	public synchronized void dispose() {
228
		if (!disposed) {
229
			disposed = true;
230
			property.removeSetChangeListener(source, listener);
231
			property = null;
232
			source = null;
233
		}
234
		super.dispose();
235
	}
236
}
(-)src/org/eclipse/core/internal/databinding/property/SetValuePropertyObservableMap.java (+86 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.property;
13
14
import org.eclipse.core.databinding.observable.Diffs;
15
import org.eclipse.core.databinding.observable.map.ComputedObservableMap;
16
import org.eclipse.core.databinding.observable.set.IObservableSet;
17
import org.eclipse.core.databinding.property.IValueProperty;
18
import org.eclipse.core.databinding.property.IValuePropertyChangeListener;
19
import org.eclipse.core.databinding.property.ValuePropertyChangeEvent;
20
21
/**
22
 * @since 3.3
23
 * 
24
 */
25
public class SetValuePropertyObservableMap extends ComputedObservableMap {
26
	private IValueProperty property;
27
28
	private boolean updating = false;
29
	private boolean disposed = false;
30
31
	private IValuePropertyChangeListener listener = new IValuePropertyChangeListener() {
32
		public void handleValuePropertyChange(
33
				final ValuePropertyChangeEvent event) {
34
			if (!disposed && !updating) {
35
				getRealm().exec(new Runnable() {
36
					public void run() {
37
						fireMapChange(Diffs.createMapDiffSingleChange(event
38
								.getSource(), event.diff.getOldValue(),
39
								event.diff.getNewValue()));
40
					}
41
				});
42
			}
43
		}
44
	};
45
46
	/**
47
	 * @param keySet
48
	 * @param valueProperty
49
	 */
50
	public SetValuePropertyObservableMap(IObservableSet keySet,
51
			IValueProperty valueProperty) {
52
		super(keySet);
53
		this.property = valueProperty;
54
	}
55
56
	protected Object doGet(Object key) {
57
		return property.getValue(key);
58
	}
59
60
	protected Object doPut(Object key, Object value) {
61
		Object result = property.getValue(key);
62
		property.setValue(key, value);
63
		keySet().add(key);
64
		return result;
65
	}
66
67
	protected void hookListener(Object addedKey) {
68
		if (!disposed)
69
			property.addValueChangeListener(addedKey, listener);
70
	}
71
72
	protected void unhookListener(Object removedKey) {
73
		if (!disposed)
74
			property.removeValueChangeListener(removedKey, listener);
75
	}
76
77
	public synchronized void dispose() {
78
		super.dispose();
79
80
		if (!disposed) {
81
			disposed = true;
82
			property = null;
83
			listener = null;
84
		}
85
	}
86
}
(-)src/org/eclipse/core/internal/databinding/property/PropertyObservableValue.java (+117 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 Matthew Hall and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Matthew Hall - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.property;
13
14
import org.eclipse.core.databinding.observable.Diffs;
15
import org.eclipse.core.databinding.observable.Realm;
16
import org.eclipse.core.databinding.observable.value.AbstractObservableValue;
17
import org.eclipse.core.databinding.property.IValueProperty;
18
import org.eclipse.core.databinding.property.IValuePropertyChangeListener;
19
import org.eclipse.core.databinding.property.ValuePropertyChangeEvent;
20
import org.eclipse.core.internal.databinding.Util;
21
22
/**
23
 * @since 1.2
24
 * 
25
 */
26
public class PropertyObservableValue extends AbstractObservableValue {
27
	private Object source;
28
	private IValueProperty property;
29
30
	private Object cachedValue;
31
32
	private boolean updating = false;
33
34
	private boolean disposed = false;
35
36
	private IValuePropertyChangeListener listener = new IValuePropertyChangeListener() {
37
		public void handleValuePropertyChange(
38
				final ValuePropertyChangeEvent event) {
39
			if (!disposed && !updating) {
40
				getRealm().exec(new Runnable() {
41
					public void run() {
42
						if (event.diff == null) {
43
							Object oldValue = cachedValue;
44
							Object newValue = cachedValue = property
45
									.getValue(source);
46
							fireValueChange(Diffs.createValueDiff(oldValue,
47
									newValue));
48
						} else {
49
							fireValueChange(event.diff);
50
						}
51
					}
52
				});
53
			}
54
		}
55
	};
56
57
	/**
58
	 * @param realm
59
	 * @param source
60
	 * @param property
61
	 */
62
	public PropertyObservableValue(Realm realm, Object source,
63
			IValueProperty property) {
64
		super(realm);
65
		this.source = source;
66
		this.property = property;
67
68
		this.cachedValue = property.getValue(source);
69
	}
70
71
	protected void firstListenerAdded() {
72
		if (!disposed) {
73
			property.addValueChangeListener(source, listener);
74
		}
75
	}
76
77
	protected void lastListenerRemoved() {
78
		if (!disposed) {
79
			property.removeValueChangeListener(source, listener);
80
		}
81
	}
82
83
	protected Object doGetValue() {
84
		return property.getValue(source);
85
	}
86
87
	protected void doSetValue(Object value) {
88
		Object oldValue = cachedValue;
89
90
		updating = true;
91
		try {
92
			property.setValue(source, value);
93
		} finally {
94
			updating = false;
95
		}
96
97
		Object newValue = cachedValue = doGetValue();
98
		if (!Util.equals(oldValue, newValue)) {
99
			fireValueChange(Diffs.createValueDiff(oldValue, newValue));
100
		}
101
	}
102
103
	public Object getValueType() {
104
		return property.getValueType();
105
	}
106
107
	public synchronized void dispose() {
108
		if (!disposed) {
109
			disposed = true;
110
			property.removeValueChangeListener(source, listener);
111
			cachedValue = null;
112
			property = null;
113
			source = null;
114
		}
115
		super.dispose();
116
	}
117
}
(-)src/org/eclipse/core/databinding/property/MasterDetailProperties.java (+87 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
/**
15
 * @since 1.2
16
 */
17
public class MasterDetailProperties {
18
	/**
19
	 * @param masterValue
20
	 * @param detailValue
21
	 * @return blah
22
	 */
23
	public static IValueProperty detailValue(IValueProperty masterValue,
24
			IValueProperty detailValue) {
25
		return null;
26
	}
27
28
	/**
29
	 * @param masterList
30
	 * @param detailValue
31
	 * @return blah
32
	 */
33
	public static IListProperty detailList(IListProperty masterList,
34
			IValueProperty detailValue) {
35
		return null;
36
	}
37
38
	/**
39
	 * @param masterValue
40
	 * @param detailList
41
	 * @return blah
42
	 */
43
	public static IListProperty detailList(IValueProperty masterValue,
44
			IListProperty detailList) {
45
		return null;
46
	}
47
48
	/**
49
	 * @param masterValue
50
	 * @param detailSet
51
	 * @return blah
52
	 */
53
	public static ISetProperty detailSet(IValueProperty masterValue,
54
			ISetProperty detailSet) {
55
		return null;
56
	}
57
58
	/**
59
	 * @param masterValue
60
	 * @param detailMap
61
	 * @return blah
62
	 */
63
	public static IMapProperty detailMap(IValueProperty masterValue,
64
			IMapProperty detailMap) {
65
		return null;
66
	}
67
68
	/**
69
	 * @param masterKeySet
70
	 * @param detailValues
71
	 * @return blah
72
	 */
73
	public static IMapProperty detailMap(ISetProperty masterKeySet,
74
			IValueProperty detailValues) {
75
		return null;
76
	}
77
78
	/**
79
	 * @param masterMap
80
	 * @param detailValues
81
	 * @return blah
82
	 */
83
	public static IMapProperty detailMap(IMapProperty masterMap,
84
			IValueProperty detailValues) {
85
		return null;
86
	}
87
}
(-)src/org/eclipse/core/databinding/property/IListPropertyChangeListener.java (+22 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
/**
15
 * @since 1.2
16
 */
17
public interface IListPropertyChangeListener extends IPropertyChangeListener {
18
	/**
19
	 * @param event
20
	 */
21
	public void handleListPropertyChange(ListPropertyChangeEvent event);
22
}
(-)src/org/eclipse/core/databinding/property/Property.java (+57 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 Matthew Hall and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Matthew Hall - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
15
/**
16
 * @since 1.2
17
 * 
18
 */
19
public abstract class Property implements IProperty {
20
	private PropertyChangeSupport changeSupport;
21
22
	synchronized PropertyChangeSupport getChangeSupport() {
23
		if (changeSupport == null)
24
			changeSupport = new PropertyChangeSupport(this);
25
		return changeSupport;
26
	}
27
28
	/**
29
	 * Notifies the property that the first listener has been added for the
30
	 * given source object. Implementers should register a listener on the
31
	 * source object which fires an appropriate change event when a property
32
	 * change is observed on the source.
33
	 * 
34
	 * @param source
35
	 *            the source object to observe for property changes.
36
	 * @see #removeListenerFrom(Object)
37
	 */
38
	protected abstract void addListenerTo(Object source);
39
40
	/**
41
	 * Notifies the property that the last listener has been removed for the
42
	 * given source object. Implementers should unregister any previously
43
	 * registered listeners from the source.
44
	 * 
45
	 * @param source
46
	 *            the source object to stop observing for property changes.
47
	 * @see #addListenerTo(Object)
48
	 */
49
	protected abstract void removeListenerFrom(Object source);
50
51
	public synchronized void dispose() {
52
		if (changeSupport != null) {
53
			changeSupport.dispose();
54
			changeSupport = null;
55
		}
56
	}
57
}

Return to bug 194734