Ticket #13290: patch-paste-at-same-position.patch

File patch-paste-at-same-position.patch, 14.1 KB (added by michael2402, 5 years ago)
  • new file src/org/openstreetmap/josm/actions/AbstractPasteAction.java

    diff --git a/src/org/openstreetmap/josm/actions/AbstractPasteAction.java b/src/org/openstreetmap/josm/actions/AbstractPasteAction.java
    new file mode 100644
    index 0000000..183d3af
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.actions;
     3
     4import java.awt.MouseInfo;
     5import java.awt.Point;
     6import java.awt.datatransfer.FlavorEvent;
     7import java.awt.datatransfer.FlavorListener;
     8import java.awt.datatransfer.Transferable;
     9import java.awt.event.ActionEvent;
     10
     11import org.openstreetmap.josm.Main;
     12import org.openstreetmap.josm.data.coor.EastNorth;
     13import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
     14import org.openstreetmap.josm.gui.datatransfer.OsmTransferHandler;
     15import org.openstreetmap.josm.tools.Shortcut;
     16
     17/**
     18 * This is the base class for all actions that paste objects.
     19 * @author Michael Zangl
     20 * @since xxx
     21 */
     22public abstract class AbstractPasteAction extends JosmAction implements FlavorListener {
     23
     24    protected final OsmTransferHandler transferHandler;
     25
     26    /**
     27     * Create a new {@link AbstractPasteAction}
     28     * @param name See {@link JosmAction#JosmAction(String, String, String, Shortcut, boolean, String, boolean)}
     29     * @param iconName See {@link JosmAction#JosmAction(String, String, String, Shortcut, boolean, String, boolean)}
     30     * @param tooltip See {@link JosmAction#JosmAction(String, String, String, Shortcut, boolean, String, boolean)}
     31     * @param shortcut See {@link JosmAction#JosmAction(String, String, String, Shortcut, boolean, String, boolean)}
     32     * @param registerInToolbar See {@link JosmAction#JosmAction(String, String, String, Shortcut, boolean, String, boolean)}
     33     */
     34    public AbstractPasteAction(String name, String iconName, String tooltip, Shortcut shortcut,
     35            boolean registerInToolbar) {
     36        super(name, iconName, tooltip, shortcut, registerInToolbar);
     37        transferHandler = new OsmTransferHandler();
     38        ClipboardUtils.getClipboard().addFlavorListener(this);
     39    }
     40
     41    /**
     42     * Compute the location the objects should be pasted at.
     43     * @param e The action event that triggered the paste
     44     * @return The paste position.
     45     */
     46    protected EastNorth computePastePosition(ActionEvent e) {
     47        // default to paste in center of map (pasted via menu or cursor not in MapView)
     48        EastNorth mPosition = Main.map.mapView.getCenter();
     49        // We previously checked for modifier to know if the action has been trigerred via shortcut or via menu
     50        // But this does not work if the shortcut is changed to a single key (see #9055)
     51        // Observed behaviour: getActionCommand() returns Action.NAME when triggered via menu, but shortcut text when triggered with it
     52        if (e != null && !getValue(NAME).equals(e.getActionCommand())) {
     53            final Point mp = MouseInfo.getPointerInfo().getLocation();
     54            final Point tl = Main.map.mapView.getLocationOnScreen();
     55            final Point pos = new Point(mp.x-tl.x, mp.y-tl.y);
     56            if (Main.map.mapView.contains(pos)) {
     57                mPosition = Main.map.mapView.getEastNorth(pos.x, pos.y);
     58            }
     59        }
     60        return mPosition;
     61    }
     62
     63    @Override
     64    public void actionPerformed(ActionEvent e) {
     65        Transferable contents = ClipboardUtils.getClipboard().getContents(null);
     66        doPaste(e, contents);
     67    }
     68
     69    protected void doPaste(ActionEvent e, Transferable contents) {
     70        transferHandler.pasteOn(Main.getLayerManager().getEditLayer(), computePastePosition(e), contents);
     71    }
     72
     73    @Override
     74    protected void updateEnabledState() {
     75        setEnabled(getLayerManager().getEditDataSet() != null && transferHandler.isDataAvailable());
     76    }
     77
     78    @Override
     79    public void flavorsChanged(FlavorEvent e) {
     80        updateEnabledState();
     81    }
     82
     83}
  • src/org/openstreetmap/josm/actions/DuplicateAction.java

    diff --git a/src/org/openstreetmap/josm/actions/DuplicateAction.java b/src/org/openstreetmap/josm/actions/DuplicateAction.java
    index 66efb08..cb8bb5d 100644
    a b import java.awt.event.ActionEvent; 
    99import java.awt.event.KeyEvent;
    1010import java.util.Collection;
    1111
    12 import org.openstreetmap.josm.Main;
    1312import org.openstreetmap.josm.data.osm.OsmPrimitive;
    14 import org.openstreetmap.josm.gui.datatransfer.OsmTransferHandler;
    1513import org.openstreetmap.josm.gui.datatransfer.PrimitiveTransferable;
    1614import org.openstreetmap.josm.gui.datatransfer.data.PrimitiveTransferData;
    1715import org.openstreetmap.josm.tools.Shortcut;
    import org.openstreetmap.josm.tools.Shortcut; 
    1917/**
    2018 * An action that duplicates the given nodes. They are not added to the clipboard.
    2119 */
    22 public final class DuplicateAction extends JosmAction {
     20public final class DuplicateAction extends AbstractPasteAction {
    2321
    2422    /**
    2523     * Constructs a new {@code DuplicateAction}.
    public final class DuplicateAction extends JosmAction { 
    3432    @Override
    3533    public void actionPerformed(ActionEvent e) {
    3634        PrimitiveTransferData data = PrimitiveTransferData.getDataWithReferences(getLayerManager().getEditDataSet().getSelected());
    37         new OsmTransferHandler().pasteOn(Main.getLayerManager().getEditLayer(),
    38                 PasteAction.computePastePosition(e, getValue(NAME)), new PrimitiveTransferable(data));
     35        doPaste(e, new PrimitiveTransferable(data));
    3936    }
    4037
    4138    @Override
  • src/org/openstreetmap/josm/actions/PasteAction.java

    diff --git a/src/org/openstreetmap/josm/actions/PasteAction.java b/src/org/openstreetmap/josm/actions/PasteAction.java
    index 9ab5725..b54f14b 100644
    a b package org.openstreetmap.josm.actions; 
    55import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
    66import static org.openstreetmap.josm.tools.I18n.tr;
    77
    8 import java.awt.MouseInfo;
    9 import java.awt.Point;
    10 import java.awt.datatransfer.FlavorEvent;
    11 import java.awt.datatransfer.FlavorListener;
    12 import java.awt.event.ActionEvent;
    138import java.awt.event.KeyEvent;
    149
    1510import org.openstreetmap.josm.Main;
    16 import org.openstreetmap.josm.data.coor.EastNorth;
    17 import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
    18 import org.openstreetmap.josm.gui.datatransfer.OsmTransferHandler;
    1911import org.openstreetmap.josm.tools.Shortcut;
    2012
    2113/**
    2214 * Paste OSM primitives from clipboard to the current edit layer.
    2315 * @since 404
    2416 */
    25 public final class PasteAction extends JosmAction implements FlavorListener {
    26 
    27     private final OsmTransferHandler transferHandler;
     17public final class PasteAction extends AbstractPasteAction {
    2818
    2919    /**
    3020     * Constructs a new {@code PasteAction}.
    3121     */
    3222    public PasteAction() {
    33         super(tr("Paste"), "paste", tr("Paste contents of paste buffer."),
     23        super(tr("Paste"), "paste", tr("Paste contents of clipboard."),
    3424                Shortcut.registerShortcut("system:paste", tr("Edit: {0}", tr("Paste")), KeyEvent.VK_V, Shortcut.CTRL), true);
    3525        putValue("help", ht("/Action/Paste"));
    3626        // CUA shortcut for paste (https://en.wikipedia.org/wiki/IBM_Common_User_Access#Description)
    3727        Main.registerActionShortcut(this,
    3828                Shortcut.registerShortcut("system:paste:cua", tr("Edit: {0}", tr("Paste")), KeyEvent.VK_INSERT, Shortcut.SHIFT));
    39         transferHandler = new OsmTransferHandler();
    40         ClipboardUtils.getClipboard().addFlavorListener(this);
    41     }
    42 
    43     @Override
    44     public void actionPerformed(ActionEvent e) {
    45         transferHandler.pasteOn(Main.getLayerManager().getEditLayer(), computePastePosition(e, getValue(NAME)));
    46     }
    47 
    48     static EastNorth computePastePosition(ActionEvent e, Object name) {
    49         // default to paste in center of map (pasted via menu or cursor not in MapView)
    50         EastNorth mPosition = Main.map.mapView.getCenter();
    51         // We previously checked for modifier to know if the action has been trigerred via shortcut or via menu
    52         // But this does not work if the shortcut is changed to a single key (see #9055)
    53         // Observed behaviour: getActionCommand() returns Action.NAME when triggered via menu, but shortcut text when triggered with it
    54         if (e != null && !name.equals(e.getActionCommand())) {
    55             final Point mp = MouseInfo.getPointerInfo().getLocation();
    56             final Point tl = Main.map.mapView.getLocationOnScreen();
    57             final Point pos = new Point(mp.x-tl.x, mp.y-tl.y);
    58             if (Main.map.mapView.contains(pos)) {
    59                 mPosition = Main.map.mapView.getEastNorth(pos.x, pos.y);
    60             }
    61         }
    62         return mPosition;
    63     }
    64 
    65     @Override
    66     protected void updateEnabledState() {
    67         setEnabled(getLayerManager().getEditDataSet() != null && transferHandler.isDataAvailable());
    68     }
    69 
    70     @Override
    71     public void flavorsChanged(FlavorEvent e) {
    72         updateEnabledState();
    7329    }
    7430}
  • new file src/org/openstreetmap/josm/actions/PasteAtSourcePositionAction.java

    diff --git a/src/org/openstreetmap/josm/actions/PasteAtSourcePositionAction.java b/src/org/openstreetmap/josm/actions/PasteAtSourcePositionAction.java
    new file mode 100644
    index 0000000..86a1f14
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.actions;
     3
     4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
     5import static org.openstreetmap.josm.tools.I18n.tr;
     6
     7import java.awt.event.ActionEvent;
     8import java.awt.event.KeyEvent;
     9
     10import org.openstreetmap.josm.data.coor.EastNorth;
     11import org.openstreetmap.josm.tools.Shortcut;
     12
     13/**
     14 * A special version of the {@link PasteAction} that pastes at the exact source location the item was copied from.
     15 * @author Michael Zangl
     16 * @since xxx
     17 */
     18public class PasteAtSourcePositionAction extends AbstractPasteAction {
     19    /**
     20     * Constructs a new {@link PasteAtSourcePositionAction}
     21     */
     22    public PasteAtSourcePositionAction() {
     23        super(tr("Paste at source position"), "paste", tr("Paste contents of clipboard at the position they were copied from."),
     24                Shortcut.registerShortcut("menu:edit:pasteAtSource", tr("Edit: {0}", tr("Paste at source position")),
     25                        KeyEvent.VK_V, Shortcut.ALT_CTRL), true);
     26        putValue("help", ht("/Action/Paste"));
     27    }
     28
     29    @Override
     30    protected EastNorth computePastePosition(ActionEvent e) {
     31        // null means use old position
     32        return null;
     33    }
     34}
  • src/org/openstreetmap/josm/gui/MainMenu.java

    diff --git a/src/org/openstreetmap/josm/gui/MainMenu.java b/src/org/openstreetmap/josm/gui/MainMenu.java
    index 172e60b..060c293 100644
    a b import org.openstreetmap.josm.actions.OrthogonalizeAction; 
    7373import org.openstreetmap.josm.actions.OrthogonalizeAction.Undo;
    7474import org.openstreetmap.josm.actions.OverpassDownloadAction;
    7575import org.openstreetmap.josm.actions.PasteAction;
     76import org.openstreetmap.josm.actions.PasteAtSourcePositionAction;
    7677import org.openstreetmap.josm.actions.PasteTagsAction;
    7778import org.openstreetmap.josm.actions.PreferenceToggleAction;
    7879import org.openstreetmap.josm.actions.PreferencesAction;
    public class MainMenu extends JMenuBar { 
    194195    public final JosmAction copyCoordinates = new CopyCoordinatesAction();
    195196    /** Edit / Paste */
    196197    public final PasteAction paste = new PasteAction();
     198    /** Edit / Paste at source */
     199    private final PasteAtSourcePositionAction pasteAtSource = new PasteAtSourcePositionAction();
    197200    /** Edit / Paste Tags */
    198201    public final PasteTagsAction pasteTags = new PasteTagsAction();
    199202    /** Edit / Duplicate */
    public class MainMenu extends JMenuBar { 
    679682        add(editMenu, copy);
    680683        add(editMenu, copyCoordinates, true);
    681684        add(editMenu, paste);
     685        add(editMenu, pasteAtSource);
    682686        add(editMenu, pasteTags);
    683687        add(editMenu, duplicate);
    684688        add(editMenu, delete);
  • src/org/openstreetmap/josm/gui/datatransfer/OsmTransferHandler.java

    diff --git a/src/org/openstreetmap/josm/gui/datatransfer/OsmTransferHandler.java b/src/org/openstreetmap/josm/gui/datatransfer/OsmTransferHandler.java
    index 5001c48..fdc8b89 100644
    a b public class OsmTransferHandler extends TransferHandler { 
    8282    /**
    8383     * Paste the current clipboard current at the given position
    8484     * @param editLayer The layer to paste on.
    85      * @param mPosition The position to paste at.
     85     * @param mPosition The position to paste at. If it is <code>null</code>, the original position will be used.
    8686     */
    8787    public void pasteOn(OsmDataLayer editLayer, EastNorth mPosition) {
    8888        Transferable transferable = ClipboardUtils.getClipboard().getContents(null);
    public class OsmTransferHandler extends TransferHandler { 
    9292    /**
    9393     * Paste the given clipboard current at the given position
    9494     * @param editLayer The layer to paste on.
    95      * @param mPosition The position to paste at.
     95     * @param mPosition The position to paste at. If it is <code>null</code>, the original position will be used.
    9696     * @param transferable The transferable to use.
    9797     */
    9898    public void pasteOn(OsmDataLayer editLayer, EastNorth mPosition, Transferable transferable) {
  • src/org/openstreetmap/josm/gui/datatransfer/importers/PrimitiveDataPaster.java

    diff --git a/src/org/openstreetmap/josm/gui/datatransfer/importers/PrimitiveDataPaster.java b/src/org/openstreetmap/josm/gui/datatransfer/importers/PrimitiveDataPaster.java
    index 1823263..804b209 100644
    a b public final class PrimitiveDataPaster extends AbstractOsmDataPaster { 
    4949        }
    5050
    5151        EastNorth center = pasteBuffer.getCenter();
    52         EastNorth offset = center == null ? null : pasteAt.subtract(center);
     52        EastNorth offset = center == null || pasteAt == null ? new EastNorth(0, 0) : pasteAt.subtract(center);
    5353
    5454        AddPrimitivesCommand command = createNewPrimitives(pasteBuffer, offset, layer);
    5555