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

Last change on this file since 13632 was 13572, checked in by Don-vip, 6 years ago

fix #15798 - support direct download of GPX files from HOT Tasking Manager

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