source: josm/trunk/src/org/openstreetmap/josm/data/UndoRedoHandler.java@ 7206

Last change on this file since 7206 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: 6.0 KB
Line 
1//License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data;
3
4import java.util.Collection;
5import java.util.Iterator;
6import java.util.LinkedList;
7
8import org.openstreetmap.josm.Main;
9import org.openstreetmap.josm.command.Command;
10import org.openstreetmap.josm.data.osm.DataSet;
11import org.openstreetmap.josm.data.osm.OsmPrimitive;
12import org.openstreetmap.josm.gui.MapView;
13import org.openstreetmap.josm.gui.layer.Layer;
14import org.openstreetmap.josm.gui.layer.OsmDataLayer.CommandQueueListener;
15import org.openstreetmap.josm.tools.CheckParameterUtil;
16
17public class UndoRedoHandler implements MapView.LayerChangeListener {
18
19 /**
20 * All commands that were made on the dataset. Don't write from outside!
21 */
22 public final LinkedList<Command> commands = new LinkedList<>();
23 /**
24 * The stack for redoing commands
25 */
26 public final LinkedList<Command> redoCommands = new LinkedList<>();
27
28 private final LinkedList<CommandQueueListener> listenerCommands = new LinkedList<>();
29
30 /**
31 * Constructs a new {@code UndoRedoHandler}.
32 */
33 public UndoRedoHandler() {
34 MapView.addLayerChangeListener(this);
35 }
36
37 /**
38 * Executes the command and add it to the intern command queue.
39 * @param c The command to execute. Must not be {@code null}.
40 */
41 public void addNoRedraw(final Command c) {
42 CheckParameterUtil.ensureParameterNotNull(c, "c");
43 c.executeCommand();
44 commands.add(c);
45 // Limit the number of commands in the undo list.
46 // Currently you have to undo the commands one by one. If
47 // this changes, a higher default value may be reasonable.
48 if (commands.size() > Main.pref.getInteger("undo.max", 1000)) {
49 commands.removeFirst();
50 }
51 redoCommands.clear();
52 }
53
54 public void afterAdd() {
55 fireCommandsChanged();
56
57 // the command may have changed the selection so tell the listeners about the current situation
58 DataSet ds = Main.main.getCurrentDataSet();
59 if (ds != null) {
60 ds.fireSelectionChanged();
61 }
62 }
63
64 /**
65 * Executes the command and add it to the intern command queue.
66 * @param c The command to execute. Must not be {@code null}.
67 */
68 public synchronized void add(final Command c) {
69 addNoRedraw(c);
70 afterAdd();
71 }
72
73 /**
74 * Undoes the last added command.
75 */
76 public void undo() {
77 undo(1);
78 }
79
80 /**
81 * Undoes multiple commands.
82 * @param num The number of commands to undo
83 */
84 public synchronized void undo(int num) {
85 if (commands.isEmpty())
86 return;
87 Collection<? extends OsmPrimitive> oldSelection = Main.main.getCurrentDataSet().getSelected();
88 Main.main.getCurrentDataSet().beginUpdate();
89 try {
90 for (int i=1; i<=num; ++i) {
91 final Command c = commands.removeLast();
92 c.undoCommand();
93 redoCommands.addFirst(c);
94 if (commands.isEmpty()) {
95 break;
96 }
97 }
98 }
99 finally {
100 Main.main.getCurrentDataSet().endUpdate();
101 }
102 fireCommandsChanged();
103 Collection<? extends OsmPrimitive> newSelection = Main.main.getCurrentDataSet().getSelected();
104 if (!oldSelection.equals(newSelection)) {
105 Main.main.getCurrentDataSet().fireSelectionChanged();
106 }
107 }
108
109 /**
110 * Redoes the last undoed command.
111 */
112 public void redo() {
113 redo(1);
114 }
115
116 /**
117 * Redoes multiple commands.
118 * @param num The number of commands to redo
119 */
120 public void redo(int num) {
121 if (redoCommands.isEmpty())
122 return;
123 Collection<? extends OsmPrimitive> oldSelection = Main.main.getCurrentDataSet().getSelected();
124 for (int i=0; i<num; ++i) {
125 final Command c = redoCommands.removeFirst();
126 c.executeCommand();
127 commands.add(c);
128 if (redoCommands.isEmpty()) {
129 break;
130 }
131 }
132 fireCommandsChanged();
133 Collection<? extends OsmPrimitive> newSelection = Main.main.getCurrentDataSet().getSelected();
134 if (!oldSelection.equals(newSelection)) {
135 Main.main.getCurrentDataSet().fireSelectionChanged();
136 }
137 }
138
139 public void fireCommandsChanged() {
140 for (final CommandQueueListener l : listenerCommands) {
141 l.commandChanged(commands.size(), redoCommands.size());
142 }
143 }
144
145 public void clean() {
146 redoCommands.clear();
147 commands.clear();
148 fireCommandsChanged();
149 }
150
151 public void clean(Layer layer) {
152 if (layer == null)
153 return;
154 boolean changed = false;
155 for (Iterator<Command> it = commands.iterator(); it.hasNext();) {
156 if (it.next().invalidBecauselayerRemoved(layer)) {
157 it.remove();
158 changed = true;
159 }
160 }
161 for (Iterator<Command> it = redoCommands.iterator(); it.hasNext();) {
162 if (it.next().invalidBecauselayerRemoved(layer)) {
163 it.remove();
164 changed = true;
165 }
166 }
167 if (changed) {
168 fireCommandsChanged();
169 }
170 }
171
172 @Override
173 public void layerRemoved(Layer oldLayer) {
174 clean(oldLayer);
175 }
176
177 @Override
178 public void layerAdded(Layer newLayer) {}
179 @Override
180 public void activeLayerChange(Layer oldLayer, Layer newLayer) {}
181
182 /**
183 * Removes a command queue listener.
184 * @param l The command queue listener to remove
185 */
186 public void removeCommandQueueListener(CommandQueueListener l) {
187 listenerCommands.remove(l);
188 }
189
190 /**
191 * Adds a command queue listener.
192 * @param l The commands queue listener to add
193 * @return {@code true} if the listener has been added, {@code false} otherwise
194 */
195 public boolean addCommandQueueListener(CommandQueueListener l) {
196 return listenerCommands.add(l);
197 }
198}
Note: See TracBrowser for help on using the repository browser.