[304] | 1 | //License: GPL. Copyright 2007 by Immanuel Scholz and others
|
---|
[301] | 2 | package org.openstreetmap.josm.data;
|
---|
| 3 |
|
---|
[304] | 4 | import java.util.Iterator;
|
---|
[301] | 5 | import java.util.LinkedList;
|
---|
| 6 | import java.util.Stack;
|
---|
| 7 |
|
---|
| 8 | import org.openstreetmap.josm.Main;
|
---|
| 9 | import org.openstreetmap.josm.command.Command;
|
---|
[1877] | 10 | import org.openstreetmap.josm.data.osm.DataSet;
|
---|
[304] | 11 | import org.openstreetmap.josm.gui.layer.Layer;
|
---|
[301] | 12 | import org.openstreetmap.josm.gui.layer.OsmDataLayer;
|
---|
[304] | 13 | import org.openstreetmap.josm.gui.layer.Layer.LayerChangeListener;
|
---|
[301] | 14 | import org.openstreetmap.josm.gui.layer.OsmDataLayer.CommandQueueListener;
|
---|
| 15 |
|
---|
[304] | 16 | public class UndoRedoHandler implements LayerChangeListener {
|
---|
[301] | 17 |
|
---|
[1169] | 18 | /**
|
---|
| 19 | * All commands that were made on the dataset. Don't write from outside!
|
---|
| 20 | */
|
---|
| 21 | public final LinkedList<Command> commands = new LinkedList<Command>();
|
---|
| 22 | /**
|
---|
| 23 | * The stack for redoing commands
|
---|
| 24 | */
|
---|
| 25 | private final Stack<Command> redoCommands = new Stack<Command>();
|
---|
[301] | 26 |
|
---|
[1169] | 27 | public final LinkedList<CommandQueueListener> listenerCommands = new LinkedList<CommandQueueListener>();
|
---|
[301] | 28 |
|
---|
| 29 |
|
---|
[1169] | 30 | public UndoRedoHandler() {
|
---|
| 31 | Layer.listeners.add(this);
|
---|
| 32 | }
|
---|
[304] | 33 |
|
---|
| 34 |
|
---|
[1169] | 35 | /**
|
---|
| 36 | * Execute the command and add it to the intern command queue.
|
---|
| 37 | */
|
---|
[2098] | 38 | public void addNoRedraw(final Command c) {
|
---|
[1169] | 39 | c.executeCommand();
|
---|
| 40 | commands.add(c);
|
---|
| 41 | redoCommands.clear();
|
---|
[2098] | 42 | }
|
---|
| 43 |
|
---|
| 44 | public void afterAdd() {
|
---|
[1169] | 45 | if (Main.map != null && Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) {
|
---|
| 46 | OsmDataLayer data = (OsmDataLayer)Main.map.mapView.getActiveLayer();
|
---|
| 47 | data.fireDataChange();
|
---|
| 48 | }
|
---|
| 49 | fireCommandsChanged();
|
---|
[1877] | 50 |
|
---|
| 51 | // the command may have changed the selection so tell the listeners about the current situation
|
---|
[2348] | 52 | Main.main.getCurrentDataSet().fireSelectionChanged();
|
---|
[1169] | 53 | }
|
---|
[304] | 54 |
|
---|
[1169] | 55 | /**
|
---|
[2098] | 56 | * Execute the command and add it to the intern command queue.
|
---|
| 57 | */
|
---|
| 58 | public void add(final Command c) {
|
---|
| 59 | addNoRedraw(c);
|
---|
| 60 | afterAdd();
|
---|
| 61 | }
|
---|
| 62 |
|
---|
| 63 | /**
|
---|
[1169] | 64 | * Undoes the last added command.
|
---|
| 65 | */
|
---|
| 66 | public void undo() {
|
---|
| 67 | if (commands.isEmpty())
|
---|
| 68 | return;
|
---|
| 69 | final Command c = commands.removeLast();
|
---|
| 70 | c.undoCommand();
|
---|
| 71 | redoCommands.push(c);
|
---|
| 72 | if (Main.map != null && Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) {
|
---|
| 73 | OsmDataLayer data = (OsmDataLayer)Main.map.mapView.getActiveLayer();
|
---|
| 74 | data.fireDataChange();
|
---|
| 75 | }
|
---|
| 76 | fireCommandsChanged();
|
---|
[1814] | 77 | Main.main.getCurrentDataSet().setSelected();
|
---|
[1169] | 78 | }
|
---|
[301] | 79 |
|
---|
[1169] | 80 | /**
|
---|
| 81 | * Redoes the last undoed command.
|
---|
| 82 | * TODO: This has to be moved to a central place in order to support multiple layers.
|
---|
| 83 | */
|
---|
| 84 | public void redo() {
|
---|
| 85 | if (redoCommands.isEmpty())
|
---|
| 86 | return;
|
---|
| 87 | final Command c = redoCommands.pop();
|
---|
| 88 | c.executeCommand();
|
---|
| 89 | commands.add(c);
|
---|
| 90 | if (Main.map != null && Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) {
|
---|
| 91 | OsmDataLayer data = (OsmDataLayer)Main.map.mapView.getActiveLayer();
|
---|
| 92 | data.fireDataChange();
|
---|
| 93 | }
|
---|
| 94 | fireCommandsChanged();
|
---|
| 95 | }
|
---|
[301] | 96 |
|
---|
[1169] | 97 | public void fireCommandsChanged() {
|
---|
[1814] | 98 | for (final CommandQueueListener l : listenerCommands) {
|
---|
[1169] | 99 | l.commandChanged(commands.size(), redoCommands.size());
|
---|
[1814] | 100 | }
|
---|
[1169] | 101 | }
|
---|
[301] | 102 |
|
---|
[1169] | 103 | public void clean() {
|
---|
| 104 | redoCommands.clear();
|
---|
| 105 | commands.clear();
|
---|
| 106 | fireCommandsChanged();
|
---|
| 107 | }
|
---|
[304] | 108 |
|
---|
[1894] | 109 | public void clean(Layer layer) {
|
---|
| 110 | if (layer == null)
|
---|
| 111 | return;
|
---|
[1169] | 112 | boolean changed = false;
|
---|
| 113 | for (Iterator<Command> it = commands.iterator(); it.hasNext();) {
|
---|
[1894] | 114 | if (it.next().invalidBecauselayerRemoved(layer)) {
|
---|
[1169] | 115 | it.remove();
|
---|
| 116 | changed = true;
|
---|
| 117 | }
|
---|
| 118 | }
|
---|
| 119 | for (Iterator<Command> it = redoCommands.iterator(); it.hasNext();) {
|
---|
[1894] | 120 | if (it.next().invalidBecauselayerRemoved(layer)) {
|
---|
[1169] | 121 | it.remove();
|
---|
| 122 | changed = true;
|
---|
| 123 | }
|
---|
| 124 | }
|
---|
[1814] | 125 | if (changed) {
|
---|
[1169] | 126 | fireCommandsChanged();
|
---|
[1814] | 127 | }
|
---|
[1169] | 128 | }
|
---|
[304] | 129 |
|
---|
[1894] | 130 | public void layerRemoved(Layer oldLayer) {
|
---|
| 131 | clean(oldLayer);
|
---|
| 132 | }
|
---|
| 133 |
|
---|
[1169] | 134 | public void layerAdded(Layer newLayer) {}
|
---|
| 135 | public void activeLayerChange(Layer oldLayer, Layer newLayer) {}
|
---|
[301] | 136 | }
|
---|