source: josm/trunk/src/org/openstreetmap/josm/command/Command.java@ 3034

Last change on this file since 3034 was 3034, checked in by jttt, 14 years ago

Fix #4467 Don't silently drop locally deleted member primitives from downloaded ways and relation (fix the issue when deleted primitive is referenced)

  • Property svn:eol-style set to native
File size: 5.0 KB
Line 
1//License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.command;
3
4import java.util.ArrayList;
5import java.util.Collection;
6import java.util.HashMap;
7import java.util.LinkedHashMap;
8import java.util.Map;
9import java.util.Map.Entry;
10
11import javax.swing.tree.MutableTreeNode;
12
13import org.openstreetmap.josm.Main;
14import org.openstreetmap.josm.data.osm.Node;
15import org.openstreetmap.josm.data.osm.OsmPrimitive;
16import org.openstreetmap.josm.data.osm.PrimitiveData;
17import org.openstreetmap.josm.data.osm.Relation;
18import org.openstreetmap.josm.data.osm.Way;
19import org.openstreetmap.josm.data.osm.visitor.AbstractVisitor;
20import org.openstreetmap.josm.gui.layer.Layer;
21import org.openstreetmap.josm.gui.layer.OsmDataLayer;
22import org.openstreetmap.josm.tools.CheckParameterUtil;
23
24/**
25 * Classes implementing Command modify a dataset in a specific way. A command is
26 * one atomic action on a specific dataset, such as move or delete.
27 *
28 * The command remembers the {@see OsmDataLayer} it is operating on.
29 *
30 * @author imi
31 */
32abstract public class Command {
33
34 private static final class CloneVisitor extends AbstractVisitor {
35 public final Map<OsmPrimitive, PrimitiveData> orig = new LinkedHashMap<OsmPrimitive, PrimitiveData>();
36
37 public void visit(Node n) {
38 orig.put(n, n.save());
39 }
40 public void visit(Way w) {
41 orig.put(w, w.save());
42 }
43 public void visit(Relation e) {
44 orig.put(e, e.save());
45 }
46 }
47
48 /** the map of OsmPrimitives in the original state to OsmPrimitives in cloned state */
49 private Map<OsmPrimitive, PrimitiveData> cloneMap = new HashMap<OsmPrimitive, PrimitiveData>();
50
51 /** the layer which this command is applied to */
52 private OsmDataLayer layer;
53
54 public Command() {
55 this.layer = Main.map.mapView.getEditLayer();
56 }
57
58 /**
59 * Creates a new command in the context of a specific data layer
60 *
61 * @param layer the data layer. Must not be null.
62 * @throws IllegalArgumentException thrown if layer is null
63 */
64 public Command(OsmDataLayer layer) throws IllegalArgumentException {
65 CheckParameterUtil.ensureParameterNotNull(layer, "layer");
66 this.layer = layer;
67 }
68
69 /**
70 * Executes the command on the dataset. This implementation will remember all
71 * primitives returned by fillModifiedData for restoring them on undo.
72 */
73 public boolean executeCommand() {
74 CloneVisitor visitor = new CloneVisitor();
75 Collection<OsmPrimitive> all = new ArrayList<OsmPrimitive>();
76 fillModifiedData(all, all, all);
77 for (OsmPrimitive osm : all) {
78 osm.visit(visitor);
79 }
80 cloneMap = visitor.orig;
81 return true;
82 }
83
84 /**
85 * Undoes the command.
86 * It can be assumed that all objects are in the same state they were before.
87 * It can also be assumed that executeCommand was called exactly once before.
88 *
89 * This implementation undoes all objects stored by a former call to executeCommand.
90 */
91 public void undoCommand() {
92 for (Entry<OsmPrimitive, PrimitiveData> e : cloneMap.entrySet()) {
93 OsmPrimitive primitive = e.getKey();
94 if (primitive.getDataSet() != null) {
95 e.getKey().load(e.getValue());
96 }
97 }
98 }
99
100 /**
101 * Called when a layer has been removed to have the command remove itself from
102 * any buffer if it is not longer applicable to the dataset (e.g. it was part of
103 * the removed layer)
104 *
105 * @param oldLayer the old layer
106 * @return true if this command
107 */
108 public boolean invalidBecauselayerRemoved(Layer oldLayer) {
109 if (!(oldLayer instanceof OsmDataLayer))
110 return false;
111 return layer == oldLayer;
112 }
113
114 /**
115 * Lets other commands access the original version
116 * of the object. Usually for undoing.
117 */
118 public PrimitiveData getOrig(OsmPrimitive osm) {
119 PrimitiveData o = cloneMap.get(osm);
120 if (o != null)
121 return o;
122 Main.debug("unable to find osm with id: " + osm.getId() + " hashCode: " + osm.hashCode());
123 for (OsmPrimitive t : cloneMap.keySet()) {
124 PrimitiveData to = cloneMap.get(t);
125 Main.debug("now: " + t.getId() + " hashCode: " + t.hashCode());
126 Main.debug("orig: " + to.getUniqueId() + " hashCode: " + to.hashCode());
127 }
128 return o;
129 }
130
131 /**
132 * Replies the layer this command is (or was) applied to.
133 *
134 * @return
135 */
136 protected OsmDataLayer getLayer() {
137 return layer;
138 }
139
140 /**
141 * Fill in the changed data this command operates on.
142 * Add to the lists, don't clear them.
143 *
144 * @param modified The modified primitives
145 * @param deleted The deleted primitives
146 * @param added The added primitives
147 */
148 abstract public void fillModifiedData(Collection<OsmPrimitive> modified,
149 Collection<OsmPrimitive> deleted,
150 Collection<OsmPrimitive> added);
151
152 abstract public MutableTreeNode description();
153
154}
Note: See TracBrowser for help on using the repository browser.