source: josm/trunk/src/org/openstreetmap/josm/actions/PasteAction.java @ 4920

Revision 3995, 7.4 KB checked in by mjulius, 11 months ago (diff)

fix #3590 - Primitives or objects: Pick one

  • Property svn:eol-style set to native
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2// Author: David Earl
3package org.openstreetmap.josm.actions;
4
5import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
6import static org.openstreetmap.josm.tools.I18n.tr;
7
8import java.awt.event.ActionEvent;
9import java.awt.event.KeyEvent;
10import java.util.ArrayList;
11import java.util.HashMap;
12import java.util.List;
13import java.util.Map;
14
15import org.openstreetmap.josm.Main;
16import org.openstreetmap.josm.command.AddPrimitivesCommand;
17import org.openstreetmap.josm.data.coor.EastNorth;
18import org.openstreetmap.josm.data.osm.NodeData;
19import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
20import org.openstreetmap.josm.data.osm.PrimitiveData;
21import org.openstreetmap.josm.data.osm.PrimitiveDeepCopy;
22import org.openstreetmap.josm.data.osm.PrimitiveDeepCopy.PasteBufferChangedListener;
23import org.openstreetmap.josm.data.osm.RelationData;
24import org.openstreetmap.josm.data.osm.RelationMemberData;
25import org.openstreetmap.josm.data.osm.WayData;
26import org.openstreetmap.josm.gui.ExtendedDialog;
27import org.openstreetmap.josm.gui.layer.Layer;
28import org.openstreetmap.josm.tools.Shortcut;
29
30public final class PasteAction extends JosmAction implements PasteBufferChangedListener {
31
32    public PasteAction() {
33        super(tr("Paste"), "paste", tr("Paste contents of paste buffer."),
34                Shortcut.registerShortcut("system:paste", tr("Edit: {0}", tr("Paste")), KeyEvent.VK_V, Shortcut.GROUP_MENU), true);
35        putValue("help", ht("/Action/Paste"));
36        Main.pasteBuffer.addPasteBufferChangedListener(this);
37    }
38
39    public void actionPerformed(ActionEvent e) {
40        if (!isEnabled())
41            return;
42        pasteData(Main.pasteBuffer, Main.pasteSource, e);
43    }
44
45    public  void pasteData(PrimitiveDeepCopy pasteBuffer, Layer source, ActionEvent e) {
46        /* Find the middle of the pasteBuffer area */
47        double maxEast = -1E100, minEast = 1E100, maxNorth = -1E100, minNorth = 1E100;
48        boolean incomplete = false;
49        for (PrimitiveData data : pasteBuffer.getAll()) {
50            if (data instanceof NodeData) {
51                NodeData n = (NodeData)data;
52                double east = n.getEastNorth().east();
53                double north = n.getEastNorth().north();
54                if (east > maxEast) { maxEast = east; }
55                if (east < minEast) { minEast = east; }
56                if (north > maxNorth) { maxNorth = north; }
57                if (north < minNorth) { minNorth = north; }
58            }
59            if (data.isIncomplete()) {
60                incomplete = true;
61            }
62        }
63
64        // Allow to cancel paste if there are incomplete primitives
65        if (incomplete) {
66            if (!confirmDeleteIncomplete()) return;
67        }
68
69        EastNorth mPosition;
70        if((e.getModifiers() & ActionEvent.CTRL_MASK) ==0){
71            /* adjust the coordinates to the middle of the visible map area */
72            mPosition = Main.map.mapView.getCenter();
73        } else {
74            if (Main.map.mapView.lastMEvent != null) {
75                mPosition = Main.map.mapView.getEastNorth(Main.map.mapView.lastMEvent.getX(), Main.map.mapView.lastMEvent.getY());
76            } else {
77                mPosition = Main.map.mapView.getCenter();
78            }
79        }
80
81        double offsetEast  = mPosition.east() - (maxEast + minEast)/2.0;
82        double offsetNorth = mPosition.north() - (maxNorth + minNorth)/2.0;
83
84        // Make a copy of pasteBuffer and map from old id to copied data id
85        List<PrimitiveData> bufferCopy = new ArrayList<PrimitiveData>();
86        Map<Long, Long> newNodeIds = new HashMap<Long, Long>();
87        Map<Long, Long> newWayIds = new HashMap<Long, Long>();
88        Map<Long, Long> newRelationIds = new HashMap<Long, Long>();
89        for (PrimitiveData data: pasteBuffer.getAll()) {
90            if (data.isIncomplete()) {
91                continue;
92            }
93            PrimitiveData copy = data.makeCopy();
94            copy.clearOsmId();
95            if (data instanceof NodeData) {
96                newNodeIds.put(data.getUniqueId(), copy.getUniqueId());
97            } else if (data instanceof WayData) {
98                newWayIds.put(data.getUniqueId(), copy.getUniqueId());
99            } else if (data instanceof RelationData) {
100                newRelationIds.put(data.getUniqueId(), copy.getUniqueId());
101            }
102            bufferCopy.add(copy);
103        }
104
105        // Update references in copied buffer
106        for (PrimitiveData data:bufferCopy) {
107            if (data instanceof NodeData) {
108                NodeData nodeData = (NodeData)data;
109                if (Main.map.mapView.getEditLayer() == source) {
110                    nodeData.setEastNorth(nodeData.getEastNorth().add(offsetEast, offsetNorth));
111                }
112            } else if (data instanceof WayData) {
113                List<Long> newNodes = new ArrayList<Long>();
114                for (Long oldNodeId: ((WayData)data).getNodes()) {
115                    Long newNodeId = newNodeIds.get(oldNodeId);
116                    if (newNodeId != null) {
117                        newNodes.add(newNodeId);
118                    }
119                }
120                ((WayData)data).setNodes(newNodes);
121            } else if (data instanceof RelationData) {
122                List<RelationMemberData> newMembers = new ArrayList<RelationMemberData>();
123                for (RelationMemberData member: ((RelationData)data).getMembers()) {
124                    OsmPrimitiveType memberType = member.getMemberType();
125                    Long newId = null;
126                    switch (memberType) {
127                    case NODE:
128                        newId = newNodeIds.get(member.getMemberId());
129                        break;
130                    case WAY:
131                        newId = newWayIds.get(member.getMemberId());
132                        break;
133                    case RELATION:
134                        newId = newRelationIds.get(member.getMemberId());
135                        break;
136                    }
137                    if (newId != null) {
138                        newMembers.add(new RelationMemberData(member.getRole(), memberType, newId));
139                    }
140                }
141                ((RelationData)data).setMembers(newMembers);
142            }
143        }
144
145        /* Now execute the commands to add the duplicated contents of the paste buffer to the map */
146
147        Main.main.undoRedo.add(new AddPrimitivesCommand(bufferCopy));
148        Main.map.mapView.repaint();
149    }
150
151    protected boolean confirmDeleteIncomplete() {
152        ExtendedDialog ed = new ExtendedDialog(Main.parent,
153                tr("Delete incomplete members?"),
154                new String[] {tr("Paste without incomplete members"), tr("Cancel")});
155        ed.setButtonIcons(new String[] {"dialogs/relation/deletemembers.png", "cancel.png"});
156        ed.setContent(tr("The copied data contains incomplete objects.  "
157                + "When pasting the incomplete objects are removed.  "
158                + "Do you want to paste the data without the incomplete objects?"));
159        ed.showDialog();
160        return ed.getValue() == 1;
161    }
162
163    @Override
164    protected void updateEnabledState() {
165        if (getCurrentDataSet() == null || Main.pasteBuffer == null) {
166            setEnabled(false);
167            return;
168        }
169        setEnabled(!Main.pasteBuffer.isEmpty());
170    }
171
172    @Override
173    public void pasteBufferChanged(PrimitiveDeepCopy pasteBuffer) {
174        updateEnabledState();
175    }
176}
Note: See TracBrowser for help on using the repository browser.