source: josm/trunk/src/org/openstreetmap/josm/data/osm/DataSet.java@ 2512

Last change on this file since 2512 was 2512, checked in by stoecker, 14 years ago

i18n updated, fixed files to reduce problems when applying patches, fix #4017

  • Property svn:eol-style set to native
File size: 30.2 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.data.osm;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.geom.Area;
7import java.util.ArrayList;
8import java.util.Arrays;
9import java.util.Collection;
10import java.util.Collections;
11import java.util.Comparator;
12import java.util.HashMap;
13import java.util.HashSet;
14import java.util.Iterator;
15import java.util.LinkedHashSet;
16import java.util.LinkedList;
17import java.util.List;
18import java.util.Map;
19import java.util.Set;
20
21import org.openstreetmap.josm.data.SelectionChangedListener;
22
23/**
24 * DataSet is the data behind the application. It can consists of only a few points up to the whole
25 * osm database. DataSet's can be merged together, saved, (up/down/disk)loaded etc.
26 *
27 * Note that DataSet is not an osm-primitive and so has no key association but a few members to
28 * store some information.
29 *
30 * @author imi
31 */
32public class DataSet implements Cloneable {
33
34 private static class IdHash implements Hash<PrimitiveId,OsmPrimitive> {
35
36 public int getHashCode(PrimitiveId k) {
37 return (int)k.getUniqueId() ^ k.getType().hashCode();
38 }
39
40 public boolean equals(PrimitiveId key, OsmPrimitive value) {
41 if (key == null || value == null) return false;
42 return key.getUniqueId() == value.getUniqueId() && key.getType() == value.getType();
43 }
44 }
45
46 private Storage<OsmPrimitive> allPrimitives = new Storage<OsmPrimitive>(new IdHash());
47 private Map<PrimitiveId, OsmPrimitive> primitivesMap = allPrimitives.foreignKey(new IdHash());
48 private List<DataSetListener> listeners = new ArrayList<DataSetListener>();
49 // Number of open calls to beginUpdate
50 private int updateCount;
51
52 /**
53 * The API version that created this data set, if any.
54 */
55 private String version;
56
57 /**
58 * Replies the API version this dataset was created from. May be null.
59 *
60 * @return the API version this dataset was created from. May be null.
61 */
62 public String getVersion() {
63 return version;
64 }
65
66 /**
67 * Sets the API version this dataset was created from.
68 *
69 * @param version the API version, i.e. "0.5" or "0.6"
70 */
71 public void setVersion(String version) {
72 this.version = version;
73 }
74
75 /**
76 * All nodes goes here, even when included in other data (ways etc). This enables the instant
77 * conversion of the whole DataSet by iterating over this data structure.
78 */
79 private QuadBuckets<Node> nodes = new QuadBuckets<Node>();
80
81 /**
82 * Replies an unmodifiable collection of nodes in this dataset
83 *
84 * @return an unmodifiable collection of nodes in this dataset
85 */
86 public Collection<Node> getNodes() {
87 return Collections.unmodifiableCollection(nodes);
88 }
89
90 public List<Node> searchNodes(BBox bbox) {
91 return nodes.search(bbox);
92 }
93
94 /**
95 * All ways (Streets etc.) in the DataSet.
96 *
97 * The way nodes are stored only in the way list.
98 */
99 private QuadBuckets<Way> ways = new QuadBuckets<Way>();
100
101 /**
102 * Replies an unmodifiable collection of ways in this dataset
103 *
104 * @return an unmodifiable collection of ways in this dataset
105 */
106 public Collection<Way> getWays() {
107 return Collections.unmodifiableCollection(ways);
108 }
109
110 public List<Way> searchWays(BBox bbox) {
111 return ways.search(bbox);
112 }
113
114 /**
115 * All relations/relationships
116 */
117 private Collection<Relation> relations = new LinkedList<Relation>();
118
119 /**
120 * Replies an unmodifiable collection of relations in this dataset
121 *
122 * @return an unmodifiable collection of relations in this dataset
123 */
124 public Collection<Relation> getRelations() {
125 return Collections.unmodifiableCollection(relations);
126 }
127
128 /**
129 * All data sources of this DataSet.
130 */
131 public Collection<DataSource> dataSources = new LinkedList<DataSource>();
132
133 /**
134 * @return A collection containing all primitives of the dataset. The data is ordered after:
135 * first come nodes, then ways, then relations. Ordering in between the categories is not
136 * guaranteed.
137 */
138 public List<OsmPrimitive> allPrimitives() {
139 List<OsmPrimitive> o = new LinkedList<OsmPrimitive>();
140 o.addAll(nodes);
141 o.addAll(ways);
142 o.addAll(relations);
143 return o;
144 }
145
146 /**
147 * @return A collection containing all not-deleted primitives (except keys).
148 */
149 public Collection<OsmPrimitive> allNonDeletedPrimitives() {
150 Collection<OsmPrimitive> o = new LinkedList<OsmPrimitive>();
151 for (OsmPrimitive osm : allPrimitives())
152 if (osm.isVisible() && !osm.isDeleted()) {
153 o.add(osm);
154 }
155 return o;
156 }
157
158 public Collection<OsmPrimitive> allNonDeletedCompletePrimitives() {
159 Collection<OsmPrimitive> o = new LinkedList<OsmPrimitive>();
160 for (OsmPrimitive osm : allPrimitives())
161 if (osm.isVisible() && !osm.isDeleted() && !osm.incomplete) {
162 o.add(osm);
163 }
164 return o;
165 }
166
167 public Collection<OsmPrimitive> allNonDeletedPhysicalPrimitives() {
168 Collection<OsmPrimitive> o = new LinkedList<OsmPrimitive>();
169 for (OsmPrimitive osm : allPrimitives())
170 if (osm.isVisible() && !osm.isDeleted() && !osm.incomplete && !(osm instanceof Relation)) {
171 o.add(osm);
172 }
173 return o;
174 }
175
176 /**
177 * Adds a primitive to the dataset
178 *
179 * @param primitive the primitive. Ignored if null.
180 */
181 public void addPrimitive(OsmPrimitive primitive) {
182 if (getPrimitiveById(primitive) != null)
183 throw new DataIntegrityProblemException(
184 tr("Unable to add primitive {0} to the dataset because it's already included", primitive.toString()));
185
186 if (primitive instanceof Node) {
187 nodes.add((Node) primitive);
188 } else if (primitive instanceof Way) {
189 ways.add((Way) primitive);
190 } else if (primitive instanceof Relation) {
191 relations.add((Relation) primitive);
192 }
193 allPrimitives.add(primitive);
194 primitive.setDataset(this);
195 firePrimitivesAdded(Collections.singletonList(primitive));
196 }
197
198 public OsmPrimitive addPrimitive(PrimitiveData data) {
199 OsmPrimitive result;
200 if (data instanceof NodeData) {
201 result = new Node();
202 } else if (data instanceof WayData) {
203 result = new Way();
204 } else if (data instanceof RelationData) {
205 result = new Relation();
206 } else
207 throw new AssertionError();
208 result.setDataset(this);
209 result.load(data);
210 addPrimitive(result);
211 return result;
212 }
213
214 /**
215 * Removes a primitive from the dataset. This method only removes the
216 * primitive form the respective collection of primitives managed
217 * by this dataset, i.e. from {@see #nodes}, {@see #ways}, or
218 * {@see #relations}. References from other primitives to this
219 * primitive are left unchanged.
220 *
221 * @param primitive the primitive
222 */
223 public void removePrimitive(PrimitiveId primitiveId) {
224 OsmPrimitive primitive = getPrimitiveByIdChecked(primitiveId);
225 if (primitive == null)
226 return;
227 if (primitive instanceof Node) {
228 nodes.remove(primitive);
229 } else if (primitive instanceof Way) {
230 ways.remove(primitive);
231 } else if (primitive instanceof Relation) {
232 relations.remove(primitive);
233 }
234 selectedPrimitives.remove(primitive);
235 allPrimitives.remove(primitive);
236 primitive.setDataset(null);
237 errors.remove(primitive);
238 firePrimitivesRemoved(Collections.singletonList(primitive));
239 }
240
241 /*---------------------------------------------------
242 * SELECTION HANDLING
243 *---------------------------------------------------*/
244
245 /**
246 * A list of listeners to selection changed events. The list is static, as listeners register
247 * themselves for any dataset selection changes that occur, regardless of the current active
248 * dataset. (However, the selection does only change in the active layer)
249 */
250 public static Collection<SelectionChangedListener> selListeners = new LinkedList<SelectionChangedListener>();
251
252 /**
253 * notifies all registered selection change listeners about the current selection of
254 * primitives
255 *
256 * @param sel the current selection
257 */
258 private static void notifySelectionChangeListeners(Collection<? extends OsmPrimitive> sel) {
259 for (SelectionChangedListener l : selListeners) {
260 l.selectionChanged(sel);
261 }
262 }
263
264 /**
265 * Notifies all registered {@see SelectionChangedListener} about the current selection in
266 * this dataset.
267 *
268 */
269 public void fireSelectionChanged(){
270 notifySelectionChangeListeners(selectedPrimitives);
271 }
272
273 LinkedHashSet<OsmPrimitive> selectedPrimitives = new LinkedHashSet<OsmPrimitive>();
274
275 public Collection<OsmPrimitive> getSelectedNodesAndWays() {
276 Collection<OsmPrimitive> sel = new LinkedList<OsmPrimitive>();
277 for (OsmPrimitive osm : selectedPrimitives) {
278 if (osm instanceof Way ||
279 osm instanceof Node) {
280 sel.add(osm);
281 }
282 }
283 return sel;
284 }
285
286 /**
287 * Return a list of all selected objects. Even keys are returned.
288 * @return List of all selected objects.
289 */
290 public Collection<OsmPrimitive> getSelected() {
291 // It would be nice to have this be a copy-on-write list
292 // or an Collections.unmodifiableList(). It would be
293 // much faster for large selections. May users just
294 // call this, and only check the .size().
295 return new ArrayList<OsmPrimitive>(selectedPrimitives);
296 }
297
298 /**
299 * Return selected nodes.
300 */
301 public Collection<OsmPrimitive> getSelectedNodes() {
302 return getSelected(nodes);
303 }
304
305 /**
306 * Return selected ways.
307 */
308 public Collection<OsmPrimitive> getSelectedWays() {
309 return getSelected(ways);
310 }
311
312 /**
313 * Return selected relations.
314 */
315 public Collection<OsmPrimitive> getSelectedRelations() {
316 return getSelected(relations);
317 }
318
319 /**
320 * Return all selected items in the collection.
321 * @param list The collection from which the selected items are returned.
322 */
323 private Collection<OsmPrimitive> getSelected(Collection<? extends OsmPrimitive> list) {
324 if (list == null)
325 return new LinkedList<OsmPrimitive>();
326 // getSelected() is called with large lists, so
327 // creating the return list from the selection
328 // should be faster most of the time.
329 Collection<OsmPrimitive> sel = new LinkedHashSet<OsmPrimitive>(selectedPrimitives);
330 sel.retainAll(list);
331 return sel;
332 }
333
334 public boolean isSelected(OsmPrimitive osm) {
335 return selectedPrimitives.contains(osm);
336 }
337
338 public void toggleSelected(Collection<? extends PrimitiveId> osm) {
339 boolean changed = false;
340 for (PrimitiveId o : osm) {
341 changed = changed | this.__toggleSelected(o);
342 }
343 if (changed) {
344 fireSelectionChanged();
345 }
346 }
347 public void toggleSelected(PrimitiveId... osm) {
348 toggleSelected(Arrays.asList(osm));
349 }
350 private boolean __toggleSelected(PrimitiveId primitiveId) {
351 OsmPrimitive primitive = getPrimitiveByIdChecked(primitiveId);
352 if (primitive == null)
353 return false;
354 if (!selectedPrimitives.remove(primitive)) {
355 selectedPrimitives.add(primitive);
356 }
357 return true;
358 }
359
360 /**
361 * Sets the current selection to the primitives in <code>selection</code>.
362 * Notifies all {@see SelectionChangedListener} if <code>fireSelectionChangeEvent</code> is true.
363 *
364 * @param selection the selection
365 * @param fireSelectionChangeEvent true, if the selection change listeners are to be notified; false, otherwise
366 */
367 public void setSelected(Collection<? extends PrimitiveId> selection, boolean fireSelectionChangeEvent) {
368 boolean wasEmpty = selectedPrimitives.isEmpty();
369 selectedPrimitives = new LinkedHashSet<OsmPrimitive>();
370 addSelected(selection, fireSelectionChangeEvent);
371 if (!wasEmpty && selectedPrimitives.isEmpty() && fireSelectionChangeEvent) {
372 fireSelectionChanged();
373 }
374 }
375
376 /**
377 * Sets the current selection to the primitives in <code>selection</code>
378 * and notifies all {@see SelectionChangedListener}.
379 *
380 * @param selection the selection
381 */
382 public void setSelected(Collection<? extends PrimitiveId> selection) {
383 setSelected(selection, true /* fire selection change event */);
384 }
385
386 public void setSelected(PrimitiveId... osm) {
387 if (osm.length == 1 && osm[0] == null) {
388 setSelected();
389 return;
390 }
391 List<PrimitiveId> list = Arrays.asList(osm);
392 setSelected(list);
393 }
394
395 /**
396 * Adds the primitives in <code>selection</code> to the current selection
397 * and notifies all {@see SelectionChangedListener}.
398 *
399 * @param selection the selection
400 */
401 public void addSelected(Collection<? extends PrimitiveId> selection) {
402 addSelected(selection, true /* fire selection change event */);
403 }
404
405 public void addSelected(PrimitiveId... osm) {
406 addSelected(Arrays.asList(osm));
407 }
408
409 /**
410 * Adds the primitives in <code>selection</code> to the current selection.
411 * Notifies all {@see SelectionChangedListener} if <code>fireSelectionChangeEvent</code> is true.
412 *
413 * @param selection the selection
414 * @param fireSelectionChangeEvent true, if the selection change listeners are to be notified; false, otherwise
415 */
416 public void addSelected(Collection<? extends PrimitiveId> selection, boolean fireSelectionChangeEvent) {
417 boolean changed = false;
418 for (PrimitiveId id: selection) {
419 OsmPrimitive primitive = getPrimitiveByIdChecked(id);
420 if (primitive != null) {
421 changed = changed | selectedPrimitives.add(primitive);
422 }
423 }
424 if (fireSelectionChangeEvent && changed) {
425 fireSelectionChanged();
426 }
427 }
428
429 /**
430 * Remove the selection from every value in the collection.
431 * @param list The collection to remove the selection from.
432 */
433 public void clearSelection(PrimitiveId... osm) {
434 clearSelection(Arrays.asList(osm));
435 }
436 public void clearSelection(Collection<? extends PrimitiveId> list) {
437 boolean changed = false;
438 for (PrimitiveId id:list) {
439 OsmPrimitive primitive = getPrimitiveById(id);
440 if (primitive != null) {
441 changed = changed | selectedPrimitives.remove(primitive);
442 }
443 }
444 if (changed) {
445 fireSelectionChanged();
446 }
447 }
448 public void clearSelection() {
449 if (!selectedPrimitives.isEmpty()) {
450 selectedPrimitives.clear();
451 fireSelectionChanged();
452 }
453 }
454
455 /*------------------------------------------------------
456 * FILTERED / DISABLED HANDLING
457 *-----------------------------------------------------*/
458
459 public void setDisabled(OsmPrimitive... osm) {
460 if (osm.length == 1 && osm[0] == null) {
461 setDisabled();
462 return;
463 }
464 clearDisabled(nodes);
465 clearDisabled(ways);
466 clearDisabled(relations);
467 for (OsmPrimitive o : osm)
468 if (o != null) {
469 o.setDisabled(true);
470 }
471 }
472
473 public void setFiltered(Collection<? extends OsmPrimitive> selection) {
474 clearFiltered(nodes);
475 clearFiltered(ways);
476 clearFiltered(relations);
477 for (OsmPrimitive osm : selection) {
478 osm.setFiltered(true);
479 }
480 }
481
482 public void setFiltered(OsmPrimitive... osm) {
483 if (osm.length == 1 && osm[0] == null) {
484 setFiltered();
485 return;
486 }
487 clearFiltered(nodes);
488 clearFiltered(ways);
489 clearFiltered(relations);
490 for (OsmPrimitive o : osm)
491 if (o != null) {
492 o.setFiltered(true);
493 }
494 }
495
496 public void setDisabled(Collection<? extends OsmPrimitive> selection) {
497 clearDisabled(nodes);
498 clearDisabled(ways);
499 clearDisabled(relations);
500 for (OsmPrimitive osm : selection) {
501 osm.setDisabled(true);
502 }
503 }
504
505 /**
506 * Remove the filtered parameter from every value in the collection.
507 * @param list The collection to remove the filtered parameter from.
508 */
509 private void clearFiltered(Collection<? extends OsmPrimitive> list) {
510 if (list == null)
511 return;
512 for (OsmPrimitive osm : list) {
513 osm.setFiltered(false);
514 }
515 }
516 /**
517 * Remove the disabled parameter from every value in the collection.
518 * @param list The collection to remove the disabled parameter from.
519 */
520 private void clearDisabled(Collection<? extends OsmPrimitive> list) {
521 if (list == null)
522 return;
523 for (OsmPrimitive osm : list) {
524 osm.setDisabled(false);
525 }
526 }
527
528 @Override public DataSet clone() {
529 DataSet ds = new DataSet();
530 for (Node n : nodes) {
531 ds.addPrimitive(new Node(n));
532 }
533 for (Way w : ways) {
534 ds.addPrimitive(new Way(w));
535 }
536 for (Relation e : relations) {
537 ds.addPrimitive(new Relation(e));
538 }
539 for (DataSource source : dataSources) {
540 ds.dataSources.add(new DataSource(source.bounds, source.origin));
541 }
542 ds.version = version;
543 return ds;
544 }
545
546 /**
547 * Returns the total area of downloaded data (the "yellow rectangles").
548 * @return Area object encompassing downloaded data.
549 */
550 public Area getDataSourceArea() {
551 if (dataSources.isEmpty()) return null;
552 Area a = new Area();
553 for (DataSource source : dataSources) {
554 // create area from data bounds
555 a.add(new Area(source.bounds.asRect()));
556 }
557 return a;
558 }
559
560 // Provide well-defined sorting for collections of OsmPrimitives.
561 // FIXME: probably not a good place to put this code.
562 public static OsmPrimitive[] sort(Collection<? extends OsmPrimitive> list) {
563 OsmPrimitive[] selArr = new OsmPrimitive[list.size()];
564 final HashMap<Object, String> h = new HashMap<Object, String>();
565 selArr = list.toArray(selArr);
566 Arrays.sort(selArr, new Comparator<OsmPrimitive>() {
567 public int compare(OsmPrimitive a, OsmPrimitive b) {
568 if (a.getClass() == b.getClass()) {
569 String as = h.get(a);
570 if (as == null) {
571 as = a.getName() != null ? a.getName() : Long.toString(a.getId());
572 h.put(a, as);
573 }
574 String bs = h.get(b);
575 if (bs == null) {
576 bs = b.getName() != null ? b.getName() : Long.toString(b.getId());
577 h.put(b, bs);
578 }
579 int res = as.compareTo(bs);
580 if (res != 0)
581 return res;
582 }
583 return a.compareTo(b);
584 }
585 });
586 return selArr;
587 }
588
589 /**
590 * returns a primitive with a given id from the data set. null, if no such primitive
591 * exists
592 *
593 * @param id uniqueId of the primitive. Might be < 0 for newly created primitives
594 * @param type the type of the primitive. Must not be null.
595 * @return the primitive
596 * @exception NullPointerException thrown, if type is null
597 */
598 public OsmPrimitive getPrimitiveById(long id, OsmPrimitiveType type) {
599 return getPrimitiveById(new SimplePrimitiveId(id, type), false);
600 }
601
602 public OsmPrimitive getPrimitiveById(PrimitiveId primitiveId) {
603 return getPrimitiveById(primitiveId, false);
604 }
605
606 public OsmPrimitive getPrimitiveById(PrimitiveId primitiveId, boolean createNew) {
607 OsmPrimitive result = primitivesMap.get(primitiveId);
608
609 if (result == null && createNew) {
610 switch (primitiveId.getType()) {
611 case NODE: result = new Node(primitiveId.getUniqueId(), true); break;
612 case WAY: result = new Way(primitiveId.getUniqueId(), true); break;
613 case RELATION: result = new Relation(primitiveId.getUniqueId(), true); break;
614 }
615 addPrimitive(result);
616 }
617
618 return result;
619 }
620
621 /**
622 * Show message and stack trace in log in case primitive is not found
623 * @param primitiveId
624 * @return Primitive by id.
625 */
626 private OsmPrimitive getPrimitiveByIdChecked(PrimitiveId primitiveId) {
627 OsmPrimitive result = getPrimitiveById(primitiveId);
628 if (result == null) {
629 System.out.println(tr("JOSM expected to find primitive [{0} {1}] in dataset but it's not there. Please report this "
630 + " at http://josm.openstreetmap.de . This is not a critical error, it should be safe to continue in your work.",
631 primitiveId.getType(), Long.toString(primitiveId.getUniqueId())));
632 new Exception().printStackTrace();
633 }
634
635 return result;
636 }
637
638 public Set<Long> getPrimitiveIds() {
639 HashSet<Long> ret = new HashSet<Long>();
640 for (OsmPrimitive primitive : nodes) {
641 ret.add(primitive.getId());
642 }
643 for (OsmPrimitive primitive : ways) {
644 ret.add(primitive.getId());
645 }
646 for (OsmPrimitive primitive : relations) {
647 ret.add(primitive.getId());
648 }
649 return ret;
650 }
651
652 protected void deleteWay(Way way) {
653 way.setNodes(null);
654 way.setDeleted(true);
655 }
656
657 /**
658 * removes all references from ways in this dataset to a particular node
659 *
660 * @param node the node
661 */
662 public void unlinkNodeFromWays(Node node) {
663 for (Way way: ways) {
664 List<Node> nodes = way.getNodes();
665 if (nodes.remove(node)) {
666 if (nodes.size() < 2) {
667 deleteWay(way);
668 } else {
669 way.setNodes(nodes);
670 }
671 }
672 }
673 }
674
675 /**
676 * removes all references from relations in this dataset to this primitive
677 *
678 * @param primitive the primitive
679 */
680 public void unlinkPrimitiveFromRelations(OsmPrimitive primitive) {
681 for (Relation relation : relations) {
682 Iterator<RelationMember> it = relation.getMembers().iterator();
683 while(it.hasNext()) {
684 RelationMember member = it.next();
685 if (member.getMember().equals(primitive)) {
686 it.remove();
687 }
688 }
689 }
690 }
691
692 /**
693 * removes all references from from other primitives to the
694 * referenced primitive
695 *
696 * @param referencedPrimitive the referenced primitive
697 */
698 public void unlinkReferencesToPrimitive(OsmPrimitive referencedPrimitive) {
699 if (referencedPrimitive instanceof Node) {
700 unlinkNodeFromWays((Node)referencedPrimitive);
701 unlinkPrimitiveFromRelations(referencedPrimitive);
702 } else {
703 unlinkPrimitiveFromRelations(referencedPrimitive);
704 }
705 }
706
707 /**
708 * Replies a list of parent relations which refer to the relation
709 * <code>child</code>. Replies an empty list if child is null.
710 *
711 * @param child the child relation
712 * @return a list of parent relations which refer to the relation
713 * <code>child</code>
714 */
715 public List<Relation> getParentRelations(Relation child) {
716 ArrayList<Relation> parents = new ArrayList<Relation>();
717 if (child == null)
718 return parents;
719 for (Relation parent : relations) {
720 if (parent == child) {
721 continue;
722 }
723 for (RelationMember member: parent.getMembers()) {
724 if (member.refersTo(child)) {
725 parents.add(parent);
726 break;
727 }
728 }
729 }
730 return parents;
731 }
732
733 /**
734 * Replies true if there is at least one primitive in this dataset with
735 * {@see OsmPrimitive#isModified()} == <code>true</code>.
736 *
737 * @return true if there is at least one primitive in this dataset with
738 * {@see OsmPrimitive#isModified()} == <code>true</code>.
739 */
740 public boolean isModified() {
741 for (Node n: nodes) {
742 if (n.isModified()) return true;
743 }
744 for (Way w: ways) {
745 if (w.isModified()) return true;
746 }
747 for (Relation r: relations) {
748 if (r.isModified()) return true;
749 }
750 return false;
751 }
752
753 /**
754 * Reindex all nodes and ways after their coordinates were changed. This is a temporary solution, reindexing should
755 * be automatic in the future
756 * @deprecated Reindexing should be automatic
757 */
758 @Deprecated
759 public void reindexAll() {
760 List<Node> ntmp = new ArrayList<Node>(nodes);
761 nodes.clear();
762 nodes.addAll(ntmp);
763 List<Way> wtmp = new ArrayList<Way>(ways);
764 ways.clear();
765 ways.addAll(wtmp);
766 }
767
768 private void reindexNode(Node node) {
769 nodes.remove(node);
770 nodes.add(node);
771 for (Way way:OsmPrimitive.getFilteredList(node.getReferrers(), Way.class)) {
772 ways.remove(way);
773 way.updatePosition();
774 ways.add(way);
775 }
776 }
777
778 private void reindexWay(Way way) {
779 ways.remove(way);
780 way.updatePosition();
781 ways.add(way);
782 }
783
784 public void addDataSetListener(DataSetListener dsl) {
785 listeners.add(dsl);
786 }
787
788 public void removeDataSetListener(DataSetListener dsl) {
789 listeners.remove(dsl);
790 }
791
792 /**
793 * Can be called before bigger changes on dataset. Events are disabled until {@link #endUpdate()}.
794 * {@link DataSetListener#dataChanged()} event is triggered after end of changes
795 * <br>
796 * Typical usecase should look like this:
797 * <pre>
798 * ds.beginUpdate();
799 * try {
800 * ...
801 * } finally {
802 * ds.endUpdate();
803 * }
804 * </pre>
805 */
806 public void beginUpdate() {
807 updateCount++;
808 }
809
810 /**
811 * @see DataSet#beginUpdate()
812 */
813 public void endUpdate() {
814 if (updateCount > 0) {
815 updateCount--;
816 if (updateCount == 0) {
817 fireDataChanged();
818 }
819 } else
820 throw new AssertionError("endUpdate called without beginUpdate");
821 }
822
823 private void fireDataChanged() {
824 if (updateCount == 0) {
825 for (DataSetListener dsl : listeners) {
826 dsl.dataChanged();
827 }
828 }
829 }
830
831 void firePrimitivesAdded(Collection<? extends OsmPrimitive> added) {
832 if (updateCount == 0) {
833 for (DataSetListener dsl : listeners) {
834 dsl.primtivesAdded(added);
835 }
836 }
837 }
838
839 void firePrimitivesRemoved(Collection<? extends OsmPrimitive> removed) {
840 if (updateCount == 0) {
841 for (DataSetListener dsl : listeners) {
842 dsl.primtivesRemoved(removed);
843 }
844 }
845 }
846
847 void fireTagsChanged(OsmPrimitive prim) {
848 if (updateCount == 0) {
849 for (DataSetListener dsl : listeners) {
850 dsl.tagsChanged(prim);
851 }
852 }
853 }
854
855 void fireRelationMembersChanged(Relation r) {
856 if (updateCount == 0) {
857 for (DataSetListener dsl : listeners) {
858 dsl.relationMembersChanged(r);
859 }
860 }
861 }
862
863 void fireNodeMoved(Node node) {
864 reindexNode(node);
865 if (updateCount == 0) {
866 for (DataSetListener dsl : listeners) {
867 dsl.nodeMoved(node);
868 }
869 }
870 }
871
872 void fireWayNodesChanged(Way way) {
873 reindexWay(way);
874 if (updateCount == 0) {
875 for (DataSetListener dsl : listeners) {
876 dsl.wayNodesChanged(way);
877 }
878 }
879 }
880
881 public void clenupDeletedPrimitives() {
882 if (cleanupDeleted(nodes.iterator())
883 | cleanupDeleted(ways.iterator())
884 | cleanupDeleted(relations.iterator())) {
885 fireSelectionChanged();
886 }
887 }
888
889 private boolean cleanupDeleted(Iterator<? extends OsmPrimitive> it) {
890 boolean changed = false;
891 while (it.hasNext()) {
892 OsmPrimitive primitive = it.next();
893 if (primitive.isDeleted()) {
894 selectedPrimitives.remove(primitive);
895 allPrimitives.remove(primitive);
896 primitive.setDataset(null);
897 changed = true;
898 it.remove();
899 }
900 }
901 return changed;
902 }
903
904 /**
905 * Removes all primitives from the dataset and resets the currently selected primitives
906 * to the empty collection. Also notifies selection change listeners if necessary.
907 *
908 */
909 public void clear() {
910 clearSelection();
911 for (OsmPrimitive primitive:allPrimitives) {
912 primitive.setDataset(null);
913 }
914 nodes.clear();
915 ways.clear();
916 relations.clear();
917 allPrimitives.clear();
918 }
919
920 // TODO Should be completely part of validator
921 private Map<OsmPrimitive, List<String>> errors = new HashMap<OsmPrimitive, List<String>>();
922
923 public void addError(OsmPrimitive primitive, String error) {
924 List<String> perrors = errors.get(primitive);
925 if (perrors == null) {
926 perrors = new ArrayList<String>();
927 }
928 perrors.add(error);
929 errors.put(primitive, perrors);
930 }
931
932 /**
933 * Replies the list of errors registered for this primitive.
934 *
935 * @param primitive the primitive for which errors are queried
936 * @return the list of errors. Never null.
937 * @deprecated should be moved to the validator plugin
938 */
939 @Deprecated
940 public List<String> getErrors(OsmPrimitive primitive) {
941 List<String> ret = errors.get(primitive);
942 if (ret == null) {
943 ret = Collections.emptyList();
944 }
945 return ret;
946 }
947
948 public void clearErrors()
949 {
950 errors.clear();
951 }
952}
Note: See TracBrowser for help on using the repository browser.