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