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