source: josm/trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTaskList.java@ 2097

Last change on this file since 2097 was 2097, checked in by Gubaer, 15 years ago

applied #3318: patch by dmuecke: josm opens modal error dialog for every block that fails to download

File size: 9.8 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.awt.EventQueue;
7import java.awt.geom.Area;
8import java.awt.geom.Rectangle2D;
9import java.util.ArrayList;
10import java.util.Collection;
11import java.util.HashSet;
12import java.util.LinkedList;
13import java.util.List;
14import java.util.Set;
15
16import javax.swing.JOptionPane;
17
18import org.openstreetmap.josm.Main;
19import org.openstreetmap.josm.actions.UpdateSelectionAction;
20import org.openstreetmap.josm.data.osm.DataSet;
21import org.openstreetmap.josm.data.osm.OsmPrimitive;
22import org.openstreetmap.josm.gui.download.DownloadDialog.DownloadTask;
23import org.openstreetmap.josm.gui.layer.Layer;
24import org.openstreetmap.josm.gui.layer.OsmDataLayer;
25import org.openstreetmap.josm.gui.progress.ProgressMonitor;
26
27/**
28 * This class encapsulates the downloading of several bounding boxes that would otherwise be too
29 * large to download in one go. Error messages will be collected for all downloads and displayed
30 * as a list in the end.
31 * @author xeen
32 *
33 */
34public class DownloadOsmTaskList implements Runnable {
35 private List<DownloadTask> osmTasks = new LinkedList<DownloadTask>();
36 private ProgressMonitor progressMonitor;
37
38 /**
39 * Downloads a list of areas from the OSM Server
40 * @param newLayer Set to true if all areas should be put into a single new layer
41 * @param The List of Rectangle2D to download
42 */
43 public void download(boolean newLayer, List<Rectangle2D> rects, ProgressMonitor progressMonitor) {
44 this.progressMonitor = progressMonitor;
45 if(newLayer) {
46 Layer l = new OsmDataLayer(new DataSet(), OsmDataLayer.createNewName(), null);
47 Main.main.addLayer(l);
48 Main.map.mapView.setActiveLayer(l);
49 }
50
51 progressMonitor.beginTask(null, rects.size());
52 try {
53 int i = 0;
54 for(Rectangle2D td : rects) {
55 i++;
56 DownloadTask dt = new DownloadOsmTask();
57 ProgressMonitor childProgress = progressMonitor.createSubTaskMonitor(1, false);
58 childProgress.setSilent(true);
59 childProgress.setCustomText(tr("Download {0} of {1} ({2} left)", i, rects.size(), rects.size()-i));
60 dt.download(null, td.getMinY(), td.getMinX(), td.getMaxY(), td.getMaxX(), childProgress);
61 osmTasks.add(dt);
62 }
63 } finally {
64 // If we try to get the error message now the download task will never have been started
65 // and we'd be stuck in a classical dead lock. Instead attach this to the worker and once
66 // run() gets called all downloadTasks have finished and we can grab the error messages.
67 Main.worker.execute(this);
68 }
69 }
70
71 /**
72 * Downloads a list of areas from the OSM Server
73 * @param newLayer Set to true if all areas should be put into a single new layer
74 * @param The Collection of Areas to download
75 */
76 public void download(boolean newLayer, Collection<Area> areas, ProgressMonitor progressMonitor) {
77 progressMonitor.beginTask(tr("Updating data"));
78 try {
79 List<Rectangle2D> rects = new LinkedList<Rectangle2D>();
80 for(Area a : areas) {
81 rects.add(a.getBounds2D());
82 }
83
84 download(newLayer, rects, progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
85 } finally {
86 progressMonitor.finishTask();
87 }
88 }
89
90 /**
91 * Grabs and displays the error messages after all download threads have finished.
92 */
93 public void run() {
94 progressMonitor.finishTask();
95 String errors = "";
96
97 LinkedList<Integer> shown = new LinkedList<Integer>();
98 for(DownloadTask dt : osmTasks) {
99 String err = dt.getErrorMessage();
100 // avoid display of identical messages
101 if (err.equals("") || shown.contains(err.hashCode())) {
102 continue;
103 }
104 shown.add(err.hashCode());
105 errors += "<br>* " + err;
106 }
107
108 if(! errors.equals("")) {
109 JOptionPane.showMessageDialog(
110 Main.parent,
111 "<html>"+tr("The following errors occurred during mass download:{0}", errors)
112 +"</html>",
113 tr("Errors during Download"),
114 JOptionPane.ERROR_MESSAGE);
115 return;
116 }
117
118 // FIXME: this is a hack. We assume that the user canceled the whole download if at least
119 // one task was canceled or if it failed
120 //
121 for (DownloadTask task: osmTasks) {
122 if (task instanceof DownloadOsmTask) {
123 DownloadOsmTask osmTask = (DownloadOsmTask)task;
124 if (osmTask.isCanceled() || osmTask.isFailed())
125 return;
126 }
127 }
128 final OsmDataLayer editLayer = Main.map.mapView.getEditLayer();
129 if (editLayer != null) {
130 Set<OsmPrimitive> myPrimitives = getCompletePrimitives(editLayer.data);
131 for (DownloadTask task : osmTasks) {
132 if(task instanceof DownloadOsmTask) {
133 DataSet ds = ((DownloadOsmTask)task).getDownloadedData();
134 if (ds != null) {
135 myPrimitives.removeAll(ds.nodes);
136 myPrimitives.removeAll(ds.ways);
137 myPrimitives.removeAll(ds.relations);
138 }
139 }
140 }
141 if (! myPrimitives.isEmpty()) {
142 handlePotentiallyDeletedPrimitives(myPrimitives);
143 }
144 }
145 }
146
147
148 /**
149 * Replies the set of ids of all complete primitives (i.e. those with
150 * ! primitive.incomplete)
151 *
152 * @return the set of ids of all complete primitives
153 */
154 protected Set<OsmPrimitive> getCompletePrimitives(DataSet ds) {
155 HashSet<OsmPrimitive> ret = new HashSet<OsmPrimitive>();
156 for (OsmPrimitive primitive : ds.nodes) {
157 if (!primitive.incomplete && primitive.getId() == 0) {
158 ret.add(primitive);
159 }
160 }
161 for (OsmPrimitive primitive : ds.ways) {
162 if (! primitive.incomplete && primitive.getId() == 0) {
163 ret.add(primitive);
164 }
165 }
166 for (OsmPrimitive primitive : ds.relations) {
167 if (! primitive.incomplete && primitive.getId() == 0) {
168 ret.add(primitive);;
169 }
170 }
171 return ret;
172 }
173
174 /**
175 * Updates the local state of a set of primitives (given by a set of primitive
176 * ids) with the state currently held on the server.
177 *
178 * @param potentiallyDeleted a set of ids to check update from the server
179 */
180 protected void updatePotentiallyDeletedPrimitives(Set<OsmPrimitive> potentiallyDeleted) {
181 final ArrayList<OsmPrimitive> toSelect = new ArrayList<OsmPrimitive>();
182 for (OsmPrimitive primitive : potentiallyDeleted) {
183 if (primitive != null) {
184 toSelect.add(primitive);
185 }
186 }
187 EventQueue.invokeLater(
188 new Runnable() {
189 public void run() {
190 new UpdateSelectionAction().updatePrimitives(toSelect);
191 }
192 }
193 );
194 }
195
196 /**
197 * Processes a set of primitives (given by a set of their ids) which might be
198 * deleted on the server. First prompts the user whether he wants to check
199 * the current state on the server. If yes, retrieves the current state on the server
200 * and checks whether the primitives are indeed deleted on the server.
201 *
202 * @param potentiallyDeleted a set of primitives (given by their ids)
203 */
204 protected void handlePotentiallyDeletedPrimitives(Set<OsmPrimitive> potentiallyDeleted) {
205 String [] options = {
206 "Check on the server",
207 "Ignore"
208 };
209
210 String message = tr("<html>"
211 + "There are {0} primitives in your local dataset which<br>"
212 + "might be deleted on the server. If you later try to delete or<br>"
213 + "update them the server is likely to report a<br>"
214 + "conflict.<br>"
215 + "<br>"
216 + "Click <strong>{1}</strong> to check the state of these primitives<br>"
217 + "on the server.<br>"
218 + "Click <strong>{2}</strong> to ignore.<br>"
219 + "</html>",
220 potentiallyDeleted.size(), options[0], options[1]
221 );
222
223 int ret =JOptionPane.showOptionDialog(
224 Main.parent,
225 message,
226 tr("Deleted or moved primitives"),
227 JOptionPane.YES_NO_OPTION,
228 JOptionPane.WARNING_MESSAGE,
229 null,
230 options,
231 options[0]
232 );
233 switch(ret) {
234 case JOptionPane.CLOSED_OPTION: return;
235 case JOptionPane.NO_OPTION: return;
236 case JOptionPane.YES_OPTION: updatePotentiallyDeletedPrimitives(potentiallyDeleted); break;
237 }
238 }
239
240 /**
241 * Replies the set of primitive ids which have been downloaded by this task list
242 *
243 * @return the set of primitive ids which have been downloaded by this task list
244 */
245 public Set<OsmPrimitive> getDownloadedPrimitives() {
246 HashSet<OsmPrimitive> ret = new HashSet<OsmPrimitive>();
247 for (DownloadTask task : osmTasks) {
248 if(task instanceof DownloadOsmTask) {
249 DataSet ds = ((DownloadOsmTask)task).getDownloadedData();
250 if (ds != null) {
251 ret.addAll(ds.nodes);
252 ret.addAll(ds.ways);
253 ret.addAll(ds.relations);
254 }
255 }
256 }
257 return ret;
258 }
259}
Note: See TracBrowser for help on using the repository browser.