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/internal/databinding/beans/BeanValueProperty.java (+178 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 Matthew Hall and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Matthew Hall - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.beans;
13
14
import java.beans.PropertyChangeEvent;
15
import java.beans.PropertyChangeListener;
16
import java.beans.PropertyDescriptor;
17
import java.lang.reflect.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.observable.Diffs;
23
import org.eclipse.core.databinding.property.ValueProperty;
24
import org.eclipse.core.databinding.util.Policy;
25
import org.eclipse.core.internal.databinding.Util;
26
import org.eclipse.core.runtime.IStatus;
27
import org.eclipse.core.runtime.Status;
28
29
/**
30
 * @since 3.3
31
 * 
32
 */
33
public class BeanValueProperty extends ValueProperty {
34
	private PropertyDescriptor propertyDescriptor;
35
	private final boolean attachListener;
36
37
	private boolean updating;
38
39
	private ListenerSupport listenerSupport;
40
41
	/**
42
	 * @param propertyDescriptor
43
	 */
44
	public BeanValueProperty(PropertyDescriptor propertyDescriptor) {
45
		this(propertyDescriptor, true);
46
	}
47
48
	/**
49
	 * @param propertyDescriptor
50
	 * @param attachListener
51
	 */
52
	public BeanValueProperty(PropertyDescriptor propertyDescriptor,
53
			boolean attachListener) {
54
		this.propertyDescriptor = propertyDescriptor;
55
		this.attachListener = attachListener;
56
57
	}
58
59
	protected void addListenerTo(Object source) {
60
		if (attachListener) {
61
			initListenerSupport();
62
			listenerSupport.hookListener(source);
63
		}
64
	}
65
66
	private void initListenerSupport() {
67
		if (listenerSupport == null) {
68
			synchronized (this) {
69
				if (listenerSupport != null) {
70
					PropertyChangeListener propertyChangeListener = new PropertyChangeListener() {
71
						public void propertyChange(PropertyChangeEvent evt) {
72
							if (!updating) {
73
								fireValueChange(evt.getSource(), Diffs
74
										.createValueDiff(evt.getOldValue(), evt
75
												.getNewValue()));
76
							}
77
						}
78
					};
79
					listenerSupport = new ListenerSupport(
80
							propertyChangeListener, propertyDescriptor
81
									.getName());
82
				}
83
			}
84
		}
85
	}
86
87
	protected void removeListenerFrom(Object source) {
88
		if (attachListener && listenerSupport != null) {
89
			listenerSupport.unhookListener(source);
90
		}
91
	}
92
93
	public Object getValueType(Object source) {
94
		return propertyDescriptor.getPropertyType();
95
	}
96
97
	public Object getValue(Object source) {
98
		try {
99
			Method readMethod = propertyDescriptor.getReadMethod();
100
			if (readMethod == null) {
101
				throw new BindingException(propertyDescriptor.getName()
102
						+ " property does not have a read method."); //$NON-NLS-1$
103
			}
104
			if (!readMethod.isAccessible()) {
105
				readMethod.setAccessible(true);
106
			}
107
			return readMethod.invoke(source, null);
108
		} catch (InvocationTargetException e) {
109
			/*
110
			 * InvocationTargetException wraps any exception thrown by the
111
			 * invoked method.
112
			 */
113
			throw new RuntimeException(e.getCause());
114
		} catch (Exception e) {
115
			if (BeansObservables.DEBUG) {
116
				Policy
117
						.getLog()
118
						.log(
119
								new Status(
120
										IStatus.WARNING,
121
										Policy.JFACE_DATABINDING,
122
										IStatus.OK,
123
										"Could not read value of " + source + "." + propertyDescriptor.getName(), e)); //$NON-NLS-1$ //$NON-NLS-2$
124
			}
125
			return null;
126
		}
127
	}
128
129
	public void setValue(Object source, Object value) {
130
		Object oldValue = getValue(source);
131
132
		if (Util.equals(oldValue, value)) {
133
			return;
134
		}
135
136
		updating = true;
137
		try {
138
			Method writeMethod = propertyDescriptor.getWriteMethod();
139
			if (!writeMethod.isAccessible()) {
140
				writeMethod.setAccessible(true);
141
			}
142
			writeMethod.invoke(source, new Object[] { value });
143
		} catch (InvocationTargetException e) {
144
			/*
145
			 * InvocationTargetException wraps any exception thrown by the
146
			 * invoked method.
147
			 */
148
			throw new RuntimeException(e.getCause());
149
		} catch (Exception e) {
150
			if (BeansObservables.DEBUG) {
151
				Policy
152
						.getLog()
153
						.log(
154
								new Status(
155
										IStatus.WARNING,
156
										Policy.JFACE_DATABINDING,
157
										IStatus.OK,
158
										"Could not change value of " + source + "." + propertyDescriptor.getName(), e)); //$NON-NLS-1$ //$NON-NLS-2$
159
			}
160
		} finally {
161
			updating = false;
162
		}
163
164
		Object newValue = getValue(source);
165
		if (!Util.equals(oldValue, newValue)) {
166
			fireValueChange(source, Diffs.createValueDiff(oldValue, newValue));
167
		}
168
	}
169
170
	public synchronized void dispose() {
171
		if (listenerSupport != null) {
172
			listenerSupport.dispose();
173
			listenerSupport = null;
174
		}
175
		propertyDescriptor = null;
176
		super.dispose();
177
	}
178
}
(-)src/org/eclipse/core/databinding/beans/PojoProperties.java (+32 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 Matthew Hall and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Matthew Hall - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.beans;
13
14
import org.eclipse.core.databinding.property.IValueProperty;
15
import org.eclipse.core.internal.databinding.beans.BeanValueProperty;
16
17
/**
18
 * @since 1.2
19
 * 
20
 */
21
public class PojoProperties {
22
	/**
23
	 * @param beanClass
24
	 * @param propertyName
25
	 * @return a bean value property for the given property name.
26
	 */
27
	public static IValueProperty valueProperty(Class beanClass,
28
			String propertyName) {
29
		return new BeanValueProperty(BeansObservables.getPropertyDescriptor(
30
				beanClass, propertyName), false);
31
	}
32
}
(-)src/org/eclipse/core/databinding/beans/BeanProperties.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
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.beans;
13
14
import org.eclipse.core.databinding.property.IValueProperty;
15
import org.eclipse.core.internal.databinding.beans.BeanValueProperty;
16
17
/**
18
 * @since 1.2
19
 * 
20
 */
21
public class BeanProperties {
22
	/**
23
	 * @param beanClass
24
	 * @param propertyName
25
	 * @return a value property for the given property name of the given bean
26
	 *         class.
27
	 */
28
	public static IValueProperty valueProperty(Class beanClass,
29
			String propertyName) {
30
		return new BeanValueProperty(BeansObservables.getPropertyDescriptor(
31
				beanClass, propertyName));
32
	}
33
}
(-)src/org/eclipse/core/databinding/property/ValueProperty.java (+115 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 Matthew Hall and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Matthew Hall - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import java.util.Collections;
15
import java.util.IdentityHashMap;
16
import java.util.Iterator;
17
import java.util.Map;
18
19
import org.eclipse.core.databinding.observable.value.ValueDiff;
20
import org.eclipse.core.runtime.ListenerList;
21
22
/**
23
 * @since 1.2
24
 */
25
public abstract class ValueProperty extends Property implements IValueProperty {
26
	private Map valueChangeListeners;
27
28
	public final void addValueChangeListener(Object source,
29
			IValuePropertyChangeListener listener) {
30
		boolean wasAlreadyListening = isListeningTo(source);
31
32
		if (valueChangeListeners == null) {
33
			synchronized (this) {
34
				if (valueChangeListeners == null) {
35
					valueChangeListeners = Collections
36
							.synchronizedMap(new IdentityHashMap());
37
				}
38
			}
39
		}
40
41
		synchronized (valueChangeListeners) {
42
			if (valueChangeListeners.containsKey(source)) {
43
				ListenerList listeners = (ListenerList) valueChangeListeners
44
						.get(source);
45
				listeners.add(listener);
46
			} else {
47
				ListenerList listeners = new ListenerList();
48
				listeners.add(listener);
49
				valueChangeListeners.put(source, listeners);
50
			}
51
		}
52
53
		if (!wasAlreadyListening)
54
			addListenerTo(source);
55
	}
56
57
	public final void removeValueChangeListener(Object source,
58
			IValuePropertyChangeListener listener) {
59
		if (valueChangeListeners != null) {
60
			ListenerList listeners = (ListenerList) valueChangeListeners
61
					.get(source);
62
			if (listeners != null) {
63
				listeners.remove(listener);
64
				if (listeners.isEmpty()) {
65
					valueChangeListeners.remove(source);
66
					if (!isListeningTo(source)) {
67
						removeListenerFrom(source);
68
					}
69
				}
70
			}
71
		}
72
	}
73
74
	protected boolean isListeningTo(Object source) {
75
		return super.isListeningTo(source)
76
				|| (valueChangeListeners != null && valueChangeListeners
77
						.containsKey(source));
78
	}
79
80
	protected void fireChange(Object source) {
81
		throw new IllegalStateException(
82
				"ValueProperty subclasses must call fireValueChange() instead of fireChange()"); //$NON-NLS-1$
83
	}
84
85
	protected void fireValueChange(Object source, ValueDiff diff) {
86
		super.fireChange(source);
87
		if (valueChangeListeners == null)
88
			return;
89
		ListenerList listenerList = (ListenerList) valueChangeListeners
90
				.get(source);
91
		if (listenerList != null) {
92
			ValuePropertyChangeEvent event = new ValuePropertyChangeEvent(
93
					source, this, diff);
94
			Object[] listeners = listenerList.getListeners();
95
			for (int i = 0; i < listeners.length; i++) {
96
				((IValuePropertyChangeListener) listeners[i])
97
						.handleValuePropertyChange(event);
98
			}
99
		}
100
	}
101
102
	public synchronized void dispose() {
103
		if (valueChangeListeners != null) {
104
			for (Iterator iterator = valueChangeListeners.keySet().iterator(); iterator
105
					.hasNext();) {
106
				Object source = iterator.next();
107
				iterator.remove();
108
				if (!isListeningTo(source))
109
					removeListenerFrom(source);
110
			}
111
			valueChangeListeners = null;
112
		}
113
		super.dispose();
114
	}
115
}
(-)src/org/eclipse/core/databinding/property/IValuePropertyChangeListener.java (+23 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
 * @since 1.2
16
 * 
17
 */
18
public interface IValuePropertyChangeListener {
19
	/**
20
	 * @param event
21
	 */
22
	public void handleValuePropertyChange(ValuePropertyChangeEvent event);
23
}
(-)src/org/eclipse/core/databinding/property/ValuePropertyChangeEvent.java (+57 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 Matthew Hall and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Matthew Hall - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import org.eclipse.core.databinding.observable.value.ValueDiff;
15
16
/**
17
 * @since 1.2
18
 * 
19
 */
20
public class ValuePropertyChangeEvent {
21
	private final Object source;
22
	private final IValueProperty property;
23
	private final ValueDiff diff;
24
25
	/**
26
	 * @param source
27
	 * @param property
28
	 * @param diff
29
	 */
30
	public ValuePropertyChangeEvent(Object source, IValueProperty property,
31
			ValueDiff diff) {
32
		this.source = source;
33
		this.property = property;
34
		this.diff = diff;
35
	}
36
37
	/**
38
	 * @return Returns the source.
39
	 */
40
	public Object getSource() {
41
		return source;
42
	}
43
44
	/**
45
	 * @return Returns the property.
46
	 */
47
	public IValueProperty getProperty() {
48
		return property;
49
	}
50
51
	/**
52
	 * @return Returns the diff.
53
	 */
54
	public ValueDiff getDiff() {
55
		return diff;
56
	}
57
}
(-)src/org/eclipse/core/databinding/property/IPropertyChangeListener.java (+23 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
 * @since 1.2
16
 * 
17
 */
18
public interface IPropertyChangeListener {
19
	/**
20
	 * @param event
21
	 */
22
	public void handlePropertyChange(PropertyChangeEvent event);
23
}
(-)src/org/eclipse/core/databinding/property/PropertyChangeEvent.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
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
/**
15
 * @since 1.2
16
 * 
17
 */
18
public class PropertyChangeEvent {
19
	private final Object source;
20
	private final IProperty property;
21
22
	/**
23
	 * @param source
24
	 * @param property
25
	 */
26
	public PropertyChangeEvent(Object source, IProperty property) {
27
		this.source = source;
28
		this.property = property;
29
30
	}
31
32
	/**
33
	 * @return Returns the source.
34
	 */
35
	public Object getSource() {
36
		return source;
37
	}
38
39
	/**
40
	 * @return Returns the property.
41
	 */
42
	public IProperty getProperty() {
43
		return property;
44
	}
45
}
(-)src/org/eclipse/core/internal/databinding/property/PropertyObservableValue.java (+104 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 Matthew Hall and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Matthew Hall - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.property;
13
14
import org.eclipse.core.databinding.observable.Diffs;
15
import org.eclipse.core.databinding.observable.Realm;
16
import org.eclipse.core.databinding.observable.value.AbstractObservableValue;
17
import org.eclipse.core.databinding.property.IValueProperty;
18
import org.eclipse.core.databinding.property.IValuePropertyChangeListener;
19
import org.eclipse.core.databinding.property.ValuePropertyChangeEvent;
20
import org.eclipse.core.internal.databinding.Util;
21
22
/**
23
 * @since 1.2
24
 * 
25
 */
26
public class PropertyObservableValue extends AbstractObservableValue {
27
	private Object source;
28
	private IValueProperty property;
29
30
	private volatile boolean updating = false;
31
32
	private boolean disposed = false;
33
34
	private IValuePropertyChangeListener listener = new IValuePropertyChangeListener() {
35
		public void handleValuePropertyChange(
36
				final ValuePropertyChangeEvent event) {
37
			if (!disposed && !updating) {
38
				getRealm().exec(new Runnable() {
39
					public void run() {
40
						fireValueChange(event.getDiff());
41
					}
42
				});
43
			}
44
		}
45
	};
46
47
	/**
48
	 * @param realm
49
	 * @param source
50
	 * @param property
51
	 */
52
	public PropertyObservableValue(Realm realm, Object source,
53
			IValueProperty property) {
54
		super(realm);
55
		this.source = source;
56
		this.property = property;
57
	}
58
59
	protected void firstListenerAdded() {
60
		if (!disposed) {
61
			property.addValueChangeListener(source, listener);
62
		}
63
	}
64
65
	protected void lastListenerRemoved() {
66
		if (!disposed) {
67
			property.removeValueChangeListener(source, listener);
68
		}
69
	}
70
71
	protected Object doGetValue() {
72
		return property.getValue(source);
73
	}
74
75
	protected void doSetValue(Object value) {
76
		Object oldValue = doGetValue();
77
78
		updating = true;
79
		try {
80
			property.setValue(source, value);
81
		} finally {
82
			updating = false;
83
		}
84
85
		Object newValue = doGetValue();
86
		if (!Util.equals(oldValue, newValue)) {
87
			fireValueChange(Diffs.createValueDiff(oldValue, newValue));
88
		}
89
	}
90
91
	public Object getValueType() {
92
		return property.getValueType(source);
93
	}
94
95
	public synchronized void dispose() {
96
		if (!disposed) {
97
			disposed = true;
98
			property.removeValueChangeListener(source, listener);
99
			property = null;
100
			source = null;
101
		}
102
		super.dispose();
103
	}
104
}
(-)src/org/eclipse/core/databinding/property/IProperty.java (+52 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 Matthew Hall and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Matthew Hall - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
/**
15
 * Interface for observing a property of a source object.
16
 * 
17
 * @since 1.2
18
 */
19
public interface IProperty {
20
	/**
21
	 * Adds the given change listener to the list of change listeners for the
22
	 * given source object. When this property changes on the source, change
23
	 * listeners are notified in a generic way, without specifying the change
24
	 * that happened. To get the changed state, a change listener needs to query
25
	 * for the current state of this property.
26
	 * 
27
	 * @param source
28
	 *            the object to listen to
29
	 * @param listener
30
	 *            the listener to receive change notifications
31
	 */
32
	public void addChangeListener(Object source,
33
			IPropertyChangeListener listener);
34
35
	/**
36
	 * Removes the given change listener from the list of change listeners for
37
	 * the given source object. Has no effect if the given listener is not
38
	 * registered as a change listener on the source object.
39
	 * 
40
	 * @param source
41
	 *            the object to stop listening to
42
	 * @param listener
43
	 *            the listener currently receiving change notifications
44
	 */
45
	public void removeChangeListener(Object source,
46
			IPropertyChangeListener listener);
47
48
	/**
49
	 * Disposes the property, removing all property listeners on source objects.
50
	 */
51
	public void dispose();
52
}
(-)src/org/eclipse/core/databinding/property/PropertyObservables.java (+80 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 Matthew Hall and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Matthew Hall - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import org.eclipse.core.databinding.observable.IObservable;
15
import org.eclipse.core.databinding.observable.Realm;
16
import org.eclipse.core.databinding.observable.masterdetail.IObservableFactory;
17
import org.eclipse.core.databinding.observable.value.IObservableValue;
18
import org.eclipse.core.internal.databinding.property.PropertyObservableValue;
19
20
/**
21
 * @since 1.2
22
 * 
23
 */
24
public class PropertyObservables {
25
	/**
26
	 * @param source
27
	 * @param property
28
	 * @return an observable value that tracks the given property of the source
29
	 *         object.
30
	 * @since 1.2
31
	 */
32
	public static IObservableValue observeValue(Object source,
33
			IValueProperty property) {
34
		return observeValue(Realm.getDefault(), source, property);
35
	}
36
37
	/**
38
	 * @param realm
39
	 * @param source
40
	 * @param property
41
	 * @return an observable value that tracks the given property of the source
42
	 *         object
43
	 * @since 1.2
44
	 */
45
	public static IObservableValue observeValue(Realm realm, Object source,
46
			IValueProperty property) {
47
		return new PropertyObservableValue(realm, source, property);
48
	}
49
50
	/**
51
	 * Returns a factory for creating obervable values tracking the given
52
	 * property of a particular source object
53
	 * 
54
	 * @param property
55
	 *            the property to be observed
56
	 * @return an observable value factory on
57
	 */
58
	public static IObservableFactory valueFactory(IValueProperty property) {
59
		return valueFactory(Realm.getDefault(), property);
60
	}
61
62
	/**
63
	 * Returns a factory for creating obervable values tracking the given
64
	 * property of a particular source object
65
	 * 
66
	 * @param realm
67
	 *            the realm to use
68
	 * @param property
69
	 *            the property to be observed
70
	 * @return an observable value factory
71
	 */
72
	public static IObservableFactory valueFactory(final Realm realm,
73
			final IValueProperty property) {
74
		return new IObservableFactory() {
75
			public IObservable createObservable(Object target) {
76
				return observeValue(realm, target, property);
77
			}
78
		};
79
	}
80
}
(-)src/org/eclipse/core/databinding/property/Property.java (+106 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 Matthew Hall and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Matthew Hall - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import java.util.Collections;
15
import java.util.IdentityHashMap;
16
import java.util.Iterator;
17
import java.util.Map;
18
19
import org.eclipse.core.runtime.ListenerList;
20
21
/**
22
 * @since 1.2
23
 * 
24
 */
25
public abstract class Property implements IProperty {
26
	private Map changeListeners;
27
28
	public final void addChangeListener(Object source,
29
			IPropertyChangeListener listener) {
30
		boolean wasAlreadyListening = isListeningTo(source);
31
32
		if (changeListeners == null) {
33
			synchronized (this) {
34
				if (changeListeners == null) {
35
					changeListeners = Collections
36
							.synchronizedMap(new IdentityHashMap());
37
				}
38
			}
39
		}
40
41
		synchronized (changeListeners) {
42
			if (changeListeners.containsKey(source)) {
43
				ListenerList listeners = (ListenerList) changeListeners
44
						.get(source);
45
				listeners.add(listener);
46
			} else {
47
				ListenerList listeners = new ListenerList();
48
				listeners.add(listener);
49
				changeListeners.put(source, listeners);
50
			}
51
		}
52
53
		if (!wasAlreadyListening)
54
			addListenerTo(source);
55
	}
56
57
	public final void removeChangeListener(Object source,
58
			IPropertyChangeListener listener) {
59
		if (changeListeners != null) {
60
			ListenerList listeners = (ListenerList) changeListeners.get(source);
61
			if (listeners != null) {
62
				listeners.remove(listener);
63
				if (listeners.isEmpty()) {
64
					changeListeners.remove(source);
65
					if (!isListeningTo(source)) {
66
						removeListenerFrom(source);
67
					}
68
				}
69
			}
70
		}
71
	}
72
73
	protected boolean isListeningTo(Object source) {
74
		return changeListeners != null && changeListeners.containsKey(source);
75
	}
76
77
	protected abstract void addListenerTo(Object source);
78
79
	protected abstract void removeListenerFrom(Object source);
80
81
	protected void fireChange(Object source) {
82
		if (changeListeners == null)
83
			return;
84
		ListenerList listenerList = (ListenerList) changeListeners.get(source);
85
		if (listenerList != null) {
86
			PropertyChangeEvent event = new PropertyChangeEvent(source, this);
87
			Object[] listeners = listenerList.getListeners();
88
			for (int i = 0; i < listeners.length; i++) {
89
				((IPropertyChangeListener) listeners[i])
90
						.handlePropertyChange(event);
91
			}
92
		}
93
	}
94
95
	public synchronized void dispose() {
96
		if (changeListeners != null) {
97
			for (Iterator iterator = changeListeners.keySet().iterator(); iterator.hasNext();) {
98
				Object source = iterator.next();
99
				iterator.remove();
100
				if (!isListeningTo(source))
101
					removeListenerFrom(source);
102
			}
103
			changeListeners = null;
104
		}
105
	}
106
}
(-)src/org/eclipse/core/databinding/property/IValueProperty.java (+51 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 Matthew Hall and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Matthew Hall - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
/**
15
 * Interface for observing a value property of a source object.
16
 * 
17
 * @since 1.2
18
 */
19
public interface IValueProperty extends IProperty {
20
	/**
21
	 * @param source
22
	 * @return the value type
23
	 */
24
	public Object getValueType(Object source);
25
26
	/**
27
	 * @param source
28
	 * @return the property value
29
	 */
30
	public Object getValue(Object source);
31
32
	/**
33
	 * @param source
34
	 * @param value
35
	 */
36
	public void setValue(Object source, Object value);
37
38
	/**
39
	 * @param source
40
	 * @param listener
41
	 */
42
	public void addValueChangeListener(Object source,
43
			IValuePropertyChangeListener listener);
44
45
	/**
46
	 * @param source
47
	 * @param listener
48
	 */
49
	public void removeValueChangeListener(Object source,
50
			IValuePropertyChangeListener listener);
51
}

Return to bug 194734