source: josm/trunk/src/org/openstreetmap/josm/command/AddPrimitivesCommand.java @ 12718

Last change on this file since 12718 was 12718, checked in by Don-vip, 3 months ago

see #13036 - see #15229 - see #15182 - make Commands depends only on a DataSet, not a Layer. This removes a lot of GUI dependencies

  • Property svn:eol-style set to native
File size: 7.8 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.command;
3
4import static org.openstreetmap.josm.tools.I18n.trn;
5
6import java.util.ArrayList;
7import java.util.Collection;
8import java.util.HashSet;
9import java.util.List;
10import java.util.Objects;
11import java.util.Optional;
12import java.util.stream.Collectors;
13
14import javax.swing.Icon;
15
16import org.openstreetmap.josm.data.osm.DataSet;
17import org.openstreetmap.josm.data.osm.Node;
18import org.openstreetmap.josm.data.osm.NodeData;
19import org.openstreetmap.josm.data.osm.OsmPrimitive;
20import org.openstreetmap.josm.data.osm.PrimitiveData;
21import org.openstreetmap.josm.gui.layer.OsmDataLayer;
22import org.openstreetmap.josm.tools.CheckParameterUtil;
23import org.openstreetmap.josm.tools.JosmRuntimeException;
24
25/**
26 * Add primitives to a data layer.
27 * @since 2305
28 */
29public class AddPrimitivesCommand extends Command {
30
31    private List<PrimitiveData> data;
32    private Collection<PrimitiveData> toSelect;
33    private List<PrimitiveData> preExistingData;
34
35    // only filled on undo
36    private List<OsmPrimitive> createdPrimitives;
37
38    /**
39     * Constructs a new {@code AddPrimitivesCommand} to add data to the current edit layer.
40     * @param data The OSM primitives data to add. Must not be {@code null}
41     */
42    public AddPrimitivesCommand(List<PrimitiveData> data) {
43        this(data, data);
44    }
45
46    /**
47     * Constructs a new {@code AddPrimitivesCommand} to add data to the current edit layer.
48     * @param data The OSM primitives to add. Must not be {@code null}
49     * @param toSelect The OSM primitives to select at the end. Can be {@code null}
50     * @since 5953
51     */
52    public AddPrimitivesCommand(List<PrimitiveData> data, List<PrimitiveData> toSelect) {
53        init(data, toSelect);
54    }
55
56    /**
57     * Constructs a new {@code AddPrimitivesCommand} to add data to the given layer.
58     * @param data The OSM primitives data to add. Must not be {@code null}
59     * @param toSelect The OSM primitives to select at the end. Can be {@code null}
60     * @param layer The target data layer. Must not be {@code null}
61     * @deprecated to be removed end of 2017. Use {@link #AddPrimitivesCommand(List, List, DataSet)} instead
62     */
63    @Deprecated
64    public AddPrimitivesCommand(List<PrimitiveData> data, List<PrimitiveData> toSelect, OsmDataLayer layer) {
65        super(layer);
66        init(data, toSelect);
67    }
68
69    /**
70     * Constructs a new {@code AddPrimitivesCommand} to add data to the given data set.
71     * @param data The OSM primitives data to add. Must not be {@code null}
72     * @param toSelect The OSM primitives to select at the end. Can be {@code null}
73     * @param ds The target data set. Must not be {@code null}
74     * @since 12718
75     */
76    public AddPrimitivesCommand(List<PrimitiveData> data, List<PrimitiveData> toSelect, DataSet ds) {
77        super(ds);
78        init(data, toSelect);
79    }
80
81    private void init(List<PrimitiveData> data, List<PrimitiveData> toSelect) {
82        CheckParameterUtil.ensureParameterNotNull(data, "data");
83        this.data = new ArrayList<>(data);
84        if (toSelect == data) {
85            this.toSelect = this.data;
86        } else if (toSelect != null) {
87            this.toSelect = new ArrayList<>(toSelect);
88        }
89    }
90
91    @Override
92    public boolean executeCommand() {
93        DataSet ds = getAffectedDataSet();
94        if (createdPrimitives == null) { // first time execution
95            List<OsmPrimitive> newPrimitives = new ArrayList<>(data.size());
96            preExistingData = new ArrayList<>();
97
98            for (PrimitiveData pd : data) {
99                OsmPrimitive primitive = ds.getPrimitiveById(pd);
100                boolean created = primitive == null;
101                if (primitive == null) {
102                    primitive = pd.getType().newInstance(pd.getUniqueId(), true);
103                } else {
104                    preExistingData.add(primitive.save());
105                }
106                if (pd instanceof NodeData) { // Load nodes immediately because they can't be added to dataset without coordinates
107                    primitive.load(pd);
108                }
109                if (created) {
110                    ds.addPrimitive(primitive);
111                }
112                newPrimitives.add(primitive);
113            }
114
115            // Then load ways and relations
116            for (int i = 0; i < newPrimitives.size(); i++) {
117                if (!(newPrimitives.get(i) instanceof Node)) {
118                    newPrimitives.get(i).load(data.get(i));
119                }
120            }
121            newPrimitives.stream().forEach(p -> p.setModified(true));
122        } else { // redo
123            // When redoing this command, we have to add the same objects, otherwise
124            // a subsequent command (e.g. MoveCommand) cannot be redone.
125            for (OsmPrimitive osm : createdPrimitives) {
126                if (preExistingData.stream().anyMatch(pd -> pd.getUniqueId() == osm.getUniqueId())) {
127                    Optional<PrimitiveData> o = data.stream().filter(pd -> pd.getUniqueId() == osm.getUniqueId()).findAny();
128                    if (o.isPresent()) {
129                        osm.load(o.get());
130                    }
131                } else {
132                    ds.addPrimitive(osm);
133                }
134            }
135        }
136        if (toSelect != null) {
137            ds.setSelected(toSelect.stream().map(ds::getPrimitiveById).collect(Collectors.toList()));
138        }
139        return true;
140    }
141
142    @Override public void undoCommand() {
143        DataSet ds = getAffectedDataSet();
144        if (createdPrimitives == null) {
145            createdPrimitives = new ArrayList<>(data.size());
146            for (PrimitiveData pd : data) {
147                OsmPrimitive p = ds.getPrimitiveById(pd);
148                createdPrimitives.add(p);
149            }
150            createdPrimitives = PurgeCommand.topoSort(createdPrimitives);
151        }
152        for (OsmPrimitive osm : createdPrimitives) {
153            Optional<PrimitiveData> previous = preExistingData.stream().filter(pd -> pd.getUniqueId() == osm.getUniqueId()).findAny();
154            if (previous.isPresent()) {
155                osm.load(previous.get());
156            } else {
157                ds.removePrimitive(osm);
158            }
159        }
160    }
161
162    @Override
163    public String getDescriptionText() {
164        int size = data != null ? data.size() : createdPrimitives.size();
165        return trn("Added {0} object", "Added {0} objects", size, size);
166    }
167
168    @Override
169    public Icon getDescriptionIcon() {
170        return null;
171    }
172
173    @Override
174    public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted,
175            Collection<OsmPrimitive> added) {
176        // Does nothing because we don't want to create OsmPrimitives.
177    }
178
179    @Override
180    public Collection<? extends OsmPrimitive> getParticipatingPrimitives() {
181        if (createdPrimitives != null)
182            return createdPrimitives;
183
184        Collection<OsmPrimitive> prims = new HashSet<>();
185        for (PrimitiveData d : data) {
186            prims.add(Optional.ofNullable(getAffectedDataSet().getPrimitiveById(d)).orElseThrow(
187                    () -> new JosmRuntimeException("No primitive found for " + d)));
188        }
189        return prims;
190    }
191
192    @Override
193    public int hashCode() {
194        return Objects.hash(super.hashCode(), data, toSelect, preExistingData, createdPrimitives);
195    }
196
197    @Override
198    public boolean equals(Object obj) {
199        if (this == obj) return true;
200        if (obj == null || getClass() != obj.getClass()) return false;
201        if (!super.equals(obj)) return false;
202        AddPrimitivesCommand that = (AddPrimitivesCommand) obj;
203        return Objects.equals(data, that.data) &&
204               Objects.equals(toSelect, that.toSelect) &&
205               Objects.equals(preExistingData, that.preExistingData) &&
206               Objects.equals(createdPrimitives, that.createdPrimitives);
207    }
208}
Note: See TracBrowser for help on using the repository browser.