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    }