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/jface/internal/databinding/viewers/ViewerInputProperty.java (-3 / +3 lines)
Lines 13-19 Link Here
13
package org.eclipse.jface.internal.databinding.viewers;
13
package org.eclipse.jface.internal.databinding.viewers;
14
14
15
import org.eclipse.core.databinding.property.INativePropertyListener;
15
import org.eclipse.core.databinding.property.INativePropertyListener;
16
import org.eclipse.core.databinding.property.IPropertyChangeListener;
16
import org.eclipse.core.databinding.property.ISimplePropertyListener;
17
import org.eclipse.jface.viewers.Viewer;
17
import org.eclipse.jface.viewers.Viewer;
18
18
19
/**
19
/**
Lines 33-40 Link Here
33
		((Viewer) source).setInput(value);
33
		((Viewer) source).setInput(value);
34
	}
34
	}
35
35
36
	protected INativePropertyListener adaptListener(
36
	public INativePropertyListener adaptListener(
37
			IPropertyChangeListener listener) {
37
			ISimplePropertyListener listener) {
38
		return null;
38
		return null;
39
	}
39
	}
40
40
(-)src/org/eclipse/jface/internal/databinding/viewers/SelectionProviderSingleSelectionProperty.java (-6 / +6 lines)
Lines 13-20 Link Here
13
package org.eclipse.jface.internal.databinding.viewers;
13
package org.eclipse.jface.internal.databinding.viewers;
14
14
15
import org.eclipse.core.databinding.property.INativePropertyListener;
15
import org.eclipse.core.databinding.property.INativePropertyListener;
16
import org.eclipse.core.databinding.property.IPropertyChangeListener;
16
import org.eclipse.core.databinding.property.ISimplePropertyListener;
17
import org.eclipse.core.databinding.property.PropertyChangeEvent;
17
import org.eclipse.core.databinding.property.SimplePropertyEvent;
18
import org.eclipse.jface.viewers.ISelection;
18
import org.eclipse.jface.viewers.ISelection;
19
import org.eclipse.jface.viewers.ISelectionChangedListener;
19
import org.eclipse.jface.viewers.ISelectionChangedListener;
20
import org.eclipse.jface.viewers.ISelectionProvider;
20
import org.eclipse.jface.viewers.ISelectionProvider;
Lines 47-53 Link Here
47
	}
47
	}
48
48
49
	public INativePropertyListener adaptListener(
49
	public INativePropertyListener adaptListener(
50
			IPropertyChangeListener listener) {
50
			ISimplePropertyListener listener) {
51
		return new SelectionChangedListener(listener);
51
		return new SelectionChangedListener(listener);
52
	}
52
	}
53
53
Lines 65-78 Link Here
65
65
66
	private class SelectionChangedListener implements INativePropertyListener,
66
	private class SelectionChangedListener implements INativePropertyListener,
67
			ISelectionChangedListener {
67
			ISelectionChangedListener {
68
		private IPropertyChangeListener listener;
68
		private ISimplePropertyListener listener;
69
69
70
		private SelectionChangedListener(IPropertyChangeListener listener) {
70
		private SelectionChangedListener(ISimplePropertyListener listener) {
71
			this.listener = listener;
71
			this.listener = listener;
72
		}
72
		}
73
73
74
		public void selectionChanged(SelectionChangedEvent event) {
74
		public void selectionChanged(SelectionChangedEvent event) {
75
			listener.handlePropertyChange(new PropertyChangeEvent(event
75
			listener.handlePropertyChange(new SimplePropertyEvent(event
76
					.getSource(),
76
					.getSource(),
77
					SelectionProviderSingleSelectionProperty.this, null));
77
					SelectionProviderSingleSelectionProperty.this, null));
78
		}
78
		}
(-)src/org/eclipse/jface/internal/databinding/viewers/StructuredViewerFiltersProperty.java (-2 / +2 lines)
Lines 18-24 Link Here
18
18
19
import org.eclipse.core.databinding.observable.set.SetDiff;
19
import org.eclipse.core.databinding.observable.set.SetDiff;
20
import org.eclipse.core.databinding.property.INativePropertyListener;
20
import org.eclipse.core.databinding.property.INativePropertyListener;
21
import org.eclipse.core.databinding.property.IPropertyChangeListener;
21
import org.eclipse.core.databinding.property.ISimplePropertyListener;
22
import org.eclipse.jface.viewers.StructuredViewer;
22
import org.eclipse.jface.viewers.StructuredViewer;
23
import org.eclipse.jface.viewers.ViewerFilter;
23
import org.eclipse.jface.viewers.ViewerFilter;
24
24
Lines 48-54 Link Here
48
	}
48
	}
49
49
50
	public INativePropertyListener adaptListener(
50
	public INativePropertyListener adaptListener(
51
			IPropertyChangeListener listener) {
51
			ISimplePropertyListener listener) {
52
		return null;
52
		return null;
53
	}
53
	}
54
54
(-)src/org/eclipse/jface/internal/databinding/viewers/CheckableCheckedElementsProperty.java (-6 / +6 lines)
Lines 20-27 Link Here
20
import org.eclipse.core.databinding.observable.Diffs;
20
import org.eclipse.core.databinding.observable.Diffs;
21
import org.eclipse.core.databinding.observable.set.SetDiff;
21
import org.eclipse.core.databinding.observable.set.SetDiff;
22
import org.eclipse.core.databinding.property.INativePropertyListener;
22
import org.eclipse.core.databinding.property.INativePropertyListener;
23
import org.eclipse.core.databinding.property.IPropertyChangeListener;
23
import org.eclipse.core.databinding.property.ISimplePropertyListener;
24
import org.eclipse.core.databinding.property.PropertyChangeEvent;
24
import org.eclipse.core.databinding.property.SimplePropertyEvent;
25
import org.eclipse.jface.viewers.CheckStateChangedEvent;
25
import org.eclipse.jface.viewers.CheckStateChangedEvent;
26
import org.eclipse.jface.viewers.ICheckStateListener;
26
import org.eclipse.jface.viewers.ICheckStateListener;
27
import org.eclipse.jface.viewers.ICheckable;
27
import org.eclipse.jface.viewers.ICheckable;
Lines 74-80 Link Here
74
	}
74
	}
75
75
76
	public INativePropertyListener adaptListener(
76
	public INativePropertyListener adaptListener(
77
			IPropertyChangeListener listener) {
77
			ISimplePropertyListener listener) {
78
		return new CheckStateListener(listener);
78
		return new CheckStateListener(listener);
79
	}
79
	}
80
80
Lines 90-98 Link Here
90
90
91
	private class CheckStateListener implements INativePropertyListener,
91
	private class CheckStateListener implements INativePropertyListener,
92
			ICheckStateListener {
92
			ICheckStateListener {
93
		private IPropertyChangeListener listener;
93
		private ISimplePropertyListener listener;
94
94
95
		private CheckStateListener(IPropertyChangeListener listener) {
95
		private CheckStateListener(ISimplePropertyListener listener) {
96
			this.listener = listener;
96
			this.listener = listener;
97
		}
97
		}
98
98
Lines 103-109 Link Here
103
			Set additions = checked ? elementSet : Collections.EMPTY_SET;
103
			Set additions = checked ? elementSet : Collections.EMPTY_SET;
104
			Set removals = checked ? Collections.EMPTY_SET : elementSet;
104
			Set removals = checked ? Collections.EMPTY_SET : elementSet;
105
			SetDiff diff = Diffs.createSetDiff(additions, removals);
105
			SetDiff diff = Diffs.createSetDiff(additions, removals);
106
			listener.handlePropertyChange(new PropertyChangeEvent(event
106
			listener.handlePropertyChange(new SimplePropertyEvent(event
107
					.getSource(), CheckableCheckedElementsProperty.this, diff));
107
					.getSource(), CheckableCheckedElementsProperty.this, diff));
108
		}
108
		}
109
	}
109
	}
(-)src/org/eclipse/jface/internal/databinding/viewers/SelectionProviderMultipleSelectionProperty.java (-6 / +6 lines)
Lines 17-24 Link Here
17
17
18
import org.eclipse.core.databinding.observable.list.ListDiff;
18
import org.eclipse.core.databinding.observable.list.ListDiff;
19
import org.eclipse.core.databinding.property.INativePropertyListener;
19
import org.eclipse.core.databinding.property.INativePropertyListener;
20
import org.eclipse.core.databinding.property.IPropertyChangeListener;
20
import org.eclipse.core.databinding.property.ISimplePropertyListener;
21
import org.eclipse.core.databinding.property.PropertyChangeEvent;
21
import org.eclipse.core.databinding.property.SimplePropertyEvent;
22
import org.eclipse.jface.viewers.ISelection;
22
import org.eclipse.jface.viewers.ISelection;
23
import org.eclipse.jface.viewers.ISelectionChangedListener;
23
import org.eclipse.jface.viewers.ISelectionChangedListener;
24
import org.eclipse.jface.viewers.ISelectionProvider;
24
import org.eclipse.jface.viewers.ISelectionProvider;
Lines 50-56 Link Here
50
	}
50
	}
51
51
52
	public INativePropertyListener adaptListener(
52
	public INativePropertyListener adaptListener(
53
			IPropertyChangeListener listener) {
53
			ISimplePropertyListener listener) {
54
		return new SelectionChangedListener(listener);
54
		return new SelectionChangedListener(listener);
55
	}
55
	}
56
56
Lines 67-80 Link Here
67
67
68
	private class SelectionChangedListener implements INativePropertyListener,
68
	private class SelectionChangedListener implements INativePropertyListener,
69
			ISelectionChangedListener {
69
			ISelectionChangedListener {
70
		private IPropertyChangeListener listener;
70
		private ISimplePropertyListener listener;
71
71
72
		private SelectionChangedListener(IPropertyChangeListener listener) {
72
		private SelectionChangedListener(ISimplePropertyListener listener) {
73
			this.listener = listener;
73
			this.listener = listener;
74
		}
74
		}
75
75
76
		public void selectionChanged(SelectionChangedEvent event) {
76
		public void selectionChanged(SelectionChangedEvent event) {
77
			listener.handlePropertyChange(new PropertyChangeEvent(event
77
			listener.handlePropertyChange(new SimplePropertyEvent(event
78
					.getSource(),
78
					.getSource(),
79
					SelectionProviderMultipleSelectionProperty.this, null));
79
					SelectionProviderMultipleSelectionProperty.this, null));
80
		}
80
		}
(-)src/org/eclipse/jface/internal/databinding/swt/ControlStringListProperty.java (-2 / +2 lines)
Lines 17-23 Link Here
17
17
18
import org.eclipse.core.databinding.observable.list.ListDiff;
18
import org.eclipse.core.databinding.observable.list.ListDiff;
19
import org.eclipse.core.databinding.property.INativePropertyListener;
19
import org.eclipse.core.databinding.property.INativePropertyListener;
20
import org.eclipse.core.databinding.property.IPropertyChangeListener;
20
import org.eclipse.core.databinding.property.ISimplePropertyListener;
21
import org.eclipse.swt.widgets.Control;
21
import org.eclipse.swt.widgets.Control;
22
22
23
/**
23
/**
Lines 44-50 Link Here
44
	abstract String[] doGetStringList(Control control);
44
	abstract String[] doGetStringList(Control control);
45
45
46
	public INativePropertyListener adaptListener(
46
	public INativePropertyListener adaptListener(
47
			IPropertyChangeListener listener) {
47
			ISimplePropertyListener listener) {
48
		return null;
48
		return null;
49
	}
49
	}
50
50
(-)src/org/eclipse/jface/internal/databinding/swt/WidgetValueProperty.java (-7 / +7 lines)
Lines 14-21 Link Here
14
import org.eclipse.core.databinding.observable.Realm;
14
import org.eclipse.core.databinding.observable.Realm;
15
import org.eclipse.core.databinding.observable.value.IObservableValue;
15
import org.eclipse.core.databinding.observable.value.IObservableValue;
16
import org.eclipse.core.databinding.property.INativePropertyListener;
16
import org.eclipse.core.databinding.property.INativePropertyListener;
17
import org.eclipse.core.databinding.property.IPropertyChangeListener;
17
import org.eclipse.core.databinding.property.ISimplePropertyListener;
18
import org.eclipse.core.databinding.property.PropertyChangeEvent;
18
import org.eclipse.core.databinding.property.SimplePropertyEvent;
19
import org.eclipse.core.databinding.property.value.SimpleValueProperty;
19
import org.eclipse.core.databinding.property.value.SimpleValueProperty;
20
import org.eclipse.jface.databinding.swt.ISWTObservableValue;
20
import org.eclipse.jface.databinding.swt.ISWTObservableValue;
21
import org.eclipse.jface.databinding.swt.SWTObservables;
21
import org.eclipse.jface.databinding.swt.SWTObservables;
Lines 39-46 Link Here
39
		this.events = events;
39
		this.events = events;
40
	}
40
	}
41
41
42
	protected INativePropertyListener adaptListener(
42
	public INativePropertyListener adaptListener(
43
			IPropertyChangeListener listener) {
43
			ISimplePropertyListener listener) {
44
		return new WidgetListener(listener);
44
		return new WidgetListener(listener);
45
	}
45
	}
46
46
Lines 70-83 Link Here
70
	}
70
	}
71
71
72
	private class WidgetListener implements INativePropertyListener, Listener {
72
	private class WidgetListener implements INativePropertyListener, Listener {
73
		private final IPropertyChangeListener listener;
73
		private final ISimplePropertyListener listener;
74
74
75
		protected WidgetListener(IPropertyChangeListener listener) {
75
		protected WidgetListener(ISimplePropertyListener listener) {
76
			this.listener = listener;
76
			this.listener = listener;
77
		}
77
		}
78
78
79
		public void handleEvent(Event event) {
79
		public void handleEvent(Event event) {
80
			listener.handlePropertyChange(new PropertyChangeEvent(event.widget,
80
			listener.handlePropertyChange(new SimplePropertyEvent(event.widget,
81
					WidgetValueProperty.this, null));
81
					WidgetValueProperty.this, null));
82
		}
82
		}
83
	}
83
	}
(-)src/org/eclipse/jface/examples/databinding/snippets/Snippet026AnonymousBeanProperties.java (-7 / +7 lines)
Lines 26-33 Link Here
26
import org.eclipse.core.databinding.observable.set.SetDiff;
26
import org.eclipse.core.databinding.observable.set.SetDiff;
27
import org.eclipse.core.databinding.observable.value.IObservableValue;
27
import org.eclipse.core.databinding.observable.value.IObservableValue;
28
import org.eclipse.core.databinding.property.INativePropertyListener;
28
import org.eclipse.core.databinding.property.INativePropertyListener;
29
import org.eclipse.core.databinding.property.IPropertyChangeListener;
29
import org.eclipse.core.databinding.property.ISimplePropertyListener;
30
import org.eclipse.core.databinding.property.PropertyChangeEvent;
30
import org.eclipse.core.databinding.property.SimplePropertyEvent;
31
import org.eclipse.core.databinding.property.set.DelegatingSetProperty;
31
import org.eclipse.core.databinding.property.set.DelegatingSetProperty;
32
import org.eclipse.core.databinding.property.set.ISetProperty;
32
import org.eclipse.core.databinding.property.set.ISetProperty;
33
import org.eclipse.core.databinding.property.set.SimpleSetProperty;
33
import org.eclipse.core.databinding.property.set.SimpleSetProperty;
Lines 242-262 Link Here
242
			}
242
			}
243
		}
243
		}
244
244
245
		protected INativePropertyListener adaptListener(
245
		public INativePropertyListener adaptListener(
246
				final IPropertyChangeListener listener) {
246
				final ISimplePropertyListener listener) {
247
			return new Listener(listener);
247
			return new Listener(listener);
248
		}
248
		}
249
249
250
		private class Listener implements INativePropertyListener,
250
		private class Listener implements INativePropertyListener,
251
				PropertyChangeListener {
251
				PropertyChangeListener {
252
			private final IPropertyChangeListener listener;
252
			private final ISimplePropertyListener listener;
253
253
254
			Listener(IPropertyChangeListener listener) {
254
			Listener(ISimplePropertyListener listener) {
255
				this.listener = listener;
255
				this.listener = listener;
256
			}
256
			}
257
257
258
			public void propertyChange(java.beans.PropertyChangeEvent evt) {
258
			public void propertyChange(java.beans.PropertyChangeEvent evt) {
259
				listener.handlePropertyChange(new PropertyChangeEvent(evt
259
				listener.handlePropertyChange(new SimplePropertyEvent(evt
260
						.getSource(), ContactGroupContactsProperty.this, null));
260
						.getSource(), ContactGroupContactsProperty.this, null));
261
			}
261
			}
262
		}
262
		}
(-)src/org/eclipse/core/internal/databinding/beans/BeanSetProperty.java (-6 / +6 lines)
Lines 23-30 Link Here
23
import org.eclipse.core.databinding.observable.Diffs;
23
import org.eclipse.core.databinding.observable.Diffs;
24
import org.eclipse.core.databinding.observable.set.SetDiff;
24
import org.eclipse.core.databinding.observable.set.SetDiff;
25
import org.eclipse.core.databinding.property.INativePropertyListener;
25
import org.eclipse.core.databinding.property.INativePropertyListener;
26
import org.eclipse.core.databinding.property.IPropertyChangeListener;
26
import org.eclipse.core.databinding.property.ISimplePropertyListener;
27
import org.eclipse.core.databinding.property.PropertyChangeEvent;
27
import org.eclipse.core.databinding.property.SimplePropertyEvent;
28
import org.eclipse.core.databinding.property.set.SimpleSetProperty;
28
import org.eclipse.core.databinding.property.set.SimpleSetProperty;
29
29
30
/**
30
/**
Lines 82-96 Link Here
82
	}
82
	}
83
83
84
	public INativePropertyListener adaptListener(
84
	public INativePropertyListener adaptListener(
85
			final IPropertyChangeListener listener) {
85
			final ISimplePropertyListener listener) {
86
		return new Listener(listener);
86
		return new Listener(listener);
87
	}
87
	}
88
88
89
	private class Listener implements INativePropertyListener,
89
	private class Listener implements INativePropertyListener,
90
			PropertyChangeListener {
90
			PropertyChangeListener {
91
		private final IPropertyChangeListener listener;
91
		private final ISimplePropertyListener listener;
92
92
93
		private Listener(IPropertyChangeListener listener) {
93
		private Listener(ISimplePropertyListener listener) {
94
			this.listener = listener;
94
			this.listener = listener;
95
		}
95
		}
96
96
Lines 104-110 Link Here
104
				diff = null;
104
				diff = null;
105
			}
105
			}
106
			if (propertyDescriptor.getName().equals(evt.getPropertyName())) {
106
			if (propertyDescriptor.getName().equals(evt.getPropertyName())) {
107
				listener.handlePropertyChange(new PropertyChangeEvent(evt
107
				listener.handlePropertyChange(new SimplePropertyEvent(evt
108
						.getSource(), BeanSetProperty.this, diff));
108
						.getSource(), BeanSetProperty.this, diff));
109
			}
109
			}
110
		}
110
		}
(-)src/org/eclipse/core/internal/databinding/beans/PojoValueProperty.java (-2 / +2 lines)
Lines 15-21 Link Here
15
import java.beans.PropertyDescriptor;
15
import java.beans.PropertyDescriptor;
16
16
17
import org.eclipse.core.databinding.property.INativePropertyListener;
17
import org.eclipse.core.databinding.property.INativePropertyListener;
18
import org.eclipse.core.databinding.property.IPropertyChangeListener;
18
import org.eclipse.core.databinding.property.ISimplePropertyListener;
19
import org.eclipse.core.databinding.property.value.SimpleValueProperty;
19
import org.eclipse.core.databinding.property.value.SimpleValueProperty;
20
20
21
/**
21
/**
Lines 52-58 Link Here
52
	}
52
	}
53
53
54
	public INativePropertyListener adaptListener(
54
	public INativePropertyListener adaptListener(
55
			IPropertyChangeListener listener) {
55
			ISimplePropertyListener listener) {
56
		return null;
56
		return null;
57
	}
57
	}
58
58
(-)src/org/eclipse/core/internal/databinding/beans/PojoSetProperty.java (-2 / +2 lines)
Lines 21-27 Link Here
21
21
22
import org.eclipse.core.databinding.observable.set.SetDiff;
22
import org.eclipse.core.databinding.observable.set.SetDiff;
23
import org.eclipse.core.databinding.property.INativePropertyListener;
23
import org.eclipse.core.databinding.property.INativePropertyListener;
24
import org.eclipse.core.databinding.property.IPropertyChangeListener;
24
import org.eclipse.core.databinding.property.ISimplePropertyListener;
25
import org.eclipse.core.databinding.property.set.SimpleSetProperty;
25
import org.eclipse.core.databinding.property.set.SimpleSetProperty;
26
26
27
/**
27
/**
Lines 79-85 Link Here
79
	}
79
	}
80
80
81
	public INativePropertyListener adaptListener(
81
	public INativePropertyListener adaptListener(
82
			IPropertyChangeListener listener) {
82
			ISimplePropertyListener listener) {
83
		return null;
83
		return null;
84
	}
84
	}
85
85
(-)src/org/eclipse/core/internal/databinding/beans/BeanListProperty.java (-7 / +7 lines)
Lines 22-29 Link Here
22
import org.eclipse.core.databinding.observable.Diffs;
22
import org.eclipse.core.databinding.observable.Diffs;
23
import org.eclipse.core.databinding.observable.list.ListDiff;
23
import org.eclipse.core.databinding.observable.list.ListDiff;
24
import org.eclipse.core.databinding.property.INativePropertyListener;
24
import org.eclipse.core.databinding.property.INativePropertyListener;
25
import org.eclipse.core.databinding.property.IPropertyChangeListener;
25
import org.eclipse.core.databinding.property.ISimplePropertyListener;
26
import org.eclipse.core.databinding.property.PropertyChangeEvent;
26
import org.eclipse.core.databinding.property.SimplePropertyEvent;
27
import org.eclipse.core.databinding.property.list.SimpleListProperty;
27
import org.eclipse.core.databinding.property.list.SimpleListProperty;
28
28
29
/**
29
/**
Lines 81-96 Link Here
81
		return propertyValue;
81
		return propertyValue;
82
	}
82
	}
83
83
84
	protected INativePropertyListener adaptListener(
84
	public INativePropertyListener adaptListener(
85
			final IPropertyChangeListener listener) {
85
			final ISimplePropertyListener listener) {
86
		return new Listener(listener);
86
		return new Listener(listener);
87
	}
87
	}
88
88
89
	private class Listener implements INativePropertyListener,
89
	private class Listener implements INativePropertyListener,
90
			PropertyChangeListener {
90
			PropertyChangeListener {
91
		private final IPropertyChangeListener listener;
91
		private final ISimplePropertyListener listener;
92
92
93
		private Listener(IPropertyChangeListener listener) {
93
		private Listener(ISimplePropertyListener listener) {
94
			this.listener = listener;
94
			this.listener = listener;
95
		}
95
		}
96
96
Lines 105-111 Link Here
105
				} else {
105
				} else {
106
					diff = null;
106
					diff = null;
107
				}
107
				}
108
				listener.handlePropertyChange(new PropertyChangeEvent(evt
108
				listener.handlePropertyChange(new SimplePropertyEvent(evt
109
						.getSource(), BeanListProperty.this, diff));
109
						.getSource(), BeanListProperty.this, diff));
110
			}
110
			}
111
		}
111
		}
(-)src/org/eclipse/core/internal/databinding/beans/PojoMapProperty.java (-2 / +2 lines)
Lines 18-24 Link Here
18
18
19
import org.eclipse.core.databinding.observable.map.MapDiff;
19
import org.eclipse.core.databinding.observable.map.MapDiff;
20
import org.eclipse.core.databinding.property.INativePropertyListener;
20
import org.eclipse.core.databinding.property.INativePropertyListener;
21
import org.eclipse.core.databinding.property.IPropertyChangeListener;
21
import org.eclipse.core.databinding.property.ISimplePropertyListener;
22
import org.eclipse.core.databinding.property.map.SimpleMapProperty;
22
import org.eclipse.core.databinding.property.map.SimpleMapProperty;
23
23
24
/**
24
/**
Lines 66-72 Link Here
66
	}
66
	}
67
67
68
	public INativePropertyListener adaptListener(
68
	public INativePropertyListener adaptListener(
69
			IPropertyChangeListener listener) {
69
			ISimplePropertyListener listener) {
70
		return null;
70
		return null;
71
	}
71
	}
72
72
(-)src/org/eclipse/core/internal/databinding/beans/BeanMapProperty.java (-6 / +6 lines)
Lines 20-27 Link Here
20
import org.eclipse.core.databinding.observable.Diffs;
20
import org.eclipse.core.databinding.observable.Diffs;
21
import org.eclipse.core.databinding.observable.map.MapDiff;
21
import org.eclipse.core.databinding.observable.map.MapDiff;
22
import org.eclipse.core.databinding.property.INativePropertyListener;
22
import org.eclipse.core.databinding.property.INativePropertyListener;
23
import org.eclipse.core.databinding.property.IPropertyChangeListener;
23
import org.eclipse.core.databinding.property.ISimplePropertyListener;
24
import org.eclipse.core.databinding.property.PropertyChangeEvent;
24
import org.eclipse.core.databinding.property.SimplePropertyEvent;
25
import org.eclipse.core.databinding.property.map.SimpleMapProperty;
25
import org.eclipse.core.databinding.property.map.SimpleMapProperty;
26
26
27
/**
27
/**
Lines 69-83 Link Here
69
	}
69
	}
70
70
71
	public INativePropertyListener adaptListener(
71
	public INativePropertyListener adaptListener(
72
			final IPropertyChangeListener listener) {
72
			final ISimplePropertyListener listener) {
73
		return new Listener(listener);
73
		return new Listener(listener);
74
	}
74
	}
75
75
76
	private class Listener implements INativePropertyListener,
76
	private class Listener implements INativePropertyListener,
77
			PropertyChangeListener {
77
			PropertyChangeListener {
78
		private final IPropertyChangeListener listener;
78
		private final ISimplePropertyListener listener;
79
79
80
		private Listener(IPropertyChangeListener listener) {
80
		private Listener(ISimplePropertyListener listener) {
81
			this.listener = listener;
81
			this.listener = listener;
82
		}
82
		}
83
83
Lines 92-98 Link Here
92
				} else {
92
				} else {
93
					diff = null;
93
					diff = null;
94
				}
94
				}
95
				listener.handlePropertyChange(new PropertyChangeEvent(evt
95
				listener.handlePropertyChange(new SimplePropertyEvent(evt
96
						.getSource(), BeanMapProperty.this, diff));
96
						.getSource(), BeanMapProperty.this, diff));
97
			}
97
			}
98
		}
98
		}
(-)src/org/eclipse/core/internal/databinding/beans/PojoListProperty.java (-2 / +2 lines)
Lines 20-26 Link Here
20
20
21
import org.eclipse.core.databinding.observable.list.ListDiff;
21
import org.eclipse.core.databinding.observable.list.ListDiff;
22
import org.eclipse.core.databinding.property.INativePropertyListener;
22
import org.eclipse.core.databinding.property.INativePropertyListener;
23
import org.eclipse.core.databinding.property.IPropertyChangeListener;
23
import org.eclipse.core.databinding.property.ISimplePropertyListener;
24
import org.eclipse.core.databinding.property.list.SimpleListProperty;
24
import org.eclipse.core.databinding.property.list.SimpleListProperty;
25
25
26
/**
26
/**
Lines 79-85 Link Here
79
	}
79
	}
80
80
81
	public INativePropertyListener adaptListener(
81
	public INativePropertyListener adaptListener(
82
			IPropertyChangeListener listener) {
82
			ISimplePropertyListener listener) {
83
		return null;
83
		return null;
84
	}
84
	}
85
85
(-)src/org/eclipse/core/internal/databinding/beans/BeanValueProperty.java (-6 / +6 lines)
Lines 18-25 Link Here
18
import org.eclipse.core.databinding.observable.Diffs;
18
import org.eclipse.core.databinding.observable.Diffs;
19
import org.eclipse.core.databinding.observable.value.ValueDiff;
19
import org.eclipse.core.databinding.observable.value.ValueDiff;
20
import org.eclipse.core.databinding.property.INativePropertyListener;
20
import org.eclipse.core.databinding.property.INativePropertyListener;
21
import org.eclipse.core.databinding.property.IPropertyChangeListener;
21
import org.eclipse.core.databinding.property.ISimplePropertyListener;
22
import org.eclipse.core.databinding.property.PropertyChangeEvent;
22
import org.eclipse.core.databinding.property.SimplePropertyEvent;
23
import org.eclipse.core.databinding.property.value.SimpleValueProperty;
23
import org.eclipse.core.databinding.property.value.SimpleValueProperty;
24
24
25
/**
25
/**
Lines 54-68 Link Here
54
	}
54
	}
55
55
56
	public INativePropertyListener adaptListener(
56
	public INativePropertyListener adaptListener(
57
			final IPropertyChangeListener listener) {
57
			final ISimplePropertyListener listener) {
58
		return new Listener(listener);
58
		return new Listener(listener);
59
	}
59
	}
60
60
61
	private class Listener implements INativePropertyListener,
61
	private class Listener implements INativePropertyListener,
62
			PropertyChangeListener {
62
			PropertyChangeListener {
63
		private final IPropertyChangeListener listener;
63
		private final ISimplePropertyListener listener;
64
64
65
		private Listener(IPropertyChangeListener listener) {
65
		private Listener(ISimplePropertyListener listener) {
66
			this.listener = listener;
66
			this.listener = listener;
67
		}
67
		}
68
68
Lines 76-82 Link Here
76
				} else {
76
				} else {
77
					diff = null;
77
					diff = null;
78
				}
78
				}
79
				listener.handlePropertyChange(new PropertyChangeEvent(evt
79
				listener.handlePropertyChange(new SimplePropertyEvent(evt
80
						.getSource(), BeanValueProperty.this, diff));
80
						.getSource(), BeanValueProperty.this, diff));
81
			}
81
			}
82
		}
82
		}
(-)src/org/eclipse/core/databinding/property/map/SimpleMapProperty.java (-39 / +23 lines)
Lines 15-25 Link Here
15
import java.util.Collections;
15
import java.util.Collections;
16
import java.util.Map;
16
import java.util.Map;
17
17
18
import org.eclipse.core.databinding.observable.IDiff;
18
import org.eclipse.core.databinding.observable.Realm;
19
import org.eclipse.core.databinding.observable.Realm;
19
import org.eclipse.core.databinding.observable.map.IObservableMap;
20
import org.eclipse.core.databinding.observable.map.IObservableMap;
20
import org.eclipse.core.databinding.observable.map.MapDiff;
21
import org.eclipse.core.databinding.observable.map.MapDiff;
21
import org.eclipse.core.databinding.property.INativePropertyListener;
22
import org.eclipse.core.databinding.property.INativePropertyListener;
22
import org.eclipse.core.databinding.property.IPropertyChangeListener;
23
import org.eclipse.core.databinding.property.ISimplePropertyListener;
24
import org.eclipse.core.internal.databinding.property.map.SimpleMapPropertyObservableMap;
23
25
24
/**
26
/**
25
 * Simplified abstract implementation of IMapProperty. This class takes care of
27
 * Simplified abstract implementation of IMapProperty. This class takes care of
Lines 32-38 Link Here
32
 * <li> {@link #getValueType()}
34
 * <li> {@link #getValueType()}
33
 * <li> {@link #doGetMap(Object)}
35
 * <li> {@link #doGetMap(Object)}
34
 * <li> {@link #doSetMap(Object, Map, MapDiff)}
36
 * <li> {@link #doSetMap(Object, Map, MapDiff)}
35
 * <li> {@link #adaptListener(IPropertyChangeListener)}
37
 * <li> {@link #adaptListener(ISimplePropertyListener)}
36
 * <li> {@link #doAddListener(Object, INativePropertyListener)}
38
 * <li> {@link #doAddListener(Object, INativePropertyListener)}
37
 * <li> {@link #doRemoveListener(Object, INativePropertyListener)}
39
 * <li> {@link #doRemoveListener(Object, INativePropertyListener)}
38
 * </ul>
40
 * </ul>
Lines 43-65 Link Here
43
 * @since 1.2
45
 * @since 1.2
44
 */
46
 */
45
public abstract class SimpleMapProperty extends MapProperty implements
47
public abstract class SimpleMapProperty extends MapProperty implements
46
		IMapProperty {
48
		ISimpleMapProperty {
47
	public IObservableMap observe(Realm realm, Object source) {
49
	public IObservableMap observe(Realm realm, Object source) {
48
		return new SimpleMapPropertyObservableMap(realm, source, this);
50
		return new SimpleMapPropertyObservableMap(realm, source, this);
49
	}
51
	}
50
52
51
	// Accessors
53
	// Accessors
52
54
53
	/**
55
	public final Object get(Object source) {
54
	 * Returns an unmodifiable Map with the current contents of the source's map
55
	 * property.
56
	 * 
57
	 * @param source
58
	 *            the property source
59
	 * @return a Map with the current contents of the source's map property
60
	 * @noreference This method is not intended to be referenced by clients.
61
	 */
62
	protected final Map getMap(Object source) {
63
		if (source == null)
56
		if (source == null)
64
			return Collections.EMPTY_MAP;
57
			return Collections.EMPTY_MAP;
65
		return Collections.unmodifiableMap(doGetMap(source));
58
		return Collections.unmodifiableMap(doGetMap(source));
Lines 77-96 Link Here
77
70
78
	// Mutators
71
	// Mutators
79
72
80
	/**
73
	public final void set(Object source, Object value, IDiff diff) {
81
	 * Updates the property on the source with the specified change.
74
		Map map = (Map) value;
82
	 * 
75
		MapDiff mapDiff = (MapDiff) diff;
83
	 * @param source
76
		if (source != null && !mapDiff.isEmpty())
84
	 *            the property source
77
			doSetMap(source, map, mapDiff);
85
	 * @param map
86
	 *            the new map
87
	 * @param diff
88
	 *            a diff describing the change
89
	 * @noreference This method is not intended to be referenced by clients.
90
	 */
91
	protected final void setMap(Object source, Map map, MapDiff diff) {
92
		if (source != null && !diff.isEmpty())
93
			doSetMap(source, map, diff);
94
	}
78
	}
95
79
96
	/**
80
	/**
Lines 124-146 Link Here
124
	 *             ISetProperty or IMapProperty) depending on the property.
108
	 *             ISetProperty or IMapProperty) depending on the property.
125
	 * @noreference This method is not intended to be referenced by clients.
109
	 * @noreference This method is not intended to be referenced by clients.
126
	 */
110
	 */
127
	protected abstract INativePropertyListener adaptListener(
111
	public abstract INativePropertyListener adaptListener(
128
			IPropertyChangeListener listener);
112
			ISimplePropertyListener listener);
129
113
130
	/**
114
	/**
131
	 * Adds the specified listener as a listener for this property on the
115
	 * Adds the specified listener as a listener for this property on the
132
	 * specified property source. If the source object has no listener API for
116
	 * specified property source. If the source object has no listener API for
133
	 * this property (i.e. {@link #adaptListener(IPropertyChangeListener)}
117
	 * this property (i.e. {@link #adaptListener(ISimplePropertyListener)}
134
	 * returns null), this method does nothing.
118
	 * returns null), this method does nothing.
135
	 * 
119
	 * 
136
	 * @param source
120
	 * @param source
137
	 *            the property source
121
	 *            the property source
138
	 * @param listener
122
	 * @param listener
139
	 *            a listener obtained from calling
123
	 *            a listener obtained from calling
140
	 *            {@link #adaptListener(IPropertyChangeListener)} .
124
	 *            {@link #adaptListener(ISimplePropertyListener)} .
141
	 * @noreference This method is not intended to be referenced by clients.
125
	 * @noreference This method is not intended to be referenced by clients.
142
	 */
126
	 */
143
	protected final void addListener(Object source,
127
	public final void addListener(Object source,
144
			INativePropertyListener listener) {
128
			INativePropertyListener listener) {
145
		if (source != null)
129
		if (source != null)
146
			doAddListener(source, listener);
130
			doAddListener(source, listener);
Lines 149-162 Link Here
149
	/**
133
	/**
150
	 * Adds the specified listener as a listener for this property on the
134
	 * Adds the specified listener as a listener for this property on the
151
	 * specified property source. If the source object has no listener API for
135
	 * specified property source. If the source object has no listener API for
152
	 * this property (i.e. {@link #adaptListener(IPropertyChangeListener)}
136
	 * this property (i.e. {@link #adaptListener(ISimplePropertyListener)}
153
	 * returns null), this method does nothing.
137
	 * returns null), this method does nothing.
154
	 * 
138
	 * 
155
	 * @param source
139
	 * @param source
156
	 *            the property source
140
	 *            the property source
157
	 * @param listener
141
	 * @param listener
158
	 *            a listener obtained from calling
142
	 *            a listener obtained from calling
159
	 *            {@link #adaptListener(IPropertyChangeListener)} .
143
	 *            {@link #adaptListener(ISimplePropertyListener)} .
160
	 * @noreference This method is not intended to be referenced by clients.
144
	 * @noreference This method is not intended to be referenced by clients.
161
	 */
145
	 */
162
	protected abstract void doAddListener(Object source,
146
	protected abstract void doAddListener(Object source,
Lines 165-181 Link Here
165
	/**
149
	/**
166
	 * Removes the specified listener as a listener for this property on the
150
	 * Removes the specified listener as a listener for this property on the
167
	 * specified property source. If the source object has no listener API for
151
	 * specified property source. If the source object has no listener API for
168
	 * this property (i.e. {@link #adaptListener(IPropertyChangeListener)}
152
	 * this property (i.e. {@link #adaptListener(ISimplePropertyListener)}
169
	 * returns null), this method does nothing.
153
	 * returns null), this method does nothing.
170
	 * 
154
	 * 
171
	 * @param source
155
	 * @param source
172
	 *            the property source
156
	 *            the property source
173
	 * @param listener
157
	 * @param listener
174
	 *            a listener obtained from calling
158
	 *            a listener obtained from calling
175
	 *            {@link #adaptListener(IPropertyChangeListener)} .
159
	 *            {@link #adaptListener(ISimplePropertyListener)} .
176
	 * @noreference This method is not intended to be referenced by clients.
160
	 * @noreference This method is not intended to be referenced by clients.
177
	 */
161
	 */
178
	protected final void removeListener(Object source,
162
	public final void removeListener(Object source,
179
			INativePropertyListener listener) {
163
			INativePropertyListener listener) {
180
		if (source != null)
164
		if (source != null)
181
			doRemoveListener(source, listener);
165
			doRemoveListener(source, listener);
Lines 184-197 Link Here
184
	/**
168
	/**
185
	 * Removes the specified listener as a listener for this property on the
169
	 * Removes the specified listener as a listener for this property on the
186
	 * specified property source. If the source object has no listener API for
170
	 * specified property source. If the source object has no listener API for
187
	 * this property (i.e. {@link #adaptListener(IPropertyChangeListener)}
171
	 * this property (i.e. {@link #adaptListener(ISimplePropertyListener)}
188
	 * returns null), this method does nothing.
172
	 * returns null), this method does nothing.
189
	 * 
173
	 * 
190
	 * @param source
174
	 * @param source
191
	 *            the property source
175
	 *            the property source
192
	 * @param listener
176
	 * @param listener
193
	 *            a listener obtained from calling
177
	 *            a listener obtained from calling
194
	 *            {@link #adaptListener(IPropertyChangeListener)} .
178
	 *            {@link #adaptListener(ISimplePropertyListener)} .
195
	 * @noreference This method is not intended to be referenced by clients.
179
	 * @noreference This method is not intended to be referenced by clients.
196
	 */
180
	 */
197
	protected abstract void doRemoveListener(Object source,
181
	protected abstract void doRemoveListener(Object source,
(-)src/org/eclipse/core/databinding/property/map/DelegatingMapProperty.java (-4 / +22 lines)
Lines 18-24 Link Here
18
import org.eclipse.core.databinding.observable.map.IObservableMap;
18
import org.eclipse.core.databinding.observable.map.IObservableMap;
19
import org.eclipse.core.databinding.observable.map.MapDiff;
19
import org.eclipse.core.databinding.observable.map.MapDiff;
20
import org.eclipse.core.databinding.property.INativePropertyListener;
20
import org.eclipse.core.databinding.property.INativePropertyListener;
21
import org.eclipse.core.databinding.property.IPropertyChangeListener;
21
import org.eclipse.core.databinding.property.ISimplePropertyListener;
22
22
23
/**
23
/**
24
 * @since 1.2
24
 * @since 1.2
Lines 38-44 Link Here
38
		this.valueType = valueType;
38
		this.valueType = valueType;
39
	}
39
	}
40
40
41
	protected final IMapProperty getDelegate(Object source) {
41
	/**
42
	 * Returns the property to delegate to for the specified source object.
43
	 * Repeated calls to this method with the same source object returns the
44
	 * same delegate instance.
45
	 * 
46
	 * @param source
47
	 *            the property source (may be null)
48
	 * @return the property to delegate to for the specified source object.
49
	 */
50
	public final IMapProperty getDelegate(Object source) {
42
		if (source == null)
51
		if (source == null)
43
			return null;
52
			return null;
44
		IMapProperty delegate = doGetDelegate(source);
53
		IMapProperty delegate = doGetDelegate(source);
Lines 47-52 Link Here
47
		return delegate;
56
		return delegate;
48
	}
57
	}
49
58
59
	/**
60
	 * Returns the property to delegate to for the specified source object.
61
	 * Implementers must ensure that repeated calls to this method with the same
62
	 * source object returns the same delegate instance.
63
	 * 
64
	 * @param source
65
	 *            the property source
66
	 * @return the property to delegate to for the specified source object.
67
	 */
50
	protected abstract IMapProperty doGetDelegate(Object source);
68
	protected abstract IMapProperty doGetDelegate(Object source);
51
69
52
	public Object getKeyType() {
70
	public Object getKeyType() {
Lines 69-76 Link Here
69
		protected void doSetMap(Object source, Map map, MapDiff diff) {
87
		protected void doSetMap(Object source, Map map, MapDiff diff) {
70
		}
88
		}
71
89
72
		protected INativePropertyListener adaptListener(
90
		public INativePropertyListener adaptListener(
73
				IPropertyChangeListener listener) {
91
				ISimplePropertyListener listener) {
74
			return null;
92
			return null;
75
		}
93
		}
76
94
(-)src/org/eclipse/core/databinding/property/map/SimpleMapPropertyObservableMap.java (-296 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 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property.map;
13
14
import java.util.AbstractSet;
15
import java.util.Collection;
16
import java.util.Collections;
17
import java.util.ConcurrentModificationException;
18
import java.util.HashMap;
19
import java.util.HashSet;
20
import java.util.Iterator;
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.ObservableTracker;
26
import org.eclipse.core.databinding.observable.Realm;
27
import org.eclipse.core.databinding.observable.map.AbstractObservableMap;
28
import org.eclipse.core.databinding.observable.map.MapDiff;
29
import org.eclipse.core.databinding.property.INativePropertyListener;
30
import org.eclipse.core.databinding.property.IProperty;
31
import org.eclipse.core.databinding.property.IPropertyChangeListener;
32
import org.eclipse.core.databinding.property.IPropertyObservable;
33
import org.eclipse.core.databinding.property.PropertyChangeEvent;
34
35
/**
36
 * @since 1.2
37
 */
38
class SimpleMapPropertyObservableMap extends AbstractObservableMap implements
39
		IPropertyObservable {
40
	private Object source;
41
	private SimpleMapProperty property;
42
43
	private volatile boolean updating = false;
44
45
	private volatile int modCount = 0;
46
47
	private INativePropertyListener listener;
48
49
	private Map cachedMap;
50
51
	/**
52
	 * @param realm
53
	 * @param source
54
	 * @param property
55
	 */
56
	public SimpleMapPropertyObservableMap(Realm realm, Object source,
57
			SimpleMapProperty property) {
58
		super(realm);
59
		this.source = source;
60
		this.property = property;
61
	}
62
63
	public Object getKeyType() {
64
		return property.getKeyType();
65
	}
66
67
	public Object getValueType() {
68
		return property.getValueType();
69
	}
70
71
	private void getterCalled() {
72
		ObservableTracker.getterCalled(this);
73
	}
74
75
	protected void firstListenerAdded() {
76
		if (!isDisposed()) {
77
			cachedMap = new HashMap(this);
78
79
			if (listener == null) {
80
				listener = property
81
						.adaptListener(new IPropertyChangeListener() {
82
							public void handlePropertyChange(
83
									final PropertyChangeEvent event) {
84
								modCount++;
85
								if (!isDisposed() && !updating) {
86
									getRealm().exec(new Runnable() {
87
										public void run() {
88
											notifyIfChanged((MapDiff) event.diff);
89
										}
90
									});
91
								}
92
							}
93
						});
94
			}
95
			property.addListener(source, listener);
96
		}
97
	}
98
99
	protected void lastListenerRemoved() {
100
		if (listener != null) {
101
			property.removeListener(source, listener);
102
		}
103
104
		cachedMap.clear();
105
		cachedMap = null;
106
	}
107
108
	// Queries
109
110
	private Map getMap() {
111
		return property.getMap(source);
112
	}
113
114
	// Single change operations
115
116
	private EntrySet es = new EntrySet();
117
118
	public Set entrySet() {
119
		getterCalled();
120
		return es;
121
	}
122
123
	private class EntrySet extends AbstractSet {
124
		public Iterator iterator() {
125
			return new EntrySetIterator();
126
		}
127
128
		public int size() {
129
			return getMap().size();
130
		}
131
	}
132
133
	private class EntrySetIterator implements Iterator {
134
		private volatile int expectedModCount = modCount;
135
		Map map = new HashMap(getMap());
136
		Iterator iterator = map.entrySet().iterator();
137
		Map.Entry last = null;
138
139
		public boolean hasNext() {
140
			getterCalled();
141
			checkForComodification();
142
			return iterator.hasNext();
143
		}
144
145
		public Object next() {
146
			getterCalled();
147
			checkForComodification();
148
			last = (Map.Entry) iterator.next();
149
			return last;
150
		}
151
152
		public void remove() {
153
			getterCalled();
154
			checkForComodification();
155
156
			iterator.remove(); // stay in sync
157
			MapDiff diff = Diffs.createMapDiffSingleRemove(last.getKey(), last
158
					.getValue());
159
160
			boolean wasUpdating = updating;
161
			updating = true;
162
			try {
163
				property.setMap(source, map, diff);
164
			} finally {
165
				updating = wasUpdating;
166
			}
167
168
			notifyIfChanged(null);
169
170
			last = null;
171
			expectedModCount = modCount;
172
		}
173
174
		private void checkForComodification() {
175
			if (expectedModCount != modCount)
176
				throw new ConcurrentModificationException();
177
		}
178
	}
179
180
	public Set keySet() {
181
		getterCalled();
182
		// AbstractMap depends on entrySet() to fulfil keySet() API, so all
183
		// getterCalled() and comodification checks will still be handled
184
		return super.keySet();
185
	}
186
187
	public Object put(Object key, Object value) {
188
		checkRealm();
189
190
		Map map = new HashMap(getMap());
191
192
		boolean add = !map.containsKey(key);
193
194
		Object oldValue = map.put(key, value);
195
196
		MapDiff diff;
197
		if (add)
198
			diff = Diffs.createMapDiffSingleAdd(key, value);
199
		else
200
			diff = Diffs.createMapDiffSingleChange(key, oldValue, value);
201
202
		boolean wasUpdating = updating;
203
		updating = true;
204
		try {
205
			property.setMap(source, map, diff);
206
			modCount++;
207
		} finally {
208
			updating = wasUpdating;
209
		}
210
211
		notifyIfChanged(null);
212
213
		return oldValue;
214
	}
215
216
	public void putAll(Map m) {
217
		checkRealm();
218
219
		Map map = new HashMap(getMap());
220
221
		Map oldValues = new HashMap();
222
		Map newValues = new HashMap();
223
		Set changedKeys = new HashSet();
224
		Set addedKeys = new HashSet();
225
		for (Iterator it = m.entrySet().iterator(); it.hasNext();) {
226
			Map.Entry entry = (Entry) it.next();
227
			Object key = entry.getKey();
228
			Object newValue = entry.getValue();
229
			if (map.containsKey(key)) {
230
				changedKeys.add(key);
231
				oldValues.put(key, map.get(key));
232
			} else {
233
				addedKeys.add(key);
234
			}
235
			map.put(key, newValue);
236
237
			newValues.put(key, newValue);
238
		}
239
240
		MapDiff diff = Diffs.createMapDiff(addedKeys, Collections.EMPTY_SET,
241
				changedKeys, oldValues, newValues);
242
243
		boolean wasUpdating = updating;
244
		updating = true;
245
		try {
246
			property.setMap(source, map, diff);
247
			modCount++;
248
		} finally {
249
			updating = wasUpdating;
250
		}
251
252
		notifyIfChanged(null);
253
	}
254
255
	public Object remove(Object key) {
256
		checkRealm();
257
		return super.remove(key);
258
	}
259
260
	public Collection values() {
261
		getterCalled();
262
		// AbstractMap depends on entrySet() to fulfil values() API, so all
263
		// getterCalled() and comodification checks will still be handled
264
		return super.values();
265
	}
266
267
	private void notifyIfChanged(MapDiff diff) {
268
		if (hasListeners()) {
269
			Map oldMap = cachedMap;
270
			Map newMap = cachedMap = property.getMap(source);
271
			if (diff == null)
272
				diff = Diffs.computeMapDiff(oldMap, newMap);
273
			if (!diff.isEmpty())
274
				fireMapChange(diff);
275
		}
276
	}
277
278
	public Object getObserved() {
279
		return source;
280
	}
281
282
	public IProperty getProperty() {
283
		return property;
284
	}
285
286
	public synchronized void dispose() {
287
		if (!isDisposed()) {
288
			if (listener != null)
289
				property.removeListener(source, listener);
290
			property = null;
291
			source = null;
292
			listener = null;
293
		}
294
		super.dispose();
295
	}
296
}
(-)src/org/eclipse/core/databinding/property/value/ObservableSetDelegatingValuePropertyObservableMap.java (-235 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 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property.value;
13
14
import java.util.AbstractSet;
15
import java.util.Collections;
16
import java.util.HashMap;
17
import java.util.Iterator;
18
import java.util.Map;
19
import java.util.Set;
20
21
import org.eclipse.core.databinding.observable.Diffs;
22
import org.eclipse.core.databinding.observable.IObserving;
23
import org.eclipse.core.databinding.observable.IStaleListener;
24
import org.eclipse.core.databinding.observable.ObservableTracker;
25
import org.eclipse.core.databinding.observable.StaleEvent;
26
import org.eclipse.core.databinding.observable.map.AbstractObservableMap;
27
import org.eclipse.core.databinding.observable.map.MapDiff;
28
import org.eclipse.core.databinding.observable.set.IObservableSet;
29
import org.eclipse.core.databinding.observable.set.ISetChangeListener;
30
import org.eclipse.core.databinding.observable.set.SetChangeEvent;
31
import org.eclipse.core.databinding.observable.set.SetDiff;
32
import org.eclipse.core.internal.databinding.Util;
33
34
/**
35
 * @since 1.2
36
 */
37
class ObservableSetDelegatingValuePropertyObservableMap extends
38
		AbstractObservableMap implements IObserving {
39
	private IObservableSet masterSet;
40
	private DelegatingValueProperty detailProperty;
41
	private DelegatingCache cache;
42
43
	private Set entrySet;
44
45
	class EntrySet extends AbstractSet {
46
		public Iterator iterator() {
47
			return new Iterator() {
48
				final Iterator it = masterSet.iterator();
49
50
				public boolean hasNext() {
51
					return it.hasNext();
52
				}
53
54
				public Object next() {
55
					return new MapEntry(it.next());
56
				}
57
58
				public void remove() {
59
					it.remove();
60
				}
61
			};
62
		}
63
64
		public int size() {
65
			return masterSet.size();
66
		}
67
	}
68
69
	class MapEntry implements Map.Entry {
70
		private final Object key;
71
72
		MapEntry(Object key) {
73
			this.key = key;
74
		}
75
76
		public Object getKey() {
77
			getterCalled();
78
			return key;
79
		}
80
81
		public Object getValue() {
82
			getterCalled();
83
84
			if (!masterSet.contains(key))
85
				return null;
86
87
			return cache.get(key);
88
		}
89
90
		public Object setValue(Object value) {
91
			checkRealm();
92
93
			if (!masterSet.contains(key))
94
				return null;
95
96
			return cache.put(key, value);
97
		}
98
99
		public boolean equals(Object o) {
100
			getterCalled();
101
			if (o == this)
102
				return true;
103
			if (o == null)
104
				return false;
105
			if (!(o instanceof Map.Entry))
106
				return false;
107
			Map.Entry that = (Map.Entry) o;
108
			return Util.equals(this.getKey(), that.getKey())
109
					&& Util.equals(this.getValue(), that.getValue());
110
		}
111
112
		public int hashCode() {
113
			getterCalled();
114
			Object value = getValue();
115
			return (key == null ? 0 : key.hashCode())
116
					^ (value == null ? 0 : value.hashCode());
117
		}
118
	}
119
120
	private ISetChangeListener masterListener = new ISetChangeListener() {
121
		public void handleSetChange(SetChangeEvent event) {
122
			if (isDisposed())
123
				return;
124
125
			cache.addAll(masterSet);
126
127
			// Need both obsolete and new elements to convert diff
128
			MapDiff diff = convertDiff(event.diff);
129
130
			cache.retainAll(masterSet);
131
132
			fireMapChange(diff);
133
		}
134
135
		private MapDiff convertDiff(SetDiff diff) {
136
			// Convert diff to detail value
137
			Map oldValues = new HashMap();
138
			Map newValues = new HashMap();
139
140
			for (Iterator it = diff.getRemovals().iterator(); it.hasNext();) {
141
				Object masterElement = it.next();
142
				oldValues.put(masterElement, cache.get(masterElement));
143
			}
144
			for (Iterator it = diff.getAdditions().iterator(); it.hasNext();) {
145
				Object masterElement = it.next();
146
				newValues.put(masterElement, cache.get(masterElement));
147
			}
148
			return Diffs.createMapDiff(diff.getAdditions(), diff.getRemovals(),
149
					Collections.EMPTY_SET, oldValues, newValues);
150
		}
151
	};
152
153
	private IStaleListener staleListener = new IStaleListener() {
154
		public void handleStale(StaleEvent staleEvent) {
155
			fireStale();
156
		}
157
	};
158
159
	/**
160
	 * @param keySet
161
	 * @param valueProperty
162
	 */
163
	public ObservableSetDelegatingValuePropertyObservableMap(
164
			IObservableSet keySet, DelegatingValueProperty valueProperty) {
165
		super(keySet.getRealm());
166
		this.masterSet = keySet;
167
		this.detailProperty = valueProperty;
168
		this.cache = new DelegatingCache(getRealm(), valueProperty) {
169
			void handleValueChange(Object masterElement, Object oldValue,
170
					Object newValue) {
171
				fireMapChange(Diffs.createMapDiffSingleChange(masterElement,
172
						oldValue, newValue));
173
			}
174
		};
175
		cache.addAll(masterSet);
176
177
		masterSet.addSetChangeListener(masterListener);
178
		masterSet.addStaleListener(staleListener);
179
	}
180
181
	public Set entrySet() {
182
		getterCalled();
183
		if (entrySet == null)
184
			entrySet = new EntrySet();
185
		return entrySet;
186
	}
187
188
	private void getterCalled() {
189
		ObservableTracker.getterCalled(this);
190
	}
191
192
	public Object get(Object key) {
193
		getterCalled();
194
		return cache.get(key);
195
	}
196
197
	public Object put(Object key, Object value) {
198
		checkRealm();
199
		return cache.put(key, value);
200
	}
201
202
	public boolean isStale() {
203
		return masterSet.isStale();
204
	}
205
206
	public Object getObserved() {
207
		return masterSet;
208
	}
209
210
	public Object getKeyType() {
211
		return masterSet.getElementType();
212
	}
213
214
	public Object getValueType() {
215
		return detailProperty.getValueType();
216
	}
217
218
	public synchronized void dispose() {
219
		if (masterSet != null) {
220
			masterSet.removeSetChangeListener(masterListener);
221
			masterSet.removeStaleListener(staleListener);
222
			masterSet = null;
223
		}
224
225
		if (cache != null) {
226
			cache.dispose();
227
			cache = null;
228
		}
229
230
		masterListener = null;
231
		detailProperty = null;
232
233
		super.dispose();
234
	}
235
}
(-)src/org/eclipse/core/databinding/property/value/DelegatingCache.java (-208 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 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.value;
13
14
import java.util.Collection;
15
import java.util.Collections;
16
import java.util.HashMap;
17
import java.util.HashSet;
18
import java.util.Iterator;
19
import java.util.Map;
20
import java.util.Set;
21
22
import org.eclipse.core.databinding.observable.Realm;
23
import org.eclipse.core.databinding.observable.map.IMapChangeListener;
24
import org.eclipse.core.databinding.observable.map.IObservableMap;
25
import org.eclipse.core.databinding.observable.map.MapChangeEvent;
26
import org.eclipse.core.databinding.observable.set.IObservableSet;
27
import org.eclipse.core.databinding.observable.set.ISetChangeListener;
28
import org.eclipse.core.databinding.observable.set.SetChangeEvent;
29
import org.eclipse.core.databinding.observable.set.WritableSet;
30
import org.eclipse.core.internal.databinding.IdentityWrapper;
31
import org.eclipse.core.internal.databinding.Util;
32
33
/**
34
 * @since 3.3
35
 * 
36
 */
37
abstract class DelegatingCache {
38
	private Realm realm;
39
	private DelegatingValueProperty detailProperty;
40
	private IObservableSet elements;
41
	private Map delegateCaches;
42
43
	private class DelegateCache implements IMapChangeListener {
44
		private final IValueProperty delegate;
45
		private final IObservableSet masterElements;
46
		private final IObservableMap masterElementValues;
47
		private final Map cachedValues;
48
49
		DelegateCache(IValueProperty delegate) {
50
			this.delegate = delegate;
51
			this.masterElements = new WritableSet(realm, Collections.EMPTY_SET,
52
					elements.getElementType());
53
			this.masterElementValues = delegate.observeDetail(masterElements);
54
			this.cachedValues = new HashMap();
55
56
			masterElementValues.addMapChangeListener(this);
57
		}
58
59
		void add(Object masterElement) {
60
			boolean wasEmpty = masterElements.isEmpty();
61
62
			masterElements.add(masterElement);
63
			cachedValues.put(new IdentityWrapper(masterElement),
64
					masterElementValues.get(masterElement));
65
66
			if (wasEmpty)
67
				delegateCaches.put(delegate, this);
68
		}
69
70
		void remove(Object masterElement) {
71
			cachedValues.remove(new IdentityWrapper(masterElement));
72
			masterElements.remove(masterElement);
73
			if (cachedValues.isEmpty())
74
				dispose();
75
		}
76
77
		Object get(Object masterElement) {
78
			return cachedValues.get(new IdentityWrapper(masterElement));
79
		}
80
81
		Object put(Object masterElement, Object detailValue) {
82
			Object oldValue = masterElementValues.put(masterElement,
83
					detailValue);
84
			notifyIfChanged(masterElement);
85
			return oldValue;
86
		}
87
88
		boolean containsValue(Object detailValue) {
89
			return cachedValues.containsValue(detailValue);
90
		}
91
92
		public void handleMapChange(MapChangeEvent event) {
93
			Set changedKeys = event.diff.getChangedKeys();
94
			for (Iterator it = changedKeys.iterator(); it.hasNext();)
95
				notifyIfChanged(it.next());
96
		}
97
98
		private void notifyIfChanged(Object masterElement) {
99
			Object oldValue = cachedValues.get(new IdentityWrapper(
100
					masterElement));
101
			Object newValue = masterElementValues.get(masterElement);
102
			if (!Util.equals(oldValue, newValue)) {
103
				cachedValues.put(new IdentityWrapper(masterElement), newValue);
104
				handleValueChange(masterElement, oldValue, newValue);
105
			}
106
		}
107
108
		void handleValueChange(Object masterElement, Object oldValue,
109
				Object newValue) {
110
			DelegatingCache.this.handleValueChange(masterElement, oldValue,
111
					newValue);
112
		}
113
114
		void dispose() {
115
			delegateCaches.remove(delegate);
116
			masterElementValues.dispose();
117
			masterElements.dispose();
118
			cachedValues.clear();
119
		}
120
	}
121
122
	DelegatingCache(Realm realm, DelegatingValueProperty detailProperty) {
123
		this.realm = realm;
124
		this.detailProperty = detailProperty;
125
126
		this.elements = new WritableSet(realm);
127
		this.delegateCaches = new HashMap();
128
129
		elements.addSetChangeListener(new ISetChangeListener() {
130
			public void handleSetChange(SetChangeEvent event) {
131
				for (Iterator it = event.diff.getRemovals().iterator(); it
132
						.hasNext();) {
133
					IdentityWrapper wrapper = (IdentityWrapper) it.next();
134
					Object element = wrapper.unwrap();
135
					getCache(element).remove(element);
136
137
				}
138
				for (Iterator it = event.diff.getAdditions().iterator(); it
139
						.hasNext();) {
140
					IdentityWrapper wrapper = (IdentityWrapper) it.next();
141
					Object element = wrapper.unwrap();
142
					getCache(element).add(element);
143
				}
144
			}
145
		});
146
	}
147
148
	private DelegateCache getCache(Object masterElement) {
149
		IValueProperty delegate = detailProperty.getDelegate(masterElement);
150
		if (delegateCaches.containsKey(delegate)) {
151
			return (DelegateCache) delegateCaches.get(delegate);
152
		}
153
		return new DelegateCache(delegate);
154
	}
155
156
	Object get(Object element) {
157
		return getCache(element).get(element);
158
	}
159
160
	Object put(Object element, Object value) {
161
		return getCache(element).put(element, value);
162
	}
163
164
	boolean contains(Object value) {
165
		for (Iterator it = delegateCaches.values().iterator(); it.hasNext();) {
166
			DelegateCache cache = (DelegateCache) it.next();
167
			if (cache.containsValue(value))
168
				return true;
169
		}
170
		return false;
171
	}
172
173
	private Set identitySet(Collection elements) {
174
		Set result = new HashSet();
175
		for (Iterator it = elements.iterator(); it.hasNext();) {
176
			result.add(new IdentityWrapper(it.next()));
177
		}
178
		return result;
179
	}
180
181
	void addAll(Collection elements) {
182
		this.elements.addAll(identitySet(elements));
183
	}
184
185
	void retainAll(Collection elements) {
186
		this.elements.retainAll(identitySet(elements));
187
	}
188
189
	abstract void handleValueChange(Object masterElement, Object oldValue,
190
			Object newValue);
191
192
	void dispose() {
193
		if (elements != null) {
194
			elements.clear(); // clears caches
195
			elements.dispose();
196
			elements = null;
197
		}
198
199
		if (delegateCaches != null) {
200
			for (Iterator it = delegateCaches.values().iterator(); it.hasNext();) {
201
				DelegateCache cache = (DelegateCache) it.next();
202
				cache.dispose();
203
			}
204
			delegateCaches.clear();
205
			delegateCaches = null;
206
		}
207
	}
208
}
(-)src/org/eclipse/core/databinding/property/value/ObservableListSimpleValuePropertyObservableList.java (-443 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 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property.value;
13
14
import java.lang.reflect.Array;
15
import java.util.ArrayList;
16
import java.util.Collection;
17
import java.util.HashMap;
18
import java.util.HashSet;
19
import java.util.Iterator;
20
import java.util.List;
21
import java.util.ListIterator;
22
import java.util.Map;
23
import java.util.Set;
24
25
import org.eclipse.core.databinding.observable.Diffs;
26
import org.eclipse.core.databinding.observable.IObserving;
27
import org.eclipse.core.databinding.observable.IStaleListener;
28
import org.eclipse.core.databinding.observable.ObservableTracker;
29
import org.eclipse.core.databinding.observable.StaleEvent;
30
import org.eclipse.core.databinding.observable.list.AbstractObservableList;
31
import org.eclipse.core.databinding.observable.list.IListChangeListener;
32
import org.eclipse.core.databinding.observable.list.IObservableList;
33
import org.eclipse.core.databinding.observable.list.ListChangeEvent;
34
import org.eclipse.core.databinding.observable.list.ListDiff;
35
import org.eclipse.core.databinding.observable.list.ListDiffEntry;
36
import org.eclipse.core.databinding.observable.set.IObservableSet;
37
import org.eclipse.core.databinding.observable.set.ISetChangeListener;
38
import org.eclipse.core.databinding.observable.set.SetChangeEvent;
39
import org.eclipse.core.databinding.observable.set.WritableSet;
40
import org.eclipse.core.databinding.property.INativePropertyListener;
41
import org.eclipse.core.databinding.property.IPropertyChangeListener;
42
import org.eclipse.core.databinding.property.PropertyChangeEvent;
43
import org.eclipse.core.internal.databinding.IdentityWrapper;
44
import org.eclipse.core.internal.databinding.Util;
45
46
/**
47
 * @since 1.2
48
 */
49
class ObservableListSimpleValuePropertyObservableList extends
50
		AbstractObservableList implements IObserving {
51
	private IObservableList masterList;
52
	private SimpleValueProperty detailProperty;
53
54
	private IObservableSet knownMasterElements;
55
	private Map cachedValues;
56
57
	private boolean updating;
58
59
	private IListChangeListener masterListener = new IListChangeListener() {
60
		public void handleListChange(ListChangeEvent event) {
61
			if (!isDisposed()) {
62
				updateKnownElements();
63
				fireListChange(convertDiff(event.diff));
64
			}
65
		}
66
67
		private void updateKnownElements() {
68
			Set identityKnownElements = new HashSet();
69
			for (Iterator it = masterList.iterator(); it.hasNext();) {
70
				identityKnownElements.add(new IdentityWrapper(it.next()));
71
			}
72
73
			knownMasterElements.retainAll(identityKnownElements);
74
			knownMasterElements.addAll(identityKnownElements);
75
		}
76
77
		private ListDiff convertDiff(ListDiff diff) {
78
			// Convert diff to detail value
79
			ListDiffEntry[] masterEntries = diff.getDifferences();
80
			ListDiffEntry[] detailEntries = new ListDiffEntry[masterEntries.length];
81
			for (int i = 0; i < masterEntries.length; i++) {
82
				ListDiffEntry masterDifference = masterEntries[i];
83
				int index = masterDifference.getPosition();
84
				boolean addition = masterDifference.isAddition();
85
				Object masterElement = masterDifference.getElement();
86
				Object elementDetailValue = detailProperty
87
						.getValue(masterElement);
88
				detailEntries[i] = Diffs.createListDiffEntry(index, addition,
89
						elementDetailValue);
90
			}
91
			return Diffs.createListDiff(detailEntries);
92
		}
93
	};
94
95
	private IStaleListener staleListener = new IStaleListener() {
96
		public void handleStale(StaleEvent staleEvent) {
97
			fireStale();
98
		}
99
	};
100
101
	private INativePropertyListener detailListener;
102
103
	/**
104
	 * @param masterList
105
	 * @param valueProperty
106
	 */
107
	public ObservableListSimpleValuePropertyObservableList(
108
			IObservableList masterList, SimpleValueProperty valueProperty) {
109
		super(masterList.getRealm());
110
		this.masterList = masterList;
111
		this.detailProperty = valueProperty;
112
113
		IPropertyChangeListener listener = new IPropertyChangeListener() {
114
			public void handlePropertyChange(PropertyChangeEvent event) {
115
				if (!isDisposed() && !updating) {
116
					notifyIfChanged(event.getSource());
117
				}
118
			}
119
		};
120
		this.detailListener = detailProperty.adaptListener(listener);
121
	}
122
123
	protected void firstListenerAdded() {
124
		knownMasterElements = new WritableSet(getRealm());
125
		cachedValues = new HashMap();
126
		knownMasterElements.addSetChangeListener(new ISetChangeListener() {
127
			public void handleSetChange(SetChangeEvent event) {
128
				for (Iterator it = event.diff.getRemovals().iterator(); it
129
						.hasNext();) {
130
					IdentityWrapper wrapper = (IdentityWrapper) it.next();
131
					Object key = wrapper.unwrap();
132
					detailProperty.removeListener(key, detailListener);
133
					cachedValues.remove(wrapper);
134
				}
135
				for (Iterator it = event.diff.getAdditions().iterator(); it
136
						.hasNext();) {
137
					IdentityWrapper wrapper = (IdentityWrapper) it.next();
138
					Object key = wrapper.unwrap();
139
					cachedValues.put(wrapper, detailProperty.getValue(key));
140
					detailProperty.addListener(key, detailListener);
141
				}
142
			}
143
		});
144
		for (Iterator it = masterList.iterator(); it.hasNext();) {
145
			knownMasterElements.add(new IdentityWrapper(it.next()));
146
		}
147
148
		masterList.addListChangeListener(masterListener);
149
		masterList.addStaleListener(staleListener);
150
	}
151
152
	protected void lastListenerRemoved() {
153
		masterList.removeListChangeListener(masterListener);
154
		masterList.removeStaleListener(staleListener);
155
		if (knownMasterElements != null) {
156
			knownMasterElements.clear(); // clears cachedValues
157
			knownMasterElements.dispose();
158
			knownMasterElements = null;
159
		}
160
		cachedValues.clear();
161
		cachedValues = null;
162
	}
163
164
	protected int doGetSize() {
165
		getterCalled();
166
		return masterList.size();
167
	}
168
169
	private void getterCalled() {
170
		ObservableTracker.getterCalled(this);
171
	}
172
173
	public Object getElementType() {
174
		return detailProperty.getValueType();
175
	}
176
177
	public Object get(int index) {
178
		getterCalled();
179
		Object masterElement = masterList.get(index);
180
		return detailProperty.getValue(masterElement);
181
	}
182
183
	public boolean add(Object o) {
184
		throw new UnsupportedOperationException();
185
	}
186
187
	public boolean addAll(Collection c) {
188
		throw new UnsupportedOperationException();
189
	}
190
191
	public boolean addAll(int index, Collection c) {
192
		throw new UnsupportedOperationException();
193
	}
194
195
	public boolean contains(Object o) {
196
		getterCalled();
197
198
		for (Iterator it = masterList.iterator(); it.hasNext();) {
199
			if (Util.equals(detailProperty.getValue(it.next()), o))
200
				return true;
201
		}
202
		return false;
203
	}
204
205
	public boolean isEmpty() {
206
		getterCalled();
207
		return masterList.isEmpty();
208
	}
209
210
	public boolean isStale() {
211
		getterCalled();
212
		return masterList.isStale();
213
	}
214
215
	public Iterator iterator() {
216
		getterCalled();
217
		return new Iterator() {
218
			Iterator it = masterList.iterator();
219
220
			public boolean hasNext() {
221
				getterCalled();
222
				return it.hasNext();
223
			}
224
225
			public Object next() {
226
				getterCalled();
227
				Object masterElement = it.next();
228
				return detailProperty.getValue(masterElement);
229
			}
230
231
			public void remove() {
232
				throw new UnsupportedOperationException();
233
			}
234
		};
235
	}
236
237
	public Object move(int oldIndex, int newIndex) {
238
		throw new UnsupportedOperationException();
239
	}
240
241
	public boolean remove(Object o) {
242
		throw new UnsupportedOperationException();
243
	}
244
245
	public boolean removeAll(Collection c) {
246
		throw new UnsupportedOperationException();
247
	}
248
249
	public boolean retainAll(Collection c) {
250
		throw new UnsupportedOperationException();
251
	}
252
253
	public Object[] toArray() {
254
		getterCalled();
255
		Object[] masterElements = masterList.toArray();
256
		Object[] result = new Object[masterElements.length];
257
		for (int i = 0; i < result.length; i++) {
258
			result[i] = detailProperty.getValue(masterElements[i]);
259
		}
260
		return result;
261
	}
262
263
	public Object[] toArray(Object[] a) {
264
		getterCalled();
265
		Object[] masterElements = masterList.toArray();
266
		if (a.length < masterElements.length)
267
			a = (Object[]) Array.newInstance(a.getClass().getComponentType(),
268
					masterElements.length);
269
		for (int i = 0; i < masterElements.length; i++) {
270
			a[i] = detailProperty.getValue(masterElements[i]);
271
		}
272
		return a;
273
	}
274
275
	public void add(int index, Object o) {
276
		throw new UnsupportedOperationException();
277
	}
278
279
	public void clear() {
280
		throw new UnsupportedOperationException();
281
	}
282
283
	public ListIterator listIterator() {
284
		return listIterator(0);
285
	}
286
287
	public ListIterator listIterator(final int index) {
288
		getterCalled();
289
		return new ListIterator() {
290
			ListIterator it = masterList.listIterator(index);
291
			Object lastMasterElement;
292
			Object lastElement;
293
			boolean haveIterated = false;
294
295
			public void add(Object arg0) {
296
				throw new UnsupportedOperationException();
297
			}
298
299
			public boolean hasNext() {
300
				getterCalled();
301
				return it.hasNext();
302
			}
303
304
			public boolean hasPrevious() {
305
				getterCalled();
306
				return it.hasPrevious();
307
			}
308
309
			public Object next() {
310
				getterCalled();
311
				lastMasterElement = it.next();
312
				lastElement = detailProperty.getValue(lastMasterElement);
313
				haveIterated = true;
314
				return lastElement;
315
			}
316
317
			public int nextIndex() {
318
				getterCalled();
319
				return it.nextIndex();
320
			}
321
322
			public Object previous() {
323
				getterCalled();
324
				lastMasterElement = it.previous();
325
				lastElement = detailProperty.getValue(lastMasterElement);
326
				haveIterated = true;
327
				return lastElement;
328
			}
329
330
			public int previousIndex() {
331
				getterCalled();
332
				return it.previousIndex();
333
			}
334
335
			public void remove() {
336
				throw new UnsupportedOperationException();
337
			}
338
339
			public void set(Object o) {
340
				checkRealm();
341
				if (!haveIterated)
342
					throw new IllegalStateException();
343
344
				boolean wasUpdating = updating;
345
				updating = true;
346
				try {
347
					detailProperty.setValue(lastElement, o);
348
				} finally {
349
					updating = wasUpdating;
350
				}
351
352
				notifyIfChanged(lastMasterElement);
353
354
				lastElement = o;
355
			}
356
		};
357
	}
358
359
	private void notifyIfChanged(Object masterElement) {
360
		if (cachedValues != null) {
361
			Object oldValue = cachedValues.get(new IdentityWrapper(
362
					masterElement));
363
			Object newValue = detailProperty.getValue(masterElement);
364
			if (!Util.equals(oldValue, newValue)) {
365
				cachedValues.put(new IdentityWrapper(masterElement), newValue);
366
				fireListChange(indicesOf(masterElement), oldValue, newValue);
367
			}
368
		}
369
	}
370
371
	private int[] indicesOf(Object masterElement) {
372
		List indices = new ArrayList();
373
374
		for (ListIterator it = ObservableListSimpleValuePropertyObservableList.this.masterList
375
				.listIterator(); it.hasNext();) {
376
			if (masterElement == it.next())
377
				indices.add(new Integer(it.previousIndex()));
378
		}
379
380
		int[] result = new int[indices.size()];
381
		for (int i = 0; i < result.length; i++) {
382
			result[i] = ((Integer) indices.get(i)).intValue();
383
		}
384
		return result;
385
	}
386
387
	private void fireListChange(int[] indices, Object oldValue, Object newValue) {
388
		ListDiffEntry[] differences = new ListDiffEntry[indices.length * 2];
389
		for (int i = 0; i < indices.length; i++) {
390
			int index = indices[i];
391
			differences[i * 2] = Diffs.createListDiffEntry(index, false,
392
					oldValue);
393
			differences[i * 2 + 1] = Diffs.createListDiffEntry(index, true,
394
					newValue);
395
		}
396
		fireListChange(Diffs.createListDiff(differences));
397
	}
398
399
	public Object remove(int index) {
400
		throw new UnsupportedOperationException();
401
	}
402
403
	public Object set(int index, Object o) {
404
		checkRealm();
405
		Object masterElement = masterList.get(index);
406
		Object oldValue = detailProperty.getValue(masterElement);
407
408
		boolean wasUpdating = updating;
409
		updating = true;
410
		try {
411
			detailProperty.setValue(masterElement, o);
412
		} finally {
413
			updating = wasUpdating;
414
		}
415
416
		notifyIfChanged(masterElement);
417
418
		return oldValue;
419
	}
420
421
	public Object getObserved() {
422
		return masterList;
423
	}
424
425
	public synchronized void dispose() {
426
		if (masterList != null) {
427
			masterList.removeListChangeListener(masterListener);
428
			masterList = null;
429
		}
430
		if (knownMasterElements != null) {
431
			knownMasterElements.clear(); // detaches listeners
432
			knownMasterElements.dispose();
433
			knownMasterElements = null;
434
		}
435
436
		masterListener = null;
437
		detailListener = null;
438
		detailProperty = null;
439
		cachedValues = null;
440
441
		super.dispose();
442
	}
443
}
(-)src/org/eclipse/core/databinding/property/value/ObservableMapDelegatingValuePropertyObservableMap.java (-310 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 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property.value;
13
14
import java.util.AbstractSet;
15
import java.util.Collections;
16
import java.util.HashMap;
17
import java.util.HashSet;
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.observable.map.MapDiff;
32
import org.eclipse.core.internal.databinding.Util;
33
34
/**
35
 * @since 1.2
36
 */
37
class ObservableMapDelegatingValuePropertyObservableMap extends
38
		AbstractObservableMap implements IObserving {
39
	private IObservableMap masterMap;
40
	private DelegatingValueProperty detailProperty;
41
	private DelegatingCache cache;
42
43
	private Set entrySet;
44
45
	class EntrySet extends AbstractSet {
46
		public Iterator iterator() {
47
			return new Iterator() {
48
				Iterator it = masterMap.entrySet().iterator();
49
50
				public boolean hasNext() {
51
					getterCalled();
52
					return it.hasNext();
53
				}
54
55
				public Object next() {
56
					getterCalled();
57
					Map.Entry next = (Map.Entry) it.next();
58
					return new MapEntry(next.getKey());
59
				}
60
61
				public void remove() {
62
					it.remove();
63
				}
64
			};
65
		}
66
67
		public int size() {
68
			return masterMap.size();
69
		}
70
	}
71
72
	class MapEntry implements Map.Entry {
73
		private Object key;
74
75
		MapEntry(Object key) {
76
			this.key = key;
77
		}
78
79
		public Object getKey() {
80
			getterCalled();
81
			return key;
82
		}
83
84
		public Object getValue() {
85
			getterCalled();
86
87
			if (!masterMap.containsKey(key))
88
				return null;
89
90
			Object masterValue = masterMap.get(key);
91
			return cache.get(masterValue);
92
		}
93
94
		public Object setValue(Object value) {
95
			checkRealm();
96
97
			if (!masterMap.containsKey(key))
98
				return null;
99
100
			Object masterValue = masterMap.get(key);
101
			return cache.put(masterValue, value);
102
		}
103
104
		public boolean equals(Object o) {
105
			getterCalled();
106
			if (o == this)
107
				return true;
108
			if (o == null)
109
				return false;
110
			if (!(o instanceof Map.Entry))
111
				return false;
112
			Map.Entry that = (Map.Entry) o;
113
			return Util.equals(this.getKey(), that.getKey())
114
					&& Util.equals(this.getValue(), that.getValue());
115
		}
116
117
		public int hashCode() {
118
			getterCalled();
119
			Object value = getValue();
120
			return (key == null ? 0 : key.hashCode())
121
					^ (value == null ? 0 : value.hashCode());
122
		}
123
	}
124
125
	private IMapChangeListener masterListener = new IMapChangeListener() {
126
		public void handleMapChange(final MapChangeEvent event) {
127
			if (isDisposed())
128
				return;
129
130
			cache.addAll(masterMap.values());
131
132
			// Need both obsolete and new master values to convert diff
133
			MapDiff diff = convertDiff(event.diff);
134
135
			cache.retainAll(masterMap.values());
136
137
			fireMapChange(diff);
138
		}
139
140
		private MapDiff convertDiff(MapDiff diff) {
141
			Map oldValues = new HashMap();
142
			Map newValues = new HashMap();
143
144
			Set addedKeys = diff.getAddedKeys();
145
			for (Iterator it = addedKeys.iterator(); it.hasNext();) {
146
				Object key = it.next();
147
				Object masterValue = diff.getNewValue(key);
148
				Object newValue = cache.get(masterValue);
149
				newValues.put(key, newValue);
150
			}
151
152
			Set removedKeys = diff.getRemovedKeys();
153
			for (Iterator it = removedKeys.iterator(); it.hasNext();) {
154
				Object key = it.next();
155
				Object masterValue = diff.getOldValue(key);
156
				Object oldValue = cache.get(masterValue);
157
				oldValues.put(key, oldValue);
158
			}
159
160
			Set changedKeys = new HashSet(diff.getChangedKeys());
161
			for (Iterator it = changedKeys.iterator(); it.hasNext();) {
162
				Object key = it.next();
163
164
				Object oldMasterValue = diff.getOldValue(key);
165
				Object newMasterValue = diff.getNewValue(key);
166
167
				Object oldValue = cache.get(oldMasterValue);
168
				Object newValue = cache.get(newMasterValue);
169
170
				if (Util.equals(oldValue, newValue)) {
171
					it.remove();
172
				} else {
173
					oldValues.put(key, oldValue);
174
					newValues.put(key, newValue);
175
				}
176
			}
177
178
			return Diffs.createMapDiff(addedKeys, removedKeys, changedKeys,
179
					oldValues, newValues);
180
		}
181
	};
182
183
	private IStaleListener staleListener = new IStaleListener() {
184
		public void handleStale(StaleEvent staleEvent) {
185
			fireStale();
186
		}
187
	};
188
189
	/**
190
	 * @param map
191
	 * @param valueProperty
192
	 */
193
	public ObservableMapDelegatingValuePropertyObservableMap(
194
			IObservableMap map, DelegatingValueProperty valueProperty) {
195
		super(map.getRealm());
196
		this.masterMap = map;
197
		this.detailProperty = valueProperty;
198
		this.cache = new DelegatingCache(getRealm(), valueProperty) {
199
			void handleValueChange(Object masterElement, Object oldValue,
200
					Object newValue) {
201
				fireMapChange(keysFor(masterElement), oldValue, newValue);
202
			}
203
		};
204
		cache.addAll(masterMap.values());
205
206
		masterMap.addMapChangeListener(masterListener);
207
		masterMap.addStaleListener(staleListener);
208
	}
209
210
	public Set entrySet() {
211
		getterCalled();
212
		if (entrySet == null)
213
			entrySet = new EntrySet();
214
		return entrySet;
215
	}
216
217
	private void getterCalled() {
218
		ObservableTracker.getterCalled(this);
219
	}
220
221
	public Object get(Object key) {
222
		getterCalled();
223
		Object masterValue = masterMap.get(key);
224
		return cache.get(masterValue);
225
	}
226
227
	public Object put(Object key, Object value) {
228
		if (!masterMap.containsKey(key))
229
			return null;
230
		Object masterValue = masterMap.get(key);
231
		return cache.put(masterValue, value);
232
	}
233
234
	public boolean isStale() {
235
		getterCalled();
236
		return masterMap.isStale();
237
	}
238
239
	public Object getObserved() {
240
		return masterMap;
241
	}
242
243
	public Object getKeyType() {
244
		return masterMap.getKeyType();
245
	}
246
247
	public Object getValueType() {
248
		return detailProperty.getValueType();
249
	}
250
251
	private Set keysFor(Object masterValue) {
252
		Set keys = new HashSet();
253
254
		for (Iterator it = masterMap.entrySet().iterator(); it.hasNext();) {
255
			Map.Entry entry = (Entry) it.next();
256
			if (entry.getValue() == masterValue) {
257
				keys.add(entry.getKey());
258
			}
259
		}
260
261
		return keys;
262
	}
263
264
	private void fireMapChange(final Set changedKeys, final Object oldValue,
265
			final Object newValue) {
266
		fireMapChange(new MapDiff() {
267
			public Set getAddedKeys() {
268
				return Collections.EMPTY_SET;
269
			}
270
271
			public Set getRemovedKeys() {
272
				return Collections.EMPTY_SET;
273
			}
274
275
			public Set getChangedKeys() {
276
				return Collections.unmodifiableSet(changedKeys);
277
			}
278
279
			public Object getOldValue(Object key) {
280
				if (changedKeys.contains(key))
281
					return oldValue;
282
				return null;
283
			}
284
285
			public Object getNewValue(Object key) {
286
				if (changedKeys.contains(key))
287
					return newValue;
288
				return null;
289
			}
290
		});
291
	}
292
293
	public synchronized void dispose() {
294
		if (masterMap != null) {
295
			masterMap.removeMapChangeListener(masterListener);
296
			masterMap.removeStaleListener(staleListener);
297
			masterMap = null;
298
		}
299
300
		if (cache != null) {
301
			cache.dispose();
302
			cache = null;
303
		}
304
305
		masterListener = null;
306
		detailProperty = null;
307
308
		super.dispose();
309
	}
310
}
(-)src/org/eclipse/core/databinding/property/value/ObservableSetSimpleValuePropertyObservableMap.java (-138 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 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property.value;
13
14
import java.util.HashMap;
15
import java.util.Iterator;
16
import java.util.Map;
17
18
import org.eclipse.core.databinding.observable.Diffs;
19
import org.eclipse.core.databinding.observable.IObserving;
20
import org.eclipse.core.databinding.observable.map.ComputedObservableMap;
21
import org.eclipse.core.databinding.observable.set.IObservableSet;
22
import org.eclipse.core.databinding.property.INativePropertyListener;
23
import org.eclipse.core.databinding.property.IPropertyChangeListener;
24
import org.eclipse.core.databinding.property.PropertyChangeEvent;
25
import org.eclipse.core.internal.databinding.Util;
26
27
/**
28
 * @since 1.2
29
 */
30
class ObservableSetSimpleValuePropertyObservableMap extends
31
		ComputedObservableMap implements IObserving {
32
	private SimpleValueProperty detailProperty;
33
34
	private INativePropertyListener listener;
35
36
	private Map cachedValues;
37
38
	private boolean updating;
39
40
	/**
41
	 * @param keySet
42
	 * @param valueProperty
43
	 */
44
	public ObservableSetSimpleValuePropertyObservableMap(IObservableSet keySet,
45
			SimpleValueProperty valueProperty) {
46
		super(keySet);
47
		this.detailProperty = valueProperty;
48
	}
49
50
	protected void firstListenerAdded() {
51
		cachedValues = new HashMap(this);
52
		if (listener == null) {
53
			listener = detailProperty
54
					.adaptListener(new IPropertyChangeListener() {
55
						public void handlePropertyChange(
56
								final PropertyChangeEvent event) {
57
							if (!isDisposed() && !updating) {
58
								getRealm().exec(new Runnable() {
59
									public void run() {
60
										notifyIfChanged(event.getSource());
61
									}
62
								});
63
							}
64
						}
65
					});
66
		}
67
		super.firstListenerAdded();
68
	}
69
70
	protected void lastListenerRemoved() {
71
		super.lastListenerRemoved();
72
		cachedValues.clear();
73
		cachedValues = null;
74
	}
75
76
	protected void hookListener(Object addedKey) {
77
		if (listener != null) {
78
			cachedValues.put(addedKey, detailProperty.getValue(addedKey));
79
			detailProperty.addListener(addedKey, listener);
80
		}
81
	}
82
83
	protected void unhookListener(Object removedKey) {
84
		if (listener != null) {
85
			detailProperty.removeListener(removedKey, listener);
86
			cachedValues.remove(removedKey);
87
		}
88
	}
89
90
	protected Object doGet(Object key) {
91
		return detailProperty.getValue(key);
92
	}
93
94
	protected Object doPut(Object key, Object value) {
95
		Object oldValue = detailProperty.getValue(key);
96
97
		updating = true;
98
		try {
99
			detailProperty.setValue(key, value);
100
		} finally {
101
			updating = false;
102
		}
103
104
		notifyIfChanged(key);
105
106
		return oldValue;
107
	}
108
109
	private void notifyIfChanged(Object key) {
110
		if (cachedValues != null) {
111
			Object oldValue = cachedValues.get(key);
112
			Object newValue = detailProperty.getValue(key);
113
			if (!Util.equals(oldValue, newValue)) {
114
				cachedValues.put(key, newValue);
115
				fireMapChange(Diffs.createMapDiffSingleChange(key, oldValue,
116
						newValue));
117
			}
118
		}
119
	}
120
121
	public Object getObserved() {
122
		return keySet();
123
	}
124
125
	public synchronized void dispose() {
126
		if (!isDisposed()) {
127
			if (listener != null) {
128
				for (Iterator it = values().iterator(); it.hasNext();) {
129
					unhookListener(it.next());
130
				}
131
				listener = null;
132
			}
133
			detailProperty = null;
134
		}
135
136
		super.dispose();
137
	}
138
}
(-)src/org/eclipse/core/databinding/property/value/ObservableListDelegatingValuePropertyObservableList.java (-341 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
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property.value;
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.IStaleListener;
23
import org.eclipse.core.databinding.observable.ObservableTracker;
24
import org.eclipse.core.databinding.observable.StaleEvent;
25
import org.eclipse.core.databinding.observable.list.AbstractObservableList;
26
import org.eclipse.core.databinding.observable.list.IListChangeListener;
27
import org.eclipse.core.databinding.observable.list.IObservableList;
28
import org.eclipse.core.databinding.observable.list.ListChangeEvent;
29
import org.eclipse.core.databinding.observable.list.ListDiff;
30
import org.eclipse.core.databinding.observable.list.ListDiffEntry;
31
32
/**
33
 * @since 1.2
34
 */
35
class ObservableListDelegatingValuePropertyObservableList extends
36
		AbstractObservableList {
37
	private IObservableList masterList;
38
	private DelegatingValueProperty detailProperty;
39
	private DelegatingCache cache;
40
41
	private IListChangeListener masterListener = new IListChangeListener() {
42
		public void handleListChange(ListChangeEvent event) {
43
			if (isDisposed())
44
				return;
45
46
			cache.addAll(masterList);
47
48
			// Need both obsolete and new elements to convert diff
49
			ListDiff diff = convertDiff(event.diff);
50
51
			cache.retainAll(masterList);
52
53
			fireListChange(diff);
54
		}
55
56
		private ListDiff convertDiff(ListDiff diff) {
57
			// Convert diff to detail value
58
			ListDiffEntry[] masterEntries = diff.getDifferences();
59
			ListDiffEntry[] detailEntries = new ListDiffEntry[masterEntries.length];
60
			for (int i = 0; i < masterEntries.length; i++) {
61
				ListDiffEntry masterDifference = masterEntries[i];
62
				int index = masterDifference.getPosition();
63
				boolean addition = masterDifference.isAddition();
64
				Object masterElement = masterDifference.getElement();
65
				Object detailValue = cache.get(masterElement);
66
67
				detailEntries[i] = Diffs.createListDiffEntry(index, addition,
68
						detailValue);
69
			}
70
			return Diffs.createListDiff(detailEntries);
71
		}
72
	};
73
74
	private IStaleListener staleListener = new IStaleListener() {
75
		public void handleStale(StaleEvent staleEvent) {
76
			fireStale();
77
		}
78
	};
79
80
	/**
81
	 * @param masterList
82
	 * @param valueProperty
83
	 */
84
	public ObservableListDelegatingValuePropertyObservableList(
85
			IObservableList masterList, DelegatingValueProperty valueProperty) {
86
		super(masterList.getRealm());
87
		this.masterList = masterList;
88
		this.detailProperty = valueProperty;
89
		this.cache = new DelegatingCache(getRealm(), valueProperty) {
90
			void handleValueChange(Object masterElement, Object oldValue,
91
					Object newValue) {
92
				fireListChange(indicesOf(masterElement), oldValue, newValue);
93
			}
94
		};
95
		cache.addAll(masterList);
96
97
		masterList.addListChangeListener(masterListener);
98
		masterList.addStaleListener(staleListener);
99
	}
100
101
	protected int doGetSize() {
102
		getterCalled();
103
		return masterList.size();
104
	}
105
106
	private void getterCalled() {
107
		ObservableTracker.getterCalled(this);
108
	}
109
110
	public Object get(int index) {
111
		getterCalled();
112
		Object masterElement = masterList.get(index);
113
		return cache.get(masterElement);
114
	}
115
116
	public boolean add(Object o) {
117
		throw new UnsupportedOperationException();
118
	}
119
120
	public boolean addAll(Collection c) {
121
		throw new UnsupportedOperationException();
122
	}
123
124
	public boolean addAll(int index, Collection c) {
125
		throw new UnsupportedOperationException();
126
	}
127
128
	public boolean contains(Object o) {
129
		getterCalled();
130
		return cache.contains(o);
131
	}
132
133
	public boolean isEmpty() {
134
		getterCalled();
135
		return masterList.isEmpty();
136
	}
137
138
	public boolean isStale() {
139
		getterCalled();
140
		return masterList.isStale();
141
	}
142
143
	public Iterator iterator() {
144
		getterCalled();
145
		return new Iterator() {
146
			Iterator it = masterList.iterator();
147
148
			public boolean hasNext() {
149
				getterCalled();
150
				return it.hasNext();
151
			}
152
153
			public Object next() {
154
				getterCalled();
155
				Object masterElement = it.next();
156
				return cache.get(masterElement);
157
			}
158
159
			public void remove() {
160
				throw new UnsupportedOperationException();
161
			}
162
		};
163
	}
164
165
	public Object move(int oldIndex, int newIndex) {
166
		throw new UnsupportedOperationException();
167
	}
168
169
	public boolean remove(Object o) {
170
		throw new UnsupportedOperationException();
171
	}
172
173
	public boolean removeAll(Collection c) {
174
		throw new UnsupportedOperationException();
175
	}
176
177
	public boolean retainAll(Collection c) {
178
		throw new UnsupportedOperationException();
179
	}
180
181
	public Object[] toArray() {
182
		getterCalled();
183
		Object[] masterElements = masterList.toArray();
184
		Object[] result = new Object[masterElements.length];
185
		for (int i = 0; i < result.length; i++) {
186
			result[i] = cache.get(masterElements[i]);
187
		}
188
		return result;
189
	}
190
191
	public Object[] toArray(Object[] a) {
192
		getterCalled();
193
		Object[] masterElements = masterList.toArray();
194
		if (a.length < masterElements.length)
195
			a = (Object[]) Array.newInstance(a.getClass().getComponentType(),
196
					masterElements.length);
197
		for (int i = 0; i < masterElements.length; i++) {
198
			a[i] = cache.get(masterElements[i]);
199
		}
200
		return a;
201
	}
202
203
	public void add(int index, Object o) {
204
		throw new UnsupportedOperationException();
205
	}
206
207
	public void clear() {
208
		throw new UnsupportedOperationException();
209
	}
210
211
	public ListIterator listIterator() {
212
		return listIterator(0);
213
	}
214
215
	public ListIterator listIterator(final int index) {
216
		getterCalled();
217
		return new ListIterator() {
218
			ListIterator it = masterList.listIterator(index);
219
			Object lastMasterElement;
220
			Object lastElement;
221
			boolean haveIterated = false;
222
223
			public void add(Object arg0) {
224
				throw new UnsupportedOperationException();
225
			}
226
227
			public boolean hasNext() {
228
				getterCalled();
229
				return it.hasNext();
230
			}
231
232
			public boolean hasPrevious() {
233
				getterCalled();
234
				return it.hasPrevious();
235
			}
236
237
			public Object next() {
238
				getterCalled();
239
				lastMasterElement = it.next();
240
				lastElement = cache.get(lastMasterElement);
241
				haveIterated = true;
242
				return lastElement;
243
			}
244
245
			public int nextIndex() {
246
				getterCalled();
247
				return it.nextIndex();
248
			}
249
250
			public Object previous() {
251
				getterCalled();
252
				lastMasterElement = it.previous();
253
				lastElement = cache.get(lastMasterElement);
254
				haveIterated = true;
255
				return lastElement;
256
			}
257
258
			public int previousIndex() {
259
				getterCalled();
260
				return it.previousIndex();
261
			}
262
263
			public void remove() {
264
				throw new UnsupportedOperationException();
265
			}
266
267
			public void set(Object o) {
268
				checkRealm();
269
				if (!haveIterated)
270
					throw new IllegalStateException();
271
272
				cache.put(lastMasterElement, o);
273
274
				lastElement = o;
275
			}
276
		};
277
	}
278
279
	private int[] indicesOf(Object masterElement) {
280
		List indices = new ArrayList();
281
282
		for (ListIterator it = masterList.listIterator(); it.hasNext();) {
283
			if (masterElement == it.next())
284
				indices.add(new Integer(it.previousIndex()));
285
		}
286
287
		int[] result = new int[indices.size()];
288
		for (int i = 0; i < result.length; i++) {
289
			result[i] = ((Integer) indices.get(i)).intValue();
290
		}
291
		return result;
292
	}
293
294
	private void fireListChange(int[] indices, Object oldValue, Object newValue) {
295
		ListDiffEntry[] differences = new ListDiffEntry[indices.length * 2];
296
		for (int i = 0; i < indices.length; i++) {
297
			int index = indices[i];
298
			differences[i * 2] = Diffs.createListDiffEntry(index, false,
299
					oldValue);
300
			differences[i * 2 + 1] = Diffs.createListDiffEntry(index, true,
301
					newValue);
302
		}
303
		fireListChange(Diffs.createListDiff(differences));
304
	}
305
306
	public Object remove(int index) {
307
		throw new UnsupportedOperationException();
308
	}
309
310
	public Object set(int index, Object o) {
311
		checkRealm();
312
		Object masterElement = masterList.get(index);
313
		return cache.put(masterElement, o);
314
	}
315
316
	public Object getObserved() {
317
		return masterList;
318
	}
319
320
	public Object getElementType() {
321
		return detailProperty.getValueType();
322
	}
323
324
	public synchronized void dispose() {
325
		if (masterList != null) {
326
			masterList.removeListChangeListener(masterListener);
327
			masterList.removeStaleListener(staleListener);
328
			masterList = null;
329
		}
330
331
		if (cache != null) {
332
			cache.dispose();
333
			cache = null;
334
		}
335
336
		masterListener = null;
337
		detailProperty = null;
338
339
		super.dispose();
340
	}
341
}
(-)src/org/eclipse/core/databinding/property/value/SimpleValueProperty.java (-72 / +19 lines)
Lines 12-24 Link Here
12
12
13
package org.eclipse.core.databinding.property.value;
13
package org.eclipse.core.databinding.property.value;
14
14
15
import org.eclipse.core.databinding.observable.IDiff;
15
import org.eclipse.core.databinding.observable.Realm;
16
import org.eclipse.core.databinding.observable.Realm;
16
import org.eclipse.core.databinding.observable.list.IObservableList;
17
import org.eclipse.core.databinding.observable.list.IObservableList;
17
import org.eclipse.core.databinding.observable.map.IObservableMap;
18
import org.eclipse.core.databinding.observable.map.IObservableMap;
18
import org.eclipse.core.databinding.observable.set.IObservableSet;
19
import org.eclipse.core.databinding.observable.set.IObservableSet;
19
import org.eclipse.core.databinding.observable.value.IObservableValue;
20
import org.eclipse.core.databinding.observable.value.IObservableValue;
20
import org.eclipse.core.databinding.property.INativePropertyListener;
21
import org.eclipse.core.databinding.property.INativePropertyListener;
21
import org.eclipse.core.databinding.property.IPropertyChangeListener;
22
import org.eclipse.core.databinding.property.ISimplePropertyListener;
23
import org.eclipse.core.internal.databinding.property.value.ObservableListSimpleValuePropertyObservableList;
24
import org.eclipse.core.internal.databinding.property.value.ObservableMapSimpleValuePropertyObservableMap;
25
import org.eclipse.core.internal.databinding.property.value.ObservableSetSimpleValuePropertyObservableMap;
26
import org.eclipse.core.internal.databinding.property.value.SimpleValuePropertyObservableValue;
22
27
23
/**
28
/**
24
 * Simplified abstract implementation of IValueProperty. This class takes care
29
 * Simplified abstract implementation of IValueProperty. This class takes care
Lines 30-36 Link Here
30
 * <li> {@link #getValueType()}
35
 * <li> {@link #getValueType()}
31
 * <li> {@link #doGetValue(Object)}
36
 * <li> {@link #doGetValue(Object)}
32
 * <li> {@link #doSetValue(Object, Object)}
37
 * <li> {@link #doSetValue(Object, Object)}
33
 * <li> {@link #adaptListener(IPropertyChangeListener)}
38
 * <li> {@link #adaptListener(ISimplePropertyListener)}
34
 * <li> {@link #doAddListener(Object, INativePropertyListener)}
39
 * <li> {@link #doAddListener(Object, INativePropertyListener)}
35
 * <li> {@link #doRemoveListener(Object, INativePropertyListener)}
40
 * <li> {@link #doRemoveListener(Object, INativePropertyListener)}
36
 * </ul>
41
 * </ul>
Lines 40-55 Link Here
40
 * 
45
 * 
41
 * @since 1.2
46
 * @since 1.2
42
 */
47
 */
43
public abstract class SimpleValueProperty extends ValueProperty {
48
public abstract class SimpleValueProperty extends ValueProperty implements
44
	/**
49
		ISimpleValueProperty {
45
	 * Returns the value of the property on the specified source object
50
	public final Object get(Object source) {
46
	 * 
47
	 * @param source
48
	 *            the property source (may be null)
49
	 * @return the current value of the source's value property
50
	 * @noreference This method is not intended to be referenced by clients.
51
	 */
52
	protected final Object getValue(Object source) {
53
		return source == null ? null : doGetValue(source);
51
		return source == null ? null : doGetValue(source);
54
	}
52
	}
55
53
Lines 63-117 Link Here
63
	 */
61
	 */
64
	protected abstract Object doGetValue(Object source);
62
	protected abstract Object doGetValue(Object source);
65
63
66
	/**
64
	public final void set(Object source, Object value, IDiff diff) {
67
	 * Sets the source's value property to the specified value
68
	 * 
69
	 * @param source
70
	 *            the property source
71
	 * @param value
72
	 *            the new value
73
	 * @noreference This method is not intended to be referenced by clients.
74
	 */
75
	protected final void setValue(Object source, Object value) {
76
		if (source != null)
65
		if (source != null)
77
			doSetValue(source, value);
66
			doSetValue(source, value);
78
	}
67
	}
79
68
80
	protected abstract void doSetValue(Object source, Object value);
69
	protected abstract void doSetValue(Object source, Object value);
81
70
82
	/**
71
	public abstract INativePropertyListener adaptListener(
83
	 * Returns a listener which implements the correct listener interface for
72
			ISimplePropertyListener listener);
84
	 * the expected source object, and which parlays property change events from
85
	 * the source object to the given listener. If there is no listener API for
86
	 * this property, this method returns null.
87
	 * 
88
	 * @param listener
89
	 *            the property listener to receive events
90
	 * @return a native listener which parlays property change events to the
91
	 *         specified listener.
92
	 * @throws ClassCastException
93
	 *             if the provided listener does not implement the correct
94
	 *             listener interface (IValueProperty, IListProperty,
95
	 *             ISetProperty or IMapProperty) depending on the property.
96
	 * @noreference This method is not intended to be referenced by clients.
97
	 */
98
	protected abstract INativePropertyListener adaptListener(
99
			IPropertyChangeListener listener);
100
73
101
	/**
74
	public final void addListener(Object source,
102
	 * Adds the specified listener as a listener for this property on the
103
	 * specified property source. If the source object has no listener API for
104
	 * this property (i.e. {@link #adaptListener(IPropertyChangeListener)}
105
	 * returns null), this method does nothing.
106
	 * 
107
	 * @param source
108
	 *            the property source
109
	 * @param listener
110
	 *            a listener obtained from calling
111
	 *            {@link #adaptListener(IPropertyChangeListener)}.
112
	 * @noreference This method is not intended to be referenced by clients.
113
	 */
114
	protected final void addListener(Object source,
115
			INativePropertyListener listener) {
75
			INativePropertyListener listener) {
116
		if (source != null)
76
		if (source != null)
117
			doAddListener(source, listener);
77
			doAddListener(source, listener);
Lines 120-152 Link Here
120
	/**
80
	/**
121
	 * Adds the specified listener as a listener for this property on the
81
	 * Adds the specified listener as a listener for this property on the
122
	 * specified property source. If the source object has no listener API for
82
	 * specified property source. If the source object has no listener API for
123
	 * this property (i.e. {@link #adaptListener(IPropertyChangeListener)}
83
	 * this property (i.e. {@link #adaptListener(ISimplePropertyListener)}
124
	 * returns null), this method does nothing.
84
	 * returns null), this method does nothing.
125
	 * 
85
	 * 
126
	 * @param source
86
	 * @param source
127
	 *            the property source
87
	 *            the property source
128
	 * @param listener
88
	 * @param listener
129
	 *            a listener obtained from calling
89
	 *            a listener obtained from calling
130
	 *            {@link #adaptListener(IPropertyChangeListener)}.
90
	 *            {@link #adaptListener(ISimplePropertyListener)}.
131
	 * @noreference This method is not intended to be referenced by clients.
91
	 * @noreference This method is not intended to be referenced by clients.
132
	 */
92
	 */
133
	protected abstract void doAddListener(Object source,
93
	protected abstract void doAddListener(Object source,
134
			INativePropertyListener listener);
94
			INativePropertyListener listener);
135
95
136
	/**
96
	public final void removeListener(Object source,
137
	 * Removes the specified listener as a listener for this property on the
138
	 * specified property source. If the source object has no listener API for
139
	 * this property (i.e. {@link #adaptListener(IPropertyChangeListener)}
140
	 * returns null), this method does nothing.
141
	 * 
142
	 * @param source
143
	 *            the property source
144
	 * @param listener
145
	 *            a listener obtained from calling
146
	 *            {@link #adaptListener(IPropertyChangeListener)}.
147
	 * @noreference This method is not intended to be referenced by clients.
148
	 */
149
	protected final void removeListener(Object source,
150
			INativePropertyListener listener) {
97
			INativePropertyListener listener) {
151
		if (source != null)
98
		if (source != null)
152
			doRemoveListener(source, listener);
99
			doRemoveListener(source, listener);
Lines 155-168 Link Here
155
	/**
102
	/**
156
	 * Removes the specified listener as a listener for this property on the
103
	 * Removes the specified listener as a listener for this property on the
157
	 * specified property source. If the source object has no listener API for
104
	 * specified property source. If the source object has no listener API for
158
	 * this property (i.e. {@link #adaptListener(IPropertyChangeListener)}
105
	 * this property (i.e. {@link #adaptListener(ISimplePropertyListener)}
159
	 * returns null), this method does nothing.
106
	 * returns null), this method does nothing.
160
	 * 
107
	 * 
161
	 * @param source
108
	 * @param source
162
	 *            the property source
109
	 *            the property source
163
	 * @param listener
110
	 * @param listener
164
	 *            a listener obtained from calling
111
	 *            a listener obtained from calling
165
	 *            {@link #adaptListener(IPropertyChangeListener)}.
112
	 *            {@link #adaptListener(ISimplePropertyListener)}.
166
	 * @noreference This method is not intended to be referenced by clients.
113
	 * @noreference This method is not intended to be referenced by clients.
167
	 */
114
	 */
168
	protected abstract void doRemoveListener(Object source,
115
	protected abstract void doRemoveListener(Object source,
(-)src/org/eclipse/core/databinding/property/value/ObservableMapSimpleValuePropertyObservableMap.java (-369 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 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property.value;
13
14
import java.util.AbstractSet;
15
import java.util.Collections;
16
import java.util.HashMap;
17
import java.util.HashSet;
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.observable.map.MapDiff;
32
import org.eclipse.core.databinding.observable.set.IObservableSet;
33
import org.eclipse.core.databinding.observable.set.ISetChangeListener;
34
import org.eclipse.core.databinding.observable.set.SetChangeEvent;
35
import org.eclipse.core.databinding.observable.set.WritableSet;
36
import org.eclipse.core.databinding.property.INativePropertyListener;
37
import org.eclipse.core.databinding.property.IPropertyChangeListener;
38
import org.eclipse.core.databinding.property.PropertyChangeEvent;
39
import org.eclipse.core.internal.databinding.IdentityWrapper;
40
import org.eclipse.core.internal.databinding.Util;
41
42
/**
43
 * @since 1.2
44
 * 
45
 */
46
class ObservableMapSimpleValuePropertyObservableMap extends
47
		AbstractObservableMap implements IObserving {
48
	private IObservableMap masterMap;
49
	private SimpleValueProperty detailProperty;
50
51
	private IObservableSet knownMasterValues;
52
	private Map cachedValues;
53
54
	private boolean updating = false;
55
56
	private IMapChangeListener masterListener = new IMapChangeListener() {
57
		public void handleMapChange(final MapChangeEvent event) {
58
			if (!isDisposed()) {
59
				updateKnownValues();
60
				if (!updating)
61
					fireMapChange(convertDiff(event.diff));
62
			}
63
		}
64
65
		private void updateKnownValues() {
66
			Set identityKnownValues = new HashSet();
67
			for (Iterator it = masterMap.values().iterator(); it.hasNext();) {
68
				identityKnownValues.add(new IdentityWrapper(it.next()));
69
			}
70
71
			knownMasterValues.retainAll(identityKnownValues);
72
			knownMasterValues.addAll(identityKnownValues);
73
		}
74
75
		private MapDiff convertDiff(MapDiff diff) {
76
			Map oldValues = new HashMap();
77
			Map newValues = new HashMap();
78
79
			Set addedKeys = diff.getAddedKeys();
80
			for (Iterator it = addedKeys.iterator(); it.hasNext();) {
81
				Object key = it.next();
82
				Object newSource = diff.getNewValue(key);
83
				Object newValue = detailProperty.getValue(newSource);
84
				newValues.put(key, newValue);
85
			}
86
87
			Set removedKeys = diff.getRemovedKeys();
88
			for (Iterator it = removedKeys.iterator(); it.hasNext();) {
89
				Object key = it.next();
90
				Object oldSource = diff.getOldValue(key);
91
				Object oldValue = detailProperty.getValue(oldSource);
92
				oldValues.put(key, oldValue);
93
			}
94
95
			Set changedKeys = new HashSet(diff.getChangedKeys());
96
			for (Iterator it = changedKeys.iterator(); it.hasNext();) {
97
				Object key = it.next();
98
99
				Object oldSource = diff.getOldValue(key);
100
				Object newSource = diff.getNewValue(key);
101
102
				Object oldValue = detailProperty.getValue(oldSource);
103
				Object newValue = detailProperty.getValue(newSource);
104
105
				if (Util.equals(oldValue, newValue)) {
106
					it.remove();
107
				} else {
108
					oldValues.put(key, oldValue);
109
					newValues.put(key, newValue);
110
				}
111
			}
112
113
			return Diffs.createMapDiff(addedKeys, removedKeys, changedKeys,
114
					oldValues, newValues);
115
		}
116
	};
117
118
	private IStaleListener staleListener = new IStaleListener() {
119
		public void handleStale(StaleEvent staleEvent) {
120
			fireStale();
121
		}
122
	};
123
124
	private INativePropertyListener detailListener;
125
126
	/**
127
	 * @param map
128
	 * @param valueProperty
129
	 */
130
	public ObservableMapSimpleValuePropertyObservableMap(IObservableMap map,
131
			SimpleValueProperty valueProperty) {
132
		super(map.getRealm());
133
		this.masterMap = map;
134
		this.detailProperty = valueProperty;
135
136
		IPropertyChangeListener listener = new IPropertyChangeListener() {
137
			public void handlePropertyChange(PropertyChangeEvent event) {
138
				notifyIfChanged(event.getSource());
139
			}
140
		};
141
		this.detailListener = detailProperty.adaptListener(listener);
142
	}
143
144
	protected void firstListenerAdded() {
145
		knownMasterValues = new WritableSet(getRealm());
146
		cachedValues = new HashMap();
147
		knownMasterValues.addSetChangeListener(new ISetChangeListener() {
148
			public void handleSetChange(SetChangeEvent event) {
149
				for (Iterator it = event.diff.getRemovals().iterator(); it
150
						.hasNext();) {
151
					IdentityWrapper wrapper = (IdentityWrapper) it.next();
152
					Object key = wrapper.unwrap();
153
					detailProperty.removeListener(key, detailListener);
154
					cachedValues.remove(wrapper);
155
				}
156
				for (Iterator it = event.diff.getAdditions().iterator(); it
157
						.hasNext();) {
158
					IdentityWrapper wrapper = (IdentityWrapper) it.next();
159
					Object key = wrapper.unwrap();
160
					cachedValues.put(wrapper, detailProperty.getValue(key));
161
					detailProperty.addListener(key, detailListener);
162
				}
163
			}
164
		});
165
		for (Iterator it = masterMap.values().iterator(); it.hasNext();) {
166
			knownMasterValues.add(new IdentityWrapper(it.next()));
167
		}
168
169
		masterMap.addMapChangeListener(masterListener);
170
		masterMap.addStaleListener(staleListener);
171
	}
172
173
	protected void lastListenerRemoved() {
174
		masterMap.removeMapChangeListener(masterListener);
175
		masterMap.removeStaleListener(staleListener);
176
		if (knownMasterValues != null) {
177
			knownMasterValues.clear(); // removes attached listeners
178
			knownMasterValues.dispose();
179
			knownMasterValues = null;
180
		}
181
		cachedValues.clear();
182
		cachedValues = null;
183
	}
184
185
	private Set entrySet;
186
187
	public Set entrySet() {
188
		getterCalled();
189
		if (entrySet == null)
190
			entrySet = new EntrySet();
191
		return entrySet;
192
	}
193
194
	class EntrySet extends AbstractSet {
195
		public Iterator iterator() {
196
			return new Iterator() {
197
				Iterator it = masterMap.entrySet().iterator();
198
199
				public boolean hasNext() {
200
					getterCalled();
201
					return it.hasNext();
202
				}
203
204
				public Object next() {
205
					getterCalled();
206
					Map.Entry next = (Map.Entry) it.next();
207
					return new MapEntry(next.getKey());
208
				}
209
210
				public void remove() {
211
					it.remove();
212
				}
213
			};
214
		}
215
216
		public int size() {
217
			return masterMap.size();
218
		}
219
	}
220
221
	class MapEntry implements Map.Entry {
222
		private Object key;
223
224
		MapEntry(Object key) {
225
			this.key = key;
226
		}
227
228
		public Object getKey() {
229
			getterCalled();
230
			return key;
231
		}
232
233
		public Object getValue() {
234
			getterCalled();
235
			if (!masterMap.containsKey(key))
236
				return null;
237
			return detailProperty.getValue(masterMap.get(key));
238
		}
239
240
		public Object setValue(Object value) {
241
			if (!masterMap.containsKey(key))
242
				return null;
243
			Object source = masterMap.get(key);
244
245
			Object oldValue = detailProperty.getValue(source);
246
247
			updating = true;
248
			try {
249
				detailProperty.setValue(source, value);
250
			} finally {
251
				updating = false;
252
			}
253
254
			notifyIfChanged(source);
255
256
			return oldValue;
257
		}
258
259
		public boolean equals(Object o) {
260
			getterCalled();
261
			if (o == this)
262
				return true;
263
			if (o == null)
264
				return false;
265
			if (!(o instanceof Map.Entry))
266
				return false;
267
			Map.Entry that = (Map.Entry) o;
268
			return Util.equals(this.getKey(), that.getKey())
269
					&& Util.equals(this.getValue(), that.getValue());
270
		}
271
272
		public int hashCode() {
273
			getterCalled();
274
			Object value = getValue();
275
			return (key == null ? 0 : key.hashCode())
276
					^ (value == null ? 0 : value.hashCode());
277
		}
278
	}
279
280
	public Object put(Object key, Object value) {
281
		if (!masterMap.containsKey(key))
282
			return null;
283
		Object masterValue = masterMap.get(key);
284
		Object oldValue = detailProperty.getValue(key);
285
		detailProperty.setValue(masterValue, value);
286
		notifyIfChanged(masterValue);
287
		return oldValue;
288
	}
289
290
	private void notifyIfChanged(Object masterValue) {
291
		if (cachedValues != null) {
292
			final Set keys = keysFor(masterValue);
293
294
			final Object oldValue = cachedValues.get(new IdentityWrapper(
295
					masterValue));
296
			final Object newValue = detailProperty.getValue(masterValue);
297
298
			if (!Util.equals(oldValue, newValue)) {
299
				cachedValues.put(new IdentityWrapper(masterValue), newValue);
300
				fireMapChange(new MapDiff() {
301
					public Set getAddedKeys() {
302
						return Collections.EMPTY_SET;
303
					}
304
305
					public Set getChangedKeys() {
306
						return keys;
307
					}
308
309
					public Set getRemovedKeys() {
310
						return Collections.EMPTY_SET;
311
					}
312
313
					public Object getNewValue(Object key) {
314
						return newValue;
315
					}
316
317
					public Object getOldValue(Object key) {
318
						return oldValue;
319
					}
320
				});
321
			}
322
		}
323
	}
324
325
	private Set keysFor(Object value) {
326
		Set keys = new HashSet();
327
328
		for (Iterator it = masterMap.entrySet().iterator(); it.hasNext();) {
329
			Map.Entry entry = (Entry) it.next();
330
			if (entry.getValue() == value) {
331
				keys.add(entry.getKey());
332
			}
333
		}
334
335
		return keys;
336
	}
337
338
	public boolean isStale() {
339
		getterCalled();
340
		return masterMap.isStale();
341
	}
342
343
	private void getterCalled() {
344
		ObservableTracker.getterCalled(this);
345
	}
346
347
	public Object getObserved() {
348
		return masterMap;
349
	}
350
351
	public synchronized void dispose() {
352
		if (masterMap != null) {
353
			masterMap.removeMapChangeListener(masterListener);
354
			masterMap = null;
355
		}
356
		if (knownMasterValues != null) {
357
			knownMasterValues.clear(); // detaches listeners
358
			knownMasterValues.dispose();
359
			knownMasterValues = null;
360
		}
361
362
		masterListener = null;
363
		detailListener = null;
364
		detailProperty = null;
365
		cachedValues = null;
366
367
		super.dispose();
368
	}
369
}
(-)src/org/eclipse/core/databinding/property/value/SimpleValuePropertyObservableValue.java (-130 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 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property.value;
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.observable.value.ValueDiff;
18
import org.eclipse.core.databinding.property.INativePropertyListener;
19
import org.eclipse.core.databinding.property.IProperty;
20
import org.eclipse.core.databinding.property.IPropertyChangeListener;
21
import org.eclipse.core.databinding.property.IPropertyObservable;
22
import org.eclipse.core.databinding.property.PropertyChangeEvent;
23
import org.eclipse.core.internal.databinding.Util;
24
25
/**
26
 * @since 1.2
27
 * 
28
 */
29
class SimpleValuePropertyObservableValue extends AbstractObservableValue
30
		implements IPropertyObservable {
31
	private Object source;
32
	private SimpleValueProperty property;
33
34
	private boolean updating = false;
35
	private Object cachedValue;
36
37
	private INativePropertyListener listener;
38
39
	/**
40
	 * @param realm
41
	 * @param source
42
	 * @param property
43
	 */
44
	public SimpleValuePropertyObservableValue(Realm realm, Object source,
45
			SimpleValueProperty property) {
46
		super(realm);
47
		this.source = source;
48
		this.property = property;
49
	}
50
51
	protected void firstListenerAdded() {
52
		if (!isDisposed()) {
53
			cachedValue = property.getValue(source);
54
			if (listener == null) {
55
				listener = property
56
						.adaptListener(new IPropertyChangeListener() {
57
							public void handlePropertyChange(
58
									final PropertyChangeEvent event) {
59
								if (!isDisposed() && !updating) {
60
									getRealm().exec(new Runnable() {
61
										public void run() {
62
											notifyIfChanged((ValueDiff) event.diff);
63
										}
64
									});
65
								}
66
							}
67
						});
68
			}
69
			property.addListener(source, listener);
70
		}
71
	}
72
73
	protected void lastListenerRemoved() {
74
		if (listener != null) {
75
			property.removeListener(source, listener);
76
		}
77
		cachedValue = null;
78
	}
79
80
	protected Object doGetValue() {
81
		notifyIfChanged(null);
82
		return property.getValue(source);
83
	}
84
85
	protected void doSetValue(Object value) {
86
		updating = true;
87
		try {
88
			property.setValue(source, value);
89
		} finally {
90
			updating = false;
91
		}
92
93
		notifyIfChanged(null);
94
	}
95
96
	private void notifyIfChanged(ValueDiff diff) {
97
		if (hasListeners()) {
98
			Object oldValue = cachedValue;
99
			Object newValue = cachedValue = property.getValue(source);
100
			if (diff == null)
101
				diff = Diffs.createValueDiff(oldValue, newValue);
102
			if (hasListeners() && !Util.equals(oldValue, newValue)) {
103
				fireValueChange(diff);
104
			}
105
		}
106
	}
107
108
	public Object getValueType() {
109
		return property.getValueType();
110
	}
111
112
	public Object getObserved() {
113
		return source;
114
	}
115
116
	public IProperty getProperty() {
117
		return property;
118
	}
119
120
	public synchronized void dispose() {
121
		if (!isDisposed()) {
122
			if (listener != null)
123
				property.removeListener(source, listener);
124
			source = null;
125
			property = null;
126
			listener = null;
127
		}
128
		super.dispose();
129
	}
130
}
(-)src/org/eclipse/core/databinding/property/value/DelegatingValueProperty.java (-4 / +16 lines)
Lines 17-23 Link Here
17
import org.eclipse.core.databinding.observable.set.IObservableSet;
17
import org.eclipse.core.databinding.observable.set.IObservableSet;
18
import org.eclipse.core.databinding.observable.value.IObservableValue;
18
import org.eclipse.core.databinding.observable.value.IObservableValue;
19
import org.eclipse.core.databinding.property.INativePropertyListener;
19
import org.eclipse.core.databinding.property.INativePropertyListener;
20
import org.eclipse.core.databinding.property.IPropertyChangeListener;
20
import org.eclipse.core.databinding.property.ISimplePropertyListener;
21
import org.eclipse.core.internal.databinding.property.value.ObservableListDelegatingValuePropertyObservableList;
22
import org.eclipse.core.internal.databinding.property.value.ObservableMapDelegatingValuePropertyObservableMap;
23
import org.eclipse.core.internal.databinding.property.value.ObservableSetDelegatingValuePropertyObservableMap;
21
24
22
/**
25
/**
23
 * @since 1.2
26
 * @since 1.2
Lines 35-41 Link Here
35
		this.valueType = valueType;
38
		this.valueType = valueType;
36
	}
39
	}
37
40
38
	protected final IValueProperty getDelegate(Object source) {
41
	/**
42
	 * Returns the property to delegate to for the specified source object.
43
	 * Repeated calls to this method with the same source object returns the
44
	 * same delegate instance.
45
	 * 
46
	 * @param source
47
	 *            the property source (may be null)
48
	 * @return the property to delegate to for the specified source object.
49
	 */
50
	public final IValueProperty getDelegate(Object source) {
39
		if (source == null)
51
		if (source == null)
40
			return null;
52
			return null;
41
		IValueProperty delegate = doGetDelegate(source);
53
		IValueProperty delegate = doGetDelegate(source);
Lines 90-97 Link Here
90
		protected void doSetValue(Object source, Object value) {
102
		protected void doSetValue(Object source, Object value) {
91
		}
103
		}
92
104
93
		protected INativePropertyListener adaptListener(
105
		public INativePropertyListener adaptListener(
94
				IPropertyChangeListener listener) {
106
				ISimplePropertyListener listener) {
95
			return null;
107
			return null;
96
		}
108
		}
97
109
(-)src/org/eclipse/core/databinding/property/INativePropertyListener.java (+1 lines)
Lines 18-23 Link Here
18
 * provided when the native listener was constructed.
18
 * provided when the native listener was constructed.
19
 * 
19
 * 
20
 * @since 1.2
20
 * @since 1.2
21
 * @see ISimpleProperty#adaptListener(ISimplePropertyListener)
21
 */
22
 */
22
public interface INativePropertyListener {
23
public interface INativePropertyListener {
23
}
24
}
(-)src/org/eclipse/core/databinding/property/IPropertyChangeListener.java (-30 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 194734)
10
 *     Matthew Hall - but 194734
11
 ******************************************************************************/
12
13
package org.eclipse.core.databinding.property;
14
15
/**
16
 * Listener for changes to properties on a particular source object
17
 * 
18
 * @noextend This interface is not intended to be extended by clients.
19
 * 
20
 * @since 1.2
21
 */
22
public interface IPropertyChangeListener {
23
	/**
24
	 * Handle the property change described in the event.
25
	 * 
26
	 * @param event
27
	 *            an event describing the list change that occured.
28
	 */
29
	public void handlePropertyChange(PropertyChangeEvent event);
30
}
(-)src/org/eclipse/core/databinding/property/PropertyChangeEvent.java (-76 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 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property;
13
14
import java.util.EventObject;
15
16
import org.eclipse.core.databinding.observable.IDiff;
17
import org.eclipse.core.internal.databinding.Util;
18
19
/**
20
 * Base class for change events in the properties API
21
 * 
22
 * @since 1.2
23
 */
24
public final class PropertyChangeEvent extends EventObject {
25
	private static final long serialVersionUID = 1L;
26
27
	/**
28
	 * The property that changed
29
	 */
30
	public final IProperty property;
31
32
	/**
33
	 * A diff object describing the change in state, or null for an unknown
34
	 * change.
35
	 */
36
	public final IDiff diff;
37
38
	/**
39
	 * Constructs a PropertyChangeEvent 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 diff describing the change in state, or null if the change
47
	 *            is unknown.
48
	 */
49
	public PropertyChangeEvent(Object source, IProperty property, IDiff diff) {
50
		super(source);
51
		this.property = property;
52
		this.diff = diff;
53
	}
54
55
	public boolean equals(Object obj) {
56
		if (obj == this)
57
			return true;
58
		if (obj == null)
59
			return false;
60
		if (getClass() != obj.getClass())
61
			return false;
62
63
		PropertyChangeEvent that = (PropertyChangeEvent) obj;
64
		return Util.equals(getSource(), that.getSource())
65
				&& Util.equals(this.property, that.property)
66
				&& Util.equals(this.diff, that.diff);
67
	}
68
69
	public int hashCode() {
70
		int hash = 17;
71
		hash = hash * 37 + getSource().hashCode();
72
		hash = hash * 37 + property.hashCode();
73
		hash = hash * 37 + (diff == null ? 0 : diff.hashCode());
74
		return hash;
75
	}
76
}
(-)src/org/eclipse/core/databinding/property/list/DelegatingListProperty.java (-4 / +22 lines)
Lines 18-24 Link Here
18
import org.eclipse.core.databinding.observable.list.IObservableList;
18
import org.eclipse.core.databinding.observable.list.IObservableList;
19
import org.eclipse.core.databinding.observable.list.ListDiff;
19
import org.eclipse.core.databinding.observable.list.ListDiff;
20
import org.eclipse.core.databinding.property.INativePropertyListener;
20
import org.eclipse.core.databinding.property.INativePropertyListener;
21
import org.eclipse.core.databinding.property.IPropertyChangeListener;
21
import org.eclipse.core.databinding.property.ISimplePropertyListener;
22
22
23
/**
23
/**
24
 * @since 1.2
24
 * @since 1.2
Lines 37-43 Link Here
37
		this.nullProperty = new NullListProperty();
37
		this.nullProperty = new NullListProperty();
38
	}
38
	}
39
39
40
	protected final IListProperty getDelegate(Object source) {
40
	/**
41
	 * Returns the property to delegate to for the specified source object.
42
	 * Repeated calls to this method with the same source object returns the
43
	 * same delegate instance.
44
	 * 
45
	 * @param source
46
	 *            the property source (may be null)
47
	 * @return the property to delegate to for the specified source object.
48
	 */
49
	public final IListProperty getDelegate(Object source) {
41
		if (source == null)
50
		if (source == null)
42
			return null;
51
			return null;
43
		IListProperty delegate = doGetDelegate(source);
52
		IListProperty delegate = doGetDelegate(source);
Lines 46-51 Link Here
46
		return delegate;
55
		return delegate;
47
	}
56
	}
48
57
58
	/**
59
	 * Returns the property to delegate to for the specified source object.
60
	 * Implementers must ensure that repeated calls to this method with the same
61
	 * source object returns the same delegate instance.
62
	 * 
63
	 * @param source
64
	 *            the property source
65
	 * @return the property to delegate to for the specified source object.
66
	 */
49
	protected abstract IListProperty doGetDelegate(Object source);
67
	protected abstract IListProperty doGetDelegate(Object source);
50
68
51
	public Object getElementType() {
69
	public Object getElementType() {
Lines 68-75 Link Here
68
		protected void doSetList(Object source, List list, ListDiff diff) {
86
		protected void doSetList(Object source, List list, ListDiff diff) {
69
		}
87
		}
70
88
71
		protected INativePropertyListener adaptListener(
89
		public INativePropertyListener adaptListener(
72
				IPropertyChangeListener listener) {
90
				ISimplePropertyListener listener) {
73
			return null;
91
			return null;
74
		}
92
		}
75
93
(-)src/org/eclipse/core/databinding/property/list/SimpleListPropertyObservableList.java (-666 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 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property.list;
13
14
import java.util.ArrayList;
15
import java.util.Collection;
16
import java.util.Collections;
17
import java.util.ConcurrentModificationException;
18
import java.util.Iterator;
19
import java.util.List;
20
import java.util.ListIterator;
21
22
import org.eclipse.core.databinding.observable.Diffs;
23
import org.eclipse.core.databinding.observable.ObservableTracker;
24
import org.eclipse.core.databinding.observable.Realm;
25
import org.eclipse.core.databinding.observable.list.AbstractObservableList;
26
import org.eclipse.core.databinding.observable.list.ListDiff;
27
import org.eclipse.core.databinding.observable.list.ListDiffEntry;
28
import org.eclipse.core.databinding.property.IProperty;
29
import org.eclipse.core.databinding.property.INativePropertyListener;
30
import org.eclipse.core.databinding.property.IPropertyChangeListener;
31
import org.eclipse.core.databinding.property.IPropertyObservable;
32
import org.eclipse.core.databinding.property.PropertyChangeEvent;
33
34
/**
35
 * @since 1.2
36
 * 
37
 */
38
class SimpleListPropertyObservableList extends AbstractObservableList implements
39
		IPropertyObservable {
40
	private Object source;
41
	private SimpleListProperty property;
42
43
	private volatile boolean updating = false;
44
45
	private volatile int modCount = 0;
46
47
	private INativePropertyListener listener;
48
49
	private List cachedList;
50
51
	/**
52
	 * @param realm
53
	 * @param source
54
	 * @param property
55
	 */
56
	public SimpleListPropertyObservableList(Realm realm, Object source,
57
			SimpleListProperty property) {
58
		super(realm);
59
		this.source = source;
60
		this.property = property;
61
	}
62
63
	protected void firstListenerAdded() {
64
		if (!isDisposed()) {
65
			cachedList = getList();
66
67
			if (listener == null) {
68
				listener = property
69
						.adaptListener(new IPropertyChangeListener() {
70
							public void handlePropertyChange(
71
									final PropertyChangeEvent event) {
72
								modCount++;
73
								if (!isDisposed() && !updating) {
74
									getRealm().exec(new Runnable() {
75
										public void run() {
76
											notifyIfChanged((ListDiff) event.diff);
77
										}
78
									});
79
								}
80
							}
81
						});
82
			}
83
			property.addListener(source, listener);
84
		}
85
	}
86
87
	protected void lastListenerRemoved() {
88
		if (listener != null) {
89
			property.removeListener(source, listener);
90
		}
91
92
		cachedList = null;
93
	}
94
95
	private void getterCalled() {
96
		ObservableTracker.getterCalled(this);
97
	}
98
99
	public Object getElementType() {
100
		return property.getElementType();
101
	}
102
103
	// Queries
104
105
	private List getList() {
106
		return property.getList(source);
107
	}
108
109
	protected int doGetSize() {
110
		return getList().size();
111
	}
112
113
	public boolean contains(Object o) {
114
		getterCalled();
115
		return getList().contains(o);
116
	}
117
118
	public boolean containsAll(Collection c) {
119
		getterCalled();
120
		return getList().containsAll(c);
121
	}
122
123
	public Object get(int index) {
124
		getterCalled();
125
		return getList().get(index);
126
	}
127
128
	public int indexOf(Object o) {
129
		getterCalled();
130
		return getList().indexOf(o);
131
	}
132
133
	public boolean isEmpty() {
134
		getterCalled();
135
		return getList().isEmpty();
136
	}
137
138
	public int lastIndexOf(Object o) {
139
		getterCalled();
140
		return getList().lastIndexOf(o);
141
	}
142
143
	public Object[] toArray() {
144
		getterCalled();
145
		return getList().toArray();
146
	}
147
148
	public Object[] toArray(Object[] a) {
149
		getterCalled();
150
		return getList().toArray(a);
151
	}
152
153
	// Single change operations
154
155
	public boolean add(Object o) {
156
		checkRealm();
157
		add(getList().size(), o);
158
		return true;
159
	}
160
161
	public void add(int index, Object o) {
162
		checkRealm();
163
		boolean wasUpdating = updating;
164
		updating = true;
165
		List list = new ArrayList(getList());
166
		list.add(index, o);
167
		ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry(index,
168
				true, o));
169
		try {
170
			property.setList(source, list, diff);
171
			modCount++;
172
		} finally {
173
			updating = wasUpdating;
174
		}
175
176
		notifyIfChanged(null);
177
	}
178
179
	public Iterator iterator() {
180
		getterCalled();
181
		return new Iterator() {
182
			int expectedModCount = modCount;
183
			List list = new ArrayList(getList());
184
			ListIterator iterator = list.listIterator();
185
186
			Object lastElement = null;
187
			int lastIndex = -1;
188
189
			public boolean hasNext() {
190
				getterCalled();
191
				checkForComodification();
192
				return iterator.hasNext();
193
			}
194
195
			public Object next() {
196
				getterCalled();
197
				checkForComodification();
198
				Object next = lastElement = iterator.next();
199
				lastIndex = iterator.previousIndex();
200
				return next;
201
			}
202
203
			public void remove() {
204
				checkRealm();
205
				checkForComodification();
206
				if (lastIndex == -1)
207
					throw new IllegalStateException();
208
209
				iterator.remove(); // stay in sync
210
				ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry(
211
						lastIndex, false, lastElement));
212
213
				boolean wasUpdating = updating;
214
				updating = true;
215
				try {
216
					property.setList(source, list, diff);
217
					modCount++;
218
				} finally {
219
					updating = wasUpdating;
220
				}
221
222
				notifyIfChanged(null);
223
224
				lastElement = null;
225
				lastIndex = -1;
226
227
				expectedModCount = modCount;
228
			}
229
230
			private void checkForComodification() {
231
				if (expectedModCount != modCount)
232
					throw new ConcurrentModificationException();
233
			}
234
		};
235
	}
236
237
	public Object move(int oldIndex, int newIndex) {
238
		checkRealm();
239
240
		List list = getList();
241
		int size = list.size();
242
		if (oldIndex < 0 || oldIndex >= size || newIndex < 0
243
				|| newIndex >= size)
244
			throw new IndexOutOfBoundsException();
245
246
		if (oldIndex == newIndex)
247
			return list.get(oldIndex);
248
249
		list = new ArrayList(list);
250
		Object element = list.remove(oldIndex);
251
		list.add(newIndex, element);
252
253
		ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry(
254
				oldIndex, false, element), Diffs.createListDiffEntry(newIndex,
255
				true, element));
256
257
		boolean wasUpdating = updating;
258
		updating = true;
259
		try {
260
			property.setList(source, list, diff);
261
			modCount++;
262
		} finally {
263
			updating = wasUpdating;
264
		}
265
266
		notifyIfChanged(null);
267
268
		return element;
269
	}
270
271
	public boolean remove(Object o) {
272
		checkRealm();
273
274
		int index = getList().indexOf(o);
275
		if (index == -1)
276
			return false;
277
278
		remove(index);
279
280
		return true;
281
	}
282
283
	public ListIterator listIterator() {
284
		return listIterator(0);
285
	}
286
287
	public ListIterator listIterator(final int index) {
288
		getterCalled();
289
		return new ListIterator() {
290
			int expectedModCount = modCount;
291
			List list = new ArrayList(getList());
292
			ListIterator iterator = list.listIterator(index);
293
294
			Object lastElement = null;
295
			int lastIndex = -1;
296
297
			public boolean hasNext() {
298
				getterCalled();
299
				checkForComodification();
300
				return iterator.hasNext();
301
			}
302
303
			public int nextIndex() {
304
				getterCalled();
305
				checkForComodification();
306
				return iterator.nextIndex();
307
			}
308
309
			public Object next() {
310
				getterCalled();
311
				checkForComodification();
312
				lastElement = iterator.next();
313
				lastIndex = iterator.previousIndex();
314
				return lastElement;
315
			}
316
317
			public boolean hasPrevious() {
318
				getterCalled();
319
				checkForComodification();
320
				return iterator.hasPrevious();
321
			}
322
323
			public int previousIndex() {
324
				getterCalled();
325
				checkForComodification();
326
				return iterator.previousIndex();
327
			}
328
329
			public Object previous() {
330
				getterCalled();
331
				checkForComodification();
332
				lastElement = iterator.previous();
333
				lastIndex = iterator.nextIndex();
334
				return lastElement;
335
			}
336
337
			public void add(Object o) {
338
				checkRealm();
339
				checkForComodification();
340
				int index = iterator.nextIndex();
341
342
				iterator.add(o); // keep in sync
343
344
				List list = getList();
345
				list.add(index, o);
346
				ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry(
347
						index, true, o));
348
				boolean wasUpdating = updating;
349
				updating = true;
350
				try {
351
					property.setList(source, list, diff);
352
					modCount++;
353
				} finally {
354
					updating = wasUpdating;
355
				}
356
357
				notifyIfChanged(null);
358
359
				lastElement = null;
360
				lastIndex = -1;
361
				expectedModCount = modCount;
362
			}
363
364
			public void set(Object o) {
365
				checkRealm();
366
				checkForComodification();
367
368
				iterator.set(o);
369
				ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry(
370
						lastIndex, false, lastElement), Diffs
371
						.createListDiffEntry(lastIndex, true, o));
372
373
				boolean wasUpdating = updating;
374
				updating = true;
375
				try {
376
					property.setList(source, list, diff);
377
					modCount++;
378
				} finally {
379
					updating = wasUpdating;
380
				}
381
382
				notifyIfChanged(null);
383
384
				lastElement = o;
385
				expectedModCount = modCount;
386
			}
387
388
			public void remove() {
389
				checkRealm();
390
				checkForComodification();
391
				if (lastIndex == -1)
392
					throw new IllegalStateException();
393
394
				iterator.remove(); // keep in sync
395
				ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry(
396
						lastIndex, false, lastElement));
397
398
				boolean wasUpdating = updating;
399
				updating = true;
400
				try {
401
					property.setList(source, list, diff);
402
					modCount++;
403
				} finally {
404
					updating = wasUpdating;
405
				}
406
407
				notifyIfChanged(null);
408
409
				lastElement = null;
410
				lastIndex = -1;
411
				expectedModCount = modCount;
412
			}
413
414
			private void checkForComodification() {
415
				if (expectedModCount != modCount)
416
					throw new ConcurrentModificationException();
417
			}
418
		};
419
	}
420
421
	public Object remove(int index) {
422
		checkRealm();
423
424
		List list = new ArrayList(getList());
425
		Object element = list.remove(index);
426
		ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry(index,
427
				false, element));
428
429
		boolean wasUpdating = updating;
430
		updating = true;
431
		try {
432
			property.setList(source, list, diff);
433
			modCount++;
434
		} finally {
435
			updating = wasUpdating;
436
		}
437
438
		notifyIfChanged(null);
439
440
		return element;
441
	}
442
443
	public Object set(int index, Object o) {
444
		checkRealm();
445
446
		List list = new ArrayList(getList());
447
		Object oldElement = list.set(index, o);
448
449
		ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry(index,
450
				false, oldElement), Diffs.createListDiffEntry(index, true, o));
451
452
		boolean wasUpdating = updating;
453
		updating = true;
454
		try {
455
			property.setList(source, list, diff);
456
			modCount++;
457
		} finally {
458
			updating = wasUpdating;
459
		}
460
461
		notifyIfChanged(null);
462
463
		return oldElement;
464
	}
465
466
	public List subList(int fromIndex, int toIndex) {
467
		getterCalled();
468
		return Collections.unmodifiableList(getList().subList(fromIndex,
469
				toIndex));
470
	}
471
472
	// Bulk change operations
473
474
	public boolean addAll(Collection c) {
475
		checkRealm();
476
477
		return addAll(getList().size(), c);
478
	}
479
480
	public boolean addAll(int index, Collection c) {
481
		checkRealm();
482
483
		if (c.isEmpty())
484
			return false;
485
486
		List list = new ArrayList(getList());
487
		list.addAll(index, c);
488
489
		ListDiffEntry[] entries = new ListDiffEntry[c.size()];
490
		int offsetIndex = 0;
491
		for (Iterator it = c.iterator(); it.hasNext();) {
492
			Object element = it.next();
493
			entries[offsetIndex] = Diffs.createListDiffEntry(index
494
					+ offsetIndex, true, element);
495
			offsetIndex++;
496
		}
497
		ListDiff diff = Diffs.createListDiff(entries);
498
499
		boolean wasUpdating = updating;
500
		updating = true;
501
		try {
502
			property.setList(source, list, diff);
503
			modCount++;
504
		} finally {
505
			updating = wasUpdating;
506
		}
507
508
		notifyIfChanged(null);
509
510
		return true;
511
	}
512
513
	public boolean removeAll(Collection c) {
514
		checkRealm();
515
516
		if (c.isEmpty())
517
			return false;
518
519
		List list = getList();
520
		if (list.isEmpty())
521
			return false;
522
523
		list = new ArrayList(list);
524
		List entries = new ArrayList();
525
		ListDiff diff;
526
527
		boolean wasUpdating = updating;
528
		updating = true;
529
		try {
530
			for (ListIterator it = list.listIterator(); it.hasNext();) {
531
				Object element = it.next();
532
				int index = it.previousIndex();
533
				if (c.contains(element)) {
534
					it.remove();
535
					entries.add(Diffs
536
							.createListDiffEntry(index, false, element));
537
				}
538
			}
539
			if (entries.isEmpty())
540
				return false;
541
542
			diff = Diffs.createListDiff((ListDiffEntry[]) entries
543
					.toArray(new ListDiffEntry[entries.size()]));
544
			property.setList(source, list, diff);
545
			modCount++;
546
		} finally {
547
			updating = wasUpdating;
548
		}
549
550
		notifyIfChanged(null);
551
552
		return !diff.isEmpty();
553
	}
554
555
	public boolean retainAll(Collection c) {
556
		checkRealm();
557
558
		List list = getList();
559
		if (list.isEmpty())
560
			return false;
561
562
		if (c.isEmpty()) {
563
			clear();
564
			return true;
565
		}
566
567
		list = new ArrayList(list);
568
		List entries = new ArrayList();
569
		ListDiff diff;
570
571
		boolean wasUpdating = updating;
572
		updating = true;
573
		try {
574
			for (ListIterator it = list.listIterator(); it.hasNext();) {
575
				Object element = it.next();
576
				int index = it.previousIndex();
577
				if (!c.contains(element)) {
578
					it.remove();
579
					entries.add(Diffs
580
							.createListDiffEntry(index, false, element));
581
				}
582
			}
583
			if (entries.isEmpty())
584
				return false;
585
586
			diff = Diffs.createListDiff((ListDiffEntry[]) entries
587
					.toArray(new ListDiffEntry[entries.size()]));
588
			property.setList(source, list, diff);
589
			modCount++;
590
		} finally {
591
			updating = wasUpdating;
592
		}
593
594
		notifyIfChanged(null);
595
596
		return !diff.isEmpty();
597
	}
598
599
	public void clear() {
600
		checkRealm();
601
602
		List list = getList();
603
		if (list.isEmpty())
604
			return;
605
606
		List entries = new ArrayList();
607
		for (Iterator it = list.iterator(); it.hasNext();) {
608
			// always report 0 as the remove index
609
			entries.add(Diffs.createListDiffEntry(0, false, it.next()));
610
		}
611
612
		ListDiff diff = Diffs.createListDiff((ListDiffEntry[]) entries
613
				.toArray(new ListDiffEntry[entries.size()]));
614
		boolean wasUpdating = updating;
615
		updating = true;
616
		try {
617
			property.setList(source, Collections.EMPTY_LIST, diff);
618
			modCount++;
619
		} finally {
620
			updating = wasUpdating;
621
		}
622
623
		notifyIfChanged(null);
624
	}
625
626
	private void notifyIfChanged(ListDiff diff) {
627
		if (hasListeners()) {
628
			List oldList = cachedList;
629
			List newList = cachedList = property.getList(source);
630
			if (diff == null)
631
				diff = Diffs.computeListDiff(oldList, newList);
632
			if (!diff.isEmpty()) {
633
				fireListChange(diff);
634
			}
635
		}
636
	}
637
638
	public boolean equals(Object o) {
639
		getterCalled();
640
		return getList().equals(o);
641
	}
642
643
	public int hashCode() {
644
		getterCalled();
645
		return getList().hashCode();
646
	}
647
648
	public Object getObserved() {
649
		return source;
650
	}
651
652
	public IProperty getProperty() {
653
		return property;
654
	}
655
656
	public synchronized void dispose() {
657
		if (!isDisposed()) {
658
			if (listener != null)
659
				property.removeListener(source, listener);
660
			property = null;
661
			source = null;
662
			listener = null;
663
		}
664
		super.dispose();
665
	}
666
}
(-)src/org/eclipse/core/databinding/property/list/SimpleListProperty.java (-79 / +20 lines)
Lines 15-25 Link Here
15
import java.util.Collections;
15
import java.util.Collections;
16
import java.util.List;
16
import java.util.List;
17
17
18
import org.eclipse.core.databinding.observable.IDiff;
18
import org.eclipse.core.databinding.observable.Realm;
19
import org.eclipse.core.databinding.observable.Realm;
19
import org.eclipse.core.databinding.observable.list.IObservableList;
20
import org.eclipse.core.databinding.observable.list.IObservableList;
20
import org.eclipse.core.databinding.observable.list.ListDiff;
21
import org.eclipse.core.databinding.observable.list.ListDiff;
21
import org.eclipse.core.databinding.property.INativePropertyListener;
22
import org.eclipse.core.databinding.property.INativePropertyListener;
22
import org.eclipse.core.databinding.property.IPropertyChangeListener;
23
import org.eclipse.core.databinding.property.ISimplePropertyListener;
24
import org.eclipse.core.internal.databinding.property.list.SimpleListPropertyObservableList;
23
25
24
/**
26
/**
25
 * Simplified abstract implementation of IListProperty. This class takes care of
27
 * Simplified abstract implementation of IListProperty. This class takes care of
Lines 31-37 Link Here
31
 * <li> {@link #getElementType()}
33
 * <li> {@link #getElementType()}
32
 * <li> {@link #doGetList(Object)}
34
 * <li> {@link #doGetList(Object)}
33
 * <li> {@link #doSetList(Object, List, ListDiff)}
35
 * <li> {@link #doSetList(Object, List, ListDiff)}
34
 * <li> {@link #adaptListener(IPropertyChangeListener)}
36
 * <li> {@link #adaptListener(ISimplePropertyListener)}
35
 * <li> {@link #doAddListener(Object, INativePropertyListener)}
37
 * <li> {@link #doAddListener(Object, INativePropertyListener)}
36
 * <li> {@link #doRemoveListener(Object, INativePropertyListener)}
38
 * <li> {@link #doRemoveListener(Object, INativePropertyListener)}
37
 * </ul>
39
 * </ul>
Lines 41-64 Link Here
41
 * 
43
 * 
42
 * @since 1.2
44
 * @since 1.2
43
 */
45
 */
44
public abstract class SimpleListProperty extends ListProperty {
46
public abstract class SimpleListProperty extends ListProperty implements
47
		ISimpleListProperty {
45
	public IObservableList observe(Realm realm, Object source) {
48
	public IObservableList observe(Realm realm, Object source) {
46
		return new SimpleListPropertyObservableList(realm, source, this);
49
		return new SimpleListPropertyObservableList(realm, source, this);
47
	}
50
	}
48
51
49
	// Accessors
52
	// Accessors
50
53
51
	/**
54
	public final Object get(Object source) {
52
	 * Returns an unmodifiable List with the current contents of the source's
53
	 * list property
54
	 * 
55
	 * @param source
56
	 *            the property source
57
	 * @return an unmodifiable List with the current contents of the source's
58
	 *         list property
59
	 * @noreference This method is not intended to be referenced by clients.
60
	 */
61
	protected final List getList(Object source) {
62
		if (source == null)
55
		if (source == null)
63
			return Collections.EMPTY_LIST;
56
			return Collections.EMPTY_LIST;
64
		return Collections.unmodifiableList(doGetList(source));
57
		return Collections.unmodifiableList(doGetList(source));
Lines 76-95 Link Here
76
69
77
	// Mutators
70
	// Mutators
78
71
79
	/**
72
	public final void set(Object source, Object value, IDiff diff) {
80
	 * Updates the property on the source with the specified change.
73
		List list = (List) value;
81
	 * 
74
		ListDiff listDiff = (ListDiff) diff;
82
	 * @param source
75
		if (source != null && !listDiff.isEmpty())
83
	 *            the property source
76
			doSetList(source, list, listDiff);
84
	 * @param list
85
	 *            the new list
86
	 * @param diff
87
	 *            a diff describing the change
88
	 * @noreference This method is not intended to be referenced by clients.
89
	 */
90
	protected final void setList(Object source, List list, ListDiff diff) {
91
		if (source != null && !diff.isEmpty())
92
			doSetList(source, list, diff);
93
	}
77
	}
94
78
95
	/**
79
	/**
Lines 105-144 Link Here
105
	 */
89
	 */
106
	protected abstract void doSetList(Object source, List list, ListDiff diff);
90
	protected abstract void doSetList(Object source, List list, ListDiff diff);
107
91
108
	/**
92
	public abstract INativePropertyListener adaptListener(
109
	 * Returns a listener which implements the correct listener interface for
93
			ISimplePropertyListener listener);
110
	 * the expected source object, and which parlays property change events from
111
	 * the source object to the given listener. If there is no listener API for
112
	 * this property, this method returns null.
113
	 * 
114
	 * @param listener
115
	 *            the property listener to receive events
116
	 * @return a native listener which parlays property change events to the
117
	 *         specified listener.
118
	 * @throws ClassCastException
119
	 *             if the provided listener does not implement the correct
120
	 *             listener interface (IValueProperty, IListProperty,
121
	 *             ISetProperty or IMapProperty) depending on the property.
122
	 * @noreference This method is not intended to be referenced by clients.
123
	 * @noreference This method is not intended to be referenced by clients.
124
	 */
125
	protected abstract INativePropertyListener adaptListener(
126
			IPropertyChangeListener listener);
127
94
128
	/**
95
	public final void addListener(Object source,
129
	 * Adds the specified listener as a listener for this property on the
130
	 * specified property source. If the source object has no listener API for
131
	 * this property (i.e. {@link #adaptListener(IPropertyChangeListener)}
132
	 * returns null), this method does nothing.
133
	 * 
134
	 * @param source
135
	 *            the property source
136
	 * @param listener
137
	 *            a listener obtained from calling
138
	 *            {@link #adaptListener(IPropertyChangeListener)}.
139
	 * @noreference This method is not intended to be referenced by clients.
140
	 */
141
	protected final void addListener(Object source,
142
			INativePropertyListener listener) {
96
			INativePropertyListener listener) {
143
		if (source != null)
97
		if (source != null)
144
			doAddListener(source, listener);
98
			doAddListener(source, listener);
Lines 147-179 Link Here
147
	/**
101
	/**
148
	 * Adds the specified listener as a listener for this property on the
102
	 * Adds the specified listener as a listener for this property on the
149
	 * specified property source. If the source object has no listener API for
103
	 * specified property source. If the source object has no listener API for
150
	 * this property (i.e. {@link #adaptListener(IPropertyChangeListener)}
104
	 * this property (i.e. {@link #adaptListener(ISimplePropertyListener)}
151
	 * returns null), this method does nothing.
105
	 * returns null), this method does nothing.
152
	 * 
106
	 * 
153
	 * @param source
107
	 * @param source
154
	 *            the property source
108
	 *            the property source
155
	 * @param listener
109
	 * @param listener
156
	 *            a listener obtained from calling
110
	 *            a listener obtained from calling
157
	 *            {@link #adaptListener(IPropertyChangeListener)}.
111
	 *            {@link #adaptListener(ISimplePropertyListener)}.
158
	 * @noreference This method is not intended to be referenced by clients.
112
	 * @noreference This method is not intended to be referenced by clients.
159
	 */
113
	 */
160
	protected abstract void doAddListener(Object source,
114
	protected abstract void doAddListener(Object source,
161
			INativePropertyListener listener);
115
			INativePropertyListener listener);
162
116
163
	/**
117
	public final void removeListener(Object source,
164
	 * Removes the specified listener as a listener for this property on the
165
	 * specified property source. If the source object has no listener API for
166
	 * this property (i.e. {@link #adaptListener(IPropertyChangeListener)}
167
	 * returns null), this method does nothing.
168
	 * 
169
	 * @param source
170
	 *            the property source
171
	 * @param listener
172
	 *            a listener obtained from calling
173
	 *            {@link #adaptListener(IPropertyChangeListener)}.
174
	 * @noreference This method is not intended to be referenced by clients.
175
	 */
176
	protected final void removeListener(Object source,
177
			INativePropertyListener listener) {
118
			INativePropertyListener listener) {
178
		if (source != null)
119
		if (source != null)
179
			doRemoveListener(source, listener);
120
			doRemoveListener(source, listener);
Lines 182-195 Link Here
182
	/**
123
	/**
183
	 * Removes the specified listener as a listener for this property on the
124
	 * Removes the specified listener as a listener for this property on the
184
	 * specified property source. If the source object has no listener API for
125
	 * specified property source. If the source object has no listener API for
185
	 * this property (i.e. {@link #adaptListener(IPropertyChangeListener)}
126
	 * this property (i.e. {@link #adaptListener(ISimplePropertyListener)}
186
	 * returns null), this method does nothing.
127
	 * returns null), this method does nothing.
187
	 * 
128
	 * 
188
	 * @param source
129
	 * @param source
189
	 *            the property source
130
	 *            the property source
190
	 * @param listener
131
	 * @param listener
191
	 *            a listener obtained from calling
132
	 *            a listener obtained from calling
192
	 *            {@link #adaptListener(IPropertyChangeListener)}.
133
	 *            {@link #adaptListener(ISimplePropertyListener)}.
193
	 * @noreference This method is not intended to be referenced by clients.
134
	 * @noreference This method is not intended to be referenced by clients.
194
	 */
135
	 */
195
	protected abstract void doRemoveListener(Object source,
136
	protected abstract void doRemoveListener(Object source,
(-)src/org/eclipse/core/databinding/property/set/SimpleSetPropertyObservableSet.java (-407 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 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.property.set;
13
14
import java.util.Collection;
15
import java.util.Collections;
16
import java.util.ConcurrentModificationException;
17
import java.util.HashSet;
18
import java.util.Iterator;
19
import java.util.Set;
20
21
import org.eclipse.core.databinding.observable.Diffs;
22
import org.eclipse.core.databinding.observable.Realm;
23
import org.eclipse.core.databinding.observable.set.AbstractObservableSet;
24
import org.eclipse.core.databinding.observable.set.SetDiff;
25
import org.eclipse.core.databinding.property.IProperty;
26
import org.eclipse.core.databinding.property.INativePropertyListener;
27
import org.eclipse.core.databinding.property.IPropertyChangeListener;
28
import org.eclipse.core.databinding.property.IPropertyObservable;
29
import org.eclipse.core.databinding.property.PropertyChangeEvent;
30
31
/**
32
 * @since 1.2
33
 * 
34
 */
35
class SimpleSetPropertyObservableSet extends AbstractObservableSet implements
36
		IPropertyObservable {
37
	private Object source;
38
	private SimpleSetProperty property;
39
40
	private volatile boolean updating = false;
41
42
	private volatile int modCount = 0;
43
44
	private INativePropertyListener listener;
45
46
	private Set cachedSet;
47
48
	/**
49
	 * @param realm
50
	 * @param source
51
	 * @param property
52
	 */
53
	public SimpleSetPropertyObservableSet(Realm realm, Object source,
54
			SimpleSetProperty property) {
55
		super(realm);
56
		this.source = source;
57
		this.property = property;
58
	}
59
60
	protected void firstListenerAdded() {
61
		if (!isDisposed()) {
62
			cachedSet = getSet();
63
64
			if (listener == null) {
65
				listener = property
66
						.adaptListener(new IPropertyChangeListener() {
67
							public void handlePropertyChange(
68
									final PropertyChangeEvent event) {
69
								modCount++;
70
								if (!isDisposed() && !updating) {
71
									getRealm().exec(new Runnable() {
72
										public void run() {
73
											notifyIfChanged((SetDiff) event.diff);
74
										}
75
									});
76
								}
77
							}
78
						});
79
			}
80
			property.addListener(source, listener);
81
		}
82
	}
83
84
	protected void lastListenerRemoved() {
85
		if (listener != null) {
86
			property.removeListener(source, listener);
87
		}
88
89
		cachedSet = null;
90
	}
91
92
	protected Set getWrappedSet() {
93
		return getSet();
94
	}
95
96
	public Object getElementType() {
97
		return property.getElementType();
98
	}
99
100
	// Queries
101
102
	private Set getSet() {
103
		return property.getSet(source);
104
	}
105
106
	public boolean contains(Object o) {
107
		getterCalled();
108
		return getSet().contains(o);
109
	}
110
111
	public boolean containsAll(Collection c) {
112
		getterCalled();
113
		return getSet().containsAll(c);
114
	}
115
116
	public boolean isEmpty() {
117
		getterCalled();
118
		return getSet().isEmpty();
119
	}
120
121
	public Object[] toArray() {
122
		getterCalled();
123
		return getSet().toArray();
124
	}
125
126
	public Object[] toArray(Object[] a) {
127
		getterCalled();
128
		return getSet().toArray(a);
129
	}
130
131
	// Single change operations
132
133
	public boolean add(Object o) {
134
		checkRealm();
135
136
		Set set = new HashSet(getSet());
137
		if (!set.add(o))
138
			return false;
139
140
		SetDiff diff = Diffs.createSetDiff(Collections.singleton(o),
141
				Collections.EMPTY_SET);
142
143
		boolean wasUpdating = updating;
144
		updating = true;
145
		try {
146
			property.setSet(source, set, diff);
147
			modCount++;
148
		} finally {
149
			updating = wasUpdating;
150
		}
151
152
		notifyIfChanged(null);
153
154
		return true;
155
	}
156
157
	public Iterator iterator() {
158
		getterCalled();
159
		return new Iterator() {
160
			int expectedModCount = modCount;
161
			Set set = new HashSet(getSet());
162
			Iterator iterator = set.iterator();
163
			Object last = null;
164
165
			public boolean hasNext() {
166
				getterCalled();
167
				checkForComodification();
168
				return iterator.hasNext();
169
			}
170
171
			public Object next() {
172
				getterCalled();
173
				checkForComodification();
174
				last = iterator.next();
175
				return last;
176
			}
177
178
			public void remove() {
179
				checkRealm();
180
				checkForComodification();
181
182
				iterator.remove(); // stay in sync
183
				SetDiff diff = Diffs.createSetDiff(Collections.EMPTY_SET,
184
						Collections.singleton(last));
185
186
				boolean wasUpdating = updating;
187
				updating = true;
188
				try {
189
					property.setSet(source, set, diff);
190
					modCount++;
191
				} finally {
192
					updating = wasUpdating;
193
				}
194
195
				notifyIfChanged(null);
196
197
				last = null;
198
				expectedModCount = modCount;
199
			}
200
201
			private void checkForComodification() {
202
				if (expectedModCount != modCount)
203
					throw new ConcurrentModificationException();
204
			}
205
		};
206
	}
207
208
	public boolean remove(Object o) {
209
		getterCalled();
210
211
		Set set = new HashSet(getSet());
212
		if (!set.remove(o))
213
			return false;
214
215
		SetDiff diff = Diffs.createSetDiff(Collections.EMPTY_SET, Collections
216
				.singleton(o));
217
218
		boolean wasUpdating = updating;
219
		updating = true;
220
		try {
221
			property.setSet(source, set, diff);
222
			modCount++;
223
		} finally {
224
			updating = wasUpdating;
225
		}
226
227
		notifyIfChanged(null);
228
229
		return true;
230
	}
231
232
	// Bulk change operations
233
234
	public boolean addAll(Collection c) {
235
		getterCalled();
236
237
		if (c.isEmpty())
238
			return false;
239
240
		Set set = new HashSet(getSet());
241
242
		Set additions = new HashSet(c);
243
		for (Iterator it = c.iterator(); it.hasNext();) {
244
			Object element = it.next();
245
			if (set.add(element))
246
				additions.add(element);
247
		}
248
249
		if (additions.isEmpty())
250
			return false;
251
252
		SetDiff diff = Diffs.createSetDiff(additions, Collections.EMPTY_SET);
253
254
		boolean wasUpdating = updating;
255
		updating = true;
256
		try {
257
			property.setSet(source, set, diff);
258
			modCount++;
259
		} finally {
260
			updating = wasUpdating;
261
		}
262
263
		notifyIfChanged(null);
264
265
		return true;
266
	}
267
268
	public boolean removeAll(Collection c) {
269
		getterCalled();
270
271
		Set set = getSet();
272
		if (set.isEmpty())
273
			return false;
274
		if (c.isEmpty())
275
			return false;
276
277
		set = new HashSet(set);
278
279
		Set removals = new HashSet(c);
280
		for (Iterator it = c.iterator(); it.hasNext();) {
281
			Object element = it.next();
282
			if (set.remove(element))
283
				removals.add(element);
284
		}
285
286
		if (removals.isEmpty())
287
			return false;
288
289
		SetDiff diff = Diffs.createSetDiff(Collections.EMPTY_SET, removals);
290
291
		boolean wasUpdating = updating;
292
		updating = true;
293
		try {
294
			property.setSet(source, set, diff);
295
			modCount++;
296
		} finally {
297
			updating = wasUpdating;
298
		}
299
300
		notifyIfChanged(null);
301
302
		return true;
303
	}
304
305
	public boolean retainAll(Collection c) {
306
		getterCalled();
307
308
		Set set = getSet();
309
		if (set.isEmpty())
310
			return false;
311
312
		if (c.isEmpty()) {
313
			clear();
314
			return true;
315
		}
316
317
		set = new HashSet(set);
318
319
		Set removals = new HashSet();
320
		for (Iterator it = set.iterator(); it.hasNext();) {
321
			Object element = it.next();
322
			if (!c.contains(element)) {
323
				it.remove();
324
				removals.add(element);
325
			}
326
		}
327
328
		if (removals.isEmpty())
329
			return false;
330
331
		SetDiff diff = Diffs.createSetDiff(Collections.EMPTY_SET, removals);
332
333
		boolean wasUpdating = updating;
334
		updating = true;
335
		try {
336
			property.setSet(source, set, diff);
337
			modCount++;
338
		} finally {
339
			updating = wasUpdating;
340
		}
341
342
		notifyIfChanged(null);
343
344
		return true;
345
	}
346
347
	public void clear() {
348
		getterCalled();
349
350
		Set set = getSet();
351
		if (set.isEmpty())
352
			return;
353
354
		SetDiff diff = Diffs.createSetDiff(Collections.EMPTY_SET, set);
355
356
		boolean wasUpdating = updating;
357
		updating = true;
358
		try {
359
			property.setSet(source, Collections.EMPTY_SET, diff);
360
			modCount++;
361
		} finally {
362
			updating = wasUpdating;
363
		}
364
365
		notifyIfChanged(null);
366
	}
367
368
	private void notifyIfChanged(SetDiff diff) {
369
		if (hasListeners()) {
370
			Set oldSet = cachedSet;
371
			Set newSet = cachedSet = property.getSet(source);
372
			if (diff == null)
373
				diff = Diffs.computeSetDiff(oldSet, newSet);
374
			if (!diff.isEmpty())
375
				fireSetChange(diff);
376
		}
377
	}
378
379
	public boolean equals(Object o) {
380
		getterCalled();
381
		return getSet().equals(o);
382
	}
383
384
	public int hashCode() {
385
		getterCalled();
386
		return getSet().hashCode();
387
	}
388
389
	public Object getObserved() {
390
		return source;
391
	}
392
393
	public IProperty getProperty() {
394
		return property;
395
	}
396
397
	public synchronized void dispose() {
398
		if (!isDisposed()) {
399
			if (listener != null)
400
				property.removeListener(source, listener);
401
			property = null;
402
			source = null;
403
			listener = null;
404
		}
405
		super.dispose();
406
	}
407
}
(-)src/org/eclipse/core/databinding/property/set/DelegatingSetProperty.java (-3 / +21 lines)
Lines 18-24 Link Here
18
import org.eclipse.core.databinding.observable.set.IObservableSet;
18
import org.eclipse.core.databinding.observable.set.IObservableSet;
19
import org.eclipse.core.databinding.observable.set.SetDiff;
19
import org.eclipse.core.databinding.observable.set.SetDiff;
20
import org.eclipse.core.databinding.property.INativePropertyListener;
20
import org.eclipse.core.databinding.property.INativePropertyListener;
21
import org.eclipse.core.databinding.property.IPropertyChangeListener;
21
import org.eclipse.core.databinding.property.ISimplePropertyListener;
22
22
23
/**
23
/**
24
 * @since 1.2
24
 * @since 1.2
Lines 36-41 Link Here
36
		this.elementType = elementType;
36
		this.elementType = elementType;
37
	}
37
	}
38
38
39
	/**
40
	 * Returns the property to delegate to for the specified source object.
41
	 * Repeated calls to this method with the same source object returns the
42
	 * same delegate instance.
43
	 * 
44
	 * @param source
45
	 *            the property source (may be null)
46
	 * @return the property to delegate to for the specified source object.
47
	 */
39
	protected final ISetProperty getDelegate(Object source) {
48
	protected final ISetProperty getDelegate(Object source) {
40
		if (source == null)
49
		if (source == null)
41
			return null;
50
			return null;
Lines 45-50 Link Here
45
		return delegate;
54
		return delegate;
46
	}
55
	}
47
56
57
	/**
58
	 * Returns the property to delegate to for the specified source object.
59
	 * Implementers must ensure that repeated calls to this method with the same
60
	 * source object returns the same delegate instance.
61
	 * 
62
	 * @param source
63
	 *            the property source
64
	 * @return the property to delegate to for the specified source object.
65
	 */
48
	protected abstract ISetProperty doGetDelegate(Object source);
66
	protected abstract ISetProperty doGetDelegate(Object source);
49
67
50
	public Object getElementType() {
68
	public Object getElementType() {
Lines 67-74 Link Here
67
		protected void doSetSet(Object source, Set set, SetDiff diff) {
85
		protected void doSetSet(Object source, Set set, SetDiff diff) {
68
		}
86
		}
69
87
70
		protected INativePropertyListener adaptListener(
88
		public INativePropertyListener adaptListener(
71
				IPropertyChangeListener listener) {
89
				ISimplePropertyListener listener) {
72
			return null;
90
			return null;
73
		}
91
		}
74
92
(-)src/org/eclipse/core/databinding/property/set/SimpleSetProperty.java (-77 / +20 lines)
Lines 15-25 Link Here
15
import java.util.Collections;
15
import java.util.Collections;
16
import java.util.Set;
16
import java.util.Set;
17
17
18
import org.eclipse.core.databinding.observable.IDiff;
18
import org.eclipse.core.databinding.observable.Realm;
19
import org.eclipse.core.databinding.observable.Realm;
19
import org.eclipse.core.databinding.observable.set.IObservableSet;
20
import org.eclipse.core.databinding.observable.set.IObservableSet;
20
import org.eclipse.core.databinding.observable.set.SetDiff;
21
import org.eclipse.core.databinding.observable.set.SetDiff;
21
import org.eclipse.core.databinding.property.INativePropertyListener;
22
import org.eclipse.core.databinding.property.INativePropertyListener;
22
import org.eclipse.core.databinding.property.IPropertyChangeListener;
23
import org.eclipse.core.databinding.property.ISimplePropertyListener;
24
import org.eclipse.core.internal.databinding.property.set.SimpleSetPropertyObservableSet;
23
25
24
/**
26
/**
25
 * Simplified abstract implementation of ISetProperty. This class takes care of
27
 * Simplified abstract implementation of ISetProperty. This class takes care of
Lines 31-37 Link Here
31
 * <li> {@link #getElementType()}
33
 * <li> {@link #getElementType()}
32
 * <li> {@link #doGetSet(Object)}
34
 * <li> {@link #doGetSet(Object)}
33
 * <li> {@link #doSetSet(Object, Set, SetDiff)}
35
 * <li> {@link #doSetSet(Object, Set, SetDiff)}
34
 * <li> {@link #adaptListener(IPropertyChangeListener)}
36
 * <li> {@link #adaptListener(ISimplePropertyListener)}
35
 * <li> {@link #doAddListener(Object, INativePropertyListener)}
37
 * <li> {@link #doAddListener(Object, INativePropertyListener)}
36
 * <li> {@link #doRemoveListener(Object, INativePropertyListener)}
38
 * <li> {@link #doRemoveListener(Object, INativePropertyListener)}
37
 * </ul>
39
 * </ul>
Lines 41-62 Link Here
41
 * 
43
 * 
42
 * @since 1.2
44
 * @since 1.2
43
 */
45
 */
44
public abstract class SimpleSetProperty extends SetProperty {
46
public abstract class SimpleSetProperty extends SetProperty implements
47
		ISimpleSetProperty {
45
	public IObservableSet observe(Realm realm, Object source) {
48
	public IObservableSet observe(Realm realm, Object source) {
46
		return new SimpleSetPropertyObservableSet(realm, source, this);
49
		return new SimpleSetPropertyObservableSet(realm, source, this);
47
	}
50
	}
48
51
49
	// Accessors
52
	// Accessors
50
53
51
	/**
54
	public final Object get(Object source) {
52
	 * Returns a Set with the current contents of the source's set property
53
	 * 
54
	 * @param source
55
	 *            the property source
56
	 * @return a Set with the current contents of the source's set property
57
	 * @noreference This method is not intended to be referenced by clients.
58
	 */
59
	protected final Set getSet(Object source) {
60
		if (source == null)
55
		if (source == null)
61
			return Collections.EMPTY_SET;
56
			return Collections.EMPTY_SET;
62
		return Collections.unmodifiableSet(doGetSet(source));
57
		return Collections.unmodifiableSet(doGetSet(source));
Lines 76-95 Link Here
76
71
77
	// Mutators
72
	// Mutators
78
73
79
	/**
74
	public final void set(Object source, Object value, IDiff diff) {
80
	 * Updates the property on the source with the specified change.
75
		Set set = (Set) value;
81
	 * 
76
		SetDiff setDiff = (SetDiff) diff;
82
	 * @param source
77
		if (source != null && !setDiff.isEmpty())
83
	 *            the property source
78
			doSetSet(source, set, setDiff);
84
	 * @param set
85
	 *            the new set
86
	 * @param diff
87
	 *            a diff describing the change
88
	 * @noreference This method is not intended to be referenced by clients.
89
	 */
90
	protected final void setSet(Object source, Set set, SetDiff diff) {
91
		if (source != null && !diff.isEmpty())
92
			doSetSet(source, set, diff);
93
	}
79
	}
94
80
95
	/**
81
	/**
Lines 107-146 Link Here
107
93
108
	// Listeners
94
	// Listeners
109
95
110
	/**
96
	public abstract INativePropertyListener adaptListener(
111
	 * Returns a listener which implements the correct listener interface for
97
			ISimplePropertyListener listener);
112
	 * the expected source object, and which parlays property change events from
113
	 * the source object to the given listener. If there is no listener API for
114
	 * this property, this method returns null.
115
	 * 
116
	 * @param listener
117
	 *            the property listener to receive events
118
	 * @return a native listener which parlays property change events to the
119
	 *         specified listener.
120
	 * @throws ClassCastException
121
	 *             if the provided listener does not implement the correct
122
	 *             listener interface (IValueProperty, IListProperty,
123
	 *             ISetProperty or IMapProperty) depending on the property.
124
	 * @noreference This method is not intended to be referenced by clients.
125
	 * @noreference This method is not intended to be referenced by clients.
126
	 */
127
	protected abstract INativePropertyListener adaptListener(
128
			IPropertyChangeListener listener);
129
98
130
	/**
99
	public final void addListener(Object source,
131
	 * Adds the specified listener as a listener for this property on the
132
	 * specified property source. If the source object has no listener API for
133
	 * this property (i.e. {@link #adaptListener(IPropertyChangeListener)}
134
	 * returns null), this method does nothing.
135
	 * 
136
	 * @param source
137
	 *            the property source
138
	 * @param listener
139
	 *            a listener obtained from calling
140
	 *            {@link #adaptListener(IPropertyChangeListener)}.
141
	 * @noreference This method is not intended to be referenced by clients.
142
	 */
143
	protected final void addListener(Object source,
144
			INativePropertyListener listener) {
100
			INativePropertyListener listener) {
145
		if (source != null)
101
		if (source != null)
146
			doAddListener(source, listener);
102
			doAddListener(source, listener);
Lines 149-181 Link Here
149
	/**
105
	/**
150
	 * Adds the specified listener as a listener for this property on the
106
	 * Adds the specified listener as a listener for this property on the
151
	 * specified property source. If the source object has no listener API for
107
	 * specified property source. If the source object has no listener API for
152
	 * this property (i.e. {@link #adaptListener(IPropertyChangeListener)}
108
	 * this property (i.e. {@link #adaptListener(ISimplePropertyListener)}
153
	 * returns null), this method does nothing.
109
	 * returns null), this method does nothing.
154
	 * 
110
	 * 
155
	 * @param source
111
	 * @param source
156
	 *            the property source
112
	 *            the property source
157
	 * @param listener
113
	 * @param listener
158
	 *            a listener obtained from calling
114
	 *            a listener obtained from calling
159
	 *            {@link #adaptListener(IPropertyChangeListener)}.
115
	 *            {@link #adaptListener(ISimplePropertyListener)}.
160
	 * @noreference This method is not intended to be referenced by clients.
116
	 * @noreference This method is not intended to be referenced by clients.
161
	 */
117
	 */
162
	protected abstract void doAddListener(Object source,
118
	protected abstract void doAddListener(Object source,
163
			INativePropertyListener listener);
119
			INativePropertyListener listener);
164
120
165
	/**
121
	public final void removeListener(Object source,
166
	 * Removes the specified listener as a listener for this property on the
167
	 * specified property source. If the source object has no listener API for
168
	 * this property (i.e. {@link #adaptListener(IPropertyChangeListener)}
169
	 * returns null), this method does nothing.
170
	 * 
171
	 * @param source
172
	 *            the property source
173
	 * @param listener
174
	 *            a listener obtained from calling
175
	 *            {@link #adaptListener(IPropertyChangeListener)} .
176
	 * @noreference This method is not intended to be referenced by clients.
177
	 */
178
	protected final void removeListener(Object source,
179
			INativePropertyListener listener) {
122
			INativePropertyListener listener) {
180
		if (source != null)
123
		if (source != null)
181
			doRemoveListener(source, listener);
124
			doRemoveListener(source, listener);
Lines 184-197 Link Here
184
	/**
127
	/**
185
	 * Removes the specified listener as a listener for this property on the
128
	 * Removes the specified listener as a listener for this property on the
186
	 * specified property source. If the source object has no listener API for
129
	 * specified property source. If the source object has no listener API for
187
	 * this property (i.e. {@link #adaptListener(IPropertyChangeListener)}
130
	 * this property (i.e. {@link #adaptListener(ISimplePropertyListener)}
188
	 * returns null), this method does nothing.
131
	 * returns null), this method does nothing.
189
	 * 
132
	 * 
190
	 * @param source
133
	 * @param source
191
	 *            the property source
134
	 *            the property source
192
	 * @param listener
135
	 * @param listener
193
	 *            a listener obtained from calling
136
	 *            a listener obtained from calling
194
	 *            {@link #adaptListener(IPropertyChangeListener)} .
137
	 *            {@link #adaptListener(ISimplePropertyListener)} .
195
	 * @noreference This method is not intended to be referenced by clients.
138
	 * @noreference This method is not intended to be referenced by clients.
196
	 */
139
	 */
197
	protected abstract void doRemoveListener(Object source,
140
	protected abstract void doRemoveListener(Object source,
(-)src/org/eclipse/core/internal/databinding/property/map/SimpleMapPropertyObservableMap.java (+297 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.map;
13
14
import java.util.AbstractSet;
15
import java.util.Collection;
16
import java.util.Collections;
17
import java.util.ConcurrentModificationException;
18
import java.util.HashMap;
19
import java.util.HashSet;
20
import java.util.Iterator;
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.ObservableTracker;
26
import org.eclipse.core.databinding.observable.Realm;
27
import org.eclipse.core.databinding.observable.map.AbstractObservableMap;
28
import org.eclipse.core.databinding.observable.map.MapDiff;
29
import org.eclipse.core.databinding.property.INativePropertyListener;
30
import org.eclipse.core.databinding.property.IProperty;
31
import org.eclipse.core.databinding.property.IPropertyObservable;
32
import org.eclipse.core.databinding.property.ISimplePropertyListener;
33
import org.eclipse.core.databinding.property.SimplePropertyEvent;
34
import org.eclipse.core.databinding.property.map.ISimpleMapProperty;
35
36
/**
37
 * @since 1.2
38
 */
39
public class SimpleMapPropertyObservableMap extends AbstractObservableMap
40
		implements IPropertyObservable {
41
	private Object source;
42
	private ISimpleMapProperty property;
43
44
	private volatile boolean updating = false;
45
46
	private volatile int modCount = 0;
47
48
	private INativePropertyListener listener;
49
50
	private Map cachedMap;
51
52
	/**
53
	 * @param realm
54
	 * @param source
55
	 * @param property
56
	 */
57
	public SimpleMapPropertyObservableMap(Realm realm, Object source,
58
			ISimpleMapProperty property) {
59
		super(realm);
60
		this.source = source;
61
		this.property = property;
62
	}
63
64
	public Object getKeyType() {
65
		return property.getKeyType();
66
	}
67
68
	public Object getValueType() {
69
		return property.getValueType();
70
	}
71
72
	private void getterCalled() {
73
		ObservableTracker.getterCalled(this);
74
	}
75
76
	protected void firstListenerAdded() {
77
		if (!isDisposed()) {
78
			cachedMap = new HashMap(this);
79
80
			if (listener == null) {
81
				listener = property
82
						.adaptListener(new ISimplePropertyListener() {
83
							public void handlePropertyChange(
84
									final SimplePropertyEvent event) {
85
								modCount++;
86
								if (!isDisposed() && !updating) {
87
									getRealm().exec(new Runnable() {
88
										public void run() {
89
											notifyIfChanged((MapDiff) event.diff);
90
										}
91
									});
92
								}
93
							}
94
						});
95
			}
96
			property.addListener(source, listener);
97
		}
98
	}
99
100
	protected void lastListenerRemoved() {
101
		if (listener != null) {
102
			property.removeListener(source, listener);
103
		}
104
105
		cachedMap.clear();
106
		cachedMap = null;
107
	}
108
109
	// Queries
110
111
	private Map getMap() {
112
		return (Map) property.get(source);
113
	}
114
115
	// Single change operations
116
117
	private EntrySet es = new EntrySet();
118
119
	public Set entrySet() {
120
		getterCalled();
121
		return es;
122
	}
123
124
	private class EntrySet extends AbstractSet {
125
		public Iterator iterator() {
126
			return new EntrySetIterator();
127
		}
128
129
		public int size() {
130
			return getMap().size();
131
		}
132
	}
133
134
	private class EntrySetIterator implements Iterator {
135
		private volatile int expectedModCount = modCount;
136
		Map map = new HashMap(getMap());
137
		Iterator iterator = map.entrySet().iterator();
138
		Map.Entry last = null;
139
140
		public boolean hasNext() {
141
			getterCalled();
142
			checkForComodification();
143
			return iterator.hasNext();
144
		}
145
146
		public Object next() {
147
			getterCalled();
148
			checkForComodification();
149
			last = (Map.Entry) iterator.next();
150
			return last;
151
		}
152
153
		public void remove() {
154
			getterCalled();
155
			checkForComodification();
156
157
			iterator.remove(); // stay in sync
158
			MapDiff diff = Diffs.createMapDiffSingleRemove(last.getKey(), last
159
					.getValue());
160
161
			boolean wasUpdating = updating;
162
			updating = true;
163
			try {
164
				property.set(source, map, diff);
165
			} finally {
166
				updating = wasUpdating;
167
			}
168
169
			notifyIfChanged(null);
170
171
			last = null;
172
			expectedModCount = modCount;
173
		}
174
175
		private void checkForComodification() {
176
			if (expectedModCount != modCount)
177
				throw new ConcurrentModificationException();
178
		}
179
	}
180
181
	public Set keySet() {
182
		getterCalled();
183
		// AbstractMap depends on entrySet() to fulfil keySet() API, so all
184
		// getterCalled() and comodification checks will still be handled
185
		return super.keySet();
186
	}
187
188
	public Object put(Object key, Object value) {
189
		checkRealm();
190
191
		Map map = new HashMap(getMap());
192
193
		boolean add = !map.containsKey(key);
194
195
		Object oldValue = map.put(key, value);
196
197
		MapDiff diff;
198
		if (add)
199
			diff = Diffs.createMapDiffSingleAdd(key, value);
200
		else
201
			diff = Diffs.createMapDiffSingleChange(key, oldValue, value);
202
203
		boolean wasUpdating = updating;
204
		updating = true;
205
		try {
206
			property.set(source, map, diff);
207
			modCount++;
208
		} finally {
209
			updating = wasUpdating;
210
		}
211
212
		notifyIfChanged(null);
213
214
		return oldValue;
215
	}
216
217
	public void putAll(Map m) {
218
		checkRealm();
219
220
		Map map = new HashMap(getMap());
221
222
		Map oldValues = new HashMap();
223
		Map newValues = new HashMap();
224
		Set changedKeys = new HashSet();
225
		Set addedKeys = new HashSet();
226
		for (Iterator it = m.entrySet().iterator(); it.hasNext();) {
227
			Map.Entry entry = (Entry) it.next();
228
			Object key = entry.getKey();
229
			Object newValue = entry.getValue();
230
			if (map.containsKey(key)) {
231
				changedKeys.add(key);
232
				oldValues.put(key, map.get(key));
233
			} else {
234
				addedKeys.add(key);
235
			}
236
			map.put(key, newValue);
237
238
			newValues.put(key, newValue);
239
		}
240
241
		MapDiff diff = Diffs.createMapDiff(addedKeys, Collections.EMPTY_SET,
242
				changedKeys, oldValues, newValues);
243
244
		boolean wasUpdating = updating;
245
		updating = true;
246
		try {
247
			property.set(source, map, diff);
248
			modCount++;
249
		} finally {
250
			updating = wasUpdating;
251
		}
252
253
		notifyIfChanged(null);
254
	}
255
256
	public Object remove(Object key) {
257
		checkRealm();
258
		return super.remove(key);
259
	}
260
261
	public Collection values() {
262
		getterCalled();
263
		// AbstractMap depends on entrySet() to fulfil values() API, so all
264
		// getterCalled() and comodification checks will still be handled
265
		return super.values();
266
	}
267
268
	private void notifyIfChanged(MapDiff diff) {
269
		if (hasListeners()) {
270
			Map oldMap = cachedMap;
271
			Map newMap = cachedMap = (Map) property.get(source);
272
			if (diff == null)
273
				diff = Diffs.computeMapDiff(oldMap, newMap);
274
			if (!diff.isEmpty())
275
				fireMapChange(diff);
276
		}
277
	}
278
279
	public Object getObserved() {
280
		return source;
281
	}
282
283
	public IProperty getProperty() {
284
		return property;
285
	}
286
287
	public synchronized void dispose() {
288
		if (!isDisposed()) {
289
			if (listener != null)
290
				property.removeListener(source, listener);
291
			property = null;
292
			source = null;
293
			listener = null;
294
		}
295
		super.dispose();
296
	}
297
}
(-)src/org/eclipse/core/internal/databinding/property/set/SimpleSetPropertyObservableSet.java (+408 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.set;
13
14
import java.util.Collection;
15
import java.util.Collections;
16
import java.util.ConcurrentModificationException;
17
import java.util.HashSet;
18
import java.util.Iterator;
19
import java.util.Set;
20
21
import org.eclipse.core.databinding.observable.Diffs;
22
import org.eclipse.core.databinding.observable.Realm;
23
import org.eclipse.core.databinding.observable.set.AbstractObservableSet;
24
import org.eclipse.core.databinding.observable.set.SetDiff;
25
import org.eclipse.core.databinding.property.INativePropertyListener;
26
import org.eclipse.core.databinding.property.IProperty;
27
import org.eclipse.core.databinding.property.IPropertyObservable;
28
import org.eclipse.core.databinding.property.ISimplePropertyListener;
29
import org.eclipse.core.databinding.property.SimplePropertyEvent;
30
import org.eclipse.core.databinding.property.set.ISimpleSetProperty;
31
32
/**
33
 * @since 1.2
34
 * 
35
 */
36
public class SimpleSetPropertyObservableSet extends AbstractObservableSet
37
		implements IPropertyObservable {
38
	private Object source;
39
	private ISimpleSetProperty property;
40
41
	private volatile boolean updating = false;
42
43
	private volatile int modCount = 0;
44
45
	private INativePropertyListener listener;
46
47
	private Set cachedSet;
48
49
	/**
50
	 * @param realm
51
	 * @param source
52
	 * @param property
53
	 */
54
	public SimpleSetPropertyObservableSet(Realm realm, Object source,
55
			ISimpleSetProperty property) {
56
		super(realm);
57
		this.source = source;
58
		this.property = property;
59
	}
60
61
	protected void firstListenerAdded() {
62
		if (!isDisposed()) {
63
			cachedSet = getSet();
64
65
			if (listener == null) {
66
				listener = property
67
						.adaptListener(new ISimplePropertyListener() {
68
							public void handlePropertyChange(
69
									final SimplePropertyEvent event) {
70
								modCount++;
71
								if (!isDisposed() && !updating) {
72
									getRealm().exec(new Runnable() {
73
										public void run() {
74
											notifyIfChanged((SetDiff) event.diff);
75
										}
76
									});
77
								}
78
							}
79
						});
80
			}
81
			property.addListener(source, listener);
82
		}
83
	}
84
85
	protected void lastListenerRemoved() {
86
		if (listener != null) {
87
			property.removeListener(source, listener);
88
		}
89
90
		cachedSet = null;
91
	}
92
93
	protected Set getWrappedSet() {
94
		return getSet();
95
	}
96
97
	public Object getElementType() {
98
		return property.getElementType();
99
	}
100
101
	// Queries
102
103
	private Set getSet() {
104
		return (Set) property.get(source);
105
	}
106
107
	public boolean contains(Object o) {
108
		getterCalled();
109
		return getSet().contains(o);
110
	}
111
112
	public boolean containsAll(Collection c) {
113
		getterCalled();
114
		return getSet().containsAll(c);
115
	}
116
117
	public boolean isEmpty() {
118
		getterCalled();
119
		return getSet().isEmpty();
120
	}
121
122
	public Object[] toArray() {
123
		getterCalled();
124
		return getSet().toArray();
125
	}
126
127
	public Object[] toArray(Object[] a) {
128
		getterCalled();
129
		return getSet().toArray(a);
130
	}
131
132
	// Single change operations
133
134
	public boolean add(Object o) {
135
		checkRealm();
136
137
		Set set = new HashSet(getSet());
138
		if (!set.add(o))
139
			return false;
140
141
		SetDiff diff = Diffs.createSetDiff(Collections.singleton(o),
142
				Collections.EMPTY_SET);
143
144
		boolean wasUpdating = updating;
145
		updating = true;
146
		try {
147
			property.set(source, set, diff);
148
			modCount++;
149
		} finally {
150
			updating = wasUpdating;
151
		}
152
153
		notifyIfChanged(null);
154
155
		return true;
156
	}
157
158
	public Iterator iterator() {
159
		getterCalled();
160
		return new Iterator() {
161
			int expectedModCount = modCount;
162
			Set set = new HashSet(getSet());
163
			Iterator iterator = set.iterator();
164
			Object last = null;
165
166
			public boolean hasNext() {
167
				getterCalled();
168
				checkForComodification();
169
				return iterator.hasNext();
170
			}
171
172
			public Object next() {
173
				getterCalled();
174
				checkForComodification();
175
				last = iterator.next();
176
				return last;
177
			}
178
179
			public void remove() {
180
				checkRealm();
181
				checkForComodification();
182
183
				iterator.remove(); // stay in sync
184
				SetDiff diff = Diffs.createSetDiff(Collections.EMPTY_SET,
185
						Collections.singleton(last));
186
187
				boolean wasUpdating = updating;
188
				updating = true;
189
				try {
190
					property.set(source, set, diff);
191
					modCount++;
192
				} finally {
193
					updating = wasUpdating;
194
				}
195
196
				notifyIfChanged(null);
197
198
				last = null;
199
				expectedModCount = modCount;
200
			}
201
202
			private void checkForComodification() {
203
				if (expectedModCount != modCount)
204
					throw new ConcurrentModificationException();
205
			}
206
		};
207
	}
208
209
	public boolean remove(Object o) {
210
		getterCalled();
211
212
		Set set = new HashSet(getSet());
213
		if (!set.remove(o))
214
			return false;
215
216
		SetDiff diff = Diffs.createSetDiff(Collections.EMPTY_SET, Collections
217
				.singleton(o));
218
219
		boolean wasUpdating = updating;
220
		updating = true;
221
		try {
222
			property.set(source, set, diff);
223
			modCount++;
224
		} finally {
225
			updating = wasUpdating;
226
		}
227
228
		notifyIfChanged(null);
229
230
		return true;
231
	}
232
233
	// Bulk change operations
234
235
	public boolean addAll(Collection c) {
236
		getterCalled();
237
238
		if (c.isEmpty())
239
			return false;
240
241
		Set set = new HashSet(getSet());
242
243
		Set additions = new HashSet(c);
244
		for (Iterator it = c.iterator(); it.hasNext();) {
245
			Object element = it.next();
246
			if (set.add(element))
247
				additions.add(element);
248
		}
249
250
		if (additions.isEmpty())
251
			return false;
252
253
		SetDiff diff = Diffs.createSetDiff(additions, Collections.EMPTY_SET);
254
255
		boolean wasUpdating = updating;
256
		updating = true;
257
		try {
258
			property.set(source, set, diff);
259
			modCount++;
260
		} finally {
261
			updating = wasUpdating;
262
		}
263
264
		notifyIfChanged(null);
265
266
		return true;
267
	}
268
269
	public boolean removeAll(Collection c) {
270
		getterCalled();
271
272
		Set set = getSet();
273
		if (set.isEmpty())
274
			return false;
275
		if (c.isEmpty())
276
			return false;
277
278
		set = new HashSet(set);
279
280
		Set removals = new HashSet(c);
281
		for (Iterator it = c.iterator(); it.hasNext();) {
282
			Object element = it.next();
283
			if (set.remove(element))
284
				removals.add(element);
285
		}
286
287
		if (removals.isEmpty())
288
			return false;
289
290
		SetDiff diff = Diffs.createSetDiff(Collections.EMPTY_SET, removals);
291
292
		boolean wasUpdating = updating;
293
		updating = true;
294
		try {
295
			property.set(source, set, diff);
296
			modCount++;
297
		} finally {
298
			updating = wasUpdating;
299
		}
300
301
		notifyIfChanged(null);
302
303
		return true;
304
	}
305
306
	public boolean retainAll(Collection c) {
307
		getterCalled();
308
309
		Set set = getSet();
310
		if (set.isEmpty())
311
			return false;
312
313
		if (c.isEmpty()) {
314
			clear();
315
			return true;
316
		}
317
318
		set = new HashSet(set);
319
320
		Set removals = new HashSet();
321
		for (Iterator it = set.iterator(); it.hasNext();) {
322
			Object element = it.next();
323
			if (!c.contains(element)) {
324
				it.remove();
325
				removals.add(element);
326
			}
327
		}
328
329
		if (removals.isEmpty())
330
			return false;
331
332
		SetDiff diff = Diffs.createSetDiff(Collections.EMPTY_SET, removals);
333
334
		boolean wasUpdating = updating;
335
		updating = true;
336
		try {
337
			property.set(source, set, diff);
338
			modCount++;
339
		} finally {
340
			updating = wasUpdating;
341
		}
342
343
		notifyIfChanged(null);
344
345
		return true;
346
	}
347
348
	public void clear() {
349
		getterCalled();
350
351
		Set set = getSet();
352
		if (set.isEmpty())
353
			return;
354
355
		SetDiff diff = Diffs.createSetDiff(Collections.EMPTY_SET, set);
356
357
		boolean wasUpdating = updating;
358
		updating = true;
359
		try {
360
			property.set(source, Collections.EMPTY_SET, diff);
361
			modCount++;
362
		} finally {
363
			updating = wasUpdating;
364
		}
365
366
		notifyIfChanged(null);
367
	}
368
369
	private void notifyIfChanged(SetDiff diff) {
370
		if (hasListeners()) {
371
			Set oldSet = cachedSet;
372
			Set newSet = cachedSet = (Set) property.get(source);
373
			if (diff == null)
374
				diff = Diffs.computeSetDiff(oldSet, newSet);
375
			if (!diff.isEmpty())
376
				fireSetChange(diff);
377
		}
378
	}
379
380
	public boolean equals(Object o) {
381
		getterCalled();
382
		return getSet().equals(o);
383
	}
384
385
	public int hashCode() {
386
		getterCalled();
387
		return getSet().hashCode();
388
	}
389
390
	public Object getObserved() {
391
		return source;
392
	}
393
394
	public IProperty getProperty() {
395
		return property;
396
	}
397
398
	public synchronized void dispose() {
399
		if (!isDisposed()) {
400
			if (listener != null)
401
				property.removeListener(source, listener);
402
			property = null;
403
			source = null;
404
			listener = null;
405
		}
406
		super.dispose();
407
	}
408
}
(-)src/org/eclipse/core/internal/databinding/property/value/ObservableSetSimpleValuePropertyObservableMap.java (+145 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.value;
13
14
import java.util.HashMap;
15
import java.util.Iterator;
16
import java.util.Map;
17
18
import org.eclipse.core.databinding.observable.Diffs;
19
import org.eclipse.core.databinding.observable.map.ComputedObservableMap;
20
import org.eclipse.core.databinding.observable.set.IObservableSet;
21
import org.eclipse.core.databinding.property.INativePropertyListener;
22
import org.eclipse.core.databinding.property.IProperty;
23
import org.eclipse.core.databinding.property.IPropertyObservable;
24
import org.eclipse.core.databinding.property.ISimplePropertyListener;
25
import org.eclipse.core.databinding.property.SimplePropertyEvent;
26
import org.eclipse.core.databinding.property.value.ISimpleValueProperty;
27
import org.eclipse.core.internal.databinding.Util;
28
29
/**
30
 * @since 1.2
31
 */
32
public class ObservableSetSimpleValuePropertyObservableMap extends
33
		ComputedObservableMap implements IPropertyObservable {
34
	private ISimpleValueProperty detailProperty;
35
36
	private INativePropertyListener listener;
37
38
	private Map cachedValues;
39
40
	private boolean updating;
41
42
	/**
43
	 * @param keySet
44
	 * @param valueProperty
45
	 */
46
	public ObservableSetSimpleValuePropertyObservableMap(IObservableSet keySet,
47
			ISimpleValueProperty valueProperty) {
48
		super(keySet);
49
		this.detailProperty = valueProperty;
50
	}
51
52
	protected void firstListenerAdded() {
53
		cachedValues = new HashMap(this);
54
		if (listener == null) {
55
			listener = detailProperty
56
					.adaptListener(new ISimplePropertyListener() {
57
						public void handlePropertyChange(
58
								final SimplePropertyEvent event) {
59
							if (!isDisposed() && !updating) {
60
								getRealm().exec(new Runnable() {
61
									public void run() {
62
										notifyIfChanged(event.getSource());
63
									}
64
								});
65
							}
66
						}
67
					});
68
		}
69
		super.firstListenerAdded();
70
	}
71
72
	protected void lastListenerRemoved() {
73
		super.lastListenerRemoved();
74
		cachedValues.clear();
75
		cachedValues = null;
76
	}
77
78
	protected void hookListener(Object addedKey) {
79
		if (listener != null) {
80
			cachedValues.put(addedKey, detailProperty.get(addedKey));
81
			detailProperty.addListener(addedKey, listener);
82
		}
83
	}
84
85
	protected void unhookListener(Object removedKey) {
86
		if (listener != null) {
87
			detailProperty.removeListener(removedKey, listener);
88
			cachedValues.remove(removedKey);
89
		}
90
	}
91
92
	protected Object doGet(Object key) {
93
		return detailProperty.get(key);
94
	}
95
96
	protected Object doPut(Object key, Object value) {
97
		Object oldValue = detailProperty.get(key);
98
99
		updating = true;
100
		try {
101
			detailProperty.set(key, value, Diffs.createValueDiff(oldValue,
102
					value));
103
		} finally {
104
			updating = false;
105
		}
106
107
		notifyIfChanged(key);
108
109
		return oldValue;
110
	}
111
112
	private void notifyIfChanged(Object key) {
113
		if (cachedValues != null) {
114
			Object oldValue = cachedValues.get(key);
115
			Object newValue = detailProperty.get(key);
116
			if (!Util.equals(oldValue, newValue)) {
117
				cachedValues.put(key, newValue);
118
				fireMapChange(Diffs.createMapDiffSingleChange(key, oldValue,
119
						newValue));
120
			}
121
		}
122
	}
123
124
	public Object getObserved() {
125
		return keySet();
126
	}
127
128
	public IProperty getProperty() {
129
		return detailProperty;
130
	}
131
132
	public synchronized void dispose() {
133
		if (!isDisposed()) {
134
			if (listener != null) {
135
				for (Iterator it = values().iterator(); it.hasNext();) {
136
					unhookListener(it.next());
137
				}
138
				listener = null;
139
			}
140
			detailProperty = null;
141
		}
142
143
		super.dispose();
144
	}
145
}
(-)src/org/eclipse/core/internal/databinding/property/value/ObservableSetDelegatingValuePropertyObservableMap.java (+241 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.value;
13
14
import java.util.AbstractSet;
15
import java.util.Collections;
16
import java.util.HashMap;
17
import java.util.Iterator;
18
import java.util.Map;
19
import java.util.Set;
20
21
import org.eclipse.core.databinding.observable.Diffs;
22
import org.eclipse.core.databinding.observable.IStaleListener;
23
import org.eclipse.core.databinding.observable.ObservableTracker;
24
import org.eclipse.core.databinding.observable.StaleEvent;
25
import org.eclipse.core.databinding.observable.map.AbstractObservableMap;
26
import org.eclipse.core.databinding.observable.map.MapDiff;
27
import org.eclipse.core.databinding.observable.set.IObservableSet;
28
import org.eclipse.core.databinding.observable.set.ISetChangeListener;
29
import org.eclipse.core.databinding.observable.set.SetChangeEvent;
30
import org.eclipse.core.databinding.observable.set.SetDiff;
31
import org.eclipse.core.databinding.property.IProperty;
32
import org.eclipse.core.databinding.property.IPropertyObservable;
33
import org.eclipse.core.databinding.property.value.DelegatingValueProperty;
34
import org.eclipse.core.internal.databinding.Util;
35
36
/**
37
 * @since 1.2
38
 */
39
public class ObservableSetDelegatingValuePropertyObservableMap extends
40
		AbstractObservableMap implements IPropertyObservable {
41
	private IObservableSet masterSet;
42
	private DelegatingValueProperty detailProperty;
43
	private DelegatingCache cache;
44
45
	private Set entrySet;
46
47
	class EntrySet extends AbstractSet {
48
		public Iterator iterator() {
49
			return new Iterator() {
50
				final Iterator it = masterSet.iterator();
51
52
				public boolean hasNext() {
53
					return it.hasNext();
54
				}
55
56
				public Object next() {
57
					return new MapEntry(it.next());
58
				}
59
60
				public void remove() {
61
					it.remove();
62
				}
63
			};
64
		}
65
66
		public int size() {
67
			return masterSet.size();
68
		}
69
	}
70
71
	class MapEntry implements Map.Entry {
72
		private final Object key;
73
74
		MapEntry(Object key) {
75
			this.key = key;
76
		}
77
78
		public Object getKey() {
79
			getterCalled();
80
			return key;
81
		}
82
83
		public Object getValue() {
84
			getterCalled();
85
86
			if (!masterSet.contains(key))
87
				return null;
88
89
			return cache.get(key);
90
		}
91
92
		public Object setValue(Object value) {
93
			checkRealm();
94
95
			if (!masterSet.contains(key))
96
				return null;
97
98
			return cache.put(key, value);
99
		}
100
101
		public boolean equals(Object o) {
102
			getterCalled();
103
			if (o == this)
104
				return true;
105
			if (o == null)
106
				return false;
107
			if (!(o instanceof Map.Entry))
108
				return false;
109
			Map.Entry that = (Map.Entry) o;
110
			return Util.equals(this.getKey(), that.getKey())
111
					&& Util.equals(this.getValue(), that.getValue());
112
		}
113
114
		public int hashCode() {
115
			getterCalled();
116
			Object value = getValue();
117
			return (key == null ? 0 : key.hashCode())
118
					^ (value == null ? 0 : value.hashCode());
119
		}
120
	}
121
122
	private ISetChangeListener masterListener = new ISetChangeListener() {
123
		public void handleSetChange(SetChangeEvent event) {
124
			if (isDisposed())
125
				return;
126
127
			cache.addAll(masterSet);
128
129
			// Need both obsolete and new elements to convert diff
130
			MapDiff diff = convertDiff(event.diff);
131
132
			cache.retainAll(masterSet);
133
134
			fireMapChange(diff);
135
		}
136
137
		private MapDiff convertDiff(SetDiff diff) {
138
			// Convert diff to detail value
139
			Map oldValues = new HashMap();
140
			Map newValues = new HashMap();
141
142
			for (Iterator it = diff.getRemovals().iterator(); it.hasNext();) {
143
				Object masterElement = it.next();
144
				oldValues.put(masterElement, cache.get(masterElement));
145
			}
146
			for (Iterator it = diff.getAdditions().iterator(); it.hasNext();) {
147
				Object masterElement = it.next();
148
				newValues.put(masterElement, cache.get(masterElement));
149
			}
150
			return Diffs.createMapDiff(diff.getAdditions(), diff.getRemovals(),
151
					Collections.EMPTY_SET, oldValues, newValues);
152
		}
153
	};
154
155
	private IStaleListener staleListener = new IStaleListener() {
156
		public void handleStale(StaleEvent staleEvent) {
157
			fireStale();
158
		}
159
	};
160
161
	/**
162
	 * @param keySet
163
	 * @param valueProperty
164
	 */
165
	public ObservableSetDelegatingValuePropertyObservableMap(
166
			IObservableSet keySet, DelegatingValueProperty valueProperty) {
167
		super(keySet.getRealm());
168
		this.masterSet = keySet;
169
		this.detailProperty = valueProperty;
170
		this.cache = new DelegatingCache(getRealm(), valueProperty) {
171
			void handleValueChange(Object masterElement, Object oldValue,
172
					Object newValue) {
173
				fireMapChange(Diffs.createMapDiffSingleChange(masterElement,
174
						oldValue, newValue));
175
			}
176
		};
177
		cache.addAll(masterSet);
178
179
		masterSet.addSetChangeListener(masterListener);
180
		masterSet.addStaleListener(staleListener);
181
	}
182
183
	public Set entrySet() {
184
		getterCalled();
185
		if (entrySet == null)
186
			entrySet = new EntrySet();
187
		return entrySet;
188
	}
189
190
	private void getterCalled() {
191
		ObservableTracker.getterCalled(this);
192
	}
193
194
	public Object get(Object key) {
195
		getterCalled();
196
		return cache.get(key);
197
	}
198
199
	public Object put(Object key, Object value) {
200
		checkRealm();
201
		return cache.put(key, value);
202
	}
203
204
	public boolean isStale() {
205
		return masterSet.isStale();
206
	}
207
208
	public Object getObserved() {
209
		return masterSet;
210
	}
211
212
	public IProperty getProperty() {
213
		return detailProperty;
214
	}
215
216
	public Object getKeyType() {
217
		return masterSet.getElementType();
218
	}
219
220
	public Object getValueType() {
221
		return detailProperty.getValueType();
222
	}
223
224
	public synchronized void dispose() {
225
		if (masterSet != null) {
226
			masterSet.removeSetChangeListener(masterListener);
227
			masterSet.removeStaleListener(staleListener);
228
			masterSet = null;
229
		}
230
231
		if (cache != null) {
232
			cache.dispose();
233
			cache = null;
234
		}
235
236
		masterListener = null;
237
		detailProperty = null;
238
239
		super.dispose();
240
	}
241
}
(-)src/org/eclipse/core/databinding/property/ISimplePropertyListener.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
 *     Matthew Hall - but 194734
11
 ******************************************************************************/
12
13
package org.eclipse.core.databinding.property;
14
15
/**
16
 * Listener for changes to properties on a particular source object
17
 * 
18
 * @noextend This interface is not intended to be extended by clients.
19
 * 
20
 * @since 1.2
21
 */
22
public interface ISimplePropertyListener {
23
	/**
24
	 * Handle the property change described in the event.
25
	 * 
26
	 * @param event
27
	 *            an event describing the property change that occured.
28
	 */
29
	public void handlePropertyChange(SimplePropertyEvent event);
30
}
(-)src/org/eclipse/core/databinding/property/list/ISimpleListProperty.java (+21 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 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.list;
13
14
import org.eclipse.core.databinding.property.ISimpleProperty;
15
16
/**
17
 * @since 1.2
18
 * 
19
 */
20
public interface ISimpleListProperty extends ISimpleProperty, IListProperty {
21
}
(-)src/org/eclipse/core/internal/databinding/property/value/ObservableMapSimpleValuePropertyObservableMap.java (+377 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.value;
13
14
import java.util.AbstractSet;
15
import java.util.Collections;
16
import java.util.HashMap;
17
import java.util.HashSet;
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.IStaleListener;
24
import org.eclipse.core.databinding.observable.ObservableTracker;
25
import org.eclipse.core.databinding.observable.StaleEvent;
26
import org.eclipse.core.databinding.observable.map.AbstractObservableMap;
27
import org.eclipse.core.databinding.observable.map.IMapChangeListener;
28
import org.eclipse.core.databinding.observable.map.IObservableMap;
29
import org.eclipse.core.databinding.observable.map.MapChangeEvent;
30
import org.eclipse.core.databinding.observable.map.MapDiff;
31
import org.eclipse.core.databinding.observable.set.IObservableSet;
32
import org.eclipse.core.databinding.observable.set.ISetChangeListener;
33
import org.eclipse.core.databinding.observable.set.SetChangeEvent;
34
import org.eclipse.core.databinding.observable.set.WritableSet;
35
import org.eclipse.core.databinding.property.INativePropertyListener;
36
import org.eclipse.core.databinding.property.IProperty;
37
import org.eclipse.core.databinding.property.IPropertyObservable;
38
import org.eclipse.core.databinding.property.ISimplePropertyListener;
39
import org.eclipse.core.databinding.property.SimplePropertyEvent;
40
import org.eclipse.core.databinding.property.value.ISimpleValueProperty;
41
import org.eclipse.core.internal.databinding.IdentityWrapper;
42
import org.eclipse.core.internal.databinding.Util;
43
44
/**
45
 * @since 1.2
46
 * 
47
 */
48
public class ObservableMapSimpleValuePropertyObservableMap extends
49
		AbstractObservableMap implements IPropertyObservable {
50
	private IObservableMap masterMap;
51
	private ISimpleValueProperty detailProperty;
52
53
	private IObservableSet knownMasterValues;
54
	private Map cachedValues;
55
56
	private boolean updating = false;
57
58
	private IMapChangeListener masterListener = new IMapChangeListener() {
59
		public void handleMapChange(final MapChangeEvent event) {
60
			if (!isDisposed()) {
61
				updateKnownValues();
62
				if (!updating)
63
					fireMapChange(convertDiff(event.diff));
64
			}
65
		}
66
67
		private void updateKnownValues() {
68
			Set identityKnownValues = new HashSet();
69
			for (Iterator it = masterMap.values().iterator(); it.hasNext();) {
70
				identityKnownValues.add(new IdentityWrapper(it.next()));
71
			}
72
73
			knownMasterValues.retainAll(identityKnownValues);
74
			knownMasterValues.addAll(identityKnownValues);
75
		}
76
77
		private MapDiff convertDiff(MapDiff diff) {
78
			Map oldValues = new HashMap();
79
			Map newValues = new HashMap();
80
81
			Set addedKeys = diff.getAddedKeys();
82
			for (Iterator it = addedKeys.iterator(); it.hasNext();) {
83
				Object key = it.next();
84
				Object newSource = diff.getNewValue(key);
85
				Object newValue = detailProperty.get(newSource);
86
				newValues.put(key, newValue);
87
			}
88
89
			Set removedKeys = diff.getRemovedKeys();
90
			for (Iterator it = removedKeys.iterator(); it.hasNext();) {
91
				Object key = it.next();
92
				Object oldSource = diff.getOldValue(key);
93
				Object oldValue = detailProperty.get(oldSource);
94
				oldValues.put(key, oldValue);
95
			}
96
97
			Set changedKeys = new HashSet(diff.getChangedKeys());
98
			for (Iterator it = changedKeys.iterator(); it.hasNext();) {
99
				Object key = it.next();
100
101
				Object oldSource = diff.getOldValue(key);
102
				Object newSource = diff.getNewValue(key);
103
104
				Object oldValue = detailProperty.get(oldSource);
105
				Object newValue = detailProperty.get(newSource);
106
107
				if (Util.equals(oldValue, newValue)) {
108
					it.remove();
109
				} else {
110
					oldValues.put(key, oldValue);
111
					newValues.put(key, newValue);
112
				}
113
			}
114
115
			return Diffs.createMapDiff(addedKeys, removedKeys, changedKeys,
116
					oldValues, newValues);
117
		}
118
	};
119
120
	private IStaleListener staleListener = new IStaleListener() {
121
		public void handleStale(StaleEvent staleEvent) {
122
			fireStale();
123
		}
124
	};
125
126
	private INativePropertyListener detailListener;
127
128
	/**
129
	 * @param map
130
	 * @param valueProperty
131
	 */
132
	public ObservableMapSimpleValuePropertyObservableMap(IObservableMap map,
133
			ISimpleValueProperty valueProperty) {
134
		super(map.getRealm());
135
		this.masterMap = map;
136
		this.detailProperty = valueProperty;
137
138
		ISimplePropertyListener listener = new ISimplePropertyListener() {
139
			public void handlePropertyChange(SimplePropertyEvent event) {
140
				notifyIfChanged(event.getSource());
141
			}
142
		};
143
		this.detailListener = detailProperty.adaptListener(listener);
144
	}
145
146
	protected void firstListenerAdded() {
147
		knownMasterValues = new WritableSet(getRealm());
148
		cachedValues = new HashMap();
149
		knownMasterValues.addSetChangeListener(new ISetChangeListener() {
150
			public void handleSetChange(SetChangeEvent event) {
151
				for (Iterator it = event.diff.getRemovals().iterator(); it
152
						.hasNext();) {
153
					IdentityWrapper wrapper = (IdentityWrapper) it.next();
154
					Object key = wrapper.unwrap();
155
					detailProperty.removeListener(key, detailListener);
156
					cachedValues.remove(wrapper);
157
				}
158
				for (Iterator it = event.diff.getAdditions().iterator(); it
159
						.hasNext();) {
160
					IdentityWrapper wrapper = (IdentityWrapper) it.next();
161
					Object key = wrapper.unwrap();
162
					cachedValues.put(wrapper, detailProperty.get(key));
163
					detailProperty.addListener(key, detailListener);
164
				}
165
			}
166
		});
167
		for (Iterator it = masterMap.values().iterator(); it.hasNext();) {
168
			knownMasterValues.add(new IdentityWrapper(it.next()));
169
		}
170
171
		masterMap.addMapChangeListener(masterListener);
172
		masterMap.addStaleListener(staleListener);
173
	}
174
175
	protected void lastListenerRemoved() {
176
		masterMap.removeMapChangeListener(masterListener);
177
		masterMap.removeStaleListener(staleListener);
178
		if (knownMasterValues != null) {
179
			knownMasterValues.clear(); // removes attached listeners
180
			knownMasterValues.dispose();
181
			knownMasterValues = null;
182
		}
183
		cachedValues.clear();
184
		cachedValues = null;
185
	}
186
187
	private Set entrySet;
188
189
	public Set entrySet() {
190
		getterCalled();
191
		if (entrySet == null)
192
			entrySet = new EntrySet();
193
		return entrySet;
194
	}
195
196
	class EntrySet extends AbstractSet {
197
		public Iterator iterator() {
198
			return new Iterator() {
199
				Iterator it = masterMap.entrySet().iterator();
200
201
				public boolean hasNext() {
202
					getterCalled();
203
					return it.hasNext();
204
				}
205
206
				public Object next() {
207
					getterCalled();
208
					Map.Entry next = (Map.Entry) it.next();
209
					return new MapEntry(next.getKey());
210
				}
211
212
				public void remove() {
213
					it.remove();
214
				}
215
			};
216
		}
217
218
		public int size() {
219
			return masterMap.size();
220
		}
221
	}
222
223
	class MapEntry implements Map.Entry {
224
		private Object key;
225
226
		MapEntry(Object key) {
227
			this.key = key;
228
		}
229
230
		public Object getKey() {
231
			getterCalled();
232
			return key;
233
		}
234
235
		public Object getValue() {
236
			getterCalled();
237
			if (!masterMap.containsKey(key))
238
				return null;
239
			return detailProperty.get(masterMap.get(key));
240
		}
241
242
		public Object setValue(Object value) {
243
			if (!masterMap.containsKey(key))
244
				return null;
245
			Object source = masterMap.get(key);
246
247
			Object oldValue = detailProperty.get(source);
248
249
			updating = true;
250
			try {
251
				detailProperty.set(source, value, Diffs.createValueDiff(
252
						oldValue, value));
253
			} finally {
254
				updating = false;
255
			}
256
257
			notifyIfChanged(source);
258
259
			return oldValue;
260
		}
261
262
		public boolean equals(Object o) {
263
			getterCalled();
264
			if (o == this)
265
				return true;
266
			if (o == null)
267
				return false;
268
			if (!(o instanceof Map.Entry))
269
				return false;
270
			Map.Entry that = (Map.Entry) o;
271
			return Util.equals(this.getKey(), that.getKey())
272
					&& Util.equals(this.getValue(), that.getValue());
273
		}
274
275
		public int hashCode() {
276
			getterCalled();
277
			Object value = getValue();
278
			return (key == null ? 0 : key.hashCode())
279
					^ (value == null ? 0 : value.hashCode());
280
		}
281
	}
282
283
	public Object put(Object key, Object value) {
284
		if (!masterMap.containsKey(key))
285
			return null;
286
		Object masterValue = masterMap.get(key);
287
		Object oldValue = detailProperty.get(key);
288
		detailProperty.set(masterValue, value, Diffs.createValueDiff(oldValue,
289
				value));
290
		notifyIfChanged(masterValue);
291
		return oldValue;
292
	}
293
294
	private void notifyIfChanged(Object masterValue) {
295
		if (cachedValues != null) {
296
			final Set keys = keysFor(masterValue);
297
298
			final Object oldValue = cachedValues.get(new IdentityWrapper(
299
					masterValue));
300
			final Object newValue = detailProperty.get(masterValue);
301
302
			if (!Util.equals(oldValue, newValue)) {
303
				cachedValues.put(new IdentityWrapper(masterValue), newValue);
304
				fireMapChange(new MapDiff() {
305
					public Set getAddedKeys() {
306
						return Collections.EMPTY_SET;
307
					}
308
309
					public Set getChangedKeys() {
310
						return keys;
311
					}
312
313
					public Set getRemovedKeys() {
314
						return Collections.EMPTY_SET;
315
					}
316
317
					public Object getNewValue(Object key) {
318
						return newValue;
319
					}
320
321
					public Object getOldValue(Object key) {
322
						return oldValue;
323
					}
324
				});
325
			}
326
		}
327
	}
328
329
	private Set keysFor(Object value) {
330
		Set keys = new HashSet();
331
332
		for (Iterator it = masterMap.entrySet().iterator(); it.hasNext();) {
333
			Map.Entry entry = (Entry) it.next();
334
			if (entry.getValue() == value) {
335
				keys.add(entry.getKey());
336
			}
337
		}
338
339
		return keys;
340
	}
341
342
	public boolean isStale() {
343
		getterCalled();
344
		return masterMap.isStale();
345
	}
346
347
	private void getterCalled() {
348
		ObservableTracker.getterCalled(this);
349
	}
350
351
	public Object getObserved() {
352
		return masterMap;
353
	}
354
355
	public IProperty getProperty() {
356
		return detailProperty;
357
	}
358
359
	public synchronized void dispose() {
360
		if (masterMap != null) {
361
			masterMap.removeMapChangeListener(masterListener);
362
			masterMap = null;
363
		}
364
		if (knownMasterValues != null) {
365
			knownMasterValues.clear(); // detaches listeners
366
			knownMasterValues.dispose();
367
			knownMasterValues = null;
368
		}
369
370
		masterListener = null;
371
		detailListener = null;
372
		detailProperty = null;
373
		cachedValues = null;
374
375
		super.dispose();
376
	}
377
}
(-)src/org/eclipse/core/databinding/property/value/ISimpleValueProperty.java (+20 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 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.value;
13
14
import org.eclipse.core.databinding.property.ISimpleProperty;
15
16
/**
17
 * @since 1.2
18
 */
19
public interface ISimpleValueProperty extends IValueProperty, ISimpleProperty {
20
}
(-)src/org/eclipse/core/internal/databinding/property/value/DelegatingCache.java (+210 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 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 (bug 194734)
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.property.value;
13
14
import java.util.Collection;
15
import java.util.Collections;
16
import java.util.HashMap;
17
import java.util.HashSet;
18
import java.util.Iterator;
19
import java.util.Map;
20
import java.util.Set;
21
22
import org.eclipse.core.databinding.observable.Realm;
23
import org.eclipse.core.databinding.observable.map.IMapChangeListener;
24
import org.eclipse.core.databinding.observable.map.IObservableMap;
25
import org.eclipse.core.databinding.observable.map.MapChangeEvent;
26
import org.eclipse.core.databinding.observable.set.IObservableSet;
27
import org.eclipse.core.databinding.observable.set.ISetChangeListener;
28
import org.eclipse.core.databinding.observable.set.SetChangeEvent;
29
import org.eclipse.core.databinding.observable.set.WritableSet;
30
import org.eclipse.core.databinding.property.value.DelegatingValueProperty;
31
import org.eclipse.core.databinding.property.value.IValueProperty;
32
import org.eclipse.core.internal.databinding.IdentityWrapper;
33
import org.eclipse.core.internal.databinding.Util;
34
35
/**
36
 * @since 3.3
37
 * 
38
 */
39
abstract class DelegatingCache {
40
	private Realm realm;
41
	private DelegatingValueProperty detailProperty;
42
	private IObservableSet elements;
43
	private Map delegateCaches;
44
45
	private class DelegateCache implements IMapChangeListener {
46
		private final IValueProperty delegate;
47
		private final IObservableSet masterElements;
48
		private final IObservableMap masterElementValues;
49
		private final Map cachedValues;
50
51
		DelegateCache(IValueProperty delegate) {
52
			this.delegate = delegate;
53
			this.masterElements = new WritableSet(realm, Collections.EMPTY_SET,
54
					elements.getElementType());
55
			this.masterElementValues = delegate.observeDetail(masterElements);
56
			this.cachedValues = new HashMap();
57
58
			masterElementValues.addMapChangeListener(this);
59
		}
60
61
		void add(Object masterElement) {
62
			boolean wasEmpty = masterElements.isEmpty();
63
64
			masterElements.add(masterElement);
65
			cachedValues.put(new IdentityWrapper(masterElement),
66
					masterElementValues.get(masterElement));
67
68
			if (wasEmpty)
69
				delegateCaches.put(delegate, this);
70
		}
71
72
		void remove(Object masterElement) {
73
			cachedValues.remove(new IdentityWrapper(masterElement));
74
			masterElements.remove(masterElement);
75
			if (cachedValues.isEmpty())
76
				dispose();
77
		}
78
79
		Object get(Object masterElement) {
80
			return cachedValues.get(new IdentityWrapper(masterElement));
81
		}
82
83
		Object put(Object masterElement, Object detailValue) {
84
			Object oldValue = masterElementValues.put(masterElement,
85
					detailValue);
86
			notifyIfChanged(masterElement);
87
			return oldValue;
88
		}
89
90
		boolean containsValue(Object detailValue) {
91
			return cachedValues.containsValue(detailValue);
92
		}
93
94
		public void handleMapChange(MapChangeEvent event) {
95
			Set changedKeys = event.diff.getChangedKeys();
96
			for (Iterator it = changedKeys.iterator(); it.hasNext();)
97
				notifyIfChanged(it.next());
98
		}
99
100
		private void notifyIfChanged(Object masterElement) {
101
			Object oldValue = cachedValues.get(new IdentityWrapper(
102
					masterElement));
103
			Object newValue = masterElementValues.get(masterElement);
104
			if (!Util.equals(oldValue, newValue)) {
105
				cachedValues.put(new IdentityWrapper(masterElement), newValue);
106
				handleValueChange(masterElement, oldValue, newValue);
107
			}
108
		}
109
110
		void handleValueChange(Object masterElement, Object oldValue,
111
				Object newValue) {
112
			DelegatingCache.this.handleValueChange(masterElement, oldValue,
113
					newValue);
114
		}
115
116
		void dispose() {
117
			delegateCaches.remove(delegate);
118
			masterElementValues.dispose();
119
			masterElements.dispose();
120
			cachedValues.clear();
121
		}
122
	}
123
124
	DelegatingCache(Realm realm, DelegatingValueProperty detailProperty) {
125
		this.realm = realm;
126
		this.detailProperty = detailProperty;
127
128
		this.elements = new WritableSet(realm);
129
		this.delegateCaches = new HashMap();
130
131
		elements.addSetChangeListener(new ISetChangeListener() {
132
			public void handleSetChange(SetChangeEvent event) {
133
				for (Iterator it = event.diff.getRemovals().iterator(); it
134
						.hasNext();) {
135
					IdentityWrapper wrapper = (IdentityWrapper) it.next();
136
					Object element = wrapper.unwrap();
137
					getCache(element).remove(element);
138
139
				}
140
				for (Iterator it = event.diff.getAdditions().iterator(); it
141
						.hasNext();) {
142
					IdentityWrapper wrapper = (IdentityWrapper) it.next();
143
					Object element = wrapper.unwrap();
144
					getCache(element).add(element);
145
				}
146
			}
147
		});
148
	}
149
150
	private DelegateCache getCache(Object masterElement) {
151
		IValueProperty delegate = detailProperty.getDelegate(masterElement);
152
		if (delegateCaches.containsKey(delegate)) {
153
			return (DelegateCache) delegateCaches.get(delegate);
154
		}
155
		return new DelegateCache(delegate);
156
	}
157
158
	Object get(Object element) {
159
		return getCache(element).get(element);
160
	}
161
162
	Object put(Object element, Object value) {
163
		return getCache(element).put(element, value);
164
	}
165
166
	boolean contains(Object value) {
167
		for (Iterator it = delegateCaches.values().iterator(); it.hasNext();) {
168
			DelegateCache cache = (DelegateCache) it.next();
169
			if (cache.containsValue(value))
170
				return true;
171
		}
172
		return false;
173
	}
174
175
	private Set identitySet(Collection elements) {
176
		Set result = new HashSet();
177
		for (Iterator it = elements.iterator(); it.hasNext();) {
178
			result.add(new IdentityWrapper(it.next()));
179
		}
180
		return result;
181
	}
182
183
	void addAll(Collection elements) {
184
		this.elements.addAll(identitySet(elements));
185
	}
186
187
	void retainAll(Collection elements) {
188
		this.elements.retainAll(identitySet(elements));
189
	}
190
191
	abstract void handleValueChange(Object masterElement, Object oldValue,
192
			Object newValue);
193
194
	void dispose() {
195
		if (elements != null) {
196
			elements.clear(); // clears caches
197
			elements.dispose();
198
			elements = null;
199
		}
200
201
		if (delegateCaches != null) {
202
			for (Iterator it = delegateCaches.values().iterator(); it.hasNext();) {
203
				DelegateCache cache = (DelegateCache) it.next();
204
				cache.dispose();
205
			}
206
			delegateCaches.clear();
207
			delegateCaches = null;
208
		}
209
	}
210
}
(-)src/org/eclipse/core/internal/databinding/property/value/SimpleValuePropertyObservableValue.java (+132 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.value;
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.observable.value.ValueDiff;
18
import org.eclipse.core.databinding.property.INativePropertyListener;
19
import org.eclipse.core.databinding.property.IProperty;
20
import org.eclipse.core.databinding.property.IPropertyObservable;
21
import org.eclipse.core.databinding.property.ISimplePropertyListener;
22
import org.eclipse.core.databinding.property.SimplePropertyEvent;
23
import org.eclipse.core.databinding.property.value.ISimpleValueProperty;
24
import org.eclipse.core.internal.databinding.Util;
25
26
/**
27
 * @since 1.2
28
 * 
29
 */
30
public class SimpleValuePropertyObservableValue extends AbstractObservableValue
31
		implements IPropertyObservable {
32
	private Object source;
33
	private ISimpleValueProperty property;
34
35
	private boolean updating = false;
36
	private Object cachedValue;
37
38
	private INativePropertyListener listener;
39
40
	/**
41
	 * @param realm
42
	 * @param source
43
	 * @param property
44
	 */
45
	public SimpleValuePropertyObservableValue(Realm realm, Object source,
46
			ISimpleValueProperty property) {
47
		super(realm);
48
		this.source = source;
49
		this.property = property;
50
	}
51
52
	protected void firstListenerAdded() {
53
		if (!isDisposed()) {
54
			cachedValue = property.get(source);
55
			if (listener == null) {
56
				listener = property
57
						.adaptListener(new ISimplePropertyListener() {
58
							public void handlePropertyChange(
59
									final SimplePropertyEvent event) {
60
								if (!isDisposed() && !updating) {
61
									getRealm().exec(new Runnable() {
62
										public void run() {
63
											notifyIfChanged((ValueDiff) event.diff);
64
										}
65
									});
66
								}
67
							}
68
						});
69
			}
70
			property.addListener(source, listener);
71
		}
72
	}
73
74
	protected void lastListenerRemoved() {
75
		if (listener != null) {
76
			property.removeListener(source, listener);
77
		}
78
		cachedValue = null;
79
	}
80
81
	protected Object doGetValue() {
82
		notifyIfChanged(null);
83
		return property.get(source);
84
	}
85
86
	protected void doSetValue(Object value) {
87
		updating = true;
88
		try {
89
			property.set(source, value, Diffs.createValueDiff(property
90
					.get(source), value));
91
		} finally {
92
			updating = false;
93
		}
94
95
		notifyIfChanged(null);
96
	}
97
98
	private void notifyIfChanged(ValueDiff diff) {
99
		if (hasListeners()) {
100
			Object oldValue = cachedValue;
101
			Object newValue = cachedValue = property.get(source);
102
			if (diff == null)
103
				diff = Diffs.createValueDiff(oldValue, newValue);
104
			if (hasListeners() && !Util.equals(oldValue, newValue)) {
105
				fireValueChange(diff);
106
			}
107
		}
108
	}
109
110
	public Object getValueType() {
111
		return property.getValueType();
112
	}
113
114
	public Object getObserved() {
115
		return source;
116
	}
117
118
	public IProperty getProperty() {
119
		return property;
120
	}
121
122
	public synchronized void dispose() {
123
		if (!isDisposed()) {
124
			if (listener != null)
125
				property.removeListener(source, listener);
126
			source = null;
127
			property = null;
128
			listener = null;
129
		}
130
		super.dispose();
131
	}
132
}
(-)src/org/eclipse/core/databinding/property/set/ISimpleSetProperty.java (+21 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 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.set;
13
14
import org.eclipse.core.databinding.property.ISimpleProperty;
15
16
/**
17
 * @since 1.2
18
 * 
19
 */
20
public interface ISimpleSetProperty extends ISimpleProperty, ISetProperty {
21
}
(-)src/org/eclipse/core/internal/databinding/property/list/SimpleListPropertyObservableList.java (+667 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.list;
13
14
import java.util.ArrayList;
15
import java.util.Collection;
16
import java.util.Collections;
17
import java.util.ConcurrentModificationException;
18
import java.util.Iterator;
19
import java.util.List;
20
import java.util.ListIterator;
21
22
import org.eclipse.core.databinding.observable.Diffs;
23
import org.eclipse.core.databinding.observable.ObservableTracker;
24
import org.eclipse.core.databinding.observable.Realm;
25
import org.eclipse.core.databinding.observable.list.AbstractObservableList;
26
import org.eclipse.core.databinding.observable.list.ListDiff;
27
import org.eclipse.core.databinding.observable.list.ListDiffEntry;
28
import org.eclipse.core.databinding.property.INativePropertyListener;
29
import org.eclipse.core.databinding.property.IProperty;
30
import org.eclipse.core.databinding.property.IPropertyObservable;
31
import org.eclipse.core.databinding.property.ISimplePropertyListener;
32
import org.eclipse.core.databinding.property.SimplePropertyEvent;
33
import org.eclipse.core.databinding.property.list.ISimpleListProperty;
34
35
/**
36
 * @since 1.2
37
 * 
38
 */
39
public class SimpleListPropertyObservableList extends AbstractObservableList
40
		implements IPropertyObservable {
41
	private Object source;
42
	private ISimpleListProperty property;
43
44
	private volatile boolean updating = false;
45
46
	private volatile int modCount = 0;
47
48
	private INativePropertyListener listener;
49
50
	private List cachedList;
51
52
	/**
53
	 * @param realm
54
	 * @param source
55
	 * @param property
56
	 */
57
	public SimpleListPropertyObservableList(Realm realm, Object source,
58
			ISimpleListProperty property) {
59
		super(realm);
60
		this.source = source;
61
		this.property = property;
62
	}
63
64
	protected void firstListenerAdded() {
65
		if (!isDisposed()) {
66
			cachedList = getList();
67
68
			if (listener == null) {
69
				listener = property
70
						.adaptListener(new ISimplePropertyListener() {
71
							public void handlePropertyChange(
72
									final SimplePropertyEvent event) {
73
								modCount++;
74
								if (!isDisposed() && !updating) {
75
									getRealm().exec(new Runnable() {
76
										public void run() {
77
											notifyIfChanged((ListDiff) event.diff);
78
										}
79
									});
80
								}
81
							}
82
						});
83
			}
84
			property.addListener(source, listener);
85
		}
86
	}
87
88
	protected void lastListenerRemoved() {
89
		if (listener != null) {
90
			property.removeListener(source, listener);
91
		}
92
93
		cachedList = null;
94
	}
95
96
	private void getterCalled() {
97
		ObservableTracker.getterCalled(this);
98
	}
99
100
	public Object getElementType() {
101
		return property.getElementType();
102
	}
103
104
	// Queries
105
106
	private List getList() {
107
		return (List) property.get(source);
108
	}
109
110
	protected int doGetSize() {
111
		return getList().size();
112
	}
113
114
	public boolean contains(Object o) {
115
		getterCalled();
116
		return getList().contains(o);
117
	}
118
119
	public boolean containsAll(Collection c) {
120
		getterCalled();
121
		return getList().containsAll(c);
122
	}
123
124
	public Object get(int index) {
125
		getterCalled();
126
		return getList().get(index);
127
	}
128
129
	public int indexOf(Object o) {
130
		getterCalled();
131
		return getList().indexOf(o);
132
	}
133
134
	public boolean isEmpty() {
135
		getterCalled();
136
		return getList().isEmpty();
137
	}
138
139
	public int lastIndexOf(Object o) {
140
		getterCalled();
141
		return getList().lastIndexOf(o);
142
	}
143
144
	public Object[] toArray() {
145
		getterCalled();
146
		return getList().toArray();
147
	}
148
149
	public Object[] toArray(Object[] a) {
150
		getterCalled();
151
		return getList().toArray(a);
152
	}
153
154
	// Single change operations
155
156
	public boolean add(Object o) {
157
		checkRealm();
158
		add(getList().size(), o);
159
		return true;
160
	}
161
162
	public void add(int index, Object o) {
163
		checkRealm();
164
		boolean wasUpdating = updating;
165
		updating = true;
166
		List list = new ArrayList(getList());
167
		list.add(index, o);
168
		ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry(index,
169
				true, o));
170
		try {
171
			property.set(source, list, diff);
172
			modCount++;
173
		} finally {
174
			updating = wasUpdating;
175
		}
176
177
		notifyIfChanged(null);
178
	}
179
180
	public Iterator iterator() {
181
		getterCalled();
182
		return new Iterator() {
183
			int expectedModCount = modCount;
184
			List list = new ArrayList(getList());
185
			ListIterator iterator = list.listIterator();
186
187
			Object lastElement = null;
188
			int lastIndex = -1;
189
190
			public boolean hasNext() {
191
				getterCalled();
192
				checkForComodification();
193
				return iterator.hasNext();
194
			}
195
196
			public Object next() {
197
				getterCalled();
198
				checkForComodification();
199
				Object next = lastElement = iterator.next();
200
				lastIndex = iterator.previousIndex();
201
				return next;
202
			}
203
204
			public void remove() {
205
				checkRealm();
206
				checkForComodification();
207
				if (lastIndex == -1)
208
					throw new IllegalStateException();
209
210
				iterator.remove(); // stay in sync
211
				ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry(
212
						lastIndex, false, lastElement));
213
214
				boolean wasUpdating = updating;
215
				updating = true;
216
				try {
217
					property.set(source, list, diff);
218
					modCount++;
219
				} finally {
220
					updating = wasUpdating;
221
				}
222
223
				notifyIfChanged(null);
224
225
				lastElement = null;
226
				lastIndex = -1;
227
228
				expectedModCount = modCount;
229
			}
230
231
			private void checkForComodification() {
232
				if (expectedModCount != modCount)
233
					throw new ConcurrentModificationException();
234
			}
235
		};
236
	}
237
238
	public Object move(int oldIndex, int newIndex) {
239
		checkRealm();
240
241
		List list = getList();
242
		int size = list.size();
243
		if (oldIndex < 0 || oldIndex >= size || newIndex < 0
244
				|| newIndex >= size)
245
			throw new IndexOutOfBoundsException();
246
247
		if (oldIndex == newIndex)
248
			return list.get(oldIndex);
249
250
		list = new ArrayList(list);
251
		Object element = list.remove(oldIndex);
252
		list.add(newIndex, element);
253
254
		ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry(
255
				oldIndex, false, element), Diffs.createListDiffEntry(newIndex,
256
				true, element));
257
258
		boolean wasUpdating = updating;
259
		updating = true;
260
		try {
261
			property.set(source, list, diff);
262
			modCount++;
263
		} finally {
264
			updating = wasUpdating;
265
		}
266
267
		notifyIfChanged(null);
268
269
		return element;
270
	}
271
272
	public boolean remove(Object o) {
273
		checkRealm();
274
275
		int index = getList().indexOf(o);
276
		if (index == -1)
277
			return false;
278
279
		remove(index);
280
281
		return true;
282
	}
283
284
	public ListIterator listIterator() {
285
		return listIterator(0);
286
	}
287
288
	public ListIterator listIterator(final int index) {
289
		getterCalled();
290
		return new ListIterator() {
291
			int expectedModCount = modCount;
292
			List list = new ArrayList(getList());
293
			ListIterator iterator = list.listIterator(index);
294
295
			Object lastElement = null;
296
			int lastIndex = -1;
297
298
			public boolean hasNext() {
299
				getterCalled();
300
				checkForComodification();
301
				return iterator.hasNext();
302
			}
303
304
			public int nextIndex() {
305
				getterCalled();
306
				checkForComodification();
307
				return iterator.nextIndex();
308
			}
309
310
			public Object next() {
311
				getterCalled();
312
				checkForComodification();
313
				lastElement = iterator.next();
314
				lastIndex = iterator.previousIndex();
315
				return lastElement;
316
			}
317
318
			public boolean hasPrevious() {
319
				getterCalled();
320
				checkForComodification();
321
				return iterator.hasPrevious();
322
			}
323
324
			public int previousIndex() {
325
				getterCalled();
326
				checkForComodification();
327
				return iterator.previousIndex();
328
			}
329
330
			public Object previous() {
331
				getterCalled();
332
				checkForComodification();
333
				lastElement = iterator.previous();
334
				lastIndex = iterator.nextIndex();
335
				return lastElement;
336
			}
337
338
			public void add(Object o) {
339
				checkRealm();
340
				checkForComodification();
341
				int index = iterator.nextIndex();
342
343
				iterator.add(o); // keep in sync
344
345
				List list = getList();
346
				list.add(index, o);
347
				ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry(
348
						index, true, o));
349
				boolean wasUpdating = updating;
350
				updating = true;
351
				try {
352
					property.set(source, list, diff);
353
					modCount++;
354
				} finally {
355
					updating = wasUpdating;
356
				}
357
358
				notifyIfChanged(null);
359
360
				lastElement = null;
361
				lastIndex = -1;
362
				expectedModCount = modCount;
363
			}
364
365
			public void set(Object o) {
366
				checkRealm();
367
				checkForComodification();
368
369
				iterator.set(o);
370
				ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry(
371
						lastIndex, false, lastElement), Diffs
372
						.createListDiffEntry(lastIndex, true, o));
373
374
				boolean wasUpdating = updating;
375
				updating = true;
376
				try {
377
					property.set(source, list, diff);
378
					modCount++;
379
				} finally {
380
					updating = wasUpdating;
381
				}
382
383
				notifyIfChanged(null);
384
385
				lastElement = o;
386
				expectedModCount = modCount;
387
			}
388
389
			public void remove() {
390
				checkRealm();
391
				checkForComodification();
392
				if (lastIndex == -1)
393
					throw new IllegalStateException();
394
395
				iterator.remove(); // keep in sync
396
				ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry(
397
						lastIndex, false, lastElement));
398
399
				boolean wasUpdating = updating;
400
				updating = true;
401
				try {
402
					property.set(source, list, diff);
403
					modCount++;
404
				} finally {
405
					updating = wasUpdating;
406
				}
407
408
				notifyIfChanged(null);
409
410
				lastElement = null;
411
				lastIndex = -1;
412
				expectedModCount = modCount;
413
			}
414
415
			private void checkForComodification() {
416
				if (expectedModCount != modCount)
417
					throw new ConcurrentModificationException();
418
			}
419
		};
420
	}
421
422
	public Object remove(int index) {
423
		checkRealm();
424
425
		List list = new ArrayList(getList());
426
		Object element = list.remove(index);
427
		ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry(index,
428
				false, element));
429
430
		boolean wasUpdating = updating;
431
		updating = true;
432
		try {
433
			property.set(source, list, diff);
434
			modCount++;
435
		} finally {
436
			updating = wasUpdating;
437
		}
438
439
		notifyIfChanged(null);
440
441
		return element;
442
	}
443
444
	public Object set(int index, Object o) {
445
		checkRealm();
446
447
		List list = new ArrayList(getList());
448
		Object oldElement = list.set(index, o);
449
450
		ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry(index,
451
				false, oldElement), Diffs.createListDiffEntry(index, true, o));
452
453
		boolean wasUpdating = updating;
454
		updating = true;
455
		try {
456
			property.set(source, list, diff);
457
			modCount++;
458
		} finally {
459
			updating = wasUpdating;
460
		}
461
462
		notifyIfChanged(null);
463
464
		return oldElement;
465
	}
466
467
	public List subList(int fromIndex, int toIndex) {
468
		getterCalled();
469
		return Collections.unmodifiableList(getList().subList(fromIndex,
470
				toIndex));
471
	}
472
473
	// Bulk change operations
474
475
	public boolean addAll(Collection c) {
476
		checkRealm();
477
478
		return addAll(getList().size(), c);
479
	}
480
481
	public boolean addAll(int index, Collection c) {
482
		checkRealm();
483
484
		if (c.isEmpty())
485
			return false;
486
487
		List list = new ArrayList(getList());
488
		list.addAll(index, c);
489
490
		ListDiffEntry[] entries = new ListDiffEntry[c.size()];
491
		int offsetIndex = 0;
492
		for (Iterator it = c.iterator(); it.hasNext();) {
493
			Object element = it.next();
494
			entries[offsetIndex] = Diffs.createListDiffEntry(index
495
					+ offsetIndex, true, element);
496
			offsetIndex++;
497
		}
498
		ListDiff diff = Diffs.createListDiff(entries);
499
500
		boolean wasUpdating = updating;
501
		updating = true;
502
		try {
503
			property.set(source, list, diff);
504
			modCount++;
505
		} finally {
506
			updating = wasUpdating;
507
		}
508
509
		notifyIfChanged(null);
510
511
		return true;
512
	}
513
514
	public boolean removeAll(Collection c) {
515
		checkRealm();
516
517
		if (c.isEmpty())
518
			return false;
519
520
		List list = getList();
521
		if (list.isEmpty())
522
			return false;
523
524
		list = new ArrayList(list);
525
		List entries = new ArrayList();
526
		ListDiff diff;
527
528
		boolean wasUpdating = updating;
529
		updating = true;
530
		try {
531
			for (ListIterator it = list.listIterator(); it.hasNext();) {
532
				Object element = it.next();
533
				int index = it.previousIndex();
534
				if (c.contains(element)) {
535
					it.remove();
536
					entries.add(Diffs
537
							.createListDiffEntry(index, false, element));
538
				}
539
			}
540
			if (entries.isEmpty())
541
				return false;
542
543
			diff = Diffs.createListDiff((ListDiffEntry[]) entries
544
					.toArray(new ListDiffEntry[entries.size()]));
545
			property.set(source, list, diff);
546
			modCount++;
547
		} finally {
548
			updating = wasUpdating;
549
		}
550
551
		notifyIfChanged(null);
552
553
		return !diff.isEmpty();
554
	}
555
556
	public boolean retainAll(Collection c) {
557
		checkRealm();
558
559
		List list = getList();
560
		if (list.isEmpty())
561
			return false;
562
563
		if (c.isEmpty()) {
564
			clear();
565
			return true;
566
		}
567
568
		list = new ArrayList(list);
569
		List entries = new ArrayList();
570
		ListDiff diff;
571
572
		boolean wasUpdating = updating;
573
		updating = true;
574
		try {
575
			for (ListIterator it = list.listIterator(); it.hasNext();) {
576
				Object element = it.next();
577
				int index = it.previousIndex();
578
				if (!c.contains(element)) {
579
					it.remove();
580
					entries.add(Diffs
581
							.createListDiffEntry(index, false, element));
582
				}
583
			}
584
			if (entries.isEmpty())
585
				return false;
586
587
			diff = Diffs.createListDiff((ListDiffEntry[]) entries
588
					.toArray(new ListDiffEntry[entries.size()]));
589
			property.set(source, list, diff);
590
			modCount++;
591
		} finally {
592
			updating = wasUpdating;
593
		}
594
595
		notifyIfChanged(null);
596
597
		return !diff.isEmpty();
598
	}
599
600
	public void clear() {
601
		checkRealm();
602
603
		List list = getList();
604
		if (list.isEmpty())
605
			return;
606
607
		List entries = new ArrayList();
608
		for (Iterator it = list.iterator(); it.hasNext();) {
609
			// always report 0 as the remove index
610
			entries.add(Diffs.createListDiffEntry(0, false, it.next()));
611
		}
612
613
		ListDiff diff = Diffs.createListDiff((ListDiffEntry[]) entries
614
				.toArray(new ListDiffEntry[entries.size()]));
615
		boolean wasUpdating = updating;
616
		updating = true;
617
		try {
618
			property.set(source, Collections.EMPTY_LIST, diff);
619
			modCount++;
620
		} finally {
621
			updating = wasUpdating;
622
		}
623
624
		notifyIfChanged(null);
625
	}
626
627
	private void notifyIfChanged(ListDiff diff) {
628
		if (hasListeners()) {
629
			List oldList = cachedList;
630
			List newList = cachedList = (List) property.get(source);
631
			if (diff == null)
632
				diff = Diffs.computeListDiff(oldList, newList);
633
			if (!diff.isEmpty()) {
634
				fireListChange(diff);
635
			}
636
		}
637
	}
638
639
	public boolean equals(Object o) {
640
		getterCalled();
641
		return getList().equals(o);
642
	}
643
644
	public int hashCode() {
645
		getterCalled();
646
		return getList().hashCode();
647
	}
648
649
	public Object getObserved() {
650
		return source;
651
	}
652
653
	public IProperty getProperty() {
654
		return property;
655
	}
656
657
	public synchronized void dispose() {
658
		if (!isDisposed()) {
659
			if (listener != null)
660
				property.removeListener(source, listener);
661
			property = null;
662
			source = null;
663
			listener = null;
664
		}
665
		super.dispose();
666
	}
667
}
(-)src/org/eclipse/core/internal/databinding/property/value/ObservableListDelegatingValuePropertyObservableList.java (+348 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.value;
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.IStaleListener;
23
import org.eclipse.core.databinding.observable.ObservableTracker;
24
import org.eclipse.core.databinding.observable.StaleEvent;
25
import org.eclipse.core.databinding.observable.list.AbstractObservableList;
26
import org.eclipse.core.databinding.observable.list.IListChangeListener;
27
import org.eclipse.core.databinding.observable.list.IObservableList;
28
import org.eclipse.core.databinding.observable.list.ListChangeEvent;
29
import org.eclipse.core.databinding.observable.list.ListDiff;
30
import org.eclipse.core.databinding.observable.list.ListDiffEntry;
31
import org.eclipse.core.databinding.property.IProperty;
32
import org.eclipse.core.databinding.property.IPropertyObservable;
33
import org.eclipse.core.databinding.property.value.DelegatingValueProperty;
34
35
/**
36
 * @since 1.2
37
 */
38
public class ObservableListDelegatingValuePropertyObservableList extends
39
		AbstractObservableList implements IPropertyObservable {
40
	private IObservableList masterList;
41
	private DelegatingValueProperty detailProperty;
42
	private DelegatingCache cache;
43
44
	private IListChangeListener masterListener = new IListChangeListener() {
45
		public void handleListChange(ListChangeEvent event) {
46
			if (isDisposed())
47
				return;
48
49
			cache.addAll(masterList);
50
51
			// Need both obsolete and new elements to convert diff
52
			ListDiff diff = convertDiff(event.diff);
53
54
			cache.retainAll(masterList);
55
56
			fireListChange(diff);
57
		}
58
59
		private ListDiff convertDiff(ListDiff diff) {
60
			// Convert diff to detail value
61
			ListDiffEntry[] masterEntries = diff.getDifferences();
62
			ListDiffEntry[] detailEntries = new ListDiffEntry[masterEntries.length];
63
			for (int i = 0; i < masterEntries.length; i++) {
64
				ListDiffEntry masterDifference = masterEntries[i];
65
				int index = masterDifference.getPosition();
66
				boolean addition = masterDifference.isAddition();
67
				Object masterElement = masterDifference.getElement();
68
				Object detailValue = cache.get(masterElement);
69
70
				detailEntries[i] = Diffs.createListDiffEntry(index, addition,
71
						detailValue);
72
			}
73
			return Diffs.createListDiff(detailEntries);
74
		}
75
	};
76
77
	private IStaleListener staleListener = new IStaleListener() {
78
		public void handleStale(StaleEvent staleEvent) {
79
			fireStale();
80
		}
81
	};
82
83
	/**
84
	 * @param masterList
85
	 * @param valueProperty
86
	 */
87
	public ObservableListDelegatingValuePropertyObservableList(
88
			IObservableList masterList, DelegatingValueProperty valueProperty) {
89
		super(masterList.getRealm());
90
		this.masterList = masterList;
91
		this.detailProperty = valueProperty;
92
		this.cache = new DelegatingCache(getRealm(), valueProperty) {
93
			void handleValueChange(Object masterElement, Object oldValue,
94
					Object newValue) {
95
				fireListChange(indicesOf(masterElement), oldValue, newValue);
96
			}
97
		};
98
		cache.addAll(masterList);
99
100
		masterList.addListChangeListener(masterListener);
101
		masterList.addStaleListener(staleListener);
102
	}
103
104
	protected int doGetSize() {
105
		getterCalled();
106
		return masterList.size();
107
	}
108
109
	private void getterCalled() {
110
		ObservableTracker.getterCalled(this);
111
	}
112
113
	public Object get(int index) {
114
		getterCalled();
115
		Object masterElement = masterList.get(index);
116
		return cache.get(masterElement);
117
	}
118
119
	public boolean add(Object o) {
120
		throw new UnsupportedOperationException();
121
	}
122
123
	public boolean addAll(Collection c) {
124
		throw new UnsupportedOperationException();
125
	}
126
127
	public boolean addAll(int index, Collection c) {
128
		throw new UnsupportedOperationException();
129
	}
130
131
	public boolean contains(Object o) {
132
		getterCalled();
133
		return cache.contains(o);
134
	}
135
136
	public boolean isEmpty() {
137
		getterCalled();
138
		return masterList.isEmpty();
139
	}
140
141
	public boolean isStale() {
142
		getterCalled();
143
		return masterList.isStale();
144
	}
145
146
	public Iterator iterator() {
147
		getterCalled();
148
		return new Iterator() {
149
			Iterator it = masterList.iterator();
150
151
			public boolean hasNext() {
152
				getterCalled();
153
				return it.hasNext();
154
			}
155
156
			public Object next() {
157
				getterCalled();
158
				Object masterElement = it.next();
159
				return cache.get(masterElement);
160
			}
161
162
			public void remove() {
163
				throw new UnsupportedOperationException();
164
			}
165
		};
166
	}
167
168
	public Object move(int oldIndex, int newIndex) {
169
		throw new UnsupportedOperationException();
170
	}
171
172
	public boolean remove(Object o) {
173
		throw new UnsupportedOperationException();
174
	}
175
176
	public boolean removeAll(Collection c) {
177
		throw new UnsupportedOperationException();
178
	}
179
180
	public boolean retainAll(Collection c) {
181
		throw new UnsupportedOperationException();
182
	}
183
184
	public Object[] toArray() {
185
		getterCalled();
186
		Object[] masterElements = masterList.toArray();
187
		Object[] result = new Object[masterElements.length];
188
		for (int i = 0; i < result.length; i++) {
189
			result[i] = cache.get(masterElements[i]);
190
		}
191
		return result;
192
	}
193
194
	public Object[] toArray(Object[] a) {
195
		getterCalled();
196
		Object[] masterElements = masterList.toArray();
197
		if (a.length < masterElements.length)
198
			a = (Object[]) Array.newInstance(a.getClass().getComponentType(),
199
					masterElements.length);
200
		for (int i = 0; i < masterElements.length; i++) {
201
			a[i] = cache.get(masterElements[i]);
202
		}
203
		return a;
204
	}
205
206
	public void add(int index, Object o) {
207
		throw new UnsupportedOperationException();
208
	}
209
210
	public void clear() {
211
		throw new UnsupportedOperationException();
212
	}
213
214
	public ListIterator listIterator() {
215
		return listIterator(0);
216
	}
217
218
	public ListIterator listIterator(final int index) {
219
		getterCalled();
220
		return new ListIterator() {
221
			ListIterator it = masterList.listIterator(index);
222
			Object lastMasterElement;
223
			Object lastElement;
224
			boolean haveIterated = false;
225
226
			public void add(Object arg0) {
227
				throw new UnsupportedOperationException();
228
			}
229
230
			public boolean hasNext() {
231
				getterCalled();
232
				return it.hasNext();
233
			}
234
235
			public boolean hasPrevious() {
236
				getterCalled();
237
				return it.hasPrevious();
238
			}
239
240
			public Object next() {
241
				getterCalled();
242
				lastMasterElement = it.next();
243
				lastElement = cache.get(lastMasterElement);
244
				haveIterated = true;
245
				return lastElement;
246
			}
247
248
			public int nextIndex() {
249
				getterCalled();
250
				return it.nextIndex();
251
			}
252
253
			public Object previous() {
254
				getterCalled();
255
				lastMasterElement = it.previous();
256
				lastElement = cache.get(lastMasterElement);
257
				haveIterated = true;
258
				return lastElement;
259
			}
260
261
			public int previousIndex() {
262
				getterCalled();
263
				return it.previousIndex();
264
			}
265
266
			public void remove() {
267
				throw new UnsupportedOperationException();
268
			}
269
270
			public void set(Object o) {
271
				checkRealm();
272
				if (!haveIterated)
273
					throw new IllegalStateException();
274
275
				cache.put(lastMasterElement, o);
276
277
				lastElement = o;
278
			}
279
		};
280
	}
281
282
	private int[] indicesOf(Object masterElement) {
283
		List indices = new ArrayList();
284
285
		for (ListIterator it = masterList.listIterator(); it.hasNext();) {
286
			if (masterElement == it.next())
287
				indices.add(new Integer(it.previousIndex()));
288
		}
289
290
		int[] result = new int[indices.size()];
291
		for (int i = 0; i < result.length; i++) {
292
			result[i] = ((Integer) indices.get(i)).intValue();
293
		}
294
		return result;
295
	}
296
297
	private void fireListChange(int[] indices, Object oldValue, Object newValue) {
298
		ListDiffEntry[] differences = new ListDiffEntry[indices.length * 2];
299
		for (int i = 0; i < indices.length; i++) {
300
			int index = indices[i];
301
			differences[i * 2] = Diffs.createListDiffEntry(index, false,
302
					oldValue);
303
			differences[i * 2 + 1] = Diffs.createListDiffEntry(index, true,
304
					newValue);
305
		}
306
		fireListChange(Diffs.createListDiff(differences));
307
	}
308
309
	public Object remove(int index) {
310
		throw new UnsupportedOperationException();
311
	}
312
313
	public Object set(int index, Object o) {
314
		checkRealm();
315
		Object masterElement = masterList.get(index);
316
		return cache.put(masterElement, o);
317
	}
318
319
	public Object getObserved() {
320
		return masterList;
321
	}
322
323
	public IProperty getProperty() {
324
		return detailProperty;
325
	}
326
327
	public Object getElementType() {
328
		return detailProperty.getValueType();
329
	}
330
331
	public synchronized void dispose() {
332
		if (masterList != null) {
333
			masterList.removeListChangeListener(masterListener);
334
			masterList.removeStaleListener(staleListener);
335
			masterList = null;
336
		}
337
338
		if (cache != null) {
339
			cache.dispose();
340
			cache = null;
341
		}
342
343
		masterListener = null;
344
		detailProperty = null;
345
346
		super.dispose();
347
	}
348
}
(-)src/org/eclipse/core/databinding/property/ISimpleProperty.java (+103 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 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.IDiff;
15
import org.eclipse.core.databinding.property.list.ISimpleListProperty;
16
import org.eclipse.core.databinding.property.map.ISimpleMapProperty;
17
import org.eclipse.core.databinding.property.set.ISimpleSetProperty;
18
import org.eclipse.core.databinding.property.value.ISimpleValueProperty;
19
20
/**
21
 * Interface for immediate (as opposed to nested) properties of a particular
22
 * source object.
23
 * 
24
 * @since 1.2
25
 * @noimplement This interface is not intended to be implemented by clients.
26
 *              Clients should instead subclass one of the classes that
27
 *              implement this interface. Note that direct implementers of this
28
 *              interface outside of the framework will be broken in future
29
 *              releases when methods are added to this interface.
30
 * @see ISimpleValueProperty
31
 * @see ISimpleListProperty
32
 * @see ISimpleSetProperty
33
 * @see ISimpleMapProperty
34
 */
35
public interface ISimpleProperty extends IProperty {
36
	/**
37
	 * Returns the current contents of the source's property.
38
	 * 
39
	 * @param source
40
	 *            the property source (may be null)
41
	 * @return the current contents of the source's property
42
	 * @noreference This method is not intended to be referenced by clients.
43
	 */
44
	public Object get(Object source);
45
46
	/**
47
	 * Sets the contents of the source's property to the specified value.
48
	 * 
49
	 * @param source
50
	 *            the property source
51
	 * @param value
52
	 *            the new value
53
	 * @param diff
54
	 *            a diff describing the change
55
	 * @noreference This method is not intended to be referenced by clients.
56
	 */
57
	public void set(Object source, Object value, IDiff diff);
58
59
	/**
60
	 * Returns a listener which implements the correct listener interface for
61
	 * the expected source object, and which parlays property change events from
62
	 * the source object to the given listener. If there is no listener API for
63
	 * this property, this method returns null.
64
	 * 
65
	 * @param listener
66
	 *            the property listener to receive events
67
	 * @return a native listener which parlays property change events to the
68
	 *         specified listener.
69
	 * @noreference This method is not intended to be referenced by clients.
70
	 */
71
	public INativePropertyListener adaptListener(
72
			ISimplePropertyListener listener);
73
74
	/**
75
	 * Adds the specified listener as a listener for this property on the
76
	 * specified property source. If the source object has no listener API for
77
	 * this property (i.e. {@link #adaptListener(ISimplePropertyListener)}
78
	 * returns null), this method does nothing.
79
	 * 
80
	 * @param source
81
	 *            the property source
82
	 * @param listener
83
	 *            a listener obtained from calling
84
	 *            {@link #adaptListener(ISimplePropertyListener)}.
85
	 * @noreference This method is not intended to be referenced by clients.
86
	 */
87
	public void addListener(Object source, INativePropertyListener listener);
88
89
	/**
90
	 * Removes the specified listener as a listener for this property on the
91
	 * specified property source. If the source object has no listener API for
92
	 * this property (i.e. {@link #adaptListener(ISimplePropertyListener)}
93
	 * returns null), this method does nothing.
94
	 * 
95
	 * @param source
96
	 *            the property source
97
	 * @param listener
98
	 *            a listener obtained from calling
99
	 *            {@link #adaptListener(ISimplePropertyListener)}.
100
	 * @noreference This method is not intended to be referenced by clients.
101
	 */
102
	public void removeListener(Object source, INativePropertyListener listener);
103
}
(-)src/org/eclipse/core/databinding/property/map/ISimpleMapProperty.java (+20 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 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.map;
13
14
import org.eclipse.core.databinding.property.ISimpleProperty;
15
16
/**
17
 * @since 1.2
18
 */
19
public interface ISimpleMapProperty extends ISimpleProperty, IMapProperty {
20
}
(-)src/org/eclipse/core/internal/databinding/property/value/ObservableMapDelegatingValuePropertyObservableMap.java (+316 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.value;
13
14
import java.util.AbstractSet;
15
import java.util.Collections;
16
import java.util.HashMap;
17
import java.util.HashSet;
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.IStaleListener;
24
import org.eclipse.core.databinding.observable.ObservableTracker;
25
import org.eclipse.core.databinding.observable.StaleEvent;
26
import org.eclipse.core.databinding.observable.map.AbstractObservableMap;
27
import org.eclipse.core.databinding.observable.map.IMapChangeListener;
28
import org.eclipse.core.databinding.observable.map.IObservableMap;
29
import org.eclipse.core.databinding.observable.map.MapChangeEvent;
30
import org.eclipse.core.databinding.observable.map.MapDiff;
31
import org.eclipse.core.databinding.property.IProperty;
32
import org.eclipse.core.databinding.property.IPropertyObservable;
33
import org.eclipse.core.databinding.property.value.DelegatingValueProperty;
34
import org.eclipse.core.internal.databinding.Util;
35
36
/**
37
 * @since 1.2
38
 */
39
public class ObservableMapDelegatingValuePropertyObservableMap extends
40
		AbstractObservableMap implements IPropertyObservable {
41
	private IObservableMap masterMap;
42
	private DelegatingValueProperty detailProperty;
43
	private DelegatingCache cache;
44
45
	private Set entrySet;
46
47
	class EntrySet extends AbstractSet {
48
		public Iterator iterator() {
49
			return new Iterator() {
50
				Iterator it = masterMap.entrySet().iterator();
51
52
				public boolean hasNext() {
53
					getterCalled();
54
					return it.hasNext();
55
				}
56
57
				public Object next() {
58
					getterCalled();
59
					Map.Entry next = (Map.Entry) it.next();
60
					return new MapEntry(next.getKey());
61
				}
62
63
				public void remove() {
64
					it.remove();
65
				}
66
			};
67
		}
68
69
		public int size() {
70
			return masterMap.size();
71
		}
72
	}
73
74
	class MapEntry implements Map.Entry {
75
		private Object key;
76
77
		MapEntry(Object key) {
78
			this.key = key;
79
		}
80
81
		public Object getKey() {
82
			getterCalled();
83
			return key;
84
		}
85
86
		public Object getValue() {
87
			getterCalled();
88
89
			if (!masterMap.containsKey(key))
90
				return null;
91
92
			Object masterValue = masterMap.get(key);
93
			return cache.get(masterValue);
94
		}
95
96
		public Object setValue(Object value) {
97
			checkRealm();
98
99
			if (!masterMap.containsKey(key))
100
				return null;
101
102
			Object masterValue = masterMap.get(key);
103
			return cache.put(masterValue, value);
104
		}
105
106
		public boolean equals(Object o) {
107
			getterCalled();
108
			if (o == this)
109
				return true;
110
			if (o == null)
111
				return false;
112
			if (!(o instanceof Map.Entry))
113
				return false;
114
			Map.Entry that = (Map.Entry) o;
115
			return Util.equals(this.getKey(), that.getKey())
116
					&& Util.equals(this.getValue(), that.getValue());
117
		}
118
119
		public int hashCode() {
120
			getterCalled();
121
			Object value = getValue();
122
			return (key == null ? 0 : key.hashCode())
123
					^ (value == null ? 0 : value.hashCode());
124
		}
125
	}
126
127
	private IMapChangeListener masterListener = new IMapChangeListener() {
128
		public void handleMapChange(final MapChangeEvent event) {
129
			if (isDisposed())
130
				return;
131
132
			cache.addAll(masterMap.values());
133
134
			// Need both obsolete and new master values to convert diff
135
			MapDiff diff = convertDiff(event.diff);
136
137
			cache.retainAll(masterMap.values());
138
139
			fireMapChange(diff);
140
		}
141
142
		private MapDiff convertDiff(MapDiff diff) {
143
			Map oldValues = new HashMap();
144
			Map newValues = new HashMap();
145
146
			Set addedKeys = diff.getAddedKeys();
147
			for (Iterator it = addedKeys.iterator(); it.hasNext();) {
148
				Object key = it.next();
149
				Object masterValue = diff.getNewValue(key);
150
				Object newValue = cache.get(masterValue);
151
				newValues.put(key, newValue);
152
			}
153
154
			Set removedKeys = diff.getRemovedKeys();
155
			for (Iterator it = removedKeys.iterator(); it.hasNext();) {
156
				Object key = it.next();
157
				Object masterValue = diff.getOldValue(key);
158
				Object oldValue = cache.get(masterValue);
159
				oldValues.put(key, oldValue);
160
			}
161
162
			Set changedKeys = new HashSet(diff.getChangedKeys());
163
			for (Iterator it = changedKeys.iterator(); it.hasNext();) {
164
				Object key = it.next();
165
166
				Object oldMasterValue = diff.getOldValue(key);
167
				Object newMasterValue = diff.getNewValue(key);
168
169
				Object oldValue = cache.get(oldMasterValue);
170
				Object newValue = cache.get(newMasterValue);
171
172
				if (Util.equals(oldValue, newValue)) {
173
					it.remove();
174
				} else {
175
					oldValues.put(key, oldValue);
176
					newValues.put(key, newValue);
177
				}
178
			}
179
180
			return Diffs.createMapDiff(addedKeys, removedKeys, changedKeys,
181
					oldValues, newValues);
182
		}
183
	};
184
185
	private IStaleListener staleListener = new IStaleListener() {
186
		public void handleStale(StaleEvent staleEvent) {
187
			fireStale();
188
		}
189
	};
190
191
	/**
192
	 * @param map
193
	 * @param valueProperty
194
	 */
195
	public ObservableMapDelegatingValuePropertyObservableMap(
196
			IObservableMap map, DelegatingValueProperty valueProperty) {
197
		super(map.getRealm());
198
		this.masterMap = map;
199
		this.detailProperty = valueProperty;
200
		this.cache = new DelegatingCache(getRealm(), valueProperty) {
201
			void handleValueChange(Object masterElement, Object oldValue,
202
					Object newValue) {
203
				fireMapChange(keysFor(masterElement), oldValue, newValue);
204
			}
205
		};
206
		cache.addAll(masterMap.values());
207
208
		masterMap.addMapChangeListener(masterListener);
209
		masterMap.addStaleListener(staleListener);
210
	}
211
212
	public Set entrySet() {
213
		getterCalled();
214
		if (entrySet == null)
215
			entrySet = new EntrySet();
216
		return entrySet;
217
	}
218
219
	private void getterCalled() {
220
		ObservableTracker.getterCalled(this);
221
	}
222
223
	public Object get(Object key) {
224
		getterCalled();
225
		Object masterValue = masterMap.get(key);
226
		return cache.get(masterValue);
227
	}
228
229
	public Object put(Object key, Object value) {
230
		if (!masterMap.containsKey(key))
231
			return null;
232
		Object masterValue = masterMap.get(key);
233
		return cache.put(masterValue, value);
234
	}
235
236
	public boolean isStale() {
237
		getterCalled();
238
		return masterMap.isStale();
239
	}
240
241
	public Object getObserved() {
242
		return masterMap;
243
	}
244
245
	public IProperty getProperty() {
246
		return detailProperty;
247
	}
248
249
	public Object getKeyType() {
250
		return masterMap.getKeyType();
251
	}
252
253
	public Object getValueType() {
254
		return detailProperty.getValueType();
255
	}
256
257
	private Set keysFor(Object masterValue) {
258
		Set keys = new HashSet();
259
260
		for (Iterator it = masterMap.entrySet().iterator(); it.hasNext();) {
261
			Map.Entry entry = (Entry) it.next();
262
			if (entry.getValue() == masterValue) {
263
				keys.add(entry.getKey());
264
			}
265
		}
266
267
		return keys;
268
	}
269
270
	private void fireMapChange(final Set changedKeys, final Object oldValue,
271
			final Object newValue) {
272
		fireMapChange(new MapDiff() {
273
			public Set getAddedKeys() {
274
				return Collections.EMPTY_SET;
275
			}
276
277
			public Set getRemovedKeys() {
278
				return Collections.EMPTY_SET;
279
			}
280
281
			public Set getChangedKeys() {
282
				return Collections.unmodifiableSet(changedKeys);
283
			}
284
285
			public Object getOldValue(Object key) {
286
				if (changedKeys.contains(key))
287
					return oldValue;
288
				return null;
289
			}
290
291
			public Object getNewValue(Object key) {
292
				if (changedKeys.contains(key))
293
					return newValue;
294
				return null;
295
			}
296
		});
297
	}
298
299
	public synchronized void dispose() {
300
		if (masterMap != null) {
301
			masterMap.removeMapChangeListener(masterListener);
302
			masterMap.removeStaleListener(staleListener);
303
			masterMap = null;
304
		}
305
306
		if (cache != null) {
307
			cache.dispose();
308
			cache = null;
309
		}
310
311
		masterListener = null;
312
		detailProperty = null;
313
314
		super.dispose();
315
	}
316
}
(-)src/org/eclipse/core/internal/databinding/property/value/ObservableListSimpleValuePropertyObservableList.java (+451 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.value;
13
14
import java.lang.reflect.Array;
15
import java.util.ArrayList;
16
import java.util.Collection;
17
import java.util.HashMap;
18
import java.util.HashSet;
19
import java.util.Iterator;
20
import java.util.List;
21
import java.util.ListIterator;
22
import java.util.Map;
23
import java.util.Set;
24
25
import org.eclipse.core.databinding.observable.Diffs;
26
import org.eclipse.core.databinding.observable.IStaleListener;
27
import org.eclipse.core.databinding.observable.ObservableTracker;
28
import org.eclipse.core.databinding.observable.StaleEvent;
29
import org.eclipse.core.databinding.observable.list.AbstractObservableList;
30
import org.eclipse.core.databinding.observable.list.IListChangeListener;
31
import org.eclipse.core.databinding.observable.list.IObservableList;
32
import org.eclipse.core.databinding.observable.list.ListChangeEvent;
33
import org.eclipse.core.databinding.observable.list.ListDiff;
34
import org.eclipse.core.databinding.observable.list.ListDiffEntry;
35
import org.eclipse.core.databinding.observable.set.IObservableSet;
36
import org.eclipse.core.databinding.observable.set.ISetChangeListener;
37
import org.eclipse.core.databinding.observable.set.SetChangeEvent;
38
import org.eclipse.core.databinding.observable.set.WritableSet;
39
import org.eclipse.core.databinding.property.INativePropertyListener;
40
import org.eclipse.core.databinding.property.IProperty;
41
import org.eclipse.core.databinding.property.IPropertyObservable;
42
import org.eclipse.core.databinding.property.ISimplePropertyListener;
43
import org.eclipse.core.databinding.property.SimplePropertyEvent;
44
import org.eclipse.core.databinding.property.value.ISimpleValueProperty;
45
import org.eclipse.core.internal.databinding.IdentityWrapper;
46
import org.eclipse.core.internal.databinding.Util;
47
48
/**
49
 * @since 1.2
50
 */
51
public class ObservableListSimpleValuePropertyObservableList extends
52
		AbstractObservableList implements IPropertyObservable {
53
	private IObservableList masterList;
54
	private ISimpleValueProperty detailProperty;
55
56
	private IObservableSet knownMasterElements;
57
	private Map cachedValues;
58
59
	private boolean updating;
60
61
	private IListChangeListener masterListener = new IListChangeListener() {
62
		public void handleListChange(ListChangeEvent event) {
63
			if (!isDisposed()) {
64
				updateKnownElements();
65
				fireListChange(convertDiff(event.diff));
66
			}
67
		}
68
69
		private void updateKnownElements() {
70
			Set identityKnownElements = new HashSet();
71
			for (Iterator it = masterList.iterator(); it.hasNext();) {
72
				identityKnownElements.add(new IdentityWrapper(it.next()));
73
			}
74
75
			knownMasterElements.retainAll(identityKnownElements);
76
			knownMasterElements.addAll(identityKnownElements);
77
		}
78
79
		private ListDiff convertDiff(ListDiff diff) {
80
			// Convert diff to detail value
81
			ListDiffEntry[] masterEntries = diff.getDifferences();
82
			ListDiffEntry[] detailEntries = new ListDiffEntry[masterEntries.length];
83
			for (int i = 0; i < masterEntries.length; i++) {
84
				ListDiffEntry masterDifference = masterEntries[i];
85
				int index = masterDifference.getPosition();
86
				boolean addition = masterDifference.isAddition();
87
				Object masterElement = masterDifference.getElement();
88
				Object elementDetailValue = detailProperty.get(masterElement);
89
				detailEntries[i] = Diffs.createListDiffEntry(index, addition,
90
						elementDetailValue);
91
			}
92
			return Diffs.createListDiff(detailEntries);
93
		}
94
	};
95
96
	private IStaleListener staleListener = new IStaleListener() {
97
		public void handleStale(StaleEvent staleEvent) {
98
			fireStale();
99
		}
100
	};
101
102
	private INativePropertyListener detailListener;
103
104
	/**
105
	 * @param masterList
106
	 * @param valueProperty
107
	 */
108
	public ObservableListSimpleValuePropertyObservableList(
109
			IObservableList masterList, ISimpleValueProperty valueProperty) {
110
		super(masterList.getRealm());
111
		this.masterList = masterList;
112
		this.detailProperty = valueProperty;
113
114
		ISimplePropertyListener listener = new ISimplePropertyListener() {
115
			public void handlePropertyChange(SimplePropertyEvent event) {
116
				if (!isDisposed() && !updating) {
117
					notifyIfChanged(event.getSource());
118
				}
119
			}
120
		};
121
		this.detailListener = detailProperty.adaptListener(listener);
122
	}
123
124
	protected void firstListenerAdded() {
125
		knownMasterElements = new WritableSet(getRealm());
126
		cachedValues = new HashMap();
127
		knownMasterElements.addSetChangeListener(new ISetChangeListener() {
128
			public void handleSetChange(SetChangeEvent event) {
129
				for (Iterator it = event.diff.getRemovals().iterator(); it
130
						.hasNext();) {
131
					IdentityWrapper wrapper = (IdentityWrapper) it.next();
132
					Object key = wrapper.unwrap();
133
					detailProperty.removeListener(key, detailListener);
134
					cachedValues.remove(wrapper);
135
				}
136
				for (Iterator it = event.diff.getAdditions().iterator(); it
137
						.hasNext();) {
138
					IdentityWrapper wrapper = (IdentityWrapper) it.next();
139
					Object key = wrapper.unwrap();
140
					cachedValues.put(wrapper, detailProperty.get(key));
141
					detailProperty.addListener(key, detailListener);
142
				}
143
			}
144
		});
145
		for (Iterator it = masterList.iterator(); it.hasNext();) {
146
			knownMasterElements.add(new IdentityWrapper(it.next()));
147
		}
148
149
		masterList.addListChangeListener(masterListener);
150
		masterList.addStaleListener(staleListener);
151
	}
152
153
	protected void lastListenerRemoved() {
154
		masterList.removeListChangeListener(masterListener);
155
		masterList.removeStaleListener(staleListener);
156
		if (knownMasterElements != null) {
157
			knownMasterElements.clear(); // clears cachedValues
158
			knownMasterElements.dispose();
159
			knownMasterElements = null;
160
		}
161
		cachedValues.clear();
162
		cachedValues = null;
163
	}
164
165
	protected int doGetSize() {
166
		getterCalled();
167
		return masterList.size();
168
	}
169
170
	private void getterCalled() {
171
		ObservableTracker.getterCalled(this);
172
	}
173
174
	public Object getElementType() {
175
		return detailProperty.getValueType();
176
	}
177
178
	public Object get(int index) {
179
		getterCalled();
180
		Object masterElement = masterList.get(index);
181
		return detailProperty.get(masterElement);
182
	}
183
184
	public boolean add(Object o) {
185
		throw new UnsupportedOperationException();
186
	}
187
188
	public boolean addAll(Collection c) {
189
		throw new UnsupportedOperationException();
190
	}
191
192
	public boolean addAll(int index, Collection c) {
193
		throw new UnsupportedOperationException();
194
	}
195
196
	public boolean contains(Object o) {
197
		getterCalled();
198
199
		for (Iterator it = masterList.iterator(); it.hasNext();) {
200
			if (Util.equals(detailProperty.get(it.next()), o))
201
				return true;
202
		}
203
		return false;
204
	}
205
206
	public boolean isEmpty() {
207
		getterCalled();
208
		return masterList.isEmpty();
209
	}
210
211
	public boolean isStale() {
212
		getterCalled();
213
		return masterList.isStale();
214
	}
215
216
	public Iterator iterator() {
217
		getterCalled();
218
		return new Iterator() {
219
			Iterator it = masterList.iterator();
220
221
			public boolean hasNext() {
222
				getterCalled();
223
				return it.hasNext();
224
			}
225
226
			public Object next() {
227
				getterCalled();
228
				Object masterElement = it.next();
229
				return detailProperty.get(masterElement);
230
			}
231
232
			public void remove() {
233
				throw new UnsupportedOperationException();
234
			}
235
		};
236
	}
237
238
	public Object move(int oldIndex, int newIndex) {
239
		throw new UnsupportedOperationException();
240
	}
241
242
	public boolean remove(Object o) {
243
		throw new UnsupportedOperationException();
244
	}
245
246
	public boolean removeAll(Collection c) {
247
		throw new UnsupportedOperationException();
248
	}
249
250
	public boolean retainAll(Collection c) {
251
		throw new UnsupportedOperationException();
252
	}
253
254
	public Object[] toArray() {
255
		getterCalled();
256
		Object[] masterElements = masterList.toArray();
257
		Object[] result = new Object[masterElements.length];
258
		for (int i = 0; i < result.length; i++) {
259
			result[i] = detailProperty.get(masterElements[i]);
260
		}
261
		return result;
262
	}
263
264
	public Object[] toArray(Object[] a) {
265
		getterCalled();
266
		Object[] masterElements = masterList.toArray();
267
		if (a.length < masterElements.length)
268
			a = (Object[]) Array.newInstance(a.getClass().getComponentType(),
269
					masterElements.length);
270
		for (int i = 0; i < masterElements.length; i++) {
271
			a[i] = detailProperty.get(masterElements[i]);
272
		}
273
		return a;
274
	}
275
276
	public void add(int index, Object o) {
277
		throw new UnsupportedOperationException();
278
	}
279
280
	public void clear() {
281
		throw new UnsupportedOperationException();
282
	}
283
284
	public ListIterator listIterator() {
285
		return listIterator(0);
286
	}
287
288
	public ListIterator listIterator(final int index) {
289
		getterCalled();
290
		return new ListIterator() {
291
			ListIterator it = masterList.listIterator(index);
292
			Object lastMasterElement;
293
			Object lastElement;
294
			boolean haveIterated = false;
295
296
			public void add(Object arg0) {
297
				throw new UnsupportedOperationException();
298
			}
299
300
			public boolean hasNext() {
301
				getterCalled();
302
				return it.hasNext();
303
			}
304
305
			public boolean hasPrevious() {
306
				getterCalled();
307
				return it.hasPrevious();
308
			}
309
310
			public Object next() {
311
				getterCalled();
312
				lastMasterElement = it.next();
313
				lastElement = detailProperty.get(lastMasterElement);
314
				haveIterated = true;
315
				return lastElement;
316
			}
317
318
			public int nextIndex() {
319
				getterCalled();
320
				return it.nextIndex();
321
			}
322
323
			public Object previous() {
324
				getterCalled();
325
				lastMasterElement = it.previous();
326
				lastElement = detailProperty.get(lastMasterElement);
327
				haveIterated = true;
328
				return lastElement;
329
			}
330
331
			public int previousIndex() {
332
				getterCalled();
333
				return it.previousIndex();
334
			}
335
336
			public void remove() {
337
				throw new UnsupportedOperationException();
338
			}
339
340
			public void set(Object o) {
341
				checkRealm();
342
				if (!haveIterated)
343
					throw new IllegalStateException();
344
345
				boolean wasUpdating = updating;
346
				updating = true;
347
				try {
348
349
					detailProperty.set(lastElement, o, Diffs.createValueDiff(
350
							lastMasterElement, o));
351
				} finally {
352
					updating = wasUpdating;
353
				}
354
355
				notifyIfChanged(lastMasterElement);
356
357
				lastElement = o;
358
			}
359
		};
360
	}
361
362
	private void notifyIfChanged(Object masterElement) {
363
		if (cachedValues != null) {
364
			Object oldValue = cachedValues.get(new IdentityWrapper(
365
					masterElement));
366
			Object newValue = detailProperty.get(masterElement);
367
			if (!Util.equals(oldValue, newValue)) {
368
				cachedValues.put(new IdentityWrapper(masterElement), newValue);
369
				fireListChange(indicesOf(masterElement), oldValue, newValue);
370
			}
371
		}
372
	}
373
374
	private int[] indicesOf(Object masterElement) {
375
		List indices = new ArrayList();
376
377
		for (ListIterator it = ObservableListSimpleValuePropertyObservableList.this.masterList
378
				.listIterator(); it.hasNext();) {
379
			if (masterElement == it.next())
380
				indices.add(new Integer(it.previousIndex()));
381
		}
382
383
		int[] result = new int[indices.size()];
384
		for (int i = 0; i < result.length; i++) {
385
			result[i] = ((Integer) indices.get(i)).intValue();
386
		}
387
		return result;
388
	}
389
390
	private void fireListChange(int[] indices, Object oldValue, Object newValue) {
391
		ListDiffEntry[] differences = new ListDiffEntry[indices.length * 2];
392
		for (int i = 0; i < indices.length; i++) {
393
			int index = indices[i];
394
			differences[i * 2] = Diffs.createListDiffEntry(index, false,
395
					oldValue);
396
			differences[i * 2 + 1] = Diffs.createListDiffEntry(index, true,
397
					newValue);
398
		}
399
		fireListChange(Diffs.createListDiff(differences));
400
	}
401
402
	public Object remove(int index) {
403
		throw new UnsupportedOperationException();
404
	}
405
406
	public Object set(int index, Object o) {
407
		checkRealm();
408
		Object masterElement = masterList.get(index);
409
		Object oldValue = detailProperty.get(masterElement);
410
411
		boolean wasUpdating = updating;
412
		updating = true;
413
		try {
414
			detailProperty.set(masterElement, o, Diffs.createValueDiff(
415
					oldValue, o));
416
		} finally {
417
			updating = wasUpdating;
418
		}
419
420
		notifyIfChanged(masterElement);
421
422
		return oldValue;
423
	}
424
425
	public Object getObserved() {
426
		return masterList;
427
	}
428
429
	public IProperty getProperty() {
430
		return detailProperty;
431
	}
432
433
	public synchronized void dispose() {
434
		if (masterList != null) {
435
			masterList.removeListChangeListener(masterListener);
436
			masterList = null;
437
		}
438
		if (knownMasterElements != null) {
439
			knownMasterElements.clear(); // detaches listeners
440
			knownMasterElements.dispose();
441
			knownMasterElements = null;
442
		}
443
444
		masterListener = null;
445
		detailListener = null;
446
		detailProperty = null;
447
		cachedValues = null;
448
449
		super.dispose();
450
	}
451
}
(-)src/org/eclipse/core/databinding/property/SimplePropertyEvent.java (+77 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.IDiff;
17
import org.eclipse.core.internal.databinding.Util;
18
19
/**
20
 * Base class for change events in the properties API
21
 * 
22
 * @since 1.2
23
 */
24
public final class SimplePropertyEvent extends EventObject {
25
	private static final long serialVersionUID = 1L;
26
27
	/**
28
	 * The property that changed
29
	 */
30
	public final ISimpleProperty property;
31
32
	/**
33
	 * A diff object describing the change in state, or null if the change is
34
	 * unknown or could not be determined.
35
	 */
36
	public final IDiff diff;
37
38
	/**
39
	 * Constructs a PropertyChangeEvent 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 diff describing the change in state, or null if the change
47
	 *            is unknown.
48
	 */
49
	public SimplePropertyEvent(Object source, ISimpleProperty property,
50
			IDiff diff) {
51
		super(source);
52
		this.property = property;
53
		this.diff = diff;
54
	}
55
56
	public boolean equals(Object obj) {
57
		if (obj == this)
58
			return true;
59
		if (obj == null)
60
			return false;
61
		if (getClass() != obj.getClass())
62
			return false;
63
64
		SimplePropertyEvent that = (SimplePropertyEvent) obj;
65
		return Util.equals(getSource(), that.getSource())
66
				&& Util.equals(this.property, that.property)
67
				&& Util.equals(this.diff, that.diff);
68
	}
69
70
	public int hashCode() {
71
		int hash = 17;
72
		hash = hash * 37 + getSource().hashCode();
73
		hash = hash * 37 + property.hashCode();
74
		hash = hash * 37 + (diff == null ? 0 : diff.hashCode());
75
		return hash;
76
	}
77
}

Return to bug 194734