78
|
1 /*******************************************************************************
|
|
2 * Copyright (c) 2006, 2007 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 module org.eclipse.core.databinding.observable.set.MappedSet;
|
81
|
13 import org.eclipse.core.databinding.observable.set.ISetChangeListener;
|
|
14 import org.eclipse.core.databinding.observable.set.SetChangeEvent;
|
|
15 import org.eclipse.core.databinding.observable.set.IObservableSet;
|
|
16 import org.eclipse.core.databinding.observable.set.ObservableSet;
|
78
|
17
|
|
18 import java.lang.all;
|
|
19
|
|
20 import java.util.Collections;
|
|
21 import java.util.HashMap;
|
|
22 import java.util.HashSet;
|
|
23 import java.util.Iterator;
|
|
24 import java.util.Map;
|
|
25 import java.util.Set;
|
|
26
|
|
27 import org.eclipse.core.databinding.observable.Diffs;
|
|
28 import org.eclipse.core.databinding.observable.Realm;
|
|
29 import org.eclipse.core.databinding.observable.map.IMapChangeListener;
|
|
30 import org.eclipse.core.databinding.observable.map.IObservableMap;
|
|
31 import org.eclipse.core.databinding.observable.map.MapChangeEvent;
|
|
32 import org.eclipse.core.databinding.observable.map.MapDiff;
|
|
33
|
|
34 /**
|
|
35 *
|
|
36 * <p>
|
|
37 * This class is thread safe. All state accessing methods must be invoked from
|
|
38 * the {@link Realm#isCurrent() current realm}. Methods for adding and removing
|
|
39 * listeners may be invoked from any thread.
|
|
40 * </p>
|
|
41 *
|
|
42 * @since 1.0
|
|
43 *
|
|
44 */
|
|
45 public class MappedSet : ObservableSet {
|
|
46
|
|
47 private final IObservableMap wrappedMap;
|
|
48
|
|
49 /*
|
|
50 * Map from values (range elements) to Integer ref counts
|
|
51 */
|
|
52 private Map valueCounts = new HashMap();
|
|
53
|
|
54 private ISetChangeListener domainListener = new class() ISetChangeListener {
|
|
55 public void handleSetChange(SetChangeEvent event) {
|
|
56 Set additions = new HashSet();
|
|
57 for (Iterator it = event.diff.getAdditions().iterator(); it.hasNext();) {
|
|
58 Object added = it.next();
|
|
59 Object mapValue = wrappedMap.get(added);
|
|
60 if (handleAddition(mapValue)) {
|
|
61 additions.add(mapValue);
|
|
62 }
|
|
63 }
|
|
64 Set removals = new HashSet();
|
|
65 for (Iterator it = event.diff.getRemovals().iterator(); it.hasNext();) {
|
|
66 Object removed = it.next();
|
|
67 Object mapValue = wrappedMap.get(removed);
|
|
68 if (handleRemoval(mapValue)) {
|
|
69 removals.add(mapValue);
|
|
70 }
|
|
71 }
|
|
72 fireSetChange(Diffs.createSetDiff(additions, removals));
|
|
73 }
|
|
74 };
|
|
75
|
|
76 private IMapChangeListener mapChangeListener = new class() IMapChangeListener {
|
|
77 public void handleMapChange(MapChangeEvent event) {
|
|
78 MapDiff diff = event.diff;
|
|
79 Set additions = new HashSet();
|
|
80 Set removals = new HashSet();
|
|
81 for (Iterator it = diff.getRemovedKeys().iterator(); it.hasNext();) {
|
|
82 Object key = it.next();
|
|
83 Object oldValue = diff.getOldValue(key);
|
|
84 if (handleRemoval(oldValue)) {
|
|
85 removals.add(oldValue);
|
|
86 }
|
|
87 }
|
|
88 for (Iterator it = diff.getChangedKeys().iterator(); it.hasNext();) {
|
|
89 Object key = it.next();
|
|
90 Object oldValue = diff.getOldValue(key);
|
|
91 Object newValue = diff.getNewValue(key);
|
|
92 if (handleRemoval(oldValue)) {
|
|
93 removals.add(oldValue);
|
|
94 }
|
|
95 if (handleAddition(newValue)) {
|
|
96 additions.add(newValue);
|
|
97 }
|
|
98 }
|
|
99 for (Iterator it = diff.getAddedKeys().iterator(); it.hasNext();) {
|
|
100 Object key = it.next();
|
|
101 Object newValue = diff.getNewValue(key);
|
|
102 if (handleAddition(newValue)) {
|
|
103 additions.add(newValue);
|
|
104 }
|
|
105 }
|
|
106 fireSetChange(Diffs.createSetDiff(additions, removals));
|
|
107 }
|
|
108 };
|
|
109
|
|
110 private IObservableSet input;
|
|
111
|
|
112 /**
|
|
113 * @param input
|
|
114 * @param map
|
|
115 */
|
|
116 public this(IObservableSet input, IObservableMap map) {
|
|
117 super(input.getRealm(), Collections.EMPTY_SET, Object.classinfo);
|
|
118 setWrappedSet(valueCounts.keySet());
|
|
119 this.wrappedMap = map;
|
|
120 this.input = input;
|
|
121 for (Iterator it = input.iterator(); it.hasNext();) {
|
|
122 Object element = it.next();
|
|
123 Object functionValue = wrappedMap.get(element);
|
|
124 handleAddition(functionValue);
|
|
125 }
|
|
126 input.addSetChangeListener(domainListener);
|
|
127 map.addMapChangeListener(mapChangeListener);
|
|
128 }
|
|
129
|
|
130 /**
|
|
131 * @param mapValue
|
|
132 * @return true if the given mapValue was an addition
|
|
133 */
|
|
134 protected bool handleAddition(Object mapValue) {
|
|
135 Integer count = cast(Integer) valueCounts.get(mapValue);
|
|
136 if (count is null) {
|
|
137 valueCounts.put(mapValue, new Integer(1));
|
|
138 return true;
|
|
139 }
|
|
140 valueCounts.put(mapValue, new Integer(count.intValue() + 1));
|
|
141 return false;
|
|
142 }
|
|
143
|
|
144 /**
|
|
145 * @param mapValue
|
|
146 * @return true if the given mapValue has been removed
|
|
147 */
|
|
148 protected bool handleRemoval(Object mapValue) {
|
|
149 Integer count = cast(Integer) valueCounts.get(mapValue);
|
|
150 if (count.intValue() <= 1) {
|
|
151 valueCounts.remove(mapValue);
|
|
152 return true;
|
|
153 }
|
|
154 valueCounts.put(mapValue, new Integer(count.intValue() - 1));
|
|
155 return false;
|
|
156 }
|
|
157
|
|
158 public synchronized void dispose() {
|
|
159 wrappedMap.removeMapChangeListener(mapChangeListener);
|
|
160 input.removeSetChangeListener(domainListener);
|
|
161 }
|
|
162
|
|
163 }
|