001 // License: GPL. Copyright 2007 by Immanuel Scholz and others
002 package org.openstreetmap.josm.command;
003
004 import static org.openstreetmap.josm.tools.I18n.tr;
005
006 import java.util.Arrays;
007 import java.util.Collection;
008 import java.util.HashSet;
009 import java.util.List;
010 import javax.swing.Icon;
011
012 import javax.swing.JLabel;
013
014 import org.openstreetmap.josm.Main;
015 import org.openstreetmap.josm.data.osm.OsmPrimitive;
016 import org.openstreetmap.josm.tools.ImageProvider;
017
018 /**
019 * A command consisting of a sequence of other commands. Executes the other commands
020 * and undo them in reverse order.
021 * @author imi
022 */
023 public class SequenceCommand extends Command {
024
025 /**
026 * The command sequenz to be executed.
027 */
028 private Command[] sequence;
029 private boolean sequence_complete;
030 private final String name;
031 public boolean continueOnError = false;
032
033 /**
034 * Create the command by specifying the list of commands to execute.
035 * @param sequenz The sequence that should be executed.
036 */
037 public SequenceCommand(String name, Collection<Command> sequenz) {
038 super();
039 this.name = name;
040 this.sequence = new Command[sequenz.size()];
041 this.sequence = sequenz.toArray(this.sequence);
042 }
043
044 /**
045 * Convenient constructor, if the commands are known at compile time.
046 */
047 public SequenceCommand(String name, Command... sequenz) {
048 this(name, Arrays.asList(sequenz));
049 }
050
051 @Override public boolean executeCommand() {
052 for (int i=0; i < sequence.length; i++) {
053 Command c = sequence[i];
054 boolean result = c.executeCommand();
055 if (!result && !continueOnError) {
056 this.undoCommands(i-1);
057 return false;
058 }
059 }
060 sequence_complete = true;
061 return true;
062 }
063
064 public Command getLastCommand() {
065 if(sequence.length == 0)
066 return null;
067 return sequence[sequence.length-1];
068 }
069 private void undoCommands(int start) {
070 // We probably aborted this halfway though the
071 // execution sequence because of a sub-command
072 // error. We already undid the sub-commands.
073 if (!sequence_complete)
074 return;
075 for (int i = start; i >= 0; --i) {
076 sequence[i].undoCommand();
077 }
078 }
079
080 @Override public void undoCommand() {
081 this.undoCommands(sequence.length-1);
082 }
083
084 @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
085 for (Command c : sequence) {
086 c.fillModifiedData(modified, deleted, added);
087 }
088 }
089
090 @Override
091 public String getDescriptionText() {
092 return tr("Sequence: {0}", name);
093 }
094
095 @Override
096 public Icon getDescriptionIcon() {
097 return ImageProvider.get("data", "sequence");
098 }
099
100 @Override
101 @SuppressWarnings("unchecked")
102 public Collection<PseudoCommand> getChildren() {
103 return (List) Arrays.asList(sequence);
104 }
105
106 @Override
107 public Collection<? extends OsmPrimitive> getParticipatingPrimitives() {
108 Collection<OsmPrimitive> prims = new HashSet<OsmPrimitive>();
109 for (Command c : sequence) {
110 prims.addAll(c.getParticipatingPrimitives());
111 }
112 return prims;
113 }
114 }