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/tests/internal/databinding/beans/JavaBeanObservableMapTest.java (-9 / +22 lines)
Lines 7-13 Link Here
7
 *
7
 *
8
 * Contributors:
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
9
 *     IBM Corporation - initial API and implementation
10
 *     Matthew Hall - bugs 213145, 241585
10
 *     Matthew Hall - bugs 213145, 241585, 194734
11
 *******************************************************************************/
11
 *******************************************************************************/
12
12
13
package org.eclipse.core.tests.internal.databinding.beans;
13
package org.eclipse.core.tests.internal.databinding.beans;
Lines 19-30 Link Here
19
import junit.framework.TestCase;
19
import junit.framework.TestCase;
20
import junit.framework.TestSuite;
20
import junit.framework.TestSuite;
21
21
22
import org.eclipse.core.databinding.beans.BeanProperties;
23
import org.eclipse.core.databinding.beans.BeansObservables;
24
import org.eclipse.core.databinding.beans.IBeanObservable;
25
import org.eclipse.core.databinding.beans.IBeanProperty;
26
import org.eclipse.core.databinding.beans.PojoObservables;
22
import org.eclipse.core.databinding.observable.Realm;
27
import org.eclipse.core.databinding.observable.Realm;
23
import org.eclipse.core.databinding.observable.map.IMapChangeListener;
28
import org.eclipse.core.databinding.observable.map.IMapChangeListener;
29
import org.eclipse.core.databinding.observable.map.IObservableMap;
24
import org.eclipse.core.databinding.observable.map.MapChangeEvent;
30
import org.eclipse.core.databinding.observable.map.MapChangeEvent;
25
import org.eclipse.core.databinding.observable.map.MapDiff;
31
import org.eclipse.core.databinding.observable.map.MapDiff;
26
import org.eclipse.core.databinding.observable.set.WritableSet;
32
import org.eclipse.core.databinding.observable.set.WritableSet;
27
import org.eclipse.core.internal.databinding.beans.JavaBeanObservableMap;
28
import org.eclipse.core.tests.databinding.observable.ThreadRealm;
33
import org.eclipse.core.tests.databinding.observable.ThreadRealm;
29
import org.eclipse.jface.databinding.conformance.util.ChangeEventTracker;
34
import org.eclipse.jface.databinding.conformance.util.ChangeEventTracker;
30
import org.eclipse.jface.databinding.conformance.util.CurrentRealm;
35
import org.eclipse.jface.databinding.conformance.util.CurrentRealm;
Lines 42-48 Link Here
42
47
43
	private PropertyDescriptor propertyDescriptor;
48
	private PropertyDescriptor propertyDescriptor;
44
49
45
	private JavaBeanObservableMap map;
50
	private IObservableMap map;
51
	private IBeanObservable beanObservable;
46
52
47
	protected void setUp() throws Exception {
53
	protected void setUp() throws Exception {
48
		ThreadRealm realm = new ThreadRealm();
54
		ThreadRealm realm = new ThreadRealm();
Lines 54-61 Link Here
54
		set.add(model1);
60
		set.add(model1);
55
		set.add(model2);
61
		set.add(model2);
56
62
57
		propertyDescriptor = new PropertyDescriptor("value", Bean.class);
63
		String propertyName = "value";
58
		map = new JavaBeanObservableMap(set, propertyDescriptor);
64
		propertyDescriptor = ((IBeanProperty) BeanProperties.valueProperty(
65
				Bean.class, propertyName)).getPropertyDescriptor();
66
		map = BeansObservables.observeMap(set, Bean.class, propertyName);
67
		beanObservable = (IBeanObservable) map;
59
	}
68
	}
60
69
61
	public void testGetValue() throws Exception {
70
	public void testGetValue() throws Exception {
Lines 135-145 Link Here
135
	}
144
	}
136
	
145
	
137
	public void testGetObserved() throws Exception {
146
	public void testGetObserved() throws Exception {
138
		assertEquals(set, map.getObserved());
147
		assertEquals(set, beanObservable.getObserved());
139
	}
148
	}
140
	
149
	
141
	public void testGetPropertyDescriptor() throws Exception {
150
	public void testGetPropertyDescriptor() throws Exception {
142
		assertEquals(propertyDescriptor, map.getPropertyDescriptor());
151
		assertEquals(propertyDescriptor, beanObservable.getPropertyDescriptor());
143
	}
152
	}
144
	
153
	
145
	public void testConstructor_SkipRegisterListeners() throws Exception {
154
	public void testConstructor_SkipRegisterListeners() throws Exception {
Lines 148-154 Link Here
148
		Bean bean = new Bean();
157
		Bean bean = new Bean();
149
		set.add(bean);
158
		set.add(bean);
150
		
159
		
151
		JavaBeanObservableMap observable = new JavaBeanObservableMap(set, new PropertyDescriptor("value", Bean.class), false);
160
		IObservableMap observable = PojoObservables.observeMap(set, Bean.class,
161
				"value");
162
		assertFalse(bean.hasListeners("value"));
152
		ChangeEventTracker.observe(observable);
163
		ChangeEventTracker.observe(observable);
153
164
154
		assertFalse(bean.hasListeners("value"));
165
		assertFalse(bean.hasListeners("value"));
Lines 160-166 Link Here
160
		Bean bean = new Bean();
171
		Bean bean = new Bean();
161
		set.add(bean);
172
		set.add(bean);
162
		
173
		
163
		JavaBeanObservableMap observable = new JavaBeanObservableMap(set, new PropertyDescriptor("value", Bean.class));
174
		IObservableMap observable = BeansObservables.observeMap(set,
175
				Bean.class, "value");
176
		assertFalse(bean.hasListeners("value"));
164
		ChangeEventTracker.observe(observable);
177
		ChangeEventTracker.observe(observable);
165
178
166
		assertTrue(bean.hasListeners("value"));
179
		assertTrue(bean.hasListeners("value"));
(-)src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableValueTest.java (-26 / +22 lines)
Lines 9-33 Link Here
9
 *     Brad Reynolds - initial API and implementation
9
 *     Brad Reynolds - initial API and implementation
10
 *     Brad Reynolds - bug 171616
10
 *     Brad Reynolds - bug 171616
11
 *     Katarzyna Marszalek - test case for bug 198519
11
 *     Katarzyna Marszalek - test case for bug 198519
12
 *     Matthew Hall - bug 213145
12
 *     Matthew Hall - bugs 213145, 194734
13
 ******************************************************************************/
13
 ******************************************************************************/
14
14
15
package org.eclipse.core.tests.internal.databinding.beans;
15
package org.eclipse.core.tests.internal.databinding.beans;
16
16
17
import java.beans.IntrospectionException;
18
import java.beans.PropertyDescriptor;
17
import java.beans.PropertyDescriptor;
19
18
20
import junit.framework.Test;
19
import junit.framework.Test;
21
import junit.framework.TestSuite;
20
import junit.framework.TestSuite;
22
21
22
import org.eclipse.core.databinding.beans.BeanProperties;
23
import org.eclipse.core.databinding.beans.BeansObservables;
23
import org.eclipse.core.databinding.beans.BeansObservables;
24
import org.eclipse.core.databinding.beans.IBeanObservable;
25
import org.eclipse.core.databinding.beans.IBeanProperty;
26
import org.eclipse.core.databinding.beans.PojoObservables;
24
import org.eclipse.core.databinding.observable.ChangeEvent;
27
import org.eclipse.core.databinding.observable.ChangeEvent;
25
import org.eclipse.core.databinding.observable.IChangeListener;
28
import org.eclipse.core.databinding.observable.IChangeListener;
26
import org.eclipse.core.databinding.observable.IObservable;
29
import org.eclipse.core.databinding.observable.IObservable;
27
import org.eclipse.core.databinding.observable.Realm;
30
import org.eclipse.core.databinding.observable.Realm;
28
import org.eclipse.core.databinding.observable.value.ComputedValue;
31
import org.eclipse.core.databinding.observable.value.ComputedValue;
29
import org.eclipse.core.databinding.observable.value.IObservableValue;
32
import org.eclipse.core.databinding.observable.value.IObservableValue;
30
import org.eclipse.core.internal.databinding.beans.JavaBeanObservableValue;
31
import org.eclipse.jface.databinding.conformance.MutableObservableValueContractTest;
33
import org.eclipse.jface.databinding.conformance.MutableObservableValueContractTest;
32
import org.eclipse.jface.databinding.conformance.delegate.AbstractObservableValueContractDelegate;
34
import org.eclipse.jface.databinding.conformance.delegate.AbstractObservableValueContractDelegate;
33
import org.eclipse.jface.databinding.conformance.util.ChangeEventTracker;
35
import org.eclipse.jface.databinding.conformance.util.ChangeEventTracker;
Lines 39-73 Link Here
39
 */
41
 */
40
public class JavaBeanObservableValueTest extends AbstractDefaultRealmTestCase {
42
public class JavaBeanObservableValueTest extends AbstractDefaultRealmTestCase {
41
	private Bean bean;
43
	private Bean bean;
42
	private JavaBeanObservableValue observableValue;
44
	private IObservableValue observableValue;
45
	private IBeanObservable beanObservable;
43
	private PropertyDescriptor propertyDescriptor;
46
	private PropertyDescriptor propertyDescriptor;
44
	private String propertyName;
47
	private String propertyName;
45
48
46
	/* (non-Javadoc)
47
	 * @see junit.framework.TestCase#setUp()
48
	 */
49
	protected void setUp() throws Exception {
49
	protected void setUp() throws Exception {
50
		super.setUp();
50
		super.setUp();
51
		
51
		
52
		bean = new Bean();
52
		bean = new Bean();
53
		propertyName = "value";
53
		propertyName = "value";
54
		propertyDescriptor = new PropertyDescriptor(propertyName, Bean.class);
54
		propertyDescriptor = ((IBeanProperty) BeanProperties.valueProperty(
55
		observableValue = new JavaBeanObservableValue(Realm.getDefault(), bean, propertyDescriptor);
55
				Bean.class, propertyName)).getPropertyDescriptor();
56
		observableValue = BeansObservables.observeValue(bean, propertyName);
57
		beanObservable = (IBeanObservable) observableValue;
56
	}
58
	}
57
59
58
	public void testGetObserved() throws Exception {
60
	public void testGetObserved() throws Exception {
59
		assertEquals(bean, observableValue.getObserved());
61
		assertEquals(bean, beanObservable.getObserved());
60
	}
62
	}
61
63
62
	public void testGetPropertyDescriptor() throws Exception {
64
	public void testGetPropertyDescriptor() throws Exception {
63
    	assertEquals(propertyDescriptor, observableValue.getPropertyDescriptor());
65
    	assertEquals(propertyDescriptor, beanObservable.getPropertyDescriptor());
64
	}
66
	}
65
67
66
	public void testSetValueThrowsExceptionThrownByBean() throws Exception {
68
	public void testSetValueThrowsExceptionThrownByBean() throws Exception {
67
		ThrowsSetException temp = new ThrowsSetException();
69
		ThrowsSetException temp = new ThrowsSetException();
68
		JavaBeanObservableValue observable = new JavaBeanObservableValue(Realm
70
		IObservableValue observable = BeansObservables.observeValue(temp,
69
				.getDefault(), temp,
71
				"value");
70
				new PropertyDescriptor("value", ThrowsSetException.class));
71
72
72
		try {
73
		try {
73
			observable.setValue("");
74
			observable.setValue("");
Lines 79-87 Link Here
79
	
80
	
80
	public void testGetValueThrowsExceptionThrownByBean() throws Exception {
81
	public void testGetValueThrowsExceptionThrownByBean() throws Exception {
81
		ThrowsGetException temp = new ThrowsGetException();
82
		ThrowsGetException temp = new ThrowsGetException();
82
		JavaBeanObservableValue observable = new JavaBeanObservableValue(Realm
83
		IObservableValue observable = BeansObservables.observeValue(temp,
83
				.getDefault(), temp,
84
				"value");
84
				new PropertyDescriptor("value", ThrowsGetException.class));
85
85
86
		try {
86
		try {
87
			observable.getValue();
87
			observable.getValue();
Lines 108-121 Link Here
108
	}
108
	}
109
109
110
	public void testConstructor_RegistersListeners() throws Exception {
110
	public void testConstructor_RegistersListeners() throws Exception {
111
		JavaBeanObservableValue observable = new JavaBeanObservableValue(Realm.getDefault(), bean, propertyDescriptor);
111
		IObservableValue observable = BeansObservables.observeValue(bean,
112
				propertyName);
112
		ChangeEventTracker.observe(observable);
113
		ChangeEventTracker.observe(observable);
113
		
114
		
114
		assertTrue(bean.hasListeners(propertyName));
115
		assertTrue(bean.hasListeners(propertyName));
115
	}
116
	}
116
	
117
	
117
	public void testConstructor_SkipRegisterListeners() throws Exception {
118
	public void testConstructor_SkipRegisterListeners() throws Exception {
118
		JavaBeanObservableValue observable = new JavaBeanObservableValue(Realm.getDefault(), bean, propertyDescriptor, false);
119
		IObservableValue observable = PojoObservables.observeValue(bean,
120
				propertyName);
119
		ChangeEventTracker.observe(observable);
121
		ChangeEventTracker.observe(observable);
120
		
122
		
121
		assertFalse(bean.hasListeners(propertyName));
123
		assertFalse(bean.hasListeners(propertyName));
Lines 138-150 Link Here
138
		}
140
		}
139
		
141
		
140
		public IObservableValue createObservableValue(Realm realm) {
142
		public IObservableValue createObservableValue(Realm realm) {
141
			try {
143
			return BeansObservables.observeValue(realm, bean, "value");
142
				PropertyDescriptor propertyDescriptor = new PropertyDescriptor("value", Bean.class);
143
				return new JavaBeanObservableValue(realm, bean,
144
						propertyDescriptor);					
145
			} catch (IntrospectionException e) {
146
				throw new RuntimeException(e);
147
			}
148
		}
144
		}
149
		
145
		
150
		public void change(IObservable observable) {
146
		public void change(IObservable observable) {
(-)src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableArrayBasedListTest.java (-32 / +25 lines)
Lines 7-18 Link Here
7
 *
7
 *
8
 * Contributors:
8
 * Contributors:
9
 *     Brad Reynolds - initial API and implementation
9
 *     Brad Reynolds - initial API and implementation
10
 *     Matthew Hall - bugs 221351, 213145
10
 *     Matthew Hall - bugs 221351, 213145, 194734
11
 ******************************************************************************/
11
 ******************************************************************************/
12
12
13
package org.eclipse.core.tests.internal.databinding.beans;
13
package org.eclipse.core.tests.internal.databinding.beans;
14
14
15
import java.beans.IntrospectionException;
16
import java.beans.PropertyChangeEvent;
15
import java.beans.PropertyChangeEvent;
17
import java.beans.PropertyChangeListener;
16
import java.beans.PropertyChangeListener;
18
import java.beans.PropertyDescriptor;
17
import java.beans.PropertyDescriptor;
Lines 23-35 Link Here
23
import junit.framework.Test;
22
import junit.framework.Test;
24
import junit.framework.TestSuite;
23
import junit.framework.TestSuite;
25
24
25
import org.eclipse.core.databinding.beans.BeanProperties;
26
import org.eclipse.core.databinding.beans.BeansObservables;
27
import org.eclipse.core.databinding.beans.IBeanObservable;
28
import org.eclipse.core.databinding.beans.IBeanProperty;
26
import org.eclipse.core.databinding.observable.IObservable;
29
import org.eclipse.core.databinding.observable.IObservable;
27
import org.eclipse.core.databinding.observable.IObservableCollection;
30
import org.eclipse.core.databinding.observable.IObservableCollection;
28
import org.eclipse.core.databinding.observable.Realm;
31
import org.eclipse.core.databinding.observable.Realm;
29
import org.eclipse.core.databinding.observable.list.IObservableList;
32
import org.eclipse.core.databinding.observable.list.IObservableList;
30
import org.eclipse.core.databinding.observable.list.ListChangeEvent;
33
import org.eclipse.core.databinding.observable.list.ListChangeEvent;
31
import org.eclipse.core.databinding.observable.list.ListDiffEntry;
34
import org.eclipse.core.databinding.observable.list.ListDiffEntry;
32
import org.eclipse.core.internal.databinding.beans.JavaBeanObservableList;
33
import org.eclipse.jface.databinding.conformance.MutableObservableListContractTest;
35
import org.eclipse.jface.databinding.conformance.MutableObservableListContractTest;
34
import org.eclipse.jface.databinding.conformance.delegate.AbstractObservableCollectionContractDelegate;
36
import org.eclipse.jface.databinding.conformance.delegate.AbstractObservableCollectionContractDelegate;
35
import org.eclipse.jface.databinding.conformance.util.ListChangeEventTracker;
37
import org.eclipse.jface.databinding.conformance.util.ListChangeEventTracker;
Lines 42-48 Link Here
42
 */
44
 */
43
public class JavaBeanObservableArrayBasedListTest extends
45
public class JavaBeanObservableArrayBasedListTest extends
44
		AbstractDefaultRealmTestCase {
46
		AbstractDefaultRealmTestCase {
45
	private JavaBeanObservableList list;
47
	private IObservableList list;
48
	private IBeanObservable beanObservable;
46
49
47
	private PropertyDescriptor propertyDescriptor;
50
	private PropertyDescriptor propertyDescriptor;
48
51
Lines 59-77 Link Here
59
		super.setUp();
62
		super.setUp();
60
63
61
		propertyName = "array";
64
		propertyName = "array";
62
		propertyDescriptor = new PropertyDescriptor(propertyName, Bean.class);
65
		propertyDescriptor = ((IBeanProperty) BeanProperties.listProperty(
66
				Bean.class, propertyName)).getPropertyDescriptor();
63
		bean = new Bean(new Object[0]);
67
		bean = new Bean(new Object[0]);
64
68
65
		list = new JavaBeanObservableList(SWTObservables.getRealm(Display
69
		list = BeansObservables.observeList(SWTObservables.getRealm(Display
66
				.getDefault()), bean, propertyDescriptor, Bean.class);
70
				.getDefault()), bean, propertyName);
71
		beanObservable = (IBeanObservable) list;
67
	}
72
	}
68
73
69
	public void testGetObserved() throws Exception {
74
	public void testGetObserved() throws Exception {
70
		assertSame(bean, list.getObserved());
75
		assertSame(bean, beanObservable.getObserved());
71
	}
76
	}
72
77
73
	public void testGetPropertyDescriptor() throws Exception {
78
	public void testGetPropertyDescriptor() throws Exception {
74
		assertSame(propertyDescriptor, list.getPropertyDescriptor());
79
		assertEquals(propertyDescriptor, beanObservable.getPropertyDescriptor());
75
	}
80
	}
76
81
77
	public void testRegistersListenerAfterFirstListenerIsAdded()
82
	public void testRegistersListenerAfterFirstListenerIsAdded()
Lines 308-323 Link Here
308
	}
313
	}
309
314
310
	public void testRemoveAll() throws Exception {
315
	public void testRemoveAll() throws Exception {
311
		List elements = Arrays.asList(new String[] { "1", "2" });
316
		list.addAll(Arrays.asList(new String[] { "1", "2", "3", "4" }));
312
		list.addAll(elements);
313
		list.addAll(elements);
314
315
		assertEquals(4, bean.getArray().length);
317
		assertEquals(4, bean.getArray().length);
316
		list.removeAll(elements);
318
319
		list.removeAll(Arrays.asList(new String[] { "2", "4" }));
317
320
318
		assertEquals(2, bean.getArray().length);
321
		assertEquals(2, bean.getArray().length);
319
		assertEquals(elements.get(0), bean.getArray()[0]);
322
		assertEquals("1", bean.getArray()[0]);
320
		assertEquals(elements.get(1), bean.getArray()[1]);
323
		assertEquals("3", bean.getArray()[1]);
321
	}
324
	}
322
325
323
	public void testRemoveAllListChangeEvent() throws Exception {
326
	public void testRemoveAllListChangeEvent() throws Exception {
Lines 471-478 Link Here
471
		PropertyChangeEvent event = listener.evt;
474
		PropertyChangeEvent event = listener.evt;
472
		assertEquals("event did not fire", 1, listener.count);
475
		assertEquals("event did not fire", 1, listener.count);
473
		assertEquals("array", event.getPropertyName());
476
		assertEquals("array", event.getPropertyName());
474
		assertTrue("old value", Arrays.equals(old, (Object[]) event.getOldValue()));
477
		assertTrue("old value", Arrays.equals(old, (Object[]) event
475
		assertTrue("new value", Arrays.equals(bean.getArray(), (Object[]) event.getNewValue()));
478
				.getOldValue()));
479
		assertTrue("new value", Arrays.equals(bean.getArray(), (Object[]) event
480
				.getNewValue()));
476
		assertFalse("lists are equal", Arrays.equals(bean.getArray(), old));
481
		assertFalse("lists are equal", Arrays.equals(bean.getArray(), old));
477
	}
482
	}
478
483
Lines 482-492 Link Here
482
487
483
		PropertyChangeEvent evt;
488
		PropertyChangeEvent evt;
484
489
485
		/*
486
		 * (non-Javadoc)
487
		 * 
488
		 * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
489
		 */
490
		public void propertyChange(PropertyChangeEvent evt) {
490
		public void propertyChange(PropertyChangeEvent evt) {
491
			count++;
491
			count++;
492
			this.evt = evt;
492
			this.evt = evt;
Lines 504-520 Link Here
504
		public IObservableCollection createObservableCollection(Realm realm,
504
		public IObservableCollection createObservableCollection(Realm realm,
505
				int elementCount) {
505
				int elementCount) {
506
			String propertyName = "array";
506
			String propertyName = "array";
507
			PropertyDescriptor propertyDescriptor;
508
			try {
509
				propertyDescriptor = new PropertyDescriptor(propertyName,
510
						Bean.class);
511
			} catch (IntrospectionException e) {
512
				throw new RuntimeException(e);
513
			}
514
			Object bean = new Bean(new Object[0]);
507
			Object bean = new Bean(new Object[0]);
515
508
516
			IObservableList list = new JavaBeanObservableList(realm, bean,
509
			IObservableList list = BeansObservables.observeList(realm, bean,
517
					propertyDescriptor, String.class);
510
					propertyName, String.class);
518
			for (int i = 0; i < elementCount; i++)
511
			for (int i = 0; i < elementCount; i++)
519
				list.add(createElement(list));
512
				list.add(createElement(list));
520
			return list;
513
			return list;
(-)src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableSetTest.java (-28 / +22 lines)
Lines 7-18 Link Here
7
 *
7
 *
8
 * Contributors:
8
 * Contributors:
9
 *     Brad Reynolds - initial API and implementation
9
 *     Brad Reynolds - initial API and implementation
10
 *     Matthew Hall - bugs 221351, 213145
10
 *     Matthew Hall - bugs 221351, 213145, 194734
11
 ******************************************************************************/
11
 ******************************************************************************/
12
12
13
package org.eclipse.core.tests.internal.databinding.beans;
13
package org.eclipse.core.tests.internal.databinding.beans;
14
14
15
import java.beans.IntrospectionException;
16
import java.beans.PropertyDescriptor;
15
import java.beans.PropertyDescriptor;
17
import java.util.Arrays;
16
import java.util.Arrays;
18
import java.util.HashSet;
17
import java.util.HashSet;
Lines 21-33 Link Here
21
import junit.framework.TestCase;
20
import junit.framework.TestCase;
22
import junit.framework.TestSuite;
21
import junit.framework.TestSuite;
23
22
23
import org.eclipse.core.databinding.beans.BeanProperties;
24
import org.eclipse.core.databinding.beans.BeansObservables;
25
import org.eclipse.core.databinding.beans.IBeanObservable;
26
import org.eclipse.core.databinding.beans.IBeanProperty;
27
import org.eclipse.core.databinding.beans.PojoObservables;
24
import org.eclipse.core.databinding.observable.IObservable;
28
import org.eclipse.core.databinding.observable.IObservable;
25
import org.eclipse.core.databinding.observable.IObservableCollection;
29
import org.eclipse.core.databinding.observable.IObservableCollection;
26
import org.eclipse.core.databinding.observable.Realm;
30
import org.eclipse.core.databinding.observable.Realm;
27
import org.eclipse.core.databinding.observable.set.IObservableSet;
31
import org.eclipse.core.databinding.observable.set.IObservableSet;
28
import org.eclipse.core.databinding.observable.set.ISetChangeListener;
32
import org.eclipse.core.databinding.observable.set.ISetChangeListener;
29
import org.eclipse.core.databinding.observable.set.SetChangeEvent;
33
import org.eclipse.core.databinding.observable.set.SetChangeEvent;
30
import org.eclipse.core.internal.databinding.beans.JavaBeanObservableSet;
31
import org.eclipse.jface.databinding.conformance.MutableObservableSetContractTest;
34
import org.eclipse.jface.databinding.conformance.MutableObservableSetContractTest;
32
import org.eclipse.jface.databinding.conformance.delegate.AbstractObservableCollectionContractDelegate;
35
import org.eclipse.jface.databinding.conformance.delegate.AbstractObservableCollectionContractDelegate;
33
import org.eclipse.jface.databinding.conformance.util.ChangeEventTracker;
36
import org.eclipse.jface.databinding.conformance.util.ChangeEventTracker;
Lines 39-72 Link Here
39
 * @since 3.3
42
 * @since 3.3
40
 */
43
 */
41
public class JavaBeanObservableSetTest extends TestCase {
44
public class JavaBeanObservableSetTest extends TestCase {
42
	private JavaBeanObservableSet observableSet;
45
	private IObservableSet observableSet;
46
	private IBeanObservable beanObservable;
43
	private Bean bean;
47
	private Bean bean;
44
	private PropertyDescriptor propertyDescriptor;
48
	private PropertyDescriptor propertyDescriptor;
45
	private String propertyName;
49
	private String propertyName;
46
	private SetChangeListener listener;
50
	private SetChangeListener listener;
47
51
48
	/*
49
	 * (non-Javadoc)
50
	 * 
51
	 * @see junit.framework.TestCase#setUp()
52
	 */
53
	protected void setUp() throws Exception {
52
	protected void setUp() throws Exception {
54
		bean = new Bean();
53
		bean = new Bean();
55
		propertyName = "set";
54
		propertyName = "set";
56
		propertyDescriptor = new PropertyDescriptor(propertyName, Bean.class);
55
		propertyDescriptor = ((IBeanProperty) BeanProperties.setProperty(
56
				Bean.class, propertyName)).getPropertyDescriptor();
57
57
58
		observableSet = new JavaBeanObservableSet(SWTObservables
58
		observableSet = BeansObservables
59
				.getRealm(Display.getDefault()), bean, propertyDescriptor,
59
				.observeSet(SWTObservables.getRealm(Display.getDefault()),
60
				Bean.class);
60
						bean, propertyName, Bean.class);
61
		beanObservable = (IBeanObservable) observableSet;
61
		listener = new SetChangeListener();
62
		listener = new SetChangeListener();
62
	}
63
	}
63
64
64
	public void testGetObserved() throws Exception {
65
	public void testGetObserved() throws Exception {
65
		assertEquals(bean, observableSet.getObserved());
66
		assertEquals(bean, beanObservable.getObserved());
66
	}
67
	}
67
68
68
	public void testGetPropertyDescriptor() throws Exception {
69
	public void testGetPropertyDescriptor() throws Exception {
69
		assertEquals(propertyDescriptor, observableSet.getPropertyDescriptor());
70
		assertEquals(propertyDescriptor, beanObservable.getPropertyDescriptor());
70
	}
71
	}
71
	
72
	
72
	public void testGetElementType() throws Exception {
73
	public void testGetElementType() throws Exception {
Lines 97-104 Link Here
97
	public void testConstructor_RegisterListeners() throws Exception {
98
	public void testConstructor_RegisterListeners() throws Exception {
98
		bean = new Bean();
99
		bean = new Bean();
99
100
100
		observableSet = new JavaBeanObservableSet(new CurrentRealm(true), bean,
101
		observableSet = BeansObservables.observeSet(new CurrentRealm(true),
101
				propertyDescriptor, Bean.class);
102
				bean, propertyName);
102
		assertFalse(bean.hasListeners(propertyName));
103
		assertFalse(bean.hasListeners(propertyName));
103
		ChangeEventTracker.observe(observableSet);
104
		ChangeEventTracker.observe(observableSet);
104
		assertTrue(bean.hasListeners(propertyName));
105
		assertTrue(bean.hasListeners(propertyName));
Lines 107-114 Link Here
107
	public void testConstructor_SkipsRegisterListeners() throws Exception {
108
	public void testConstructor_SkipsRegisterListeners() throws Exception {
108
		bean = new Bean();
109
		bean = new Bean();
109
110
110
		observableSet = new JavaBeanObservableSet(new CurrentRealm(true), bean,
111
		observableSet = PojoObservables.observeSet(new CurrentRealm(true),
111
				propertyDescriptor, Bean.class, false);
112
				bean, propertyName);
112
		assertFalse(bean.hasListeners(propertyName));
113
		assertFalse(bean.hasListeners(propertyName));
113
		ChangeEventTracker.observe(observableSet);
114
		ChangeEventTracker.observe(observableSet);
114
		assertFalse(bean.hasListeners(propertyName));
115
		assertFalse(bean.hasListeners(propertyName));
Lines 134-149 Link Here
134
				int elementCount) {
135
				int elementCount) {
135
			Bean bean = new Bean();
136
			Bean bean = new Bean();
136
			String propertyName = "set";
137
			String propertyName = "set";
137
			PropertyDescriptor propertyDescriptor;
138
			try {
139
				propertyDescriptor = new PropertyDescriptor(propertyName,
140
						Bean.class);
141
			} catch (IntrospectionException e) {
142
				throw new RuntimeException(e);
143
			}
144
138
145
			IObservableSet set = new JavaBeanObservableSet(realm,
139
			IObservableSet set = BeansObservables.observeSet(realm, bean,
146
					bean, propertyDescriptor, String.class);
140
					propertyName, String.class);
147
			for (int i = 0; i < elementCount; i++)
141
			for (int i = 0; i < elementCount; i++)
148
				set.add(createElement(set));
142
				set.add(createElement(set));
149
			return set;
143
			return set;
(-)src/org/eclipse/core/tests/internal/databinding/beans/BeanObservableValueDecoratorTest.java (-21 / +15 lines)
Lines 14-21 Link Here
14
14
15
import java.beans.PropertyDescriptor;
15
import java.beans.PropertyDescriptor;
16
16
17
import org.eclipse.core.databinding.beans.BeansObservables;
18
import org.eclipse.core.databinding.observable.value.IObservableValue;
17
import org.eclipse.core.internal.databinding.beans.BeanObservableValueDecorator;
19
import org.eclipse.core.internal.databinding.beans.BeanObservableValueDecorator;
18
import org.eclipse.core.internal.databinding.beans.JavaBeanObservableValue;
19
import org.eclipse.jface.databinding.swt.SWTObservables;
20
import org.eclipse.jface.databinding.swt.SWTObservables;
20
import org.eclipse.jface.tests.databinding.AbstractDefaultRealmTestCase;
21
import org.eclipse.jface.tests.databinding.AbstractDefaultRealmTestCase;
21
import org.eclipse.swt.widgets.Display;
22
import org.eclipse.swt.widgets.Display;
Lines 23-62 Link Here
23
/**
24
/**
24
 * @since 3.3
25
 * @since 3.3
25
 */
26
 */
26
public class BeanObservableValueDecoratorTest extends AbstractDefaultRealmTestCase {
27
public class BeanObservableValueDecoratorTest extends
28
		AbstractDefaultRealmTestCase {
27
	private Bean bean;
29
	private Bean bean;
28
	private JavaBeanObservableValue observableValue;
30
	private IObservableValue observableValue;
29
	private BeanObservableValueDecorator decorator;
31
	private BeanObservableValueDecorator decorator;
30
	private PropertyDescriptor propertyDescriptor;
32
	private PropertyDescriptor propertyDescriptor;
31
	
33
32
	/*
33
	 * (non-Javadoc)
34
	 * 
35
	 * @see junit.framework.TestCase#setUp()
36
	 */
37
	protected void setUp() throws Exception {
34
	protected void setUp() throws Exception {
38
		super.setUp();
35
		super.setUp();
39
		
36
40
		bean = new Bean();
37
		bean = new Bean();
41
		propertyDescriptor = new PropertyDescriptor("value",
38
		propertyDescriptor = new PropertyDescriptor("value", Bean.class);
42
				Bean.class);
39
		observableValue = BeansObservables.observeValue(SWTObservables
43
		observableValue = new JavaBeanObservableValue(
40
				.getRealm(Display.getDefault()), bean, "value");
44
				SWTObservables.getRealm(Display.getDefault()), bean,
41
		decorator = new BeanObservableValueDecorator(observableValue,
45
				propertyDescriptor);
42
				propertyDescriptor);
46
		decorator = new BeanObservableValueDecorator(
47
				observableValue, observableValue
48
						.getPropertyDescriptor());
49
	}
43
	}
50
44
51
	public void testGetDelegate() throws Exception {
45
	public void testGetDelegate() throws Exception {
52
		assertEquals(observableValue, decorator.getDecorated());
46
		assertSame(observableValue, decorator.getDecorated());
53
	}
47
	}
54
	
48
55
	public void testGetObserved() throws Exception {
49
	public void testGetObserved() throws Exception {
56
		assertEquals(bean, decorator.getObserved());
50
		assertSame(bean, decorator.getObserved());
57
	}
51
	}
58
52
59
	public void testGetPropertyDescriptor() throws Exception {
53
	public void testGetPropertyDescriptor() throws Exception {
60
		assertEquals(propertyDescriptor, decorator.getPropertyDescriptor());
54
		assertSame(propertyDescriptor, decorator.getPropertyDescriptor());
61
	}
55
	}
62
}
56
}
(-)src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableArrayBasedSetTest.java (-24 / +18 lines)
Lines 8-19 Link Here
8
 * Contributors:
8
 * Contributors:
9
 *     Matthew Hall - initial API and implementation (bug 221351)
9
 *     Matthew Hall - initial API and implementation (bug 221351)
10
 *     Brad Reynolds - through JavaBeanObservableArrayBasedListTest.java
10
 *     Brad Reynolds - through JavaBeanObservableArrayBasedListTest.java
11
 *     Matthew Hall - bug 213145
11
 *     Matthew Hall - bugs 213145, 194734
12
 ******************************************************************************/
12
 ******************************************************************************/
13
13
14
package org.eclipse.core.tests.internal.databinding.beans;
14
package org.eclipse.core.tests.internal.databinding.beans;
15
15
16
import java.beans.IntrospectionException;
17
import java.beans.PropertyChangeEvent;
16
import java.beans.PropertyChangeEvent;
18
import java.beans.PropertyChangeListener;
17
import java.beans.PropertyChangeListener;
19
import java.beans.PropertyDescriptor;
18
import java.beans.PropertyDescriptor;
Lines 25-36 Link Here
25
import junit.framework.Test;
24
import junit.framework.Test;
26
import junit.framework.TestSuite;
25
import junit.framework.TestSuite;
27
26
27
import org.eclipse.core.databinding.beans.BeanProperties;
28
import org.eclipse.core.databinding.beans.BeansObservables;
29
import org.eclipse.core.databinding.beans.IBeanObservable;
30
import org.eclipse.core.databinding.beans.IBeanProperty;
28
import org.eclipse.core.databinding.observable.IObservable;
31
import org.eclipse.core.databinding.observable.IObservable;
29
import org.eclipse.core.databinding.observable.IObservableCollection;
32
import org.eclipse.core.databinding.observable.IObservableCollection;
30
import org.eclipse.core.databinding.observable.Realm;
33
import org.eclipse.core.databinding.observable.Realm;
31
import org.eclipse.core.databinding.observable.set.IObservableSet;
34
import org.eclipse.core.databinding.observable.set.IObservableSet;
32
import org.eclipse.core.databinding.observable.set.SetChangeEvent;
35
import org.eclipse.core.databinding.observable.set.SetChangeEvent;
33
import org.eclipse.core.internal.databinding.beans.JavaBeanObservableSet;
34
import org.eclipse.jface.databinding.conformance.MutableObservableSetContractTest;
36
import org.eclipse.jface.databinding.conformance.MutableObservableSetContractTest;
35
import org.eclipse.jface.databinding.conformance.delegate.AbstractObservableCollectionContractDelegate;
37
import org.eclipse.jface.databinding.conformance.delegate.AbstractObservableCollectionContractDelegate;
36
import org.eclipse.jface.databinding.conformance.util.SetChangeEventTracker;
38
import org.eclipse.jface.databinding.conformance.util.SetChangeEventTracker;
Lines 43-49 Link Here
43
 */
45
 */
44
public class JavaBeanObservableArrayBasedSetTest extends
46
public class JavaBeanObservableArrayBasedSetTest extends
45
		AbstractDefaultRealmTestCase {
47
		AbstractDefaultRealmTestCase {
46
	private JavaBeanObservableSet set;
48
	private IObservableSet set;
49
	private IBeanObservable beanObservable;
47
50
48
	private PropertyDescriptor propertyDescriptor;
51
	private PropertyDescriptor propertyDescriptor;
49
52
Lines 55-73 Link Here
55
		super.setUp();
58
		super.setUp();
56
59
57
		propertyName = "array";
60
		propertyName = "array";
58
		propertyDescriptor = new PropertyDescriptor(propertyName, Bean.class);
61
		propertyDescriptor = ((IBeanProperty) BeanProperties.setProperty(
62
				Bean.class, propertyName)).getPropertyDescriptor();
59
		bean = new Bean(new HashSet());
63
		bean = new Bean(new HashSet());
60
64
61
		set = new JavaBeanObservableSet(SWTObservables.getRealm(Display
65
		set = BeansObservables.observeSet(SWTObservables.getRealm(Display
62
				.getDefault()), bean, propertyDescriptor, String.class);
66
				.getDefault()), bean, propertyName);
67
		beanObservable = (IBeanObservable) set;
63
	}
68
	}
64
69
65
	public void testGetObserved() throws Exception {
70
	public void testGetObserved() throws Exception {
66
		assertEquals(bean, set.getObserved());
71
		assertEquals(bean, beanObservable.getObserved());
67
	}
72
	}
68
73
69
	public void testGetPropertyDescriptor() throws Exception {
74
	public void testGetPropertyDescriptor() throws Exception {
70
		assertEquals(propertyDescriptor, set.getPropertyDescriptor());
75
		assertEquals(propertyDescriptor, beanObservable.getPropertyDescriptor());
71
	}
76
	}
72
77
73
	public void testRegistersListenerAfterFirstListenerIsAdded()
78
	public void testRegistersListenerAfterFirstListenerIsAdded()
Lines 292-298 Link Here
292
		assertEquals("array", event.getPropertyName());
297
		assertEquals("array", event.getPropertyName());
293
		assertTrue("old value", Arrays.equals(old, (Object[]) event
298
		assertTrue("old value", Arrays.equals(old, (Object[]) event
294
				.getOldValue()));
299
				.getOldValue()));
295
		assertTrue("new value", Arrays.equals(bean.getArray(), (Object[]) event.getNewValue()));
300
		assertTrue("new value", Arrays.equals(bean.getArray(), (Object[]) event
301
				.getNewValue()));
296
		assertFalse("lists are equal", Arrays.equals(bean.getArray(), old));
302
		assertFalse("lists are equal", Arrays.equals(bean.getArray(), old));
297
	}
303
	}
298
304
Lines 302-312 Link Here
302
308
303
		PropertyChangeEvent evt;
309
		PropertyChangeEvent evt;
304
310
305
		/*
306
		 * (non-Javadoc)
307
		 * 
308
		 * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
309
		 */
310
		public void propertyChange(PropertyChangeEvent evt) {
311
		public void propertyChange(PropertyChangeEvent evt) {
311
			count++;
312
			count++;
312
			this.evt = evt;
313
			this.evt = evt;
Lines 324-340 Link Here
324
		public IObservableCollection createObservableCollection(Realm realm,
325
		public IObservableCollection createObservableCollection(Realm realm,
325
				int elementCount) {
326
				int elementCount) {
326
			String propertyName = "array";
327
			String propertyName = "array";
327
			PropertyDescriptor propertyDescriptor;
328
			try {
329
				propertyDescriptor = new PropertyDescriptor(propertyName,
330
						Bean.class);
331
			} catch (IntrospectionException e) {
332
				throw new RuntimeException(e);
333
			}
334
			Object bean = new Bean(new Object[0]);
328
			Object bean = new Bean(new Object[0]);
335
329
336
			IObservableSet list = new JavaBeanObservableSet(realm, bean,
330
			IObservableSet list = BeansObservables.observeSet(realm, bean,
337
					propertyDescriptor, String.class);
331
					propertyName, String.class);
338
			for (int i = 0; i < elementCount; i++)
332
			for (int i = 0; i < elementCount; i++)
339
				list.add(createElement(list));
333
				list.add(createElement(list));
340
			return list;
334
			return list;
(-)src/org/eclipse/core/tests/internal/databinding/beans/BeanObservableSetDecoratorTest.java (-18 / +12 lines)
Lines 16-23 Link Here
16
16
17
import junit.framework.TestCase;
17
import junit.framework.TestCase;
18
18
19
import org.eclipse.core.databinding.beans.BeansObservables;
20
import org.eclipse.core.databinding.observable.set.IObservableSet;
19
import org.eclipse.core.internal.databinding.beans.BeanObservableSetDecorator;
21
import org.eclipse.core.internal.databinding.beans.BeanObservableSetDecorator;
20
import org.eclipse.core.internal.databinding.beans.JavaBeanObservableSet;
21
import org.eclipse.jface.databinding.swt.SWTObservables;
22
import org.eclipse.jface.databinding.swt.SWTObservables;
22
import org.eclipse.swt.widgets.Display;
23
import org.eclipse.swt.widgets.Display;
23
24
Lines 26-62 Link Here
26
 */
27
 */
27
public class BeanObservableSetDecoratorTest extends TestCase {
28
public class BeanObservableSetDecoratorTest extends TestCase {
28
	private PropertyDescriptor propertyDescriptor;
29
	private PropertyDescriptor propertyDescriptor;
29
	private JavaBeanObservableSet observableSet;
30
	private IObservableSet observableSet;
30
	private BeanObservableSetDecorator decorator;
31
	private BeanObservableSetDecorator decorator;
31
	private Bean bean;
32
	private Bean bean;
32
33
33
	/*
34
	 * (non-Javadoc)
35
	 * 
36
	 * @see junit.framework.TestCase#setUp()
37
	 */
38
	protected void setUp() throws Exception {
34
	protected void setUp() throws Exception {
39
		super.setUp();
35
		super.setUp();
40
36
41
		bean = new Bean();
37
		bean = new Bean();
42
		propertyDescriptor = new PropertyDescriptor("set",
38
		propertyDescriptor = new PropertyDescriptor("set", Bean.class);
43
				Bean.class);
39
		observableSet = BeansObservables.observeSet(SWTObservables
44
		observableSet = new JavaBeanObservableSet(
40
				.getRealm(Display.getDefault()), bean, "set");
45
				SWTObservables.getRealm(Display.getDefault()), bean,
41
		decorator = new BeanObservableSetDecorator(observableSet,
46
				propertyDescriptor, String.class);
42
				propertyDescriptor);
47
		decorator = new BeanObservableSetDecorator(
48
				observableSet, propertyDescriptor);
49
	}
43
	}
50
44
51
	public void testGetDelegate() throws Exception {
45
	public void testGetDecorated() throws Exception {
52
		assertEquals(observableSet, decorator.getDecorated());
46
		assertSame(observableSet, decorator.getDecorated());
53
	}
47
	}
54
48
55
	public void testGetObserved() throws Exception {
49
	public void testGetObserved() throws Exception {
56
		assertEquals(bean, decorator.getObserved());
50
		assertSame(bean, decorator.getObserved());
57
	}
51
	}
58
52
59
	public void testGetPropertyDescriptor() throws Exception {
53
	public void testGetPropertyDescriptor() throws Exception {
60
		assertEquals(propertyDescriptor, decorator.getPropertyDescriptor());
54
		assertSame(propertyDescriptor, decorator.getPropertyDescriptor());
61
	}
55
	}
62
}
56
}
(-)src/org/eclipse/core/tests/internal/databinding/beans/BeanObservableListDecoratorTest.java (-13 / +7 lines)
Lines 18-30 Link Here
18
import junit.framework.TestCase;
18
import junit.framework.TestCase;
19
import junit.framework.TestSuite;
19
import junit.framework.TestSuite;
20
20
21
import org.eclipse.core.databinding.beans.BeansObservables;
21
import org.eclipse.core.databinding.observable.IObservable;
22
import org.eclipse.core.databinding.observable.IObservable;
22
import org.eclipse.core.databinding.observable.IObservableCollection;
23
import org.eclipse.core.databinding.observable.IObservableCollection;
23
import org.eclipse.core.databinding.observable.Realm;
24
import org.eclipse.core.databinding.observable.Realm;
24
import org.eclipse.core.databinding.observable.list.IObservableList;
25
import org.eclipse.core.databinding.observable.list.IObservableList;
25
import org.eclipse.core.databinding.observable.list.WritableList;
26
import org.eclipse.core.databinding.observable.list.WritableList;
26
import org.eclipse.core.internal.databinding.beans.BeanObservableListDecorator;
27
import org.eclipse.core.internal.databinding.beans.BeanObservableListDecorator;
27
import org.eclipse.core.internal.databinding.beans.JavaBeanObservableList;
28
import org.eclipse.jface.databinding.conformance.MutableObservableListContractTest;
28
import org.eclipse.jface.databinding.conformance.MutableObservableListContractTest;
29
import org.eclipse.jface.databinding.conformance.delegate.AbstractObservableCollectionContractDelegate;
29
import org.eclipse.jface.databinding.conformance.delegate.AbstractObservableCollectionContractDelegate;
30
import org.eclipse.jface.databinding.swt.SWTObservables;
30
import org.eclipse.jface.databinding.swt.SWTObservables;
Lines 36-71 Link Here
36
public class BeanObservableListDecoratorTest extends TestCase {
36
public class BeanObservableListDecoratorTest extends TestCase {
37
	private Bean bean;
37
	private Bean bean;
38
	private PropertyDescriptor propertyDescriptor;
38
	private PropertyDescriptor propertyDescriptor;
39
	private JavaBeanObservableList observableList;
39
	private IObservableList observableList;
40
	private BeanObservableListDecorator decorator;
40
	private BeanObservableListDecorator decorator;
41
41
42
	/*
43
	 * (non-Javadoc)
44
	 * 
45
	 * @see junit.framework.TestCase#setUp()
46
	 */
47
	protected void setUp() throws Exception {
42
	protected void setUp() throws Exception {
48
		super.setUp();
43
		super.setUp();
49
		
44
		
50
		bean = new Bean();
45
		bean = new Bean();
51
		propertyDescriptor = new PropertyDescriptor(
46
		propertyDescriptor = new PropertyDescriptor(
52
				"list", Bean.class,"getList","setList");
47
				"list", Bean.class,"getList","setList");
53
		observableList = new JavaBeanObservableList(
48
		observableList = BeansObservables.observeList(
54
				SWTObservables.getRealm(Display.getDefault()), bean,
49
				SWTObservables.getRealm(Display.getDefault()), bean, "list");
55
				propertyDescriptor, Bean.class);
56
		decorator = new BeanObservableListDecorator(observableList, propertyDescriptor);
50
		decorator = new BeanObservableListDecorator(observableList, propertyDescriptor);
57
	}
51
	}
58
52
59
	public void testGetDelegate() throws Exception {
53
	public void testGetDelegate() throws Exception {
60
		assertEquals(observableList, decorator.getDecorated());
54
		assertSame(observableList, decorator.getDecorated());
61
	}
55
	}
62
56
63
	public void testGetObserved() throws Exception {
57
	public void testGetObserved() throws Exception {
64
		assertEquals(bean, decorator.getObserved());
58
		assertSame(bean, decorator.getObserved());
65
	}
59
	}
66
60
67
	public void testGetPropertyDescriptor() throws Exception {
61
	public void testGetPropertyDescriptor() throws Exception {
68
		assertEquals(propertyDescriptor, decorator.getPropertyDescriptor());
62
		assertSame(propertyDescriptor, decorator.getPropertyDescriptor());
69
	}
63
	}
70
64
71
	public static Test suite() {
65
	public static Test suite() {
(-)src/org/eclipse/core/tests/internal/databinding/beans/JavaBeanObservableListTest.java (-36 / +26 lines)
Lines 7-18 Link Here
7
 *
7
 *
8
 * Contributors:
8
 * Contributors:
9
 *     Brad Reynolds - initial API and implementation
9
 *     Brad Reynolds - initial API and implementation
10
 *     Matthew Hall - bugs 221351, 213145
10
 *     Matthew Hall - bugs 221351, 213145, 194734
11
 ******************************************************************************/
11
 ******************************************************************************/
12
12
13
package org.eclipse.core.tests.internal.databinding.beans;
13
package org.eclipse.core.tests.internal.databinding.beans;
14
14
15
import java.beans.IntrospectionException;
16
import java.beans.PropertyChangeEvent;
15
import java.beans.PropertyChangeEvent;
17
import java.beans.PropertyChangeListener;
16
import java.beans.PropertyChangeListener;
18
import java.beans.PropertyDescriptor;
17
import java.beans.PropertyDescriptor;
Lines 24-36 Link Here
24
import junit.framework.Test;
23
import junit.framework.Test;
25
import junit.framework.TestSuite;
24
import junit.framework.TestSuite;
26
25
26
import org.eclipse.core.databinding.beans.BeanProperties;
27
import org.eclipse.core.databinding.beans.BeansObservables;
28
import org.eclipse.core.databinding.beans.IBeanObservable;
29
import org.eclipse.core.databinding.beans.IBeanProperty;
30
import org.eclipse.core.databinding.beans.PojoObservables;
27
import org.eclipse.core.databinding.observable.IObservable;
31
import org.eclipse.core.databinding.observable.IObservable;
28
import org.eclipse.core.databinding.observable.IObservableCollection;
32
import org.eclipse.core.databinding.observable.IObservableCollection;
29
import org.eclipse.core.databinding.observable.Realm;
33
import org.eclipse.core.databinding.observable.Realm;
30
import org.eclipse.core.databinding.observable.list.IObservableList;
34
import org.eclipse.core.databinding.observable.list.IObservableList;
31
import org.eclipse.core.databinding.observable.list.ListChangeEvent;
35
import org.eclipse.core.databinding.observable.list.ListChangeEvent;
32
import org.eclipse.core.databinding.observable.list.ListDiffEntry;
36
import org.eclipse.core.databinding.observable.list.ListDiffEntry;
33
import org.eclipse.core.internal.databinding.beans.JavaBeanObservableList;
34
import org.eclipse.jface.databinding.conformance.MutableObservableListContractTest;
37
import org.eclipse.jface.databinding.conformance.MutableObservableListContractTest;
35
import org.eclipse.jface.databinding.conformance.delegate.AbstractObservableCollectionContractDelegate;
38
import org.eclipse.jface.databinding.conformance.delegate.AbstractObservableCollectionContractDelegate;
36
import org.eclipse.jface.databinding.conformance.util.ChangeEventTracker;
39
import org.eclipse.jface.databinding.conformance.util.ChangeEventTracker;
Lines 43-49 Link Here
43
 * @since 1.1
46
 * @since 1.1
44
 */
47
 */
45
public class JavaBeanObservableListTest extends AbstractDefaultRealmTestCase {
48
public class JavaBeanObservableListTest extends AbstractDefaultRealmTestCase {
46
	private JavaBeanObservableList list;
49
	private IObservableList list;
50
	private IBeanObservable beanObservable;
47
51
48
	private PropertyDescriptor propertyDescriptor;
52
	private PropertyDescriptor propertyDescriptor;
49
53
Lines 60-78 Link Here
60
		super.setUp();
64
		super.setUp();
61
65
62
		propertyName = "list";
66
		propertyName = "list";
63
		propertyDescriptor = new PropertyDescriptor(propertyName, Bean.class);
67
		propertyDescriptor = ((IBeanProperty) BeanProperties.listProperty(
68
				Bean.class, propertyName)).getPropertyDescriptor();
64
		bean = new Bean(new ArrayList());
69
		bean = new Bean(new ArrayList());
65
70
66
		list = new JavaBeanObservableList(SWTObservables.getRealm(Display
71
		list = BeansObservables.observeList(SWTObservables.getRealm(Display
67
				.getDefault()), bean, propertyDescriptor, String.class);
72
				.getDefault()), bean, propertyName);
73
		beanObservable = (IBeanObservable) list;
68
	}
74
	}
69
75
70
	public void testGetObserved() throws Exception {
76
	public void testGetObserved() throws Exception {
71
		assertEquals(bean, list.getObserved());
77
		assertEquals(bean, beanObservable.getObserved());
72
	}
78
	}
73
79
74
	public void testGetPropertyDescriptor() throws Exception {
80
	public void testGetPropertyDescriptor() throws Exception {
75
		assertEquals(propertyDescriptor, list.getPropertyDescriptor());
81
		assertEquals(propertyDescriptor, beanObservable.getPropertyDescriptor());
76
	}
82
	}
77
83
78
	public void testRegistersListenerAfterFirstListenerIsAdded()
84
	public void testRegistersListenerAfterFirstListenerIsAdded()
Lines 322-337 Link Here
322
	}
328
	}
323
329
324
	public void testRemoveAll() throws Exception {
330
	public void testRemoveAll() throws Exception {
325
		List elements = Arrays.asList(new String[] { "1", "2" });
331
		list.addAll(Arrays.asList(new String[] { "1", "2", "3", "4" }));
326
		list.addAll(elements);
327
		list.addAll(elements);
328
329
		assertEquals(4, bean.getList().size());
332
		assertEquals(4, bean.getList().size());
330
		list.removeAll(elements);
333
334
		list.removeAll(Arrays.asList(new String[] { "2", "4" }));
331
335
332
		assertEquals(2, bean.getList().size());
336
		assertEquals(2, bean.getList().size());
333
		assertEquals(elements.get(0), bean.getList().get(0));
337
		assertEquals("1", bean.getList().get(0));
334
		assertEquals(elements.get(1), bean.getList().get(1));
338
		assertEquals("3", bean.getList().get(1));
335
	}
339
	}
336
340
337
	public void testRemoveAllListChangeEvent() throws Exception {
341
	public void testRemoveAllListChangeEvent() throws Exception {
Lines 467-475 Link Here
467
471
468
	public void testConstructor_RegistersListener() throws Exception {
472
	public void testConstructor_RegistersListener() throws Exception {
469
		Bean bean = new Bean();
473
		Bean bean = new Bean();
470
		JavaBeanObservableList observable = new JavaBeanObservableList(Realm
474
		IObservableList observable = BeansObservables.observeList(Realm
471
				.getDefault(), bean,
475
				.getDefault(), bean, "list");
472
				new PropertyDescriptor("list", Bean.class), Bean.class);
473
476
474
		assertFalse(bean.hasListeners("list"));
477
		assertFalse(bean.hasListeners("list"));
475
		ChangeEventTracker.observe(observable);
478
		ChangeEventTracker.observe(observable);
Lines 478-486 Link Here
478
481
479
	public void testConstructor_SkipsRegisterListener() throws Exception {
482
	public void testConstructor_SkipsRegisterListener() throws Exception {
480
		Bean bean = new Bean();
483
		Bean bean = new Bean();
481
		JavaBeanObservableList observable = new JavaBeanObservableList(Realm
484
		IObservableList observable = PojoObservables.observeList(Realm
482
				.getDefault(), bean,
485
				.getDefault(), bean, "list");
483
				new PropertyDescriptor("list", Bean.class), Bean.class, false);
484
486
485
		assertFalse(bean.hasListeners("list"));
487
		assertFalse(bean.hasListeners("list"));
486
		ChangeEventTracker.observe(observable);
488
		ChangeEventTracker.observe(observable);
Lines 517-527 Link Here
517
519
518
		PropertyChangeEvent evt;
520
		PropertyChangeEvent evt;
519
521
520
		/*
521
		 * (non-Javadoc)
522
		 * 
523
		 * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
524
		 */
525
		public void propertyChange(PropertyChangeEvent evt) {
522
		public void propertyChange(PropertyChangeEvent evt) {
526
			count++;
523
			count++;
527
			this.evt = evt;
524
			this.evt = evt;
Lines 539-555 Link Here
539
		public IObservableCollection createObservableCollection(Realm realm,
536
		public IObservableCollection createObservableCollection(Realm realm,
540
				int elementCount) {
537
				int elementCount) {
541
			String propertyName = "list";
538
			String propertyName = "list";
542
			PropertyDescriptor propertyDescriptor;
543
			try {
544
				propertyDescriptor = new PropertyDescriptor(propertyName,
545
						Bean.class);
546
			} catch (IntrospectionException e) {
547
				throw new RuntimeException(e);
548
			}
549
			Object bean = new Bean(new ArrayList());
539
			Object bean = new Bean(new ArrayList());
550
540
551
			IObservableList list = new JavaBeanObservableList(realm, bean,
541
			IObservableList list = BeansObservables.observeList(realm, bean,
552
					propertyDescriptor, String.class);
542
					propertyName, String.class);
553
			for (int i = 0; i < elementCount; i++)
543
			for (int i = 0; i < elementCount; i++)
554
				list.add(createElement(list));
544
				list.add(createElement(list));
555
			return list;
545
			return list;
(-)src/org/eclipse/core/tests/databinding/beans/PojoObservablesTest.java (-18 / +16 lines)
Lines 7-16 Link Here
7
 *
7
 *
8
 * Contributors:
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
9
 *     IBM Corporation - initial API and implementation
10
 *     Matthew Hall - bug 194734
10
 *******************************************************************************/
11
 *******************************************************************************/
11
12
12
package org.eclipse.core.tests.databinding.beans;
13
package org.eclipse.core.tests.databinding.beans;
13
14
15
import org.eclipse.core.databinding.beans.IBeanObservable;
14
import org.eclipse.core.databinding.beans.PojoObservables;
16
import org.eclipse.core.databinding.beans.PojoObservables;
15
import org.eclipse.core.databinding.observable.Realm;
17
import org.eclipse.core.databinding.observable.Realm;
16
import org.eclipse.core.databinding.observable.list.IObservableList;
18
import org.eclipse.core.databinding.observable.list.IObservableList;
Lines 19-28 Link Here
19
import org.eclipse.core.databinding.observable.set.IObservableSet;
21
import org.eclipse.core.databinding.observable.set.IObservableSet;
20
import org.eclipse.core.databinding.observable.set.WritableSet;
22
import org.eclipse.core.databinding.observable.set.WritableSet;
21
import org.eclipse.core.databinding.observable.value.IObservableValue;
23
import org.eclipse.core.databinding.observable.value.IObservableValue;
22
import org.eclipse.core.internal.databinding.beans.JavaBeanObservableList;
23
import org.eclipse.core.internal.databinding.beans.JavaBeanObservableMap;
24
import org.eclipse.core.internal.databinding.beans.JavaBeanObservableSet;
25
import org.eclipse.core.internal.databinding.beans.JavaBeanObservableValue;
26
import org.eclipse.core.tests.internal.databinding.beans.Bean;
24
import org.eclipse.core.tests.internal.databinding.beans.Bean;
27
import org.eclipse.jface.databinding.conformance.util.ChangeEventTracker;
25
import org.eclipse.jface.databinding.conformance.util.ChangeEventTracker;
28
import org.eclipse.jface.databinding.conformance.util.CurrentRealm;
26
import org.eclipse.jface.databinding.conformance.util.CurrentRealm;
Lines 47-58 Link Here
47
		propertyName = "value";
45
		propertyName = "value";
48
	}
46
	}
49
47
50
	public void testObserveValue_ReturnsJavaBeanObservableValue()
48
	public void testObserveValue_ReturnsIBeanObservable()
51
			throws Exception {
49
			throws Exception {
52
		IObservableValue value = PojoObservables.observeValue(pojo, propertyName);
50
		IObservableValue value = PojoObservables.observeValue(pojo, propertyName);
53
51
54
		assertNotNull(value);
52
		assertNotNull(value);
55
		assertTrue(value instanceof JavaBeanObservableValue);
53
		assertTrue(value instanceof IBeanObservable);
56
	}
54
	}
57
55
58
	public void testObserveValue_DoesNotAttachListeners() throws Exception {
56
	public void testObserveValue_DoesNotAttachListeners() throws Exception {
Lines 62-78 Link Here
62
		assertFalse(pojo.hasListeners(propertyName));
60
		assertFalse(pojo.hasListeners(propertyName));
63
	}
61
	}
64
62
65
	public void testObservableValueWithRealm_ReturnsJavaBeanObservable()
63
	public void testObservableValueWithRealm_ReturnsIBeanObservable()
66
			throws Exception {
64
			throws Exception {
67
		CurrentRealm realm = new CurrentRealm(true);
65
		CurrentRealm realm = new CurrentRealm(true);
68
		IObservableValue value = PojoObservables.observeValue(realm, pojo,
66
		IObservableValue value = PojoObservables.observeValue(realm, pojo,
69
				propertyName);
67
				propertyName);
70
68
71
		assertNotNull(value);
69
		assertNotNull(value);
72
		assertTrue(value instanceof JavaBeanObservableValue);
70
		assertTrue(value instanceof IBeanObservable);
73
	}
71
	}
74
72
75
	public void testObservableMap_ReturnsJavaBeanObservableMap()
73
	public void testObservableMap_ReturnsIBeanObservable()
76
			throws Exception {
74
			throws Exception {
77
		IObservableSet set = new WritableSet();
75
		IObservableSet set = new WritableSet();
78
		set.add(new Bean());
76
		set.add(new Bean());
Lines 80-86 Link Here
80
		IObservableMap map = PojoObservables.observeMap(set, Bean.class,
78
		IObservableMap map = PojoObservables.observeMap(set, Bean.class,
81
				propertyName);
79
				propertyName);
82
		assertNotNull(map);
80
		assertNotNull(map);
83
		assertTrue(map instanceof JavaBeanObservableMap);
81
		assertTrue(map instanceof IBeanObservable);
84
	}
82
	}
85
	
83
	
86
	public void testObservableMap_DoesNotAttachListeners() throws Exception {
84
	public void testObservableMap_DoesNotAttachListeners() throws Exception {
Lines 101-109 Link Here
101
		assertEquals(2, maps.length);
99
		assertEquals(2, maps.length);
102
	}
100
	}
103
	
101
	
104
	public void testObserveListWithElementType_ReturnsJavaBeanObservableList() throws Exception {
102
	public void testObserveListWithElementType_ReturnsIBeanObservable() throws Exception {
105
		IObservableList list = PojoObservables.observeList(Realm.getDefault(), pojo, "list", String.class);
103
		IObservableList list = PojoObservables.observeList(Realm.getDefault(), pojo, "list", String.class);
106
		assertTrue(list instanceof JavaBeanObservableList);
104
		assertTrue(list instanceof IBeanObservable);
107
	}
105
	}
108
	
106
	
109
	public void testObserveListWithElementType_DoesNotAttachListeners() throws Exception {
107
	public void testObserveListWithElementType_DoesNotAttachListeners() throws Exception {
Lines 113-121 Link Here
113
		assertFalse(pojo.hasListeners("list"));
111
		assertFalse(pojo.hasListeners("list"));
114
	}
112
	}
115
	
113
	
116
	public void testObserveList_ReturnsJavaBeanObservableList() throws Exception {
114
	public void testObserveList_ReturnsIBeanObservable() throws Exception {
117
		IObservableList observable = PojoObservables.observeList(Realm.getDefault(), pojo, "list");
115
		IObservableList observable = PojoObservables.observeList(Realm.getDefault(), pojo, "list");
118
		assertTrue(observable instanceof JavaBeanObservableList);
116
		assertTrue(observable instanceof IBeanObservable);
119
	}
117
	}
120
	
118
	
121
	public void testObserveList_DoesNotAttachListeners() throws Exception {
119
	public void testObserveList_DoesNotAttachListeners() throws Exception {
Lines 125-133 Link Here
125
		assertFalse(pojo.hasListeners("list"));
123
		assertFalse(pojo.hasListeners("list"));
126
	}
124
	}
127
	
125
	
128
	public void testObserveSetWithElementType_ReturnsJavaBeanObservableList() throws Exception {
126
	public void testObserveSetWithElementType_ReturnsIBeanObservable() throws Exception {
129
		IObservableSet list = PojoObservables.observeSet(Realm.getDefault(), pojo, "set", String.class);
127
		IObservableSet list = PojoObservables.observeSet(Realm.getDefault(), pojo, "set", String.class);
130
		assertTrue(list instanceof JavaBeanObservableSet);
128
		assertTrue(list instanceof IBeanObservable);
131
	}
129
	}
132
	
130
	
133
	public void testObserveSetWithElementType_DoesNotAttachListeners() throws Exception {
131
	public void testObserveSetWithElementType_DoesNotAttachListeners() throws Exception {
Lines 137-145 Link Here
137
		assertFalse(pojo.hasListeners("set"));
135
		assertFalse(pojo.hasListeners("set"));
138
	}
136
	}
139
	
137
	
140
	public void testObserveSet_ReturnsJavaBeanObservableList() throws Exception {
138
	public void testObserveSet_ReturnsIBeanObservable() throws Exception {
141
		IObservableSet list = PojoObservables.observeSet(Realm.getDefault(), pojo, "set");
139
		IObservableSet list = PojoObservables.observeSet(Realm.getDefault(), pojo, "set");
142
		assertTrue(list instanceof JavaBeanObservableSet);
140
		assertTrue(list instanceof IBeanObservable);
143
	}
141
	}
144
	
142
	
145
	public void testObserveSet_DoesNotAttachListeners() throws Exception {
143
	public void testObserveSet_DoesNotAttachListeners() throws Exception {
(-)src/org/eclipse/core/internal/databinding/beans/JavaBeanObservableMap.java (-142 lines)
Removed 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
 *     Brad Reynolds - bug 171616
11
 *     Matthew hall - bugs 223164, 241585
12
 *******************************************************************************/
13
14
package org.eclipse.core.internal.databinding.beans;
15
16
import java.beans.PropertyChangeListener;
17
import java.beans.PropertyDescriptor;
18
import java.lang.reflect.Method;
19
20
import org.eclipse.core.databinding.beans.IBeanObservable;
21
import org.eclipse.core.databinding.observable.Diffs;
22
import org.eclipse.core.databinding.observable.map.ComputedObservableMap;
23
import org.eclipse.core.databinding.observable.set.IObservableSet;
24
import org.eclipse.core.databinding.util.Policy;
25
import org.eclipse.core.runtime.IStatus;
26
import org.eclipse.core.runtime.Status;
27
28
/**
29
 * @since 1.0
30
 * 
31
 */
32
public class JavaBeanObservableMap extends ComputedObservableMap implements
33
		IBeanObservable {
34
35
	private PropertyDescriptor propertyDescriptor;
36
	
37
	private PropertyChangeListener elementListener = new PropertyChangeListener() {
38
		public void propertyChange(final java.beans.PropertyChangeEvent event) {
39
			if (!updating) {
40
				getRealm().exec(new Runnable() {
41
					public void run() {
42
						fireMapChange(Diffs.createMapDiffSingleChange(
43
								event.getSource(), event.getOldValue(), event
44
								.getNewValue()));
45
					}
46
				});
47
			}
48
		}
49
	};
50
51
	private ListenerSupport listenerSupport;
52
53
	private boolean updating = false;
54
55
	private boolean attachListeners;
56
57
	/**
58
	 * @param domain
59
	 * @param propertyDescriptor
60
	 */
61
	public JavaBeanObservableMap(IObservableSet domain,
62
			PropertyDescriptor propertyDescriptor) {
63
		this(domain, propertyDescriptor, true);
64
	}
65
66
	/**
67
	 * @param domain
68
	 * @param propertyDescriptor
69
	 * @param attachListeners
70
	 */
71
	public JavaBeanObservableMap(IObservableSet domain,
72
			PropertyDescriptor propertyDescriptor, boolean attachListeners) {
73
		super(domain);
74
75
		this.propertyDescriptor = propertyDescriptor;
76
		this.attachListeners = attachListeners;
77
		if (attachListeners) {
78
			this.listenerSupport = new ListenerSupport(elementListener,
79
					propertyDescriptor.getName());
80
		}
81
		init();
82
	}
83
84
	protected void hookListener(Object domainElement) {
85
		if (attachListeners && domainElement != null) {
86
			listenerSupport.hookListener(domainElement);
87
		}
88
	}
89
90
	protected void unhookListener(Object domainElement) {
91
		if (attachListeners && domainElement != null) {
92
			listenerSupport.unhookListener(domainElement);
93
		}
94
	}
95
96
	protected Object doGet(Object key) {
97
		if (key == null) {
98
			return null;
99
		}
100
		try {
101
			Method readMethod = propertyDescriptor.getReadMethod();
102
			if (!readMethod.isAccessible()) {
103
				readMethod.setAccessible(true);
104
			}
105
			return readMethod.invoke(key, new Object[0]);
106
		} catch (Exception e) {
107
			Policy.getLog().log(
108
					new Status(IStatus.ERROR, Policy.JFACE_DATABINDING,
109
							IStatus.ERROR, "cannot get value", e)); //$NON-NLS-1$
110
			throw new RuntimeException(e);
111
		}
112
	}
113
114
	protected Object doPut(Object key, Object value) {
115
		try {
116
			Object oldValue = get(key);
117
			propertyDescriptor.getWriteMethod().invoke(key,
118
					new Object[] { value });
119
			keySet().add(key);
120
			return oldValue;
121
		} catch (Exception e) {
122
			Policy.getLog().log(
123
					new Status(IStatus.ERROR, Policy.JFACE_DATABINDING,
124
							IStatus.ERROR, "cannot set value", e)); //$NON-NLS-1$
125
			throw new RuntimeException(e);
126
		}
127
	}
128
129
	/* (non-Javadoc)
130
	 * @see org.eclipse.core.databinding.beans.IBeanObservable#getObserved()
131
	 */
132
	public Object getObserved() {
133
		return keySet();
134
	}
135
136
	/* (non-Javadoc)
137
	 * @see org.eclipse.core.databinding.beans.IBeanObservable#getPropertyDescriptor()
138
	 */
139
	public PropertyDescriptor getPropertyDescriptor() {
140
		return propertyDescriptor;
141
	}
142
}
(-)src/org/eclipse/core/internal/databinding/beans/JavaBeanObservableList.java (-410 lines)
Removed 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
 *     Brad Reynolds - bug 171616
11
 *     Matthew Hall - bugs 208858, 221351, 213145, 223164
12
 *     Mike Evans - bug 217558
13
 *******************************************************************************/
14
15
package org.eclipse.core.internal.databinding.beans;
16
17
import java.beans.PropertyChangeListener;
18
import java.beans.PropertyDescriptor;
19
import java.lang.reflect.Array;
20
import java.lang.reflect.InvocationTargetException;
21
import java.lang.reflect.Method;
22
import java.util.ArrayList;
23
import java.util.Arrays;
24
import java.util.Collection;
25
import java.util.Iterator;
26
import java.util.List;
27
28
import org.eclipse.core.databinding.BindingException;
29
import org.eclipse.core.databinding.beans.IBeanObservable;
30
import org.eclipse.core.databinding.observable.Diffs;
31
import org.eclipse.core.databinding.observable.Realm;
32
import org.eclipse.core.databinding.observable.list.ListDiffEntry;
33
import org.eclipse.core.databinding.observable.list.ObservableList;
34
35
/**
36
 * @since 1.0
37
 * 
38
 */
39
public class JavaBeanObservableList extends ObservableList implements
40
		IBeanObservable {
41
42
	private final Object object;
43
44
	private PropertyChangeListener collectionListener = new PropertyChangeListener() {
45
		public void propertyChange(java.beans.PropertyChangeEvent event) {
46
			if (!updating) {
47
				getRealm().exec(new Runnable() {
48
					public void run() {
49
						updateWrappedList( new ArrayList( Arrays.asList(getValues() ) ) );
50
					}
51
				});
52
			}
53
		}
54
	};
55
56
	private boolean updating = false;
57
58
	private PropertyDescriptor descriptor;
59
60
	private ListenerSupport collectionListenSupport;
61
62
	private boolean attachListeners;
63
64
	/**
65
	 * @param realm
66
	 * @param object
67
	 * @param descriptor
68
	 * @param elementType
69
	 */
70
	public JavaBeanObservableList(Realm realm, Object object,
71
			PropertyDescriptor descriptor, Class elementType) {
72
		this(realm, object, descriptor, elementType, true);
73
	}
74
75
	/**
76
	 * @param realm
77
	 * @param object
78
	 * @param descriptor
79
	 * @param elementType
80
	 * @param attachListeners
81
	 */
82
	public JavaBeanObservableList(Realm realm, Object object,
83
			PropertyDescriptor descriptor, Class elementType,
84
			boolean attachListeners) {
85
86
		super(realm, new ArrayList(), elementType);
87
		this.object = object;
88
		this.descriptor = descriptor;
89
		this.attachListeners = attachListeners;
90
91
		if (attachListeners) {
92
			this.collectionListenSupport = new ListenerSupport(
93
					collectionListener, descriptor.getName());
94
		}
95
96
		// initialize list without firing events
97
		wrappedList.addAll(Arrays.asList(getValues()));
98
	}
99
100
	protected void firstListenerAdded() {
101
		if (attachListeners) {
102
			collectionListenSupport.hookListener(this.object);
103
		}
104
	}
105
106
	protected void lastListenerRemoved() {
107
		if (collectionListenSupport != null) {
108
			collectionListenSupport.dispose();
109
		}
110
	}
111
112
	public synchronized void dispose() {
113
		super.dispose();
114
		lastListenerRemoved();
115
	}
116
117
	private Object primGetValues() {
118
		Exception ex = null;
119
		try {
120
			Method readMethod = descriptor.getReadMethod();
121
			if (!readMethod.isAccessible()) {
122
				readMethod.setAccessible(true);
123
			}
124
			return readMethod.invoke(object, new Object[0]);
125
		} catch (IllegalArgumentException e) {
126
			ex = e;
127
		} catch (IllegalAccessException e) {
128
			ex = e;
129
		} catch (InvocationTargetException e) {
130
			ex = e;
131
		}
132
		throw new BindingException("Could not read collection values", ex); //$NON-NLS-1$
133
	}
134
135
	private Object[] getValues() {
136
		Object[] values = null;
137
138
		Object result = primGetValues();
139
		if (descriptor.getPropertyType().isArray())
140
			values = (Object[]) result;
141
		else {
142
			// TODO add jUnit for POJO (var. SettableValue) collections
143
			Collection list = (Collection) result;
144
			if (list != null) {
145
				values = list.toArray();
146
			}
147
		}
148
		if (values == null)
149
			values = new Object[0];
150
		return values;
151
	}
152
153
	public Object getObserved() {
154
		return object;
155
	}
156
157
	public PropertyDescriptor getPropertyDescriptor() {
158
		return descriptor;
159
	}
160
161
	private void setValues() {
162
		if (descriptor.getPropertyType().isArray()) {
163
			Class componentType = descriptor.getPropertyType()
164
					.getComponentType();
165
			Object[] newArray = (Object[]) Array.newInstance(componentType,
166
					wrappedList.size());
167
			wrappedList.toArray(newArray);
168
			primSetValues(newArray);
169
		} else {
170
			// assume that it is a java.util.List
171
			primSetValues(new ArrayList(wrappedList));
172
		}
173
	}
174
175
	private void primSetValues(Object newValue) {
176
		Exception ex = null;
177
		try {
178
			Method writeMethod = descriptor.getWriteMethod();
179
			if (!writeMethod.isAccessible()) {
180
				writeMethod.setAccessible(true);
181
			}
182
			writeMethod.invoke(object, new Object[] { newValue });
183
			return;
184
		} catch (IllegalArgumentException e) {
185
			ex = e;
186
		} catch (IllegalAccessException e) {
187
			ex = e;
188
		} catch (InvocationTargetException e) {
189
			ex = e;
190
		}
191
		throw new BindingException("Could not write collection values", ex); //$NON-NLS-1$
192
	}
193
194
	public Object set(int index, Object element) {
195
		getterCalled();
196
		updating = true;
197
		try {
198
			Object oldElement = wrappedList.set(index, element);
199
			setValues();
200
			fireListChange(Diffs.createListDiff(Diffs.createListDiffEntry(
201
					index, false, oldElement), Diffs.createListDiffEntry(index,
202
					true, element)));
203
			return oldElement;
204
		} finally {
205
			updating = false;
206
		}
207
	}
208
209
	public Object move(int oldIndex, int newIndex) {
210
		getterCalled();
211
		updating = true;
212
		try {
213
			int size = wrappedList.size();
214
			if (oldIndex < 0 || oldIndex >= size)
215
				throw new IndexOutOfBoundsException(
216
						"oldIndex: " + oldIndex + ", size:" + size); //$NON-NLS-1$ //$NON-NLS-2$
217
			if (newIndex < 0 || newIndex >= size)
218
				throw new IndexOutOfBoundsException(
219
						"newIndex: " + newIndex + ", size:" + size); //$NON-NLS-1$ //$NON-NLS-2$
220
			if (oldIndex == newIndex)
221
				return wrappedList.get(oldIndex);
222
			Object element = wrappedList.remove(oldIndex);
223
			wrappedList.add(newIndex, element);
224
			setValues();
225
			fireListChange(Diffs.createListDiff(Diffs.createListDiffEntry(
226
					oldIndex, false, element), Diffs.createListDiffEntry(
227
					newIndex, true, element)));
228
			return element;
229
		} finally {
230
			updating = false;
231
		}
232
	}
233
234
	public Object remove(int index) {
235
		getterCalled();
236
		updating = true;
237
		try {
238
			Object oldElement = wrappedList.remove(index);
239
			setValues();
240
			fireListChange(Diffs.createListDiff(Diffs.createListDiffEntry(
241
					index, false, oldElement)));
242
			return oldElement;
243
		} finally {
244
			updating = false;
245
		}
246
	}
247
248
	public boolean add(Object element) {
249
		updating = true;
250
		try {
251
			int index = wrappedList.size();
252
			boolean result = wrappedList.add(element);
253
			setValues();
254
			fireListChange(Diffs.createListDiff(Diffs.createListDiffEntry(
255
					index, true, element)));
256
			return result;
257
		} finally {
258
			updating = false;
259
		}
260
	}
261
262
	public void add(int index, Object element) {
263
		updating = true;
264
		try {
265
			wrappedList.add(index, element);
266
			setValues();
267
			fireListChange(Diffs.createListDiff(Diffs.createListDiffEntry(
268
					index, true, element)));
269
		} finally {
270
			updating = false;
271
		}
272
	}
273
274
	public boolean addAll(Collection c) {
275
		if (c.isEmpty()) {
276
			return false;
277
		}
278
		updating = true;
279
		try {
280
			int index = wrappedList.size();
281
			boolean result = wrappedList.addAll(c);
282
			setValues();
283
			ListDiffEntry[] entries = new ListDiffEntry[c.size()];
284
			int i = 0;
285
			for (Iterator it = c.iterator(); it.hasNext();) {
286
				Object o = it.next();
287
				entries[i++] = Diffs.createListDiffEntry(index++, true, o);
288
			}
289
			fireListChange(Diffs.createListDiff(entries));
290
			return result;
291
		} finally {
292
			updating = false;
293
		}
294
	}
295
296
	public boolean addAll(int index, Collection c) {
297
		if (c.isEmpty()) {
298
			return false;
299
		}
300
		updating = true;
301
		try {
302
			boolean result = wrappedList.addAll(index, c);
303
			setValues();
304
			ListDiffEntry[] entries = new ListDiffEntry[c.size()];
305
			int i = 0;
306
			for (Iterator it = c.iterator(); it.hasNext();) {
307
				Object o = it.next();
308
				entries[i++] = Diffs.createListDiffEntry(index++, true, o);
309
			}
310
			fireListChange(Diffs.createListDiff(entries));
311
			return result;
312
		} finally {
313
			updating = false;
314
		}
315
	}
316
317
	public boolean remove(Object o) {
318
		getterCalled();
319
		int index = wrappedList.indexOf(o);
320
		if (index == -1) {
321
			return false;
322
		}
323
		updating = true;
324
		try {
325
			Object oldElement = wrappedList.remove(index);
326
			setValues();
327
			fireListChange(Diffs.createListDiff(Diffs.createListDiffEntry(
328
					index, false, oldElement)));
329
			return true;
330
		} finally {
331
			updating = false;
332
		}
333
	}
334
335
	public boolean removeAll(Collection c) {
336
		getterCalled();
337
		boolean changed = false;
338
		updating = true;
339
		try {
340
			List diffEntries = new ArrayList();
341
			for (Iterator it = c.iterator(); it.hasNext();) {
342
				Object o = it.next();
343
				int index = wrappedList.indexOf(o);
344
				if (index != -1) {
345
					changed = true;
346
					Object oldElement = wrappedList.remove(index);
347
					diffEntries.add(Diffs.createListDiffEntry(index, false,
348
							oldElement));
349
				}
350
			}
351
			if (changed) {
352
				setValues();
353
				fireListChange(Diffs
354
						.createListDiff((ListDiffEntry[]) diffEntries
355
								.toArray(new ListDiffEntry[diffEntries.size()])));
356
			}
357
			return changed;
358
		} finally {
359
			updating = false;
360
		}
361
	}
362
363
	public boolean retainAll(Collection c) {
364
		getterCalled();
365
		boolean changed = false;
366
		updating = true;
367
		try {
368
			List diffEntries = new ArrayList();
369
			int index = 0;
370
			for (Iterator it = wrappedList.iterator(); it.hasNext();) {
371
				Object o = it.next();
372
				boolean retain = c.contains(o);
373
				if (retain) {
374
					index++;
375
				} else {
376
					changed = true;
377
					it.remove();
378
					diffEntries.add(Diffs.createListDiffEntry(index, false, o));
379
				}
380
			}
381
			if (changed) {
382
				setValues();
383
				fireListChange(Diffs
384
						.createListDiff((ListDiffEntry[]) diffEntries
385
								.toArray(new ListDiffEntry[diffEntries.size()])));
386
			}
387
			return changed;
388
		} finally {
389
			updating = false;
390
		}
391
	}
392
393
	public void clear() {
394
		updating = true;
395
		try {
396
			List diffEntries = new ArrayList();
397
			for (Iterator it = wrappedList.iterator(); it.hasNext();) {
398
				Object o = it.next();
399
				diffEntries.add(Diffs.createListDiffEntry(0, false, o));
400
			}
401
			wrappedList.clear();
402
			setValues();
403
			fireListChange(Diffs.createListDiff((ListDiffEntry[]) diffEntries
404
					.toArray(new ListDiffEntry[diffEntries.size()])));
405
		} finally {
406
			updating = false;
407
		}
408
	}
409
410
}
(-)src/org/eclipse/core/internal/databinding/beans/JavaBeanPropertyObservableMap.java (-241 lines)
Removed 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 (bug 221704)
10
 *     Matthew Hall - bug 223164
11
 *******************************************************************************/
12
13
package org.eclipse.core.internal.databinding.beans;
14
15
import java.beans.PropertyChangeEvent;
16
import java.beans.PropertyChangeListener;
17
import java.beans.PropertyDescriptor;
18
import java.lang.reflect.InvocationTargetException;
19
import java.lang.reflect.Method;
20
import java.util.Collections;
21
import java.util.HashMap;
22
import java.util.HashSet;
23
import java.util.Iterator;
24
import java.util.Map;
25
import java.util.Set;
26
27
import org.eclipse.core.databinding.BindingException;
28
import org.eclipse.core.databinding.beans.IBeanObservable;
29
import org.eclipse.core.databinding.observable.Diffs;
30
import org.eclipse.core.databinding.observable.Realm;
31
import org.eclipse.core.databinding.observable.map.ObservableMap;
32
import org.eclipse.core.internal.databinding.Util;
33
import org.eclipse.core.runtime.Assert;
34
35
/**
36
 * @since 1.0
37
 * 
38
 */
39
public class JavaBeanPropertyObservableMap extends ObservableMap implements
40
		IBeanObservable {
41
42
	private final Object object;
43
44
	private PropertyChangeListener mapListener = new PropertyChangeListener() {
45
		public void propertyChange(final PropertyChangeEvent event) {
46
			if (!updating) {
47
				getRealm().exec(new Runnable() {
48
					public void run() {
49
						Map oldValue = wrappedMap;
50
						Map newValue = (Map) event.getNewValue();
51
						wrappedMap = new HashMap(newValue);
52
						
53
						fireMapChange(Diffs.computeMapDiff(oldValue, newValue));
54
					}
55
				});
56
			}
57
		}
58
	};
59
60
	private boolean updating = false;
61
62
	private PropertyDescriptor descriptor;
63
64
	private ListenerSupport collectionListenSupport;
65
66
	private boolean attachListeners;
67
68
	/**
69
	 * @param realm
70
	 * @param object
71
	 * @param descriptor
72
	 */
73
	public JavaBeanPropertyObservableMap(Realm realm, Object object,
74
			PropertyDescriptor descriptor) {
75
		this(realm, object, descriptor, true);
76
	}
77
78
	/**
79
	 * @param realm
80
	 * @param object
81
	 * @param descriptor
82
	 * @param attachListeners
83
	 */
84
	public JavaBeanPropertyObservableMap(Realm realm, Object object,
85
			PropertyDescriptor descriptor, boolean attachListeners) {
86
		super(realm, new HashMap());
87
		this.object = object;
88
		this.descriptor = descriptor;
89
		this.attachListeners = attachListeners;
90
		if (attachListeners) {
91
			this.collectionListenSupport = new ListenerSupport(mapListener,
92
					descriptor.getName());
93
		}
94
95
		wrappedMap.putAll(getMap());
96
	}
97
98
	protected void firstListenerAdded() {
99
		if (attachListeners) {
100
			collectionListenSupport.hookListener(this.object);
101
		}
102
	}
103
104
	protected void lastListenerRemoved() {
105
		if (collectionListenSupport != null) {
106
			collectionListenSupport.dispose();
107
		}
108
	}
109
110
	private Object primGetMap() {
111
		try {
112
			Method readMethod = descriptor.getReadMethod();
113
			if (!readMethod.isAccessible()) {
114
				readMethod.setAccessible(true);
115
			}
116
			return readMethod.invoke(object, new Object[0]);
117
		} catch (IllegalArgumentException e) {
118
		} catch (IllegalAccessException e) {
119
		} catch (InvocationTargetException e) {
120
		}
121
		Assert.isTrue(false, "Could not read collection values"); //$NON-NLS-1$
122
		return null;
123
	}
124
125
	private void primSetMap(Object newValue) {
126
		Exception ex = null;
127
		try {
128
			Method writeMethod = descriptor.getWriteMethod();
129
			if (!writeMethod.isAccessible()) {
130
				writeMethod.setAccessible(true);
131
			}
132
			writeMethod.invoke(object, new Object[] { newValue });
133
			return;
134
		} catch (IllegalArgumentException e) {
135
			ex = e;
136
		} catch (IllegalAccessException e) {
137
			ex = e;
138
		} catch (InvocationTargetException e) {
139
			ex = e;
140
		}
141
		throw new BindingException("Could not write collection values", ex); //$NON-NLS-1$
142
	}
143
144
	private Map getMap() {
145
		Map result = (Map) primGetMap();
146
147
		if (result == null)
148
			result = new HashMap();
149
		return result;
150
	}
151
152
	private void setMap() {
153
		primSetMap(new HashMap(wrappedMap));
154
	}
155
156
	public Object put(Object key, Object value) {
157
		checkRealm();
158
		updating = true;
159
		try {
160
			Object result = wrappedMap.put(key, value);
161
			if (!Util.equals(result, value)) {
162
				setMap();
163
				if (result == null) {
164
					fireMapChange(Diffs.createMapDiffSingleAdd(key, value));
165
				} else {
166
					fireMapChange(Diffs.createMapDiffSingleChange(key, result,
167
							value));
168
				}
169
			}
170
			return result;
171
		} finally {
172
			updating = false;
173
		}
174
	}
175
176
	public void putAll(Map map) {
177
		checkRealm();
178
		updating = true;
179
		try {
180
			Set addedKeys = new HashSet(map.size());
181
			Map changes = new HashMap(map.size());
182
			for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
183
				Map.Entry entry = (Entry) it.next();
184
				Object key = entry.getKey();
185
				Object newValue = entry.getValue();
186
				Object oldValue = wrappedMap.put(key, newValue);
187
				if (oldValue == null) {
188
					addedKeys.add(key);
189
				} else if (!Util.equals(oldValue, newValue)) {
190
					changes.put(key, oldValue);
191
				}
192
			}
193
			if (!addedKeys.isEmpty() || !changes.isEmpty()) {
194
				setMap();
195
				fireMapChange(Diffs.createMapDiff(addedKeys,
196
						Collections.EMPTY_SET, changes.keySet(), changes,
197
						wrappedMap));
198
			}
199
		} finally {
200
			updating = false;
201
		}
202
	}
203
204
	public Object remove(Object key) {
205
		checkRealm();
206
		updating = true;
207
		try {
208
			Object result = wrappedMap.remove(key);
209
			if (result!=null) {
210
				setMap();
211
				fireMapChange(Diffs.createMapDiffSingleRemove(key, result));
212
			}
213
			return result;
214
		} finally {
215
			updating = false;
216
		}
217
	}
218
219
	public void clear() {
220
		checkRealm();
221
		if (wrappedMap.isEmpty())
222
			return;
223
		updating = true;
224
		try {
225
			Map oldMap = wrappedMap;
226
			wrappedMap = new HashMap();
227
			setMap();
228
			fireMapChange(Diffs.computeMapDiff(oldMap, Collections.EMPTY_MAP));
229
		} finally {
230
			updating = false;
231
		}
232
	}
233
234
	public Object getObserved() {
235
		return object;
236
	}
237
238
	public PropertyDescriptor getPropertyDescriptor() {
239
		return descriptor;
240
	}
241
}
(-)src/org/eclipse/core/internal/databinding/beans/JavaBeanObservableSet.java (-306 lines)
Removed 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
 *     Brad Reynolds - bug 171616
11
 *     Matthew Hall - bug 221351, 223164
12
 *******************************************************************************/
13
14
package org.eclipse.core.internal.databinding.beans;
15
16
import java.beans.PropertyChangeListener;
17
import java.beans.PropertyDescriptor;
18
import java.lang.reflect.Array;
19
import java.lang.reflect.InvocationTargetException;
20
import java.lang.reflect.Method;
21
import java.util.Arrays;
22
import java.util.Collection;
23
import java.util.Collections;
24
import java.util.HashSet;
25
import java.util.Iterator;
26
import java.util.Set;
27
28
import org.eclipse.core.databinding.BindingException;
29
import org.eclipse.core.databinding.beans.IBeanObservable;
30
import org.eclipse.core.databinding.observable.Diffs;
31
import org.eclipse.core.databinding.observable.Realm;
32
import org.eclipse.core.databinding.observable.set.ObservableSet;
33
import org.eclipse.core.runtime.Assert;
34
35
/**
36
 * @since 1.0
37
 * 
38
 */
39
public class JavaBeanObservableSet extends ObservableSet implements IBeanObservable {
40
41
	private final Object object;
42
43
	private PropertyChangeListener collectionListener = new PropertyChangeListener() {
44
		public void propertyChange(java.beans.PropertyChangeEvent event) {
45
			if (!updating) {
46
				getRealm().exec(new Runnable() {
47
					public void run() {
48
						Set newElements = new HashSet(Arrays
49
								.asList(getValues()));
50
						Set addedElements = new HashSet(newElements);
51
						Set removedElements = new HashSet(wrappedSet);
52
						// remove all new elements from old elements to compute
53
						// the removed elements
54
						removedElements.removeAll(newElements);
55
						addedElements.removeAll(wrappedSet);
56
						wrappedSet = newElements;
57
						fireSetChange(Diffs.createSetDiff(addedElements,
58
								removedElements));
59
					}
60
				});
61
			}
62
		}
63
	};
64
65
	private boolean updating = false;
66
67
	private PropertyDescriptor descriptor;
68
69
	private ListenerSupport collectionListenSupport;
70
71
	private boolean attachListeners;
72
73
	/**
74
	 * @param realm
75
	 * @param object
76
	 * @param descriptor
77
	 * @param elementType
78
	 */
79
	public JavaBeanObservableSet(Realm realm, Object object,
80
			PropertyDescriptor descriptor, Class elementType) {
81
		this(realm, object, descriptor, elementType, true);
82
	}
83
84
	/**
85
	 * @param realm
86
	 * @param object
87
	 * @param descriptor
88
	 * @param elementType
89
	 * @param attachListeners
90
	 */
91
	public JavaBeanObservableSet(Realm realm, Object object,
92
			PropertyDescriptor descriptor, Class elementType,
93
			boolean attachListeners) {
94
		super(realm, new HashSet(), elementType);
95
		this.object = object;
96
		this.descriptor = descriptor;
97
		this.attachListeners = attachListeners;
98
		if (attachListeners) {
99
			this.collectionListenSupport = new ListenerSupport(
100
					collectionListener, descriptor.getName());
101
		}
102
103
		wrappedSet.addAll(Arrays.asList(getValues()));
104
	}
105
106
	protected void firstListenerAdded() {
107
		if (attachListeners) {
108
			collectionListenSupport.hookListener(this.object);
109
		}
110
	}
111
112
	protected void lastListenerRemoved() {
113
		if (collectionListenSupport != null) {
114
			collectionListenSupport.dispose();
115
		}
116
	}
117
118
	private Object primGetValues() {
119
		try {
120
			Method readMethod = descriptor.getReadMethod();
121
			if (!readMethod.isAccessible()) {
122
				readMethod.setAccessible(true);
123
			}
124
			return readMethod.invoke(object, new Object[0]);
125
		} catch (IllegalArgumentException e) {
126
		} catch (IllegalAccessException e) {
127
		} catch (InvocationTargetException e) {
128
		}
129
		Assert.isTrue(false, "Could not read collection values"); //$NON-NLS-1$
130
		return null;
131
	}
132
133
	private Object[] getValues() {
134
		Object[] values = null;
135
136
		Object result = primGetValues();
137
		if (descriptor.getPropertyType().isArray())
138
			values = (Object[]) result;
139
		else {
140
			// TODO add jUnit for POJO (var. SettableValue) collections
141
			Collection list = (Collection) result;
142
			if (list != null)
143
				values = list.toArray();
144
		}
145
		if (values == null)
146
			values = new Object[0];
147
		return values;
148
	}
149
150
	private void setValues() {
151
		if (descriptor.getPropertyType().isArray()) {
152
			Class componentType = descriptor.getPropertyType()
153
					.getComponentType();
154
			Object[] newArray = (Object[]) Array.newInstance(componentType,
155
					wrappedSet.size());
156
			wrappedSet.toArray(newArray);
157
			primSetValues(newArray);
158
		} else {
159
			// assume that it is a java.util.Set
160
			primSetValues(new HashSet(wrappedSet));
161
		}
162
	}
163
164
	public boolean add(Object o) {
165
		getterCalled();
166
		updating = true;
167
		try {
168
			boolean added = wrappedSet.add(o);
169
			if (added) {
170
				setValues();
171
				fireSetChange(Diffs.createSetDiff(Collections.singleton(o),
172
						Collections.EMPTY_SET));
173
			}
174
			return added;
175
		} finally {
176
			updating = false;
177
		}
178
	}
179
180
	public boolean remove(Object o) {
181
		getterCalled();
182
		updating = true;
183
		try {
184
			boolean removed = wrappedSet.remove(o);
185
			if (removed) {
186
				setValues();
187
				fireSetChange(Diffs.createSetDiff(Collections.EMPTY_SET,
188
						Collections.singleton(o)));
189
			}
190
			return removed;
191
		} finally {
192
			updating = false;
193
		}
194
	}
195
196
	public boolean addAll(Collection c) {
197
		getterCalled();
198
		updating = true;
199
		try {
200
			Set additions = new HashSet();
201
			for (Iterator iterator = c.iterator(); iterator.hasNext();) {
202
				Object element = iterator.next();
203
				if (wrappedSet.add(element))
204
					additions.add(element);
205
			}
206
			boolean changed = !additions.isEmpty();
207
			if (changed) {
208
				setValues();
209
				fireSetChange(Diffs.createSetDiff(additions,
210
						Collections.EMPTY_SET));
211
			}
212
			return changed;
213
		} finally {
214
			updating = false;
215
		}
216
	}
217
218
	public boolean removeAll(Collection c) {
219
		getterCalled();
220
		updating = true;
221
		try {
222
			Set removals = new HashSet();
223
			for (Iterator iterator = c.iterator(); iterator.hasNext();) {
224
				Object element = iterator.next();
225
				if (wrappedSet.remove(element))
226
					removals.add(element);
227
			}
228
			boolean changed = !removals.isEmpty();
229
			if (changed) {
230
				setValues();
231
				fireSetChange(Diffs.createSetDiff(Collections.EMPTY_SET,
232
						removals));
233
			}
234
			return changed;
235
		} finally {
236
			updating = false;
237
		}
238
	}
239
240
	public boolean retainAll(Collection c) {
241
		getterCalled();
242
		updating = true;
243
		try {
244
			Set removals = new HashSet();
245
			for (Iterator iterator = wrappedSet.iterator(); iterator.hasNext();) {
246
				Object element = iterator.next();
247
				if (!c.contains(element)) {
248
					iterator.remove();
249
					removals.add(element);
250
				}
251
			}
252
			boolean changed = !removals.isEmpty();
253
			if (changed) {
254
				setValues();
255
				fireSetChange(Diffs.createSetDiff(Collections.EMPTY_SET,
256
						removals));
257
			}
258
			return changed;
259
		} finally {
260
			updating = false;
261
		}
262
	}
263
264
	public void clear() {
265
		getterCalled();
266
		if (wrappedSet.isEmpty())
267
			return;
268
269
		updating = true;
270
		try {
271
			Set removals = new HashSet(wrappedSet);
272
			wrappedSet.clear();
273
			setValues();
274
			fireSetChange(Diffs.createSetDiff(Collections.EMPTY_SET, removals));
275
		} finally {
276
			updating = false;
277
		}
278
	}
279
280
	private void primSetValues(Object newValue) {
281
		Exception ex = null;
282
		try {
283
			Method writeMethod = descriptor.getWriteMethod();
284
			if (!writeMethod.isAccessible()) {
285
				writeMethod.setAccessible(true);
286
			}
287
			writeMethod.invoke(object, new Object[] { newValue });
288
			return;
289
		} catch (IllegalArgumentException e) {
290
			ex = e;
291
		} catch (IllegalAccessException e) {
292
			ex = e;
293
		} catch (InvocationTargetException e) {
294
			ex = e;
295
		}
296
		throw new BindingException("Could not write collection values", ex); //$NON-NLS-1$
297
	}
298
299
	public Object getObserved() {
300
		return object;
301
	}
302
303
	public PropertyDescriptor getPropertyDescriptor() {
304
		return descriptor;
305
	}
306
}
(-)src/org/eclipse/core/internal/databinding/beans/JavaBeanObservableValue.java (-190 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 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
 *     Brad Reynolds - bug 164653
11
 *     Brad Reynolds - bug 164134, 171616
12
 *******************************************************************************/
13
package org.eclipse.core.internal.databinding.beans;
14
15
import java.beans.PropertyChangeListener;
16
import java.beans.PropertyDescriptor;
17
import java.lang.reflect.InvocationTargetException;
18
import java.lang.reflect.Method;
19
20
import org.eclipse.core.databinding.BindingException;
21
import org.eclipse.core.databinding.beans.BeansObservables;
22
import org.eclipse.core.databinding.beans.IBeanObservable;
23
import org.eclipse.core.databinding.observable.Diffs;
24
import org.eclipse.core.databinding.observable.Realm;
25
import org.eclipse.core.databinding.observable.value.AbstractObservableValue;
26
import org.eclipse.core.databinding.observable.value.ValueDiff;
27
import org.eclipse.core.databinding.util.Policy;
28
import org.eclipse.core.internal.databinding.Util;
29
import org.eclipse.core.runtime.IStatus;
30
import org.eclipse.core.runtime.Status;
31
32
/**
33
 * @since 1.0
34
 * 
35
 */
36
public class JavaBeanObservableValue extends AbstractObservableValue implements IBeanObservable {
37
	private final Object object;
38
	private boolean updating = false;
39
40
	private final PropertyDescriptor propertyDescriptor;
41
	private ListenerSupport listenerSupport;
42
43
	private boolean attachListeners;
44
45
	/**
46
	 * @param realm
47
	 * @param object
48
	 * @param descriptor
49
	 */
50
	public JavaBeanObservableValue(Realm realm, Object object,
51
			PropertyDescriptor descriptor) {
52
		this(realm, object, descriptor, true);
53
	}
54
55
	/**
56
	 * @param realm
57
	 * @param object
58
	 * @param descriptor
59
	 * @param attachListeners
60
	 */
61
	public JavaBeanObservableValue(Realm realm, Object object,
62
			PropertyDescriptor descriptor, boolean attachListeners) {
63
		super(realm);
64
		this.object = object;
65
		this.propertyDescriptor = descriptor;
66
		this.attachListeners = attachListeners;
67
	}
68
69
	protected void firstListenerAdded() {
70
		if (!attachListeners) {
71
			return;
72
		}
73
			
74
		PropertyChangeListener listener = new PropertyChangeListener() {
75
			public void propertyChange(java.beans.PropertyChangeEvent event) {
76
				if (!updating) {
77
					final ValueDiff diff = Diffs.createValueDiff(event.getOldValue(),
78
											event.getNewValue());
79
					getRealm().exec(new Runnable(){
80
						public void run() {
81
							fireValueChange(diff);
82
						}});
83
				}
84
			}
85
		};
86
		
87
		if (listenerSupport == null) {
88
			listenerSupport = new ListenerSupport(listener, propertyDescriptor.getName());
89
		}
90
		
91
		listenerSupport.hookListener(object);
92
	}
93
94
	public void doSetValue(Object value) {
95
		updating = true;
96
		try {
97
			Object oldValue = doGetValue();
98
			
99
			if (Util.equals(oldValue, value)) {
100
				return;
101
			}
102
			
103
			Method writeMethod = propertyDescriptor.getWriteMethod();
104
			if (!writeMethod.isAccessible()) {
105
				writeMethod.setAccessible(true);
106
			}
107
			writeMethod.invoke(object, new Object[] { value });
108
			fireValueChange(Diffs.createValueDiff(oldValue, doGetValue()));
109
		} catch (InvocationTargetException e) {
110
			/*
111
			 * InvocationTargetException wraps any exception thrown by the
112
			 * invoked method.
113
			 */
114
			throw new RuntimeException(e.getCause());
115
		} catch (Exception e) {
116
			if (BeansObservables.DEBUG) {
117
				Policy
118
						.getLog()
119
						.log(
120
								new Status(
121
										IStatus.WARNING,
122
										Policy.JFACE_DATABINDING,
123
										IStatus.OK,
124
										"Could not change value of " + object + "." + propertyDescriptor.getName(), e)); //$NON-NLS-1$ //$NON-NLS-2$
125
			}
126
		} finally {
127
			updating = false;
128
		}
129
	}
130
131
	public Object doGetValue() {
132
		try {
133
			Method readMethod = propertyDescriptor.getReadMethod();
134
			if (readMethod == null) {
135
				throw new BindingException(propertyDescriptor.getName()
136
						+ " property does not have a read method."); //$NON-NLS-1$
137
			}
138
			if (!readMethod.isAccessible()) {
139
				readMethod.setAccessible(true);
140
			}
141
			return readMethod.invoke(object, null);
142
		} catch (InvocationTargetException e) {
143
			/*
144
			 * InvocationTargetException wraps any exception thrown by the
145
			 * invoked method.
146
			 */
147
			throw new RuntimeException(e.getCause());
148
		} catch (Exception e) {
149
			if (BeansObservables.DEBUG) {
150
				Policy
151
						.getLog()
152
						.log(
153
								new Status(
154
										IStatus.WARNING,
155
										Policy.JFACE_DATABINDING,
156
										IStatus.OK,
157
										"Could not read value of " + object + "." + propertyDescriptor.getName(), e)); //$NON-NLS-1$ //$NON-NLS-2$
158
			}
159
			return null;
160
		}
161
	}
162
163
	protected void lastListenerRemoved() {
164
		unhookListener();
165
	}
166
167
	private void unhookListener() {
168
		if (listenerSupport != null) {
169
			listenerSupport.dispose();
170
			listenerSupport = null;
171
		}
172
	}
173
174
	public Object getValueType() {
175
		return propertyDescriptor.getPropertyType();
176
	}
177
178
	public Object getObserved() {
179
		return object;
180
	}
181
182
	public PropertyDescriptor getPropertyDescriptor() {
183
		return propertyDescriptor;
184
	}
185
186
	public synchronized void dispose() {
187
		unhookListener();
188
		super.dispose();
189
	}
190
}
(-)src/org/eclipse/core/databinding/beans/BeansObservables.java (-98 / +44 lines)
Lines 8-24 Link Here
8
 * Contributors:
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
9
 *     IBM Corporation - initial API and implementation
10
 *     Brad Reynolds - bugs 164268, 171616, 147515
10
 *     Brad Reynolds - bugs 164268, 171616, 147515
11
 *     Matthew Hall - bug 221704, 234686, 246625
11
 *     Matthew Hall - bug 221704, 234686, 246625, 194734
12
 *     Thomas Kratz - bug 213787
12
 *     Thomas Kratz - bug 213787
13
 *******************************************************************************/
13
 *******************************************************************************/
14
package org.eclipse.core.databinding.beans;
14
package org.eclipse.core.databinding.beans;
15
15
16
import java.beans.BeanInfo;
17
import java.beans.IntrospectionException;
18
import java.beans.Introspector;
19
import java.beans.PropertyDescriptor;
16
import java.beans.PropertyDescriptor;
20
17
21
import org.eclipse.core.databinding.BindingException;
22
import org.eclipse.core.databinding.observable.IObservable;
18
import org.eclipse.core.databinding.observable.IObservable;
23
import org.eclipse.core.databinding.observable.Realm;
19
import org.eclipse.core.databinding.observable.Realm;
24
import org.eclipse.core.databinding.observable.list.IObservableList;
20
import org.eclipse.core.databinding.observable.list.IObservableList;
Lines 27-41 Link Here
27
import org.eclipse.core.databinding.observable.masterdetail.MasterDetailObservables;
23
import org.eclipse.core.databinding.observable.masterdetail.MasterDetailObservables;
28
import org.eclipse.core.databinding.observable.set.IObservableSet;
24
import org.eclipse.core.databinding.observable.set.IObservableSet;
29
import org.eclipse.core.databinding.observable.value.IObservableValue;
25
import org.eclipse.core.databinding.observable.value.IObservableValue;
26
import org.eclipse.core.databinding.property.IListProperty;
27
import org.eclipse.core.databinding.property.IMapProperty;
28
import org.eclipse.core.databinding.property.ISetProperty;
29
import org.eclipse.core.databinding.property.IValueProperty;
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.BeanPropertyHelper;
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;
36
import org.eclipse.core.runtime.Assert;
40
37
41
/**
38
/**
Lines 83-91 Link Here
83
	 */
80
	 */
84
	public static IObservableValue observeValue(Realm realm, Object bean,
81
	public static IObservableValue observeValue(Realm realm, Object bean,
85
			String propertyName) {
82
			String propertyName) {
86
		PropertyDescriptor descriptor = getPropertyDescriptor(bean.getClass(),
83
		IValueProperty property = BeanProperties.valueProperty(bean.getClass(),
87
				propertyName);
84
				propertyName);
88
		return new JavaBeanObservableValue(realm, bean, descriptor);
85
		PropertyDescriptor propertyDescriptor = ((IBeanProperty) property)
86
				.getPropertyDescriptor();
87
		return new BeanObservableValueDecorator(PropertyObservables
88
				.observeValue(realm, bean, property), propertyDescriptor);
89
	}
89
	}
90
90
91
	/**
91
	/**
Lines 103-111 Link Here
103
	 */
103
	 */
104
	public static IObservableMap observeMap(IObservableSet domain,
104
	public static IObservableMap observeMap(IObservableSet domain,
105
			Class beanClass, String propertyName) {
105
			Class beanClass, String propertyName) {
106
		PropertyDescriptor descriptor = getPropertyDescriptor(beanClass,
106
		IValueProperty property = BeanProperties.valueProperty(beanClass,
107
				propertyName);
107
				propertyName);
108
		return new JavaBeanObservableMap(domain, descriptor);
108
		PropertyDescriptor propertyDescriptor = ((IBeanProperty) property)
109
				.getPropertyDescriptor();
110
		return new BeanObservableMapDecorator(PropertyObservables.observeDetailValues(
111
				domain, property), propertyDescriptor);
109
	}
112
	}
110
113
111
	/**
114
	/**
Lines 124-132 Link Here
124
	 */
127
	 */
125
	public static IObservableMap observeMap(Realm realm, Object bean,
128
	public static IObservableMap observeMap(Realm realm, Object bean,
126
			String propertyName) {
129
			String propertyName) {
127
		PropertyDescriptor descriptor = getPropertyDescriptor(bean.getClass(),
130
		IMapProperty property = BeanProperties.mapProperty(bean.getClass(),
128
				propertyName);
131
				propertyName);
129
		return new JavaBeanPropertyObservableMap(realm, bean, descriptor);
132
		PropertyDescriptor propertyDescriptor = ((IBeanProperty) property)
133
				.getPropertyDescriptor();
134
		return new BeanObservableMapDecorator(PropertyObservables.observeMap(
135
				bean, property), propertyDescriptor);
130
	}
136
	}
131
137
132
	/**
138
	/**
Lines 145-171 Link Here
145
		return observeMap(Realm.getDefault(), bean, propertyName);
151
		return observeMap(Realm.getDefault(), bean, propertyName);
146
	}
152
	}
147
153
148
	/*package*/ static PropertyDescriptor getPropertyDescriptor(Class beanClass,
149
			String propertyName) {
150
		BeanInfo beanInfo;
151
		try {
152
			beanInfo = Introspector.getBeanInfo(beanClass);
153
		} catch (IntrospectionException e) {
154
			// cannot introspect, give up
155
			return null;
156
		}
157
		PropertyDescriptor[] propertyDescriptors = beanInfo
158
				.getPropertyDescriptors();
159
		for (int i = 0; i < propertyDescriptors.length; i++) {
160
			PropertyDescriptor descriptor = propertyDescriptors[i];
161
			if (descriptor.getName().equals(propertyName)) {
162
				return descriptor;
163
			}
164
		}
165
		throw new BindingException(
166
				"Could not find property with name " + propertyName + " in class " + beanClass); //$NON-NLS-1$ //$NON-NLS-2$
167
	}
168
169
	/**
154
	/**
170
	 * Returns an array of observable maps in the default realm tracking the
155
	 * Returns an array of observable maps in the default realm tracking the
171
	 * current values of the named propertys for the beans in the given set.
156
	 * current values of the named propertys for the beans in the given set.
Lines 251-262 Link Here
251
	 */
236
	 */
252
	public static IObservableList observeList(Realm realm, Object bean,
237
	public static IObservableList observeList(Realm realm, Object bean,
253
			String propertyName, Class elementType) {
238
			String propertyName, Class elementType) {
254
		PropertyDescriptor propertyDescriptor = getPropertyDescriptor(bean
239
		IListProperty property = BeanProperties.listProperty(bean.getClass(),
255
				.getClass(), propertyName);
240
				propertyName, elementType);
256
		elementType = getCollectionElementType(elementType, propertyDescriptor);
241
		PropertyDescriptor propertyDescriptor = ((IBeanProperty) property)
257
242
				.getPropertyDescriptor();
258
		return new JavaBeanObservableList(realm, bean, propertyDescriptor,
243
		return new BeanObservableListDecorator(PropertyObservables.observeList(
259
				elementType);
244
				realm, bean, property), propertyDescriptor);
260
	}
245
	}
261
246
262
	/**
247
	/**
Lines 439-448 Link Here
439
424
440
		IObservableValue value = MasterDetailObservables.detailValue(master,
425
		IObservableValue value = MasterDetailObservables.detailValue(master,
441
				valueFactory(realm, propertyName), propertyType);
426
				valueFactory(realm, propertyName), propertyType);
442
		BeanObservableValueDecorator decorator = new BeanObservableValueDecorator(
427
		return new BeanObservableValueDecorator(value, BeanPropertyHelper
443
				value, getValueTypePropertyDescriptor(master, propertyName));
428
				.getValueTypePropertyDescriptor(master, propertyName));
444
445
		return decorator;
446
	}
429
	}
447
430
448
	/**
431
	/**
Lines 495-504 Link Here
495
		Assert.isNotNull(masterType, "masterType cannot be null"); //$NON-NLS-1$
478
		Assert.isNotNull(masterType, "masterType cannot be null"); //$NON-NLS-1$
496
		IObservableValue value = MasterDetailObservables.detailValue(master,
479
		IObservableValue value = MasterDetailObservables.detailValue(master,
497
				valueFactory(realm, propertyName), propertyType);
480
				valueFactory(realm, propertyName), propertyType);
498
		BeanObservableValueDecorator decorator = new BeanObservableValueDecorator(
481
		return new BeanObservableValueDecorator(value, BeanPropertyHelper
499
				value, getPropertyDescriptor(masterType, propertyName));
482
				.getPropertyDescriptor(masterType, propertyName));
500
501
		return decorator;
502
	}
483
	}
503
484
504
	/**
485
	/**
Lines 549-559 Link Here
549
		IObservableList observableList = MasterDetailObservables.detailList(
530
		IObservableList observableList = MasterDetailObservables.detailList(
550
				master, listFactory(realm, propertyName, propertyType),
531
				master, listFactory(realm, propertyName, propertyType),
551
				propertyType);
532
				propertyType);
552
		BeanObservableListDecorator decorator = new BeanObservableListDecorator(
533
		return new BeanObservableListDecorator(observableList,
553
				observableList, getValueTypePropertyDescriptor(master,
534
				BeanPropertyHelper.getValueTypePropertyDescriptor(master,
554
						propertyName));
535
						propertyName));
555
556
		return decorator;
557
	}
536
	}
558
537
559
	/**
538
	/**
Lines 597-607 Link Here
597
		IObservableSet observableSet = MasterDetailObservables.detailSet(
576
		IObservableSet observableSet = MasterDetailObservables.detailSet(
598
				master, setFactory(realm, propertyName, propertyType),
577
				master, setFactory(realm, propertyName, propertyType),
599
				propertyType);
578
				propertyType);
600
		BeanObservableSetDecorator decorator = new BeanObservableSetDecorator(
579
		return new BeanObservableSetDecorator(observableSet, BeanPropertyHelper
601
				observableSet, getValueTypePropertyDescriptor(master,
580
				.getValueTypePropertyDescriptor(master, propertyName));
602
						propertyName));
603
604
		return decorator;
605
	}
581
	}
606
582
607
	/**
583
	/**
Lines 640-649 Link Here
640
			IObservableValue master, String propertyName) {
616
			IObservableValue master, String propertyName) {
641
		IObservableMap observableMap = MasterDetailObservables.detailMap(
617
		IObservableMap observableMap = MasterDetailObservables.detailMap(
642
				master, mapPropertyFactory(realm, propertyName));
618
				master, mapPropertyFactory(realm, propertyName));
643
		BeanObservableMapDecorator decorator = new BeanObservableMapDecorator(
619
		return new BeanObservableMapDecorator(observableMap, BeanPropertyHelper
644
				observableMap, getValueTypePropertyDescriptor(master,
620
				.getValueTypePropertyDescriptor(master, propertyName));
645
						propertyName));
646
		return decorator;
647
	}
621
	}
648
622
649
	/**
623
	/**
Lines 686-697 Link Here
686
	 */
660
	 */
687
	public static IObservableSet observeSet(Realm realm, Object bean,
661
	public static IObservableSet observeSet(Realm realm, Object bean,
688
			String propertyName, Class elementType) {
662
			String propertyName, Class elementType) {
689
		PropertyDescriptor propertyDescriptor = getPropertyDescriptor(bean
663
		ISetProperty property = BeanProperties.setProperty(bean.getClass(),
690
				.getClass(), propertyName);
664
				propertyName, elementType);
691
		elementType = getCollectionElementType(elementType, propertyDescriptor);
665
		PropertyDescriptor propertyDescriptor = ((IBeanProperty) property)
692
666
				.getPropertyDescriptor();
693
		return new JavaBeanObservableSet(realm, bean, propertyDescriptor,
667
		return new BeanObservableSetDecorator(PropertyObservables.observeSet(
694
				elementType);
668
				realm, bean, property), propertyDescriptor);
695
	}
669
	}
696
670
697
	/**
671
	/**
Lines 826-857 Link Here
826
	public static IObservableFactory mapPropertyFactory(String propertyName) {
800
	public static IObservableFactory mapPropertyFactory(String propertyName) {
827
		return mapPropertyFactory(Realm.getDefault(), propertyName);
801
		return mapPropertyFactory(Realm.getDefault(), propertyName);
828
	}
802
	}
829
830
	/**
831
	 * @param elementType
832
	 *            can be <code>null</code>
833
	 * @param propertyDescriptor
834
	 * @return type of the items in a collection/array property
835
	 */
836
	/*package*/ static Class getCollectionElementType(Class elementType,
837
			PropertyDescriptor propertyDescriptor) {
838
		if (elementType == null) {
839
			Class propertyType = propertyDescriptor.getPropertyType();
840
			elementType = propertyType.isArray() ? propertyType
841
					.getComponentType() : Object.class;
842
		}
843
844
		return elementType;
845
	}
846
847
	/**
848
	 * @param observable
849
	 * @param propertyName
850
	 * @return property descriptor or <code>null</code>
851
	 */
852
	/* package*/ static PropertyDescriptor getValueTypePropertyDescriptor(
853
			IObservableValue observable, String propertyName) {
854
		return (observable.getValueType() != null) ? getPropertyDescriptor(
855
				(Class) observable.getValueType(), propertyName) : null;
856
	}
857
}
803
}
(-)src/org/eclipse/core/databinding/beans/PojoObservables.java (-49 / +46 lines)
Lines 7-13 Link Here
7
 *
7
 *
8
 * Contributors:
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
9
 *     IBM Corporation - initial API and implementation
10
 *     Matthew Hall - bugs 221704, 234686, 246625
10
 *     Matthew Hall - bugs 221704, 234686, 246625, 194734
11
 *******************************************************************************/
11
 *******************************************************************************/
12
12
13
package org.eclipse.core.databinding.beans;
13
package org.eclipse.core.databinding.beans;
Lines 23-37 Link Here
23
import org.eclipse.core.databinding.observable.masterdetail.MasterDetailObservables;
23
import org.eclipse.core.databinding.observable.masterdetail.MasterDetailObservables;
24
import org.eclipse.core.databinding.observable.set.IObservableSet;
24
import org.eclipse.core.databinding.observable.set.IObservableSet;
25
import org.eclipse.core.databinding.observable.value.IObservableValue;
25
import org.eclipse.core.databinding.observable.value.IObservableValue;
26
import org.eclipse.core.databinding.property.IListProperty;
27
import org.eclipse.core.databinding.property.IMapProperty;
28
import org.eclipse.core.databinding.property.ISetProperty;
29
import org.eclipse.core.databinding.property.IValueProperty;
30
import org.eclipse.core.databinding.property.PropertyObservables;
26
import org.eclipse.core.internal.databinding.beans.BeanObservableListDecorator;
31
import org.eclipse.core.internal.databinding.beans.BeanObservableListDecorator;
27
import org.eclipse.core.internal.databinding.beans.BeanObservableMapDecorator;
32
import org.eclipse.core.internal.databinding.beans.BeanObservableMapDecorator;
28
import org.eclipse.core.internal.databinding.beans.BeanObservableSetDecorator;
33
import org.eclipse.core.internal.databinding.beans.BeanObservableSetDecorator;
29
import org.eclipse.core.internal.databinding.beans.BeanObservableValueDecorator;
34
import org.eclipse.core.internal.databinding.beans.BeanObservableValueDecorator;
30
import org.eclipse.core.internal.databinding.beans.JavaBeanObservableList;
35
import org.eclipse.core.internal.databinding.beans.BeanPropertyHelper;
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
36
36
/**
37
/**
37
 * A factory for creating observable objects for POJOs (plain old java objects)
38
 * A factory for creating observable objects for POJOs (plain old java objects)
Lines 73-82 Link Here
73
	 */
74
	 */
74
	public static IObservableValue observeValue(Realm realm, Object pojo,
75
	public static IObservableValue observeValue(Realm realm, Object pojo,
75
			String propertyName) {
76
			String propertyName) {
76
77
		IValueProperty property = PojoProperties.valueProperty(pojo.getClass(),
77
		PropertyDescriptor descriptor = BeansObservables.getPropertyDescriptor(
78
				propertyName);
78
				pojo.getClass(), propertyName);
79
		PropertyDescriptor propertyDescriptor = ((IBeanProperty) property)
79
		return new JavaBeanObservableValue(realm, pojo, descriptor, false);
80
				.getPropertyDescriptor();
81
		return new BeanObservableValueDecorator(PropertyObservables
82
				.observeValue(realm, pojo, property), propertyDescriptor);
80
	}
83
	}
81
84
82
	/**
85
	/**
Lines 94-102 Link Here
94
	 */
97
	 */
95
	public static IObservableMap observeMap(IObservableSet domain,
98
	public static IObservableMap observeMap(IObservableSet domain,
96
			Class pojoClass, String propertyName) {
99
			Class pojoClass, String propertyName) {
97
		PropertyDescriptor descriptor = BeansObservables.getPropertyDescriptor(
100
		IValueProperty property = PojoProperties.valueProperty(pojoClass,
98
				pojoClass, propertyName);
101
				propertyName);
99
		return new JavaBeanObservableMap(domain, descriptor, false);
102
		PropertyDescriptor propertyDescriptor = ((IBeanProperty) property)
103
				.getPropertyDescriptor();
104
		return new BeanObservableMapDecorator(PropertyObservables.observeDetailValues(
105
				domain, property), propertyDescriptor);
100
	}
106
	}
101
107
102
	/**
108
	/**
Lines 136-144 Link Here
136
	 */
142
	 */
137
	public static IObservableMap observeMap(Realm realm, Object pojo,
143
	public static IObservableMap observeMap(Realm realm, Object pojo,
138
			String propertyName) {
144
			String propertyName) {
139
		PropertyDescriptor descriptor = BeansObservables.getPropertyDescriptor(
145
		IMapProperty property = PojoProperties.mapProperty(pojo.getClass(),
140
				pojo.getClass(), propertyName);
146
				propertyName);
141
		return new JavaBeanPropertyObservableMap(realm, pojo, descriptor, false);
147
		PropertyDescriptor propertyDescriptor = ((IBeanProperty) property)
148
				.getPropertyDescriptor();
149
		return new BeanObservableMapDecorator(PropertyObservables.observeMap(
150
				pojo, property), propertyDescriptor);
142
	}
151
	}
143
152
144
	/**
153
	/**
Lines 220-232 Link Here
220
	 */
229
	 */
221
	public static IObservableList observeList(Realm realm, Object pojo,
230
	public static IObservableList observeList(Realm realm, Object pojo,
222
			String propertyName, Class elementType) {
231
			String propertyName, Class elementType) {
223
		PropertyDescriptor propertyDescriptor = BeansObservables
232
		IListProperty property = PojoProperties.listProperty(pojo.getClass(),
224
				.getPropertyDescriptor(pojo.getClass(), propertyName);
233
				propertyName, elementType);
225
		elementType = BeansObservables.getCollectionElementType(elementType,
234
		PropertyDescriptor propertyDescriptor = ((IBeanProperty) property)
226
				propertyDescriptor);
235
				.getPropertyDescriptor();
227
236
		return new BeanObservableListDecorator(PropertyObservables.observeList(
228
		return new JavaBeanObservableList(realm, pojo, propertyDescriptor,
237
				realm, pojo, property), propertyDescriptor);
229
				elementType, false);
230
	}
238
	}
231
239
232
	/**
240
	/**
Lines 310-322 Link Here
310
	 */
318
	 */
311
	public static IObservableSet observeSet(Realm realm, Object pojo,
319
	public static IObservableSet observeSet(Realm realm, Object pojo,
312
			String propertyName, Class elementType) {
320
			String propertyName, Class elementType) {
313
		PropertyDescriptor propertyDescriptor = BeansObservables
321
		ISetProperty property = PojoProperties.setProperty(pojo.getClass(),
314
				.getPropertyDescriptor(pojo.getClass(), propertyName);
322
				propertyName, elementType);
315
		elementType = BeansObservables.getCollectionElementType(elementType,
323
		PropertyDescriptor propertyDescriptor = ((IBeanProperty) property)
316
				propertyDescriptor);
324
				.getPropertyDescriptor();
317
325
		return new BeanObservableSetDecorator(PropertyObservables.observeSet(
318
		return new JavaBeanObservableSet(realm, pojo, propertyDescriptor,
326
				realm, pojo, property), propertyDescriptor);
319
				elementType, false);
320
	}
327
	}
321
328
322
	/**
329
	/**
Lines 540-550 Link Here
540
547
541
		IObservableValue value = MasterDetailObservables.detailValue(master,
548
		IObservableValue value = MasterDetailObservables.detailValue(master,
542
				valueFactory(realm, propertyName), propertyType);
549
				valueFactory(realm, propertyName), propertyType);
543
		BeanObservableValueDecorator decorator = new BeanObservableValueDecorator(
550
		return new BeanObservableValueDecorator(value, BeanPropertyHelper
544
				value, BeansObservables.getValueTypePropertyDescriptor(master,
551
				.getValueTypePropertyDescriptor(master, propertyName));
545
						propertyName));
546
547
		return decorator;
548
	}
552
	}
549
553
550
	/**
554
	/**
Lines 587-597 Link Here
587
		IObservableList observableList = MasterDetailObservables.detailList(
591
		IObservableList observableList = MasterDetailObservables.detailList(
588
				master, listFactory(realm, propertyName, propertyType),
592
				master, listFactory(realm, propertyName, propertyType),
589
				propertyType);
593
				propertyType);
590
		BeanObservableListDecorator decorator = new BeanObservableListDecorator(
594
		return new BeanObservableListDecorator(observableList,
591
				observableList, BeansObservables
595
				BeanPropertyHelper.getValueTypePropertyDescriptor(master,
592
						.getValueTypePropertyDescriptor(master, propertyName));
596
						propertyName));
593
594
		return decorator;
595
	}
597
	}
596
598
597
	/**
599
	/**
Lines 635-645 Link Here
635
		IObservableSet observableSet = MasterDetailObservables.detailSet(
637
		IObservableSet observableSet = MasterDetailObservables.detailSet(
636
				master, setFactory(realm, propertyName, propertyType),
638
				master, setFactory(realm, propertyName, propertyType),
637
				propertyType);
639
				propertyType);
638
		BeanObservableSetDecorator decorator = new BeanObservableSetDecorator(
640
		return new BeanObservableSetDecorator(observableSet, BeanPropertyHelper
639
				observableSet, BeansObservables.getValueTypePropertyDescriptor(
641
				.getValueTypePropertyDescriptor(master, propertyName));
640
						master, propertyName));
641
642
		return decorator;
643
	}
642
	}
644
643
645
	/**
644
	/**
Lines 676-685 Link Here
676
			IObservableValue master, String propertyName) {
675
			IObservableValue master, String propertyName) {
677
		IObservableMap observableMap = MasterDetailObservables.detailMap(
676
		IObservableMap observableMap = MasterDetailObservables.detailMap(
678
				master, mapPropertyFactory(realm, propertyName));
677
				master, mapPropertyFactory(realm, propertyName));
679
		BeanObservableMapDecorator decorator = new BeanObservableMapDecorator(
678
		return new BeanObservableMapDecorator(observableMap, BeanPropertyHelper
680
				observableMap, BeansObservables.getValueTypePropertyDescriptor(
679
				.getValueTypePropertyDescriptor(master, propertyName));
681
						master, propertyName));
682
		return decorator;
683
	}
680
	}
684
681
685
	/**
682
	/**
(-)src/org/eclipse/core/databinding/beans/IBeanProperty.java (+30 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 (bug 194734)
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
 * Provides access to details of bean properties.
20
 * 
21
 * @since 1.2
22
 */
23
public interface IBeanProperty extends IProperty {
24
	/**
25
	 * Returns the property descriptor of the bean property being observed
26
	 * 
27
	 * @return the property descriptor of the bean property being observed
28
	 */
29
	public PropertyDescriptor getPropertyDescriptor();
30
}
(-)src/org/eclipse/core/internal/databinding/beans/BeanMapProperty.java (+100 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.beans;
13
14
import java.beans.PropertyDescriptor;
15
import java.util.Collections;
16
import java.util.HashMap;
17
import java.util.Map;
18
19
import org.eclipse.core.databinding.beans.IBeanProperty;
20
import org.eclipse.core.databinding.observable.Diffs;
21
import org.eclipse.core.databinding.property.BasicMapProperty;
22
import org.eclipse.core.databinding.property.IMapPropertyChangeListener;
23
import org.eclipse.core.databinding.property.IPropertyChangeListener;
24
import org.eclipse.core.databinding.property.MapPropertyChangeEvent;
25
26
/**
27
 * @since 3.3
28
 * 
29
 */
30
public class BeanMapProperty extends BasicMapProperty implements IBeanProperty {
31
	private final PropertyDescriptor propertyDescriptor;
32
	private final boolean attachListener;
33
34
	/**
35
	 * @param propertyDescriptor
36
	 * @param attachListener
37
	 */
38
	public BeanMapProperty(PropertyDescriptor propertyDescriptor,
39
			boolean attachListener) {
40
		this.propertyDescriptor = propertyDescriptor;
41
		this.attachListener = attachListener;
42
	}
43
44
	public PropertyDescriptor getPropertyDescriptor() {
45
		return propertyDescriptor;
46
	}
47
48
	public Map getMap(Object source) {
49
		return source == null ? Collections.EMPTY_MAP
50
				: asMap(BeanPropertyHelper.getProperty(source,
51
						propertyDescriptor));
52
	}
53
54
	private static Map asMap(Object propertyValue) {
55
		if (propertyValue == null)
56
			return new HashMap();
57
		return (Map) propertyValue;
58
	}
59
60
	protected void setMap(Object source, Map map) {
61
		if (source != null) {
62
			BeanPropertyHelper.setProperty(source, propertyDescriptor, map);
63
		}
64
	}
65
66
	public IPropertyChangeListener adaptListener(
67
			IMapPropertyChangeListener listener) {
68
		return attachListener ? new ListenerAdaptor(listener) : null;
69
	}
70
71
	public void addPropertyChangeListener(Object source,
72
			IPropertyChangeListener listener) {
73
		if (attachListener && source != null) {
74
			((ListenerAdaptor) listener).addListenerTo(source);
75
		}
76
	}
77
78
	public void removePropertyChangeListener(Object source,
79
			IPropertyChangeListener listener) {
80
		if (attachListener && source != null) {
81
			((ListenerAdaptor) listener).removeListenerFrom(source);
82
		}
83
	}
84
85
	private class ListenerAdaptor extends BeanPropertyChangeListener {
86
		private final IMapPropertyChangeListener wrapped;
87
88
		ListenerAdaptor(IMapPropertyChangeListener wrapped) {
89
			super(propertyDescriptor);
90
			this.wrapped = wrapped;
91
		}
92
93
		protected void handlePropertyChange(Object source, Object oldValue,
94
				Object newValue) {
95
			wrapped.handleMapPropertyChange(new MapPropertyChangeEvent(source,
96
					BeanMapProperty.this, Diffs.computeMapDiff(asMap(oldValue),
97
							asMap(newValue))));
98
		}
99
	}
100
}
(-)src/org/eclipse/core/internal/databinding/beans/BeanPropertyChangeListener.java (+80 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.PropertyChangeEvent;
15
import java.beans.PropertyChangeListener;
16
import java.beans.PropertyDescriptor;
17
import java.util.Collections;
18
import java.util.HashMap;
19
import java.util.Map;
20
21
import org.eclipse.core.databinding.property.IPropertyChangeListener;
22
23
/**
24
 * @since 3.3
25
 * 
26
 */
27
public abstract class BeanPropertyChangeListener implements
28
		IPropertyChangeListener, PropertyChangeListener {
29
	private final PropertyDescriptor propertyDescriptor;
30
31
	private ListenerSupport listenerSupport;
32
	private Map sourceToCached = Collections.synchronizedMap(new HashMap());
33
34
	protected BeanPropertyChangeListener(PropertyDescriptor propertyDescriptor) {
35
		this.propertyDescriptor = propertyDescriptor;
36
	}
37
38
	public final void propertyChange(PropertyChangeEvent evt) {
39
		Object source = evt.getSource();
40
		Object oldValue = evt.getOldValue();
41
		Object newValue = evt.getNewValue();
42
		if (oldValue == null && newValue == null) {
43
			// Obscure condition indicating new and old
44
			// values are unknown
45
			oldValue = sourceToCached.get(source);
46
			newValue = BeanPropertyHelper.getProperty(source,
47
					propertyDescriptor);
48
		}
49
		sourceToCached.put(source, newValue);
50
		handlePropertyChange(source, oldValue, newValue);
51
	}
52
53
	protected abstract void handlePropertyChange(Object source,
54
			Object oldValue, Object newValue);
55
56
	private void initListenerSupport() {
57
		if (listenerSupport == null) {
58
			synchronized (this) {
59
				if (listenerSupport == null) {
60
					listenerSupport = new ListenerSupport(this,
61
							propertyDescriptor.getName());
62
				}
63
			}
64
		}
65
	}
66
67
	protected void addListenerTo(Object source) {
68
		initListenerSupport();
69
		listenerSupport.hookListener(source);
70
		sourceToCached.put(source, BeanPropertyHelper.getProperty(source,
71
				propertyDescriptor));
72
	}
73
74
	protected void removeListenerFrom(Object source) {
75
		if (listenerSupport != null) {
76
			listenerSupport.unhookListener(source);
77
			sourceToCached.remove(source);
78
		}
79
	}
80
}
(-)src/org/eclipse/core/internal/databinding/beans/BeanValueProperty.java (+98 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.beans;
13
14
import java.beans.PropertyDescriptor;
15
16
import org.eclipse.core.databinding.beans.IBeanProperty;
17
import org.eclipse.core.databinding.observable.Diffs;
18
import org.eclipse.core.databinding.property.IPropertyChangeListener;
19
import org.eclipse.core.databinding.property.IValuePropertyChangeListener;
20
import org.eclipse.core.databinding.property.ValueProperty;
21
import org.eclipse.core.databinding.property.ValuePropertyChangeEvent;
22
23
/**
24
 * @since 3.3
25
 * 
26
 */
27
public class BeanValueProperty extends ValueProperty implements IBeanProperty {
28
	private final PropertyDescriptor propertyDescriptor;
29
	private final Class valueType;
30
	private final boolean attachListener;
31
32
	/**
33
	 * @param propertyDescriptor
34
	 * @param valueType
35
	 * @param attachListener
36
	 */
37
	public BeanValueProperty(PropertyDescriptor propertyDescriptor,
38
			Class valueType, boolean attachListener) {
39
		this.propertyDescriptor = propertyDescriptor;
40
		this.valueType = valueType == null ? propertyDescriptor
41
				.getPropertyType() : valueType;
42
		this.attachListener = attachListener;
43
	}
44
45
	public PropertyDescriptor getPropertyDescriptor() {
46
		return propertyDescriptor;
47
	}
48
49
	public Object getValueType() {
50
		return valueType;
51
	}
52
53
	public Object getValue(Object source) {
54
		return source == null ? null : BeanPropertyHelper.getProperty(source,
55
				propertyDescriptor);
56
	}
57
58
	public void setValue(Object source, Object value) {
59
		if (source != null) {
60
			BeanPropertyHelper.setProperty(source, propertyDescriptor, value);
61
		}
62
	}
63
64
	public IPropertyChangeListener adaptListener(
65
			IValuePropertyChangeListener listener) {
66
		return attachListener ? new ListenerAdaptor(listener) : null;
67
	}
68
69
	public void addPropertyChangeListener(Object source,
70
			IPropertyChangeListener listener) {
71
		if (attachListener && source != null) {
72
			((ListenerAdaptor) listener).addListenerTo(source);
73
		}
74
	}
75
76
	public void removePropertyChangeListener(Object source,
77
			IPropertyChangeListener listener) {
78
		if (attachListener && source != null) {
79
			((ListenerAdaptor) listener).removeListenerFrom(source);
80
		}
81
	}
82
83
	private class ListenerAdaptor extends BeanPropertyChangeListener {
84
		private final IValuePropertyChangeListener wrapped;
85
86
		ListenerAdaptor(IValuePropertyChangeListener listener) {
87
			super(propertyDescriptor);
88
			this.wrapped = listener;
89
		}
90
91
		protected void handlePropertyChange(Object source, Object oldValue,
92
				Object newValue) {
93
			wrapped.handleValuePropertyChange(new ValuePropertyChangeEvent(
94
					source, BeanValueProperty.this, Diffs.createValueDiff(
95
							oldValue, newValue)));
96
		}
97
	}
98
}
(-)src/org/eclipse/core/databinding/beans/PojoProperties.java (+154 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.beans;
13
14
import java.beans.PropertyChangeEvent;
15
16
import org.eclipse.core.databinding.property.IListProperty;
17
import org.eclipse.core.databinding.property.IMapProperty;
18
import org.eclipse.core.databinding.property.ISetProperty;
19
import org.eclipse.core.databinding.property.IValueProperty;
20
import org.eclipse.core.internal.databinding.beans.BeanListProperty;
21
import org.eclipse.core.internal.databinding.beans.BeanMapProperty;
22
import org.eclipse.core.internal.databinding.beans.BeanPropertyHelper;
23
import org.eclipse.core.internal.databinding.beans.BeanSetProperty;
24
import org.eclipse.core.internal.databinding.beans.BeanValueProperty;
25
26
/**
27
 * A factory for creating properties for POJOs (plain old java objects) that
28
 * conform to idea of an object with getters and setters but does not provide
29
 * {@link PropertyChangeEvent property change events} on change. This factory is
30
 * identical to {@link BeanProperties} except for this fact.
31
 * 
32
 * @since 1.2
33
 */
34
public class PojoProperties {
35
	/**
36
	 * Returns a value property for the given property name of the given bean
37
	 * class.
38
	 * 
39
	 * @param beanClass
40
	 *            the bean class
41
	 * @param propertyName
42
	 *            the property name
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) {
48
		return valueProperty(beanClass, propertyName, null);
49
	}
50
51
	/**
52
	 * Returns a value property for the given property name of the given bean
53
	 * class.
54
	 * 
55
	 * @param beanClass
56
	 *            the bean class
57
	 * @param propertyName
58
	 *            the property name
59
	 * @param valueType
60
	 *            the value type of the returned value property
61
	 * @return a value property for the given property name of the given bean
62
	 *         class.
63
	 */
64
	public static IValueProperty valueProperty(Class beanClass,
65
			String propertyName, Class valueType) {
66
		return new BeanValueProperty(BeanPropertyHelper.getPropertyDescriptor(
67
				beanClass, propertyName), valueType, false);
68
	}
69
70
	/**
71
	 * Returns a set property for the given property name of the given bean
72
	 * class.
73
	 * 
74
	 * @param beanClass
75
	 *            the bean class
76
	 * @param propertyName
77
	 *            the property name
78
	 * @return a set property for the given property name of the given bean
79
	 *         class.
80
	 */
81
	public static ISetProperty setProperty(Class beanClass, String propertyName) {
82
		return setProperty(beanClass, propertyName, null);
83
	}
84
85
	/**
86
	 * Returns a set property for the given property name of the given bean
87
	 * class.
88
	 * 
89
	 * @param beanClass
90
	 *            the bean class
91
	 * @param propertyName
92
	 *            the property name
93
	 * @param elementType
94
	 *            the element type of the returned set property
95
	 * @return a set property for the given property name of the given bean
96
	 *         class.
97
	 */
98
	public static ISetProperty setProperty(Class beanClass,
99
			String propertyName, Class elementType) {
100
		return new BeanSetProperty(BeanPropertyHelper.getPropertyDescriptor(
101
				beanClass, propertyName), elementType, false);
102
	}
103
104
	/**
105
	 * Returns a list property for the given property name of the given bean
106
	 * class.
107
	 * 
108
	 * @param beanClass
109
	 *            the bean class
110
	 * @param propertyName
111
	 *            the property name
112
	 * @return a list property for the given property name of the given bean
113
	 *         class.
114
	 */
115
	public static IListProperty listProperty(Class beanClass,
116
			String propertyName) {
117
		return listProperty(beanClass, propertyName, null);
118
	}
119
120
	/**
121
	 * Returns a list property for the given property name of the given bean
122
	 * class.
123
	 * 
124
	 * @param beanClass
125
	 *            the bean class
126
	 * @param propertyName
127
	 *            the property name
128
	 * @param elementType
129
	 *            the element type of the returned list property
130
	 * @return a list property for the given property name of the given bean
131
	 *         class.
132
	 */
133
	public static IListProperty listProperty(Class beanClass,
134
			String propertyName, Class elementType) {
135
		return new BeanListProperty(BeanPropertyHelper.getPropertyDescriptor(
136
				beanClass, propertyName), elementType, false);
137
	}
138
139
	/**
140
	 * Returns a map property for the given property name of the given bean
141
	 * class.
142
	 * 
143
	 * @param beanClass
144
	 *            the bean class
145
	 * @param propertyName
146
	 *            the property name
147
	 * @return a map property for the given property name of the given bean
148
	 *         class.
149
	 */
150
	public static IMapProperty mapProperty(Class beanClass, String propertyName) {
151
		return new BeanMapProperty(BeanPropertyHelper.getPropertyDescriptor(
152
				beanClass, propertyName), false);
153
	}
154
}
(-)src/org/eclipse/core/internal/databinding/beans/BeanListProperty.java (+128 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.beans;
13
14
import java.beans.PropertyDescriptor;
15
import java.lang.reflect.Array;
16
import java.util.ArrayList;
17
import java.util.Arrays;
18
import java.util.Collections;
19
import java.util.List;
20
21
import org.eclipse.core.databinding.beans.IBeanProperty;
22
import org.eclipse.core.databinding.observable.Diffs;
23
import org.eclipse.core.databinding.property.BasicListProperty;
24
import org.eclipse.core.databinding.property.IListPropertyChangeListener;
25
import org.eclipse.core.databinding.property.IPropertyChangeListener;
26
import org.eclipse.core.databinding.property.ListPropertyChangeEvent;
27
28
/**
29
 * @since 3.3
30
 * 
31
 */
32
public class BeanListProperty extends BasicListProperty implements
33
		IBeanProperty {
34
	private final PropertyDescriptor propertyDescriptor;
35
	private final Class elementType;
36
	private final boolean attachListener;
37
38
	/**
39
	 * @param propertyDescriptor
40
	 * @param elementType
41
	 * @param attachListener
42
	 */
43
	public BeanListProperty(PropertyDescriptor propertyDescriptor,
44
			Class elementType, boolean attachListener) {
45
		this.propertyDescriptor = propertyDescriptor;
46
		this.elementType = elementType == null ? BeanPropertyHelper
47
				.getCollectionPropertyElementType(propertyDescriptor)
48
				: elementType;
49
		this.attachListener = attachListener;
50
	}
51
52
	public PropertyDescriptor getPropertyDescriptor() {
53
		return propertyDescriptor;
54
	}
55
56
	public Object getElementType() {
57
		return elementType;
58
	}
59
60
	public List getList(Object source) {
61
		return source == null ? Collections.EMPTY_LIST
62
				: asList(BeanPropertyHelper.getProperty(source,
63
						propertyDescriptor));
64
	}
65
66
	private List asList(Object propertyValue) {
67
		if (propertyValue == null)
68
			return new ArrayList();
69
		if (propertyDescriptor.getPropertyType().isArray())
70
			return new ArrayList(Arrays.asList((Object[]) propertyValue));
71
		return (List) propertyValue;
72
	}
73
74
	protected void setList(Object source, List list) {
75
		if (source != null) {
76
			BeanPropertyHelper.setProperty(source, propertyDescriptor,
77
					convertListToBeanPropertyType(list));
78
		}
79
	}
80
81
	private Object convertListToBeanPropertyType(List list) {
82
		Object propertyValue = list;
83
		if (propertyDescriptor.getPropertyType().isArray()) {
84
			Class componentType = propertyDescriptor.getPropertyType()
85
					.getComponentType();
86
			Object[] array = (Object[]) Array.newInstance(componentType, list
87
					.size());
88
			list.toArray(array);
89
			propertyValue = array;
90
		}
91
		return propertyValue;
92
	}
93
94
	public IPropertyChangeListener adaptListener(
95
			IListPropertyChangeListener listener) {
96
		return attachListener ? new ListenerAdaptor(listener) : null;
97
	}
98
99
	public void addPropertyChangeListener(Object source,
100
			IPropertyChangeListener listener) {
101
		if (attachListener && source != null) {
102
			((ListenerAdaptor) listener).addListenerTo(source);
103
		}
104
	}
105
106
	public void removePropertyChangeListener(Object source,
107
			IPropertyChangeListener listener) {
108
		if (attachListener && source != null) {
109
			((ListenerAdaptor) listener).removeListenerFrom(source);
110
		}
111
	}
112
113
	private class ListenerAdaptor extends BeanPropertyChangeListener {
114
		private final IListPropertyChangeListener wrapped;
115
116
		ListenerAdaptor(IListPropertyChangeListener wrapped) {
117
			super(propertyDescriptor);
118
			this.wrapped = wrapped;
119
		}
120
121
		protected void handlePropertyChange(Object source, Object oldValue,
122
				Object newValue) {
123
			wrapped.handleListPropertyChange(new ListPropertyChangeEvent(
124
					source, BeanListProperty.this, Diffs.computeListDiff(
125
							asList(oldValue), asList(newValue))));
126
		}
127
	}
128
}
(-)src/org/eclipse/core/internal/databinding/beans/BeanSetProperty.java (+126 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.beans;
13
14
import java.beans.PropertyDescriptor;
15
import java.lang.reflect.Array;
16
import java.util.Arrays;
17
import java.util.Collections;
18
import java.util.HashSet;
19
import java.util.Set;
20
21
import org.eclipse.core.databinding.beans.IBeanProperty;
22
import org.eclipse.core.databinding.observable.Diffs;
23
import org.eclipse.core.databinding.property.BasicSetProperty;
24
import org.eclipse.core.databinding.property.IPropertyChangeListener;
25
import org.eclipse.core.databinding.property.ISetPropertyChangeListener;
26
import org.eclipse.core.databinding.property.SetPropertyChangeEvent;
27
28
/**
29
 * @since 3.3
30
 * 
31
 */
32
public class BeanSetProperty extends BasicSetProperty implements IBeanProperty {
33
	private final PropertyDescriptor propertyDescriptor;
34
	private final Class elementType;
35
	private final boolean attachListener;
36
37
	/**
38
	 * @param propertyDescriptor
39
	 * @param elementType
40
	 * @param attachListener
41
	 */
42
	public BeanSetProperty(PropertyDescriptor propertyDescriptor,
43
			Class elementType, boolean attachListener) {
44
		this.propertyDescriptor = propertyDescriptor;
45
		this.elementType = elementType == null ? BeanPropertyHelper
46
				.getCollectionPropertyElementType(propertyDescriptor)
47
				: elementType;
48
		this.attachListener = attachListener;
49
	}
50
51
	public PropertyDescriptor getPropertyDescriptor() {
52
		return propertyDescriptor;
53
	}
54
55
	public Object getElementType() {
56
		return elementType;
57
	}
58
59
	public Set getSet(Object source) {
60
		return source == null ? Collections.EMPTY_SET
61
				: asSet(BeanPropertyHelper.getProperty(source,
62
						propertyDescriptor));
63
	}
64
65
	private Set asSet(Object propertyValue) {
66
		if (propertyValue == null)
67
			return Collections.EMPTY_SET;
68
		if (propertyDescriptor.getPropertyType().isArray())
69
			return new HashSet(Arrays.asList((Object[]) propertyValue));
70
		return (Set) propertyValue;
71
	}
72
73
	protected void setSet(Object source, Set set) {
74
		if (source != null) {
75
			BeanPropertyHelper.setProperty(source, propertyDescriptor,
76
					convertSetToBeanPropertyType(set));
77
		}
78
	}
79
80
	private Object convertSetToBeanPropertyType(Set set) {
81
		Object propertyValue = set;
82
		if (propertyDescriptor.getPropertyType().isArray()) {
83
			Class componentType = propertyDescriptor.getPropertyType()
84
					.getComponentType();
85
			Object[] array = (Object[]) Array.newInstance(componentType, set
86
					.size());
87
			propertyValue = set.toArray(array);
88
		}
89
		return propertyValue;
90
	}
91
92
	public IPropertyChangeListener adaptListener(
93
			ISetPropertyChangeListener listener) {
94
		return attachListener ? new ListenerAdaptor(listener) : null;
95
	}
96
97
	public void addPropertyChangeListener(Object source,
98
			IPropertyChangeListener listener) {
99
		if (attachListener && source != null) {
100
			((ListenerAdaptor) listener).addListenerTo(source);
101
		}
102
	}
103
104
	public void removePropertyChangeListener(Object source,
105
			IPropertyChangeListener listener) {
106
		if (attachListener && source != null) {
107
			((ListenerAdaptor) listener).removeListenerFrom(source);
108
		}
109
	}
110
111
	private class ListenerAdaptor extends BeanPropertyChangeListener {
112
		private final ISetPropertyChangeListener wrapped;
113
114
		ListenerAdaptor(ISetPropertyChangeListener wrapped) {
115
			super(propertyDescriptor);
116
			this.wrapped = wrapped;
117
		}
118
119
		protected void handlePropertyChange(Object source, Object oldValue,
120
				Object newValue) {
121
			wrapped.handleSetPropertyChange(new SetPropertyChangeEvent(source,
122
					BeanSetProperty.this, Diffs.computeSetDiff(asSet(oldValue),
123
							asSet(newValue))));
124
		}
125
	}
126
}
(-)src/org/eclipse/core/databinding/beans/BeanProperties.java (+151 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 (bug 194734)
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.BeanPropertyHelper;
21
import org.eclipse.core.internal.databinding.beans.BeanSetProperty;
22
import org.eclipse.core.internal.databinding.beans.BeanValueProperty;
23
24
/**
25
 * A factory for creating properties for Java objects that conform to the <a
26
 * href="http://java.sun.com/products/javabeans/docs/spec.html">JavaBean
27
 * specification</a> for bound properties.
28
 * 
29
 * @since 1.2
30
 */
31
public class BeanProperties {
32
	/**
33
	 * Returns a value property for the given property name of the given bean
34
	 * class.
35
	 * 
36
	 * @param beanClass
37
	 *            the bean class
38
	 * @param propertyName
39
	 *            the property name
40
	 * @return a value property for the given property name of the given bean
41
	 *         class.
42
	 */
43
	public static IValueProperty valueProperty(Class beanClass,
44
			String propertyName) {
45
		return valueProperty(beanClass, propertyName, null);
46
	}
47
48
	/**
49
	 * Returns a value property for the given property name of the given bean
50
	 * class.
51
	 * 
52
	 * @param beanClass
53
	 *            the bean class
54
	 * @param propertyName
55
	 *            the property name
56
	 * @param valueType
57
	 *            the value type of the returned value property
58
	 * @return a value property for the given property name of the given bean
59
	 *         class.
60
	 */
61
	public static IValueProperty valueProperty(Class beanClass,
62
			String propertyName, Class valueType) {
63
		return new BeanValueProperty(BeanPropertyHelper.getPropertyDescriptor(
64
				beanClass, propertyName), valueType, true);
65
	}
66
67
	/**
68
	 * Returns a set property for the given property name of the given bean
69
	 * class.
70
	 * 
71
	 * @param beanClass
72
	 *            the bean class
73
	 * @param propertyName
74
	 *            the property name
75
	 * @return a set property for the given property name of the given bean
76
	 *         class.
77
	 */
78
	public static ISetProperty setProperty(Class beanClass, String propertyName) {
79
		return setProperty(beanClass, propertyName, null);
80
	}
81
82
	/**
83
	 * Returns a set property for the given property name of the given bean
84
	 * class.
85
	 * 
86
	 * @param beanClass
87
	 *            the bean class
88
	 * @param propertyName
89
	 *            the property name
90
	 * @param elementType
91
	 *            the element type of the returned set property
92
	 * @return a set property for the given property name of the given bean
93
	 *         class.
94
	 */
95
	public static ISetProperty setProperty(Class beanClass,
96
			String propertyName, Class elementType) {
97
		return new BeanSetProperty(BeanPropertyHelper.getPropertyDescriptor(
98
				beanClass, propertyName), elementType, true);
99
	}
100
101
	/**
102
	 * Returns a list property for the given property name of the given bean
103
	 * class.
104
	 * 
105
	 * @param beanClass
106
	 *            the bean class
107
	 * @param propertyName
108
	 *            the property name
109
	 * @return a list property for the given property name of the given bean
110
	 *         class.
111
	 */
112
	public static IListProperty listProperty(Class beanClass,
113
			String propertyName) {
114
		return listProperty(beanClass, propertyName, null);
115
	}
116
117
	/**
118
	 * Returns a list property for the given property name of the given bean
119
	 * class.
120
	 * 
121
	 * @param beanClass
122
	 *            the bean class
123
	 * @param propertyName
124
	 *            the property name
125
	 * @param elementType
126
	 *            the element type of the returned list property
127
	 * @return a list property for the given property name of the given bean
128
	 *         class.
129
	 */
130
	public static IListProperty listProperty(Class beanClass,
131
			String propertyName, Class elementType) {
132
		return new BeanListProperty(BeanPropertyHelper.getPropertyDescriptor(
133
				beanClass, propertyName), elementType, true);
134
	}
135
136
	/**
137
	 * Returns a map property for the given property name of the given bean
138
	 * class.
139
	 * 
140
	 * @param beanClass
141
	 *            the bean class
142
	 * @param propertyName
143
	 *            the property name
144
	 * @return a map property for the given property name of the given bean
145
	 *         class.
146
	 */
147
	public static IMapProperty mapProperty(Class beanClass, String propertyName) {
148
		return new BeanMapProperty(BeanPropertyHelper.getPropertyDescriptor(
149
				beanClass, propertyName), true);
150
	}
151
}
(-)src/org/eclipse/core/internal/databinding/beans/BeanPropertyHelper.java (+169 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.beans;
13
14
import java.beans.BeanInfo;
15
import java.beans.IntrospectionException;
16
import java.beans.Introspector;
17
import java.beans.PropertyDescriptor;
18
import java.lang.reflect.InvocationTargetException;
19
import java.lang.reflect.Method;
20
21
import org.eclipse.core.databinding.BindingException;
22
import org.eclipse.core.databinding.beans.BeansObservables;
23
import org.eclipse.core.databinding.observable.value.IObservableValue;
24
import org.eclipse.core.databinding.util.Policy;
25
import org.eclipse.core.runtime.IStatus;
26
import org.eclipse.core.runtime.Status;
27
28
/**
29
 * @since 1.2
30
 * 
31
 */
32
public class BeanPropertyHelper {
33
	/**
34
	 * Sets the contents of the given property on the given source object to the
35
	 * given value.
36
	 * 
37
	 * @param source
38
	 *            the source object which has the property being updated
39
	 * @param propertyDescriptor
40
	 *            the property being changed
41
	 * @param value
42
	 *            the new value of the property
43
	 */
44
	public static void setProperty(Object source,
45
			PropertyDescriptor propertyDescriptor, Object value) {
46
		try {
47
			Method writeMethod = propertyDescriptor.getWriteMethod();
48
			if (!writeMethod.isAccessible()) {
49
				writeMethod.setAccessible(true);
50
			}
51
			writeMethod.invoke(source, new Object[] { value });
52
		} catch (InvocationTargetException e) {
53
			/*
54
			 * InvocationTargetException wraps any exception thrown by the
55
			 * invoked method.
56
			 */
57
			throw new RuntimeException(e.getCause());
58
		} catch (Exception e) {
59
			if (BeansObservables.DEBUG) {
60
				Policy
61
						.getLog()
62
						.log(
63
								new Status(
64
										IStatus.WARNING,
65
										Policy.JFACE_DATABINDING,
66
										IStatus.OK,
67
										"Could not change value of " + source + "." + propertyDescriptor.getName(), e)); //$NON-NLS-1$ //$NON-NLS-2$
68
			}
69
		}
70
	}
71
72
	/**
73
	 * Returns the contents of the given property for the given bean.
74
	 * 
75
	 * @param source
76
	 *            the source bean
77
	 * @param propertyDescriptor
78
	 *            the property to retrieve
79
	 * @return the contents of the given property for the given bean.
80
	 */
81
	public static Object getProperty(Object source,
82
			PropertyDescriptor propertyDescriptor) {
83
		try {
84
			Method readMethod = propertyDescriptor.getReadMethod();
85
			if (readMethod == null) {
86
				throw new BindingException(propertyDescriptor.getName()
87
						+ " property does not have a read method."); //$NON-NLS-1$
88
			}
89
			if (!readMethod.isAccessible()) {
90
				readMethod.setAccessible(true);
91
			}
92
			return readMethod.invoke(source, null);
93
		} catch (InvocationTargetException e) {
94
			/*
95
			 * InvocationTargetException wraps any exception thrown by the
96
			 * invoked method.
97
			 */
98
			throw new RuntimeException(e.getCause());
99
		} catch (Exception e) {
100
			if (BeansObservables.DEBUG) {
101
				Policy
102
						.getLog()
103
						.log(
104
								new Status(
105
										IStatus.WARNING,
106
										Policy.JFACE_DATABINDING,
107
										IStatus.OK,
108
										"Could not read value of " + source + "." + propertyDescriptor.getName(), e)); //$NON-NLS-1$ //$NON-NLS-2$
109
			}
110
			return null;
111
		}
112
	}
113
114
	/**
115
	 * Returns the element type of the given collection-typed property for the
116
	 * given bean.
117
	 * 
118
	 * @param descriptor
119
	 *            the property being inspected
120
	 * @return the element type of the given collection-typed property if it is
121
	 *         an array property, or Object.class otherwise.
122
	 */
123
	public static Class getCollectionPropertyElementType(
124
			PropertyDescriptor descriptor) {
125
		Class propertyType = descriptor.getPropertyType();
126
		return propertyType.isArray() ? propertyType.getComponentType()
127
				: Object.class;
128
	}
129
130
	/**
131
	 * @param beanClass
132
	 * @param propertyName
133
	 * @return the PropertyDescriptor for the named property on the given bean
134
	 *         class
135
	 */
136
	public static PropertyDescriptor getPropertyDescriptor(Class beanClass,
137
			String propertyName) {
138
		BeanInfo beanInfo;
139
		try {
140
			beanInfo = Introspector.getBeanInfo(beanClass);
141
		} catch (IntrospectionException e) {
142
			// cannot introspect, give up
143
			return null;
144
		}
145
		PropertyDescriptor[] propertyDescriptors = beanInfo
146
				.getPropertyDescriptors();
147
		for (int i = 0; i < propertyDescriptors.length; i++) {
148
			PropertyDescriptor descriptor = propertyDescriptors[i];
149
			if (descriptor.getName().equals(propertyName)) {
150
				return descriptor;
151
			}
152
		}
153
		throw new BindingException(
154
				"Could not find property with name " + propertyName + " in class " + beanClass); //$NON-NLS-1$ //$NON-NLS-2$
155
	}
156
157
	/**
158
	 * @param observable
159
	 * @param propertyName
160
	 * @return property descriptor or <code>null</code>
161
	 */
162
	/* package */public static PropertyDescriptor getValueTypePropertyDescriptor(
163
			IObservableValue observable, String propertyName) {
164
		if (observable.getValueType() != null)
165
			return getPropertyDescriptor((Class) observable.getValueType(),
166
					propertyName);
167
		return null;
168
	}
169
}
(-)META-INF/MANIFEST.MF (+3 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",
Lines 21-26 Link Here
21
 org.eclipse.core.internal.databinding.observable;x-internal:=true,
22
 org.eclipse.core.internal.databinding.observable;x-internal:=true,
22
 org.eclipse.core.internal.databinding.observable.masterdetail;x-friends:="org.eclipse.jface.tests.databinding",
23
 org.eclipse.core.internal.databinding.observable.masterdetail;x-friends:="org.eclipse.jface.tests.databinding",
23
 org.eclipse.core.internal.databinding.observable.tree;x-friends:="org.eclipse.jface.databinding,org.eclipse.jface.tests.databinding",
24
 org.eclipse.core.internal.databinding.observable.tree;x-friends:="org.eclipse.jface.databinding,org.eclipse.jface.tests.databinding",
25
 org.eclipse.core.internal.databinding.property;x-friends:="org.eclipse.jface.databinding,org.eclipse.jface.tests.databinding",
26
 org.eclipse.core.internal.databinding.property.masterdetail;x-friends:="org.eclipse.jface.databinding,org.eclipse.jface.tests.databinding",
24
 org.eclipse.core.internal.databinding.validation;x-friends:="org.eclipse.jface.tests.databinding"
27
 org.eclipse.core.internal.databinding.validation;x-friends:="org.eclipse.jface.tests.databinding"
25
Require-Bundle: org.eclipse.equinox.common;bundle-version="[3.2.0,4.0.0)"
28
Require-Bundle: org.eclipse.equinox.common;bundle-version="[3.2.0,4.0.0)"
26
Import-Package-Comment: see http://wiki.eclipse.org/
29
Import-Package-Comment: see http://wiki.eclipse.org/
(-)src/org/eclipse/core/databinding/property/BasicMapProperty.java (+75 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.HashMap;
15
import java.util.Iterator;
16
import java.util.Map;
17
18
/**
19
 * Abstract map property implementation for properties where the map can be
20
 * completely replaced in a single atomic operation.
21
 * <p>
22
 * For example, a map-typed bean property Customer.phoneNumbers can be modified
23
 * by calling Customer.setPhoneNumbers(Map phoneNumbers).
24
 * 
25
 * @since 1.2
26
 */
27
public abstract class BasicMapProperty extends MapProperty {
28
	/**
29
	 * Sets the map property on the source to the specified map.
30
	 * 
31
	 * @param source
32
	 *            the property source
33
	 * @param map
34
	 *            the new map
35
	 */
36
	protected abstract void setMap(Object source, Map map);
37
38
	public void clear(Object source) {
39
		if (!isEmpty(source))
40
			setMap(source, new HashMap());
41
	}
42
43
	public Object put(Object source, Object key, Object value) {
44
		Map map = new HashMap(getMap(source));
45
		Object result = map.put(key, value);
46
		setMap(source, map);
47
		return result;
48
	}
49
50
	public void putAll(Object source, Map t) {
51
		if (t.isEmpty())
52
			return;
53
		Map map = new HashMap(getMap(source));
54
		for (Iterator it = t.entrySet().iterator(); it.hasNext();) {
55
			Map.Entry entry = (Map.Entry) it.next();
56
			map.put(entry.getKey(), entry.getValue());
57
		}
58
		setMap(source, map);
59
	}
60
61
	public Object remove(Object source, Object key) {
62
		Map map = getMap(source);
63
		if (map.containsKey(key)) {
64
			map = new HashMap(map);
65
			Object result = map.remove(key);
66
			setMap(source, map);
67
			return result;
68
		}
69
		return null;
70
	}
71
72
	public int size(Object source) {
73
		return getMap(source).size();
74
	}
75
}
(-)src/org/eclipse/core/databinding/property/IListProperty.java (+171 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import java.util.Collection;
15
import java.util.List;
16
17
/**
18
 * Interface for list-typed properties.
19
 * 
20
 * @since 1.2
21
 * @noimplement This interface is not intended to be implemented by clients.
22
 */
23
public interface IListProperty extends ICollectionProperty {
24
	/**
25
	 * Returns a List with the current contents of the source's list property
26
	 * 
27
	 * @param source
28
	 *            the property source
29
	 * @return a List with the current contents of the source's list property
30
	 */
31
	List getList(Object source);
32
33
	/**
34
	 * Inserts all elements in the specified collection into the source's list
35
	 * property at the specified index.
36
	 * 
37
	 * @param source
38
	 *            the property source
39
	 * @param index
40
	 *            the insertion index
41
	 * @param c
42
	 *            the collection of elements to add
43
	 * @return whether the source's list property was changed
44
	 */
45
	boolean addAll(Object source, int index, Collection c);
46
47
	/**
48
	 * Returns the element at the specified position in the source's list
49
	 * property
50
	 * 
51
	 * @param source
52
	 *            the property source
53
	 * @param index
54
	 *            the element position
55
	 * @return the element at the given position in the source's list property
56
	 */
57
	Object get(Object source, int index);
58
59
	/**
60
	 * Replaces the element at the specified position in the source's list
61
	 * property with the given element.
62
	 * 
63
	 * @param source
64
	 *            the property source
65
	 * @param index
66
	 *            the element position
67
	 * @param element
68
	 *            the replacement element
69
	 * @return the element previously at the specified position in the source's
70
	 *         list property
71
	 */
72
	Object set(Object source, int index, Object element);
73
74
	/**
75
	 * Moves the element at the specified old position in the source's list
76
	 * property to the specified new position
77
	 * 
78
	 * @param source
79
	 *            the property source
80
	 * @param oldIndex
81
	 *            the old element position
82
	 * @param newIndex
83
	 *            the new element position
84
	 * @return the element that was moved
85
	 */
86
	Object move(Object source, int oldIndex, int newIndex);
87
88
	/**
89
	 * Inserts the element into the source's list property at the specified
90
	 * position
91
	 * 
92
	 * @param source
93
	 *            the property source
94
	 * @param index
95
	 *            the insertion index
96
	 * @param element
97
	 *            the element to insert
98
	 */
99
	void add(Object source, int index, Object element);
100
101
	/**
102
	 * Removes the element from the source's list property which is located at
103
	 * the specified position
104
	 * 
105
	 * @param source
106
	 *            the property source
107
	 * @param index
108
	 *            the index of the element to remove
109
	 * @return the element that was removed from the source's list property
110
	 */
111
	Object remove(Object source, int index);
112
113
	/**
114
	 * Returns the index of the first location of the given element in the
115
	 * source's list property, or -1 if the list does not contain the element.
116
	 * 
117
	 * @param source
118
	 *            the property source
119
	 * @param o
120
	 *            the element
121
	 * @return the index of the first location of the given element in the
122
	 *         source's list property, or -1 if the list does not contain the
123
	 *         element
124
	 */
125
	int indexOf(Object source, Object o);
126
127
	/**
128
	 * Returns the index of the last location of the given element in the
129
	 * source's list property, or -1 if the list does not contain the given
130
	 * element.
131
	 * 
132
	 * @param source
133
	 * @param o
134
	 * @return the index of the last location of the given element in the
135
	 *         source's list property, or -1 if the list does not contain the
136
	 *         element
137
	 */
138
	int lastIndexOf(Object source, Object o);
139
140
	/**
141
	 * Constructs and returns a "native" listener for the property. When the
142
	 * native listener receives a change event from the property source, a
143
	 * ListChangeEvent is constructed and sent to the specified listener.
144
	 * 
145
	 * {@link #addPropertyChangeListener(Object, IPropertyChangeListener)} and
146
	 * {@link #removePropertyChangeListener(Object, IPropertyChangeListener)}.
147
	 * 
148
	 * @param listener
149
	 *            the listener to adapt
150
	 * @return the adapted listener
151
	 */
152
	public IPropertyChangeListener adaptListener(
153
			IListPropertyChangeListener listener);
154
155
	 /**
156
	 * Convenience method which
157
	 * {@link #adaptListener(IListPropertyChangeListener) adapts} the specified
158
	 * listener,
159
	 * {@link #addPropertyChangeListener(Object, IPropertyChangeListener)
160
	 * registers} the adapted listener as a property change listener, and
161
	 * returns the adapted listener
162
	 * 
163
	 * @param source
164
	 *            the property source
165
	 * @param listener
166
	 *            the listener
167
	 * @return the adapted listener
168
	 */
169
	public IPropertyChangeListener addListChangeListener(Object source,
170
			IListPropertyChangeListener listener);
171
}
(-)src/org/eclipse/core/databinding/property/ISetProperty.java (+62 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import java.util.Set;
15
16
/**
17
 * Interface for set-typed properties
18
 * 
19
 * @since 1.2
20
 * @noimplement This interface is not intended to be implemented by clients.
21
 */
22
public interface ISetProperty extends ICollectionProperty {
23
	/**
24
	 * Returns a Set with the current contents of the source's set property
25
	 * 
26
	 * @param source
27
	 *            the property source
28
	 * @return a Set with the current contents of the source's set property
29
	 */
30
	public Set getSet(Object source);
31
32
	/**
33
	 * Constructs and returns a "native" listener for the property. When the
34
	 * native listener receives a change event from the property source, a
35
	 * SetChangeEvent is constructed and sent to the specified listener.
36
	 * 
37
	 * {@link #addPropertyChangeListener(Object, IPropertyChangeListener)} and
38
	 * {@link #removePropertyChangeListener(Object, IPropertyChangeListener)}.
39
	 * 
40
	 * @param listener
41
	 *            the listener to adapt
42
	 * @return the adapted listener
43
	 */
44
	public IPropertyChangeListener adaptListener(ISetPropertyChangeListener listener);
45
46
	 /**
47
	 * Convenience method which
48
	 * {@link #adaptListener(ISetPropertyChangeListener) adapts} the specified
49
	 * listener,
50
	 * {@link #addPropertyChangeListener(Object, IPropertyChangeListener)
51
	 * registers} the adapted listener as a property change listener, and
52
	 * returns the adapted listener
53
	 * 
54
	 * @param source
55
	 *            the property source
56
	 * @param listener
57
	 *            the listener
58
	 * @return the adapted listener
59
	 */
60
	public IPropertyChangeListener addSetChangeListener(Object source,
61
			ISetPropertyChangeListener listener);
62
}
(-)src/org/eclipse/core/databinding/property/ValuePropertyChangeEvent.java (+55 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import java.util.EventObject;
15
16
import org.eclipse.core.databinding.observable.value.ValueDiff;
17
import org.eclipse.core.runtime.Assert;
18
19
/**
20
 * Value change event describing a change of a value property on a particular
21
 * property source.
22
 * 
23
 * @since 1.2
24
 */
25
public class ValuePropertyChangeEvent extends EventObject {
26
	private static final long serialVersionUID = 1L;
27
28
	/**
29
	 * The value property that changed
30
	 */
31
	public final IValueProperty property;
32
33
	/**
34
	 * ValueDiff with the old and new values of the property.
35
	 */
36
	public final ValueDiff diff;
37
38
	/**
39
	 * Constructs a ValuePropertyChangeEvent with the given attributes
40
	 * 
41
	 * @param source
42
	 *            the property source
43
	 * @param property
44
	 *            the property that changed on the source
45
	 * @param diff
46
	 *            a ValueDiff describing the changes to the value property
47
	 */
48
	public ValuePropertyChangeEvent(Object source, IValueProperty property,
49
			ValueDiff diff) {
50
		super(source);
51
		this.property = property;
52
		Assert.isNotNull(diff, "diff cannot be null"); //$NON-NLS-1$
53
		this.diff = diff;
54
	}
55
}
(-)src/org/eclipse/core/databinding/property/MapProperty.java (+54 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
/**
15
 * Abstract implementation of IMapProperty
16
 * 
17
 * @since 1.2
18
 */
19
public abstract class MapProperty implements IMapProperty {
20
	public boolean containsKey(Object source, Object key) {
21
		return getMap(source).containsKey(key);
22
	}
23
24
	public boolean containsValue(Object source, Object value) {
25
		return getMap(source).containsValue(value);
26
	}
27
28
	public boolean equals(Object source, Object o) {
29
		return getMap(source).equals(o);
30
	}
31
32
	public Object get(Object source, Object key) {
33
		return getMap(source).get(key);
34
	}
35
36
	public int hashCode(Object source) {
37
		return getMap(source).hashCode();
38
	}
39
40
	public boolean isEmpty(Object source) {
41
		return getMap(source).isEmpty();
42
	}
43
44
	public int size(Object source) {
45
		return getMap(source).size();
46
	}
47
48
	 public final IPropertyChangeListener addMapChangeListener(Object source,
49
			IMapPropertyChangeListener listener) {
50
		IPropertyChangeListener l = adaptListener(listener);
51
		addPropertyChangeListener(source, l);
52
		return l;
53
	}
54
}
(-)src/org/eclipse/core/databinding/property/ListProperty.java (+45 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import java.util.Collection;
15
16
/**
17
 * Abstract implementation of IListProperty.
18
 * 
19
 * @since 1.2
20
 */
21
public abstract class ListProperty extends CollectionProperty implements
22
		IListProperty {
23
	Collection getCollection(Object source) {
24
		return getList(source);
25
	}
26
27
	public Object get(Object source, int index) {
28
		return getList(source).get(index);
29
	}
30
31
	public int indexOf(Object source, Object o) {
32
		return getList(source).indexOf(o);
33
	}
34
35
	public int lastIndexOf(Object source, Object o) {
36
		return getList(source).lastIndexOf(o);
37
	}
38
39
	public final IPropertyChangeListener addListChangeListener(Object source,
40
			IListPropertyChangeListener listener) {
41
		IPropertyChangeListener l = adaptListener(listener);
42
		addPropertyChangeListener(source, l);
43
		return l;
44
	}
45
}
(-)src/org/eclipse/core/databinding/property/SetPropertyChangeEvent.java (+55 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import java.util.EventObject;
15
16
import org.eclipse.core.databinding.observable.set.SetDiff;
17
import org.eclipse.core.runtime.Assert;
18
19
/**
20
 * Set change event describing an incremental change of a set property on a
21
 * particular property source.
22
 * 
23
 * @since 1.2
24
 */
25
public class SetPropertyChangeEvent extends EventObject {
26
	private static final long serialVersionUID = 1L;
27
28
	/**
29
	 * The set property that changed
30
	 */
31
	public final ISetProperty property;
32
33
	/**
34
	 * SetDiff enumerating the added and removed elements in the set.
35
	 */
36
	public final SetDiff diff;
37
38
	/**
39
	 * Constructs a SetPropertyChangeEvent with the given attributes
40
	 * 
41
	 * @param source
42
	 *            the property source
43
	 * @param property
44
	 *            the property that changed on the source
45
	 * @param diff
46
	 *            a SetDiff describing the changes to the set property
47
	 */
48
	public SetPropertyChangeEvent(Object source, ISetProperty property,
49
			SetDiff diff) {
50
		super(source);
51
		this.property = property;
52
		Assert.isNotNull(diff, "diff cannot be null"); //$NON-NLS-1$
53
		this.diff = diff;
54
	}
55
}
(-)src/org/eclipse/core/internal/databinding/property/PropertyObservableMap.java (+182 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 (bug 194734)
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.Map;
17
import java.util.Set;
18
19
import org.eclipse.core.databinding.observable.ObservableTracker;
20
import org.eclipse.core.databinding.observable.Realm;
21
import org.eclipse.core.databinding.observable.map.AbstractObservableMap;
22
import org.eclipse.core.databinding.property.IMapProperty;
23
import org.eclipse.core.databinding.property.IMapPropertyChangeListener;
24
import org.eclipse.core.databinding.property.IProperty;
25
import org.eclipse.core.databinding.property.IPropertyChangeListener;
26
import org.eclipse.core.databinding.property.IPropertyObservable;
27
import org.eclipse.core.databinding.property.MapPropertyChangeEvent;
28
29
/**
30
 * @since 3.3
31
 * 
32
 */
33
public class PropertyObservableMap extends AbstractObservableMap implements
34
		IPropertyObservable {
35
	private Object source;
36
	private IMapProperty property;
37
38
	private volatile boolean updating = false;
39
40
	private boolean disposed = false;
41
42
	private transient volatile int modCount = 0;
43
44
	private IPropertyChangeListener listener;
45
46
	/**
47
	 * @param realm
48
	 * @param source
49
	 * @param property
50
	 */
51
	public PropertyObservableMap(Realm realm, Object source,
52
			IMapProperty property) {
53
		super(realm);
54
		this.source = source;
55
		this.property = property;
56
57
		IMapPropertyChangeListener mapListener = new IMapPropertyChangeListener() {
58
			public void handleMapPropertyChange(
59
					final MapPropertyChangeEvent event) {
60
				if (!disposed && !updating) {
61
					getRealm().exec(new Runnable() {
62
						public void run() {
63
							getRealm().exec(new Runnable() {
64
								public void run() {
65
									modCount++;
66
									fireMapChange(event.diff);
67
								}
68
							});
69
						}
70
					});
71
				}
72
			}
73
		};
74
		this.listener = property.adaptListener(mapListener);
75
	}
76
77
	private void getterCalled() {
78
		ObservableTracker.getterCalled(this);
79
	}
80
81
	protected void firstListenerAdded() {
82
		if (!disposed) {
83
			property.addPropertyChangeListener(source, listener);
84
		}
85
	}
86
87
	protected void lastListenerRemoved() {
88
		if (!disposed) {
89
			property.removePropertyChangeListener(source, listener);
90
		}
91
	}
92
93
	public boolean containsKey(Object key) {
94
		getterCalled();
95
		return property.containsKey(source, key);
96
	}
97
98
	public boolean containsValue(Object value) {
99
		getterCalled();
100
		return property.containsValue(source, value);
101
	}
102
103
	public Set entrySet() {
104
		getterCalled();
105
		// unmodifiable for now
106
		return Collections.unmodifiableSet(property.getMap(source).entrySet());
107
	}
108
109
	public Object get(Object key) {
110
		getterCalled();
111
		return property.get(source, key);
112
	}
113
114
	public boolean isEmpty() {
115
		getterCalled();
116
		return property.isEmpty(source);
117
	}
118
119
	public Set keySet() {
120
		getterCalled();
121
		return Collections.unmodifiableSet(property.getMap(source).keySet());
122
	}
123
124
	public Object put(Object key, Object value) {
125
		checkRealm();
126
		return property.put(source, key, value);
127
	}
128
129
	public void putAll(Map m) {
130
		checkRealm();
131
		property.putAll(source, m);
132
	}
133
134
	public Object remove(Object key) {
135
		checkRealm();
136
		return property.remove(source, key);
137
	}
138
139
	public int size() {
140
		getterCalled();
141
		return property.size(source);
142
	}
143
144
	public Collection values() {
145
		getterCalled();
146
		return Collections.unmodifiableCollection(property.getMap(source)
147
				.values());
148
	}
149
150
	public void clear() {
151
		getterCalled();
152
		property.clear(source);
153
	}
154
155
	public boolean equals(Object o) {
156
		getterCalled();
157
		return property.equals(source, o);
158
	}
159
160
	public int hashCode() {
161
		getterCalled();
162
		return property.hashCode(source);
163
	}
164
165
	public Object getObserved() {
166
		return source;
167
	}
168
169
	public IProperty getProperty() {
170
		return property;
171
	}
172
173
	public synchronized void dispose() {
174
		if (!disposed) {
175
			disposed = true;
176
			property.removePropertyChangeListener(source, listener);
177
			property = null;
178
			source = null;
179
		}
180
		super.dispose();
181
	}
182
}
(-)src/org/eclipse/core/databinding/property/Properties.java (+196 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import org.eclipse.core.internal.databinding.property.masterdetail.ListPropertyDetailValueList;
15
import org.eclipse.core.internal.databinding.property.masterdetail.MapPropertyDetailValueMap;
16
import org.eclipse.core.internal.databinding.property.masterdetail.SetPropertyDetailValueMap;
17
import org.eclipse.core.internal.databinding.property.masterdetail.ValuePropertyDetailList;
18
import org.eclipse.core.internal.databinding.property.masterdetail.ValuePropertyDetailMap;
19
import org.eclipse.core.internal.databinding.property.masterdetail.ValuePropertyDetailSet;
20
import org.eclipse.core.internal.databinding.property.masterdetail.ValuePropertyDetailValue;
21
22
/**
23
 * A factory for chaining properties together to create nested properties.
24
 * <p>
25
 * Example: Suppose class <code>A</code> has a property <code>b</code> of type
26
 * <code>B</code>, and that class <code>B</code> has a property <code>c</code>
27
 * of type <code>C</code>:
28
 * 
29
 * <pre>
30
 * A a = new A();
31
 * B b = a.getB();
32
 * IValueProperty ab = BeanProperties.valueProperty(A.class, &quot;b&quot;);
33
 * assertTrue(ab.getValue(a) == b);
34
 * 
35
 * IValueProperty bc = BeanProperties.valueProperty(B.class, &quot;c&quot;);
36
 * C c = b.getC();
37
 * assertTrue(bc.getValue(b) == c);
38
 * </pre>
39
 * 
40
 * Using Properties, the <code>ab</code> and <code>bc</code>
41
 * properties may be combined to form a nested <code>abc</code> property:
42
 * 
43
 * <pre>
44
 * IValueProperty abc = Properties.detailValue(ab, bc)
45
 * assertTrue(abc.getValue(a) == c);
46
 * </pre>
47
 * 
48
 * @since 1.2
49
 */
50
public class Properties {
51
	// Properties of IValueProperty properties
52
53
	/**
54
	 * Returns the nested combination of the master value and detail value
55
	 * properties. Value modifications made through the returned property are
56
	 * delegated to the detail property, using the value of the master property
57
	 * as the source.
58
	 * 
59
	 * @param masterValue
60
	 *            the master property
61
	 * @param detailValue
62
	 *            the detail property
63
	 * @return the nested combination of the master and detail properties
64
	 */
65
	public static IValueProperty detailValue(IValueProperty masterValue,
66
			IValueProperty detailValue) {
67
		return new ValuePropertyDetailValue(masterValue, detailValue);
68
	}
69
70
	/**
71
	 * Returns the nested combination of the master value and detail list
72
	 * properties. List modifications made through the returned property are
73
	 * delegated to the detail property, using the value of the master property
74
	 * as the source.
75
	 * 
76
	 * @param masterValue
77
	 *            the master property
78
	 * @param detailList
79
	 *            the detail property
80
	 * @return the nested combination of the master value and detail list
81
	 *         properties
82
	 */
83
	public static IListProperty detailList(IValueProperty masterValue,
84
			IListProperty detailList) {
85
		return new ValuePropertyDetailList(masterValue, detailList);
86
	}
87
88
	/**
89
	 * Returns the nested combination of the master value and detail set
90
	 * properties. Set modifications made through the returned property are
91
	 * delegated to the detail property, using the value of the master property
92
	 * as the source.
93
	 * 
94
	 * @param masterValue
95
	 *            the master property
96
	 * @param detailSet
97
	 *            the detail property
98
	 * @return the nested combination of the master value and detail set
99
	 *         properties
100
	 */
101
	public static ISetProperty detailSet(IValueProperty masterValue,
102
			ISetProperty detailSet) {
103
		return new ValuePropertyDetailSet(masterValue, detailSet);
104
	}
105
106
	/**
107
	 * Returns the nested combination of the master value and detail map
108
	 * properties. Map modifications made through the returned property are
109
	 * delegated to the detail property, using the value of the master property
110
	 * as the source.
111
	 * 
112
	 * @param masterValue
113
	 *            the master property
114
	 * @param detailMap
115
	 *            the detail property
116
	 * @return the nested combination of the master value and detial map
117
	 *         properties
118
	 */
119
	public static IMapProperty detailMap(IValueProperty masterValue,
120
			IMapProperty detailMap) {
121
		return new ValuePropertyDetailMap(masterValue, detailMap);
122
	}
123
124
	// Properties of IListProperty master properties
125
126
	/**
127
	 * Returns the nested combination of the master list and detail value
128
	 * properties. Note that because this property is a projection of value
129
	 * properties over a list, the only modification supported is through the
130
	 * {@link IValueProperty#setValue(Object, Object)} method. Modifications
131
	 * made through the returned property are delegated to the detail property,
132
	 * using the corresponding list element from the master property as the
133
	 * source.
134
	 * 
135
	 * @param masterList
136
	 *            the master property
137
	 * @param detailValue
138
	 *            the detail property
139
	 * @return the nested combination of the master list and detail value
140
	 *         properties
141
	 */
142
	public static IListProperty detailValues(IListProperty masterList,
143
			IValueProperty detailValue) {
144
		return new ListPropertyDetailValueList(masterList, detailValue);
145
	}
146
147
	// Properties of ISetProperty master properties
148
149
	/**
150
	 * Returns the nested combination of the master set and detail value
151
	 * properties. Note that because this property is a projection of value
152
	 * properties over a set, the only modifications supported are through the
153
	 * {@link IMapProperty#put(Object, Object, Object)} and
154
	 * {@link IMapProperty#putAll(Object, java.util.Map)} methods. In the latter
155
	 * case, this property does not put entries for keys not already in the
156
	 * master key set. Modifications made through the returned property are
157
	 * delegated to the detail property, using the corresponding set element
158
	 * from the master property as the source.
159
	 * 
160
	 * @param masterKeySet
161
	 *            the master property
162
	 * @param detailValues
163
	 *            the detail property
164
	 * @return the nested combination of the master set and detail value
165
	 *         properties
166
	 */
167
	public static IMapProperty detailValues(ISetProperty masterKeySet,
168
			IValueProperty detailValues) {
169
		return new SetPropertyDetailValueMap(masterKeySet, detailValues);
170
	}
171
172
	// Properties of IMapProperty master properties
173
174
	/**
175
	 * Returns the nested combination of the master map and detail value
176
	 * properties. Note that because this property is a projection of value
177
	 * properties over a values collection, the only modifications supported are
178
	 * through the {@link IMapProperty#put(Object, Object, Object)} and
179
	 * {@link IMapProperty#putAll(Object, java.util.Map)} methods. In the latter
180
	 * case, this property does not entries for keys not already contained in
181
	 * the master map's key set. Modifications made through the returned
182
	 * property are delegated to the detail property, using the corresponding
183
	 * entry value from the master property as the source.
184
	 * 
185
	 * @param masterMap
186
	 *            the master property
187
	 * @param detailValues
188
	 *            the detail property
189
	 * @return the nested combination of the master map and detail value
190
	 *         properties.
191
	 */
192
	public static IMapProperty detailValues(IMapProperty masterMap,
193
			IValueProperty detailValues) {
194
		return new MapPropertyDetailValueMap(masterMap, detailValues);
195
	}
196
}
(-)src/org/eclipse/core/databinding/property/IValueProperty.java (+78 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
/**
15
 * Interface for value-typed properties
16
 * 
17
 * @since 1.2
18
 * @noimplement This interface is not intended to be implemented by clients.
19
 */
20
public interface IValueProperty extends IProperty {
21
	/**
22
	 * Returns the source's value property
23
	 * 
24
	 * @param source
25
	 *            the property source
26
	 * @return the current value of the source's value property
27
	 */
28
	public Object getValue(Object source);
29
30
	/**
31
	 * Sets the source's value property to the specified value
32
	 * 
33
	 * @param source
34
	 *            the property source
35
	 * @param value
36
	 *            the new value
37
	 */
38
	public void setValue(Object source, Object value);
39
40
	/**
41
	 * Returns the value type of the property, or <code>null</code> if untyped.
42
	 * 
43
	 * @return the value type of the property, or <code>null</code> if untyped.
44
	 */
45
	public Object getValueType();
46
47
	/**
48
	 * Constructs and returns a "native" listener for the property. When the
49
	 * native listener receives a change event from the property source, a
50
	 * ValueChangeEvent is constructed and sent to the specified listener.
51
	 * 
52
	 * {@link #addPropertyChangeListener(Object, IPropertyChangeListener)} and
53
	 * {@link #removePropertyChangeListener(Object, IPropertyChangeListener)}.
54
	 * 
55
	 * @param listener
56
	 *            the listener to adapt
57
	 * @return the adapted listener
58
	 */
59
	public IPropertyChangeListener adaptListener(
60
			IValuePropertyChangeListener listener);
61
62
	/**
63
	 * Convenience method which
64
	 * {@link #adaptListener(IValuePropertyChangeListener) adapts} the specified
65
	 * listener,
66
	 * {@link #addPropertyChangeListener(Object, IPropertyChangeListener)
67
	 * registers} the adapted listener as a property change listener, and
68
	 * returns the adapted listener.
69
	 * 
70
	 * @param source
71
	 *            the property source
72
	 * @param listener
73
	 *            the listener to adapt
74
	 * @return the adapted listener
75
	 */
76
	public IPropertyChangeListener addValueChangeListener(Object source,
77
			IValuePropertyChangeListener listener);
78
}
(-)src/org/eclipse/core/databinding/property/IMapProperty.java (+185 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import java.util.Map;
15
16
/**
17
 * Interface for map-typed properties
18
 * 
19
 * @since 1.2
20
 * @noimplement This interface is not intended to be implemented by clients.
21
 */
22
public interface IMapProperty extends IProperty {
23
	/**
24
	 * Returns a Map with the current contents of the source's map property
25
	 * 
26
	 * @param source
27
	 *            the property source
28
	 * @return a Map with the current contents of the source's map property
29
	 */
30
	Map getMap(Object source);
31
32
	/**
33
	 * Returns the size of the source's map property
34
	 * 
35
	 * @param source
36
	 *            the property source
37
	 * @return the size of the source's map property
38
	 */
39
	int size(Object source);
40
41
	/**
42
	 * Returns whether the source's map property is empty
43
	 * 
44
	 * @param source
45
	 *            the property source
46
	 * @return whether the source's map property is empty
47
	 */
48
	boolean isEmpty(Object source);
49
50
	/**
51
	 * Returns whether the specified key is contained in the key set of the
52
	 * source's map property
53
	 * 
54
	 * @param source
55
	 *            the property source
56
	 * @param key
57
	 *            the key
58
	 * @return whether the specified key is contained in the key set of the
59
	 *         source's map property
60
	 */
61
	boolean containsKey(Object source, Object key);
62
63
	/**
64
	 * Returns whether the specified value is contains in the values collection
65
	 * of the source's map property
66
	 * 
67
	 * @param source
68
	 *            the property source
69
	 * @param value
70
	 *            the value
71
	 * @return whether the specified value is contains in the values collection
72
	 *         of the source's map property
73
	 */
74
	boolean containsValue(Object source, Object value);
75
76
	/**
77
	 * Returns the value associated with the specified key in the source's map
78
	 * property
79
	 * 
80
	 * @param source
81
	 *            the property source
82
	 * @param key
83
	 *            the key
84
	 * @return the value associated with the specified key in the source's map
85
	 *         property
86
	 */
87
	Object get(Object source, Object key);
88
89
	/**
90
	 * Associates the specified value with the specified key in the source's map
91
	 * property
92
	 * 
93
	 * @param source
94
	 *            the property source
95
	 * @param key
96
	 *            the key
97
	 * @param value
98
	 *            the value
99
	 * @return the value that was previously associated with the given key in
100
	 *         the source's map property
101
	 */
102
	Object put(Object source, Object key, Object value);
103
104
	/**
105
	 * Removes the mapping for the specified key from the source's map property
106
	 * 
107
	 * @param source
108
	 *            the property source
109
	 * @param key
110
	 *            the key
111
	 * @return the value that was previously associated with the specified key
112
	 *         in the source's map property, or null if no such mapping exists
113
	 */
114
	Object remove(Object source, Object key);
115
116
	/**
117
	 * Adds all mappings in the specified map to the source's map property.
118
	 * 
119
	 * @param source
120
	 *            the property source
121
	 * @param t
122
	 *            the map
123
	 */
124
	void putAll(Object source, Map t);
125
126
	/**
127
	 * Removes all mapping from the source's map property
128
	 * 
129
	 * @param source
130
	 *            the property source
131
	 */
132
	void clear(Object source);
133
134
	/**
135
	 * Returns whether the source's map property is equal to the argument
136
	 * 
137
	 * @param source
138
	 *            the property source
139
	 * @param o
140
	 *            the object to test for equality
141
	 * @return whether the source's map property is equal to the argument
142
	 */
143
	boolean equals(Object source, Object o);
144
145
	/**
146
	 * Returns the hash code of the source's map property
147
	 * 
148
	 * @param source
149
	 *            the property source
150
	 * @return the hash code of the source's map property
151
	 */
152
	int hashCode(Object source);
153
154
	/**
155
	 * Constructs and returns a "native" listener for the property. When the
156
	 * native listener receives a change event from the property source, a
157
	 * MapChangeEvent is constructed and sent to the specified listener.
158
	 * 
159
	 * {@link #addPropertyChangeListener(Object, IPropertyChangeListener)} and
160
	 * {@link #removePropertyChangeListener(Object, IPropertyChangeListener)}.
161
	 * 
162
	 * @param listener
163
	 *            the listener to adapt
164
	 * @return the adapted listener
165
	 */
166
	public IPropertyChangeListener adaptListener(
167
			IMapPropertyChangeListener listener);
168
169
	 /**
170
	 * Convenience method which
171
	 * {@link #adaptListener(IMapPropertyChangeListener) adapts} the specified
172
	 * listener,
173
	 * {@link #addPropertyChangeListener(Object, IPropertyChangeListener)
174
	 * registers} the adapted listener as a property change listener, and
175
	 * returns the adapted listener
176
	 * 
177
	 * @param source
178
	 *            the property source
179
	 * @param listener
180
	 *            the listener
181
	 * @return the adapted listener
182
	 */
183
	public IPropertyChangeListener addMapChangeListener(Object source,
184
			IMapPropertyChangeListener listener);
185
}
(-)src/org/eclipse/core/databinding/property/IMapPropertyChangeListener.java (+27 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
/**
15
 * Listener for changes to map properties on a property source
16
 * 
17
 * @since 1.2
18
 */
19
public interface IMapPropertyChangeListener {
20
	/**
21
	 * Handle a change to a map property on a specific property source.
22
	 * 
23
	 * @param event
24
	 *            an event describing the map change that occured.
25
	 */
26
	public void handleMapPropertyChange(MapPropertyChangeEvent event);
27
}
(-)src/org/eclipse/core/databinding/property/ValueProperty.java (+26 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
/**
15
 * Abstract implementation of IValueProperty.
16
 * 
17
 * @since 1.2
18
 */
19
public abstract class ValueProperty implements IValueProperty {
20
	 public final IPropertyChangeListener addValueChangeListener(Object source,
21
			IValuePropertyChangeListener listener) {
22
		IPropertyChangeListener l = adaptListener(listener);
23
		addPropertyChangeListener(source, l);
24
		return l;
25
	}
26
}
(-)src/org/eclipse/core/databinding/property/IValuePropertyChangeListener.java (+27 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
/**
15
 * Listener for changes to value properties on a property source
16
 * 
17
 * @since 1.2
18
 */
19
public interface IValuePropertyChangeListener {
20
	/**
21
	 * Handle a change to a value property on a specific property source.
22
	 * 
23
	 * @param event
24
	 *            an event describing the value change that occured.
25
	 */
26
	public void handleValuePropertyChange(ValuePropertyChangeEvent event);
27
}
(-)src/org/eclipse/core/databinding/property/BasicListProperty.java (+159 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.ArrayList;
15
import java.util.Collection;
16
import java.util.Iterator;
17
import java.util.List;
18
import java.util.ListIterator;
19
20
/**
21
 * Abstract IListProperty implementation for properties where the list can be
22
 * completely replaced in a single atomic operation.
23
 * <p>
24
 * For example, a list-typed bean property Customer.invoices can be modified by
25
 * calling Customer.setInvoices(List invoices).
26
 * 
27
 * @since 1.2
28
 */
29
public abstract class BasicListProperty extends ListProperty {
30
	/**
31
	 * Sets the list property on the source to the specified list.
32
	 * 
33
	 * @param source
34
	 *            the property source
35
	 * @param list
36
	 *            the new list
37
	 */
38
	protected abstract void setList(Object source, List list);
39
40
	public boolean add(Object source, Object o) {
41
		add(source, size(source), o);
42
		return true;
43
	}
44
45
	public void add(Object source, int index, Object element) {
46
		List list = new ArrayList(getList(source));
47
		list.add(index, element);
48
		setList(source, list);
49
	}
50
51
	public boolean addAll(Object source, Collection c) {
52
		if (c.isEmpty())
53
			return false;
54
		addAll(source, size(source), c);
55
		return true;
56
	}
57
58
	public boolean addAll(Object source, int index, Collection c) {
59
		if (c.isEmpty()) {
60
			return false;
61
		}
62
63
		List list = new ArrayList(getList(source));
64
		boolean changed = false;
65
		int i = index;
66
		for (Iterator it = c.iterator(); it.hasNext(); i++) {
67
			Object o = it.next();
68
			list.add(i, o);
69
			changed = true;
70
		}
71
		if (changed) {
72
			setList(source, list);
73
		}
74
		return changed;
75
	}
76
77
	public void clear(Object source) {
78
		if (isEmpty(source))
79
			return;
80
		setList(source, new ArrayList());
81
	}
82
83
	public Object move(Object source, int oldIndex, int newIndex) {
84
		if (oldIndex == newIndex)
85
			return get(source, oldIndex);
86
		List list = new ArrayList(getList(source));
87
		Object result = list.remove(oldIndex);
88
		list.add(newIndex, result);
89
		setList(source, list);
90
		return result;
91
	}
92
93
	public boolean remove(Object source, Object o) {
94
		int i = indexOf(source, o);
95
		if (i == -1)
96
			return false;
97
		remove(source, i);
98
		return true;
99
	}
100
101
	public Object remove(Object source, int index) {
102
		List list = new ArrayList(getList(source));
103
		Object result = list.remove(index);
104
		setList(source, list);
105
		return result;
106
	}
107
108
	public boolean removeAll(Object source, Collection c) {
109
		if (isEmpty(source)) {
110
			return false;
111
		}
112
		if (c.isEmpty()) {
113
			return false;
114
		}
115
		List list = new ArrayList(getList(source));
116
		boolean changed = false;
117
		for (ListIterator it = list.listIterator(); it.hasNext();) {
118
			Object o = it.next();
119
			if (c.contains(o)) {
120
				it.remove();
121
				changed = true;
122
			}
123
		}
124
		if (changed) {
125
			setList(source, list);
126
		}
127
		return changed;
128
	}
129
130
	public boolean retainAll(Object source, Collection c) {
131
		if (isEmpty(source)) {
132
			return false;
133
		}
134
		if (c.isEmpty()) {
135
			clear(source);
136
			return true;
137
		}
138
		List list = new ArrayList(getList(source));
139
		boolean changed = false;
140
		for (ListIterator it = list.listIterator(); it.hasNext();) {
141
			Object o = it.next();
142
			if (!c.contains(o)) {
143
				it.remove();
144
				changed = true;
145
			}
146
		}
147
		if (changed) {
148
			setList(source, list);
149
		}
150
		return changed;
151
	}
152
153
	public Object set(Object source, int index, Object element) {
154
		List list = new ArrayList(getList(source));
155
		Object result = list.set(index, element);
156
		setList(source, list);
157
		return result;
158
	}
159
}
(-)src/org/eclipse/core/internal/databinding/property/masterdetail/ValuePropertyDetailValue.java (+156 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.property.masterdetail;
13
14
import java.util.HashMap;
15
import java.util.Map;
16
17
import org.eclipse.core.databinding.observable.Diffs;
18
import org.eclipse.core.databinding.observable.value.ValueDiff;
19
import org.eclipse.core.databinding.property.IPropertyChangeListener;
20
import org.eclipse.core.databinding.property.IValueProperty;
21
import org.eclipse.core.databinding.property.IValuePropertyChangeListener;
22
import org.eclipse.core.databinding.property.ValueProperty;
23
import org.eclipse.core.databinding.property.ValuePropertyChangeEvent;
24
25
/**
26
 * @since 1.2
27
 * 
28
 */
29
public class ValuePropertyDetailValue extends ValueProperty implements
30
		IValueProperty {
31
	private IValueProperty masterProperty;
32
	private IValueProperty detailProperty;
33
34
	/**
35
	 * @param masterProperty
36
	 * @param detailProperty
37
	 */
38
	public ValuePropertyDetailValue(IValueProperty masterProperty,
39
			IValueProperty detailProperty) {
40
		this.masterProperty = masterProperty;
41
		this.detailProperty = detailProperty;
42
	}
43
44
	public Object getValueType() {
45
		return detailProperty.getValueType();
46
	}
47
48
	public Object getValue(Object source) {
49
		Object masterValue = masterProperty.getValue(source);
50
		return detailProperty.getValue(masterValue);
51
	}
52
53
	public void setValue(Object source, Object value) {
54
		Object masterValue = masterProperty.getValue(source);
55
		detailProperty.setValue(masterValue, value);
56
	}
57
58
	public IPropertyChangeListener adaptListener(
59
			IValuePropertyChangeListener listener) {
60
		return new ListenerAdaptor(listener);
61
	}
62
63
	public void addPropertyChangeListener(Object source,
64
			IPropertyChangeListener listener) {
65
		((ListenerAdaptor) listener).addListenerTo(source);
66
	}
67
68
	public void removePropertyChangeListener(Object source,
69
			IPropertyChangeListener listener) {
70
		((ListenerAdaptor) listener).removeListenerFrom(source);
71
	}
72
73
	private class ListenerAdaptor implements IPropertyChangeListener {
74
		private final IValuePropertyChangeListener wrapped;
75
76
		private IPropertyChangeListener masterListener;
77
		private Map sourceToDetailListener = new HashMap();
78
79
		ListenerAdaptor(IValuePropertyChangeListener wrapped) {
80
			this.wrapped = wrapped;
81
82
			IValuePropertyChangeListener masterValueListener = new MasterValuePropertyListener();
83
			masterListener = masterProperty.adaptListener(masterValueListener);
84
		}
85
86
		private void fireValueChange(Object source, ValueDiff diff) {
87
			wrapped.handleValuePropertyChange(new ValuePropertyChangeEvent(
88
					source, ValuePropertyDetailValue.this, diff));
89
		}
90
91
		protected void addListenerTo(Object source) {
92
			masterProperty.addPropertyChangeListener(source, masterListener);
93
			addDetailPropertyListener(source);
94
		}
95
96
		protected void removeListenerFrom(Object source) {
97
			masterProperty.removePropertyChangeListener(source, masterListener);
98
			removeDetailPropertyListener(source);
99
		}
100
101
		private void addDetailPropertyListener(Object source) {
102
			Object masterValue = masterProperty.getValue(source);
103
			DetailValuePropertyListener detailListener = new DetailValuePropertyListener(
104
					source, masterValue);
105
			IPropertyChangeListener listener = detailListener.wrapper = detailProperty
106
					.adaptListener(detailListener);
107
			detailProperty.addPropertyChangeListener(masterValue, listener);
108
			sourceToDetailListener.put(source, detailListener);
109
		}
110
111
		private void removeDetailPropertyListener(Object source) {
112
			DetailValuePropertyListener detailListener = (DetailValuePropertyListener) sourceToDetailListener
113
					.remove(source);
114
			if (detailListener != null) {
115
				detailProperty.removePropertyChangeListener(
116
						detailListener.masterValue, detailListener.wrapper);
117
			}
118
		}
119
120
		private class MasterValuePropertyListener implements
121
				IValuePropertyChangeListener {
122
			public void handleValuePropertyChange(ValuePropertyChangeEvent event) {
123
				Object oldSource = event.diff.getOldValue();
124
				Object newSource = event.diff.getNewValue();
125
126
				Object oldValue = detailProperty.getValue(oldSource);
127
				Object newValue = detailProperty.getValue(newSource);
128
129
				ValueDiff diff = Diffs.createValueDiff(oldValue, newValue);
130
131
				Object source = event.getSource();
132
133
				removeDetailPropertyListener(source);
134
				addDetailPropertyListener(source);
135
136
				fireValueChange(source, diff);
137
			}
138
		}
139
140
		private class DetailValuePropertyListener implements
141
				IValuePropertyChangeListener {
142
			private Object source;
143
			private Object masterValue;
144
			private IPropertyChangeListener wrapper;
145
146
			DetailValuePropertyListener(Object source, Object masterValue) {
147
				this.source = source;
148
				this.masterValue = masterValue;
149
			}
150
151
			public void handleValuePropertyChange(ValuePropertyChangeEvent event) {
152
				fireValueChange(source, event.diff);
153
			}
154
		}
155
	}
156
}
(-)src/org/eclipse/core/internal/databinding/property/MapValuePropertyObservableMap.java (+326 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 (bug 194734)
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.IdentityHashMap;
18
import java.util.Iterator;
19
import java.util.Map;
20
import java.util.Set;
21
22
import org.eclipse.core.databinding.observable.Diffs;
23
import org.eclipse.core.databinding.observable.IObserving;
24
import org.eclipse.core.databinding.observable.IStaleListener;
25
import org.eclipse.core.databinding.observable.ObservableTracker;
26
import org.eclipse.core.databinding.observable.StaleEvent;
27
import org.eclipse.core.databinding.observable.map.AbstractObservableMap;
28
import org.eclipse.core.databinding.observable.map.IMapChangeListener;
29
import org.eclipse.core.databinding.observable.map.IObservableMap;
30
import org.eclipse.core.databinding.observable.map.MapChangeEvent;
31
import org.eclipse.core.databinding.property.IPropertyChangeListener;
32
import org.eclipse.core.databinding.property.IValueProperty;
33
import org.eclipse.core.databinding.property.IValuePropertyChangeListener;
34
import org.eclipse.core.databinding.property.ValuePropertyChangeEvent;
35
import org.eclipse.core.internal.databinding.Util;
36
37
/**
38
 * @since 3.3
39
 * 
40
 */
41
public class MapValuePropertyObservableMap extends AbstractObservableMap
42
		implements IObserving {
43
	private IObservableMap map;
44
	private IValueProperty property;
45
46
	private Map keyToMasterValueListener;
47
48
	private boolean updating = false;
49
	private boolean disposed = false;
50
51
	private IMapChangeListener mapListener = new IMapChangeListener() {
52
		public void handleMapChange(final MapChangeEvent event) {
53
			if (!updating && !disposed) {
54
				getRealm().exec(new Runnable() {
55
					public void run() {
56
						Map oldValues = new HashMap();
57
						Map newValues = new HashMap();
58
59
						Set addedKeys = event.diff.getAddedKeys();
60
						for (Iterator it = addedKeys.iterator(); it.hasNext();) {
61
							Object key = it.next();
62
							Object newSource = event.diff.getNewValue(key);
63
							Object newValue = property.getValue(newSource);
64
							newValues.put(key, newValue);
65
							addPropertySourceListener(key, newSource);
66
						}
67
68
						Set removedKeys = event.diff.getRemovedKeys();
69
						for (Iterator it = removedKeys.iterator(); it.hasNext();) {
70
							Object key = it.next();
71
							Object oldSource = event.diff.getOldValue(key);
72
							Object oldValue = property.getValue(oldSource);
73
							oldValues.put(key, oldValue);
74
							removePropertySourceListener(key, oldSource);
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
82
							Object oldSource = event.diff.getOldValue(key);
83
							Object newSource = event.diff.getNewValue(key);
84
85
							Object oldValue = property.getValue(oldSource);
86
							Object newValue = property.getValue(newSource);
87
88
							if (Util.equals(oldValue, newValue)) {
89
								it.remove();
90
							} else {
91
								oldValues.put(key, oldValue);
92
								newValues.put(key, newValue);
93
							}
94
95
							removePropertySourceListener(key, oldSource);
96
							addPropertySourceListener(key, newSource);
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.keyToMasterValueListener = new IdentityHashMap();
124
	}
125
126
	private class ValuePropertySourceChangeListener implements
127
			IValuePropertyChangeListener {
128
		private final Object key;
129
		private IPropertyChangeListener adaptor;
130
131
		public ValuePropertySourceChangeListener(Object key) {
132
			this.key = key;
133
		}
134
135
		public void handleValuePropertyChange(ValuePropertyChangeEvent event) {
136
			Object oldSource = event.diff.getOldValue();
137
			Object oldValue = property.getValue(oldSource);
138
			property.removePropertyChangeListener(oldSource, adaptor);
139
140
			Object newSource = event.diff.getNewValue();
141
			Object newValue = property.getValue(newSource);
142
			property.addPropertyChangeListener(newSource, adaptor);
143
144
			if (!Util.equals(oldValue, newValue))
145
				fireMapChange(Diffs.createMapDiffSingleChange(key, oldValue,
146
						newValue));
147
		}
148
	}
149
150
	protected void firstListenerAdded() {
151
		if (!disposed) {
152
			map.addMapChangeListener(mapListener);
153
			map.addStaleListener(staleListener);
154
			for (Iterator iterator = map.entrySet().iterator(); iterator
155
					.hasNext();) {
156
				Map.Entry entry = (Map.Entry) iterator.next();
157
				Object key = entry.getKey();
158
				Object masterValue = entry.getValue();
159
160
				addPropertySourceListener(key, masterValue);
161
			}
162
		}
163
	}
164
165
	protected void lastListenerRemoved() {
166
		if (!disposed) {
167
			map.removeMapChangeListener(mapListener);
168
			map.removeStaleListener(staleListener);
169
			for (Iterator iterator = map.entrySet().iterator(); iterator
170
					.hasNext();) {
171
				Map.Entry entry = (Map.Entry) iterator.next();
172
				Object key = entry.getKey();
173
				Object propertySource = entry.getValue();
174
175
				removePropertySourceListener(key, propertySource);
176
			}
177
		}
178
	}
179
180
	private void addPropertySourceListener(Object key, Object propertySource) {
181
		ValuePropertySourceChangeListener valueListener = new ValuePropertySourceChangeListener(
182
				key);
183
		IPropertyChangeListener listener = valueListener.adaptor = property
184
				.adaptListener(valueListener);
185
		property.addPropertyChangeListener(propertySource, listener);
186
		keyToMasterValueListener.put(key, listener);
187
	}
188
189
	private void removePropertySourceListener(Object key, Object propertySource) {
190
		IPropertyChangeListener listener = (IPropertyChangeListener) keyToMasterValueListener
191
				.remove(key);
192
		if (listener != null) {
193
			property.removePropertyChangeListener(propertySource, listener);
194
		}
195
	}
196
197
	protected Object doGet(Object key) {
198
		if (!map.containsKey(key))
199
			return null;
200
		return property.getValue(map.get(key));
201
	}
202
203
	protected Object doPut(Object key, Object value) {
204
		if (!map.containsKey(key))
205
			return null;
206
		Object source = map.get(key);
207
208
		Object oldValue = property.getValue(source);
209
210
		updating = true;
211
		try {
212
			property.setValue(source, value);
213
		} finally {
214
			updating = false;
215
		}
216
217
		Object newValue = property.getValue(source);
218
219
		if (!Util.equals(oldValue, newValue)) {
220
			fireMapChange(Diffs.createMapDiffSingleChange(key, oldValue,
221
					newValue));
222
		}
223
224
		return oldValue;
225
	}
226
227
	private Set entrySet;
228
229
	public Set entrySet() {
230
		getterCalled();
231
		if (entrySet == null)
232
			entrySet = new EntrySet();
233
		return entrySet;
234
	}
235
236
	class EntrySet extends AbstractSet {
237
		public Iterator iterator() {
238
			return new Iterator() {
239
				Iterator it = map.entrySet().iterator();
240
241
				public boolean hasNext() {
242
					getterCalled();
243
					return it.hasNext();
244
				}
245
246
				public Object next() {
247
					getterCalled();
248
					Map.Entry next = (Map.Entry) it.next();
249
					return new MapEntry(next.getKey());
250
				}
251
252
				public void remove() {
253
					it.remove();
254
				}
255
			};
256
		}
257
258
		public int size() {
259
			return map.size();
260
		}
261
	}
262
263
	class MapEntry implements Map.Entry {
264
		private Object key;
265
266
		MapEntry(Object key) {
267
			this.key = key;
268
		}
269
270
		public Object getKey() {
271
			getterCalled();
272
			return key;
273
		}
274
275
		public Object getValue() {
276
			getterCalled();
277
			return get(key);
278
		}
279
280
		public Object setValue(Object value) {
281
			return put(key, value);
282
		}
283
284
		public boolean equals(Object o) {
285
			getterCalled();
286
			if (o == this)
287
				return true;
288
			if (o == null)
289
				return false;
290
			if (!(o instanceof Map.Entry))
291
				return false;
292
			Map.Entry that = (Map.Entry) o;
293
			return Util.equals(this.getKey(), that.getKey())
294
					&& Util.equals(this.getValue(), that.getValue());
295
		}
296
297
		public int hashCode() {
298
			getterCalled();
299
			Object value = getValue();
300
			return (key == null ? 0 : key.hashCode())
301
					^ (value == null ? 0 : value.hashCode());
302
		}
303
	}
304
305
	public boolean isStale() {
306
		getterCalled();
307
		return map.isStale();
308
	}
309
310
	private void getterCalled() {
311
		ObservableTracker.getterCalled(this);
312
	}
313
314
	public Object getObserved() {
315
		return map;
316
	}
317
318
	public synchronized void dispose() {
319
		if (!disposed) {
320
			disposed = true;
321
			property = null;
322
		}
323
324
		super.dispose();
325
	}
326
}
(-)src/org/eclipse/core/internal/databinding/property/masterdetail/SetPropertyDetailValueMap.java (+263 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.property.masterdetail;
13
14
import java.util.Collections;
15
import java.util.HashMap;
16
import java.util.Iterator;
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.map.MapDiff;
22
import org.eclipse.core.databinding.property.IMapPropertyChangeListener;
23
import org.eclipse.core.databinding.property.IPropertyChangeListener;
24
import org.eclipse.core.databinding.property.ISetProperty;
25
import org.eclipse.core.databinding.property.ISetPropertyChangeListener;
26
import org.eclipse.core.databinding.property.IValueProperty;
27
import org.eclipse.core.databinding.property.IValuePropertyChangeListener;
28
import org.eclipse.core.databinding.property.MapProperty;
29
import org.eclipse.core.databinding.property.MapPropertyChangeEvent;
30
import org.eclipse.core.databinding.property.SetPropertyChangeEvent;
31
import org.eclipse.core.databinding.property.ValuePropertyChangeEvent;
32
33
/**
34
 * @since 3.3
35
 * 
36
 */
37
public class SetPropertyDetailValueMap extends MapProperty {
38
	private final ISetProperty masterProperty;
39
	private final IValueProperty detailProperty;
40
41
	/**
42
	 * @param masterProperty
43
	 * @param detailProperty
44
	 */
45
	public SetPropertyDetailValueMap(ISetProperty masterProperty,
46
			IValueProperty detailProperty) {
47
		this.masterProperty = masterProperty;
48
		this.detailProperty = detailProperty;
49
	}
50
51
	public Map getMap(Object source) {
52
		Map result = new HashMap();
53
		for (Iterator it = masterProperty.getSet(source).iterator(); it
54
				.hasNext();) {
55
			Object element = it.next();
56
			result.put(element, detailProperty.getValue(element));
57
		}
58
		return result;
59
	}
60
61
	public void clear(Object source) {
62
		throw new UnsupportedOperationException();
63
	}
64
65
	public Object put(Object source, Object key, Object value) {
66
		if (!masterProperty.contains(source, key))
67
			return null;
68
		Object result = detailProperty.getValue(key);
69
		detailProperty.setValue(key, value);
70
		return result;
71
	}
72
73
	public void putAll(Object source, Map t) {
74
		Set masterSet = masterProperty.getSet(source);
75
		for (Iterator it = t.entrySet().iterator(); it.hasNext();) {
76
			Map.Entry entry = (Map.Entry) it.next();
77
			if (masterSet.contains(entry.getKey())) {
78
				detailProperty.setValue(entry.getKey(), entry.getValue());
79
			}
80
		}
81
	}
82
83
	public Object remove(Object source, Object key) {
84
		throw new UnsupportedOperationException();
85
	}
86
87
	public IPropertyChangeListener adaptListener(
88
			IMapPropertyChangeListener listener) {
89
		return new ListenerAdaptor(listener);
90
	}
91
92
	public void addPropertyChangeListener(Object source,
93
			IPropertyChangeListener listener) {
94
		((ListenerAdaptor) listener).addListenerTo(source);
95
	}
96
97
	public void removePropertyChangeListener(Object source,
98
			IPropertyChangeListener listener) {
99
		((ListenerAdaptor) listener).removeListenerFrom(source);
100
	}
101
102
	private class ListenerAdaptor implements IPropertyChangeListener {
103
		private final IMapPropertyChangeListener wrapped;
104
105
		private IPropertyChangeListener masterListener;
106
		private Map sourceToMasterElementToDetailListener = new HashMap();
107
108
		ListenerAdaptor(IMapPropertyChangeListener wrapped) {
109
			this.wrapped = wrapped;
110
111
			ISetPropertyChangeListener masterSetListener = new MasterSetPropertyListener();
112
			masterListener = masterProperty.adaptListener(masterSetListener);
113
		}
114
115
		private void fireMapChange(Object source, MapDiff diff) {
116
			wrapped.handleMapPropertyChange(new MapPropertyChangeEvent(source,
117
					SetPropertyDetailValueMap.this, diff));
118
		}
119
120
		protected void addListenerTo(Object source) {
121
			masterProperty.addPropertyChangeListener(source, masterListener);
122
123
			Map masterElementToDetailListener = new HashMap();
124
			for (Iterator it = masterProperty.getSet(source).iterator(); it
125
					.hasNext();) {
126
				Object masterElement = it.next();
127
				DetailPropertyListener detailListener = new DetailPropertyListener(
128
						source, masterElement);
129
				IPropertyChangeListener listener = detailListener.wrapper = detailProperty
130
						.adaptListener(detailListener);
131
				detailProperty.addPropertyChangeListener(masterElement,
132
						listener);
133
				masterElementToDetailListener
134
						.put(masterElement, detailListener);
135
			}
136
137
			sourceToMasterElementToDetailListener.put(source,
138
					masterElementToDetailListener);
139
		}
140
141
		protected void removeListenerFrom(Object source) {
142
			masterProperty.removePropertyChangeListener(source, masterListener);
143
			Map masterElementToDetailListener = (Map) sourceToMasterElementToDetailListener
144
					.remove(source);
145
			if (masterElementToDetailListener != null) {
146
				for (Iterator it = masterElementToDetailListener.entrySet()
147
						.iterator(); it.hasNext();) {
148
					Map.Entry entry = (Map.Entry) it.next();
149
					detailProperty
150
							.removePropertyChangeListener(
151
									entry.getKey(),
152
									((DetailPropertyListener) entry.getValue()).wrapper);
153
				}
154
			}
155
		}
156
157
		private class MasterSetPropertyListener implements
158
				ISetPropertyChangeListener {
159
			public void handleSetPropertyChange(
160
					final SetPropertyChangeEvent event) {
161
				Object source = event.getSource();
162
163
				MapDiff diff;
164
				if (event.diff == null) {
165
					diff = null;
166
				} else {
167
					final Set removals = event.diff.getRemovals();
168
					final Set additions = event.diff.getAdditions();
169
170
					diff = new MapDiff() {
171
						public Set getAddedKeys() {
172
							return additions;
173
						}
174
175
						public Set getChangedKeys() {
176
							return Collections.EMPTY_SET;
177
						}
178
179
						public Object getNewValue(Object key) {
180
							return getValue(key);
181
						}
182
183
						public Object getOldValue(Object key) {
184
							return getValue(key);
185
						}
186
187
						private Object getValue(Object key) {
188
							return detailProperty.getValue(key);
189
						}
190
191
						public Set getRemovedKeys() {
192
							return removals;
193
						}
194
					};
195
196
					for (Iterator it = removals.iterator(); it.hasNext();) {
197
						removeElementPropertyListener(source, it.next());
198
					}
199
					for (Iterator it = additions.iterator(); it.hasNext();) {
200
						addElementPropertyListener(source, it.next());
201
					}
202
				}
203
204
				fireMapChange(source, diff);
205
			}
206
207
			private void addElementPropertyListener(Object source,
208
					Object element) {
209
				Map elementToDetailListener = (Map) sourceToMasterElementToDetailListener
210
						.get(source);
211
				if (elementToDetailListener == null) {
212
					sourceToMasterElementToDetailListener.put(source,
213
							elementToDetailListener = new HashMap());
214
				}
215
				if (!elementToDetailListener.containsKey(element)) {
216
					DetailPropertyListener detailListener = new DetailPropertyListener(
217
							source, element);
218
					IPropertyChangeListener listener = detailListener.wrapper = detailProperty
219
							.adaptListener(detailListener);
220
					detailProperty.addPropertyChangeListener(element, listener);
221
					elementToDetailListener.put(element, detailListener);
222
				}
223
			}
224
225
			private void removeElementPropertyListener(Object source,
226
					Object element) {
227
				Map elementToDetailListener = (Map) sourceToMasterElementToDetailListener
228
						.get(source);
229
				if (elementToDetailListener != null
230
						&& elementToDetailListener.containsKey(element)) {
231
					DetailPropertyListener detailListener = (DetailPropertyListener) elementToDetailListener
232
							.remove(element);
233
					detailProperty.removePropertyChangeListener(element,
234
							detailListener.wrapper);
235
				}
236
			}
237
		}
238
239
		private class DetailPropertyListener implements
240
				IValuePropertyChangeListener {
241
			private Object source;
242
			private Object masterValue;
243
			private IPropertyChangeListener wrapper;
244
245
			DetailPropertyListener(Object source, Object masterValue) {
246
				this.source = source;
247
				this.masterValue = masterValue;
248
			}
249
250
			public void handleValuePropertyChange(ValuePropertyChangeEvent event) {
251
				MapDiff diff;
252
				if (event.diff == null) {
253
					diff = null;
254
				} else {
255
					diff = Diffs.createMapDiffSingleChange(masterValue,
256
							event.diff.getOldValue(), event.diff.getNewValue());
257
				}
258
				fireMapChange(source, diff);
259
			}
260
		}
261
262
	}
263
}
(-)src/org/eclipse/core/databinding/property/SetProperty.java (+33 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import java.util.Collection;
15
16
/**
17
 * Abstract implementation of ISetProperty
18
 * 
19
 * @since 1.2
20
 */
21
public abstract class SetProperty extends CollectionProperty implements
22
		ISetProperty {
23
	Collection getCollection(Object source) {
24
		return getSet(source);
25
	}
26
27
	 public final IPropertyChangeListener addSetChangeListener(Object source,
28
			ISetPropertyChangeListener listener) {
29
		IPropertyChangeListener l = adaptListener(listener);
30
		addPropertyChangeListener(source, l);
31
		return l;
32
	}
33
}
(-)src/org/eclipse/core/internal/databinding/property/masterdetail/ValuePropertyDetailList.java (+209 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.property.masterdetail;
13
14
import java.util.Collection;
15
import java.util.HashMap;
16
import java.util.List;
17
import java.util.Map;
18
19
import org.eclipse.core.databinding.observable.Diffs;
20
import org.eclipse.core.databinding.observable.list.ListDiff;
21
import org.eclipse.core.databinding.property.IListProperty;
22
import org.eclipse.core.databinding.property.IListPropertyChangeListener;
23
import org.eclipse.core.databinding.property.IPropertyChangeListener;
24
import org.eclipse.core.databinding.property.IValueProperty;
25
import org.eclipse.core.databinding.property.IValuePropertyChangeListener;
26
import org.eclipse.core.databinding.property.ListProperty;
27
import org.eclipse.core.databinding.property.ListPropertyChangeEvent;
28
import org.eclipse.core.databinding.property.ValuePropertyChangeEvent;
29
30
/**
31
 * @since 3.3
32
 * 
33
 */
34
public class ValuePropertyDetailList extends ListProperty {
35
	private final IValueProperty masterProperty;
36
	private final IListProperty detailProperty;
37
38
	/**
39
	 * @param masterProperty
40
	 * @param detailProperty
41
	 */
42
	public ValuePropertyDetailList(IValueProperty masterProperty,
43
			IListProperty detailProperty) {
44
		this.masterProperty = masterProperty;
45
		this.detailProperty = detailProperty;
46
	}
47
48
	public List getList(Object source) {
49
		Object masterValue = masterProperty.getValue(source);
50
		return detailProperty.getList(masterValue);
51
	}
52
53
	public boolean add(Object source, Object o) {
54
		Object masterValue = masterProperty.getValue(source);
55
		return detailProperty.add(masterValue, o);
56
	}
57
58
	public boolean addAll(Object source, Collection c) {
59
		Object masterValue = masterProperty.getValue(source);
60
		return detailProperty.addAll(masterValue, c);
61
	}
62
63
	public void clear(Object source) {
64
		Object masterValue = masterProperty.getValue(source);
65
		detailProperty.clear(masterValue);
66
	}
67
68
	public Object getElementType() {
69
		return detailProperty.getElementType();
70
	}
71
72
	public boolean remove(Object source, Object o) {
73
		Object masterValue = masterProperty.getValue(source);
74
		return detailProperty.remove(masterValue, o);
75
	}
76
77
	public boolean removeAll(Object source, Collection c) {
78
		Object masterValue = masterProperty.getValue(source);
79
		return detailProperty.removeAll(masterValue, c);
80
	}
81
82
	public boolean retainAll(Object source, Collection c) {
83
		Object masterValue = masterProperty.getValue(source);
84
		return detailProperty.retainAll(masterValue, c);
85
	}
86
87
	public void add(Object source, int index, Object element) {
88
		Object masterValue = masterProperty.getValue(source);
89
		detailProperty.add(masterValue, index, element);
90
	}
91
92
	public boolean addAll(Object source, int index, Collection c) {
93
		Object masterValue = masterProperty.getValue(source);
94
		return detailProperty.addAll(masterValue, index, c);
95
	}
96
97
	public Object move(Object source, int oldIndex, int newIndex) {
98
		Object masterValue = masterProperty.getValue(source);
99
		return detailProperty.move(masterValue, oldIndex, newIndex);
100
	}
101
102
	public Object remove(Object source, int index) {
103
		Object masterValue = masterProperty.getValue(source);
104
		return detailProperty.remove(masterValue, index);
105
	}
106
107
	public Object set(Object source, int index, Object element) {
108
		Object masterValue = masterProperty.getValue(source);
109
		return detailProperty.set(masterValue, index, element);
110
	}
111
112
	public IPropertyChangeListener adaptListener(
113
			IListPropertyChangeListener listener) {
114
		return new ListenerAdaptor(listener);
115
	}
116
117
	public void addPropertyChangeListener(Object source,
118
			IPropertyChangeListener listener) {
119
		((ListenerAdaptor) listener).addListenerTo(source);
120
	}
121
122
	public void removePropertyChangeListener(Object source,
123
			IPropertyChangeListener listener) {
124
		((ListenerAdaptor) listener).removeListenerFrom(source);
125
	}
126
127
	private class ListenerAdaptor implements IPropertyChangeListener {
128
		private final IListPropertyChangeListener wrapped;
129
130
		private IPropertyChangeListener masterListener;
131
		private Map sourceToDetailListener = new HashMap();
132
133
		ListenerAdaptor(IListPropertyChangeListener wrapped) {
134
			this.wrapped = wrapped;
135
136
			IValuePropertyChangeListener masterValueListener = new MasterPropertyListener();
137
			masterListener = masterProperty.adaptListener(masterValueListener);
138
		}
139
140
		private void fireListChange(Object source, ListDiff diff) {
141
			wrapped.handleListPropertyChange(new ListPropertyChangeEvent(
142
					source, ValuePropertyDetailList.this, diff));
143
		}
144
145
		protected void addListenerTo(Object source) {
146
			masterProperty.addPropertyChangeListener(source, masterListener);
147
			addDetailPropertyListener(source);
148
		}
149
150
		protected void removeListenerFrom(Object source) {
151
			masterProperty.removePropertyChangeListener(source, masterListener);
152
			removeDetailPropertyListener(source);
153
		}
154
155
		private void addDetailPropertyListener(Object source) {
156
			Object masterValue = masterProperty.getValue(source);
157
			DetailPropertyListener detailListener = new DetailPropertyListener(
158
					source, masterValue);
159
			IPropertyChangeListener listener = detailListener.wrapper = detailProperty
160
					.adaptListener(detailListener);
161
			detailProperty.addPropertyChangeListener(masterValue, listener);
162
			sourceToDetailListener.put(source, detailListener);
163
		}
164
165
		private void removeDetailPropertyListener(Object source) {
166
			DetailPropertyListener detailListener = (DetailPropertyListener) sourceToDetailListener
167
					.remove(source);
168
			if (detailListener != null) {
169
				detailProperty.removePropertyChangeListener(
170
						detailListener.masterValue, detailListener.wrapper);
171
			}
172
			sourceToDetailListener.remove(source);
173
		}
174
175
		private class MasterPropertyListener implements
176
				IValuePropertyChangeListener {
177
			public void handleValuePropertyChange(ValuePropertyChangeEvent event) {
178
				Object oldSource = event.diff.getOldValue();
179
				Object newSource = event.diff.getNewValue();
180
181
				List oldList = detailProperty.getList(oldSource);
182
				List newList = detailProperty.getList(newSource);
183
184
				Object source = event.getSource();
185
186
				removeDetailPropertyListener(source);
187
				addDetailPropertyListener(source);
188
189
				fireListChange(source, Diffs.computeListDiff(oldList, newList));
190
			}
191
		}
192
193
		private class DetailPropertyListener implements
194
				IListPropertyChangeListener {
195
			private Object source;
196
			private Object masterValue;
197
			private IPropertyChangeListener wrapper;
198
199
			DetailPropertyListener(Object source, Object masterValue) {
200
				this.source = source;
201
				this.masterValue = masterValue;
202
			}
203
204
			public void handleListPropertyChange(ListPropertyChangeEvent event) {
205
				fireListChange(source, event.diff);
206
			}
207
		}
208
	}
209
}
(-)src/org/eclipse/core/databinding/property/IProperty.java (+44 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
/**
15
 * Interface for observing a property of a source object.
16
 * 
17
 * @since 1.2
18
 * @noimplement This interface is not intended to be implemented by clients.
19
 */
20
public interface IProperty {
21
	/**
22
	 * Adds the given property change listener to the list of listeners for the
23
	 * given source.
24
	 * 
25
	 * @param source
26
	 *            the property source
27
	 * @param listener
28
	 *            the listener
29
	 */
30
	public void addPropertyChangeListener(Object source,
31
			IPropertyChangeListener listener);
32
33
	/**
34
	 * Removes the given property change listener from the list of listeners for
35
	 * the given source.
36
	 * 
37
	 * @param source
38
	 *            the property source
39
	 * @param listener
40
	 *            the listener
41
	 */
42
	public void removePropertyChangeListener(Object source,
43
			IPropertyChangeListener listener);
44
}
(-)src/org/eclipse/core/internal/databinding/property/masterdetail/ListPropertyDetailValueList.java (+303 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.property.masterdetail;
13
14
import java.util.ArrayList;
15
import java.util.Collection;
16
import java.util.HashMap;
17
import java.util.HashSet;
18
import java.util.Iterator;
19
import java.util.List;
20
import java.util.ListIterator;
21
import java.util.Map;
22
import java.util.Set;
23
24
import org.eclipse.core.databinding.observable.Diffs;
25
import org.eclipse.core.databinding.observable.list.ListDiff;
26
import org.eclipse.core.databinding.observable.list.ListDiffEntry;
27
import org.eclipse.core.databinding.property.IListProperty;
28
import org.eclipse.core.databinding.property.IListPropertyChangeListener;
29
import org.eclipse.core.databinding.property.IPropertyChangeListener;
30
import org.eclipse.core.databinding.property.IValueProperty;
31
import org.eclipse.core.databinding.property.IValuePropertyChangeListener;
32
import org.eclipse.core.databinding.property.ListProperty;
33
import org.eclipse.core.databinding.property.ListPropertyChangeEvent;
34
import org.eclipse.core.databinding.property.ValuePropertyChangeEvent;
35
import org.eclipse.core.internal.databinding.Util;
36
37
/**
38
 * @since 3.3
39
 * 
40
 */
41
public class ListPropertyDetailValueList extends ListProperty {
42
	private final IListProperty masterProperty;
43
	private final IValueProperty detailProperty;
44
45
	/**
46
	 * @param masterProperty
47
	 * @param detailProperty
48
	 */
49
	public ListPropertyDetailValueList(IListProperty masterProperty,
50
			IValueProperty detailProperty) {
51
		this.masterProperty = masterProperty;
52
		this.detailProperty = detailProperty;
53
	}
54
55
	public List getList(Object source) {
56
		List result = new ArrayList();
57
		for (Iterator it = masterProperty.getList(source).iterator(); it
58
				.hasNext();) {
59
			result.add(detailProperty.getValue(it.next()));
60
		}
61
		return result;
62
	}
63
64
	public boolean add(Object source, Object o) {
65
		throw new UnsupportedOperationException();
66
	}
67
68
	public boolean addAll(Object source, Collection c) {
69
		throw new UnsupportedOperationException();
70
	}
71
72
	public void clear(Object source) {
73
		throw new UnsupportedOperationException();
74
	}
75
76
	public Object getElementType() {
77
		return detailProperty.getValueType();
78
	}
79
80
	public boolean remove(Object source, Object o) {
81
		throw new UnsupportedOperationException();
82
	}
83
84
	public boolean removeAll(Object source, Collection c) {
85
		throw new UnsupportedOperationException();
86
	}
87
88
	public boolean retainAll(Object source, Collection c) {
89
		throw new UnsupportedOperationException();
90
	}
91
92
	public void add(Object source, int index, Object element) {
93
		throw new UnsupportedOperationException();
94
	}
95
96
	public boolean addAll(Object source, int index, Collection c) {
97
		throw new UnsupportedOperationException();
98
	}
99
100
	public Object move(Object source, int oldIndex, int newIndex) {
101
		throw new UnsupportedOperationException();
102
	}
103
104
	public Object remove(Object source, int index) {
105
		throw new UnsupportedOperationException();
106
	}
107
108
	public Object set(Object source, int index, Object element) {
109
		Object masterElement = masterProperty.get(source, index);
110
		Object result = detailProperty.getValue(masterElement);
111
		detailProperty.setValue(masterElement, element);
112
		return result;
113
	}
114
115
	public IPropertyChangeListener adaptListener(
116
			IListPropertyChangeListener listener) {
117
		return new ListenerAdaptor(listener);
118
	}
119
120
	public void addPropertyChangeListener(Object source,
121
			IPropertyChangeListener listener) {
122
		((ListenerAdaptor) listener).addListenerTo(source);
123
	}
124
125
	public void removePropertyChangeListener(Object source,
126
			IPropertyChangeListener listener) {
127
		((ListenerAdaptor) listener).removeListenerFrom(source);
128
	}
129
130
	private class ListenerAdaptor implements IPropertyChangeListener {
131
		private final IListPropertyChangeListener wrapped;
132
133
		private IPropertyChangeListener masterListener;
134
		private Map sourceToMasterElementToDetailListener = new HashMap();
135
136
		ListenerAdaptor(IListPropertyChangeListener wrapped) {
137
			this.wrapped = wrapped;
138
139
			IListPropertyChangeListener masterListListener = new MasterListPropertyListener();
140
			masterListener = masterProperty.adaptListener(masterListListener);
141
		}
142
143
		private void fireListChange(Object source, ListDiff diff) {
144
			wrapped.handleListPropertyChange(new ListPropertyChangeEvent(
145
					source, ListPropertyDetailValueList.this, diff));
146
		}
147
148
		protected void addListenerTo(Object source) {
149
			masterProperty.addPropertyChangeListener(source, masterListener);
150
151
			Map masterElementToDetailListener = new HashMap();
152
			for (Iterator it = masterProperty.getList(source).iterator(); it
153
					.hasNext();) {
154
				Object masterElement = it.next();
155
				DetailValuePropertyListener detailListener = new DetailValuePropertyListener(
156
						source, masterElement);
157
				IPropertyChangeListener listener = detailListener.wrapper = detailProperty
158
						.adaptListener(detailListener);
159
				detailProperty.addPropertyChangeListener(masterElement,
160
						listener);
161
				masterElementToDetailListener
162
						.put(masterElement, detailListener);
163
			}
164
165
			sourceToMasterElementToDetailListener.put(source,
166
					masterElementToDetailListener);
167
		}
168
169
		protected void removeListenerFrom(Object source) {
170
			masterProperty.removePropertyChangeListener(source, masterListener);
171
			Map masterElementToDetailListener = (Map) sourceToMasterElementToDetailListener
172
					.remove(source);
173
			if (masterElementToDetailListener != null) {
174
				for (Iterator it = masterElementToDetailListener.entrySet()
175
						.iterator(); it.hasNext();) {
176
					Map.Entry entry = (Map.Entry) it.next();
177
					detailProperty
178
							.removePropertyChangeListener(entry.getKey(),
179
									((DetailValuePropertyListener) entry
180
											.getValue()).wrapper);
181
				}
182
			}
183
		}
184
185
		private class MasterListPropertyListener implements
186
				IListPropertyChangeListener {
187
			public void handleListPropertyChange(ListPropertyChangeEvent event) {
188
				Object source = event.getSource();
189
				ListDiffEntry[] masterEntries = event.diff.getDifferences();
190
				ListDiffEntry[] detailEntries = new ListDiffEntry[masterEntries.length];
191
				Set masterElementsAdded = new HashSet();
192
				Set masterElementsRemoved = new HashSet();
193
				for (int i = 0; i < masterEntries.length; i++) {
194
					ListDiffEntry masterDifference = masterEntries[i];
195
					int index = masterDifference.getPosition();
196
					boolean addition = masterDifference.isAddition();
197
					Object masterElement = masterDifference.getElement();
198
					Object elementDetailValue = detailProperty
199
							.getValue(masterElement);
200
					detailEntries[i] = Diffs.createListDiffEntry(index,
201
							addition, elementDetailValue);
202
					if (addition)
203
						masterElementsAdded.add(masterElement);
204
					else
205
						masterElementsRemoved.add(masterElement);
206
				}
207
208
				ListDiff diff = Diffs.createListDiff(detailEntries);
209
210
				for (Iterator it = masterElementsRemoved.iterator(); it
211
						.hasNext();) {
212
					Object element = it.next();
213
					if (!masterProperty.contains(source, element))
214
						removeElementPropertyListener(source, element);
215
				}
216
				for (Iterator it = masterElementsAdded.iterator(); it.hasNext();) {
217
					Object element = it.next();
218
					if (masterProperty.contains(source, element))
219
						addElementPropertyListener(source, element);
220
				}
221
222
				fireListChange(source, diff);
223
			}
224
225
			private void addElementPropertyListener(Object source,
226
					Object element) {
227
				Map elementToDetailListener = (Map) sourceToMasterElementToDetailListener
228
						.get(source);
229
				if (elementToDetailListener == null) {
230
					sourceToMasterElementToDetailListener.put(source,
231
							elementToDetailListener = new HashMap());
232
				}
233
				if (!elementToDetailListener.containsKey(element)) {
234
					DetailValuePropertyListener detailListener = new DetailValuePropertyListener(
235
							source, element);
236
					IPropertyChangeListener listener = detailListener.wrapper = detailProperty
237
							.adaptListener(detailListener);
238
					detailProperty.addPropertyChangeListener(element, listener);
239
					elementToDetailListener.put(element, detailListener);
240
				}
241
			}
242
243
			private void removeElementPropertyListener(Object source,
244
					Object element) {
245
				Map elementToDetailListener = (Map) sourceToMasterElementToDetailListener
246
						.get(source);
247
				if (elementToDetailListener != null
248
						&& elementToDetailListener.containsKey(element)) {
249
					DetailValuePropertyListener detailListener = (DetailValuePropertyListener) elementToDetailListener
250
							.remove(element);
251
					detailProperty.removePropertyChangeListener(element,
252
							detailListener.wrapper);
253
				}
254
			}
255
		}
256
257
		private class DetailValuePropertyListener implements
258
				IValuePropertyChangeListener {
259
			private Object source;
260
			private Object masterElement;
261
			private IPropertyChangeListener wrapper;
262
263
			DetailValuePropertyListener(Object source, Object masterElement) {
264
				this.source = source;
265
				this.masterElement = masterElement;
266
			}
267
268
			private int[] findIndices() {
269
				List indices = new ArrayList();
270
271
				List list = masterProperty.getList(source);
272
				for (ListIterator it = list.listIterator(); it.hasNext();) {
273
					if (Util.equals(masterElement, it.next()))
274
						indices.add(new Integer(it.previousIndex()));
275
				}
276
277
				int[] result = new int[indices.size()];
278
				for (int i = 0; i < result.length; i++) {
279
					result[i] = ((Integer) indices.get(i)).intValue();
280
				}
281
				return result;
282
			}
283
284
			public void handleValuePropertyChange(ValuePropertyChangeEvent event) {
285
				int[] indices = findIndices();
286
				Object oldValue = event.diff.getOldValue();
287
				Object newValue = event.diff.getNewValue();
288
				ListDiffEntry[] entries = new ListDiffEntry[indices.length * 2];
289
				for (int i = 0; i < indices.length; i++) {
290
					int index = indices[i];
291
					entries[i * 2] = Diffs.createListDiffEntry(index, false,
292
							oldValue);
293
					entries[i * 2 + 1] = Diffs.createListDiffEntry(index, true,
294
							newValue);
295
				}
296
297
				ListDiff diff = Diffs.createListDiff(entries);
298
				fireListChange(source, diff);
299
			}
300
		}
301
302
	}
303
}
(-)src/org/eclipse/core/databinding/property/IPropertyObservable.java (+28 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.IObserving;
15
16
/**
17
 * Provides access to the details of property observables
18
 * 
19
 * @since 1.2
20
 */
21
public interface IPropertyObservable extends IObserving {
22
	/**
23
	 * Returns the property being observed
24
	 * 
25
	 * @return the property being observed
26
	 */
27
	IProperty getProperty();
28
}
(-)src/org/eclipse/core/internal/databinding/property/masterdetail/ValuePropertyDetailMap.java (+170 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.property.masterdetail;
13
14
import java.util.HashMap;
15
import java.util.Map;
16
17
import org.eclipse.core.databinding.observable.Diffs;
18
import org.eclipse.core.databinding.observable.map.MapDiff;
19
import org.eclipse.core.databinding.property.IMapProperty;
20
import org.eclipse.core.databinding.property.IMapPropertyChangeListener;
21
import org.eclipse.core.databinding.property.IPropertyChangeListener;
22
import org.eclipse.core.databinding.property.IValueProperty;
23
import org.eclipse.core.databinding.property.IValuePropertyChangeListener;
24
import org.eclipse.core.databinding.property.MapProperty;
25
import org.eclipse.core.databinding.property.MapPropertyChangeEvent;
26
import org.eclipse.core.databinding.property.ValuePropertyChangeEvent;
27
28
/**
29
 * @since 3.3
30
 * 
31
 */
32
public class ValuePropertyDetailMap extends MapProperty {
33
	private final IValueProperty masterProperty;
34
	private final IMapProperty detailProperty;
35
36
	/**
37
	 * @param masterProperty
38
	 * @param detailProperty
39
	 */
40
	public ValuePropertyDetailMap(IValueProperty masterProperty,
41
			IMapProperty detailProperty) {
42
		this.masterProperty = masterProperty;
43
		this.detailProperty = detailProperty;
44
	}
45
46
	public Map getMap(Object source) {
47
		Object masterValue = masterProperty.getValue(source);
48
		return detailProperty.getMap(masterValue);
49
	}
50
51
	public void clear(Object source) {
52
		Object masterValue = masterProperty.getValue(source);
53
		detailProperty.clear(masterValue);
54
	}
55
56
	public Object put(Object source, Object key, Object value) {
57
		Object masterValue = masterProperty.getValue(source);
58
		return detailProperty.put(masterValue, key, value);
59
	}
60
61
	public void putAll(Object source, Map t) {
62
		Object masterValue = masterProperty.getValue(source);
63
		detailProperty.putAll(masterValue, t);
64
	}
65
66
	public Object remove(Object source, Object key) {
67
		Object masterValue = masterProperty.getValue(source);
68
		return detailProperty.remove(masterValue, key);
69
	}
70
71
	public IPropertyChangeListener adaptListener(
72
			IMapPropertyChangeListener listener) {
73
		return new ListenerAdaptor(listener);
74
	}
75
76
	public void addPropertyChangeListener(Object source,
77
			IPropertyChangeListener listener) {
78
		((ListenerAdaptor) listener).addListenerTo(source);
79
	}
80
81
	public void removePropertyChangeListener(Object source,
82
			IPropertyChangeListener listener) {
83
		((ListenerAdaptor) listener).removeListenerFrom(source);
84
	}
85
86
	private class ListenerAdaptor implements IPropertyChangeListener {
87
		private final IMapPropertyChangeListener wrapped;
88
89
		private IPropertyChangeListener masterListener;
90
		private Map sourceToDetailListener = new HashMap();
91
92
		ListenerAdaptor(IMapPropertyChangeListener wrapped) {
93
			this.wrapped = wrapped;
94
95
			IValuePropertyChangeListener masterValueListener = new MasterValueListener();
96
			masterListener = masterProperty.adaptListener(masterValueListener);
97
		}
98
99
		private void fireMapChange(Object source, MapDiff diff) {
100
			wrapped.handleMapPropertyChange(new MapPropertyChangeEvent(source,
101
					ValuePropertyDetailMap.this, diff));
102
		}
103
104
		protected void addListenerTo(Object source) {
105
			masterProperty.addPropertyChangeListener(source, masterListener);
106
			addDetailPropertyListener(source);
107
		}
108
109
		protected void removeListenerFrom(Object source) {
110
			masterProperty.removePropertyChangeListener(source, masterListener);
111
			removeDetailPropertyListener(source);
112
		}
113
114
		private void addDetailPropertyListener(Object source) {
115
			Object masterValue = masterProperty.getValue(source);
116
			DetailPropertyListener detailListener = new DetailPropertyListener(
117
					source, masterValue);
118
			IPropertyChangeListener listener = detailListener.wrapper = detailProperty
119
					.adaptListener(detailListener);
120
			detailProperty.addPropertyChangeListener(masterValue, listener);
121
			sourceToDetailListener.put(source, detailListener);
122
		}
123
124
		private void removeDetailPropertyListener(Object source) {
125
			DetailPropertyListener detailListener = (DetailPropertyListener) sourceToDetailListener
126
					.remove(source);
127
			if (detailListener != null) {
128
				detailProperty.removePropertyChangeListener(
129
						detailListener.masterValue, detailListener.wrapper);
130
			}
131
			sourceToDetailListener.remove(source);
132
		}
133
134
		private class MasterValueListener implements
135
				IValuePropertyChangeListener {
136
			public void handleValuePropertyChange(ValuePropertyChangeEvent event) {
137
				Object oldSource = event.diff.getOldValue();
138
				Object newSource = event.diff.getNewValue();
139
140
				Map oldMap = detailProperty.getMap(oldSource);
141
				Map newMap = detailProperty.getMap(newSource);
142
				MapDiff diff = Diffs.computeMapDiff(oldMap, newMap);
143
144
				Object source = event.getSource();
145
146
				removeDetailPropertyListener(source);
147
				addDetailPropertyListener(source);
148
149
				fireMapChange(source, diff);
150
			}
151
		}
152
153
		private class DetailPropertyListener implements
154
				IMapPropertyChangeListener {
155
			private Object source;
156
			private Object masterValue;
157
			private IPropertyChangeListener wrapper;
158
159
			DetailPropertyListener(Object source, Object masterValue) {
160
				this.source = source;
161
				this.masterValue = masterValue;
162
			}
163
164
			public void handleMapPropertyChange(MapPropertyChangeEvent event) {
165
				fireMapChange(source, event.diff);
166
			}
167
		}
168
169
	}
170
}
(-)src/org/eclipse/core/databinding/property/ISetPropertyChangeListener.java (+27 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
/**
15
 * Listener for changes to set properties on a property source
16
 * 
17
 * @since 1.2
18
 */
19
public interface ISetPropertyChangeListener {
20
	/**
21
	 * Handle a change to a set property on a specific property source.
22
	 * 
23
	 * @param event
24
	 *            an event describing the set change that occured.
25
	 */
26
	public void handleSetPropertyChange(SetPropertyChangeEvent event);
27
}
(-)src/org/eclipse/core/databinding/property/BasicSetProperty.java (+130 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.Collection;
15
import java.util.HashSet;
16
import java.util.Iterator;
17
import java.util.Set;
18
19
/**
20
 * Abstract set property implementation for properties where the set can be
21
 * completely replaced in a single atomic operation.
22
 * <p>
23
 * For example, a set-typed bean property Customer.addresses can be modified by
24
 * calling Customer.setAddresses(List addresses).
25
 * 
26
 * @since 1.2
27
 */
28
public abstract class BasicSetProperty extends SetProperty {
29
	/**
30
	 * Sets the set property on the source to the specified set.
31
	 * 
32
	 * @param source
33
	 *            the property source
34
	 * @param set
35
	 *            the new set
36
	 */
37
	protected abstract void setSet(Object source, Set set);
38
39
	public boolean add(Object source, Object o) {
40
		Set set = getSet(source);
41
		if (!set.contains(o)) {
42
			set = new HashSet(set);
43
			boolean added = set.add(o);
44
			if (added)
45
				setSet(source, set);
46
			return added;
47
		}
48
		return false;
49
	}
50
51
	public boolean addAll(Object source, Collection c) {
52
		if (c.isEmpty())
53
			return false;
54
55
		Set set = new HashSet(getSet(source));
56
		boolean changed = false;
57
		for (Iterator it = c.iterator(); it.hasNext();) {
58
			if (set.add(it.next())) {
59
				changed = true;
60
			}
61
		}
62
		if (changed) {
63
			setSet(source, set);
64
		}
65
		return changed;
66
	}
67
68
	public void clear(Object source) {
69
		if (!isEmpty(source))
70
			setSet(source, new HashSet());
71
	}
72
73
	public boolean remove(Object source, Object o) {
74
		Set set = getSet(source);
75
		if (!set.contains(o))
76
			return false;
77
78
		set = new HashSet(set);
79
		boolean removed = set.remove(o);
80
		if (removed) {
81
			setSet(source, set);
82
		}
83
		return removed;
84
	}
85
86
	public boolean removeAll(Object source, Collection c) {
87
		if (c.isEmpty())
88
			return false;
89
90
		Set set = new HashSet(getSet(source));
91
		boolean changed = false;
92
		for (Iterator it = set.iterator(); it.hasNext();) {
93
			Object o = it.next();
94
			if (c.contains(o)) {
95
				it.remove();
96
				changed = true;
97
			}
98
		}
99
		if (changed) {
100
			setSet(source, set);
101
		}
102
		return changed;
103
	}
104
105
	public boolean retainAll(Object source, Collection c) {
106
		Set set = getSet(source);
107
108
		if (set.isEmpty())
109
			return false;
110
111
		if (c.isEmpty()) {
112
			clear(source);
113
			return true;
114
		}
115
116
		set = new HashSet(set);
117
		boolean changed = false;
118
		for (Iterator it = set.iterator(); it.hasNext();) {
119
			Object o = it.next();
120
			if (!c.contains(o)) {
121
				it.remove();
122
				changed = true;
123
			}
124
		}
125
		if (changed) {
126
			setSet(source, set);
127
		}
128
		return changed;
129
	}
130
}
(-)src/org/eclipse/core/databinding/property/MapPropertyChangeEvent.java (+55 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import java.util.EventObject;
15
16
import org.eclipse.core.databinding.observable.map.MapDiff;
17
import org.eclipse.core.runtime.Assert;
18
19
/**
20
 * Map change event describing an incremental change of a map property on a
21
 * particular property source.
22
 * 
23
 * @since 1.2
24
 */
25
public class MapPropertyChangeEvent extends EventObject {
26
	private static final long serialVersionUID = 1L;
27
28
	/**
29
	 * The map property that changed
30
	 */
31
	public final IMapProperty property;
32
33
	/**
34
	 * MapDiff enumerating the added, changed, and removed entries in the map.
35
	 */
36
	public final MapDiff diff;
37
38
	/**
39
	 * Constructs a MapPropertyChangeEvent with the given attributes
40
	 * 
41
	 * @param source
42
	 *            the property source
43
	 * @param property
44
	 *            the property that changed on the source
45
	 * @param diff
46
	 *            a MapDiff describing the changes to the map property
47
	 */
48
	public MapPropertyChangeEvent(Object source, IMapProperty property,
49
			MapDiff diff) {
50
		super(source);
51
		this.property = property;
52
		Assert.isNotNull(diff, "diff cannot be null"); //$NON-NLS-1$
53
		this.diff = diff;
54
	}
55
}
(-)src/org/eclipse/core/databinding/property/ListPropertyChangeEvent.java (+55 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import java.util.EventObject;
15
16
import org.eclipse.core.databinding.observable.list.ListDiff;
17
import org.eclipse.core.runtime.Assert;
18
19
/**
20
 * List change event describing an incremental change of a list property on a
21
 * particular property source.
22
 * 
23
 * @since 1.2
24
 */
25
public class ListPropertyChangeEvent extends EventObject {
26
	private static final long serialVersionUID = 1L;
27
28
	/**
29
	 * The list property that changed
30
	 */
31
	public final IListProperty property;
32
33
	/**
34
	 * ListDiff enumerating the added and removed elements in the list.
35
	 */
36
	public final ListDiff diff;
37
38
	/**
39
	 * Constructs a ListPropertyChangeEvent with the given attributes
40
	 * 
41
	 * @param source
42
	 *            the property source
43
	 * @param property
44
	 *            the property that changed on the source
45
	 * @param diff
46
	 *            a ListDiff describing the changes to the list property
47
	 */
48
	public ListPropertyChangeEvent(Object source, IListProperty property,
49
			ListDiff diff) {
50
		super(source);
51
		this.property = property;
52
		Assert.isNotNull(diff, "diff cannot be null"); //$NON-NLS-1$
53
		this.diff = diff;
54
	}
55
}
(-)src/org/eclipse/core/internal/databinding/property/masterdetail/MapPropertyDetailValueMap.java (+268 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.property.masterdetail;
13
14
import java.util.HashMap;
15
import java.util.HashSet;
16
import java.util.Iterator;
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.map.MapDiff;
22
import org.eclipse.core.databinding.property.IMapProperty;
23
import org.eclipse.core.databinding.property.IMapPropertyChangeListener;
24
import org.eclipse.core.databinding.property.IPropertyChangeListener;
25
import org.eclipse.core.databinding.property.IValueProperty;
26
import org.eclipse.core.databinding.property.IValuePropertyChangeListener;
27
import org.eclipse.core.databinding.property.MapProperty;
28
import org.eclipse.core.databinding.property.MapPropertyChangeEvent;
29
import org.eclipse.core.databinding.property.ValuePropertyChangeEvent;
30
import org.eclipse.core.internal.databinding.Util;
31
32
/**
33
 * @since 3.3
34
 * 
35
 */
36
public class MapPropertyDetailValueMap extends MapProperty {
37
	private final IMapProperty masterProperty;
38
	private final IValueProperty detailProperty;
39
40
	/**
41
	 * @param masterProperty
42
	 * @param detailProperty
43
	 */
44
	public MapPropertyDetailValueMap(IMapProperty masterProperty,
45
			IValueProperty detailProperty) {
46
		this.masterProperty = masterProperty;
47
		this.detailProperty = detailProperty;
48
	}
49
50
	public Map getMap(Object source) {
51
		Map result = new HashMap();
52
		for (Iterator it = masterProperty.getMap(source).entrySet().iterator(); it
53
				.hasNext();) {
54
			Map.Entry entry = (Map.Entry) it.next();
55
			result.put(entry.getKey(), detailProperty
56
					.getValue(entry.getValue()));
57
		}
58
		return result;
59
	}
60
61
	public void clear(Object source) {
62
		throw new UnsupportedOperationException();
63
	}
64
65
	public Object put(Object source, Object key, Object value) {
66
		if (!masterProperty.containsKey(source, key))
67
			return null;
68
		Object masterValue = masterProperty.get(source, key);
69
70
		Object result = detailProperty.getValue(masterValue);
71
		detailProperty.setValue(masterValue, value);
72
		return result;
73
	}
74
75
	public void putAll(Object source, Map t) {
76
		for (Iterator it = t.entrySet().iterator(); it.hasNext();) {
77
			Map.Entry entry = (Map.Entry) it.next();
78
			Object masterKey = entry.getKey();
79
			Object detailValue = entry.getValue();
80
			if (masterProperty.getMap(source).containsKey(masterKey)) {
81
				detailProperty.setValue(masterKey, detailValue);
82
			}
83
		}
84
	}
85
86
	public Object remove(Object source, Object key) {
87
		throw new UnsupportedOperationException();
88
	}
89
90
	public IPropertyChangeListener adaptListener(
91
			IMapPropertyChangeListener listener) {
92
		return new ListenerAdaptor(listener);
93
	}
94
95
	public void addPropertyChangeListener(Object source,
96
			IPropertyChangeListener listener) {
97
		((ListenerAdaptor) listener).addListenerTo(source);
98
	}
99
100
	public void removePropertyChangeListener(Object source,
101
			IPropertyChangeListener listener) {
102
		((ListenerAdaptor) listener).removeListenerFrom(source);
103
	}
104
105
	private class ListenerAdaptor implements IPropertyChangeListener {
106
		private final IMapPropertyChangeListener wrapped;
107
108
		private IPropertyChangeListener masterListener;
109
		private Map sourceToKeyToDetailListener = new HashMap();
110
111
		ListenerAdaptor(IMapPropertyChangeListener wrapped) {
112
			this.wrapped = wrapped;
113
114
			IMapPropertyChangeListener masterMapListener = new MasterMapPropertyListener();
115
			masterListener = masterProperty.adaptListener(masterMapListener);
116
		}
117
118
		private void fireMapChange(Object source, MapDiff diff) {
119
			wrapped.handleMapPropertyChange(new MapPropertyChangeEvent(source,
120
					MapPropertyDetailValueMap.this, diff));
121
		}
122
123
		protected void addListenerTo(Object source) {
124
			masterProperty.addPropertyChangeListener(source, masterListener);
125
126
			Map keyToDetailListener = new HashMap();
127
			for (Iterator it = masterProperty.getMap(source).entrySet()
128
					.iterator(); it.hasNext();) {
129
				Map.Entry entry = (Map.Entry) it.next();
130
				Object key = entry.getKey();
131
				Object masterValue = entry.getValue();
132
				DetailValuePropertyListener detailListener = new DetailValuePropertyListener(
133
						source, key);
134
				IPropertyChangeListener listener = detailListener.wrapper = detailProperty
135
						.adaptListener(detailListener);
136
				detailProperty.addPropertyChangeListener(masterValue, listener);
137
				keyToDetailListener.put(masterValue, detailListener);
138
			}
139
140
			sourceToKeyToDetailListener.put(source, keyToDetailListener);
141
		}
142
143
		protected void removeListenerFrom(Object source) {
144
			masterProperty.removePropertyChangeListener(source, masterListener);
145
			Map masterElementToDetailListener = (Map) sourceToKeyToDetailListener
146
					.remove(source);
147
			if (masterElementToDetailListener != null) {
148
				for (Iterator it = masterElementToDetailListener.entrySet()
149
						.iterator(); it.hasNext();) {
150
					Map.Entry entry = (Map.Entry) it.next();
151
					detailProperty
152
							.removePropertyChangeListener(entry.getKey(),
153
									((DetailValuePropertyListener) entry
154
											.getValue()).wrapper);
155
				}
156
			}
157
		}
158
159
		private class MasterMapPropertyListener implements
160
				IMapPropertyChangeListener {
161
			public void handleMapPropertyChange(
162
					final MapPropertyChangeEvent event) {
163
				Object source = event.getSource();
164
165
				Map oldValues = new HashMap();
166
				Map newValues = new HashMap();
167
168
				Set addedKeys = event.diff.getAddedKeys();
169
				for (Iterator it = addedKeys.iterator(); it.hasNext();) {
170
					Object key = it.next();
171
					Object newMasterValue = event.diff.getNewValue(key);
172
					Object newDetailValue = detailProperty
173
							.getValue(newMasterValue);
174
					newValues.put(key, newDetailValue);
175
					addPropertySourceListener(source, key, newMasterValue);
176
				}
177
178
				Set removedKeys = event.diff.getRemovedKeys();
179
				for (Iterator it = removedKeys.iterator(); it.hasNext();) {
180
					Object key = it.next();
181
					Object oldMasterValue = event.diff.getOldValue(key);
182
					Object oldDetailValue = detailProperty
183
							.getValue(oldMasterValue);
184
					oldValues.put(key, oldDetailValue);
185
					removePropertySourceListener(source, key, oldMasterValue);
186
				}
187
188
				Set changedKeys = new HashSet(event.diff.getChangedKeys());
189
				for (Iterator it = changedKeys.iterator(); it.hasNext();) {
190
					Object key = it.next();
191
192
					Object oldMasterValue = event.diff.getOldValue(key);
193
					Object newMasterValue = event.diff.getNewValue(key);
194
195
					Object oldDetailValue = detailProperty
196
							.getValue(oldMasterValue);
197
					Object newDetailValue = detailProperty
198
							.getValue(newMasterValue);
199
200
					if (Util.equals(oldDetailValue, newDetailValue)) {
201
						it.remove();
202
					} else {
203
						oldValues.put(key, oldDetailValue);
204
						newValues.put(key, newDetailValue);
205
					}
206
207
					removePropertySourceListener(source, key, oldMasterValue);
208
					addPropertySourceListener(source, key, newMasterValue);
209
				}
210
211
				MapDiff diff = Diffs.createMapDiff(addedKeys, removedKeys,
212
						changedKeys, oldValues, newValues);
213
214
				fireMapChange(source, diff);
215
			}
216
217
			private void addPropertySourceListener(Object source, Object key,
218
					Object masterValue) {
219
				Map keyToDetailListener = (Map) sourceToKeyToDetailListener
220
						.get(source);
221
				if (keyToDetailListener == null) {
222
					sourceToKeyToDetailListener.put(source,
223
							keyToDetailListener = new HashMap());
224
				}
225
				if (!keyToDetailListener.containsKey(key)) {
226
					DetailValuePropertyListener detailListener = new DetailValuePropertyListener(
227
							source, key);
228
					IPropertyChangeListener listener = detailListener.wrapper = detailProperty
229
							.adaptListener(detailListener);
230
					detailProperty.addPropertyChangeListener(masterValue,
231
							listener);
232
					keyToDetailListener.put(key, detailListener);
233
				}
234
			}
235
236
			private void removePropertySourceListener(Object source,
237
					Object key, Object masterValue) {
238
				Map keyToDetailListener = (Map) sourceToKeyToDetailListener
239
						.get(source);
240
				if (keyToDetailListener != null
241
						&& keyToDetailListener.containsKey(key)) {
242
					DetailValuePropertyListener detailListener = (DetailValuePropertyListener) keyToDetailListener
243
							.remove(key);
244
					detailProperty.removePropertyChangeListener(masterValue,
245
							detailListener.wrapper);
246
				}
247
			}
248
		}
249
250
		private class DetailValuePropertyListener implements
251
				IValuePropertyChangeListener {
252
			private Object source;
253
			private Object key;
254
			private IPropertyChangeListener wrapper;
255
256
			DetailValuePropertyListener(Object source, Object key) {
257
				this.source = source;
258
				this.key = key;
259
			}
260
261
			public void handleValuePropertyChange(ValuePropertyChangeEvent event) {
262
				fireMapChange(source, Diffs.createMapDiffSingleChange(key,
263
						event.diff.getOldValue(), event.diff.getNewValue()));
264
			}
265
		}
266
267
	}
268
}
(-)src/org/eclipse/core/databinding/property/ICollectionProperty.java (+186 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import java.util.Collection;
15
16
/**
17
 * Interface for collection-typed properties.
18
 * 
19
 * @since 1.2
20
 * @noimplement This interface is not intended to be implemented by clients.
21
 */
22
public interface ICollectionProperty extends IProperty {
23
	/**
24
	 * Returns the size of the source's collection property
25
	 * 
26
	 * @param source
27
	 *            the property source
28
	 * @return the size of the source's collection property
29
	 */
30
	int size(Object source);
31
32
	/**
33
	 * Returns whether the source's collection property is empty
34
	 * 
35
	 * @param source
36
	 *            the property source
37
	 * @return whether the source's collection property is empty
38
	 */
39
	boolean isEmpty(Object source);
40
41
	/**
42
	 * Returns whether the source's collection property contains the given
43
	 * element.
44
	 * 
45
	 * @param source
46
	 *            the property source
47
	 * @param o
48
	 *            the element
49
	 * @return whether the source's collection property contains the given
50
	 *         element.
51
	 */
52
	boolean contains(Object source, Object o);
53
54
	/**
55
	 * Returns an array of all elements in the source's collection property
56
	 * 
57
	 * @param source
58
	 *            the property source
59
	 * @return an array of all elements in the source's collection property
60
	 */
61
	Object[] toArray(Object source);
62
63
	/**
64
	 * Returns an array of all elements in the source's collection property
65
	 * 
66
	 * @param source
67
	 *            the property source
68
	 * @param array
69
	 *            the array into which the elements will be copied. If the array
70
	 *            is not large enough to hold all elements, the elements will be
71
	 *            returned in a new array of the same runtime type.
72
	 * @return an array of all elements in the source's collection property
73
	 */
74
	Object[] toArray(Object source, Object[] array);
75
76
	/**
77
	 * Adds the element to the source's collection property
78
	 * 
79
	 * @param source
80
	 *            the property source
81
	 * @param o
82
	 *            the element to add
83
	 * @return whether the element was added to the source's collection property
84
	 */
85
	boolean add(Object source, Object o);
86
87
	/**
88
	 * Removes the element from the source's collection property
89
	 * 
90
	 * @param source
91
	 *            the property source
92
	 * @param o
93
	 *            the element to remove
94
	 * @return whether the element was removed from the source's collection
95
	 *         property
96
	 */
97
	boolean remove(Object source, Object o);
98
99
	/**
100
	 * Returns whether the source's collection property contains all elements in
101
	 * the given collection
102
	 * 
103
	 * @param source
104
	 *            the property source
105
	 * @param c
106
	 *            the collection of elements to test for
107
	 * @return whether the source's collection property contains all elements in
108
	 *         the given collection
109
	 */
110
	boolean containsAll(Object source, Collection c);
111
112
	/**
113
	 * Adds all elements in the specified collection to the source's collection
114
	 * property.
115
	 * 
116
	 * @param source
117
	 *            the property source
118
	 * @param c
119
	 *            the collection of elements to add.
120
	 * @return whether the source's collection property was changed
121
	 */
122
	boolean addAll(Object source, Collection c);
123
124
	/**
125
	 * Removes all elements from the source's collection property which are
126
	 * contained in the specified collection.
127
	 * 
128
	 * @param source
129
	 *            the property source
130
	 * @param c
131
	 *            the collection of elements to be removed
132
	 * @return whether the source's collection property was changed
133
	 */
134
	boolean removeAll(Object source, Collection c);
135
136
	/**
137
	 * Removes all elements from the source's collection property which are not
138
	 * contained in the specified collection.
139
	 * 
140
	 * @param source
141
	 *            the property source
142
	 * @param c
143
	 *            the collection of elements to retain
144
	 * @return whether the source's collection property was changed
145
	 */
146
	boolean retainAll(Object source, Collection c);
147
148
	/**
149
	 * Removes all elements from the source's collection property.
150
	 * 
151
	 * @param source
152
	 *            the property source
153
	 */
154
	void clear(Object source);
155
156
	/**
157
	 * Returns whether the source's collection property is equal to the
158
	 * argument.
159
	 * 
160
	 * @param source
161
	 *            the property source
162
	 * @param o
163
	 *            the object to test for equality to the source's collection
164
	 *            property
165
	 * @return whether the source's collection property is equal to the argument
166
	 */
167
	boolean equals(Object source, Object o);
168
169
	/**
170
	 * Returns the hash code of the source's collection property.
171
	 * 
172
	 * @param source
173
	 *            the property source
174
	 * @return the hash code of the source's collection property
175
	 */
176
	int hashCode(Object source);
177
178
	/**
179
	 * Returns the type of the elements in the collection or <code>null</code>
180
	 * if untyped
181
	 * 
182
	 * @return the type of the elements in the collection or <code>null</code>
183
	 *         if untyped
184
	 */
185
	Object getElementType();
186
}
(-)src/org/eclipse/core/databinding/property/PropertyObservables.java (+371 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 (bug 194734)
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.masterdetail.MasterDetailObservables;
20
import org.eclipse.core.databinding.observable.set.IObservableSet;
21
import org.eclipse.core.databinding.observable.value.IObservableValue;
22
import org.eclipse.core.internal.databinding.property.ListValuePropertyObservableList;
23
import org.eclipse.core.internal.databinding.property.MapValuePropertyObservableMap;
24
import org.eclipse.core.internal.databinding.property.PropertyObservableList;
25
import org.eclipse.core.internal.databinding.property.PropertyObservableMap;
26
import org.eclipse.core.internal.databinding.property.PropertyObservableSet;
27
import org.eclipse.core.internal.databinding.property.PropertyObservableValue;
28
import org.eclipse.core.internal.databinding.property.SetValuePropertyObservableMap;
29
30
/**
31
 * A factory for creating observables observing properties of source objects
32
 * 
33
 * @since 1.2
34
 */
35
public class PropertyObservables {
36
	/**
37
	 * Returns an observable value on the default realm that tracks the given
38
	 * property of the source object.
39
	 * 
40
	 * @param source
41
	 *            the property value
42
	 * @param property
43
	 *            the value property to observe
44
	 * @return an observable value on the default realm that tracks the given
45
	 *         property of the source object.
46
	 * @since 1.2
47
	 */
48
	public static IObservableValue observeValue(Object source,
49
			IValueProperty property) {
50
		return observeValue(Realm.getDefault(), source, property);
51
	}
52
53
	/**
54
	 * Returns an observable value on the given realm that tracks the given
55
	 * property of the source object
56
	 * 
57
	 * @param realm
58
	 *            the realm
59
	 * @param source
60
	 *            the property source
61
	 * @param property
62
	 *            the value property observe
63
	 * @return an observable value that tracks the given property of the source
64
	 *         object
65
	 * @since 1.2
66
	 */
67
	public static IObservableValue observeValue(Realm realm, Object source,
68
			IValueProperty property) {
69
		return new PropertyObservableValue(realm, source, property);
70
	}
71
72
	/**
73
	 * Returns a factory for creating observable values on the default realm
74
	 * tracking the given property of a particular source object
75
	 * 
76
	 * @param property
77
	 *            the property to observe
78
	 * @return a factory for creating observable values on the default realm
79
	 *         tracking the given property of a particular source object
80
	 */
81
	public static IObservableFactory valueFactory(IValueProperty property) {
82
		return valueFactory(Realm.getDefault(), property);
83
	}
84
85
	/**
86
	 * Returns a factory for creating observable values on the given realm
87
	 * tracking the given property of a particular source object
88
	 * 
89
	 * @param realm
90
	 *            the realm
91
	 * @param property
92
	 *            the property to observe
93
	 * @return a factory for creating observable values on the given realm
94
	 *         tracking the given property of a particular source object
95
	 */
96
	public static IObservableFactory valueFactory(final Realm realm,
97
			final IValueProperty property) {
98
		return new IObservableFactory() {
99
			public IObservable createObservable(Object target) {
100
				return observeValue(realm, target, property);
101
			}
102
		};
103
	}
104
105
	/**
106
	 * Returns an observable value on the master observable's realm which tracks
107
	 * the given property of the current value of <code>master</code>.
108
	 * 
109
	 * @param master
110
	 *            the master observable
111
	 * @param property
112
	 *            the property to observe
113
	 * @return an observable value which tracks the given property of the
114
	 *         current value of <code>master</code>.
115
	 */
116
	public static IObservableValue observeDetailValue(IObservableValue master,
117
			IValueProperty property) {
118
		return MasterDetailObservables.detailValue(master, valueFactory(master
119
				.getRealm(), property), property.getValueType());
120
	}
121
122
	/**
123
	 * Returns an observable set on the default realm that tracks the given
124
	 * property of the source object
125
	 * 
126
	 * @param source
127
	 *            the property source
128
	 * @param property
129
	 *            the property to observe
130
	 * @return an observable set on the default realm that tracks the given
131
	 *         property of the source object
132
	 */
133
	public static IObservableSet observeSet(Object source, ISetProperty property) {
134
		return observeSet(Realm.getDefault(), source, property);
135
	}
136
137
	/**
138
	 * Returns an observable set on the given realm that tracks the given
139
	 * property of the source object
140
	 * 
141
	 * @param realm
142
	 *            the realm
143
	 * @param source
144
	 *            the property source
145
	 * @param property
146
	 *            the property to observe
147
	 * @return an observable set on the given realm that tracks the given
148
	 *         property of the source object
149
	 */
150
	public static IObservableSet observeSet(Realm realm, Object source,
151
			ISetProperty property) {
152
		return new PropertyObservableSet(realm, source, property);
153
	}
154
155
	/**
156
	 * Returns a factory for creating observable sets on the default realm
157
	 * tracking the given property of a particular source object
158
	 * 
159
	 * @param property
160
	 *            the property to be observed
161
	 * @return a factory for creating observable sets on the default realm
162
	 *         tracking the given property of a particular source object
163
	 */
164
	public static IObservableFactory setFactory(ISetProperty property) {
165
		return setFactory(Realm.getDefault(), property);
166
	}
167
168
	/**
169
	 * Returns a factory for creating obervable sets on the given realm tracking
170
	 * the given property of a particular source object
171
	 * 
172
	 * @param realm
173
	 *            the realm
174
	 * @param property
175
	 *            the property to be observed
176
	 * @return a factory for creating obervable sets on the given realm tracking
177
	 *         the given property of a particular source object
178
	 */
179
	public static IObservableFactory setFactory(final Realm realm,
180
			final ISetProperty property) {
181
		return new IObservableFactory() {
182
			public IObservable createObservable(Object target) {
183
				return observeSet(realm, target, property);
184
			}
185
		};
186
	}
187
188
	/**
189
	 * Returns an observable set on the master observable's realm which tracks
190
	 * the given property of the current value of <code>master</code>.
191
	 * 
192
	 * @param master
193
	 *            the master observable
194
	 * @param property
195
	 *            the property to observe
196
	 * @return an observable set on the given realm which tracks the given
197
	 *         property of the current value of <code>master</code>.
198
	 */
199
	public static IObservableSet observeDetailSet(IObservableValue master,
200
			ISetProperty property) {
201
		return MasterDetailObservables.detailSet(master, setFactory(master
202
				.getRealm(), property), property.getElementType());
203
	}
204
205
	/**
206
	 * Returns an observable list on the default realm that tracks the given
207
	 * property of the source object
208
	 * 
209
	 * @param source
210
	 *            the property source
211
	 * @param property
212
	 *            the property to observe
213
	 * @return an observable list on the default realm that tracks the given
214
	 *         property of the source object
215
	 */
216
	public static IObservableList observeList(Object source,
217
			IListProperty property) {
218
		return observeList(Realm.getDefault(), source, property);
219
	}
220
221
	/**
222
	 * Returns an observable list on the given realm that tracks the given
223
	 * property of the source object
224
	 * 
225
	 * @param realm
226
	 *            the realm
227
	 * @param source
228
	 *            the property source
229
	 * @param property
230
	 *            the property to observe
231
	 * @return an observable list on the given realm that tracks the given
232
	 *         property of the source object
233
	 */
234
	public static IObservableList observeList(Realm realm, Object source,
235
			IListProperty property) {
236
		return new PropertyObservableList(realm, source, property);
237
	}
238
239
	/**
240
	 * Returns a factory for creating observable lists on the default realm
241
	 * tracking the given property of a particular source object
242
	 * 
243
	 * @param property
244
	 *            the property to be observed
245
	 * @return an observable value factory on
246
	 */
247
	public static IObservableFactory listFactory(IListProperty property) {
248
		return listFactory(Realm.getDefault(), property);
249
	}
250
251
	/**
252
	 * Returns a factory for creating obervable lists on the given realm
253
	 * tracking the given property of a particular source object
254
	 * 
255
	 * @param realm
256
	 *            the realm
257
	 * @param property
258
	 *            the property to be observed
259
	 * @return an observable value factory on
260
	 */
261
	public static IObservableFactory listFactory(final Realm realm,
262
			final IListProperty property) {
263
		return new IObservableFactory() {
264
			public IObservable createObservable(Object target) {
265
				return observeList(realm, target, property);
266
			}
267
		};
268
	}
269
270
	/**
271
	 * Returns an observable list on the master observable's realm which tracks
272
	 * the given property of the current value of <code>master</code>.
273
	 * 
274
	 * @param master
275
	 *            the master observable
276
	 * @param property
277
	 *            the property to observe
278
	 * @return an observable list on the given realm which tracks the given
279
	 *         property of the current value of <code>master</code>.
280
	 */
281
	public static IObservableList observeDetailList(IObservableValue master,
282
			IListProperty property) {
283
		return MasterDetailObservables.detailList(master, listFactory(master
284
				.getRealm(), property), property.getElementType());
285
	}
286
287
	/**
288
	 * Returns an observable list on the master observable's realm which tracks
289
	 * the given property of each element of <code>master</code>.
290
	 * 
291
	 * @param master
292
	 *            the master observable
293
	 * @param property
294
	 *            the property to observe on each element in the master
295
	 *            observable
296
	 * @return an observable
297
	 */
298
	public static IObservableList observeDetailValues(IObservableList master,
299
			IValueProperty property) {
300
		return new ListValuePropertyObservableList(master, property);
301
	}
302
303
	/**
304
	 * Returns an observable map on the default realm which tracks the given
305
	 * property of the source object
306
	 * 
307
	 * @param source
308
	 *            the property source
309
	 * @param property
310
	 *            the property to observe
311
	 * @return an observable map on the default realm which tracks the given
312
	 *         property of the source object
313
	 */
314
	public static IObservableMap observeMap(Object source, IMapProperty property) {
315
		return observeMap(Realm.getDefault(), source, property);
316
	}
317
318
	/**
319
	 * Returns an observable map on the given realm which tracks the given
320
	 * property of the source object
321
	 * 
322
	 * @param realm
323
	 *            the realm
324
	 * @param source
325
	 *            the property source
326
	 * @param property
327
	 *            the property to observe
328
	 * @return an observable map on the given realm which tracks the given
329
	 *         property of the source object
330
	 */
331
	public static IObservableMap observeMap(Realm realm, Object source,
332
			IMapProperty property) {
333
		return new PropertyObservableMap(realm, source, property);
334
	}
335
336
	/**
337
	 * Returns an observable map on the master observable's realm tracking the
338
	 * current values of the given property for the elements in the given set.
339
	 * 
340
	 * @param keySet
341
	 *            the master observable
342
	 * @param valueProperty
343
	 *            the property to observe on each element of the master
344
	 *            observable
345
	 * @return an observable map that tracks the current value of the given
346
	 *         property for the elements in the given set.
347
	 */
348
	public static IObservableMap observeDetailValues(IObservableSet keySet,
349
			IValueProperty valueProperty) {
350
		return new SetValuePropertyObservableMap(keySet, valueProperty);
351
	}
352
353
	/**
354
	 * Returns an observable map on the master observable's realm which tracks
355
	 * the current values of the given property for the entry values in the
356
	 * given map.
357
	 * 
358
	 * @param map
359
	 *            the master observable
360
	 * @param valueProperty
361
	 *            the property to observe on each entry value in the master
362
	 *            observable
363
	 * @return an observable map on the master observable's realm which tracks
364
	 *         the current value of the given property for the elements in the
365
	 *         given map's values collection
366
	 */
367
	public static IObservableMap observeDetailValues(IObservableMap map,
368
			IValueProperty valueProperty) {
369
		return new MapValuePropertyObservableMap(map, valueProperty);
370
	}
371
}
(-)src/org/eclipse/core/internal/databinding/property/masterdetail/ValuePropertyDetailSet.java (+185 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.property.masterdetail;
13
14
import java.util.Collection;
15
import java.util.HashMap;
16
import java.util.Map;
17
import java.util.Set;
18
19
import org.eclipse.core.databinding.observable.Diffs;
20
import org.eclipse.core.databinding.observable.set.SetDiff;
21
import org.eclipse.core.databinding.property.IPropertyChangeListener;
22
import org.eclipse.core.databinding.property.ISetProperty;
23
import org.eclipse.core.databinding.property.ISetPropertyChangeListener;
24
import org.eclipse.core.databinding.property.IValueProperty;
25
import org.eclipse.core.databinding.property.IValuePropertyChangeListener;
26
import org.eclipse.core.databinding.property.SetProperty;
27
import org.eclipse.core.databinding.property.SetPropertyChangeEvent;
28
import org.eclipse.core.databinding.property.ValuePropertyChangeEvent;
29
30
/**
31
 * @since 3.3
32
 * 
33
 */
34
public class ValuePropertyDetailSet extends SetProperty {
35
	private final IValueProperty masterProperty;
36
	private final ISetProperty detailProperty;
37
38
	/**
39
	 * @param masterProperty
40
	 * @param detailProperty
41
	 */
42
	public ValuePropertyDetailSet(IValueProperty masterProperty,
43
			ISetProperty detailProperty) {
44
		this.masterProperty = masterProperty;
45
		this.detailProperty = detailProperty;
46
	}
47
48
	public Set getSet(Object source) {
49
		Object masterValue = masterProperty.getValue(source);
50
		return detailProperty.getSet(masterValue);
51
	}
52
53
	public boolean add(Object source, Object o) {
54
		Object masterValue = masterProperty.getValue(source);
55
		return detailProperty.add(masterValue, o);
56
	}
57
58
	public boolean addAll(Object source, Collection c) {
59
		Object masterValue = masterProperty.getValue(source);
60
		return detailProperty.addAll(masterValue, c);
61
	}
62
63
	public void clear(Object source) {
64
		Object masterValue = masterProperty.getValue(source);
65
		detailProperty.clear(masterValue);
66
	}
67
68
	public Object getElementType() {
69
		return detailProperty.getElementType();
70
	}
71
72
	public boolean remove(Object source, Object o) {
73
		Object masterValue = masterProperty.getValue(source);
74
		return detailProperty.remove(masterValue, o);
75
	}
76
77
	public boolean removeAll(Object source, Collection c) {
78
		Object masterValue = masterProperty.getValue(source);
79
		return detailProperty.removeAll(masterValue, c);
80
	}
81
82
	public boolean retainAll(Object source, Collection c) {
83
		Object masterValue = masterProperty.getValue(source);
84
		return detailProperty.retainAll(masterValue, c);
85
	}
86
87
	public IPropertyChangeListener adaptListener(
88
			ISetPropertyChangeListener listener) {
89
		return new ListenerAdaptor(listener);
90
	}
91
92
	public void addPropertyChangeListener(Object source,
93
			IPropertyChangeListener listener) {
94
		((ListenerAdaptor) listener).addListenerTo(source);
95
	}
96
97
	public void removePropertyChangeListener(Object source,
98
			IPropertyChangeListener listener) {
99
		((ListenerAdaptor) listener).removeListenerFrom(source);
100
	}
101
102
	private class ListenerAdaptor implements IPropertyChangeListener {
103
		private final ISetPropertyChangeListener wrapped;
104
105
		private IPropertyChangeListener masterListener;
106
		private Map sourceToDetailListener = new HashMap();
107
108
		ListenerAdaptor(ISetPropertyChangeListener wrapped) {
109
			this.wrapped = wrapped;
110
111
			IValuePropertyChangeListener masterValueListener = new MasterPropertyListener();
112
			masterListener = masterProperty.adaptListener(masterValueListener);
113
		}
114
115
		private void fireSetChange(Object source, SetDiff diff) {
116
			wrapped.handleSetPropertyChange(new SetPropertyChangeEvent(source,
117
					ValuePropertyDetailSet.this, diff));
118
		}
119
120
		protected void addListenerTo(Object source) {
121
			masterProperty.addPropertyChangeListener(source, masterListener);
122
			addDetailPropertyListener(source);
123
		}
124
125
		protected void removeListenerFrom(Object source) {
126
			masterProperty.removePropertyChangeListener(source, masterListener);
127
			removeDetailPropertyListener(source);
128
		}
129
130
		private void addDetailPropertyListener(Object source) {
131
			Object masterValue = masterProperty.getValue(source);
132
			DetailSetPropertyListener detailListener = new DetailSetPropertyListener(
133
					source, masterValue);
134
			IPropertyChangeListener listener = detailListener.wrapper = detailProperty
135
					.adaptListener(detailListener);
136
			detailProperty.addPropertyChangeListener(masterValue, listener);
137
			sourceToDetailListener.put(source, detailListener);
138
		}
139
140
		private void removeDetailPropertyListener(Object source) {
141
			DetailSetPropertyListener detailListener = (DetailSetPropertyListener) sourceToDetailListener
142
					.remove(source);
143
			if (detailListener != null) {
144
				detailProperty.removePropertyChangeListener(
145
						detailListener.masterValue, detailListener.wrapper);
146
			}
147
			sourceToDetailListener.remove(source);
148
		}
149
150
		private class MasterPropertyListener implements
151
				IValuePropertyChangeListener {
152
			public void handleValuePropertyChange(ValuePropertyChangeEvent event) {
153
				Object oldSource = event.diff.getOldValue();
154
				Object newSource = event.diff.getNewValue();
155
156
				Set oldSet = detailProperty.getSet(oldSource);
157
				Set newSet = detailProperty.getSet(newSource);
158
				SetDiff diff = Diffs.computeSetDiff(oldSet, newSet);
159
160
				Object source = event.getSource();
161
162
				removeDetailPropertyListener(source);
163
				addDetailPropertyListener(source);
164
165
				fireSetChange(source, diff);
166
			}
167
		}
168
169
		private class DetailSetPropertyListener implements
170
				ISetPropertyChangeListener {
171
			private Object source;
172
			private Object masterValue;
173
			private IPropertyChangeListener wrapper;
174
175
			DetailSetPropertyListener(Object source, Object masterValue) {
176
				this.source = source;
177
				this.masterValue = masterValue;
178
			}
179
180
			public void handleSetPropertyChange(SetPropertyChangeEvent event) {
181
				fireSetChange(source, event.diff);
182
			}
183
		}
184
	}
185
}
(-)src/org/eclipse/core/internal/databinding/property/PropertyObservableList.java (+378 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 (bug 194734)
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.ObservableTracker;
23
import org.eclipse.core.databinding.observable.Realm;
24
import org.eclipse.core.databinding.observable.list.AbstractObservableList;
25
import org.eclipse.core.databinding.property.IListProperty;
26
import org.eclipse.core.databinding.property.IListPropertyChangeListener;
27
import org.eclipse.core.databinding.property.IProperty;
28
import org.eclipse.core.databinding.property.IPropertyChangeListener;
29
import org.eclipse.core.databinding.property.IPropertyObservable;
30
import org.eclipse.core.databinding.property.ListPropertyChangeEvent;
31
32
/**
33
 * @since 3.3
34
 * 
35
 */
36
public class PropertyObservableList extends AbstractObservableList implements
37
		IPropertyObservable {
38
	private Object source;
39
	private IListProperty property;
40
41
	private volatile boolean updating = false;
42
43
	private boolean disposed = false;
44
45
	private transient volatile int modCount = 0;
46
47
	private IPropertyChangeListener listener;
48
49
	/**
50
	 * @param realm
51
	 * @param source
52
	 * @param property
53
	 */
54
	public PropertyObservableList(Realm realm, Object source,
55
			IListProperty property) {
56
		super(realm);
57
		this.source = source;
58
		this.property = property;
59
		
60
		IListPropertyChangeListener listListener = new IListPropertyChangeListener() {
61
			public void handleListPropertyChange(final ListPropertyChangeEvent event) {
62
				if (!disposed && !updating) {
63
					getRealm().exec(new Runnable() {
64
						public void run() {
65
							getRealm().exec(new Runnable() {
66
								public void run() {
67
									modCount++;
68
									fireListChange(event.diff);
69
								}
70
							});
71
						}
72
					});
73
				}
74
			}
75
		};
76
		this.listener = property.adaptListener(listListener);
77
	}
78
79
	protected void firstListenerAdded() {
80
		if (!disposed) {
81
			property.addPropertyChangeListener(source, listener);
82
		}
83
	}
84
85
	protected void lastListenerRemoved() {
86
		if (!disposed) {
87
			property.removePropertyChangeListener(source, listener);
88
		}
89
	}
90
91
	private void getterCalled() {
92
		ObservableTracker.getterCalled(this);
93
	}
94
95
	public Object getElementType() {
96
		return property.getElementType();
97
	}
98
99
	// Queries
100
101
	protected int doGetSize() {
102
		return property.size(source);
103
	}
104
105
	public boolean contains(Object o) {
106
		getterCalled();
107
		return property.contains(source, o);
108
	}
109
110
	public boolean containsAll(Collection c) {
111
		getterCalled();
112
		return property.containsAll(source, c);
113
	}
114
115
	public Object get(int index) {
116
		getterCalled();
117
		return property.get(source, index);
118
	}
119
120
	public int indexOf(Object o) {
121
		getterCalled();
122
		return property.indexOf(source, o);
123
	}
124
125
	public boolean isEmpty() {
126
		getterCalled();
127
		return property.isEmpty(source);
128
	}
129
130
	public int lastIndexOf(Object o) {
131
		getterCalled();
132
		return property.lastIndexOf(source, o);
133
	}
134
135
	public Object[] toArray() {
136
		getterCalled();
137
		return property.toArray(source);
138
	}
139
140
	public Object[] toArray(Object[] a) {
141
		getterCalled();
142
		return property.toArray(source, a);
143
	}
144
145
	// Single change operations
146
147
	public boolean add(Object o) {
148
		checkRealm();
149
		return property.add(source, o);
150
	}
151
152
	public Iterator iterator() {
153
		getterCalled();
154
		return new Iterator() {
155
			int lastReturned = -1;
156
			int expectedModCount = modCount;
157
			ListIterator delegate = new ArrayList(property.getList(source))
158
					.listIterator();
159
160
			public boolean hasNext() {
161
				getterCalled();
162
				checkForComodification();
163
				return delegate.hasNext();
164
			}
165
166
			public Object next() {
167
				getterCalled();
168
				checkForComodification();
169
				Object next = delegate.next();
170
				lastReturned = delegate.previousIndex();
171
				return next;
172
			}
173
174
			public void remove() {
175
				checkRealm();
176
				checkForComodification();
177
				if (lastReturned == -1)
178
					throw new IllegalStateException();
179
180
				delegate.remove(); // stay in sync
181
182
				property.remove(source, lastReturned);
183
184
				lastReturned = -1;
185
				expectedModCount = modCount;
186
			}
187
188
			private void checkForComodification() {
189
				if (expectedModCount != modCount)
190
					throw new ConcurrentModificationException();
191
			}
192
		};
193
	}
194
195
	public Object move(int oldIndex, int newIndex) {
196
		getterCalled();
197
		return property.move(source, oldIndex, newIndex);
198
	}
199
200
	public boolean remove(Object o) {
201
		getterCalled();
202
		return property.remove(source, o);
203
	}
204
205
	public void add(int index, Object o) {
206
		getterCalled();
207
		property.add(source, index, o);
208
	}
209
210
	public ListIterator listIterator() {
211
		return listIterator(0);
212
	}
213
214
	public ListIterator listIterator(final int index) {
215
		getterCalled();
216
		return new ListIterator() {
217
			int lastReturned = -1;
218
			int expectedModCount = modCount;
219
			ListIterator delegate = new ArrayList(property.getList(source))
220
					.listIterator(index);
221
222
			public boolean hasNext() {
223
				getterCalled();
224
				checkForComodification();
225
				return delegate.hasNext();
226
			}
227
228
			public int nextIndex() {
229
				getterCalled();
230
				checkForComodification();
231
				return delegate.nextIndex();
232
			}
233
234
			public Object next() {
235
				getterCalled();
236
				checkForComodification();
237
				Object next = delegate.next();
238
				lastReturned = delegate.previousIndex();
239
				return next;
240
			}
241
242
			public boolean hasPrevious() {
243
				getterCalled();
244
				checkForComodification();
245
				return delegate.hasPrevious();
246
			}
247
248
			public int previousIndex() {
249
				getterCalled();
250
				checkForComodification();
251
				return delegate.previousIndex();
252
			}
253
254
			public Object previous() {
255
				getterCalled();
256
				checkForComodification();
257
				Object previous = delegate.previous();
258
				lastReturned = delegate.nextIndex();
259
				return previous;
260
			}
261
262
			public void add(Object o) {
263
				checkRealm();
264
				checkForComodification();
265
				int index = delegate.nextIndex();
266
267
				delegate.add(o); // keep in sync
268
269
				property.add(source, index, o);
270
271
				lastReturned = -1;
272
				expectedModCount = modCount;
273
			}
274
275
			public void set(Object o) {
276
				checkRealm();
277
				checkForComodification();
278
279
				delegate.set(o);
280
281
				property.set(source, lastReturned, o);
282
283
				expectedModCount = modCount;
284
			}
285
286
			public void remove() {
287
				checkRealm();
288
				checkForComodification();
289
				if (lastReturned == -1)
290
					throw new IllegalStateException();
291
292
				delegate.remove(); // keep in sync
293
294
				property.remove(source, lastReturned);
295
296
				lastReturned = -1;
297
				expectedModCount = modCount;
298
			}
299
300
			private void checkForComodification() {
301
				if (expectedModCount != modCount)
302
					throw new ConcurrentModificationException();
303
			}
304
305
		};
306
	}
307
308
	public Object remove(int index) {
309
		getterCalled();
310
		return property.remove(source, index);
311
	}
312
313
	public Object set(int index, Object o) {
314
		getterCalled();
315
		return property.set(source, index, o);
316
	}
317
318
	public List subList(int fromIndex, int toIndex) {
319
		getterCalled();
320
		return Collections.unmodifiableList(property.getList(source).subList(
321
				fromIndex, toIndex));
322
	}
323
324
	// Bulk change operations
325
326
	public boolean addAll(Collection c) {
327
		getterCalled();
328
		return property.addAll(source, c);
329
	}
330
331
	public boolean addAll(int index, Collection c) {
332
		getterCalled();
333
		return property.addAll(source, index, c);
334
	}
335
336
	public boolean removeAll(Collection c) {
337
		getterCalled();
338
		return property.removeAll(source, c);
339
	}
340
341
	public boolean retainAll(Collection c) {
342
		getterCalled();
343
		return property.retainAll(source, c);
344
	}
345
346
	public void clear() {
347
		getterCalled();
348
		property.clear(source);
349
	}
350
351
	public boolean equals(Object o) {
352
		getterCalled();
353
		return property.equals(source, o);
354
	}
355
356
	public int hashCode() {
357
		getterCalled();
358
		return property.hashCode(source);
359
	}
360
361
	public Object getObserved() {
362
		return source;
363
	}
364
365
	public IProperty getProperty() {
366
		return property;
367
	}
368
369
	public synchronized void dispose() {
370
		if (!disposed) {
371
			disposed = true;
372
			property.removePropertyChangeListener(source, listener);
373
			property = null;
374
			source = null;
375
		}
376
		super.dispose();
377
	}
378
}
(-)src/org/eclipse/core/internal/databinding/property/ListValuePropertyObservableList.java (+386 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.property;
13
14
import java.lang.reflect.Array;
15
import java.util.ArrayList;
16
import java.util.Collection;
17
import java.util.Iterator;
18
import java.util.List;
19
import java.util.ListIterator;
20
21
import org.eclipse.core.databinding.observable.Diffs;
22
import org.eclipse.core.databinding.observable.IObserving;
23
import org.eclipse.core.databinding.observable.ObservableTracker;
24
import org.eclipse.core.databinding.observable.list.AbstractObservableList;
25
import org.eclipse.core.databinding.observable.list.IListChangeListener;
26
import org.eclipse.core.databinding.observable.list.IObservableList;
27
import org.eclipse.core.databinding.observable.list.ListChangeEvent;
28
import org.eclipse.core.databinding.observable.list.ListDiff;
29
import org.eclipse.core.databinding.observable.list.ListDiffEntry;
30
import org.eclipse.core.databinding.observable.set.IObservableSet;
31
import org.eclipse.core.databinding.observable.set.ISetChangeListener;
32
import org.eclipse.core.databinding.observable.set.SetChangeEvent;
33
import org.eclipse.core.databinding.observable.set.WritableSet;
34
import org.eclipse.core.databinding.property.IPropertyChangeListener;
35
import org.eclipse.core.databinding.property.IValueProperty;
36
import org.eclipse.core.databinding.property.IValuePropertyChangeListener;
37
import org.eclipse.core.databinding.property.ValuePropertyChangeEvent;
38
import org.eclipse.core.internal.databinding.Util;
39
40
/**
41
 * @since 3.3
42
 * 
43
 */
44
public class ListValuePropertyObservableList extends AbstractObservableList
45
		implements IObserving {
46
	private IObservableList masterList;
47
	private IValueProperty detailProperty;
48
49
	private IObservableSet knownMasterElements;
50
51
	private boolean disposed = false;
52
53
	private IListChangeListener masterListener = new IListChangeListener() {
54
		public void handleListChange(ListChangeEvent event) {
55
			ListDiffEntry[] masterEntries = event.diff.getDifferences();
56
			ListDiffEntry[] detailEntries = new ListDiffEntry[masterEntries.length];
57
			for (int i = 0; i < masterEntries.length; i++) {
58
				ListDiffEntry masterDifference = masterEntries[i];
59
				int index = masterDifference.getPosition();
60
				boolean addition = masterDifference.isAddition();
61
				Object masterElement = masterDifference.getElement();
62
				Object elementDetailValue = detailProperty
63
						.getValue(masterElement);
64
				detailEntries[i] = Diffs.createListDiffEntry(index, addition,
65
						elementDetailValue);
66
			}
67
68
			// Removes listeners from elements removed from list
69
			knownMasterElements.retainAll(masterList);
70
71
			// Adds listeners to elements added to list
72
			knownMasterElements.addAll(masterList);
73
74
			fireListChange(Diffs.createListDiff(detailEntries));
75
		}
76
	};
77
78
	private final class DetailValuePropertyChangeListener implements
79
			IValuePropertyChangeListener {
80
		public void handleValuePropertyChange(
81
				final ValuePropertyChangeEvent event) {
82
			if (!disposed) {
83
				Object source = event.getSource();
84
				int[] indices = findIndices(source);
85
				Object oldValue = event.diff.getOldValue();
86
				Object newValue = event.diff.getNewValue();
87
				ListDiffEntry[] entries = new ListDiffEntry[indices.length * 2];
88
				for (int i = 0; i < indices.length; i++) {
89
					int index = indices[i];
90
					entries[i * 2] = Diffs.createListDiffEntry(index, false,
91
							oldValue);
92
					entries[i * 2 + 1] = Diffs.createListDiffEntry(index, true,
93
							newValue);
94
				}
95
96
				ListDiff diff = Diffs.createListDiff(entries);
97
				fireListChange(diff);
98
			}
99
		}
100
101
		private int[] findIndices(Object masterElement) {
102
			List indices = new ArrayList();
103
104
			for (ListIterator it = masterList.listIterator(); it.hasNext();) {
105
				if (Util.equals(masterElement, it.next()))
106
					indices.add(new Integer(it.previousIndex()));
107
			}
108
109
			int[] result = new int[indices.size()];
110
			for (int i = 0; i < result.length; i++) {
111
				result[i] = ((Integer) indices.get(i)).intValue();
112
			}
113
			return result;
114
		}
115
	}
116
117
	private IPropertyChangeListener detailListener;
118
119
	/**
120
	 * @param masterList
121
	 * @param valueProperty
122
	 */
123
	public ListValuePropertyObservableList(IObservableList masterList,
124
			IValueProperty valueProperty) {
125
		super(masterList.getRealm());
126
		this.masterList = masterList;
127
		this.detailProperty = valueProperty;
128
129
		IValuePropertyChangeListener detailValueListener = new DetailValuePropertyChangeListener();
130
		this.detailListener = detailProperty.adaptListener(detailValueListener);
131
	}
132
133
	protected void firstListenerAdded() {
134
		knownMasterElements = new WritableSet(getRealm());
135
		knownMasterElements.addSetChangeListener(new ISetChangeListener() {
136
			public void handleSetChange(SetChangeEvent event) {
137
				for (Iterator it = event.diff.getRemovals().iterator(); it
138
						.hasNext();) {
139
					detailProperty.addPropertyChangeListener(it.next(),
140
							detailListener);
141
				}
142
				for (Iterator it = event.diff.getAdditions().iterator(); it
143
						.hasNext();) {
144
					detailProperty.removePropertyChangeListener(it.next(),
145
							detailListener);
146
				}
147
			}
148
		});
149
		knownMasterElements.addAll(masterList);
150
		masterList.addListChangeListener(masterListener);
151
	}
152
153
	protected void lastListenerRemoved() {
154
		masterList.removeListChangeListener(masterListener);
155
		if (knownMasterElements != null) {
156
			knownMasterElements.clear();
157
			knownMasterElements.dispose();
158
			knownMasterElements = null;
159
		}
160
	}
161
162
	protected int doGetSize() {
163
		getterCalled();
164
		return masterList.size();
165
	}
166
167
	private void getterCalled() {
168
		ObservableTracker.getterCalled(this);
169
	}
170
171
	public Object getElementType() {
172
		return detailProperty.getValueType();
173
	}
174
175
	public Object get(int index) {
176
		getterCalled();
177
		Object masterElement = masterList.get(index);
178
		return detailProperty.getValue(masterElement);
179
	}
180
181
	public boolean add(Object o) {
182
		throw new UnsupportedOperationException();
183
	}
184
185
	public boolean addAll(Collection c) {
186
		throw new UnsupportedOperationException();
187
	}
188
189
	public boolean addAll(int index, Collection c) {
190
		throw new UnsupportedOperationException();
191
	}
192
193
	public boolean contains(Object o) {
194
		getterCalled();
195
196
		Iterator it;
197
		if (knownMasterElements != null)
198
			it = knownMasterElements.iterator();
199
		else
200
			it = masterList.iterator();
201
		for (; it.hasNext();) {
202
			if (Util.equals(detailProperty.getValue(it.next()), o))
203
				return true;
204
		}
205
		return false;
206
	}
207
208
	public boolean isEmpty() {
209
		getterCalled();
210
		return masterList.isEmpty();
211
	}
212
213
	public boolean isStale() {
214
		getterCalled();
215
		return masterList.isStale();
216
	}
217
218
	public Iterator iterator() {
219
		getterCalled();
220
		return new Iterator() {
221
			Iterator it = masterList.iterator();
222
223
			public boolean hasNext() {
224
				getterCalled();
225
				return it.hasNext();
226
			}
227
228
			public Object next() {
229
				getterCalled();
230
				Object masterElement = it.next();
231
				return detailProperty.getValue(masterElement);
232
			}
233
234
			public void remove() {
235
				throw new UnsupportedOperationException();
236
			}
237
		};
238
	}
239
240
	public Object move(int oldIndex, int newIndex) {
241
		throw new UnsupportedOperationException();
242
	}
243
244
	public boolean remove(Object o) {
245
		throw new UnsupportedOperationException();
246
	}
247
248
	public boolean removeAll(Collection c) {
249
		throw new UnsupportedOperationException();
250
	}
251
252
	public boolean retainAll(Collection c) {
253
		throw new UnsupportedOperationException();
254
	}
255
256
	public Object[] toArray() {
257
		getterCalled();
258
		Object[] masterElements = masterList.toArray();
259
		Object[] result = new Object[masterElements.length];
260
		for (int i = 0; i < result.length; i++) {
261
			result[i] = detailProperty.getValue(masterElements[i]);
262
		}
263
		return result;
264
	}
265
266
	public Object[] toArray(Object[] a) {
267
		getterCalled();
268
		Object[] masterElements = masterList.toArray();
269
		if (a.length < masterElements.length)
270
			a = (Object[]) Array.newInstance(a.getClass().getComponentType(),
271
					masterElements.length);
272
		for (int i = 0; i < masterElements.length; i++) {
273
			a[i] = detailProperty.getValue(masterElements[i]);
274
		}
275
		return a;
276
	}
277
278
	public void add(int index, Object o) {
279
		throw new UnsupportedOperationException();
280
	}
281
282
	public void clear() {
283
		throw new UnsupportedOperationException();
284
	}
285
286
	public ListIterator listIterator() {
287
		return listIterator(0);
288
	}
289
290
	public ListIterator listIterator(final int index) {
291
		getterCalled();
292
		return new ListIterator() {
293
			ListIterator it = masterList.listIterator(index);
294
			Object lastReturned;
295
			boolean haveIterated = false;
296
297
			public void add(Object arg0) {
298
				throw new UnsupportedOperationException();
299
			}
300
301
			public boolean hasNext() {
302
				getterCalled();
303
				return it.hasNext();
304
			}
305
306
			public boolean hasPrevious() {
307
				getterCalled();
308
				return it.hasPrevious();
309
			}
310
311
			public Object next() {
312
				getterCalled();
313
				Object result = lastReturned = detailProperty.getValue(it
314
						.next());
315
				haveIterated = true;
316
				return result;
317
			}
318
319
			public int nextIndex() {
320
				getterCalled();
321
				return it.nextIndex();
322
			}
323
324
			public Object previous() {
325
				getterCalled();
326
				Object result = lastReturned = detailProperty.getValue(it
327
						.previous());
328
				haveIterated = true;
329
				return result;
330
			}
331
332
			public int previousIndex() {
333
				getterCalled();
334
				return it.previousIndex();
335
			}
336
337
			public void remove() {
338
				throw new UnsupportedOperationException();
339
			}
340
341
			public void set(Object o) {
342
				checkRealm();
343
				if (!haveIterated)
344
					throw new IllegalStateException();
345
				// if listeners are registered, the value property listener will
346
				// cause the list change event to fire. otherwise it doesn't
347
				// matter because noone is listening
348
				detailProperty.setValue(lastReturned, o);
349
			}
350
		};
351
	}
352
353
	public Object remove(int index) {
354
		throw new UnsupportedOperationException();
355
	}
356
357
	public Object set(int index, Object o) {
358
		checkRealm();
359
		Object masterElement = masterList.get(index);
360
		Object oldValue = detailProperty.getValue(masterElement);
361
		detailProperty.setValue(masterElement, o);
362
		return oldValue;
363
	}
364
365
	public Object getObserved() {
366
		return masterList;
367
	}
368
369
	public synchronized void dispose() {
370
		if (masterList != null) {
371
			masterList.removeListChangeListener(masterListener);
372
			masterList = null;
373
			masterListener = null;
374
		}
375
		if (knownMasterElements != null) {
376
			knownMasterElements.clear();
377
			knownMasterElements.dispose();
378
			knownMasterElements = null;
379
			detailListener = null;
380
		}
381
		detailProperty = null;
382
		disposed = true;
383
384
		super.dispose();
385
	}
386
}
(-)src/org/eclipse/core/internal/databinding/property/PropertyObservableSet.java (+202 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 (bug 194734)
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.Realm;
21
import org.eclipse.core.databinding.observable.set.AbstractObservableSet;
22
import org.eclipse.core.databinding.property.IProperty;
23
import org.eclipse.core.databinding.property.IPropertyChangeListener;
24
import org.eclipse.core.databinding.property.IPropertyObservable;
25
import org.eclipse.core.databinding.property.ISetProperty;
26
import org.eclipse.core.databinding.property.ISetPropertyChangeListener;
27
import org.eclipse.core.databinding.property.SetPropertyChangeEvent;
28
29
/**
30
 * @since 3.3
31
 * 
32
 */
33
public class PropertyObservableSet extends AbstractObservableSet implements
34
		IPropertyObservable {
35
	private Object source;
36
	private ISetProperty property;
37
38
	private boolean updating = false;
39
40
	private boolean disposed = false;
41
42
	private transient volatile int modCount = 0;
43
44
	private IPropertyChangeListener listener;
45
46
	/**
47
	 * @param realm
48
	 * @param source
49
	 * @param property
50
	 */
51
	public PropertyObservableSet(Realm realm, Object source,
52
			ISetProperty property) {
53
		super(realm);
54
		this.source = source;
55
		this.property = property;
56
57
		ISetPropertyChangeListener setListener = new ISetPropertyChangeListener() {
58
			public void handleSetPropertyChange(
59
					final SetPropertyChangeEvent event) {
60
				if (!disposed && !updating) {
61
					getRealm().exec(new Runnable() {
62
						public void run() {
63
							getRealm().exec(new Runnable() {
64
								public void run() {
65
									modCount++;
66
									fireSetChange(event.diff);
67
								}
68
							});
69
						}
70
					});
71
				}
72
			}
73
		};
74
		listener = property.adaptListener(setListener);
75
	}
76
77
	protected void firstListenerAdded() {
78
		if (!disposed) {
79
			property.addPropertyChangeListener(source, listener);
80
		}
81
	}
82
83
	protected void lastListenerRemoved() {
84
		if (!disposed) {
85
			property.removePropertyChangeListener(source, listener);
86
		}
87
	}
88
89
	protected Set getWrappedSet() {
90
		return property.getSet(source);
91
	}
92
93
	public Object getElementType() {
94
		return property.getElementType();
95
	}
96
97
	// Queries
98
99
	protected int doGetSize() {
100
		return property.size(source);
101
	}
102
103
	// Single change operations
104
105
	public boolean add(Object o) {
106
		checkRealm();
107
		return property.add(source, o);
108
	}
109
110
	public Iterator iterator() {
111
		getterCalled();
112
		return new Iterator() {
113
			int expectedModCount = modCount;
114
			Iterator delegate = new HashSet(property.getSet(source)).iterator();
115
			Object last = null;
116
117
			public boolean hasNext() {
118
				getterCalled();
119
				checkForComodification();
120
				return delegate.hasNext();
121
			}
122
123
			public Object next() {
124
				getterCalled();
125
				checkForComodification();
126
				Object next = delegate.next();
127
				last = next;
128
				return next;
129
			}
130
131
			public void remove() {
132
				checkRealm();
133
				checkForComodification();
134
135
				delegate.remove(); // stay in sync
136
137
				property.remove(source, last);
138
139
				last = null;
140
				expectedModCount = modCount;
141
			}
142
143
			private void checkForComodification() {
144
				if (expectedModCount != modCount)
145
					throw new ConcurrentModificationException();
146
			}
147
		};
148
	}
149
150
	public boolean remove(Object o) {
151
		getterCalled();
152
		return property.remove(source, o);
153
	}
154
155
	// Bulk change operations
156
157
	public boolean addAll(Collection c) {
158
		getterCalled();
159
		return property.addAll(source, c);
160
	}
161
162
	public boolean removeAll(Collection c) {
163
		getterCalled();
164
		return property.removeAll(source, c);
165
	}
166
167
	public boolean retainAll(Collection c) {
168
		getterCalled();
169
		return property.retainAll(source, c);
170
	}
171
172
	public void clear() {
173
		getterCalled();
174
		property.clear(source);
175
	}
176
177
	public boolean equals(Object o) {
178
		return property.equals(source, o);
179
	}
180
181
	public int hashCode() {
182
		return property.hashCode(source);
183
	}
184
185
	public Object getObserved() {
186
		return source;
187
	}
188
189
	public IProperty getProperty() {
190
		return property;
191
	}
192
193
	public synchronized void dispose() {
194
		if (!disposed) {
195
			disposed = true;
196
			property.removePropertyChangeListener(source, listener);
197
			property = null;
198
			source = null;
199
		}
200
		super.dispose();
201
	}
202
}
(-)src/org/eclipse/core/databinding/property/IPropertyChangeListener.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
 * Marker interface for "native" property change listeners which wrap a
16
 * particular property change listener.
17
 * 
18
 * @see IValuePropertyChangeListener
19
 * @see ISetPropertyChangeListener
20
 * @see IListPropertyChangeListener
21
 * @see IMapPropertyChangeListener
22
 * @since 1.2
23
 */
24
public interface IPropertyChangeListener {
25
}
(-)src/org/eclipse/core/databinding/property/CollectionProperty.java (+55 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import java.util.Collection;
15
16
/**
17
 * Abstract implementation of ICollectionProperty.
18
 * 
19
 * @since 1.2
20
 */
21
public abstract class CollectionProperty implements ICollectionProperty {
22
	abstract Collection getCollection(Object source);
23
24
	public boolean contains(Object source, Object o) {
25
		return getCollection(source).contains(o);
26
	}
27
28
	public boolean containsAll(Object source, Collection c) {
29
		return getCollection(source).containsAll(c);
30
	}
31
32
	public boolean equals(Object source, Object o) {
33
		return getCollection(source).equals(o);
34
	}
35
36
	public int hashCode(Object source) {
37
		return getCollection(source).hashCode();
38
	}
39
40
	public boolean isEmpty(Object source) {
41
		return getCollection(source).isEmpty();
42
	}
43
44
	public int size(Object source) {
45
		return getCollection(source).size();
46
	}
47
48
	public Object[] toArray(Object source, Object[] array) {
49
		return getCollection(source).toArray(array);
50
	}
51
52
	public Object[] toArray(Object source) {
53
		return getCollection(source).toArray();
54
	}
55
}
(-)src/org/eclipse/core/internal/databinding/property/SetValuePropertyObservableMap.java (+96 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 (bug 194734)
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.IObserving;
16
import org.eclipse.core.databinding.observable.map.ComputedObservableMap;
17
import org.eclipse.core.databinding.observable.set.IObservableSet;
18
import org.eclipse.core.databinding.property.IPropertyChangeListener;
19
import org.eclipse.core.databinding.property.IValueProperty;
20
import org.eclipse.core.databinding.property.IValuePropertyChangeListener;
21
import org.eclipse.core.databinding.property.ValuePropertyChangeEvent;
22
23
/**
24
 * @since 3.3
25
 * 
26
 */
27
public class SetValuePropertyObservableMap extends ComputedObservableMap
28
		implements IObserving {
29
	private IValueProperty property;
30
31
	private boolean disposed = false;
32
33
	private IPropertyChangeListener listener;
34
35
	/**
36
	 * @param keySet
37
	 * @param valueProperty
38
	 */
39
	public SetValuePropertyObservableMap(IObservableSet keySet,
40
			IValueProperty valueProperty) {
41
		super(keySet);
42
		this.property = valueProperty;
43
44
		IValuePropertyChangeListener valueListener = new IValuePropertyChangeListener() {
45
			public void handleValuePropertyChange(
46
					final ValuePropertyChangeEvent event) {
47
				if (!disposed) {
48
					getRealm().exec(new Runnable() {
49
						public void run() {
50
							Object key = event.getSource();
51
							Object oldValue = event.diff.getOldValue();
52
							Object newValue = event.diff.getNewValue();
53
							fireMapChange(Diffs.createMapDiffSingleChange(key,
54
									oldValue, newValue));
55
						}
56
					});
57
				}
58
			}
59
		};
60
		this.listener = property.adaptListener(valueListener);
61
	}
62
63
	protected Object doGet(Object key) {
64
		return property.getValue(key);
65
	}
66
67
	protected Object doPut(Object key, Object value) {
68
		Object result = property.getValue(key);
69
		property.setValue(key, value);
70
		return result;
71
	}
72
73
	protected void hookListener(Object addedKey) {
74
		if (!disposed)
75
			property.addPropertyChangeListener(addedKey, listener);
76
	}
77
78
	protected void unhookListener(Object removedKey) {
79
		if (!disposed)
80
			property.removePropertyChangeListener(removedKey, listener);
81
	}
82
83
	public Object getObserved() {
84
		return keySet();
85
	}
86
87
	public synchronized void dispose() {
88
		super.dispose();
89
90
		if (!disposed) {
91
			disposed = true;
92
			property = null;
93
			listener = null;
94
		}
95
	}
96
}
(-)src/org/eclipse/core/internal/databinding/property/PropertyObservableValue.java (+120 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 (bug 194734)
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.IProperty;
18
import org.eclipse.core.databinding.property.IPropertyChangeListener;
19
import org.eclipse.core.databinding.property.IPropertyObservable;
20
import org.eclipse.core.databinding.property.IValueProperty;
21
import org.eclipse.core.databinding.property.IValuePropertyChangeListener;
22
import org.eclipse.core.databinding.property.ValuePropertyChangeEvent;
23
import org.eclipse.core.internal.databinding.Util;
24
25
/**
26
 * @since 1.2
27
 * 
28
 */
29
public class PropertyObservableValue extends AbstractObservableValue implements
30
		IPropertyObservable {
31
	private Object source;
32
	private IValueProperty property;
33
34
	private boolean updating = false;
35
36
	private boolean disposed = false;
37
38
	private IPropertyChangeListener listener;
39
40
	/**
41
	 * @param realm
42
	 * @param source
43
	 * @param property
44
	 */
45
	public PropertyObservableValue(Realm realm, Object source,
46
			IValueProperty property) {
47
		super(realm);
48
		this.source = source;
49
		this.property = property;
50
51
		IValuePropertyChangeListener valueListener = new IValuePropertyChangeListener() {
52
			public void handleValuePropertyChange(
53
					final ValuePropertyChangeEvent event) {
54
				if (!disposed && !updating) {
55
					getRealm().exec(new Runnable() {
56
						public void run() {
57
							fireValueChange(event.diff);
58
						}
59
					});
60
				}
61
			}
62
		};
63
		this.listener = property.adaptListener(valueListener);
64
	}
65
66
	protected void firstListenerAdded() {
67
		if (!disposed) {
68
			property.addPropertyChangeListener(source, listener);
69
		}
70
	}
71
72
	protected void lastListenerRemoved() {
73
		if (!disposed) {
74
			property.removePropertyChangeListener(source, listener);
75
		}
76
	}
77
78
	protected Object doGetValue() {
79
		return property.getValue(source);
80
	}
81
82
	protected void doSetValue(Object value) {
83
		Object oldValue = doGetValue();
84
85
		updating = true;
86
		try {
87
			property.setValue(source, value);
88
		} finally {
89
			updating = false;
90
		}
91
92
		Object newValue = doGetValue();
93
		if (!Util.equals(oldValue, newValue)) {
94
			fireValueChange(Diffs.createValueDiff(oldValue, newValue));
95
		}
96
	}
97
98
	public Object getValueType() {
99
		return property.getValueType();
100
	}
101
102
	public Object getObserved() {
103
		return source;
104
	}
105
106
	public IProperty getProperty() {
107
		return property;
108
	}
109
110
	public synchronized void dispose() {
111
		if (!disposed) {
112
			disposed = true;
113
			property.removePropertyChangeListener(source, listener);
114
			property = null;
115
			listener = null;
116
			source = null;
117
		}
118
		super.dispose();
119
	}
120
}
(-)src/org/eclipse/core/databinding/property/IListPropertyChangeListener.java (+27 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
/**
15
 * Listener for changes to list properties on a property source
16
 * 
17
 * @since 1.2
18
 */
19
public interface IListPropertyChangeListener {
20
	/**
21
	 * Handle a change to a list property on a specific property source.
22
	 * 
23
	 * @param event
24
	 *            an event describing the list change that occured.
25
	 */
26
	public void handleListPropertyChange(ListPropertyChangeEvent event);
27
}

Return to bug 194734