Changeset 1690 in josm for trunk/src/org/openstreetmap/josm/actions/UpdateSelectionAction.java
- Timestamp:
- 23.06.2009 22:03:37 (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/actions/UpdateSelectionAction.java
r1670 r1690 6 6 import java.awt.event.ActionEvent; 7 7 import java.awt.event.KeyEvent; 8 import java.io.IOException;9 import java.net.HttpURLConnection;10 import java.util.ArrayList;11 8 import java.util.Collection; 9 import java.util.HashSet; 10 import java.util.Set; 12 11 13 12 import javax.swing.JOptionPane; … … 15 14 import org.openstreetmap.josm.Main; 16 15 import org.openstreetmap.josm.command.PurgePrimitivesCommand; 17 import org.openstreetmap.josm.command.UndeletePrimitivesCommand;18 16 import org.openstreetmap.josm.data.osm.DataSet; 19 import org.openstreetmap.josm.data.osm.Node;20 17 import org.openstreetmap.josm.data.osm.OsmPrimitive; 21 import org.openstreetmap.josm.data.osm.OsmPrimitiveType; 22 import org.openstreetmap.josm.data.osm.Relation; 23 import org.openstreetmap.josm.data.osm.RelationMember; 24 import org.openstreetmap.josm.data.osm.Way; 25 import org.openstreetmap.josm.gui.PleaseWaitRunnable; 26 import org.openstreetmap.josm.io.OsmApi; 27 import org.openstreetmap.josm.io.OsmApiException; 28 import org.openstreetmap.josm.io.OsmServerObjectReader; 29 import org.openstreetmap.josm.io.OsmTransferException; 18 import org.openstreetmap.josm.io.MultiFetchServerObjectReader; 30 19 import org.openstreetmap.josm.tools.Shortcut; 31 import org.xml.sax.SAXException;32 20 33 21 /** … … 41 29 42 30 /** 43 * Undelete a node which is already deleted on the server. The API44 * doesn't offer a call for "undeleting" a node. We therefore create45 * a clone of the node which we flag as new. On the next upload the46 * server will assign the node a new id.47 *48 * @param node the node to undelete49 */50 protected void undeleteNode(Node node) {51 UndeletePrimitivesCommand cmd = new UndeletePrimitivesCommand(node);52 Main.main.undoRedo.add(cmd);53 }54 55 /**56 * Undelete a way which is already deleted on the server.57 *58 * This method also checks whether there are additional nodes referred to by59 * this way which are deleted on the server too.60 *61 * @param way the way to undelete62 * @see #undeleteNode(Node)63 */64 protected void undeleteWay(final Way way) {65 class NodeGoneChecker extends PleaseWaitRunnable {66 67 UndeletePrimitivesCommand cmd = null;68 69 public NodeGoneChecker() {70 super(tr("Undeleting Way..."), false);71 }72 73 @Override74 protected void cancel() {75 OsmApi.getOsmApi().cancel();76 }77 78 @Override79 protected void finish() {80 if (cmd != null) {81 Main.main.undoRedo.add(cmd);82 }83 }84 85 /**86 * replies the subset of the node list which already87 * have an assigned id88 *89 * @param way the way90 * @return the node list91 */92 protected ArrayList<Node> getCandidateNodes(Way way) {93 ArrayList<Node> candidates = new ArrayList<Node>();94 for (Node n : way.nodes) {95 if (n.id > 0 && ! candidates.contains(n)) {96 candidates.add(n);97 }98 }99 return candidates;100 }101 102 /**103 * checks whether a specific node is deleted on the server104 *105 * @param n the node106 * @return true, if the node is deleted; false, otherwise107 * @throws OsmTransferException thrown, if an error occurs while communicating with the API108 */109 protected boolean isGone(Node n) throws OsmTransferException {110 OsmServerObjectReader reader = new OsmServerObjectReader(n.id, OsmPrimitiveType.from(n), true);111 try {112 reader.parseOsm();113 } catch(OsmApiException e) {114 if (e.getResponseCode() == HttpURLConnection.HTTP_GONE)115 return true;116 throw e;117 } catch(OsmTransferException e) {118 throw e;119 }120 return false;121 }122 123 /**124 * displays a confirmation message. The user has to confirm that additional dependent125 * nodes should be undeleted too.126 *127 * @param way the way128 * @param dependent a list of dependent nodes which have to be undelete too129 * @return true, if the user confirms; false, otherwise130 */131 protected boolean confirmUndeleteDependentPrimitives(Way way, ArrayList<OsmPrimitive> dependent) {132 String [] options = {133 tr("Yes, undelete them too"),134 tr("No, cancel operation")135 };136 int ret = JOptionPane.showOptionDialog(137 Main.parent,138 tr("<html>There are {0} additional nodes used by way {1}<br>"139 + "which are deleted on the server.<br>"140 + "<br>"141 + "Do you want to undelete these nodes too?</html>",142 Long.toString(dependent.size()), Long.toString(way.id)),143 tr("Undelete additional nodes?"),144 JOptionPane.YES_NO_OPTION,145 JOptionPane.QUESTION_MESSAGE,146 null,147 options,148 options[0]149 );150 151 switch(ret) {152 case JOptionPane.CLOSED_OPTION: return false;153 case JOptionPane.YES_OPTION: return true;154 case JOptionPane.NO_OPTION: return false;155 }156 return false;157 158 }159 160 @Override161 protected void realRun() throws SAXException, IOException, OsmTransferException {162 ArrayList<Node> candidate = getCandidateNodes(way);163 ArrayList<OsmPrimitive> toDelete = new ArrayList<OsmPrimitive>();164 Main.pleaseWaitDlg.progress.setMinimum(0);165 Main.pleaseWaitDlg.progress.setMaximum(candidate.size());166 167 for (int i=0; i<candidate.size();i++) {168 Node n = candidate.get(i);169 Main.pleaseWaitDlg.progress.setValue(i);170 Main.pleaseWaitDlg.currentAction.setText(tr("Checking whether node {0} is gone ...", n.id));171 if (isGone(n)) {172 toDelete.add(n);173 }174 }175 if (toDelete.size() > 0) {176 if (!confirmUndeleteDependentPrimitives(way, toDelete))177 return;178 }179 180 toDelete.add(way);181 cmd = new UndeletePrimitivesCommand(toDelete);182 }183 }184 185 Main.worker.submit(new NodeGoneChecker());186 }187 188 /**189 * Undelete a relation which is already deleted on the server.190 *191 * This method checks whether there are additional primitives referred to by192 * this relation which are already deleted on the server.193 *194 * @param r the relation195 * @see #undeleteNode(Node)196 */197 protected void undeleteRelation(final Relation r) {198 class RelationMemberGoneChecker extends PleaseWaitRunnable {199 200 UndeletePrimitivesCommand cmd = null;201 202 public RelationMemberGoneChecker() {203 super(tr("Undeleting relation..."), false);204 }205 206 @Override207 protected void cancel() {208 OsmApi.getOsmApi().cancel();209 }210 211 @Override212 protected void finish() {213 if (cmd != null) {214 Main.main.undoRedo.add(cmd);215 }216 }217 218 protected ArrayList<OsmPrimitive> getCandidateRelationMembers(Relation r) {219 ArrayList<OsmPrimitive> candidates = new ArrayList<OsmPrimitive>();220 for (RelationMember m : r.members) {221 if (m.member.id > 0 && !candidates.contains(m.member)) {222 candidates.add(m.member);223 }224 }225 return candidates;226 }227 228 protected boolean isGone(OsmPrimitive primitive) throws OsmTransferException {229 OsmServerObjectReader reader = new OsmServerObjectReader(230 primitive.id,231 OsmPrimitiveType.from(primitive),232 true);233 try {234 reader.parseOsm();235 } catch(OsmApiException e) {236 if (e.getResponseCode() == HttpURLConnection.HTTP_GONE)237 return true;238 throw e;239 } catch(OsmTransferException e) {240 throw e;241 }242 return false;243 }244 245 protected boolean confirmUndeleteDependentPrimitives(Relation r, ArrayList<OsmPrimitive> dependent) {246 String [] options = {247 tr("Yes, undelete them too"),248 tr("No, cancel operation")249 };250 int ret = JOptionPane.showOptionDialog(251 Main.parent,252 tr("<html>There are {0} additional primitives referred to by relation {1}<br>"253 + "which are deleted on the server.<br>"254 + "<br>"255 + "Do you want to undelete them too?</html>",256 Long.toString(dependent.size()), Long.toString(r.id)),257 tr("Undelete dependent primitives?"),258 JOptionPane.YES_NO_OPTION,259 JOptionPane.QUESTION_MESSAGE,260 null,261 options,262 options[0]263 );264 265 switch(ret) {266 case JOptionPane.CLOSED_OPTION: return false;267 case JOptionPane.YES_OPTION: return true;268 case JOptionPane.NO_OPTION: return false;269 }270 return false;271 272 }273 274 @Override275 protected void realRun() throws SAXException, IOException, OsmTransferException {276 ArrayList<OsmPrimitive> candidate = getCandidateRelationMembers(r);277 ArrayList<OsmPrimitive> toDelete = new ArrayList<OsmPrimitive>();278 Main.pleaseWaitDlg.progress.setMinimum(0);279 Main.pleaseWaitDlg.progress.setMaximum(candidate.size());280 281 for (int i=0; i<candidate.size();i++) {282 OsmPrimitive primitive = candidate.get(i);283 Main.pleaseWaitDlg.progress.setValue(i);284 Main.pleaseWaitDlg.currentAction.setText(tr("Checking whether primitive {0} is gone ...", primitive.id));285 if (isGone(primitive)) {286 toDelete.add(primitive);287 }288 }289 if (toDelete.size() > 0) {290 if (!confirmUndeleteDependentPrimitives(r, toDelete))291 return;292 }293 294 toDelete.add(r);295 cmd = new UndeletePrimitivesCommand(toDelete);296 }297 }298 299 Main.worker.submit(new RelationMemberGoneChecker());300 }301 302 /**303 * User has decided to keep his local version of a primitive which had been deleted304 * on the server305 *306 * @param id the primitive id307 */308 protected void handlePrimitiveGoneKeepMine(long id) {309 OsmPrimitive primitive = Main.main.editLayer().data.getPrimitiveById(id);310 if (primitive instanceof Node) {311 undeleteNode((Node)primitive);312 } else if (primitive instanceof Way) {313 undeleteWay((Way)primitive);314 } else if (primitive instanceof Relation) {315 undeleteRelation((Relation)primitive);316 }317 }318 319 /**320 * User has decided to delete his local version of a primitive which had been deleted321 * on the server322 *323 * @param id the primitive id324 */325 protected void handlePrimitiveGoneDeleteMine(long id) {326 OsmPrimitive primitive = Main.main.editLayer().data.getPrimitiveById(id);327 PurgePrimitivesCommand cmd = new PurgePrimitivesCommand(primitive);328 Main.main.undoRedo.add(cmd);329 Main.map.mapView.repaint();330 }331 332 /**333 31 * handle an exception thrown because a primitive was deleted on the server 334 32 * … … 336 34 */ 337 35 protected void handlePrimitiveGoneException(long id) { 338 Object[] options = new Object[] { 339 tr("Keep mine"), 340 tr("Delete mine"), 341 tr("Cancel") 342 }; 343 Object defaultOption = options[0]; 344 String msg = tr("<html>The OSM primitive with id <strong>{0}</strong> has been deleted<br>" 345 + "on the server by another mapper.<br>" 346 + "<br>" 347 + "Click <strong>{1}</strong> to keep your primitive and ignore the deleted state.<br>" 348 + "Your primitive will be assigend a new id.<br>" 349 + "Click <strong>{2}</strong> to accept the state on the server and to delete your primitive.<br>" 350 + "Click <strong>{3}</strong> to cancel.<br>", 351 id, options[0], options[1], options[2] 352 ); 353 int ret = JOptionPane.showOptionDialog( 354 null, 355 msg, 356 tr("Primitive deleted on the server"), 357 JOptionPane.YES_NO_CANCEL_OPTION, 358 JOptionPane.ERROR_MESSAGE, 359 null, 360 options, 361 defaultOption 362 ); 363 switch(ret) { 364 case JOptionPane.CLOSED_OPTION: return; 365 case JOptionPane.CANCEL_OPTION: return; 366 case 0: handlePrimitiveGoneKeepMine(id); break; 367 case 1: handlePrimitiveGoneDeleteMine(id); break; 368 default: 369 // should not happen 370 throw new IllegalStateException(tr("unexpected return value. Got {0}", ret)); 36 MultiFetchServerObjectReader reader = new MultiFetchServerObjectReader(); 37 reader.append(Main.main.editLayer().data,id); 38 DataSet ds = null; 39 try { 40 ds = reader.parseOsm(); 41 } catch(Exception e) { 42 handleUpdateException(e); 43 return; 371 44 } 45 Main.main.editLayer().mergeFrom(ds); 372 46 } 373 47 … … 378 52 * @param e the exception 379 53 */ 380 protected void handleUpdateException(long id, Exception e) { 381 if (e instanceof OsmApiException) { 382 OsmApiException ex = (OsmApiException)e; 383 // if the primitive was deleted on the server ask the user 384 // whether he wants to undelete it 385 // 386 if (ex.getResponseCode() == HttpURLConnection.HTTP_GONE) { 387 handlePrimitiveGoneException(id); 388 return; 389 } 390 } 391 54 protected void handleUpdateException(Exception e) { 392 55 e.printStackTrace(); 393 56 JOptionPane.showMessageDialog( … … 406 69 JOptionPane.showMessageDialog( 407 70 Main.parent, 408 tr("Could not find primitive with id {0} in the current dataset", id),71 tr("Could not find primitive with id {0} in the current dataset", new Long(id).toString()), 409 72 tr("Missing primitive"), 410 73 JOptionPane.ERROR_MESSAGE … … 413 76 414 77 /** 415 * Updates the primitive with id <code>id</code> with the current state kept on the server.416 78 * 417 * @param id 79 * 80 * 418 81 */ 419 public void updatePrimitive(long id) { 420 OsmPrimitive primitive = Main.main.editLayer().data.getPrimitiveById(id); 421 if (primitive == null) { 422 handleMissingPrimitive(id); 423 return; 424 } 425 OsmServerObjectReader reader = new OsmServerObjectReader( 426 id, 427 OsmPrimitiveType.from(primitive), 428 true); 82 public void updatePrimitives(Collection<OsmPrimitive> selection) { 83 MultiFetchServerObjectReader reader = new MultiFetchServerObjectReader(); 84 reader.append(selection); 429 85 DataSet ds = null; 430 86 try { 431 87 ds = reader.parseOsm(); 432 88 } catch(Exception e) { 433 handleUpdateException( id,e);89 handleUpdateException(e); 434 90 return; 435 91 } … … 437 93 } 438 94 95 public void updatePrimitive(long id) { 96 OsmPrimitive primitive = Main.main.editLayer().data.getPrimitiveById(id); 97 Set<OsmPrimitive> s = new HashSet<OsmPrimitive>(); 98 s.add(primitive); 99 updatePrimitives(s); 100 } 439 101 440 102 public UpdateSelectionAction() { … … 461 123 return; 462 124 } 463 464 // check whether the current selection has an acceptable range. 465 // We don't want to hammer the API with hundreds of individual 466 // GET requests. 467 // 468 if (selection.size() > DEFAULT_MAX_SIZE_UPDATE_SELECTION) { 469 JOptionPane.showMessageDialog( 470 Main.parent, 471 tr("<html>There are <strong>{0}</strong> primitives <br>" 472 + "selected for individual update. Please reduce the selection<br>" 473 + "to max. {1} primitives.</html>", 474 selection.size(), DEFAULT_MAX_SIZE_UPDATE_SELECTION 475 ), 476 tr("Selection too big"), 477 JOptionPane.WARNING_MESSAGE 478 ); 479 return; 480 } 481 for(OsmPrimitive primitive : selection) { 482 // FIXME: users should be able to abort this loop 483 // 484 updatePrimitive(primitive.id); 485 } 125 updatePrimitives(selection); 486 126 } 487 127 }
Note: See TracChangeset
for help on using the changeset viewer.
