Ticket #12300: 12300-v3.patch

File 12300-v3.patch, 17.3 KB (added by simon04, 10 years ago)
  • new file src/org/openstreetmap/josm/gui/datatransfer/PrimitiveTransferable.java

    diff --git a/src/org/openstreetmap/josm/gui/datatransfer/PrimitiveTransferable.java b/src/org/openstreetmap/josm/gui/datatransfer/PrimitiveTransferable.java
    new file mode 100644
    index 0000000..06befa9
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.gui.datatransfer;
     3
     4import java.awt.datatransfer.DataFlavor;
     5import java.awt.datatransfer.Transferable;
     6import java.awt.datatransfer.UnsupportedFlavorException;
     7import java.util.ArrayList;
     8import java.util.Collection;
     9
     10import org.openstreetmap.josm.data.osm.OsmPrimitive;
     11import org.openstreetmap.josm.data.osm.PrimitiveData;
     12import org.openstreetmap.josm.gui.DefaultNameFormatter;
     13
     14public class PrimitiveTransferable implements Transferable {
     15
     16    public static final DataFlavor PRIMITIVE_DATA = new DataFlavor(PrimitiveData.class, PrimitiveData.class.getName());
     17    private final Collection<OsmPrimitive> primitives;
     18
     19    public PrimitiveTransferable(Collection<OsmPrimitive> members) {
     20        this.primitives = members;
     21    }
     22
     23    @Override
     24    public DataFlavor[] getTransferDataFlavors() {
     25        return new DataFlavor[]{PRIMITIVE_DATA, DataFlavor.stringFlavor};
     26    }
     27
     28    @Override
     29    public boolean isDataFlavorSupported(DataFlavor flavor) {
     30        return flavor == PRIMITIVE_DATA;
     31    }
     32
     33    @Override
     34    public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException {
     35        if (DataFlavor.stringFlavor.equals(flavor)) {
     36            return getStringData();
     37        } else if (PRIMITIVE_DATA.equals(flavor)) {
     38            return getRelationMemberData();
     39        }
     40        throw new UnsupportedFlavorException(flavor);
     41    }
     42
     43    protected String getStringData() {
     44        final StringBuilder sb = new StringBuilder();
     45        for (OsmPrimitive primitive : primitives) {
     46            sb.append(primitive.getType());
     47            sb.append(" ").append(primitive.getUniqueId());
     48            sb.append(" #").append(primitive.getDisplayName(DefaultNameFormatter.getInstance()));
     49            sb.append("\n");
     50        }
     51        return sb.toString().replace("\u200E", "").replace("\u200F", "");
     52    }
     53
     54    protected Collection<PrimitiveData> getRelationMemberData() {
     55        final Collection<PrimitiveData> r = new ArrayList<>(primitives.size());
     56        for (OsmPrimitive primitive : primitives) {
     57            r.add(primitive.save());
     58        }
     59        return r;
     60    }
     61}
  • new file src/org/openstreetmap/josm/gui/datatransfer/RelationMemberTransferable.java

    diff --git a/src/org/openstreetmap/josm/gui/datatransfer/RelationMemberTransferable.java b/src/org/openstreetmap/josm/gui/datatransfer/RelationMemberTransferable.java
    new file mode 100644
    index 0000000..b8afcd1
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.gui.datatransfer;
     3
     4import java.awt.datatransfer.DataFlavor;
     5import java.awt.datatransfer.Transferable;
     6import java.awt.datatransfer.UnsupportedFlavorException;
     7import java.util.ArrayList;
     8import java.util.Collection;
     9
     10import org.openstreetmap.josm.data.osm.RelationMember;
     11import org.openstreetmap.josm.data.osm.RelationMemberData;
     12import org.openstreetmap.josm.gui.DefaultNameFormatter;
     13
     14public class RelationMemberTransferable implements Transferable {
     15
     16    public static final DataFlavor RELATION_MEMBER_DATA = new DataFlavor(RelationMemberData.class, RelationMemberData.class.getName());
     17    private final Collection<RelationMember> members;
     18
     19    public RelationMemberTransferable(Collection<RelationMember> members) {
     20        this.members = members;
     21    }
     22
     23    @Override
     24    public DataFlavor[] getTransferDataFlavors() {
     25        return new DataFlavor[]{RELATION_MEMBER_DATA, DataFlavor.stringFlavor};
     26    }
     27
     28    @Override
     29    public boolean isDataFlavorSupported(DataFlavor flavor) {
     30        return flavor == RELATION_MEMBER_DATA;
     31    }
     32
     33    @Override
     34    public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException {
     35        if (DataFlavor.stringFlavor.equals(flavor)) {
     36            return getStringData();
     37        } else if (RELATION_MEMBER_DATA.equals(flavor)) {
     38            return getRelationMemberData();
     39        }
     40        throw new UnsupportedFlavorException(flavor);
     41    }
     42
     43    protected String getStringData() {
     44        final StringBuilder sb = new StringBuilder();
     45        for (RelationMember member : members) {
     46            sb.append(member.getType());
     47            sb.append(" ").append(member.getUniqueId());
     48            sb.append(" ").append(member.getRole());
     49            sb.append(" #").append(member.getMember().getDisplayName(DefaultNameFormatter.getInstance()));
     50            sb.append("\n");
     51        }
     52        return sb.toString().replace("\u200E", "").replace("\u200F", "");
     53    }
     54
     55    protected Collection<RelationMemberData> getRelationMemberData() {
     56        final Collection<RelationMemberData> r = new ArrayList<>(members.size());
     57        for (RelationMember member : members) {
     58            r.add(new RelationMemberData(member.getRole(), member.getType(), member.getUniqueId()));
     59        }
     60        return r;
     61    }
     62}
  • src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java

    diff --git a/src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java b/src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java
    index f9cdafd..9c9ec79 100644
    a b  
    66
    77import java.awt.Component;
    88import java.awt.Rectangle;
     9import java.awt.datatransfer.Transferable;
    910import java.awt.event.ActionEvent;
    1011import java.awt.event.ActionListener;
    1112import java.awt.event.KeyEvent;
     
    2324import javax.swing.AbstractAction;
    2425import javax.swing.AbstractListModel;
    2526import javax.swing.DefaultListSelectionModel;
     27import javax.swing.JComponent;
    2628import javax.swing.JList;
    2729import javax.swing.JMenuItem;
    2830import javax.swing.JPopupMenu;
    2931import javax.swing.ListSelectionModel;
     32import javax.swing.TransferHandler;
    3033import javax.swing.event.ListDataEvent;
    3134import javax.swing.event.ListDataListener;
    3235import javax.swing.event.ListSelectionEvent;
     
    6568import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
    6669import org.openstreetmap.josm.gui.PopupMenuHandler;
    6770import org.openstreetmap.josm.gui.SideButton;
     71import org.openstreetmap.josm.gui.datatransfer.PrimitiveTransferable;
    6872import org.openstreetmap.josm.gui.history.HistoryBrowserDialogManager;
    6973import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    7074import org.openstreetmap.josm.gui.util.GuiHelper;
    protected void buildContentPanel() {  
    107111        lstPrimitives.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
    108112        lstPrimitives.setSelectionModel(selectionModel);
    109113        lstPrimitives.setCellRenderer(new OsmPrimitivRenderer());
    110         // Fix #6290. Drag & Drop is not supported anyway and Copy/Paste is better propagated to main window
    111         lstPrimitives.setTransferHandler(null);
     114        lstPrimitives.setTransferHandler(new SelectionTransferHandler());
     115        lstPrimitives.setDragEnabled(true);
    112116
    113117        lstPrimitives.getSelectionModel().addListSelectionListener(actSelect);
    114118        lstPrimitives.getSelectionModel().addListSelectionListener(actShowHistory);
    public SelectionHistoryPopup(Collection<Collection<? extends OsmPrimitive>> hist  
    854858            }
    855859        }
    856860    }
     861
     862    /**
     863     * A transfer handler class for drag-and-drop support.
     864     */
     865    protected class SelectionTransferHandler extends TransferHandler {
     866
     867        @Override
     868        public int getSourceActions(JComponent c) {
     869            return COPY;
     870        }
     871
     872        @Override
     873        protected Transferable createTransferable(JComponent c) {
     874            return new PrimitiveTransferable(getSelectedPrimitives());
     875        }
     876    }
    857877}
  • src/org/openstreetmap/josm/gui/dialogs/relation/MemberTable.java

    diff --git a/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTable.java b/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTable.java
    index 3d41fd3..9eb25c7 100644
    a b  
    1414import java.util.List;
    1515
    1616import javax.swing.AbstractAction;
     17import javax.swing.DropMode;
    1718import javax.swing.JComponent;
    1819import javax.swing.JPopupMenu;
    1920import javax.swing.JTable;
    protected void init() {  
    8283        //
    8384        getActionMap().put("selectNextColumnCell", new SelectNextColumnCellAction());
    8485        getActionMap().put("selectPreviousColumnCell", new SelectPreviousColumnCellAction());
     86
     87        setTransferHandler(new MemberTransferHandler());
     88        setFillsViewportHeight(true); // allow drop on empty table
     89        setDragEnabled(true);
     90        setDropMode(DropMode.INSERT_ROWS);
    8591    }
    8692
    8793    @Override
  • src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java

    diff --git a/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java b/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java
    index f87ef71..7564a7e 100644
    a b public boolean hasIncompleteSelectedMembers() {  
    422422    }
    423423
    424424    private void addMembersAtIndex(List<? extends OsmPrimitive> primitives, int index) {
    425         final Collection<TaggingPreset> presets = TaggingPresets.getMatchingPresets(EnumSet.of(TaggingPresetType.RELATION),
    426                 presetHandler.getSelection().iterator().next().getKeys(), false);
    427425        if (primitives == null)
    428426            return;
    429427        int idx = index;
    430428        for (OsmPrimitive primitive : primitives) {
    431             Set<String> potentialRoles = new TreeSet<>();
    432             for (TaggingPreset tp : presets) {
    433                 String suggestedRole = tp.suggestRoleForOsmPrimitive(primitive);
    434                 if (suggestedRole != null) {
    435                     potentialRoles.add(suggestedRole);
    436                 }
    437             }
    438             // TODO: propose user to choose role among potential ones instead of picking first one
    439             final String role = potentialRoles.isEmpty() ? null : potentialRoles.iterator().next();
    440             RelationMember member = new RelationMember(role == null ? "" : role, primitive);
     429            final RelationMember member = getRelationMemberForPrimitive(primitive);
    441430            members.add(idx++, member);
    442431        }
    443432        fireTableDataChanged();
    private void addMembersAtIndex(List<? extends OsmPrimitive> primitives, int inde  
    446435        fireMakeMemberVisible(index);
    447436    }
    448437
     438    RelationMember getRelationMemberForPrimitive(final OsmPrimitive primitive) {
     439        final Collection<TaggingPreset> presets = TaggingPresets.getMatchingPresets(EnumSet.of(TaggingPresetType.RELATION),
     440                presetHandler.getSelection().iterator().next().getKeys(), false);
     441        Collection<String> potentialRoles = new TreeSet<>();
     442        for (TaggingPreset tp : presets) {
     443            String suggestedRole = tp.suggestRoleForOsmPrimitive(primitive);
     444            if (suggestedRole != null) {
     445                potentialRoles.add(suggestedRole);
     446            }
     447        }
     448        // TODO: propose user to choose role among potential ones instead of picking first one
     449        final String role = potentialRoles.isEmpty() ? "" : potentialRoles.iterator().next();
     450        return new RelationMember(role == null ? "" : role, primitive);
     451    }
     452
     453    void addMembersAtIndex(final Iterable<RelationMember> newMembers, final int index) {
     454        int idx = index;
     455        for (RelationMember member : newMembers) {
     456            members.add(idx++, member);
     457        }
     458        fireTableRowsInserted(index, idx - 1);
     459    }
     460
    449461    public void addMembersAtBeginning(List<? extends OsmPrimitive> primitives) {
    450462        addMembersAtIndex(primitives, 0);
    451463    }
  • new file src/org/openstreetmap/josm/gui/dialogs/relation/MemberTransferHandler.java

    diff --git a/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTransferHandler.java b/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTransferHandler.java
    new file mode 100644
    index 0000000..b4c42c7
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.gui.dialogs.relation;
     3
     4import static org.openstreetmap.josm.tools.I18n.tr;
     5
     6import java.awt.datatransfer.Transferable;
     7import java.awt.datatransfer.UnsupportedFlavorException;
     8import java.io.IOException;
     9import java.util.ArrayList;
     10import java.util.Collection;
     11
     12import javax.swing.JComponent;
     13import javax.swing.JTable;
     14import javax.swing.TransferHandler;
     15
     16import org.openstreetmap.josm.Main;
     17import org.openstreetmap.josm.data.osm.OsmPrimitive;
     18import org.openstreetmap.josm.data.osm.PrimitiveData;
     19import org.openstreetmap.josm.data.osm.RelationMember;
     20import org.openstreetmap.josm.data.osm.RelationMemberData;
     21import org.openstreetmap.josm.gui.datatransfer.PrimitiveTransferable;
     22import org.openstreetmap.josm.gui.datatransfer.RelationMemberTransferable;
     23import org.openstreetmap.josm.tools.Utils.Function;
     24
     25class MemberTransferHandler extends TransferHandler {
     26
     27    @Override
     28    public int getSourceActions(JComponent c) {
     29        return COPY_OR_MOVE;
     30    }
     31
     32    @Override
     33    protected Transferable createTransferable(JComponent c) {
     34        final MemberTable source = (MemberTable) c;
     35        return new RelationMemberTransferable(source.getMemberTableModel().getSelectedMembers());
     36    }
     37
     38    @Override
     39    public boolean canImport(TransferSupport support) {
     40        support.setShowDropLocation(true);
     41        return support.isDataFlavorSupported(RelationMemberTransferable.RELATION_MEMBER_DATA)
     42                || support.isDataFlavorSupported(PrimitiveTransferable.PRIMITIVE_DATA);
     43    }
     44
     45    @Override
     46    public boolean importData(TransferSupport support) {
     47        final MemberTable destination = (MemberTable) support.getComponent();
     48        final int insertRow = ((JTable.DropLocation) support.getDropLocation()).getRow();
     49
     50        try {
     51            if (support.isDataFlavorSupported(RelationMemberTransferable.RELATION_MEMBER_DATA)) {
     52                importRelationMemberData(support, destination, insertRow);
     53            } else if (support.isDataFlavorSupported(PrimitiveTransferable.PRIMITIVE_DATA)) {
     54                importPrimitiveData(support, destination, insertRow);
     55            }
     56        } catch (Exception e) {
     57            Main.warn(e);
     58            return false;
     59        }
     60
     61        return true;
     62    }
     63
     64    protected void importRelationMemberData(TransferSupport support, final MemberTable destination, int insertRow)
     65            throws UnsupportedFlavorException, IOException {
     66        //noinspection unchecked
     67        final Collection<RelationMemberData> memberData = (Collection<RelationMemberData>)
     68                support.getTransferable().getTransferData(RelationMemberTransferable.RELATION_MEMBER_DATA);
     69        importData(destination, insertRow, memberData, new Function<RelationMemberData, RelationMember>() {
     70            @Override
     71            public RelationMember apply(RelationMemberData member) {
     72                final OsmPrimitive p = destination.getLayer().data.getPrimitiveById(member.getUniqueId(), member.getType());
     73                if (p == null) {
     74                    Main.warn(tr("Cannot add {0} since it is not part of dataset", member));
     75                    return null;
     76                } else {
     77                    return new RelationMember(member.getRole(), p);
     78                }
     79            }
     80        });
     81    }
     82
     83    protected void importPrimitiveData(TransferSupport support, final MemberTable destination, int insertRow)
     84            throws UnsupportedFlavorException, IOException {
     85        //noinspection unchecked
     86        final Collection<PrimitiveData> data = (Collection<PrimitiveData>)
     87                support.getTransferable().getTransferData(PrimitiveTransferable.PRIMITIVE_DATA);
     88        importData(destination, insertRow, data, new Function<PrimitiveData, RelationMember>() {
     89            @Override
     90            public RelationMember apply(PrimitiveData data) {
     91                final OsmPrimitive p = destination.getLayer().data.getPrimitiveById(data);
     92                if (p == null) {
     93                    Main.warn(tr("Cannot add {0} since it is not part of dataset", data));
     94                    return null;
     95                } else {
     96                    return destination.getMemberTableModel().getRelationMemberForPrimitive(p);
     97                }
     98            }
     99        });
     100    }
     101
     102    protected <T> void importData(MemberTable destination, int insertRow, Collection<T> memberData, Function<T, RelationMember> toMemberFunction) {
     103        final Collection<RelationMember> membersToAdd = new ArrayList<>(memberData.size());
     104        for (T i : memberData) {
     105            final RelationMember member = toMemberFunction.apply(i);
     106            if (member != null) {
     107                membersToAdd.add(member);
     108            }
     109        }
     110        destination.getMemberTableModel().addMembersAtIndex(membersToAdd, insertRow);
     111    }
     112
     113    @Override
     114    protected void exportDone(JComponent sourceComponent, Transferable data, int action) {
     115        if (action != MOVE) {
     116            return;
     117        }
     118        final MemberTable source = (MemberTable) sourceComponent;
     119        final MemberTableModel model = source.getMemberTableModel();
     120        model.remove(source.getSelectedRows());
     121        model.selectionChanged(null);
     122    }
     123}