Ignore:
Timestamp:
2016-07-23T14:54:19+02:00 (8 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/gui
Files:
12 added
23 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/MapFrame.java

    r10600 r10604  
    99import java.awt.Dimension;
    1010import java.awt.Font;
    11 import java.awt.GraphicsEnvironment;
    1211import java.awt.GridBagLayout;
    1312import java.awt.Rectangle;
     
    197196
    198197        mapView = new MapView(Main.getLayerManager(), contentPane, viewportData);
    199         if (!GraphicsEnvironment.isHeadless()) {
    200             new FileDrop(mapView);
    201         }
    202198
    203199        splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true);
  • trunk/src/org/openstreetmap/josm/gui/MapView.java

    r10600 r10604  
    5353import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache;
    5454import org.openstreetmap.josm.gui.MapViewState.MapViewRectangle;
     55import org.openstreetmap.josm.gui.datatransfer.OsmTransferHandler;
    5556import org.openstreetmap.josm.gui.layer.AbstractMapViewPaintable;
    5657import org.openstreetmap.josm.gui.layer.GpxLayer;
     
    581582            add(c);
    582583        }
     584        setTransferHandler(new OsmTransferHandler());
    583585    }
    584586
  • trunk/src/org/openstreetmap/josm/gui/datatransfer/PrimitiveTransferable.java

    r9969 r10604  
    55import java.awt.datatransfer.Transferable;
    66import java.awt.datatransfer.UnsupportedFlavorException;
    7 import java.io.Serializable;
    87import java.util.ArrayList;
    9 import java.util.Collection;
     8import java.util.Arrays;
     9import java.util.List;
    1010
    11 import org.openstreetmap.josm.data.osm.OsmPrimitive;
     11import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
    1212import org.openstreetmap.josm.data.osm.PrimitiveData;
    13 import org.openstreetmap.josm.gui.DefaultNameFormatter;
    14 import org.openstreetmap.josm.tools.CheckParameterUtil;
     13import org.openstreetmap.josm.gui.datatransfer.data.PrimitiveTransferData;
     14import org.openstreetmap.josm.gui.datatransfer.data.TagTransferData;
    1515
    1616/**
    17  * Transferable objects for {@link PrimitiveData}.
     17 * Transferable objects for {@link PrimitiveTransferData} objects
    1818 * @since 9369
     19 * @since 10604 Complete rework
    1920 */
    2021public class PrimitiveTransferable implements Transferable {
    2122
    2223    /**
    23      * A wrapper for a collection of {@link PrimitiveData}.
     24     * The flavors that are available for normal primitives.
    2425     */
    25     public static final class Data implements Serializable {
    26         private static final long serialVersionUID = -1485089993600213704L;
    27         private final Collection<PrimitiveData> primitiveData;
    28 
    29         private Data(Collection<PrimitiveData> primitiveData) {
    30             CheckParameterUtil.ensureThat(primitiveData instanceof Serializable, "primitiveData must be instanceof Serializable");
    31             this.primitiveData = primitiveData;
    32         }
    33 
    34         /**
    35          * Returns the contained {@link PrimitiveData}
    36          * @return the contained {@link PrimitiveData}
    37          */
    38         public Collection<PrimitiveData> getPrimitiveData() {
    39             return primitiveData;
    40         }
    41     }
    42 
    43     /**
    44      * Data flavor for {@link PrimitiveData} which is wrapped in {@link Data}.
    45      */
    46     public static final DataFlavor PRIMITIVE_DATA = new DataFlavor(Data.class, Data.class.getName());
    47     private final Collection<? extends OsmPrimitive> primitives;
     26    private static final List<DataFlavor> PRIMITIVE_FLAVORS = Arrays.asList(PrimitiveTransferData.DATA_FLAVOR,
     27            TagTransferData.FLAVOR, DataFlavor.stringFlavor);
     28    private final PrimitiveTransferData primitives;
    4829
    4930    /**
     
    5132     * @param primitives collection of OSM primitives
    5233     */
    53     public PrimitiveTransferable(Collection<? extends OsmPrimitive> primitives) {
     34    public PrimitiveTransferable(PrimitiveTransferData primitives) {
    5435        this.primitives = primitives;
    5536    }
     
    5738    @Override
    5839    public DataFlavor[] getTransferDataFlavors() {
    59         return new DataFlavor[]{PRIMITIVE_DATA, DataFlavor.stringFlavor};
     40        ArrayList<DataFlavor> flavors = new ArrayList<>(PRIMITIVE_FLAVORS);
     41        return flavors.toArray(new DataFlavor[flavors.size()]);
    6042    }
    6143
    6244    @Override
    6345    public boolean isDataFlavorSupported(DataFlavor flavor) {
    64         return flavor == PRIMITIVE_DATA;
     46        DataFlavor[] flavors = getTransferDataFlavors();
     47        for (DataFlavor f : flavors) {
     48            if (flavor.equals(f)) {
     49                return true;
     50            }
     51        }
     52        return false;
    6553    }
    6654
     
    6957        if (DataFlavor.stringFlavor.equals(flavor)) {
    7058            return getStringData();
    71         } else if (PRIMITIVE_DATA.equals(flavor)) {
    72             return getPrimitiveData();
     59        } else if (PrimitiveTransferData.DATA_FLAVOR.equals(flavor)) {
     60            return primitives;
     61        } else if (TagTransferData.FLAVOR.equals(flavor)) {
     62            return new TagTransferData(primitives.getDirectlyAdded());
     63        } else {
     64            throw new UnsupportedFlavorException(flavor);
    7365        }
    74         throw new UnsupportedFlavorException(flavor);
    7566    }
    7667
    7768    protected String getStringData() {
    7869        final StringBuilder sb = new StringBuilder();
    79         for (OsmPrimitive primitive : primitives) {
    80             sb.append(primitive.getType())
    81               .append(' ').append(primitive.getUniqueId())
    82               .append(" # ").append(primitive.getDisplayName(DefaultNameFormatter.getInstance()))
    83               .append('\n');
     70        for (PrimitiveData primitive : primitives.getAll()) {
     71            if (sb.length() > 0) {
     72                sb.append("\n");
     73            }
     74            sb.append(OsmPrimitiveType.from(primitive).getAPIName()).append(' ').append(primitive.getId());
    8475        }
    8576        return sb.toString().replace("\u200E", "").replace("\u200F", "");
    8677    }
    87 
    88     protected Data getPrimitiveData() {
    89         final Collection<PrimitiveData> r = new ArrayList<>(primitives.size());
    90         for (OsmPrimitive primitive : primitives) {
    91             r.add(primitive.save());
    92         }
    93         return new Data(r);
    94     }
    9578}
  • trunk/src/org/openstreetmap/josm/gui/datatransfer/RelationMemberTransferable.java

    r9969 r10604  
    77import java.io.Serializable;
    88import java.util.ArrayList;
     9import java.util.Arrays;
    910import java.util.Collection;
     11import java.util.Collections;
     12import java.util.HashSet;
    1013
     14import org.openstreetmap.josm.data.osm.OsmPrimitive;
    1115import org.openstreetmap.josm.data.osm.RelationMember;
    1216import org.openstreetmap.josm.data.osm.RelationMemberData;
    1317import org.openstreetmap.josm.gui.DefaultNameFormatter;
     18import org.openstreetmap.josm.gui.datatransfer.data.PrimitiveTransferData;
    1419import org.openstreetmap.josm.tools.CheckParameterUtil;
    1520
     
    3742         */
    3843        public Collection<RelationMemberData> getRelationMemberData() {
    39             return relationMemberDatas;
     44            return Collections.unmodifiableCollection(relationMemberDatas);
     45        }
     46
     47        /**
     48         * Gets the Data for the given list of members.
     49         * @param members The collection. The order is preserved.
     50         * @return The data.
     51         */
     52        public static Data getData(Collection<RelationMember> members) {
     53            final Collection<RelationMemberData> r = new ArrayList<>(members.size());
     54            for (RelationMember member : members) {
     55                r.add(new RelationMemberData(member.getRole(), member.getType(), member.getUniqueId()));
     56            }
     57            return new Data(r);
    4058        }
    4159    }
     
    4462     * Data flavor for {@link RelationMemberData} which is wrapped in {@link Data}.
    4563     */
    46     public static final DataFlavor RELATION_MEMBER_DATA = new DataFlavor(Data.class, Data.class.getName());
     64    public static final DataFlavor RELATION_MEMBER_DATA = new DataFlavor(Data.class, "Relation member");
    4765    private final Collection<RelationMember> members;
    4866
     
    5270     */
    5371    public RelationMemberTransferable(Collection<RelationMember> members) {
    54         this.members = members;
     72        this.members = new ArrayList<>(members);
    5573    }
    5674
    5775    @Override
    5876    public DataFlavor[] getTransferDataFlavors() {
    59         return new DataFlavor[]{RELATION_MEMBER_DATA, DataFlavor.stringFlavor};
     77        return new DataFlavor[]{RELATION_MEMBER_DATA, PrimitiveTransferData.DATA_FLAVOR, DataFlavor.stringFlavor};
    6078    }
    6179
    6280    @Override
    6381    public boolean isDataFlavorSupported(DataFlavor flavor) {
    64         return flavor == RELATION_MEMBER_DATA;
     82        return Arrays.asList(getTransferDataFlavors()).contains(flavor);
    6583    }
    6684
     
    7189        } else if (RELATION_MEMBER_DATA.equals(flavor)) {
    7290            return getRelationMemberData();
     91        } else if (PrimitiveTransferData.DATA_FLAVOR.equals(flavor)) {
     92            return getPrimitiveData();
    7393        }
    7494        throw new UnsupportedFlavorException(flavor);
     95    }
     96
     97    private PrimitiveTransferData getPrimitiveData() {
     98        Collection<OsmPrimitive> primitives = new HashSet<>();
     99        for (RelationMember member : members) {
     100            primitives.add(member.getMember());
     101        }
     102        return PrimitiveTransferData.getData(primitives);
    75103    }
    76104
     
    88116
    89117    protected Data getRelationMemberData() {
    90         final Collection<RelationMemberData> r = new ArrayList<>(members.size());
    91         for (RelationMember member : members) {
    92             r.add(new RelationMemberData(member.getRole(), member.getType(), member.getUniqueId()));
    93         }
    94         return new Data(r);
     118        return Data.getData(members);
    95119    }
    96120}
  • trunk/src/org/openstreetmap/josm/gui/dialogs/OsmIdSelectionDialog.java

    r10173 r10604  
    3434import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
    3535import org.openstreetmap.josm.gui.ExtendedDialog;
     36import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
    3637import org.openstreetmap.josm.gui.widgets.HistoryComboBox;
    3738import org.openstreetmap.josm.gui.widgets.HtmlPanel;
     
    202203
    203204    protected void tryToPasteFromClipboard(OsmIdTextField tfId, OsmPrimitiveTypesComboBox cbType) {
    204         String buf = Utils.getClipboardContent();
     205        String buf = ClipboardUtils.getClipboardStringContent();
    205206        if (buf == null || buf.isEmpty()) return;
    206207        if (buf.length() > Main.pref.getInteger("downloadprimitive.max-autopaste-length", 2000)) return;
  • trunk/src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java

    r10453 r10604  
    7070import org.openstreetmap.josm.gui.SideButton;
    7171import org.openstreetmap.josm.gui.datatransfer.PrimitiveTransferable;
     72import org.openstreetmap.josm.gui.datatransfer.data.PrimitiveTransferData;
    7273import org.openstreetmap.josm.gui.history.HistoryBrowserDialogManager;
    7374import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeEvent;
     
    881882        @Override
    882883        protected Transferable createTransferable(JComponent c) {
    883             return new PrimitiveTransferable(getSelectedPrimitives());
     884            return new PrimitiveTransferable(PrimitiveTransferData.getData(getSelectedPrimitives()));
    884885        }
    885886    }
  • trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PropertiesDialog.java

    r10446 r10604  
    8787import org.openstreetmap.josm.gui.PopupMenuHandler;
    8888import org.openstreetmap.josm.gui.SideButton;
     89import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
    8990import org.openstreetmap.josm.gui.dialogs.ToggleDialog;
    9091import org.openstreetmap.josm.gui.dialogs.relation.RelationEditor;
     
    12651266            String key = editHelper.getDataKey(tagTable.getSelectedRow());
    12661267            Collection<OsmPrimitive> sel = Main.main.getInProgressSelection();
    1267             String clipboard = Utils.getClipboardContent();
     1268            String clipboard = ClipboardUtils.getClipboardStringContent();
    12681269            if (sel.isEmpty() || clipboard == null)
    12691270                return;
     
    12951296            }
    12961297            if (!values.isEmpty()) {
    1297                 Utils.copyToClipboard(Utils.join("\n", values));
     1298                ClipboardUtils.copyString(Utils.join("\n", values));
    12981299            }
    12991300        }
  • trunk/src/org/openstreetmap/josm/gui/dialogs/properties/TagEditHelper.java

    r10413 r10604  
    7777import org.openstreetmap.josm.data.preferences.StringProperty;
    7878import org.openstreetmap.josm.gui.ExtendedDialog;
     79import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
    7980import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
    8081import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingComboBox;
     
    584585        private void selectACComboBoxSavingUnixBuffer(AutoCompletingComboBox cb) {
    585586            // select combobox with saving unix system selection (middle mouse paste)
    586             Clipboard sysSel = GuiHelper.getSystemSelection();
     587            Clipboard sysSel = ClipboardUtils.getSystemSelection();
    587588            if (sysSel != null) {
    588                 Transferable old = Utils.getTransferableContent(sysSel);
     589                Transferable old = ClipboardUtils.getClipboardContent(sysSel);
    589590                cb.requestFocusInWindow();
    590591                cb.getEditor().selectAll();
  • trunk/src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java

    r10454 r10604  
    1212import java.awt.GridBagLayout;
    1313import java.awt.Window;
     14import java.awt.datatransfer.Clipboard;
     15import java.awt.datatransfer.FlavorListener;
    1416import java.awt.event.ActionEvent;
    1517import java.awt.event.FocusAdapter;
     
    6264import org.openstreetmap.josm.gui.DefaultNameFormatter;
    6365import org.openstreetmap.josm.gui.MainMenu;
     66import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
    6467import org.openstreetmap.josm.gui.dialogs.relation.actions.AddSelectedAfterSelection;
    6568import org.openstreetmap.josm.gui.dialogs.relation.actions.AddSelectedAtEndAction;
     
    153156     */
    154157    private final CancelAction cancelAction;
     158    /**
     159     * A list of listeners that need to be notified on clipboard content changes.
     160     */
     161    private final ArrayList<FlavorListener> clipboardListeners = new ArrayList<>();
    155162
    156163    /**
     
    274281        // CHECKSTYLE.ON: LineLength
    275282
    276         registerCopyPasteAction(new PasteMembersAction(memberTableModel, getLayer(), this) {
     283        registerCopyPasteAction(new PasteMembersAction(memberTable, getLayer(), this) {
    277284            @Override
    278285            public void actionPerformed(ActionEvent e) {
     
    743750        }
    744751        super.setVisible(visible);
     752        Clipboard clipboard = ClipboardUtils.getClipboard();
    745753        if (visible) {
    746754            leftButtonToolbar.sortBelowButton.setVisible(ExpertToggleAction.isExpert());
     
    750758            }
    751759            tagEditorPanel.requestFocusInWindow();
     760            for (FlavorListener listener : clipboardListeners) {
     761                clipboard.addFlavorListener(listener);
     762            }
    752763        } else {
    753764            // make sure all registered listeners are unregistered
     
    760771                Main.main.menu.windowMenu.remove(windowMenuItem);
    761772                windowMenuItem = null;
     773            }
     774            for (FlavorListener listener : clipboardListeners) {
     775                clipboard.removeFlavorListener(listener);
    762776            }
    763777            dispose();
     
    824838    }
    825839
    826     private static void registerCopyPasteAction(AbstractAction action, Object actionName, KeyStroke shortcut,
     840    private void registerCopyPasteAction(AbstractAction action, Object actionName, KeyStroke shortcut,
    827841            JRootPane rootPane, JTable... tables) {
    828842        int mods = shortcut.getModifiers();
     
    840854            table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(shortcut, actionName);
    841855            table.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(shortcut, actionName);
     856        }
     857        if (action instanceof FlavorListener) {
     858            clipboardListeners.add((FlavorListener) action);
    842859        }
    843860    }
  • trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTable.java

    r10478 r10604  
    8686        zoomToGap = new ZoomToGapAction();
    8787        registerListeners();
     88        menu.addSeparator();
    8889        getSelectionModel().addListSelectionListener(zoomToGap);
    8990        menu.add(zoomToGap);
  • trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java

    r10413 r10604  
    480480        }
    481481        invalidateConnectionType();
    482         final List<Integer> selection = getSelectedIndices();
    483482        fireTableRowsInserted(index, idx - 1);
    484         setSelectedMembersIdx(selection);
    485483    }
    486484
  • trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTransferHandler.java

    r10212 r10604  
    1717import org.openstreetmap.josm.data.osm.OsmPrimitive;
    1818import org.openstreetmap.josm.data.osm.PrimitiveData;
     19import org.openstreetmap.josm.data.osm.PrimitiveId;
    1920import org.openstreetmap.josm.data.osm.RelationMember;
    2021import org.openstreetmap.josm.data.osm.RelationMemberData;
    21 import org.openstreetmap.josm.gui.datatransfer.PrimitiveTransferable;
    2222import org.openstreetmap.josm.gui.datatransfer.RelationMemberTransferable;
    23 import org.openstreetmap.josm.tools.Utils.Function;
     23import org.openstreetmap.josm.gui.datatransfer.data.PrimitiveTransferData;
    2424
    25 class MemberTransferHandler extends TransferHandler {
     25/**
     26 * A transfer handler that helps with importing / exporting members for relations.
     27 * @author Michael Zangl
     28 * @since 10604
     29 */
     30public class MemberTransferHandler extends TransferHandler {
    2631
    2732    @Override
     
    3843    @Override
    3944    public boolean canImport(TransferSupport support) {
    40         support.setShowDropLocation(true);
     45        if (support.isDrop()) {
     46            support.setShowDropLocation(true);
     47        }
    4148        return support.isDataFlavorSupported(RelationMemberTransferable.RELATION_MEMBER_DATA)
    42                 || support.isDataFlavorSupported(PrimitiveTransferable.PRIMITIVE_DATA);
     49                || support.isDataFlavorSupported(PrimitiveTransferData.DATA_FLAVOR);
    4350    }
    4451
    4552    @Override
    4653    public boolean importData(TransferSupport support) {
    47         final MemberTable destination = (MemberTable) support.getComponent();
    48         final int insertRow = ((JTable.DropLocation) support.getDropLocation()).getRow();
     54        MemberTable destination = (MemberTable) support.getComponent();
     55        int insertRow = computeInsertionRow(support, destination);
    4956
     57        return importDataAt(support, destination, insertRow);
     58    }
     59
     60    private int computeInsertionRow(TransferSupport support, MemberTable destination) {
     61        final int insertRow;
     62        if (support.isDrop()) {
     63            insertRow = ((JTable.DropLocation) support.getDropLocation()).getRow();
     64        } else {
     65            int selection = destination.getSelectedRow();
     66            if (selection < 0) {
     67                // no selection, add at the end.
     68                insertRow = destination.getRowCount();
     69            } else {
     70                insertRow = selection;
     71            }
     72        }
     73        return insertRow;
     74    }
     75
     76    private boolean importDataAt(TransferSupport support, MemberTable destination, int insertRow) {
    5077        try {
    5178            if (support.isDataFlavorSupported(RelationMemberTransferable.RELATION_MEMBER_DATA)) {
    5279                importRelationMemberData(support, destination, insertRow);
    53             } else if (support.isDataFlavorSupported(PrimitiveTransferable.PRIMITIVE_DATA)) {
     80                return true;
     81            } else if (support.isDataFlavorSupported(PrimitiveTransferData.DATA_FLAVOR)) {
    5482                importPrimitiveData(support, destination, insertRow);
     83                return true;
     84            } else {
     85                return false;
    5586            }
    5687        } catch (IOException | UnsupportedFlavorException e) {
     
    5889            return false;
    5990        }
    60 
    61         return true;
    6291    }
    6392
     
    6695        final RelationMemberTransferable.Data memberData = (RelationMemberTransferable.Data)
    6796                support.getTransferable().getTransferData(RelationMemberTransferable.RELATION_MEMBER_DATA);
    68         importData(destination, insertRow, memberData.getRelationMemberData(), new Function<RelationMemberData, RelationMember>() {
     97        importData(destination, insertRow, memberData.getRelationMemberData(), new AbstractRelationMemberConverter<RelationMemberData>() {
    6998            @Override
    70             public RelationMember apply(RelationMemberData member) {
    71                 final OsmPrimitive p = destination.getLayer().data.getPrimitiveById(member.getUniqueId(), member.getType());
    72                 if (p == null) {
    73                     Main.warn(tr("Cannot add {0} since it is not part of dataset", member));
    74                     return null;
    75                 } else {
    76                     return new RelationMember(member.getRole(), p);
    77                 }
     99            protected RelationMember getMember(MemberTable destination, RelationMemberData data, OsmPrimitive p) {
     100                return new RelationMember(data.getRole(), p);
    78101            }
    79102        });
     
    82105    protected void importPrimitiveData(TransferSupport support, final MemberTable destination, int insertRow)
    83106            throws UnsupportedFlavorException, IOException {
    84         final PrimitiveTransferable.Data data = (PrimitiveTransferable.Data)
    85                 support.getTransferable().getTransferData(PrimitiveTransferable.PRIMITIVE_DATA);
    86         importData(destination, insertRow, data.getPrimitiveData(), new Function<PrimitiveData, RelationMember>() {
     107        final PrimitiveTransferData data = (PrimitiveTransferData)
     108                support.getTransferable().getTransferData(PrimitiveTransferData.DATA_FLAVOR);
     109        importData(destination, insertRow, data.getDirectlyAdded(), new AbstractRelationMemberConverter<PrimitiveData>() {
    87110            @Override
    88             public RelationMember apply(PrimitiveData data) {
    89                 final OsmPrimitive p = destination.getLayer().data.getPrimitiveById(data);
    90                 if (p == null) {
    91                     Main.warn(tr("Cannot add {0} since it is not part of dataset", data));
    92                     return null;
    93                 } else {
    94                     return destination.getMemberTableModel().getRelationMemberForPrimitive(p);
    95                 }
     111            protected RelationMember getMember(MemberTable destination, PrimitiveData data, OsmPrimitive p) {
     112                return destination.getMemberTableModel().getRelationMemberForPrimitive(p);
    96113            }
    97114        });
    98115    }
    99116
    100     protected <T> void importData(MemberTable destination, int insertRow,
    101                                   Collection<T> memberData, Function<T, RelationMember> toMemberFunction) {
     117    protected <T extends PrimitiveId> void importData(MemberTable destination, int insertRow,
     118                                  Collection<T> memberData, AbstractRelationMemberConverter<T> toMemberFunction) {
    102119        final Collection<RelationMember> membersToAdd = new ArrayList<>(memberData.size());
    103         for (T i : memberData) {
    104             final RelationMember member = toMemberFunction.apply(i);
     120        for (T data : memberData) {
     121            final RelationMember member = toMemberFunction.importPrimitive(destination, data);
    105122            if (member != null) {
    106123                membersToAdd.add(member);
     
    120137        model.selectionChanged(null);
    121138    }
     139
     140    private abstract static class AbstractRelationMemberConverter<T extends PrimitiveId> {
     141        protected RelationMember importPrimitive(MemberTable destination, T data) {
     142            final OsmPrimitive p = destination.getLayer().data.getPrimitiveById(data);
     143            if (p == null) {
     144                Main.warn(tr("Cannot add {0} since it is not part of dataset", data));
     145                return null;
     146            } else {
     147                return getMember(destination, data, p);
     148            }
     149        }
     150
     151        protected abstract RelationMember getMember(MemberTable destination, T data, OsmPrimitive p);
     152    }
    122153}
  • trunk/src/org/openstreetmap/josm/gui/dialogs/relation/actions/CopyMembersAction.java

    r9710 r10604  
    55import java.util.Collection;
    66
    7 import org.openstreetmap.josm.actions.CopyAction;
    8 import org.openstreetmap.josm.data.osm.OsmPrimitive;
     7import org.openstreetmap.josm.data.osm.RelationMember;
     8import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
     9import org.openstreetmap.josm.gui.datatransfer.RelationMemberTransferable;
    910import org.openstreetmap.josm.gui.dialogs.relation.IRelationEditor;
    1011import org.openstreetmap.josm.gui.dialogs.relation.MemberTableModel;
     
    2930    @Override
    3031    public void actionPerformed(ActionEvent e) {
    31         final Collection<OsmPrimitive> primitives = memberTableModel.getSelectedChildPrimitives();
    32         if (!primitives.isEmpty()) {
    33             CopyAction.copy(layer, primitives);
     32        final Collection<RelationMember> members = memberTableModel.getSelectedMembers();
     33
     34        if (!members.isEmpty()) {
     35            ClipboardUtils.copy(new RelationMemberTransferable(members));
    3436        }
    3537    }
  • trunk/src/org/openstreetmap/josm/gui/dialogs/relation/actions/PasteMembersAction.java

    r10420 r10604  
    22package org.openstreetmap.josm.gui.dialogs.relation.actions;
    33
    4 import static org.openstreetmap.josm.tools.I18n.tr;
     4import java.awt.datatransfer.FlavorEvent;
     5import java.awt.datatransfer.FlavorListener;
     6import java.awt.event.ActionEvent;
    57
    6 import java.awt.event.ActionEvent;
    7 import java.util.ArrayList;
    8 import java.util.List;
     8import javax.swing.TransferHandler.TransferSupport;
    99
    10 import javax.swing.JOptionPane;
    11 
    12 import org.openstreetmap.josm.Main;
    13 import org.openstreetmap.josm.data.osm.DataSet;
    14 import org.openstreetmap.josm.data.osm.OsmPrimitive;
    15 import org.openstreetmap.josm.data.osm.PrimitiveData;
    16 import org.openstreetmap.josm.gui.dialogs.relation.GenericRelationEditor.AddAbortException;
     10import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
    1711import org.openstreetmap.josm.gui.dialogs.relation.IRelationEditor;
    18 import org.openstreetmap.josm.gui.dialogs.relation.MemberTableModel;
     12import org.openstreetmap.josm.gui.dialogs.relation.MemberTable;
     13import org.openstreetmap.josm.gui.dialogs.relation.MemberTransferHandler;
    1914import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    2015
     
    2318 * @since 9496
    2419 */
    25 public class PasteMembersAction extends AddFromSelectionAction {
     20public class PasteMembersAction extends AddFromSelectionAction implements FlavorListener {
    2621
    2722    /**
    2823     * Constructs a new {@code PasteMembersAction}.
    29      * @param memberTableModel member table model
     24     * @param memberTable member table
    3025     * @param layer OSM data layer
    3126     * @param editor relation editor
    3227     */
    33     public PasteMembersAction(MemberTableModel memberTableModel, OsmDataLayer layer, IRelationEditor editor) {
    34         super(null, memberTableModel, null, null, null, layer, editor);
     28    public PasteMembersAction(MemberTable memberTable, OsmDataLayer layer, IRelationEditor editor) {
     29        super(memberTable, null, null, null, null, layer, editor);
     30        updateEnabledState();
    3531    }
    3632
    3733    @Override
    3834    public void actionPerformed(ActionEvent e) {
    39         try {
    40             List<PrimitiveData> primitives = Main.pasteBuffer.getDirectlyAdded();
    41             DataSet ds = layer.data;
    42             List<OsmPrimitive> toAdd = new ArrayList<>();
    43             boolean hasNewInOtherLayer = false;
     35        new MemberTransferHandler().importData(getSupport());
     36    }
    4437
    45             for (PrimitiveData primitive: primitives) {
    46                 OsmPrimitive primitiveInDs = ds.getPrimitiveById(primitive);
    47                 if (primitiveInDs != null) {
    48                     toAdd.add(primitiveInDs);
    49                 } else if (!primitive.isNew()) {
    50                     OsmPrimitive p = primitive.getType().newInstance(primitive.getUniqueId(), true);
    51                     ds.addPrimitive(p);
    52                     toAdd.add(p);
    53                 } else {
    54                     hasNewInOtherLayer = true;
    55                     break;
    56                 }
    57             }
    58 
    59             if (hasNewInOtherLayer) {
    60                 JOptionPane.showMessageDialog(Main.parent,
    61                         tr("Members from paste buffer cannot be added because they are not included in current layer"));
    62                 return;
    63             }
    64 
    65             toAdd = filterConfirmedPrimitives(toAdd);
    66             int index = memberTableModel.getSelectionModel().getMaxSelectionIndex();
    67             if (index == -1) {
    68                 index = memberTableModel.getRowCount() - 1;
    69             }
    70             memberTableModel.addMembersAfterIdx(toAdd, index);
    71 
    72         } catch (AddAbortException ex) {
    73             Main.trace(ex);
    74         }
     38    private TransferSupport getSupport() {
     39        return new TransferSupport(memberTable, ClipboardUtils.getClipboard().getContents(null));
    7540    }
    7641
    7742    @Override
    7843    protected void updateEnabledState() {
    79         // Do nothing
     44        setEnabled(new MemberTransferHandler().canImport(getSupport()));
     45    }
     46
     47    @Override
     48    public void flavorsChanged(FlavorEvent e) {
     49        updateEnabledState();
    8050    }
    8151}
  • trunk/src/org/openstreetmap/josm/gui/download/DownloadDialog.java

    r10424 r10604  
    3939import org.openstreetmap.josm.data.Bounds;
    4040import org.openstreetmap.josm.gui.MapView;
     41import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
    4142import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction;
    4243import org.openstreetmap.josm.gui.help.HelpUtil;
     
    4849import org.openstreetmap.josm.tools.InputMapUtils;
    4950import org.openstreetmap.josm.tools.OsmUrlToBounds;
    50 import org.openstreetmap.josm.tools.Utils;
    5151import org.openstreetmap.josm.tools.WindowGeometry;
    5252
     
    243243            @Override
    244244            public void actionPerformed(ActionEvent e) {
    245                 String clip = Utils.getClipboardContent();
     245                String clip = ClipboardUtils.getClipboardStringContent();
    246246                if (clip == null) {
    247247                    return;
  • trunk/src/org/openstreetmap/josm/gui/layer/NoteLayer.java

    r10484 r10604  
    3131import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
    3232import org.openstreetmap.josm.gui.MapView;
     33import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
    3334import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
    3435import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
     
    4142import org.openstreetmap.josm.tools.ColorHelper;
    4243import org.openstreetmap.josm.tools.ImageProvider;
    43 import org.openstreetmap.josm.tools.Utils;
    4444import org.openstreetmap.josm.tools.date.DateUtils;
    4545
     
    238238        if (SwingUtilities.isRightMouseButton(e) && noteData.getSelectedNote() != null) {
    239239            final String url = OsmApi.getOsmApi().getBaseUrl() + "notes/" + noteData.getSelectedNote().getId();
    240             Utils.copyToClipboard(url);
     240            ClipboardUtils.copyString(url);
    241241            return;
    242242        } else if (!SwingUtilities.isLeftMouseButton(e)) {
  • trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java

    r10436 r10604  
    5353import org.openstreetmap.josm.gui.NavigatableComponent;
    5454import org.openstreetmap.josm.gui.PleaseWaitRunnable;
     55import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
    5556import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
    5657import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
     
    725726    public void copyCurrentPhotoPath() {
    726727        if (data != null && !data.isEmpty() && currentPhoto >= 0 && currentPhoto < data.size()) {
    727             Utils.copyToClipboard(data.get(currentPhoto).getFile().toString());
     728            ClipboardUtils.copyString(data.get(currentPhoto).getFile().toString());
    728729        }
    729730    }
  • trunk/src/org/openstreetmap/josm/gui/tagging/TagEditorModel.java

    r10217 r10604  
    88import java.util.ArrayList;
    99import java.util.Collection;
     10import java.util.Collections;
    1011import java.util.Comparator;
    1112import java.util.EnumSet;
     
    2526import org.openstreetmap.josm.data.osm.Tag;
    2627import org.openstreetmap.josm.data.osm.TagCollection;
     28import org.openstreetmap.josm.data.osm.TagMap;
    2729import org.openstreetmap.josm.data.osm.Tagged;
    2830import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetType;
     
    4749
    4850    private transient OsmPrimitive primitive;
     51
     52    private EndEditListener endEditListener;
    4953
    5054    /**
     
    167171     */
    168172    public void clear() {
     173        commitPendingEdit();
    169174        boolean wasEmpty = tags.isEmpty();
    170175        tags.clear();
     
    183188     */
    184189    public void add(TagModel tag) {
     190        commitPendingEdit();
    185191        CheckParameterUtil.ensureParameterNotNull(tag, "tag");
    186192        tags.add(tag);
     
    189195    }
    190196
     197    /**
     198     * Add a tag at the beginning of the table.
     199     *
     200     * @param tag The tag to add
     201     *
     202     * @throws IllegalArgumentException if tag is null
     203     *
     204     * @see #add(TagModel)
     205     */
    191206    public void prepend(TagModel tag) {
     207        commitPendingEdit();
    192208        CheckParameterUtil.ensureParameterNotNull(tag, "tag");
    193209        tags.add(0, tag);
     
    209225     */
    210226    public void add(String name, String value) {
     227        commitPendingEdit();
    211228        String key = (name == null) ? "" : name;
    212229        String val = (value == null) ? "" : value;
     
    259276        if (tags == null)
    260277            return;
     278        commitPendingEdit();
    261279        for (int tagIdx : tagIndices) {
    262280            TagModel tag = tags.get(tagIdx);
     
    277295        if (tags == null)
    278296            return;
     297        commitPendingEdit();
    279298        for (int tagIdx : tagIndices) {
    280299            TagModel tag = tags.get(tagIdx);
     
    293312     */
    294313    public void delete(String name) {
     314        commitPendingEdit();
    295315        if (name == null)
    296316            return;
     
    318338        if (tags == null)
    319339            return;
     340        commitPendingEdit();
    320341        List<TagModel> toDelete = new ArrayList<>();
    321342        for (int tagIdx : tagIndices) {
     
    356377     */
    357378    public void initFromPrimitive(Tagged primitive) {
     379        commitPendingEdit();
    358380        this.tags.clear();
    359381        for (String key : primitive.keySet()) {
     
    361383            this.tags.add(new TagModel(key, value));
    362384        }
     385        sort();
    363386        TagModel tag = new TagModel();
    364         sort();
    365387        tags.add(tag);
    366388        setDirty(false);
     
    374396     */
    375397    public void initFromTags(Map<String, String> tags) {
     398        commitPendingEdit();
    376399        this.tags.clear();
    377400        for (Entry<String, String> entry : tags.entrySet()) {
     
    391414     */
    392415    public void initFromTags(TagCollection tags) {
     416        commitPendingEdit();
    393417        this.tags.clear();
    394418        if (tags == null) {
     
    424448     */
    425449    private Map<String, String> applyToTags(boolean keepEmpty) {
    426         Map<String, String> result = new HashMap<>();
     450        // TagMap preserves the order of tags.
     451        TagMap result = new TagMap();
    427452        for (TagModel tag: this.tags) {
    428453            // tag still holds an unchanged list of different values for the same key.
     
    433458
    434459            // tag name holds an empty key. Don't apply it to the selection.
    435             //
    436460            if (!keepEmpty && (tag.getName().trim().isEmpty() || tag.getValue().trim().isEmpty())) {
    437461                continue;
     
    539563     */
    540564    protected void sort() {
    541         java.util.Collections.sort(
     565        Collections.sort(
    542566                tags,
    543567                new Comparator<TagModel>() {
     
    591615     */
    592616    public void updateTags(List<Tag> tags) {
    593          if (tags.isEmpty())
     617        if (tags.isEmpty())
    594618            return;
    595619
     620        commitPendingEdit();
    596621        Map<String, TagModel> modelTags = new HashMap<>();
    597622        for (int i = 0; i < getRowCount(); i++) {
     
    648673    }
    649674
     675    /**
     676     * Sets the listener that is notified when an edit should be aborted.
     677     * @param endEditListener The listener to be notified when editing should be aborted.
     678     */
     679    public void setEndEditListener(EndEditListener endEditListener) {
     680        this.endEditListener = endEditListener;
     681    }
     682
     683    private void commitPendingEdit() {
     684        if (endEditListener != null) {
     685            endEditListener.endCellEditing();
     686        }
     687    }
     688
    650689    class SelectionStateMemento {
    651690        private final int rowMin;
     
    674713        }
    675714    }
     715
     716    /**
     717     * A listener that is called whenever the cells may be updated from outside the editor and the editor should thus be commited.
     718     * @since 10604
     719     */
     720    @FunctionalInterface
     721    public interface EndEditListener {
     722        /**
     723         * Requests to end the editing of any cells on this model
     724         */
     725        void endCellEditing();
     726    }
    676727}
  • trunk/src/org/openstreetmap/josm/gui/tagging/TagTable.java

    r10378 r10604  
    22package org.openstreetmap.josm.gui.tagging;
    33
    4 import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
    54import static org.openstreetmap.josm.tools.I18n.tr;
    65
     
    1312import java.beans.PropertyChangeEvent;
    1413import java.beans.PropertyChangeListener;
    15 import java.util.ArrayList;
    1614import java.util.Collections;
    1715import java.util.EventObject;
    18 import java.util.List;
    19 import java.util.Map;
    2016import java.util.concurrent.CopyOnWriteArrayList;
    2117
     
    3228
    3329import org.openstreetmap.josm.Main;
    34 import org.openstreetmap.josm.actions.CopyAction;
    35 import org.openstreetmap.josm.actions.PasteTagsAction;
    36 import org.openstreetmap.josm.data.osm.OsmPrimitive;
    37 import org.openstreetmap.josm.data.osm.PrimitiveData;
    3830import org.openstreetmap.josm.data.osm.Relation;
    39 import org.openstreetmap.josm.data.osm.Tag;
     31import org.openstreetmap.josm.data.osm.TagMap;
     32import org.openstreetmap.josm.gui.datatransfer.OsmTransferHandler;
     33import org.openstreetmap.josm.gui.tagging.TagEditorModel.EndEditListener;
    4034import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionList;
    4135import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionManager;
    4236import org.openstreetmap.josm.gui.widgets.JosmTable;
    4337import org.openstreetmap.josm.tools.ImageProvider;
    44 import org.openstreetmap.josm.tools.TextTagParser;
    45 import org.openstreetmap.josm.tools.Utils;
    4638
    4739/**
     
    4941 * @since 1762
    5042 */
    51 public class TagTable extends JosmTable {
     43public class TagTable extends JosmTable implements EndEditListener {
    5244    /** the table cell editor used by this table */
    5345    private TagCellEditor editor;
     
    211203            }
    212204
    213             if (isEditing()) {
    214                 CellEditor cEditor = getCellEditor();
    215                 if (cEditor != null) {
    216                     cEditor.cancelCellEditing();
    217                 }
    218             }
     205            endCellEditing();
    219206
    220207            if (model.getRowCount() == 0) {
     
    233220
    234221        protected final void updateEnabledState() {
    235             if (isEditing() && getSelectedColumnCount() == 1 && getSelectedRowCount() == 1) {
    236                 setEnabled(true);
    237             } else if (!isEditing() && getSelectedColumnCount() == 1 && getSelectedRowCount() == 1) {
    238                 setEnabled(true);
    239             } else if (getSelectedColumnCount() > 1 || getSelectedRowCount() > 1) {
     222            if (getSelectedColumnCount() >= 1 && getSelectedRowCount() >= 1) {
    240223                setEnabled(true);
    241224            } else {
     
    295278            Relation relation = new Relation();
    296279            model.applyToPrimitive(relation);
    297 
    298             String buf = Utils.getClipboardContent();
    299             if (buf == null || buf.isEmpty() || buf.matches(CopyAction.CLIPBOARD_REGEXP)) {
    300                 List<PrimitiveData> directlyAdded = Main.pasteBuffer.getDirectlyAdded();
    301                 if (directlyAdded == null || directlyAdded.isEmpty()) return;
    302                 PasteTagsAction.TagPaster tagPaster = new PasteTagsAction.TagPaster(directlyAdded,
    303                         Collections.<OsmPrimitive>singletonList(relation));
    304                 model.updateTags(tagPaster.execute());
    305             } else {
    306                  // Paste tags from arbitrary text
    307                  Map<String, String> tags = TextTagParser.readTagsFromText(buf);
    308                  if (tags == null || tags.isEmpty()) {
    309                     TextTagParser.showBadBufferMessage(ht("/Action/PasteTags"));
    310                  } else if (TextTagParser.validateTags(tags)) {
    311                      List<Tag> newTags = new ArrayList<>();
    312                      for (Map.Entry<String, String> entry: tags.entrySet()) {
    313                         String k = entry.getKey();
    314                         String v = entry.getValue();
    315                         newTags.add(new Tag(k, v));
    316                      }
    317                      model.updateTags(newTags);
    318                  }
    319             }
     280            new OsmTransferHandler().pasteTags(Collections.singleton(relation));
     281            model.updateTags(new TagMap(relation.getKeys()).getTags());
    320282        }
    321283
     
    415377              model.getRowSelectionModel());
    416378        this.model = model;
     379        model.setEndEditListener(this);
    417380        init(maxCharacters);
    418381    }
     
    488451     */
    489452    public void setTagCellEditor(TagCellEditor editor) {
    490         if (isEditing()) {
    491             this.editor.cancelCellEditing();
    492         }
     453        endCellEditing();
    493454        this.editor = editor;
    494455        getColumnModel().getColumn(0).setCellEditor(editor);
     
    546507        // delegate to the default implementation
    547508        return super.editCellAt(row, column, e);
     509    }
     510
     511    @Override
     512    public void endCellEditing() {
     513        if (isEditing()) {
     514            CellEditor cEditor = getCellEditor();
     515            if (cEditor != null) {
     516                // First attempt to commit. If this does not work, cancel.
     517                cEditor.stopCellEditing();
     518                cEditor.cancelCellEditing();
     519            }
     520        }
    548521    }
    549522
  • trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletingComboBox.java

    r10308 r10604  
    2424
    2525import org.openstreetmap.josm.Main;
    26 import org.openstreetmap.josm.gui.util.GuiHelper;
     26import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
    2727import org.openstreetmap.josm.gui.widgets.JosmComboBox;
    28 import org.openstreetmap.josm.tools.Utils;
    2928
    3029/**
     
    134133            final JTextComponent editorComponent = comboBox.getEditorComponent();
    135134            // save unix system selection (middle mouse paste)
    136             Clipboard sysSel = GuiHelper.getSystemSelection();
     135            Clipboard sysSel = ClipboardUtils.getSystemSelection();
    137136            if (sysSel != null) {
    138                 Transferable old = Utils.getTransferableContent(sysSel);
     137                Transferable old = ClipboardUtils.getClipboardContent(sysSel);
    139138                editorComponent.select(start, end);
    140139                if (old != null) {
     
    201200                        }
    202201                        // save unix system selection (middle mouse paste)
    203                         Clipboard sysSel = GuiHelper.getSystemSelection();
     202                        Clipboard sysSel = ClipboardUtils.getSystemSelection();
    204203                        if (sysSel != null) {
    205                             Transferable old = Utils.getTransferableContent(sysSel);
     204                            Transferable old = ClipboardUtils.getClipboardContent(sysSel);
    206205                            editorComponent.selectAll();
    207206                            if (old != null) {
  • trunk/src/org/openstreetmap/josm/gui/util/GuiHelper.java

    r10471 r10604  
    2121import java.awt.Toolkit;
    2222import java.awt.Window;
    23 import java.awt.datatransfer.Clipboard;
    2423import java.awt.event.ActionListener;
    2524import java.awt.event.HierarchyEvent;
     
    497496
    498497    /**
    499      * Gets the singleton instance of the system selection as a <code>Clipboard</code> object.
    500      * This allows an application to read and modify the current, system-wide selection.
    501      * @return the system selection as a <code>Clipboard</code>, or <code>null</code> if the native platform does not
    502      *         support a system selection <code>Clipboard</code> or if GraphicsEnvironment.isHeadless() returns true
    503      * @see Toolkit#getSystemSelection
    504      * @since 9576
    505      */
    506     public static Clipboard getSystemSelection() {
    507         return GraphicsEnvironment.isHeadless() ? null : Toolkit.getDefaultToolkit().getSystemSelection();
    508     }
    509 
    510     /**
    511498     * Returns the first <code>Window</code> ancestor of event source, or
    512499     * {@code null} if event source is not a component contained inside a <code>Window</code>.
  • trunk/src/org/openstreetmap/josm/gui/widgets/AbstractIdTextField.java

    r10212 r10604  
    55
    66import org.openstreetmap.josm.Main;
    7 import org.openstreetmap.josm.tools.Utils;
     7import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
    88
    99/**
     
    7171     */
    7272    public void tryToPasteFromClipboard() {
    73         tryToPasteFrom(Utils.getClipboardContent());
     73        tryToPasteFrom(ClipboardUtils.getClipboardStringContent());
    7474    }
    7575
  • trunk/src/org/openstreetmap/josm/gui/widgets/UrlLabel.java

    r10181 r10604  
    1111import javax.swing.SwingUtilities;
    1212
     13import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
    1314import org.openstreetmap.josm.tools.OpenBrowser;
    14 import org.openstreetmap.josm.tools.Utils;
    1515
    1616/**
     
    112112            OpenBrowser.displayUrl(url);
    113113        } else if (SwingUtilities.isRightMouseButton(e)) {
    114             Utils.copyToClipboard(url);
     114            ClipboardUtils.copyString(url);
    115115        }
    116116    }
Note: See TracChangeset for help on using the changeset viewer.