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

Last change on this file since 7294 was 7005, checked in by Don-vip, 10 years ago

see #8465 - use diamond operator where applicable

  • Property svn:eol-style set to native
File size: 8.4 KB
Line 
1//License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.command;
3
4import java.awt.GridBagLayout;
5import java.util.ArrayList;
6import java.util.Collection;
7import java.util.HashMap;
8import java.util.LinkedHashMap;
9import java.util.Map;
10import java.util.Map.Entry;
11
12import javax.swing.JOptionPane;
13import javax.swing.JPanel;
14
15import org.openstreetmap.josm.Main;
16import org.openstreetmap.josm.data.coor.EastNorth;
17import org.openstreetmap.josm.data.coor.LatLon;
18import org.openstreetmap.josm.data.osm.Node;
19import org.openstreetmap.josm.data.osm.OsmPrimitive;
20import org.openstreetmap.josm.data.osm.PrimitiveData;
21import org.openstreetmap.josm.data.osm.Relation;
22import org.openstreetmap.josm.data.osm.Way;
23import org.openstreetmap.josm.data.osm.visitor.AbstractVisitor;
24import org.openstreetmap.josm.gui.ConditionalOptionPaneUtil;
25import org.openstreetmap.josm.gui.layer.Layer;
26import org.openstreetmap.josm.gui.layer.OsmDataLayer;
27import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
28import org.openstreetmap.josm.tools.CheckParameterUtil;
29
30/**
31 * Classes implementing Command modify a dataset in a specific way. A command is
32 * one atomic action on a specific dataset, such as move or delete.
33 *
34 * The command remembers the {@link OsmDataLayer} it is operating on.
35 *
36 * @author imi
37 */
38public abstract class Command extends PseudoCommand {
39
40 private static final class CloneVisitor extends AbstractVisitor {
41 public final Map<OsmPrimitive, PrimitiveData> orig = new LinkedHashMap<>();
42
43 @Override
44 public void visit(Node n) {
45 orig.put(n, n.save());
46 }
47 @Override
48 public void visit(Way w) {
49 orig.put(w, w.save());
50 }
51 @Override
52 public void visit(Relation e) {
53 orig.put(e, e.save());
54 }
55 }
56
57 /**
58 * Small helper for holding the interesting part of the old data state of the objects.
59 */
60 public static class OldNodeState {
61
62 final LatLon latlon;
63 final EastNorth eastNorth; // cached EastNorth to be used for applying exact displacement
64 final boolean modified;
65
66 /**
67 * Constructs a new {@code OldNodeState} for the given node.
68 * @param node The node whose state has to be remembered
69 */
70 public OldNodeState(Node node){
71 latlon = node.getCoor();
72 eastNorth = node.getEastNorth();
73 modified = node.isModified();
74 }
75 }
76
77 /** the map of OsmPrimitives in the original state to OsmPrimitives in cloned state */
78 private Map<OsmPrimitive, PrimitiveData> cloneMap = new HashMap<>();
79
80 /** the layer which this command is applied to */
81 private final OsmDataLayer layer;
82
83 /**
84 * Creates a new command in the context of the current edit layer, if any
85 */
86 public Command() {
87 this.layer = Main.main == null ? null : Main.main.getEditLayer();
88 }
89
90 /**
91 * Creates a new command in the context of a specific data layer
92 *
93 * @param layer the data layer. Must not be null.
94 * @throws IllegalArgumentException thrown if layer is null
95 */
96 public Command(OsmDataLayer layer) throws IllegalArgumentException {
97 CheckParameterUtil.ensureParameterNotNull(layer, "layer");
98 this.layer = layer;
99 }
100
101 /**
102 * Executes the command on the dataset. This implementation will remember all
103 * primitives returned by fillModifiedData for restoring them on undo.
104 * @return true
105 */
106 public boolean executeCommand() {
107 CloneVisitor visitor = new CloneVisitor();
108 Collection<OsmPrimitive> all = new ArrayList<>();
109 fillModifiedData(all, all, all);
110 for (OsmPrimitive osm : all) {
111 osm.accept(visitor);
112 }
113 cloneMap = visitor.orig;
114 return true;
115 }
116
117 /**
118 * Undoes the command.
119 * It can be assumed that all objects are in the same state they were before.
120 * It can also be assumed that executeCommand was called exactly once before.
121 *
122 * This implementation undoes all objects stored by a former call to executeCommand.
123 */
124 public void undoCommand() {
125 for (Entry<OsmPrimitive, PrimitiveData> e : cloneMap.entrySet()) {
126 OsmPrimitive primitive = e.getKey();
127 if (primitive.getDataSet() != null) {
128 e.getKey().load(e.getValue());
129 }
130 }
131 }
132
133 /**
134 * Called when a layer has been removed to have the command remove itself from
135 * any buffer if it is not longer applicable to the dataset (e.g. it was part of
136 * the removed layer)
137 *
138 * @param oldLayer the old layer
139 * @return true if this command
140 */
141 public boolean invalidBecauselayerRemoved(Layer oldLayer) {
142 if (!(oldLayer instanceof OsmDataLayer))
143 return false;
144 return layer == oldLayer;
145 }
146
147 /**
148 * Lets other commands access the original version
149 * of the object. Usually for undoing.
150 * @param osm The requested OSM object
151 * @return The original version of the requested object, if any
152 */
153 public PrimitiveData getOrig(OsmPrimitive osm) {
154 return cloneMap.get(osm);
155 }
156
157 /**
158 * Replies the layer this command is (or was) applied to.
159 *
160 */
161 protected OsmDataLayer getLayer() {
162 return layer;
163 }
164
165 /**
166 * Fill in the changed data this command operates on.
167 * Add to the lists, don't clear them.
168 *
169 * @param modified The modified primitives
170 * @param deleted The deleted primitives
171 * @param added The added primitives
172 */
173 public abstract void fillModifiedData(Collection<OsmPrimitive> modified,
174 Collection<OsmPrimitive> deleted,
175 Collection<OsmPrimitive> added);
176
177 /**
178 * Return the primitives that take part in this command.
179 */
180 @Override public Collection<? extends OsmPrimitive> getParticipatingPrimitives() {
181 return cloneMap.keySet();
182 }
183
184 /**
185 * Check whether user is about to operate on data outside of the download area.
186 * Request confirmation if he is.
187 *
188 * @param operation the operation name which is used for setting some preferences
189 * @param dialogTitle the title of the dialog being displayed
190 * @param outsideDialogMessage the message text to be displayed when data is outside of the download area
191 * @param incompleteDialogMessage the message text to be displayed when data is incomplete
192 * @param primitives the primitives to operate on
193 * @param ignore {@code null} or a primitive to be ignored
194 * @return true, if operating on outlying primitives is OK; false, otherwise
195 */
196 public static boolean checkAndConfirmOutlyingOperation(String operation,
197 String dialogTitle, String outsideDialogMessage, String incompleteDialogMessage,
198 Collection<? extends OsmPrimitive> primitives,
199 Collection<? extends OsmPrimitive> ignore) {
200 boolean outside = false;
201 boolean incomplete = false;
202 for (OsmPrimitive osm : primitives) {
203 if (osm.isIncomplete()) {
204 incomplete = true;
205 } else if (osm.isOutsideDownloadArea()
206 && (ignore == null || !ignore.contains(osm))) {
207 outside = true;
208 }
209 }
210 if (outside) {
211 JPanel msg = new JPanel(new GridBagLayout());
212 msg.add(new JMultilineLabel("<html>" + outsideDialogMessage + "</html>"));
213 boolean answer = ConditionalOptionPaneUtil.showConfirmationDialog(
214 operation + "_outside_nodes",
215 Main.parent,
216 msg,
217 dialogTitle,
218 JOptionPane.YES_NO_OPTION,
219 JOptionPane.QUESTION_MESSAGE,
220 JOptionPane.YES_OPTION);
221 if(!answer)
222 return false;
223 }
224 if (incomplete) {
225 JPanel msg = new JPanel(new GridBagLayout());
226 msg.add(new JMultilineLabel("<html>" + incompleteDialogMessage + "</html>"));
227 boolean answer = ConditionalOptionPaneUtil.showConfirmationDialog(
228 operation + "_incomplete",
229 Main.parent,
230 msg,
231 dialogTitle,
232 JOptionPane.YES_NO_OPTION,
233 JOptionPane.QUESTION_MESSAGE,
234 JOptionPane.YES_OPTION);
235 if(!answer)
236 return false;
237 }
238 return true;
239 }
240
241}
Note: See TracBrowser for help on using the repository browser.