001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.actions; 003 004import java.awt.MouseInfo; 005import java.awt.Point; 006import java.awt.datatransfer.FlavorEvent; 007import java.awt.datatransfer.FlavorListener; 008import java.awt.datatransfer.Transferable; 009import java.awt.event.ActionEvent; 010 011import org.openstreetmap.josm.Main; 012import org.openstreetmap.josm.data.coor.EastNorth; 013import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils; 014import org.openstreetmap.josm.gui.datatransfer.OsmTransferHandler; 015import org.openstreetmap.josm.tools.Shortcut; 016 017/** 018 * This is the base class for all actions that paste objects. 019 * @author Michael Zangl 020 * @since 10765 021 */ 022public abstract class AbstractPasteAction extends JosmAction implements FlavorListener { 023 024 protected final OsmTransferHandler transferHandler; 025 026 /** 027 * Constructs a new {@link AbstractPasteAction}. 028 * @param name the action's text as displayed on the menu (if it is added to a menu) 029 * @param iconName the filename of the icon to use 030 * @param tooltip a longer description of the action that will be displayed in the tooltip. Please note 031 * that html is not supported for menu actions on some platforms. 032 * @param shortcut a ready-created shortcut object or null if you don't want a shortcut. But you always 033 * do want a shortcut, remember you can always register it with group=none, so you 034 * won't be assigned a shortcut unless the user configures one. If you pass null here, 035 * the user CANNOT configure a shortcut for your action. 036 * @param registerInToolbar register this action for the toolbar preferences? 037 */ 038 public AbstractPasteAction(String name, String iconName, String tooltip, Shortcut shortcut, 039 boolean registerInToolbar) { 040 this(name, iconName, tooltip, shortcut, registerInToolbar, null); 041 } 042 043 /** 044 * Constructs a new {@link AbstractPasteAction}. 045 * @param name the action's text as displayed on the menu (if it is added to a menu) 046 * @param iconName the filename of the icon to use 047 * @param tooltip a longer description of the action that will be displayed in the tooltip. Please note 048 * that html is not supported for menu actions on some platforms. 049 * @param shortcut a ready-created shortcut object or null if you don't want a shortcut. But you always 050 * do want a shortcut, remember you can always register it with group=none, so you 051 * won't be assigned a shortcut unless the user configures one. If you pass null here, 052 * the user CANNOT configure a shortcut for your action. 053 * @param registerInToolbar register this action for the toolbar preferences? 054 * @param toolbarId identifier for the toolbar preferences. The iconName is used, if this parameter is null 055 */ 056 public AbstractPasteAction(String name, String iconName, String tooltip, Shortcut shortcut, 057 boolean registerInToolbar, String toolbarId) { 058 super(name, iconName, tooltip, shortcut, registerInToolbar, toolbarId, true); 059 transferHandler = new OsmTransferHandler(); 060 ClipboardUtils.getClipboard().addFlavorListener(this); 061 } 062 063 /** 064 * Compute the location the objects should be pasted at. 065 * @param e The action event that triggered the paste 066 * @return The paste position. 067 */ 068 protected EastNorth computePastePosition(ActionEvent e) { 069 // default to paste in center of map (pasted via menu or cursor not in MapView) 070 EastNorth mPosition = Main.map.mapView.getCenter(); 071 // We previously checked for modifier to know if the action has been trigerred via shortcut or via menu 072 // But this does not work if the shortcut is changed to a single key (see #9055) 073 // Observed behaviour: getActionCommand() returns Action.NAME when triggered via menu, but shortcut text when triggered with it 074 if (e != null && !getValue(NAME).equals(e.getActionCommand())) { 075 final Point mp = MouseInfo.getPointerInfo().getLocation(); 076 final Point tl = Main.map.mapView.getLocationOnScreen(); 077 final Point pos = new Point(mp.x-tl.x, mp.y-tl.y); 078 if (Main.map.mapView.contains(pos)) { 079 mPosition = Main.map.mapView.getEastNorth(pos.x, pos.y); 080 } 081 } 082 return mPosition; 083 } 084 085 @Override 086 public void actionPerformed(ActionEvent e) { 087 doPaste(e, ClipboardUtils.getClipboard().getContents(null)); 088 } 089 090 protected void doPaste(ActionEvent e, Transferable contents) { 091 transferHandler.pasteOn(Main.getLayerManager().getEditLayer(), computePastePosition(e), contents); 092 } 093 094 @Override 095 protected void updateEnabledState() { 096 setEnabled(getLayerManager().getEditDataSet() != null && transferHandler.isDataAvailable()); 097 } 098 099 @Override 100 public void flavorsChanged(FlavorEvent e) { 101 updateEnabledState(); 102 } 103}