001 // License: GPL. Copyright 2007 by Immanuel Scholz and others 002 package org.openstreetmap.josm.actions.downloadtasks; 003 004 import static org.openstreetmap.josm.tools.I18n.tr; 005 006 import java.io.IOException; 007 import java.util.concurrent.Future; 008 import java.util.regex.Matcher; 009 import java.util.regex.Pattern; 010 011 import org.openstreetmap.josm.Main; 012 import org.openstreetmap.josm.data.Bounds; 013 import org.openstreetmap.josm.data.Bounds.ParseMethod; 014 import org.openstreetmap.josm.data.gpx.GpxData; 015 import org.openstreetmap.josm.gui.PleaseWaitRunnable; 016 import org.openstreetmap.josm.gui.layer.GpxLayer; 017 import org.openstreetmap.josm.gui.layer.Layer; 018 import org.openstreetmap.josm.gui.progress.ProgressMonitor; 019 import org.openstreetmap.josm.gui.progress.ProgressTaskId; 020 import org.openstreetmap.josm.gui.progress.ProgressTaskIds; 021 import org.openstreetmap.josm.io.BoundingBoxDownloader; 022 import org.openstreetmap.josm.io.OsmServerLocationReader; 023 import org.openstreetmap.josm.io.OsmServerReader; 024 import org.openstreetmap.josm.io.OsmTransferException; 025 import org.xml.sax.SAXException; 026 027 public class DownloadGpsTask extends AbstractDownloadTask { 028 029 private DownloadTask downloadTask; 030 031 private static final String PATTERN_TRACE_ID = "http://.*openstreetmap.org/trace/\\p{Digit}+/data"; 032 033 private static final String PATTERN_TRACKPOINTS_BBOX = "http://.*/api/0.6/trackpoints\\?bbox=.*,.*,.*,.*"; 034 035 private static final String PATTERN_EXTERNAL_GPX_SCRIPT = "http://.*exportgpx.*"; 036 private static final String PATTERN_EXTERNAL_GPX_FILE = "http://.*/(.*\\.gpx)"; 037 038 protected String newLayerName = null; 039 040 public Future<?> download(boolean newLayer, Bounds downloadArea, ProgressMonitor progressMonitor) { 041 downloadTask = new DownloadTask(newLayer, 042 new BoundingBoxDownloader(downloadArea), progressMonitor); 043 // We need submit instead of execute so we can wait for it to finish and get the error 044 // message if necessary. If no one calls getErrorMessage() it just behaves like execute. 045 return Main.worker.submit(downloadTask); 046 } 047 048 public Future<?> loadUrl(boolean newLayer, String url, ProgressMonitor progressMonitor) { 049 if (url != null && (url.matches(PATTERN_TRACE_ID) || url.matches(PATTERN_EXTERNAL_GPX_SCRIPT) || url.matches(PATTERN_EXTERNAL_GPX_FILE))) { 050 downloadTask = new DownloadTask(newLayer, 051 new OsmServerLocationReader(url), progressMonitor); 052 // Extract .gpx filename from URL to set the new layer name 053 Matcher matcher = Pattern.compile(PATTERN_EXTERNAL_GPX_FILE).matcher(url); 054 newLayerName = matcher.matches() ? matcher.group(1) : null; 055 // We need submit instead of execute so we can wait for it to finish and get the error 056 // message if necessary. If no one calls getErrorMessage() it just behaves like execute. 057 return Main.worker.submit(downloadTask); 058 059 } else if (url != null && url.matches(PATTERN_TRACKPOINTS_BBOX)) { 060 String[] table = url.split("\\?|=|&"); 061 for (int i = 0; i<table.length; i++) { 062 if (table[i].equals("bbox") && i<table.length-1 ) 063 return download(newLayer, new Bounds(table[i+1], ",", ParseMethod.LEFT_BOTTOM_RIGHT_TOP), progressMonitor); 064 } 065 } 066 return null; 067 } 068 069 /* (non-Javadoc) 070 * @see org.openstreetmap.josm.actions.downloadtasks.DownloadTask#acceptsUrl(java.lang.String) 071 */ 072 @Override 073 public boolean acceptsUrl(String url) { 074 return url != null && (url.matches(PATTERN_TRACE_ID) || url.matches(PATTERN_TRACKPOINTS_BBOX) 075 || url.matches(PATTERN_EXTERNAL_GPX_SCRIPT) || url.matches(PATTERN_EXTERNAL_GPX_FILE)); 076 } 077 078 public void cancel() { 079 if (downloadTask != null) { 080 downloadTask.cancel(); 081 } 082 } 083 084 class DownloadTask extends PleaseWaitRunnable { 085 private OsmServerReader reader; 086 private GpxData rawData; 087 private final boolean newLayer; 088 089 public DownloadTask(boolean newLayer, OsmServerReader reader, ProgressMonitor progressMonitor) { 090 super(tr("Downloading GPS data")); 091 this.reader = reader; 092 this.newLayer = newLayer; 093 } 094 095 @Override public void realRun() throws IOException, SAXException, OsmTransferException { 096 try { 097 if (isCanceled()) 098 return; 099 rawData = reader.parseRawGps(progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false)); 100 } catch(Exception e) { 101 if (isCanceled()) 102 return; 103 if (e instanceof OsmTransferException) { 104 rememberException(e); 105 } else { 106 rememberException(new OsmTransferException(e)); 107 } 108 } 109 } 110 111 @Override protected void finish() { 112 if (isCanceled() || isFailed()) 113 return; 114 if (rawData == null) 115 return; 116 String name = newLayerName != null ? newLayerName : tr("Downloaded GPX Data"); 117 GpxLayer layer = new GpxLayer(rawData, name); 118 Layer x = findMergeLayer(); 119 if (newLayer || x == null) { 120 Main.main.addLayer(layer); 121 } else { 122 x.mergeFrom(layer); 123 Main.map.repaint(); 124 } 125 } 126 127 private Layer findMergeLayer() { 128 boolean merge = Main.pref.getBoolean("download.gps.mergeWithLocal", false); 129 if (!Main.isDisplayingMapView()) 130 return null; 131 Layer active = Main.map.mapView.getActiveLayer(); 132 if (active != null && active instanceof GpxLayer && (merge || ((GpxLayer)active).data.fromServer)) 133 return active; 134 for (Layer l : Main.map.mapView.getAllLayers()) { 135 if (l instanceof GpxLayer && (merge || ((GpxLayer)l).data.fromServer)) 136 return l; 137 } 138 return null; 139 } 140 141 @Override protected void cancel() { 142 setCanceled(true); 143 if (reader != null) { 144 reader.cancel(); 145 } 146 } 147 148 @Override 149 public ProgressTaskId canRunInBackground() { 150 return ProgressTaskIds.DOWNLOAD_GPS; 151 } 152 } 153 }