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

Last change on this file since 1811 was 1811, checked in by jttt, 15 years ago

PleaseWait refactoring. Progress is now reported using ProgressMonitor interface, that is available through PleaseWaitRunnable.

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