source: josm/trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmChangeTask.java@ 5345

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

fix #7857 - Mark osmChange primitives inside <modify> block as modified + allow to load remote .osc files

File size: 8.3 KB
Line 
1package org.openstreetmap.josm.actions.downloadtasks;
2
3import java.util.ArrayList;
4import java.util.Date;
5import java.util.HashSet;
6import java.util.Iterator;
7import java.util.List;
8import java.util.Set;
9import java.util.concurrent.Future;
10
11import org.openstreetmap.josm.Main;
12import org.openstreetmap.josm.data.Bounds;
13import org.openstreetmap.josm.data.osm.DataSet;
14import org.openstreetmap.josm.data.osm.NodeData;
15import org.openstreetmap.josm.data.osm.OsmPrimitive;
16import org.openstreetmap.josm.data.osm.PrimitiveData;
17import org.openstreetmap.josm.data.osm.PrimitiveId;
18import org.openstreetmap.josm.data.osm.RelationData;
19import org.openstreetmap.josm.data.osm.WayData;
20import org.openstreetmap.josm.data.osm.history.History;
21import org.openstreetmap.josm.data.osm.history.HistoryDataSet;
22import org.openstreetmap.josm.data.osm.history.HistoryDataSetListener;
23import org.openstreetmap.josm.data.osm.history.HistoryNode;
24import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
25import org.openstreetmap.josm.data.osm.history.HistoryRelation;
26import org.openstreetmap.josm.data.osm.history.HistoryWay;
27import org.openstreetmap.josm.gui.history.HistoryLoadTask;
28import org.openstreetmap.josm.gui.progress.ProgressMonitor;
29import org.openstreetmap.josm.io.OsmServerLocationReader;
30import org.openstreetmap.josm.io.OsmServerReader;
31import org.openstreetmap.josm.io.OsmTransferException;
32import org.openstreetmap.josm.tools.Pair;
33
34public class DownloadOsmChangeTask extends DownloadOsmTask {
35
36 @Override
37 public boolean acceptsUrl(String url) {
38 return url != null && (
39 url.matches("http://.*/api/0.6/changeset/\\p{Digit}+/download") // OSM API 0.6 changesets
40 || url.matches("http://.*/.*\\.osc") // Remote .osc files
41 );
42 }
43
44 /* (non-Javadoc)
45 * @see org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask#download(boolean, org.openstreetmap.josm.data.Bounds, org.openstreetmap.josm.gui.progress.ProgressMonitor)
46 */
47 @Override
48 public Future<?> download(boolean newLayer, Bounds downloadArea,
49 ProgressMonitor progressMonitor) {
50 return null;
51 }
52
53 /* (non-Javadoc)
54 * @see org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask#loadUrl(boolean, java.lang.String, org.openstreetmap.josm.gui.progress.ProgressMonitor)
55 */
56 @Override
57 public Future<?> loadUrl(boolean new_layer, String url,
58 ProgressMonitor progressMonitor) {
59 downloadTask = new DownloadTask(new_layer,
60 new OsmServerLocationReader(url),
61 progressMonitor);
62 // Extract .osc filename from URL to set the new layer name
63 extractOsmFilename("http://.*/(.*\\.osc)", url);
64 return Main.worker.submit(downloadTask);
65 }
66
67 protected class DownloadTask extends DownloadOsmTask.DownloadTask {
68
69 public DownloadTask(boolean newLayer, OsmServerReader reader,
70 ProgressMonitor progressMonitor) {
71 super(newLayer, reader, progressMonitor);
72 }
73
74 /* (non-Javadoc)
75 * @see org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask.DownloadTask#parseDataSet()
76 */
77 @Override
78 protected DataSet parseDataSet() throws OsmTransferException {
79 return reader.parseOsmChange(progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
80 }
81
82 /* (non-Javadoc)
83 * @see org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask.DownloadTask#finish()
84 */
85 @Override
86 protected void finish() {
87 super.finish();
88 if (isFailed() || isCanceled() || downloadedData == null)
89 return; // user canceled download or error occurred
90 try {
91 // A changeset does not contain all referred primitives, this is the list of incomplete ones
92 Set<OsmPrimitive> toLoad = new HashSet<OsmPrimitive>();
93 // For each incomplete primitive, we'll have to get its state at date it was referred
94 List<Pair<OsmPrimitive, Date>> toMonitor = new ArrayList<Pair<OsmPrimitive, Date>>();
95 for (OsmPrimitive p : downloadedData.allNonDeletedPrimitives()) {
96 if (p.isIncomplete()) {
97 Date timestamp = null;
98 for (OsmPrimitive ref : p.getReferrers()) {
99 if (!ref.isTimestampEmpty()) {
100 timestamp = ref.getTimestamp();
101 break;
102 }
103 }
104 if (toLoad.add(p)) {
105 toMonitor.add(new Pair<OsmPrimitive, Date>(p, timestamp));
106 }
107 }
108 }
109 if (isCanceled()) return;
110 // Updating process is asynchronous and done after each history request
111 HistoryDataSet.getInstance().addHistoryDataSetListener(new HistoryListener(toMonitor));
112 // Let's load all required history
113 Main.worker.submit(new HistoryLoadTask().add(toLoad));
114 } catch (Exception e) {
115 rememberException(e);
116 setFailed(true);
117 }
118 }
119 }
120 /**
121 * Asynchroneous updater of incomplete primitives.
122 *
123 */
124 private static class HistoryListener implements HistoryDataSetListener {
125
126 private final List<Pair<OsmPrimitive, Date>> toMonitor;
127
128 public HistoryListener(List<Pair<OsmPrimitive, Date>> toMonitor) {
129 this.toMonitor = toMonitor;
130 }
131
132 @Override
133 public void historyUpdated(HistoryDataSet source, PrimitiveId id) {
134 for (Iterator<Pair<OsmPrimitive, Date>> it = toMonitor.iterator(); it.hasNext();) {
135 Pair<OsmPrimitive, Date> pair = it.next();
136 History history = source.getHistory(pair.a.getPrimitiveId());
137 // If the history has been loaded and a timestamp is known
138 if (history != null && pair.b != null) {
139 // Lookup for the primitive version at the specified timestamp
140 HistoryOsmPrimitive hp = history.getByDate(pair.b);
141 if (hp != null) {
142 PrimitiveData data = null;
143
144 switch (pair.a.getType()) {
145 case NODE:
146 data = new NodeData();
147 ((NodeData)data).setCoor(((HistoryNode)hp).getCoords());
148 break;
149 case WAY:
150 data = new WayData();
151 ((WayData)data).setNodes(((HistoryWay)hp).getNodes());
152 break;
153 case RELATION:
154 data = new RelationData();
155 ((RelationData)data).setMembers(((HistoryRelation)hp).getMembers());
156 break;
157 default: throw new AssertionError();
158 }
159
160 data.setUser(hp.getUser());
161 try {
162 data.setVisible(hp.isVisible());
163 } catch (IllegalStateException e) {
164 System.err.println("Cannot change visibility for "+pair.a+": "+e.getMessage());
165 }
166 data.setTimestamp(hp.getTimestamp());
167 data.setKeys(hp.getTags());
168 data.setOsmId(hp.getChangesetId(), (int) hp.getVersion());
169
170 // Load the history data
171 pair.a.load(data);
172 // Forget this primitive
173 it.remove();
174 }
175 }
176 }
177 if (toMonitor.isEmpty()) {
178 // No more primitive to update. Processing is finished
179 source.removeHistoryDataSetListener(this);
180 // Be sure all updated primitives are correctly drawn
181 Main.map.repaint();
182 }
183 }
184
185 @Override
186 public void historyDataSetCleared(HistoryDataSet source) {
187 }
188 }
189}
Note: See TracBrowser for help on using the repository browser.