source: josm/trunk/src/org/openstreetmap/josm/gui/datatransfer/importers/PrimitiveDataPaster.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

File size: 6.5 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.datatransfer.importers;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.datatransfer.UnsupportedFlavorException;
7import java.io.IOException;
8import java.util.ArrayList;
9import java.util.EnumMap;
10import java.util.HashMap;
11import java.util.List;
12import java.util.Map;
13
14import javax.swing.TransferHandler.TransferSupport;
15
16import org.openstreetmap.josm.Main;
17import org.openstreetmap.josm.command.AddPrimitivesCommand;
18import org.openstreetmap.josm.data.coor.EastNorth;
19import org.openstreetmap.josm.data.osm.NodeData;
20import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
21import org.openstreetmap.josm.data.osm.PrimitiveData;
22import org.openstreetmap.josm.data.osm.RelationData;
23import org.openstreetmap.josm.data.osm.RelationMemberData;
24import org.openstreetmap.josm.data.osm.WayData;
25import org.openstreetmap.josm.gui.ExtendedDialog;
26import org.openstreetmap.josm.gui.MainApplication;
27import org.openstreetmap.josm.gui.datatransfer.data.PrimitiveTransferData;
28import org.openstreetmap.josm.gui.layer.OsmDataLayer;
29import org.openstreetmap.josm.tools.JosmRuntimeException;
30import org.openstreetmap.josm.tools.bugreport.BugReport;
31
32/**
33 * This transfer support allows us to transfer primitives. This is the default paste action when primitives were copied.
34 * @author Michael Zangl
35 * @since 10604
36 */
37public final class PrimitiveDataPaster extends AbstractOsmDataPaster {
38    /**
39     * Create a new {@link PrimitiveDataPaster}
40     */
41    public PrimitiveDataPaster() {
42        super(PrimitiveTransferData.DATA_FLAVOR);
43    }
44
45    @Override
46    public boolean importData(TransferSupport support, final OsmDataLayer layer, EastNorth pasteAt)
47            throws UnsupportedFlavorException, IOException {
48        PrimitiveTransferData pasteBuffer = (PrimitiveTransferData) support.getTransferable().getTransferData(df);
49        // Allow to cancel paste if there are incomplete primitives
50        if (pasteBuffer.hasIncompleteData() && !confirmDeleteIncomplete()) {
51            return false;
52        }
53
54        EastNorth center = pasteBuffer.getCenter();
55        EastNorth offset = center == null || pasteAt == null ? new EastNorth(0, 0) : pasteAt.subtract(center);
56
57        AddPrimitivesCommand command = createNewPrimitives(pasteBuffer, offset, layer);
58
59        /* Now execute the commands to add the duplicated contents of the paste buffer to the map */
60        MainApplication.undoRedo.add(command);
61        return true;
62    }
63
64    private static AddPrimitivesCommand createNewPrimitives(PrimitiveTransferData pasteBuffer, EastNorth offset, OsmDataLayer layer) {
65        // Make a copy of pasteBuffer and map from old id to copied data id
66        List<PrimitiveData> bufferCopy = new ArrayList<>();
67        List<PrimitiveData> toSelect = new ArrayList<>();
68        EnumMap<OsmPrimitiveType, Map<Long, Long>> newIds = generateNewPrimitives(pasteBuffer, bufferCopy, toSelect);
69
70        // Update references in copied buffer
71        for (PrimitiveData data : bufferCopy) {
72            try {
73                if (data instanceof NodeData) {
74                    NodeData nodeData = (NodeData) data;
75                    nodeData.setEastNorth(nodeData.getEastNorth().add(offset));
76                } else if (data instanceof WayData) {
77                    updateNodes(newIds.get(OsmPrimitiveType.NODE), data);
78                } else if (data instanceof RelationData) {
79                    updateMembers(newIds, data);
80                }
81            } catch (JosmRuntimeException | IllegalArgumentException | IllegalStateException e) {
82                throw BugReport.intercept(e).put("data", data);
83            }
84        }
85        return new AddPrimitivesCommand(bufferCopy, toSelect, layer.data);
86    }
87
88    private static EnumMap<OsmPrimitiveType, Map<Long, Long>> generateNewPrimitives(PrimitiveTransferData pasteBuffer,
89            List<PrimitiveData> bufferCopy, List<PrimitiveData> toSelect) {
90        EnumMap<OsmPrimitiveType, Map<Long, Long>> newIds = new EnumMap<>(OsmPrimitiveType.class);
91        newIds.put(OsmPrimitiveType.NODE, new HashMap<Long, Long>());
92        newIds.put(OsmPrimitiveType.WAY, new HashMap<Long, Long>());
93        newIds.put(OsmPrimitiveType.RELATION, new HashMap<Long, Long>());
94
95        for (PrimitiveData data : pasteBuffer.getAll()) {
96            if (data.isIncomplete() || !data.isVisible()) {
97                continue;
98            }
99            PrimitiveData copy = data.makeCopy();
100            // don't know why this is reset, but we need it to not crash on copying incomplete nodes.
101            boolean wasIncomplete = copy.isIncomplete();
102            copy.clearOsmMetadata();
103            copy.setIncomplete(wasIncomplete);
104            newIds.get(data.getType()).put(data.getUniqueId(), copy.getUniqueId());
105
106            bufferCopy.add(copy);
107            if (pasteBuffer.getDirectlyAdded().contains(data)) {
108                toSelect.add(copy);
109            }
110        }
111        return newIds;
112    }
113
114    private static void updateMembers(EnumMap<OsmPrimitiveType, Map<Long, Long>> newIds, PrimitiveData data) {
115        List<RelationMemberData> newMembers = new ArrayList<>();
116        for (RelationMemberData member : ((RelationData) data).getMembers()) {
117            OsmPrimitiveType memberType = member.getMemberType();
118            Long newId = newIds.get(memberType).get(member.getMemberId());
119            if (newId != null) {
120                newMembers.add(new RelationMemberData(member.getRole(), memberType, newId));
121            }
122        }
123        ((RelationData) data).setMembers(newMembers);
124    }
125
126    private static void updateNodes(Map<Long, Long> newNodeIds, PrimitiveData data) {
127        List<Long> newNodes = new ArrayList<>();
128        for (Long oldNodeId : ((WayData) data).getNodes()) {
129            Long newNodeId = newNodeIds.get(oldNodeId);
130            if (newNodeId != null) {
131                newNodes.add(newNodeId);
132            }
133        }
134        ((WayData) data).setNodes(newNodes);
135    }
136
137    private static boolean confirmDeleteIncomplete() {
138        ExtendedDialog ed = new ExtendedDialog(Main.parent, tr("Delete incomplete members?"),
139                tr("Paste without incomplete members"), tr("Cancel"));
140        ed.setButtonIcons("dialogs/relation/deletemembers", "cancel");
141        ed.setContent(tr(
142                "The copied data contains incomplete objects.  " + "When pasting the incomplete objects are removed.  "
143                        + "Do you want to paste the data without the incomplete objects?"));
144        ed.showDialog();
145        return ed.getValue() == 1;
146    }
147}
Note: See TracBrowser for help on using the repository browser.