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