001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.actions.downloadtasks; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.Component; 007import java.io.IOException; 008import java.text.MessageFormat; 009import java.util.ArrayList; 010import java.util.Collection; 011import java.util.Collections; 012import java.util.List; 013 014import org.openstreetmap.josm.Main; 015import org.openstreetmap.josm.data.osm.Changeset; 016import org.openstreetmap.josm.data.osm.ChangesetCache; 017import org.openstreetmap.josm.data.osm.ChangesetDataSet; 018import org.openstreetmap.josm.gui.ExceptionDialogUtil; 019import org.openstreetmap.josm.io.OsmTransferCanceledException; 020import org.openstreetmap.josm.io.OsmTransferException; 021import org.openstreetmap.josm.tools.Logging; 022import org.xml.sax.SAXException; 023 024/** 025 * This is an asynchronous task for downloading the changeset content of a collection of changesets. 026 * @since 2689 027 */ 028public class ChangesetContentDownloadTask extends AbstractChangesetDownloadTask { 029 030 class DownloadTask extends RunnableDownloadTask { 031 /** the list of changeset ids to download */ 032 private final List<Integer> toDownload = new ArrayList<>(); 033 034 DownloadTask(Component parent, Collection<Integer> ids) { 035 super(parent, tr("Downloading changeset content")); 036 for (Integer id: ids != null ? ids : Collections.<Integer>emptyList()) { 037 if (id == null || id <= 0) { 038 continue; 039 } 040 toDownload.add(id); 041 } 042 } 043 044 /** 045 * Downloads the changeset with id <code>changesetId</code> (only "header" information, no content) 046 * 047 * @param changesetId the changeset id 048 * @throws OsmTransferException if something went wrong 049 */ 050 protected void downloadChangeset(int changesetId) throws OsmTransferException { 051 Changeset cs = reader.readChangeset(changesetId, false, getProgressMonitor().createSubTaskMonitor(0, false)); 052 ChangesetCache.getInstance().update(cs); 053 } 054 055 @Override 056 protected void realRun() throws SAXException, IOException, OsmTransferException { 057 try { 058 getProgressMonitor().setTicksCount(toDownload.size()); 059 int i = 0; 060 for (int id: toDownload) { 061 i++; 062 if (!isAvailableLocally(id)) { 063 getProgressMonitor().setCustomText(tr("({0}/{1}) Downloading changeset {2}...", i, toDownload.size(), id)); 064 downloadChangeset(id); 065 } 066 if (isCanceled()) 067 return; 068 getProgressMonitor().setCustomText(tr("({0}/{1}) Downloading content for changeset {2}...", i, toDownload.size(), id)); 069 ChangesetDataSet ds = reader.downloadChangeset(id, getProgressMonitor().createSubTaskMonitor(0, false)); 070 Changeset cs = ChangesetCache.getInstance().get(id); 071 cs.setContent(ds); 072 ChangesetCache.getInstance().update(cs); 073 downloadedChangesets.add(cs); 074 getProgressMonitor().worked(1); 075 } 076 } catch (OsmTransferCanceledException e) { 077 // the download was canceled by the user. This exception is caught if the user canceled the authentication dialog. 078 setCanceled(true); 079 Logging.trace(e); 080 return; 081 } catch (OsmTransferException e) { 082 if (isCanceled()) 083 return; 084 rememberLastException(e); 085 } 086 } 087 088 @Override 089 protected void finish() { 090 rememberDownloadedData(downloadedChangesets); 091 if (isCanceled()) 092 return; 093 if (lastException != null) { 094 ExceptionDialogUtil.explainException(lastException); 095 } 096 } 097 } 098 099 /** 100 * Creates a download task for a single changeset 101 * 102 * @param changesetId the changeset id. > 0 required. 103 * @throws IllegalArgumentException if changesetId <= 0 104 */ 105 public ChangesetContentDownloadTask(int changesetId) { 106 this(Main.parent, changesetId); 107 } 108 109 /** 110 * Creates a download task for a collection of changesets. null values and id <=0 in 111 * the collection are silently discarded. 112 * 113 * @param changesetIds the changeset ids. Empty collection assumed, if null. 114 */ 115 public ChangesetContentDownloadTask(Collection<Integer> changesetIds) { 116 this(Main.parent, changesetIds); 117 } 118 119 /** 120 * Creates a download task for a single changeset 121 * 122 * @param parent the parent component for the {@link org.openstreetmap.josm.gui.PleaseWaitDialog}. Must not be {@code null}. 123 * @param changesetId the changeset id. {@code >0} required. 124 * @throws IllegalArgumentException if {@code changesetId <= 0} 125 * @throws IllegalArgumentException if parent is {@code null} 126 */ 127 public ChangesetContentDownloadTask(Component parent, int changesetId) { 128 if (changesetId <= 0) 129 throw new IllegalArgumentException( 130 MessageFormat.format("Expected integer value > 0 for parameter ''{0}'', got ''{1}''", "changesetId", changesetId)); 131 setDownloadTask(new DownloadTask(parent, Collections.singleton(changesetId))); 132 } 133 134 /** 135 * Creates a download task for a collection of changesets. null values and id <=0 in 136 * the collection are sillently discarded. 137 * 138 * @param parent the parent component for the {@link org.openstreetmap.josm.gui.PleaseWaitDialog}. Must not be {@code null}. 139 * @param changesetIds the changeset ids. Empty collection assumed, if {@code null}. 140 * @throws IllegalArgumentException if parent is {@code null} 141 */ 142 public ChangesetContentDownloadTask(Component parent, Collection<Integer> changesetIds) { 143 setDownloadTask(new DownloadTask(parent, changesetIds)); 144 } 145 146 /** 147 * Replies true if the local {@link ChangesetCache} already includes the changeset with 148 * id <code>changesetId</code>. 149 * 150 * @param changesetId the changeset id 151 * @return true if the local {@link ChangesetCache} already includes the changeset with 152 * id <code>changesetId</code> 153 */ 154 protected static boolean isAvailableLocally(int changesetId) { 155 return ChangesetCache.getInstance().get(changesetId) != null; 156 } 157}