Ignore:
Timestamp:
2016-07-23T14:54:19+02:00 (4 years ago)
Author:
Don-vip
Message:

fix #12478, fix #12565, fix #11114 - Use ​Swing Copy/Paste instead of CopyAction/PasteAction with custom buffer (patch by michael2402, modified) - gsoc-core

Location:
trunk/src/org/openstreetmap/josm/actions
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/CopyAction.java

    r10448 r10604  
    99import java.awt.event.KeyEvent;
    1010import java.util.Collection;
     11import java.util.Collections;
    1112
    1213import javax.swing.JOptionPane;
    1314
    1415import org.openstreetmap.josm.Main;
     16import org.openstreetmap.josm.data.osm.DataSet;
    1517import org.openstreetmap.josm.data.osm.OsmPrimitive;
    16 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
    17 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
     18import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
     19import org.openstreetmap.josm.gui.datatransfer.PrimitiveTransferable;
     20import org.openstreetmap.josm.gui.datatransfer.data.PrimitiveTransferData;
    1821import org.openstreetmap.josm.tools.Shortcut;
    19 import org.openstreetmap.josm.tools.Utils;
    2022
    2123/**
     
    2325 * @since 404
    2426 */
    25 public final class CopyAction extends JosmAction {
    26 
    27     /** regular expression that matches text clipboard contents after copying */
    28     public static final String CLIPBOARD_REGEXP = "((node|way|relation)\\s\\d+,)*(node|way|relation)\\s\\d+";
    29 
     27public class CopyAction extends JosmAction {
    3028    /**
    3129     * Constructs a new {@code CopyAction}.
     
    4341    @Override
    4442    public void actionPerformed(ActionEvent e) {
    45         if (isEmptySelection()) return;
    46         Collection<OsmPrimitive> selection = getLayerManager().getEditDataSet().getSelected();
     43        DataSet set = getLayerManager().getEditDataSet();
     44        Collection<OsmPrimitive> selection = set == null ? Collections.<OsmPrimitive>emptySet() : set.getSelected();
     45        if (selection.isEmpty()) {
     46            showEmptySelectionWarning();
     47            return;
     48        }
    4749
    48         copy(getLayerManager().getEditLayer(), selection);
     50        copy(selection);
    4951    }
    5052
     
    5254     * Copies the given primitive ids to the clipboard. The output by this function
    5355     * looks similar to: node 1089302677,node 1089303458,way 93793372
    54      * @param source The OSM data layer source
    5556     * @param primitives The OSM primitives to copy
    5657     */
    57     public static void copy(OsmDataLayer source, Collection<OsmPrimitive> primitives) {
     58    public static void copy(Collection<OsmPrimitive> primitives) {
    5859        // copy ids to the clipboard
    59         String ids = getCopyString(primitives);
    60         Utils.copyToClipboard(ids);
    61 
    62         Main.pasteBuffer.makeCopy(primitives);
    63         Main.pasteSource = source;
    64     }
    65 
    66     static String getCopyString(Collection<? extends OsmPrimitive> primitives) {
    67         StringBuilder idsBuilder = new StringBuilder();
    68         for (OsmPrimitive p : primitives) {
    69             idsBuilder.append(OsmPrimitiveType.from(p).getAPIName()).append(' ').append(p.getId()).append(',');
    70         }
    71         return idsBuilder.substring(0, idsBuilder.length() - 1);
     60        ClipboardUtils.copy(new PrimitiveTransferable(PrimitiveTransferData.getDataWithReferences(primitives)));
    7261    }
    7362
     
    8271    }
    8372
    84     private boolean isEmptySelection() {
    85         Collection<OsmPrimitive> sel = getLayerManager().getEditDataSet().getSelected();
    86         if (sel.isEmpty()) {
    87             JOptionPane.showMessageDialog(
    88                     Main.parent,
    89                     tr("Please select something to copy."),
    90                     tr("Information"),
    91                     JOptionPane.INFORMATION_MESSAGE
    92             );
    93             return true;
    94         }
    95         return false;
     73    protected void showEmptySelectionWarning() {
     74        JOptionPane.showMessageDialog(
     75                Main.parent,
     76                tr("Please select something to copy."),
     77                tr("Information"),
     78                JOptionPane.INFORMATION_MESSAGE
     79        );
    9680    }
    9781}
  • trunk/src/org/openstreetmap/josm/actions/CopyCoordinatesAction.java

    r10448 r10604  
    1212import org.openstreetmap.josm.data.osm.Node;
    1313import org.openstreetmap.josm.data.osm.OsmPrimitive;
     14import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
    1415import org.openstreetmap.josm.tools.Shortcut;
    1516import org.openstreetmap.josm.tools.Utils;
     
    3536            s.append('\n');
    3637        }
    37         Utils.copyToClipboard(s.toString().trim());
     38        ClipboardUtils.copyString(s.toString().trim());
    3839    }
    3940
  • trunk/src/org/openstreetmap/josm/actions/DuplicateAction.java

    r10409 r10604  
    1212import org.openstreetmap.josm.Main;
    1313import org.openstreetmap.josm.data.osm.OsmPrimitive;
    14 import org.openstreetmap.josm.data.osm.PrimitiveDeepCopy;
     14import org.openstreetmap.josm.gui.datatransfer.OsmTransferHandler;
     15import org.openstreetmap.josm.gui.datatransfer.PrimitiveTransferable;
     16import org.openstreetmap.josm.gui.datatransfer.data.PrimitiveTransferData;
    1517import org.openstreetmap.josm.tools.Shortcut;
    1618
     19/**
     20 * An action that dupplicates the given nodes. They are not added to the clipboard.
     21 */
    1722public final class DuplicateAction extends JosmAction {
    1823
     
    2227    public DuplicateAction() {
    2328        super(tr("Duplicate"), "duplicate",
    24                 tr("Duplicate selection by copy and immediate paste."),
     29                tr("Duplicate selection."),
    2530                Shortcut.registerShortcut("system:duplicate", tr("Edit: {0}", tr("Duplicate")), KeyEvent.VK_D, Shortcut.CTRL), true);
    2631        putValue("help", ht("/Action/Duplicate"));
     
    2934    @Override
    3035    public void actionPerformed(ActionEvent e) {
    31         Main.main.menu.paste.pasteData(
    32                 new PrimitiveDeepCopy(getLayerManager().getEditDataSet().getSelected()), getLayerManager().getEditLayer(), e);
     36        PrimitiveTransferData data = PrimitiveTransferData.getDataWithReferences(getLayerManager().getEditDataSet().getSelected());
     37        new OsmTransferHandler().pasteOn(Main.getLayerManager().getEditLayer(), data.getCenter(), new PrimitiveTransferable(data));
    3338    }
    3439
  • trunk/src/org/openstreetmap/josm/actions/MapRectifierWMSmenuAction.java

    r10463 r10604  
    2323import org.openstreetmap.josm.data.imagery.ImageryInfo;
    2424import org.openstreetmap.josm.gui.ExtendedDialog;
     25import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
    2526import org.openstreetmap.josm.gui.layer.WMSLayer;
    2627import org.openstreetmap.josm.gui.widgets.JosmTextField;
     
    2829import org.openstreetmap.josm.tools.GBC;
    2930import org.openstreetmap.josm.tools.Shortcut;
    30 import org.openstreetmap.josm.tools.Utils;
    3131
    3232/**
     
    124124        JosmTextField tfWmsUrl = new JosmTextField(30);
    125125
    126         String clip = Utils.getClipboardContent();
     126        String clip = ClipboardUtils.getClipboardStringContent();
    127127        clip = clip == null ? "" : clip.trim();
    128128        ButtonGroup group = new ButtonGroup();
  • trunk/src/org/openstreetmap/josm/actions/PasteAction.java

    r10413 r10604  
    88import java.awt.MouseInfo;
    99import java.awt.Point;
     10import java.awt.datatransfer.FlavorEvent;
     11import java.awt.datatransfer.FlavorListener;
    1012import java.awt.event.ActionEvent;
    1113import java.awt.event.KeyEvent;
    12 import java.util.ArrayList;
    13 import java.util.HashMap;
    14 import java.util.List;
    15 import java.util.Map;
    1614
    1715import org.openstreetmap.josm.Main;
    18 import org.openstreetmap.josm.command.AddPrimitivesCommand;
    1916import org.openstreetmap.josm.data.coor.EastNorth;
    20 import org.openstreetmap.josm.data.osm.NodeData;
    21 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
    22 import org.openstreetmap.josm.data.osm.PrimitiveData;
    23 import org.openstreetmap.josm.data.osm.PrimitiveDeepCopy;
    24 import org.openstreetmap.josm.data.osm.PrimitiveDeepCopy.PasteBufferChangedListener;
    25 import org.openstreetmap.josm.data.osm.RelationData;
    26 import org.openstreetmap.josm.data.osm.RelationMemberData;
    27 import org.openstreetmap.josm.data.osm.WayData;
    28 import org.openstreetmap.josm.gui.ExtendedDialog;
    29 import org.openstreetmap.josm.gui.layer.Layer;
     17import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
     18import org.openstreetmap.josm.gui.datatransfer.OsmTransferHandler;
    3019import org.openstreetmap.josm.tools.Shortcut;
    3120
     
    3423 * @since 404
    3524 */
    36 public final class PasteAction extends JosmAction implements PasteBufferChangedListener {
     25public final class PasteAction extends JosmAction implements FlavorListener {
     26
     27    private final OsmTransferHandler transferHandler;
    3728
    3829    /**
     
    4637        Main.registerActionShortcut(this,
    4738                Shortcut.registerShortcut("system:paste:cua", tr("Edit: {0}", tr("Paste")), KeyEvent.VK_INSERT, Shortcut.SHIFT));
    48         Main.pasteBuffer.addPasteBufferChangedListener(this);
     39        transferHandler = new OsmTransferHandler();
     40        ClipboardUtils.getClipboard().addFlavorListener(this);
    4941    }
    5042
    5143    @Override
    5244    public void actionPerformed(ActionEvent e) {
    53         if (!isEnabled())
    54             return;
    55         pasteData(Main.pasteBuffer, Main.pasteSource, e);
    56     }
    57 
    58     /**
    59      * Paste OSM primitives from the given paste buffer and OSM data layer source to the current edit layer.
    60      * @param pasteBuffer The paste buffer containing primitive ids to copy
    61      * @param source The OSM data layer used to look for primitive ids
    62      * @param e The ActionEvent that triggered this operation
    63      */
    64     public void pasteData(PrimitiveDeepCopy pasteBuffer, Layer source, ActionEvent e) {
    65         /* Find the middle of the pasteBuffer area */
    66         double maxEast = -1E100;
    67         double minEast = 1E100;
    68         double maxNorth = -1E100;
    69         double minNorth = 1E100;
    70         boolean incomplete = false;
    71         for (PrimitiveData data : pasteBuffer.getAll()) {
    72             if (data instanceof NodeData) {
    73                 NodeData n = (NodeData) data;
    74                 if (n.getEastNorth() != null) {
    75                     double east = n.getEastNorth().east();
    76                     double north = n.getEastNorth().north();
    77                     if (east > maxEast) {
    78                         maxEast = east;
    79                     }
    80                     if (east < minEast) {
    81                         minEast = east;
    82                     }
    83                     if (north > maxNorth) {
    84                         maxNorth = north;
    85                     }
    86                     if (north < minNorth) {
    87                         minNorth = north;
    88                     }
    89                 }
    90             }
    91             if (data.isIncomplete()) {
    92                 incomplete = true;
    93             }
    94         }
    95 
    96         // Allow to cancel paste if there are incomplete primitives
    97         if (incomplete && !confirmDeleteIncomplete()) {
    98             return;
    99         }
    100 
    10145        // default to paste in center of map (pasted via menu or cursor not in MapView)
    10246        EastNorth mPosition = Main.map.mapView.getCenter();
     
    11357        }
    11458
    115         double offsetEast = mPosition.east() - (maxEast + minEast)/2.0;
    116         double offsetNorth = mPosition.north() - (maxNorth + minNorth)/2.0;
    117 
    118         // Make a copy of pasteBuffer and map from old id to copied data id
    119         List<PrimitiveData> bufferCopy = new ArrayList<>();
    120         List<PrimitiveData> toSelect = new ArrayList<>();
    121         Map<Long, Long> newNodeIds = new HashMap<>();
    122         Map<Long, Long> newWayIds = new HashMap<>();
    123         Map<Long, Long> newRelationIds = new HashMap<>();
    124         for (PrimitiveData data: pasteBuffer.getAll()) {
    125             if (data.isIncomplete()) {
    126                 continue;
    127             }
    128             PrimitiveData copy = data.makeCopy();
    129             copy.clearOsmMetadata();
    130             if (data instanceof NodeData) {
    131                 newNodeIds.put(data.getUniqueId(), copy.getUniqueId());
    132             } else if (data instanceof WayData) {
    133                 newWayIds.put(data.getUniqueId(), copy.getUniqueId());
    134             } else if (data instanceof RelationData) {
    135                 newRelationIds.put(data.getUniqueId(), copy.getUniqueId());
    136             }
    137             bufferCopy.add(copy);
    138             if (pasteBuffer.getDirectlyAdded().contains(data)) {
    139                 toSelect.add(copy);
    140             }
    141         }
    142 
    143         // Update references in copied buffer
    144         for (PrimitiveData data:bufferCopy) {
    145             if (data instanceof NodeData) {
    146                 NodeData nodeData = (NodeData) data;
    147                 if (Main.getLayerManager().getEditLayer() == source) {
    148                     nodeData.setEastNorth(nodeData.getEastNorth().add(offsetEast, offsetNorth));
    149                 }
    150             } else if (data instanceof WayData) {
    151                 List<Long> newNodes = new ArrayList<>();
    152                 for (Long oldNodeId: ((WayData) data).getNodes()) {
    153                     Long newNodeId = newNodeIds.get(oldNodeId);
    154                     if (newNodeId != null) {
    155                         newNodes.add(newNodeId);
    156                     }
    157                 }
    158                 ((WayData) data).setNodes(newNodes);
    159             } else if (data instanceof RelationData) {
    160                 List<RelationMemberData> newMembers = new ArrayList<>();
    161                 for (RelationMemberData member: ((RelationData) data).getMembers()) {
    162                     OsmPrimitiveType memberType = member.getMemberType();
    163                     Long newId;
    164                     switch (memberType) {
    165                     case NODE:
    166                         newId = newNodeIds.get(member.getMemberId());
    167                         break;
    168                     case WAY:
    169                         newId = newWayIds.get(member.getMemberId());
    170                         break;
    171                     case RELATION:
    172                         newId = newRelationIds.get(member.getMemberId());
    173                         break;
    174                     default: throw new AssertionError();
    175                     }
    176                     if (newId != null) {
    177                         newMembers.add(new RelationMemberData(member.getRole(), memberType, newId));
    178                     }
    179                 }
    180                 ((RelationData) data).setMembers(newMembers);
    181             }
    182         }
    183 
    184         /* Now execute the commands to add the duplicated contents of the paste buffer to the map */
    185         Main.main.undoRedo.add(new AddPrimitivesCommand(bufferCopy, toSelect));
    186         Main.map.mapView.repaint();
    187     }
    188 
    189     private static boolean confirmDeleteIncomplete() {
    190         ExtendedDialog ed = new ExtendedDialog(Main.parent,
    191                 tr("Delete incomplete members?"),
    192                 new String[] {tr("Paste without incomplete members"), tr("Cancel")});
    193         ed.setButtonIcons(new String[] {"dialogs/relation/deletemembers", "cancel"});
    194         ed.setContent(tr("The copied data contains incomplete objects.  "
    195                 + "When pasting the incomplete objects are removed.  "
    196                 + "Do you want to paste the data without the incomplete objects?"));
    197         ed.showDialog();
    198         return ed.getValue() == 1;
     59        transferHandler.pasteOn(Main.getLayerManager().getEditLayer(), mPosition);
    19960    }
    20061
    20162    @Override
    20263    protected void updateEnabledState() {
    203         if (getLayerManager().getEditDataSet() == null || Main.pasteBuffer == null) {
    204             setEnabled(false);
    205             return;
    206         }
    207         setEnabled(!Main.pasteBuffer.isEmpty());
     64        setEnabled(getLayerManager().getEditDataSet() != null && transferHandler.isDataAvailable());
    20865    }
    20966
    21067    @Override
    211     public void pasteBufferChanged(PrimitiveDeepCopy pasteBuffer) {
     68    public void flavorsChanged(FlavorEvent e) {
    21269        updateEnabledState();
    21370    }
  • trunk/src/org/openstreetmap/josm/actions/PasteTagsAction.java

    r10383 r10604  
    2626import org.openstreetmap.josm.data.osm.TagCollection;
    2727import org.openstreetmap.josm.gui.conflict.tags.PasteTagsConflictResolverDialog;
     28import org.openstreetmap.josm.gui.datatransfer.OsmTransferHandler;
    2829import org.openstreetmap.josm.tools.I18n;
    2930import org.openstreetmap.josm.tools.Shortcut;
    3031import org.openstreetmap.josm.tools.TextTagParser;
    31 import org.openstreetmap.josm.tools.Utils;
    3232
    3333/**
     
    4242
    4343    private static final String help = ht("/Action/PasteTags");
     44    private final OsmTransferHandler transferHandler = new OsmTransferHandler();
    4445
    4546    /**
     
    5455    }
    5556
     57    /**
     58     * Used to update the tags.
     59     */
    5660    public static class TagPaster {
    5761
     
    259263            return;
    260264
    261         String buf = Utils.getClipboardContent();
    262         if (buf == null || buf.isEmpty() || buf.matches(CopyAction.CLIPBOARD_REGEXP)) {
    263             pasteTagsFromJOSMBuffer(selection);
    264         } else {
    265             // Paste tags from arbitrary text
    266             pasteTagsFromText(selection, buf);
    267         }
     265        transferHandler.pasteTags(selection);
    268266    }
    269267
     
    290288        commitCommands(selection, commands);
    291289        return !commands.isEmpty();
    292     }
    293 
    294     /**
    295      * Paste tags from JOSM buffer
    296      * @param selection objects that will have the tags
    297      * @return false if JOSM buffer was empty
    298      */
    299     public static boolean pasteTagsFromJOSMBuffer(Collection<OsmPrimitive> selection) {
    300         List<PrimitiveData> directlyAdded = Main.pasteBuffer.getDirectlyAdded();
    301         if (directlyAdded == null || directlyAdded.isEmpty()) return false;
    302 
    303         PasteTagsAction.TagPaster tagPaster = new PasteTagsAction.TagPaster(directlyAdded, selection);
    304         List<Command> commands = new ArrayList<>();
    305         for (Tag tag : tagPaster.execute()) {
    306             commands.add(new ChangePropertyCommand(selection, tag.getKey(), "".equals(tag.getValue()) ? null : tag.getValue()));
    307         }
    308         commitCommands(selection, commands);
    309         return true;
    310290    }
    311291
Note: See TracChangeset for help on using the changeset viewer.