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

Last change on this file since 9722 was 8513, checked in by Don-vip, 9 years ago

checkstyle: blocks

  • Property svn:eol-style set to native
File size: 8.9 KB
RevLine 
[6380]1// License: GPL. For details, see LICENSE file.
[626]2// Author: David Earl
3package org.openstreetmap.josm.actions;
4
[2818]5import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
[626]6import static org.openstreetmap.josm.tools.I18n.tr;
7
[5052]8import java.awt.MouseInfo;
9import java.awt.Point;
[626]10import java.awt.event.ActionEvent;
11import java.awt.event.KeyEvent;
12import java.util.ArrayList;
13import java.util.HashMap;
14import java.util.List;
[2305]15import java.util.Map;
[626]16
17import org.openstreetmap.josm.Main;
[2305]18import org.openstreetmap.josm.command.AddPrimitivesCommand;
[1636]19import org.openstreetmap.josm.data.coor.EastNorth;
[2305]20import org.openstreetmap.josm.data.osm.NodeData;
[2818]21import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
[2305]22import org.openstreetmap.josm.data.osm.PrimitiveData;
23import org.openstreetmap.josm.data.osm.PrimitiveDeepCopy;
[6047]24import org.openstreetmap.josm.data.osm.PrimitiveDeepCopy.PasteBufferChangedListener;
[2305]25import org.openstreetmap.josm.data.osm.RelationData;
26import org.openstreetmap.josm.data.osm.RelationMemberData;
27import org.openstreetmap.josm.data.osm.WayData;
[2818]28import org.openstreetmap.josm.gui.ExtendedDialog;
[1592]29import org.openstreetmap.josm.gui.layer.Layer;
[1084]30import org.openstreetmap.josm.tools.Shortcut;
[626]31
[5953]32/**
33 * Paste OSM primitives from clipboard to the current edit layer.
34 * @since 404
35 */
[3384]36public final class PasteAction extends JosmAction implements PasteBufferChangedListener {
[626]37
[5953]38 /**
39 * Constructs a new {@code PasteAction}.
40 */
[626]41 public PasteAction() {
[1169]42 super(tr("Paste"), "paste", tr("Paste contents of paste buffer."),
[4982]43 Shortcut.registerShortcut("system:paste", tr("Edit: {0}", tr("Paste")), KeyEvent.VK_V, Shortcut.CTRL), true);
[2323]44 putValue("help", ht("/Action/Paste"));
[6920]45 // CUA shortcut for paste (https://en.wikipedia.org/wiki/IBM_Common_User_Access#Description)
[6451]46 Main.registerActionShortcut(this,
47 Shortcut.registerShortcut("system:paste:cua", tr("Edit: {0}", tr("Paste")), KeyEvent.VK_INSERT, Shortcut.SHIFT));
[3384]48 Main.pasteBuffer.addPasteBufferChangedListener(this);
[626]49 }
50
[6084]51 @Override
[1169]52 public void actionPerformed(ActionEvent e) {
[1820]53 if (!isEnabled())
54 return;
[1592]55 pasteData(Main.pasteBuffer, Main.pasteSource, e);
[1351]56 }
[1592]57
[5953]58 /**
59 * Paste OSM primitives from the given paste buffer and OSM data layer source to the current edit layer.
60 * @param pasteBuffer The paste buffer containing primitive ids to copy
61 * @param source The OSM data layer used to look for primitive ids
62 * @param e The ActionEvent that triggered this operation
63 */
64 public void pasteData(PrimitiveDeepCopy pasteBuffer, Layer source, ActionEvent e) {
[1169]65 /* Find the middle of the pasteBuffer area */
66 double maxEast = -1E100, minEast = 1E100, maxNorth = -1E100, minNorth = 1E100;
[2818]67 boolean incomplete = false;
[2305]68 for (PrimitiveData data : pasteBuffer.getAll()) {
69 if (data instanceof NodeData) {
[8510]70 NodeData n = (NodeData) data;
[5096]71 if (n.getEastNorth() != null) {
72 double east = n.getEastNorth().east();
73 double north = n.getEastNorth().north();
[8513]74 if (east > maxEast) {
75 maxEast = east;
76 }
77 if (east < minEast) {
78 minEast = east;
79 }
80 if (north > maxNorth) {
81 maxNorth = north;
82 }
83 if (north < minNorth) {
84 minNorth = north;
85 }
[5096]86 }
[2305]87 }
[2818]88 if (data.isIncomplete()) {
89 incomplete = true;
90 }
[1169]91 }
[811]92
[2818]93 // Allow to cancel paste if there are incomplete primitives
94 if (incomplete) {
95 if (!confirmDeleteIncomplete()) return;
96 }
97
[5052]98 // default to paste in center of map (pasted via menu or cursor not in MapView)
99 EastNorth mPosition = Main.map.mapView.getCenter();
[6227]100 // We previously checked for modifier to know if the action has been trigerred via shortcut or via menu
101 // But this does not work if the shortcut is changed to a single key (see #9055)
102 // Observed behaviour: getActionCommand() returns Action.NAME when triggered via menu, but shortcut text when triggered with it
[7987]103 if (e != null && !getValue(NAME).equals(e.getActionCommand())) {
[5052]104 final Point mp = MouseInfo.getPointerInfo().getLocation();
105 final Point tl = Main.map.mapView.getLocationOnScreen();
106 final Point pos = new Point(mp.x-tl.x, mp.y-tl.y);
[8510]107 if (Main.map.mapView.contains(pos)) {
[5052]108 mPosition = Main.map.mapView.getEastNorth(pos.x, pos.y);
[2312]109 }
[1169]110 }
[811]111
[1169]112 double offsetEast = mPosition.east() - (maxEast + minEast)/2.0;
113 double offsetNorth = mPosition.north() - (maxNorth + minNorth)/2.0;
[1023]114
[2305]115 // Make a copy of pasteBuffer and map from old id to copied data id
[7005]116 List<PrimitiveData> bufferCopy = new ArrayList<>();
117 List<PrimitiveData> toSelect = new ArrayList<>();
118 Map<Long, Long> newNodeIds = new HashMap<>();
119 Map<Long, Long> newWayIds = new HashMap<>();
120 Map<Long, Long> newRelationIds = new HashMap<>();
[2818]121 for (PrimitiveData data: pasteBuffer.getAll()) {
122 if (data.isIncomplete()) {
123 continue;
124 }
[2305]125 PrimitiveData copy = data.makeCopy();
[6140]126 copy.clearOsmMetadata();
[2818]127 if (data instanceof NodeData) {
[2932]128 newNodeIds.put(data.getUniqueId(), copy.getUniqueId());
[2818]129 } else if (data instanceof WayData) {
[2932]130 newWayIds.put(data.getUniqueId(), copy.getUniqueId());
[2818]131 } else if (data instanceof RelationData) {
[2932]132 newRelationIds.put(data.getUniqueId(), copy.getUniqueId());
[2818]133 }
[2305]134 bufferCopy.add(copy);
[5953]135 if (pasteBuffer.getDirectlyAdded().contains(data)) {
136 toSelect.add(copy);
137 }
[1169]138 }
[2305]139
140 // Update references in copied buffer
141 for (PrimitiveData data:bufferCopy) {
142 if (data instanceof NodeData) {
[8510]143 NodeData nodeData = (NodeData) data;
[6336]144 if (Main.main.getEditLayer() == source) {
[2305]145 nodeData.setEastNorth(nodeData.getEastNorth().add(offsetEast, offsetNorth));
[1205]146 }
[2305]147 } else if (data instanceof WayData) {
[7005]148 List<Long> newNodes = new ArrayList<>();
[8510]149 for (Long oldNodeId: ((WayData) data).getNodes()) {
[2818]150 Long newNodeId = newNodeIds.get(oldNodeId);
151 if (newNodeId != null) {
152 newNodes.add(newNodeId);
153 }
[2305]154 }
[8510]155 ((WayData) data).setNodes(newNodes);
[2305]156 } else if (data instanceof RelationData) {
[7005]157 List<RelationMemberData> newMembers = new ArrayList<>();
[8510]158 for (RelationMemberData member: ((RelationData) data).getMembers()) {
[2818]159 OsmPrimitiveType memberType = member.getMemberType();
160 Long newId = null;
161 switch (memberType) {
162 case NODE:
163 newId = newNodeIds.get(member.getMemberId());
164 break;
165 case WAY:
166 newId = newWayIds.get(member.getMemberId());
167 break;
168 case RELATION:
169 newId = newRelationIds.get(member.getMemberId());
170 break;
171 }
172 if (newId != null) {
173 newMembers.add(new RelationMemberData(member.getRole(), memberType, newId));
174 }
[2305]175 }
[8510]176 ((RelationData) data).setMembers(newMembers);
[1169]177 }
178 }
[1023]179
[2305]180 /* Now execute the commands to add the duplicated contents of the paste buffer to the map */
[5953]181 Main.main.undoRedo.add(new AddPrimitivesCommand(bufferCopy, toSelect));
[1169]182 Main.map.mapView.repaint();
[626]183 }
[1820]184
[2818]185 protected boolean confirmDeleteIncomplete() {
186 ExtendedDialog ed = new ExtendedDialog(Main.parent,
187 tr("Delete incomplete members?"),
188 new String[] {tr("Paste without incomplete members"), tr("Cancel")});
[8061]189 ed.setButtonIcons(new String[] {"dialogs/relation/deletemembers", "cancel"});
[3995]190 ed.setContent(tr("The copied data contains incomplete objects. "
191 + "When pasting the incomplete objects are removed. "
192 + "Do you want to paste the data without the incomplete objects?"));
[2818]193 ed.showDialog();
194 return ed.getValue() == 1;
195 }
196
[1820]197 @Override
198 protected void updateEnabledState() {
[1844]199 if (getCurrentDataSet() == null || Main.pasteBuffer == null) {
[1820]200 setEnabled(false);
201 return;
202 }
[2305]203 setEnabled(!Main.pasteBuffer.isEmpty());
[1820]204 }
[3384]205
206 @Override
207 public void pasteBufferChanged(PrimitiveDeepCopy pasteBuffer) {
208 updateEnabledState();
209 }
[626]210}
Note: See TracBrowser for help on using the repository browser.