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.data.osm.OsmPrimitive; 017import org.openstreetmap.josm.data.osm.PrimitiveData; 018import org.openstreetmap.josm.data.osm.PrimitiveId; 019import org.openstreetmap.josm.data.osm.RelationMember; 020import org.openstreetmap.josm.data.osm.RelationMemberData; 021import org.openstreetmap.josm.gui.datatransfer.RelationMemberTransferable; 022import org.openstreetmap.josm.gui.datatransfer.data.PrimitiveTransferData; 023import org.openstreetmap.josm.tools.Logging; 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 DropLocation dl = support.getDropLocation(); 064 if (dl instanceof JTable.DropLocation) { 065 insertRow = ((JTable.DropLocation) dl).getRow(); 066 } else { 067 insertRow = 0; 068 } 069 } else { 070 int selection = destination.getSelectedRow(); 071 if (selection < 0) { 072 // no selection, add at the end. 073 insertRow = destination.getRowCount(); 074 } else { 075 insertRow = selection; 076 } 077 } 078 return insertRow; 079 } 080 081 private boolean importDataAt(TransferSupport support, MemberTable destination, int insertRow) { 082 try { 083 if (support.isDataFlavorSupported(RelationMemberTransferable.RELATION_MEMBER_DATA)) { 084 importRelationMemberData(support, destination, insertRow); 085 return true; 086 } else if (support.isDataFlavorSupported(PrimitiveTransferData.DATA_FLAVOR)) { 087 importPrimitiveData(support, destination, insertRow); 088 return true; 089 } else { 090 return false; 091 } 092 } catch (IOException | UnsupportedFlavorException e) { 093 Logging.warn(e); 094 return false; 095 } 096 } 097 098 protected void importRelationMemberData(TransferSupport support, final MemberTable destination, int insertRow) 099 throws UnsupportedFlavorException, IOException { 100 final RelationMemberTransferable.Data memberData = (RelationMemberTransferable.Data) 101 support.getTransferable().getTransferData(RelationMemberTransferable.RELATION_MEMBER_DATA); 102 importData(destination, insertRow, memberData.getRelationMemberData(), new AbstractRelationMemberConverter<RelationMemberData>() { 103 @Override 104 protected RelationMember getMember(MemberTable destination, RelationMemberData data, OsmPrimitive p) { 105 return new RelationMember(data.getRole(), p); 106 } 107 }); 108 } 109 110 protected void importPrimitiveData(TransferSupport support, final MemberTable destination, int insertRow) 111 throws UnsupportedFlavorException, IOException { 112 final PrimitiveTransferData data = (PrimitiveTransferData) 113 support.getTransferable().getTransferData(PrimitiveTransferData.DATA_FLAVOR); 114 importData(destination, insertRow, data.getDirectlyAdded(), new AbstractRelationMemberConverter<PrimitiveData>() { 115 @Override 116 protected RelationMember getMember(MemberTable destination, PrimitiveData data, OsmPrimitive p) { 117 return destination.getMemberTableModel().getRelationMemberForPrimitive(p); 118 } 119 }); 120 } 121 122 protected <T extends PrimitiveId> void importData(MemberTable destination, int insertRow, 123 Collection<T> memberData, AbstractRelationMemberConverter<T> toMemberFunction) { 124 final Collection<RelationMember> membersToAdd = new ArrayList<>(memberData.size()); 125 for (T data : memberData) { 126 final RelationMember member = toMemberFunction.importPrimitive(destination, data); 127 if (member != null) { 128 membersToAdd.add(member); 129 } 130 } 131 destination.getMemberTableModel().addMembersAtIndexKeepingOldSelection(membersToAdd, insertRow); 132 } 133 134 @Override 135 protected void exportDone(JComponent sourceComponent, Transferable data, int action) { 136 if (action != MOVE) { 137 return; 138 } 139 final MemberTable source = (MemberTable) sourceComponent; 140 final MemberTableModel model = source.getMemberTableModel(); 141 model.remove(source.getSelectedRows()); 142 model.selectionChanged(null); 143 } 144 145 private abstract static class AbstractRelationMemberConverter<T extends PrimitiveId> { 146 protected RelationMember importPrimitive(MemberTable destination, T data) { 147 final OsmPrimitive p = destination.getLayer().data.getPrimitiveById(data); 148 if (p == null) { 149 Logging.warn(tr("Cannot add {0} since it is not part of dataset", data)); 150 return null; 151 } else { 152 return getMember(destination, data, p); 153 } 154 } 155 156 protected abstract RelationMember getMember(MemberTable destination, T data, OsmPrimitive p); 157 } 158}