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

Last change on this file since 2828 was 2818, checked in by mjulius, 14 years ago

don't paste incomplete members
When relations with incomplete members have been copied offer the user the choice between cancel and pasting without the incomplete members.

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