001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.datatransfer.importers;
003
004import java.awt.Component;
005import java.awt.datatransfer.DataFlavor;
006import java.awt.datatransfer.UnsupportedFlavorException;
007import java.io.IOException;
008import java.util.Collections;
009import java.util.List;
010import java.util.regex.Matcher;
011import java.util.regex.Pattern;
012
013import javax.swing.TransferHandler.TransferSupport;
014
015import org.openstreetmap.josm.Main;
016import org.openstreetmap.josm.data.coor.EastNorth;
017import org.openstreetmap.josm.data.coor.LatLon;
018import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
019import org.openstreetmap.josm.data.osm.PrimitiveId;
020import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
021import org.openstreetmap.josm.data.preferences.BooleanProperty;
022import org.openstreetmap.josm.gui.MapView;
023import org.openstreetmap.josm.gui.io.DownloadPrimitivesWithReferrersTask;
024import org.openstreetmap.josm.gui.layer.OsmDataLayer;
025
026/**
027 * Handles the paste / drop of an OSM address.
028 * <p>
029 * e.g. http://www.openstreetmap.org/node/123 downloads node 123
030 *
031 * @author Michael Zangl
032 * @since 10881
033 */
034public class OsmLinkPaster extends AbstractOsmDataPaster {
035
036    private static final BooleanProperty PASTE_REFERRERS = new BooleanProperty("paste.url.download-referrers", true);
037    private static final String OSM_SERVER = "^https?\\://(\\w+\\.)?(osm|openstreetmap)\\.org/";
038
039    /**
040     * Create a new Osm address paster
041     */
042    public OsmLinkPaster() {
043        super(DataFlavor.stringFlavor);
044    }
045
046    @Override
047    public boolean importData(TransferSupport support, OsmDataLayer layer, EastNorth pasteAt)
048            throws UnsupportedFlavorException, IOException {
049        if (!supports(support)) {
050            throw new UnsupportedFlavorException(df);
051        }
052
053        String transferData = (String) support.getTransferable().getTransferData(df);
054        List<PrimitiveId> ids = parseIds(transferData);
055
056        if (!ids.isEmpty()) {
057            Main.worker.submit(new DownloadPrimitivesWithReferrersTask(layer == null,
058                    ids, PASTE_REFERRERS.get(), PASTE_REFERRERS.get(), null, null));
059            return true;
060        }
061
062        LatLon ll = parseLatLon(transferData);
063        if (ll != null) {
064            Component comp = support.getComponent();
065            if (comp instanceof MapView) {
066                ((MapView) comp).zoomTo(ll);
067            }
068        }
069
070        return false;
071    }
072
073    protected static LatLon parseLatLon(String transferData) {
074        Matcher matcher = Pattern
075                .compile(OSM_SERVER + "#map=(?<zoom>\\d+)/(?<lat>-?\\d+\\.\\d+)/(?<lon>-?\\d+\\.\\d+)$")
076                .matcher(transferData);
077
078        if (!matcher.matches()) {
079            return null;
080        } else {
081            return new LatLon(Double.parseDouble(matcher.group("lat")), Double.parseDouble(matcher.group("lon")));
082        }
083    }
084
085    static List<PrimitiveId> parseIds(String transferData) {
086        Matcher matcher = Pattern
087                .compile(OSM_SERVER + "(?<type>node|way|relation)/(?<id>\\d+)(\\/.*)?$")
088                .matcher(transferData);
089
090        if (!matcher.matches()) {
091            return Collections.emptyList();
092        }
093
094        OsmPrimitiveType type;
095        switch (matcher.group("type")) {
096        case "way":
097            type = OsmPrimitiveType.WAY;
098            break;
099
100        case "node":
101            type = OsmPrimitiveType.NODE;
102            break;
103
104        case "relation":
105            type = OsmPrimitiveType.RELATION;
106            break;
107
108        default:
109            throw new AssertionError();
110        }
111
112        return Collections.singletonList(new SimplePrimitiveId(Long.parseLong(matcher.group("id")), type));
113    }
114}