// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.actions.downloadtasks; import static org.openstreetmap.josm.tools.I18n.tr; import static org.openstreetmap.josm.tools.I18n.trn; import java.io.IOException; import java.net.URL; import java.util.List; import java.util.concurrent.Future; import javax.swing.JOptionPane; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.data.Bounds; import org.openstreetmap.josm.data.ProjectionBounds; import org.openstreetmap.josm.data.ViewportData; import org.openstreetmap.josm.data.notes.Note; import org.openstreetmap.josm.data.osm.NoteData; import org.openstreetmap.josm.data.preferences.IntegerProperty; import org.openstreetmap.josm.gui.PleaseWaitRunnable; import org.openstreetmap.josm.gui.layer.NoteLayer; import org.openstreetmap.josm.gui.progress.ProgressMonitor; import org.openstreetmap.josm.io.BoundingBoxDownloader; import org.openstreetmap.josm.io.BoundingBoxDownloader.MoreNotesException; import org.openstreetmap.josm.io.OsmApi; import org.openstreetmap.josm.io.OsmServerLocationReader; import org.openstreetmap.josm.io.OsmServerReader; import org.openstreetmap.josm.io.OsmTransferException; import org.xml.sax.SAXException; /** Task for downloading notes */ public class DownloadNotesTask extends AbstractDownloadTask<NoteData> { private static final String PATTERN_API_URL = "https?://.*/api/0.6/notes.*"; private static final String PATTERN_DUMP_FILE = "https?://.*/(.*\\.osn(.bz2)?)"; /** Property defining the number of notes to be downloaded */ public static final IntegerProperty DOWNLOAD_LIMIT = new IntegerProperty("osm.notes.downloadLimit", 1000); /** Property defining number of days a bug needs to be closed to no longer be downloaded */ public static final IntegerProperty DAYS_CLOSED = new IntegerProperty("osm.notes.daysClosed", 7); private DownloadTask downloadTask; private NoteLayer noteLayer; /** * Download a specific note by its id. * @param id Note identifier * @param progressMonitor progress monitor * @return the future representing the asynchronous task */ public Future<?> download(long id, ProgressMonitor progressMonitor) { final String url = OsmApi.getOsmApi().getBaseUrl() + "notes/" + id; downloadTask = new DownloadRawUrlTask(new OsmServerLocationReader(url), progressMonitor); return Main.worker.submit(downloadTask); } @Override public Future<?> download(boolean newLayer, Bounds downloadArea, ProgressMonitor progressMonitor) { downloadTask = new DownloadBoundingBoxTask(new BoundingBoxDownloader(downloadArea), progressMonitor); return Main.worker.submit(downloadTask); } @Override public Future<?> loadUrl(boolean newLayer, String url, ProgressMonitor progressMonitor) { if (url.endsWith(".bz2")) { downloadTask = new DownloadBzip2RawUrlTask(new OsmServerLocationReader(url), progressMonitor); } else { downloadTask = new DownloadRawUrlTask(new OsmServerLocationReader(url), progressMonitor); } return Main.worker.submit(downloadTask); } @Override public void cancel() { if (downloadTask != null) { downloadTask.cancel(); } } @Override public String getConfirmationMessage(URL url) { return null; } @Override public String getTitle() { return tr("Download OSM Notes"); } @Override public String[] getPatterns() { return new String[] {PATTERN_API_URL, PATTERN_DUMP_FILE}; } @Override public boolean isSafeForRemotecontrolRequests() { return true; } @Override public ProjectionBounds getDownloadProjectionBounds() { return noteLayer != null ? noteLayer.getViewProjectionBounds() : null; } abstract class DownloadTask extends PleaseWaitRunnable { protected OsmServerReader reader; protected List<Note> notesData; DownloadTask(OsmServerReader reader, ProgressMonitor progressMonitor) { super(tr("Downloading Notes"), progressMonitor, false); this.reader = reader; } @Override protected void finish() { rememberDownloadedData(new NoteData(notesData)); if (isCanceled() || isFailed() || notesData == null || notesData.isEmpty()) { return; } if (Main.isDebugEnabled()) { Main.debug("Notes downloaded: " + notesData.size()); } noteLayer = new NoteLayer(notesData, tr("Notes")); List<NoteLayer> noteLayers = Main.getLayerManager().getLayersOfType(NoteLayer.class); if (!noteLayers.isEmpty()) { noteLayers.get(0).getNoteData().addNotes(notesData); if (Main.map != null && zoomAfterDownload) { Main.map.mapView.scheduleZoomTo(new ViewportData(noteLayer.getViewProjectionBounds())); } } else { Main.getLayerManager().addLayer(noteLayer, zoomAfterDownload); } } @Override protected void cancel() { setCanceled(true); if (reader != null) { reader.cancel(); } } @Override public abstract void realRun() throws IOException, SAXException, OsmTransferException; } class DownloadBoundingBoxTask extends DownloadTask { DownloadBoundingBoxTask(OsmServerReader reader, ProgressMonitor progressMonitor) { super(reader, progressMonitor); } @Override public void realRun() throws IOException, SAXException, OsmTransferException { if (isCanceled()) { return; } ProgressMonitor subMonitor = progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false); try { notesData = reader.parseNotes(DOWNLOAD_LIMIT.get(), DAYS_CLOSED.get(), subMonitor); } catch (MoreNotesException e) { Main.debug(e); notesData = e.notes; JOptionPane.showMessageDialog(Main.parent, "<html>" + trn("{0} note has been downloaded.", "{0} notes have been downloaded.", e.limit, e.limit) + "<br>" + tr("Since the download limit was {0}, there might be more notes to download.", e.limit) + "<br>" + tr("Request a smaller area to make sure that all notes are being downloaded.") + "</html>", tr("More notes to download"), JOptionPane.INFORMATION_MESSAGE); } catch (OsmTransferException e) { if (isCanceled()) return; rememberException(e); } } } class DownloadRawUrlTask extends DownloadTask { DownloadRawUrlTask(OsmServerReader reader, ProgressMonitor progressMonitor) { super(reader, progressMonitor); } @Override public void realRun() throws IOException, SAXException, OsmTransferException { if (isCanceled()) { return; } ProgressMonitor subMonitor = progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false); try { notesData = reader.parseRawNotes(subMonitor); } catch (OsmTransferException e) { if (isCanceled()) return; rememberException(e); } } } class DownloadBzip2RawUrlTask extends DownloadTask { DownloadBzip2RawUrlTask(OsmServerReader reader, ProgressMonitor progressMonitor) { super(reader, progressMonitor); } @Override public void realRun() throws IOException, SAXException, OsmTransferException { if (isCanceled()) { return; } ProgressMonitor subMonitor = progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false); try { notesData = reader.parseRawNotesBzip2(subMonitor); } catch (OsmTransferException e) { if (isCanceled()) return; rememberException(e); } } } }