001: /* uDig - User Friendly Desktop Internet GIS client
002: * http://udig.refractions.net
003: * (C) 2004, Refractions Research Inc.
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation;
008: * version 2.1 of the License.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: */
015: package net.refractions.udig.tools.edit.support;
016:
017: import java.util.AbstractSet;
018: import java.util.ArrayList;
019: import java.util.Collection;
020: import java.util.Collections;
021: import java.util.HashSet;
022: import java.util.Iterator;
023: import java.util.List;
024: import java.util.Map;
025: import java.util.Set;
026: import java.util.concurrent.ConcurrentHashMap;
027:
028: import net.refractions.udig.tools.edit.EditPlugin;
029: import net.refractions.udig.tools.edit.support.EditBlackboardEvent.EventType;
030:
031: /**
032: * A set of points that are on the EditBlackboard. Only the edit black board can edit this set. All
033: * public add methods will throw and exception.
034: *
035: * @author jones
036: * @since 1.1.0
037: */
038: public class Selection extends AbstractSet<Point> implements Set<Point> {
039:
040: /** long serialVersionUID field */
041: private static final long serialVersionUID = 3103252189848308511L;
042: private EditBlackboard blackboard;
043: protected Map<Point, Collection<LazyCoord>> coordMap = new ConcurrentHashMap<Point, Collection<LazyCoord>>();
044: boolean notify = true;
045: protected BlackboardListener blackboardListener = new BlackboardListener();
046:
047: public Selection(EditBlackboard blackboard) {
048: this .blackboard = blackboard;
049: blackboard.getListeners().add(getBlackboardListener());
050: }
051:
052: public Selection(Selection selection2) {
053: this (selection2.blackboard);
054: coordMap.putAll(selection2.coordMap);
055: }
056:
057: protected BlackboardListener getBlackboardListener() {
058: return blackboardListener;
059: }
060:
061: /**
062: * The list of lazy coordinates. The list is unmodifiable.
063: *
064: * @param point
065: * @return
066: */
067: synchronized Collection<LazyCoord> getLazyCoordinates(Point point) {
068: return Collections.unmodifiableCollection(coordMap.get(point));
069: }
070:
071: /**
072: * Adds a point to the selection and all the Coordinates that are in the editblackboard at that
073: * point.
074: *
075: * @see #getCoordinates(Point);
076: * @param o
077: * @return
078: */
079: boolean doAdd(Point o) {
080: boolean result;
081: synchronized (this ) {
082: result = addInternal(o);
083: }
084: if (result)
085: notifyListeners(Collections.singleton(o), null);
086: return result;
087: }
088:
089: /**
090: * @param o
091: * @param coords
092: * @return
093: */
094: protected boolean addInternal(Point o) {
095: List<LazyCoord> coords = this .blackboard.coordMapping.get(o);
096: if (coords != null && coords.size() != 0
097: && !coordMap.containsKey(o)) {
098: coordMap.put(o, new ArrayList<LazyCoord>(coords));
099: return true;
100: }
101: return false;
102: }
103:
104: boolean doAddAll(Collection<? extends Point> c) {
105: Set<Point> added = new HashSet<Point>();
106: boolean result = false;
107: synchronized (this ) {
108: for (Point point : c) {
109: if (point == null)
110: continue;
111: boolean wasAdded = addInternal(point);
112: if (wasAdded)
113: added.add(point);
114: result = result || wasAdded;
115: }
116: }
117: if (result)
118: notifyListeners(added, null);
119: return result;
120: }
121:
122: void doClear() {
123: Set<Point> set = null;
124: synchronized (this ) {
125: set = new HashSet<Point>(this .coordMap.keySet());
126: coordMap.clear();
127: }
128: if (set != null && !set.isEmpty())
129: notifyListeners(null, set);
130: }
131:
132: public synchronized boolean contains(Object o) {
133: return coordMap.containsKey(o);
134: }
135:
136: public synchronized boolean containsAll(Collection<?> c) {
137: return coordMap.keySet().containsAll(c);
138: }
139:
140: public synchronized boolean isEmpty() {
141: return coordMap.isEmpty();
142: }
143:
144: public Iterator<Point> iterator() {
145: return new Iterator<Point>() {
146: Iterator<Point> iter = coordMap.keySet().iterator();
147: Point lastPoint;
148:
149: public boolean hasNext() {
150: return iter.hasNext();
151: }
152:
153: public Point next() {
154: lastPoint = iter.next();
155: return lastPoint;
156: }
157:
158: public void remove() {
159: throw new UnsupportedOperationException();
160: }
161:
162: };
163: }
164:
165: boolean doRemove(Object o) {
166: boolean result;
167: synchronized (this ) {
168: result = coordMap.remove(o) != null;
169: }
170: if (result)
171: notifyListeners(null, Collections.singleton((Point) o));
172: return result;
173: }
174:
175: boolean doRetainAll(Collection<?> c) {
176: boolean result;
177: Set<Point> removed = new HashSet<Point>();
178: synchronized (this ) {
179: for (Point p : coordMap.keySet()) {
180: if (p == null)
181: continue;
182: if (!c.contains(p)) {
183: removed.add((Point) p);
184: }
185: }
186: result = doRemoveAll(removed, false);
187: }
188: if (!removed.isEmpty())
189: notifyListeners(null, removed);
190: return result;
191: }
192:
193: boolean doRemoveAll(Collection<?> c, boolean notify) {
194: boolean result = false;
195: Set<Point> removed = new HashSet<Point>();
196: synchronized (this ) {
197: for (Object point : c) {
198: if (point == null)
199: continue;
200: if (this .coordMap.remove(point) != null) {
201: removed.add((Point) point);
202: result = true;
203: }
204: }
205: }
206: if (notify && result)
207: notifyListeners(null, removed);
208:
209: return result;
210: }
211:
212: public synchronized int size() {
213: return coordMap.size();
214: }
215:
216: public synchronized Object[] toArray() {
217: return coordMap.keySet().toArray();
218: }
219:
220: public synchronized <T> T[] toArray(T[] a) {
221: return coordMap.keySet().toArray(a);
222: }
223:
224: protected void notifyListeners(Set<Point> added, Set<Point> removed) {
225: if (!notify)
226: return;
227:
228: if (added == null) {
229: added = Collections.<Point> emptySet();
230: }
231: if (removed == null) {
232: removed = Collections.<Point> emptySet();
233: }
234: blackboard.notify(new EditBlackboardEvent(blackboard, this ,
235: EventType.SELECTION, removed, added));
236: }
237:
238: @Override
239: public synchronized String toString() {
240: return coordMap.keySet().toString();
241: }
242:
243: class BlackboardListener extends EditBlackboardAdapter {
244:
245: @Override
246: public synchronized void changed(EditBlackboardEvent e) {
247: Object oldValue = e.getOldValue();
248: switch (e.getType()) {
249: case SET_GEOMS:
250: if (size() > 0)
251: doClear();
252: break;
253: case MOVE_POINT:
254: Point newValue = (Point) e.getNewValue();
255: if (movePoint(oldValue, newValue)) {
256: notifyListeners(Collections.singleton(newValue),
257: Collections.singleton((Point) oldValue));
258: }
259:
260: break;
261: case REMOVE_POINT:
262: doRemove(oldValue);
263: break;
264:
265: case TRANFORMATION:
266: Map<Point, List<Point>> p = e.getTransformationMap();
267: HashSet<Point> added = new HashSet<Point>();
268: try {
269: notify = false;
270: for (Map.Entry<Point, List<Point>> entry : p
271: .entrySet()) {
272: if (doRemove(entry.getKey())) {
273: doAddAll(entry.getValue());
274: added.addAll(entry.getValue());
275: }
276: }
277: } finally {
278: notify = true;
279: }
280: notifyListeners(added, p.keySet());
281:
282: break;
283: default:
284: break;
285: }
286:
287: assertValid();
288: }
289:
290: /**
291: * @param oldValue
292: * @param newValue
293: */
294: private boolean movePoint(Object oldValue, Point newValue) {
295: if (newValue.equals(oldValue))
296: return false;
297: if (!contains(oldValue))
298: return false;
299: Collection<LazyCoord> oldCoords = coordMap.get(oldValue);
300: Collection<LazyCoord> newCoords = coordMap.get(newValue);
301: coordMap.remove(oldValue);
302: if (newCoords == null) {
303: newCoords = new ArrayList<LazyCoord>();
304: coordMap.put(newValue, newCoords);
305: }
306: newCoords.addAll(oldCoords);
307: return true;
308: }
309:
310: @Override
311: public synchronized void batchChange(List<EditBlackboardEvent> e) {
312: if (e.isEmpty())
313: return;
314: e.get(0).getEditBlackboard().startBatchingEvents();
315: for (EditBlackboardEvent event : e) {
316: changed(event);
317: }
318: e.get(0).getEditBlackboard().fireBatchedEvents();
319: }
320:
321: }
322:
323: void add(Point point, List<LazyCoord> coords) {
324: Collection<LazyCoord> mappedCoords = coordMap.get(point);
325: if (mappedCoords == null) {
326: mappedCoords = new ArrayList<LazyCoord>();
327: coordMap.put(point, mappedCoords);
328: }
329: mappedCoords.addAll(coords);
330: }
331:
332: public void disconnect() {
333: blackboard.getListeners().remove(this .blackboardListener);
334: notify = false;
335: }
336:
337: public boolean isNotify() {
338: return notify;
339: }
340:
341: public void setNotify(boolean notify) {
342: this .notify = notify;
343: }
344:
345: public void assertValid() {
346: if (!EditPlugin.isDebugging(EditPlugin.RUN_ASSERTIONS))
347: return;
348:
349: // for (Map.Entry<Point, Collection<LazyCoord>> entry : this.coordMap.entrySet()) {
350: // List<LazyCoord> list = blackboard.coordMapping.get(entry.getKey());
351: // if( list!=null && list.isEmpty() ){
352: // throw new AssertionError(entry.getKey()+" is not in blackboard"); //$NON-NLS-1$
353: // }
354: //
355: // for (LazyCoord coord : entry.getValue()) {
356: // if( !list.contains(coord) )
357: // throw new AssertionError(coord+" is not in blackboard at correct location");
358: // //$NON-NLS-1$
359: // }
360: // }
361: }
362: }
|