001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.dialogs.relation;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.awt.datatransfer.Transferable;
007import java.awt.datatransfer.UnsupportedFlavorException;
008import java.io.IOException;
009import java.util.ArrayList;
010import java.util.Collection;
011
012import javax.swing.JComponent;
013import javax.swing.JTable;
014import javax.swing.TransferHandler;
015
016import org.openstreetmap.josm.Main;
017import org.openstreetmap.josm.data.osm.OsmPrimitive;
018import org.openstreetmap.josm.data.osm.PrimitiveData;
019import org.openstreetmap.josm.data.osm.RelationMember;
020import org.openstreetmap.josm.data.osm.RelationMemberData;
021import org.openstreetmap.josm.gui.datatransfer.PrimitiveTransferable;
022import org.openstreetmap.josm.gui.datatransfer.RelationMemberTransferable;
023import org.openstreetmap.josm.tools.Utils.Function;
024
025class MemberTransferHandler extends TransferHandler {
026
027    @Override
028    public int getSourceActions(JComponent c) {
029        return COPY_OR_MOVE;
030    }
031
032    @Override
033    protected Transferable createTransferable(JComponent c) {
034        final MemberTable source = (MemberTable) c;
035        return new RelationMemberTransferable(source.getMemberTableModel().getSelectedMembers());
036    }
037
038    @Override
039    public boolean canImport(TransferSupport support) {
040        support.setShowDropLocation(true);
041        return support.isDataFlavorSupported(RelationMemberTransferable.RELATION_MEMBER_DATA)
042                || support.isDataFlavorSupported(PrimitiveTransferable.PRIMITIVE_DATA);
043    }
044
045    @Override
046    public boolean importData(TransferSupport support) {
047        final MemberTable destination = (MemberTable) support.getComponent();
048        final int insertRow = ((JTable.DropLocation) support.getDropLocation()).getRow();
049
050        try {
051            if (support.isDataFlavorSupported(RelationMemberTransferable.RELATION_MEMBER_DATA)) {
052                importRelationMemberData(support, destination, insertRow);
053            } else if (support.isDataFlavorSupported(PrimitiveTransferable.PRIMITIVE_DATA)) {
054                importPrimitiveData(support, destination, insertRow);
055            }
056        } catch (IOException | UnsupportedFlavorException e) {
057            Main.warn(e);
058            return false;
059        }
060
061        return true;
062    }
063
064    protected void importRelationMemberData(TransferSupport support, final MemberTable destination, int insertRow)
065            throws UnsupportedFlavorException, IOException {
066        final RelationMemberTransferable.Data memberData = (RelationMemberTransferable.Data)
067                support.getTransferable().getTransferData(RelationMemberTransferable.RELATION_MEMBER_DATA);
068        importData(destination, insertRow, memberData.getRelationMemberData(), new Function<RelationMemberData, RelationMember>() {
069            @Override
070            public RelationMember apply(RelationMemberData member) {
071                final OsmPrimitive p = destination.getLayer().data.getPrimitiveById(member.getUniqueId(), member.getType());
072                if (p == null) {
073                    Main.warn(tr("Cannot add {0} since it is not part of dataset", member));
074                    return null;
075                } else {
076                    return new RelationMember(member.getRole(), p);
077                }
078            }
079        });
080    }
081
082    protected void importPrimitiveData(TransferSupport support, final MemberTable destination, int insertRow)
083            throws UnsupportedFlavorException, IOException {
084        final PrimitiveTransferable.Data data = (PrimitiveTransferable.Data)
085                support.getTransferable().getTransferData(PrimitiveTransferable.PRIMITIVE_DATA);
086        importData(destination, insertRow, data.getPrimitiveData(), new Function<PrimitiveData, RelationMember>() {
087            @Override
088            public RelationMember apply(PrimitiveData data) {
089                final OsmPrimitive p = destination.getLayer().data.getPrimitiveById(data);
090                if (p == null) {
091                    Main.warn(tr("Cannot add {0} since it is not part of dataset", data));
092                    return null;
093                } else {
094                    return destination.getMemberTableModel().getRelationMemberForPrimitive(p);
095                }
096            }
097        });
098    }
099
100    protected <T> void importData(MemberTable destination, int insertRow,
101                                  Collection<T> memberData, Function<T, RelationMember> toMemberFunction) {
102        final Collection<RelationMember> membersToAdd = new ArrayList<>(memberData.size());
103        for (T i : memberData) {
104            final RelationMember member = toMemberFunction.apply(i);
105            if (member != null) {
106                membersToAdd.add(member);
107            }
108        }
109        destination.getMemberTableModel().addMembersAtIndexKeepingOldSelection(membersToAdd, insertRow);
110    }
111
112    @Override
113    protected void exportDone(JComponent sourceComponent, Transferable data, int action) {
114        if (action != MOVE) {
115            return;
116        }
117        final MemberTable source = (MemberTable) sourceComponent;
118        final MemberTableModel model = source.getMemberTableModel();
119        model.remove(source.getSelectedRows());
120        model.selectionChanged(null);
121    }
122}