source: josm/trunk/src/org/openstreetmap/josm/gui/history/HistoryLoadTask.java@ 16155

Last change on this file since 16155 was 16123, checked in by Don-vip, 4 years ago

fix #18918 - Enable Ctrl-H shortcut to display history of primitives selected in changeset manager

  • Property svn:eol-style set to native
File size: 9.0 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.history;
3
4import static org.openstreetmap.josm.tools.I18n.marktr;
5import static org.openstreetmap.josm.tools.I18n.tr;
6
7import java.awt.Component;
8import java.io.IOException;
9import java.util.ArrayList;
10import java.util.Collection;
11import java.util.HashSet;
12import java.util.List;
13import java.util.Objects;
14import java.util.Set;
15
16import org.openstreetmap.josm.data.osm.Changeset;
17import org.openstreetmap.josm.data.osm.OsmPrimitive;
18import org.openstreetmap.josm.data.osm.PrimitiveId;
19import org.openstreetmap.josm.data.osm.history.History;
20import org.openstreetmap.josm.data.osm.history.HistoryDataSet;
21import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
22import org.openstreetmap.josm.gui.ExceptionDialogUtil;
23import org.openstreetmap.josm.gui.PleaseWaitRunnable;
24import org.openstreetmap.josm.gui.progress.ProgressMonitor;
25import org.openstreetmap.josm.io.ChangesetQuery;
26import org.openstreetmap.josm.io.OsmServerChangesetReader;
27import org.openstreetmap.josm.io.OsmServerHistoryReader;
28import org.openstreetmap.josm.io.OsmTransferException;
29import org.openstreetmap.josm.tools.CheckParameterUtil;
30import org.xml.sax.SAXException;
31
32/**
33 * Loads the object history of a collection of objects from the server.
34 *
35 * It provides a fluent API for configuration.
36 *
37 * Sample usage:
38 *
39 * <pre>
40 * HistoryLoadTask task = new HistoryLoadTask()
41 * .add(node)
42 * .add(way)
43 * .add(relation)
44 * .add(aHistoryItem);
45 *
46 * MainApplication.worker.execute(task);
47 * </pre>
48 */
49public class HistoryLoadTask extends PleaseWaitRunnable {
50
51 private boolean canceled;
52 private Exception lastException;
53 private final Set<PrimitiveId> toLoad = new HashSet<>();
54 private HistoryDataSet loadedData;
55 private OsmServerHistoryReader reader;
56 private boolean getChangesetData = true;
57
58 /**
59 * Constructs a new {@code HistoryLoadTask}.
60 */
61 public HistoryLoadTask() {
62 super(tr("Load history"), true);
63 }
64
65 /**
66 * Constructs a new {@code HistoryLoadTask}.
67 *
68 * @param parent the component to be used as reference to find the
69 * parent for {@link org.openstreetmap.josm.gui.PleaseWaitDialog}.
70 * Must not be <code>null</code>.
71 * @throws NullPointerException if parent is <code>null</code>
72 */
73 public HistoryLoadTask(Component parent) {
74 super(Objects.requireNonNull(parent, "parent"), tr("Load history"), true);
75 }
76
77 /**
78 * Adds an object whose history is to be loaded.
79 *
80 * @param pid the primitive id. Must not be null. Id &gt; 0 required.
81 * @return this task
82 */
83 public HistoryLoadTask add(PrimitiveId pid) {
84 CheckParameterUtil.ensureThat(pid.getUniqueId() > 0, "id > 0");
85 toLoad.add(pid);
86 return this;
87 }
88
89 /**
90 * Adds an object to be loaded, the object is specified by a history item.
91 *
92 * @param primitive the history item
93 * @return this task
94 * @throws NullPointerException if primitive is null
95 */
96 public HistoryLoadTask add(HistoryOsmPrimitive primitive) {
97 return add(primitive.getPrimitiveId());
98 }
99
100 /**
101 * Adds an object to be loaded, the object is specified by an already loaded object history.
102 *
103 * @param history the history. Must not be null.
104 * @return this task
105 * @throws NullPointerException if history is null
106 */
107 public HistoryLoadTask add(History history) {
108 return add(history.getPrimitiveId());
109 }
110
111 /**
112 * Adds an object to be loaded, the object is specified by an OSM primitive.
113 *
114 * @param primitive the OSM primitive. Must not be null. primitive.getOsmId() &gt; 0 required.
115 * @return this task
116 * @throws NullPointerException if the primitive is null
117 * @throws IllegalArgumentException if primitive.getOsmId() &lt;= 0
118 */
119 public HistoryLoadTask add(OsmPrimitive primitive) {
120 CheckParameterUtil.ensureThat(primitive.getOsmId() > 0, "id > 0");
121 return add(primitive.getOsmPrimitiveId());
122 }
123
124 /**
125 * Adds a collection of objects to loaded, specified by a collection of OSM primitives.
126 *
127 * @param primitives the OSM primitives. Must not be <code>null</code>.
128 * <code>primitive.getId() &gt; 0</code> required.
129 * @return this task
130 * @throws NullPointerException if primitives is null
131 * @throws IllegalArgumentException if one of the ids in the collection &lt;= 0
132 * @since 16123
133 */
134 public HistoryLoadTask addPrimitiveIds(Collection<? extends PrimitiveId> primitives) {
135 primitives.forEach(this::add);
136 return this;
137 }
138
139 /**
140 * Adds a collection of objects to loaded, specified by a collection of OSM primitives.
141 *
142 * @param primitives the OSM primitives. Must not be <code>null</code>.
143 * <code>primitive.getId() &gt; 0</code> required.
144 * @return this task
145 * @throws NullPointerException if primitives is null
146 * @throws IllegalArgumentException if one of the ids in the collection &lt;= 0
147 * @since 16123
148 */
149 public HistoryLoadTask addOsmPrimitives(Collection<? extends OsmPrimitive> primitives) {
150 primitives.forEach(this::add);
151 return this;
152 }
153
154 @Override
155 protected void cancel() {
156 if (reader != null) {
157 reader.cancel();
158 }
159 canceled = true;
160 }
161
162 @Override
163 protected void finish() {
164 if (isCanceled())
165 return;
166 if (lastException != null) {
167 ExceptionDialogUtil.explainException(lastException);
168 return;
169 }
170 HistoryDataSet.getInstance().mergeInto(loadedData);
171 }
172
173 @Override
174 protected void realRun() throws SAXException, IOException, OsmTransferException {
175 loadedData = new HistoryDataSet();
176 int ticks = toLoad.size();
177 if (getChangesetData)
178 ticks *= 2;
179 try {
180 progressMonitor.setTicksCount(ticks);
181 for (PrimitiveId pid: toLoad) {
182 if (canceled) {
183 break;
184 }
185 loadHistory(pid);
186 }
187 } catch (OsmTransferException e) {
188 lastException = e;
189 }
190 }
191
192 private void loadHistory(PrimitiveId pid) throws OsmTransferException {
193 String msg = getLoadingMessage(pid);
194 progressMonitor.indeterminateSubTask(tr(msg, Long.toString(pid.getUniqueId())));
195 reader = null;
196 HistoryDataSet ds;
197 try {
198 reader = new OsmServerHistoryReader(pid.getType(), pid.getUniqueId());
199 if (getChangesetData) {
200 ds = loadHistory(reader, progressMonitor);
201 } else {
202 ds = reader.parseHistory(progressMonitor.createSubTaskMonitor(1, false));
203 }
204 } catch (OsmTransferException e) {
205 if (canceled)
206 return;
207 throw e;
208 }
209 loadedData.mergeInto(ds);
210 }
211
212 protected static HistoryDataSet loadHistory(OsmServerHistoryReader reader, ProgressMonitor progressMonitor) throws OsmTransferException {
213 HistoryDataSet ds = reader.parseHistory(progressMonitor.createSubTaskMonitor(1, false));
214 if (ds != null) {
215 // load corresponding changesets (mostly for changeset comment)
216 OsmServerChangesetReader changesetReader = new OsmServerChangesetReader();
217 List<Long> changesetIds = new ArrayList<>(ds.getChangesetIds());
218
219 // query changesets 100 by 100 (OSM API limit)
220 int n = ChangesetQuery.MAX_CHANGESETS_NUMBER;
221 for (int i = 0; i < changesetIds.size(); i += n) {
222 for (Changeset c : changesetReader.queryChangesets(
223 new ChangesetQuery().forChangesetIds(changesetIds.subList(i, Math.min(i + n, changesetIds.size()))),
224 progressMonitor.createSubTaskMonitor(1, false))) {
225 ds.putChangeset(c);
226 }
227 }
228 }
229 return ds;
230 }
231
232 protected static String getLoadingMessage(PrimitiveId pid) {
233 switch (pid.getType()) {
234 case NODE:
235 return marktr("Loading history for node {0}");
236 case WAY:
237 return marktr("Loading history for way {0}");
238 case RELATION:
239 return marktr("Loading history for relation {0}");
240 default:
241 return "";
242 }
243 }
244
245 /**
246 * Determines if this task has ben canceled.
247 * @return {@code true} if this task has ben canceled
248 */
249 public boolean isCanceled() {
250 return canceled;
251 }
252
253 /**
254 * Returns the last exception that occurred during loading, if any.
255 * @return the last exception that occurred during loading, or {@code null}
256 */
257 public Exception getLastException() {
258 return lastException;
259 }
260
261 /**
262 * Determine if changeset information is needed. By default it is retrieved.
263 * @param b false means don't retrieve changeset data.
264 * @since 14763
265 */
266 public void setChangesetDataNeeded(boolean b) {
267 getChangesetData = b;
268 }
269}
Note: See TracBrowser for help on using the repository browser.