// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.gui.dialogs.relation;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import javax.swing.JComponent;
import javax.swing.JTable;
import javax.swing.TransferHandler;
import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.data.osm.OsmPrimitive;
import org.openstreetmap.josm.data.osm.PrimitiveData;
import org.openstreetmap.josm.data.osm.PrimitiveId;
import org.openstreetmap.josm.data.osm.RelationMember;
import org.openstreetmap.josm.data.osm.RelationMemberData;
import org.openstreetmap.josm.gui.datatransfer.RelationMemberTransferable;
import org.openstreetmap.josm.gui.datatransfer.data.PrimitiveTransferData;
/**
* A transfer handler that helps with importing / exporting members for relations.
* @author Michael Zangl
* @since 10604
*/
public class MemberTransferHandler extends TransferHandler {
@Override
public int getSourceActions(JComponent c) {
return COPY_OR_MOVE;
}
@Override
protected Transferable createTransferable(JComponent c) {
final MemberTable source = (MemberTable) c;
return new RelationMemberTransferable(source.getMemberTableModel().getSelectedMembers());
}
@Override
public boolean canImport(TransferSupport support) {
if (support.isDrop()) {
support.setShowDropLocation(true);
}
return support.isDataFlavorSupported(RelationMemberTransferable.RELATION_MEMBER_DATA)
|| support.isDataFlavorSupported(PrimitiveTransferData.DATA_FLAVOR);
}
@Override
public boolean importData(TransferSupport support) {
MemberTable destination = (MemberTable) support.getComponent();
int insertRow = computeInsertionRow(support, destination);
return importDataAt(support, destination, insertRow);
}
private static int computeInsertionRow(TransferSupport support, MemberTable destination) {
final int insertRow;
if (support.isDrop()) {
DropLocation dl = support.getDropLocation();
if (dl instanceof JTable.DropLocation) {
insertRow = ((JTable.DropLocation) dl).getRow();
} else {
insertRow = 0;
}
} else {
int selection = destination.getSelectedRow();
if (selection < 0) {
// no selection, add at the end.
insertRow = destination.getRowCount();
} else {
insertRow = selection;
}
}
return insertRow;
}
private boolean importDataAt(TransferSupport support, MemberTable destination, int insertRow) {
try {
if (support.isDataFlavorSupported(RelationMemberTransferable.RELATION_MEMBER_DATA)) {
importRelationMemberData(support, destination, insertRow);
return true;
} else if (support.isDataFlavorSupported(PrimitiveTransferData.DATA_FLAVOR)) {
importPrimitiveData(support, destination, insertRow);
return true;
} else {
return false;
}
} catch (IOException | UnsupportedFlavorException e) {
Main.warn(e);
return false;
}
}
protected void importRelationMemberData(TransferSupport support, final MemberTable destination, int insertRow)
throws UnsupportedFlavorException, IOException {
final RelationMemberTransferable.Data memberData = (RelationMemberTransferable.Data)
support.getTransferable().getTransferData(RelationMemberTransferable.RELATION_MEMBER_DATA);
importData(destination, insertRow, memberData.getRelationMemberData(), new AbstractRelationMemberConverter<RelationMemberData>() {
@Override
protected RelationMember getMember(MemberTable destination, RelationMemberData data, OsmPrimitive p) {
return new RelationMember(data.getRole(), p);
}
});
}
protected void importPrimitiveData(TransferSupport support, final MemberTable destination, int insertRow)
throws UnsupportedFlavorException, IOException {
final PrimitiveTransferData data = (PrimitiveTransferData)
support.getTransferable().getTransferData(PrimitiveTransferData.DATA_FLAVOR);
importData(destination, insertRow, data.getDirectlyAdded(), new AbstractRelationMemberConverter<PrimitiveData>() {
@Override
protected RelationMember getMember(MemberTable destination, PrimitiveData data, OsmPrimitive p) {
return destination.getMemberTableModel().getRelationMemberForPrimitive(p);
}
});
}
protected <T extends PrimitiveId> void importData(MemberTable destination, int insertRow,
Collection<T> memberData, AbstractRelationMemberConverter<T> toMemberFunction) {
final Collection<RelationMember> membersToAdd = new ArrayList<>(memberData.size());
for (T data : memberData) {
final RelationMember member = toMemberFunction.importPrimitive(destination, data);
if (member != null) {
membersToAdd.add(member);
}
}
destination.getMemberTableModel().addMembersAtIndexKeepingOldSelection(membersToAdd, insertRow);
}
@Override
protected void exportDone(JComponent sourceComponent, Transferable data, int action) {
if (action != MOVE) {
return;
}
final MemberTable source = (MemberTable) sourceComponent;
final MemberTableModel model = source.getMemberTableModel();
model.remove(source.getSelectedRows());
model.selectionChanged(null);
}
private abstract static class AbstractRelationMemberConverter<T extends PrimitiveId> {
protected RelationMember importPrimitive(MemberTable destination, T data) {
final OsmPrimitive p = destination.getLayer().data.getPrimitiveById(data);
if (p == null) {
Main.warn(tr("Cannot add {0} since it is not part of dataset", data));
return null;
} else {
return getMember(destination, data, p);
}
}
protected abstract RelationMember getMember(MemberTable destination, T data, OsmPrimitive p);
}
}