source: josm/trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadGpsTask.java@ 8908

Last change on this file since 8908 was 8908, checked in by Don-vip, 9 years ago

improve download tasks unit tests

  • Property svn:eol-style set to native
File size: 8.2 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.actions.downloadtasks;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.io.IOException;
7import java.net.URL;
8import java.util.concurrent.Future;
9import java.util.regex.Matcher;
10import java.util.regex.Pattern;
11
12import org.openstreetmap.josm.Main;
13import org.openstreetmap.josm.data.Bounds;
14import org.openstreetmap.josm.data.Bounds.ParseMethod;
15import org.openstreetmap.josm.data.gpx.GpxData;
16import org.openstreetmap.josm.gui.PleaseWaitRunnable;
17import org.openstreetmap.josm.gui.layer.GpxLayer;
18import org.openstreetmap.josm.gui.layer.Layer;
19import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
20import org.openstreetmap.josm.gui.progress.ProgressMonitor;
21import org.openstreetmap.josm.gui.progress.ProgressTaskId;
22import org.openstreetmap.josm.gui.progress.ProgressTaskIds;
23import org.openstreetmap.josm.io.BoundingBoxDownloader;
24import org.openstreetmap.josm.io.GpxImporter;
25import org.openstreetmap.josm.io.GpxImporter.GpxImporterData;
26import org.openstreetmap.josm.io.OsmServerLocationReader;
27import org.openstreetmap.josm.io.OsmServerReader;
28import org.openstreetmap.josm.io.OsmTransferException;
29import org.openstreetmap.josm.tools.CheckParameterUtil;
30import org.xml.sax.SAXException;
31
32/**
33 * Task allowing to download GPS data.
34 */
35public class DownloadGpsTask extends AbstractDownloadTask<GpxData> {
36
37 private DownloadTask downloadTask;
38
39 private static final String PATTERN_TRACE_ID = "https?://.*(osm|openstreetmap).org/trace/\\p{Digit}+/data";
40
41 private static final String PATTERN_TRACKPOINTS_BBOX = "https?://.*/api/0.6/trackpoints\\?bbox=.*,.*,.*,.*";
42
43 private static final String PATTERN_EXTERNAL_GPX_SCRIPT = "https?://.*exportgpx.*";
44 private static final String PATTERN_EXTERNAL_GPX_FILE = "https?://.*/(.*\\.gpx)";
45
46 protected String newLayerName;
47
48 @Override
49 public String[] getPatterns() {
50 return new String[] {PATTERN_EXTERNAL_GPX_FILE, PATTERN_EXTERNAL_GPX_SCRIPT, PATTERN_TRACE_ID, PATTERN_TRACKPOINTS_BBOX};
51 }
52
53 @Override
54 public String getTitle() {
55 return tr("Download GPS");
56 }
57
58 @Override
59 public Future<?> download(boolean newLayer, Bounds downloadArea, ProgressMonitor progressMonitor) {
60 downloadTask = new DownloadTask(newLayer,
61 new BoundingBoxDownloader(downloadArea), progressMonitor);
62 // We need submit instead of execute so we can wait for it to finish and get the error
63 // message if necessary. If no one calls getErrorMessage() it just behaves like execute.
64 return Main.worker.submit(downloadTask);
65 }
66
67 @Override
68 public Future<?> loadUrl(boolean newLayer, String url, ProgressMonitor progressMonitor) {
69 CheckParameterUtil.ensureParameterNotNull(url, "url");
70 if (url.matches(PATTERN_TRACE_ID)
71 || url.matches(PATTERN_EXTERNAL_GPX_SCRIPT)
72 || url.matches(PATTERN_EXTERNAL_GPX_FILE)) {
73 downloadTask = new DownloadTask(newLayer,
74 new OsmServerLocationReader(url), progressMonitor);
75 // Extract .gpx filename from URL to set the new layer name
76 Matcher matcher = Pattern.compile(PATTERN_EXTERNAL_GPX_FILE).matcher(url);
77 newLayerName = matcher.matches() ? matcher.group(1) : null;
78 // We need submit instead of execute so we can wait for it to finish and get the error
79 // message if necessary. If no one calls getErrorMessage() it just behaves like execute.
80 return Main.worker.submit(downloadTask);
81
82 } else if (url.matches(PATTERN_TRACKPOINTS_BBOX)) {
83 String[] table = url.split("\\?|=|&");
84 for (int i = 0; i < table.length; i++) {
85 if ("bbox".equals(table[i]) && i < table.length-1)
86 return download(newLayer, new Bounds(table[i+1], ",", ParseMethod.LEFT_BOTTOM_RIGHT_TOP), progressMonitor);
87 }
88 }
89 return null;
90 }
91
92 @Override
93 public void cancel() {
94 if (downloadTask != null) {
95 downloadTask.cancel();
96 }
97 }
98
99 class DownloadTask extends PleaseWaitRunnable {
100 private OsmServerReader reader;
101 private GpxData rawData;
102 private final boolean newLayer;
103
104 DownloadTask(boolean newLayer, OsmServerReader reader, ProgressMonitor progressMonitor) {
105 super(tr("Downloading GPS data"), progressMonitor, false);
106 this.reader = reader;
107 this.newLayer = newLayer;
108 }
109
110 @Override
111 public void realRun() throws IOException, SAXException, OsmTransferException {
112 try {
113 if (isCanceled())
114 return;
115 ProgressMonitor subMonitor = progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false);
116 rawData = reader.parseRawGps(subMonitor);
117 } catch (Exception e) {
118 if (isCanceled())
119 return;
120 if (e instanceof OsmTransferException) {
121 rememberException(e);
122 } else {
123 rememberException(new OsmTransferException(e));
124 }
125 }
126 }
127
128 @Override
129 protected void finish() {
130 rememberDownloadedData(rawData);
131 if (isCanceled() || isFailed())
132 return;
133 if (rawData == null)
134 return;
135 String name = newLayerName != null ? newLayerName : tr("Downloaded GPX Data");
136
137 GpxImporterData layers = GpxImporter.loadLayers(rawData, reader.isGpxParsedProperly(), name,
138 tr("Markers from {0}", name));
139
140 GpxLayer gpxLayer = addOrMergeLayer(layers.getGpxLayer(), findGpxMergeLayer());
141 addOrMergeLayer(layers.getMarkerLayer(), findMarkerMergeLayer(gpxLayer));
142
143 layers.getPostLayerTask().run();
144 }
145
146 private <L extends Layer> L addOrMergeLayer(L layer, L mergeLayer) {
147 if (layer == null) return null;
148 if (newLayer || mergeLayer == null) {
149 if (Main.main != null) {
150 Main.main.addLayer(layer);
151 }
152 return layer;
153 } else {
154 mergeLayer.mergeFrom(layer);
155 if (Main.map != null) {
156 Main.map.repaint();
157 }
158 return mergeLayer;
159 }
160 }
161
162 private GpxLayer findGpxMergeLayer() {
163 if (!Main.isDisplayingMapView())
164 return null;
165 boolean merge = Main.pref.getBoolean("download.gps.mergeWithLocal", false);
166 Layer active = Main.map.mapView.getActiveLayer();
167 if (active instanceof GpxLayer && (merge || ((GpxLayer) active).data.fromServer))
168 return (GpxLayer) active;
169 for (GpxLayer l : Main.map.mapView.getLayersOfType(GpxLayer.class)) {
170 if (merge || l.data.fromServer)
171 return l;
172 }
173 return null;
174 }
175
176 private MarkerLayer findMarkerMergeLayer(GpxLayer fromLayer) {
177 if (!Main.isDisplayingMapView())
178 return null;
179 for (MarkerLayer l : Main.map.mapView.getLayersOfType(MarkerLayer.class)) {
180 if (fromLayer != null && l.fromLayer == fromLayer)
181 return l;
182 }
183 return null;
184 }
185
186 @Override
187 protected void cancel() {
188 setCanceled(true);
189 if (reader != null) {
190 reader.cancel();
191 }
192 }
193
194 @Override
195 public ProgressTaskId canRunInBackground() {
196 return ProgressTaskIds.DOWNLOAD_GPS;
197 }
198 }
199
200 @Override
201 public String getConfirmationMessage(URL url) {
202 // TODO
203 return null;
204 }
205
206 @Override
207 public boolean isSafeForRemotecontrolRequests() {
208 return true;
209 }
210
211 /**
212 * Determines if the given URL denotes an OSM gpx-related API call.
213 * @param url The url to check
214 * @return true if the url matches "Trace ID" API call or "Trackpoints bbox" API call, false otherwise
215 * @see GpxData#fromServer
216 * @since 5745
217 */
218 public static final boolean isFromServer(String url) {
219 return url != null && (url.matches(PATTERN_TRACE_ID) || url.matches(PATTERN_TRACKPOINTS_BBOX));
220 }
221}
Note: See TracBrowser for help on using the repository browser.