[6380] | 1 | // License: GPL. For details, see LICENSE file.
|
---|
[626] | 2 | package org.openstreetmap.josm.command;
|
---|
| 3 |
|
---|
| 4 | import static org.openstreetmap.josm.tools.I18n.tr;
|
---|
| 5 |
|
---|
| 6 | import java.util.Arrays;
|
---|
| 7 | import java.util.Collection;
|
---|
[3262] | 8 | import java.util.HashSet;
|
---|
[9371] | 9 | import java.util.Objects;
|
---|
[5926] | 10 |
|
---|
[4918] | 11 | import javax.swing.Icon;
|
---|
[626] | 12 |
|
---|
[12726] | 13 | import org.openstreetmap.josm.data.osm.DataSet;
|
---|
[626] | 14 | import org.openstreetmap.josm.data.osm.OsmPrimitive;
|
---|
[3262] | 15 | import org.openstreetmap.josm.tools.ImageProvider;
|
---|
[7436] | 16 | import org.openstreetmap.josm.tools.Utils;
|
---|
[626] | 17 |
|
---|
| 18 | /**
|
---|
[655] | 19 | * A command consisting of a sequence of other commands. Executes the other commands
|
---|
[626] | 20 | * and undo them in reverse order.
|
---|
| 21 | * @author imi
|
---|
[6396] | 22 | * @since 31
|
---|
[626] | 23 | */
|
---|
| 24 | public class SequenceCommand extends Command {
|
---|
| 25 |
|
---|
[6396] | 26 | /** The command sequence to be executed. */
|
---|
[1169] | 27 | private Command[] sequence;
|
---|
[6396] | 28 | private boolean sequenceComplete;
|
---|
[1169] | 29 | private final String name;
|
---|
[6396] | 30 | /** Determines if the sequence execution should continue after one of its commands fails. */
|
---|
[11874] | 31 | protected final boolean continueOnError;
|
---|
[626] | 32 |
|
---|
[1169] | 33 | /**
|
---|
| 34 | * Create the command by specifying the list of commands to execute.
|
---|
[12726] | 35 | * @param ds The target data set. Must not be {@code null}
|
---|
[6396] | 36 | * @param name The description text
|
---|
[12726] | 37 | * @param sequenz The sequence that should be executed
|
---|
[11874] | 38 | * @param continueOnError Determines if the sequence execution should continue after one of its commands fails
|
---|
[12726] | 39 | * @since 12726
|
---|
[1169] | 40 | */
|
---|
[12726] | 41 | public SequenceCommand(DataSet ds, String name, Collection<Command> sequenz, boolean continueOnError) {
|
---|
| 42 | super(ds);
|
---|
[1169] | 43 | this.name = name;
|
---|
[13206] | 44 | this.sequence = sequenz.toArray(new Command[0]);
|
---|
[11874] | 45 | this.continueOnError = continueOnError;
|
---|
[1169] | 46 | }
|
---|
[626] | 47 |
|
---|
[1169] | 48 | /**
|
---|
[11874] | 49 | * Create the command by specifying the list of commands to execute.
|
---|
| 50 | * @param name The description text
|
---|
[12726] | 51 | * @param sequenz The sequence that should be executed. Must not be null or empty
|
---|
| 52 | * @param continueOnError Determines if the sequence execution should continue after one of its commands fails
|
---|
| 53 | * @since 11874
|
---|
| 54 | */
|
---|
| 55 | public SequenceCommand(String name, Collection<Command> sequenz, boolean continueOnError) {
|
---|
| 56 | this(sequenz.iterator().next().getAffectedDataSet(), name, sequenz, continueOnError);
|
---|
| 57 | }
|
---|
| 58 |
|
---|
| 59 | /**
|
---|
| 60 | * Create the command by specifying the list of commands to execute.
|
---|
| 61 | * @param name The description text
|
---|
[11874] | 62 | * @param sequenz The sequence that should be executed.
|
---|
| 63 | */
|
---|
| 64 | public SequenceCommand(String name, Collection<Command> sequenz) {
|
---|
| 65 | this(name, sequenz, false);
|
---|
| 66 | }
|
---|
| 67 |
|
---|
| 68 | /**
|
---|
[1169] | 69 | * Convenient constructor, if the commands are known at compile time.
|
---|
[6396] | 70 | * @param name The description text
|
---|
| 71 | * @param sequenz The sequence that should be executed.
|
---|
[1169] | 72 | */
|
---|
| 73 | public SequenceCommand(String name, Command... sequenz) {
|
---|
| 74 | this(name, Arrays.asList(sequenz));
|
---|
| 75 | }
|
---|
[626] | 76 |
|
---|
[1169] | 77 | @Override public boolean executeCommand() {
|
---|
[8510] | 78 | for (int i = 0; i < sequence.length; i++) {
|
---|
[6396] | 79 | boolean result = sequence[i].executeCommand();
|
---|
[1169] | 80 | if (!result && !continueOnError) {
|
---|
[6397] | 81 | undoCommands(i-1);
|
---|
[1169] | 82 | return false;
|
---|
| 83 | }
|
---|
| 84 | }
|
---|
[6396] | 85 | sequenceComplete = true;
|
---|
[1169] | 86 | return true;
|
---|
| 87 | }
|
---|
[626] | 88 |
|
---|
[6396] | 89 | /**
|
---|
| 90 | * Returns the last command.
|
---|
| 91 | * @return The last command, or {@code null} if the sequence is empty.
|
---|
| 92 | */
|
---|
[1169] | 93 | public Command getLastCommand() {
|
---|
[6396] | 94 | if (sequence.length == 0)
|
---|
[1169] | 95 | return null;
|
---|
| 96 | return sequence[sequence.length-1];
|
---|
| 97 | }
|
---|
[7436] | 98 |
|
---|
[6397] | 99 | protected final void undoCommands(int start) {
|
---|
[1750] | 100 | for (int i = start; i >= 0; --i) {
|
---|
[1169] | 101 | sequence[i].undoCommand();
|
---|
[1750] | 102 | }
|
---|
[1169] | 103 | }
|
---|
[630] | 104 |
|
---|
[1169] | 105 | @Override public void undoCommand() {
|
---|
[11733] | 106 | // We probably aborted this halfway though the
|
---|
| 107 | // execution sequence because of a sub-command
|
---|
| 108 | // error. We already undid the sub-commands.
|
---|
| 109 | if (!sequenceComplete)
|
---|
| 110 | return;
|
---|
[6397] | 111 | undoCommands(sequence.length-1);
|
---|
[1169] | 112 | }
|
---|
[626] | 113 |
|
---|
[1169] | 114 | @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
|
---|
[1750] | 115 | for (Command c : sequence) {
|
---|
[1169] | 116 | c.fillModifiedData(modified, deleted, added);
|
---|
[1750] | 117 | }
|
---|
[626] | 118 | }
|
---|
[1169] | 119 |
|
---|
[4918] | 120 | @Override
|
---|
| 121 | public String getDescriptionText() {
|
---|
| 122 | return tr("Sequence: {0}", name);
|
---|
[3262] | 123 | }
|
---|
| 124 |
|
---|
| 125 | @Override
|
---|
[4918] | 126 | public Icon getDescriptionIcon() {
|
---|
| 127 | return ImageProvider.get("data", "sequence");
|
---|
| 128 | }
|
---|
| 129 |
|
---|
| 130 | @Override
|
---|
[3262] | 131 | public Collection<PseudoCommand> getChildren() {
|
---|
[6142] | 132 | return Arrays.<PseudoCommand>asList(sequence);
|
---|
[3262] | 133 | }
|
---|
| 134 |
|
---|
| 135 | @Override
|
---|
| 136 | public Collection<? extends OsmPrimitive> getParticipatingPrimitives() {
|
---|
[7005] | 137 | Collection<OsmPrimitive> prims = new HashSet<>();
|
---|
[1750] | 138 | for (Command c : sequence) {
|
---|
[3262] | 139 | prims.addAll(c.getParticipatingPrimitives());
|
---|
[1750] | 140 | }
|
---|
[3262] | 141 | return prims;
|
---|
[1169] | 142 | }
|
---|
[7436] | 143 |
|
---|
[11747] | 144 | protected final void setSequence(Command... sequence) {
|
---|
[7436] | 145 | this.sequence = Utils.copyArray(sequence);
|
---|
[6396] | 146 | }
|
---|
[7436] | 147 |
|
---|
[6397] | 148 | protected final void setSequenceComplete(boolean sequenceComplete) {
|
---|
| 149 | this.sequenceComplete = sequenceComplete;
|
---|
| 150 | }
|
---|
[8456] | 151 |
|
---|
| 152 | @Override
|
---|
| 153 | public int hashCode() {
|
---|
[9377] | 154 | return Objects.hash(super.hashCode(), Arrays.hashCode(sequence), sequenceComplete, name, continueOnError);
|
---|
[8456] | 155 | }
|
---|
| 156 |
|
---|
| 157 | @Override
|
---|
| 158 | public boolean equals(Object obj) {
|
---|
[9371] | 159 | if (this == obj) return true;
|
---|
| 160 | if (obj == null || getClass() != obj.getClass()) return false;
|
---|
| 161 | if (!super.equals(obj)) return false;
|
---|
| 162 | SequenceCommand that = (SequenceCommand) obj;
|
---|
| 163 | return sequenceComplete == that.sequenceComplete &&
|
---|
| 164 | continueOnError == that.continueOnError &&
|
---|
| 165 | Arrays.equals(sequence, that.sequence) &&
|
---|
| 166 | Objects.equals(name, that.name);
|
---|
[8456] | 167 | }
|
---|
[626] | 168 | }
|
---|