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.PrimitiveId; 020import org.openstreetmap.josm.data.osm.RelationMember; 021import org.openstreetmap.josm.data.osm.RelationMemberData; 022import org.openstreetmap.josm.gui.datatransfer.RelationMemberTransferable; 023import org.openstreetmap.josm.gui.datatransfer.data.PrimitiveTransferData; 024 025/** 026 * A transfer handler that helps with importing / exporting members for relations. 027 * @author Michael Zangl 028 * @since 10604 029 */ 030public class MemberTransferHandler extends TransferHandler { 031 032 @Override 033 public int getSourceActions(JComponent c) { 034 return COPY_OR_MOVE; 035 } 036 037 @Override 038 protected Transferable createTransferable(JComponent c) { 039 final MemberTable source = (MemberTable) c; 040 return new RelationMemberTransferable(source.getMemberTableModel().getSelectedMembers()); 041 } 042 043 @Override 044 public boolean canImport(TransferSupport support) { 045 if (support.isDrop()) { 046 support.setShowDropLocation(true); 047 } 048 return support.isDataFlavorSupported(RelationMemberTransferable.RELATION_MEMBER_DATA) 049 || support.isDataFlavorSupported(PrimitiveTransferData.DATA_FLAVOR); 050 } 051 052 @Override 053 public boolean importData(TransferSupport support) { 054 MemberTable destination = (MemberTable) support.getComponent(); 055 int insertRow = computeInsertionRow(support, destination); 056 057 return importDataAt(support, destination, insertRow); 058 } 059 060 private static int computeInsertionRow(TransferSupport support, MemberTable destination) { 061 final int insertRow; 062 if (support.isDrop()) { 063 insertRow = ((JTable.DropLocation) support.getDropLocation()).getRow(); 064 } else { 065 int selection = destination.getSelectedRow(); 066 if (selection < 0) { 067 // no selection, add at the end. 068 insertRow = destination.getRowCount(); 069 } else { 070 insertRow = selection; 071 } 072 } 073 return insertRow; 074 } 075 076 private boolean importDataAt(TransferSupport support, MemberTable destination, int insertRow) { 077 try { 078 if (support.isDataFlavorSupported(RelationMemberTransferable.RELATION_MEMBER_DATA)) { 079 importRelationMemberData(support, destination, insertRow); 080 return true; 081 } else if (support.isDataFlavorSupported(PrimitiveTransferData.DATA_FLAVOR)) { 082 importPrimitiveData(support, destination, insertRow); 083 return true; 084 } else { 085 return false; 086 } 087 } catch (IOException | UnsupportedFlavorException e) { 088 Main.warn(e); 089 return false; 090 } 091 } 092 093 protected void importRelationMemberData(TransferSupport support, final MemberTable destination, int insertRow) 094 throws UnsupportedFlavorException, IOException { 095 final RelationMemberTransferable.Data memberData = (RelationMemberTransferable.Data) 096 support.getTransferable().getTransferData(RelationMemberTransferable.RELATION_MEMBER_DATA); 097 importData(destination, insertRow, memberData.getRelationMemberData(), new AbstractRelationMemberConverter<RelationMemberData>() { 098 @Override 099 protected RelationMember getMember(MemberTable destination, RelationMemberData data, OsmPrimitive p) { 100 return new RelationMember(data.getRole(), p); 101 } 102 }); 103 } 104 105 protected void importPrimitiveData(TransferSupport support, final MemberTable destination, int insertRow) 106 throws UnsupportedFlavorException, IOException { 107 final PrimitiveTransferData data = (PrimitiveTransferData) 108 support.getTransferable().getTransferData(PrimitiveTransferData.DATA_FLAVOR); 109 importData(destination, insertRow, data.getDirectlyAdded(), new AbstractRelationMemberConverter<PrimitiveData>() { 110 @Override 111 protected RelationMember getMember(MemberTable destination, PrimitiveData data, OsmPrimitive p) { 112 return destination.getMemberTableModel().getRelationMemberForPrimitive(p); 113 } 114 }); 115 } 116 117 protected <T extends PrimitiveId> void importData(MemberTable destination, int insertRow, 118 Collection<T> memberData, AbstractRelationMemberConverter<T> toMemberFunction) { 119 final Collection<RelationMember> membersToAdd = new ArrayList<>(memberData.size()); 120 for (T data : memberData) { 121 final RelationMember member = toMemberFunction.importPrimitive(destination, data); 122 if (member != null) { 123 membersToAdd.add(member); 124 } 125 } 126 destination.getMemberTableModel().addMembersAtIndexKeepingOldSelection(membersToAdd, insertRow); 127 } 128 129 @Override 130 protected void exportDone(JComponent sourceComponent, Transferable data, int action) { 131 if (action != MOVE) { 132 return; 133 } 134 final MemberTable source = (MemberTable) sourceComponent; 135 final MemberTableModel model = source.getMemberTableModel(); 136 model.remove(source.getSelectedRows()); 137 model.selectionChanged(null); 138 } 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 } 153}