comparison org.eclipse.core.databinding.observable/src/org/eclipse/core/databinding/observable/set/MappedSet.d @ 95:6208d4f6a277

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