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

Last change on this file since 16864 was 16864, checked in by simon04, 4 years ago

fix #15441 - Separate GpxRouteLayer

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