// 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.getClipboardContent());
}
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();
}
}