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

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

see #15182 - deprecate Main.worker, replace it by gui.MainApplication.worker + code refactoring to make sure only editor packages use it

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