Index: /trunk/src/org/openstreetmap/josm/actions/AbstractPasteAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/AbstractPasteAction.java (revision 10766)
+++ /trunk/src/org/openstreetmap/josm/actions/AbstractPasteAction.java (revision 10766)
@@ -0,0 +1,103 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.actions;
+
+import java.awt.MouseInfo;
+import java.awt.Point;
+import java.awt.datatransfer.FlavorEvent;
+import java.awt.datatransfer.FlavorListener;
+import java.awt.datatransfer.Transferable;
+import java.awt.event.ActionEvent;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
+import org.openstreetmap.josm.gui.datatransfer.OsmTransferHandler;
+import org.openstreetmap.josm.tools.Shortcut;
+
+/**
+ * This is the base class for all actions that paste objects.
+ * @author Michael Zangl
+ * @since 10765
+ */
+public abstract class AbstractPasteAction extends JosmAction implements FlavorListener {
+
+ protected final OsmTransferHandler transferHandler;
+
+ /**
+ * Constructs a new {@link AbstractPasteAction}.
+ * @param name the action's text as displayed on the menu (if it is added to a menu)
+ * @param iconName the filename of the icon to use
+ * @param tooltip a longer description of the action that will be displayed in the tooltip. Please note
+ * that html is not supported for menu actions on some platforms.
+ * @param shortcut a ready-created shortcut object or null if you don't want a shortcut. But you always
+ * do want a shortcut, remember you can always register it with group=none, so you
+ * won't be assigned a shortcut unless the user configures one. If you pass null here,
+ * the user CANNOT configure a shortcut for your action.
+ * @param registerInToolbar register this action for the toolbar preferences?
+ */
+ public AbstractPasteAction(String name, String iconName, String tooltip, Shortcut shortcut,
+ boolean registerInToolbar) {
+ this(name, iconName, tooltip, shortcut, registerInToolbar, null);
+ }
+
+ /**
+ * Constructs a new {@link AbstractPasteAction}.
+ * @param name the action's text as displayed on the menu (if it is added to a menu)
+ * @param iconName the filename of the icon to use
+ * @param tooltip a longer description of the action that will be displayed in the tooltip. Please note
+ * that html is not supported for menu actions on some platforms.
+ * @param shortcut a ready-created shortcut object or null if you don't want a shortcut. But you always
+ * do want a shortcut, remember you can always register it with group=none, so you
+ * won't be assigned a shortcut unless the user configures one. If you pass null here,
+ * the user CANNOT configure a shortcut for your action.
+ * @param registerInToolbar register this action for the toolbar preferences?
+ * @param toolbarId identifier for the toolbar preferences. The iconName is used, if this parameter is null
+ */
+ public AbstractPasteAction(String name, String iconName, String tooltip, Shortcut shortcut,
+ boolean registerInToolbar, String toolbarId) {
+ super(name, iconName, tooltip, shortcut, registerInToolbar, toolbarId, true);
+ transferHandler = new OsmTransferHandler();
+ ClipboardUtils.getClipboard().addFlavorListener(this);
+ }
+
+ /**
+ * Compute the location the objects should be pasted at.
+ * @param e The action event that triggered the paste
+ * @return The paste position.
+ */
+ protected EastNorth computePastePosition(ActionEvent e) {
+ // default to paste in center of map (pasted via menu or cursor not in MapView)
+ EastNorth mPosition = Main.map.mapView.getCenter();
+ // We previously checked for modifier to know if the action has been trigerred via shortcut or via menu
+ // But this does not work if the shortcut is changed to a single key (see #9055)
+ // Observed behaviour: getActionCommand() returns Action.NAME when triggered via menu, but shortcut text when triggered with it
+ if (e != null && !getValue(NAME).equals(e.getActionCommand())) {
+ final Point mp = MouseInfo.getPointerInfo().getLocation();
+ final Point tl = Main.map.mapView.getLocationOnScreen();
+ final Point pos = new Point(mp.x-tl.x, mp.y-tl.y);
+ if (Main.map.mapView.contains(pos)) {
+ mPosition = Main.map.mapView.getEastNorth(pos.x, pos.y);
+ }
+ }
+ return mPosition;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ doPaste(e, ClipboardUtils.getClipboard().getContents(null));
+ }
+
+ protected void doPaste(ActionEvent e, Transferable contents) {
+ transferHandler.pasteOn(Main.getLayerManager().getEditLayer(), computePastePosition(e), contents);
+ }
+
+ @Override
+ protected void updateEnabledState() {
+ setEnabled(getLayerManager().getEditDataSet() != null && transferHandler.isDataAvailable());
+ }
+
+ @Override
+ public void flavorsChanged(FlavorEvent e) {
+ updateEnabledState();
+ }
+}
Index: /trunk/src/org/openstreetmap/josm/actions/DuplicateAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/DuplicateAction.java (revision 10765)
+++ /trunk/src/org/openstreetmap/josm/actions/DuplicateAction.java (revision 10766)
@@ -10,7 +10,5 @@
import java.util.Collection;
-import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.gui.datatransfer.OsmTransferHandler;
import org.openstreetmap.josm.gui.datatransfer.PrimitiveTransferable;
import org.openstreetmap.josm.gui.datatransfer.data.PrimitiveTransferData;
@@ -20,5 +18,5 @@
* An action that duplicates the given nodes. They are not added to the clipboard.
*/
-public final class DuplicateAction extends JosmAction {
+public final class DuplicateAction extends AbstractPasteAction {
/**
@@ -35,6 +33,5 @@
public void actionPerformed(ActionEvent e) {
PrimitiveTransferData data = PrimitiveTransferData.getDataWithReferences(getLayerManager().getEditDataSet().getSelected());
- new OsmTransferHandler().pasteOn(Main.getLayerManager().getEditLayer(),
- PasteAction.computePastePosition(e, getValue(NAME)), new PrimitiveTransferable(data));
+ doPaste(e, new PrimitiveTransferable(data));
}
Index: /trunk/src/org/openstreetmap/josm/actions/PasteAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/PasteAction.java (revision 10765)
+++ /trunk/src/org/openstreetmap/josm/actions/PasteAction.java (revision 10766)
@@ -6,15 +6,7 @@
import static org.openstreetmap.josm.tools.I18n.tr;
-import java.awt.MouseInfo;
-import java.awt.Point;
-import java.awt.datatransfer.FlavorEvent;
-import java.awt.datatransfer.FlavorListener;
-import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.coor.EastNorth;
-import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
-import org.openstreetmap.josm.gui.datatransfer.OsmTransferHandler;
import org.openstreetmap.josm.tools.Shortcut;
@@ -23,7 +15,5 @@
* @since 404
*/
-public final class PasteAction extends JosmAction implements FlavorListener {
-
- private final OsmTransferHandler transferHandler;
+public final class PasteAction extends AbstractPasteAction {
/**
@@ -31,5 +21,5 @@
*/
public PasteAction() {
- super(tr("Paste"), "paste", tr("Paste contents of paste buffer."),
+ super(tr("Paste"), "paste", tr("Paste contents of clipboard."),
Shortcut.registerShortcut("system:paste", tr("Edit: {0}", tr("Paste")), KeyEvent.VK_V, Shortcut.CTRL), true);
putValue("help", ht("/Action/Paste"));
@@ -37,38 +27,4 @@
Main.registerActionShortcut(this,
Shortcut.registerShortcut("system:paste:cua", tr("Edit: {0}", tr("Paste")), KeyEvent.VK_INSERT, Shortcut.SHIFT));
- transferHandler = new OsmTransferHandler();
- ClipboardUtils.getClipboard().addFlavorListener(this);
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- transferHandler.pasteOn(Main.getLayerManager().getEditLayer(), computePastePosition(e, getValue(NAME)));
- }
-
- static EastNorth computePastePosition(ActionEvent e, Object name) {
- // default to paste in center of map (pasted via menu or cursor not in MapView)
- EastNorth mPosition = Main.map.mapView.getCenter();
- // We previously checked for modifier to know if the action has been trigerred via shortcut or via menu
- // But this does not work if the shortcut is changed to a single key (see #9055)
- // Observed behaviour: getActionCommand() returns Action.NAME when triggered via menu, but shortcut text when triggered with it
- if (e != null && !name.equals(e.getActionCommand())) {
- final Point mp = MouseInfo.getPointerInfo().getLocation();
- final Point tl = Main.map.mapView.getLocationOnScreen();
- final Point pos = new Point(mp.x-tl.x, mp.y-tl.y);
- if (Main.map.mapView.contains(pos)) {
- mPosition = Main.map.mapView.getEastNorth(pos.x, pos.y);
- }
- }
- return mPosition;
- }
-
- @Override
- protected void updateEnabledState() {
- setEnabled(getLayerManager().getEditDataSet() != null && transferHandler.isDataAvailable());
- }
-
- @Override
- public void flavorsChanged(FlavorEvent e) {
- updateEnabledState();
}
}
Index: /trunk/src/org/openstreetmap/josm/actions/PasteAtSourcePositionAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/PasteAtSourcePositionAction.java (revision 10766)
+++ /trunk/src/org/openstreetmap/josm/actions/PasteAtSourcePositionAction.java (revision 10766)
@@ -0,0 +1,35 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.actions;
+
+import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.tools.Shortcut;
+
+/**
+ * A special version of the {@link PasteAction} that pastes at the exact source location the item was copied from.
+ * @author Michael Zangl
+ * @since 10765
+ */
+public class PasteAtSourcePositionAction extends AbstractPasteAction {
+
+ /**
+ * Constructs a new {@link PasteAtSourcePositionAction}.
+ */
+ public PasteAtSourcePositionAction() {
+ super(tr("Paste at source position"), "paste", tr("Paste contents of clipboard at the position they were copied from."),
+ Shortcut.registerShortcut("menu:edit:pasteAtSource", tr("Edit: {0}", tr("Paste at source position")),
+ KeyEvent.VK_V, Shortcut.ALT_CTRL), true, "pasteatsource");
+ putValue("help", ht("/Action/Paste"));
+ }
+
+ @Override
+ protected EastNorth computePastePosition(ActionEvent e) {
+ // null means use old position
+ return null;
+ }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/MainMenu.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/MainMenu.java (revision 10765)
+++ /trunk/src/org/openstreetmap/josm/gui/MainMenu.java (revision 10766)
@@ -74,4 +74,5 @@
import org.openstreetmap.josm.actions.OverpassDownloadAction;
import org.openstreetmap.josm.actions.PasteAction;
+import org.openstreetmap.josm.actions.PasteAtSourcePositionAction;
import org.openstreetmap.josm.actions.PasteTagsAction;
import org.openstreetmap.josm.actions.PreferenceToggleAction;
@@ -195,4 +196,6 @@
/** Edit / Paste */
public final PasteAction paste = new PasteAction();
+ /** Edit / Paste at source */
+ private final PasteAtSourcePositionAction pasteAtSource = new PasteAtSourcePositionAction();
/** Edit / Paste Tags */
public final PasteTagsAction pasteTags = new PasteTagsAction();
@@ -680,4 +683,5 @@
add(editMenu, copyCoordinates, true);
add(editMenu, paste);
+ add(editMenu, pasteAtSource, true);
add(editMenu, pasteTags);
add(editMenu, duplicate);
Index: /trunk/src/org/openstreetmap/josm/gui/datatransfer/OsmTransferHandler.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/datatransfer/OsmTransferHandler.java (revision 10765)
+++ /trunk/src/org/openstreetmap/josm/gui/datatransfer/OsmTransferHandler.java (revision 10766)
@@ -83,5 +83,5 @@
* Paste the current clipboard current at the given position
* @param editLayer The layer to paste on.
- * @param mPosition The position to paste at.
+ * @param mPosition The position to paste at. If it is null
, the original position will be used.
*/
public void pasteOn(OsmDataLayer editLayer, EastNorth mPosition) {
@@ -93,5 +93,5 @@
* Paste the given clipboard current at the given position
* @param editLayer The layer to paste on.
- * @param mPosition The position to paste at.
+ * @param mPosition The position to paste at. If it is null
, the original position will be used.
* @param transferable The transferable to use.
*/
Index: /trunk/src/org/openstreetmap/josm/gui/datatransfer/importers/PrimitiveDataPaster.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/datatransfer/importers/PrimitiveDataPaster.java (revision 10765)
+++ /trunk/src/org/openstreetmap/josm/gui/datatransfer/importers/PrimitiveDataPaster.java (revision 10766)
@@ -50,5 +50,5 @@
EastNorth center = pasteBuffer.getCenter();
- EastNorth offset = center == null ? null : pasteAt.subtract(center);
+ EastNorth offset = center == null || pasteAt == null ? new EastNorth(0, 0) : pasteAt.subtract(center);
AddPrimitivesCommand command = createNewPrimitives(pasteBuffer, offset, layer);