Changeset 18395 in josm
- Timestamp:
- 2022-03-13T08:07:10+01:00 (3 years ago)
- Location:
- trunk/src/org/openstreetmap/josm
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/actions/DeleteAction.java
r16840 r18395 10 10 import java.awt.event.KeyEvent; 11 11 import java.util.Collection; 12 import java.util.Collections; 12 13 13 14 import javax.swing.JOptionPane; … … 24 25 import org.openstreetmap.josm.gui.dialogs.DeleteFromRelationConfirmationDialog; 25 26 import org.openstreetmap.josm.gui.widgets.JMultilineLabel; 27 import org.openstreetmap.josm.tools.Pair; 26 28 import org.openstreetmap.josm.tools.Shortcut; 27 29 … … 50 52 @Override 51 53 public boolean confirmDeletionFromRelation(Collection<RelationToChildReference> references) { 54 return this.confirmDeletionFromRelation(references, Collections.emptyList()); 55 } 56 57 @Override 58 public boolean confirmDeletionFromRelation(Collection<RelationToChildReference> references, 59 Collection<Pair<Relation, Boolean>> parentsToDelete) { 52 60 DeleteFromRelationConfirmationDialog dialog = DeleteFromRelationConfirmationDialog.getInstance(); 53 61 dialog.getModel().populate(references); 62 dialog.getDeletedRelationsModel().populate(parentsToDelete); 54 63 dialog.setVisible(true); 55 64 return !dialog.isCanceled(); -
trunk/src/org/openstreetmap/josm/command/DeleteCommand.java
r18208 r18395 36 36 import org.openstreetmap.josm.tools.CheckParameterUtil; 37 37 import org.openstreetmap.josm.tools.ImageProvider; 38 import org.openstreetmap.josm.tools.Pair; 38 39 import org.openstreetmap.josm.tools.Utils; 39 40 … … 102 103 */ 103 104 boolean confirmDeletionFromRelation(Collection<RelationToChildReference> references); 105 106 /** 107 * Confirm before removing a collection of primitives from their parent relations, with the probability of 108 * deleting the parents as well. 109 * @param references the list of relation-to-child references 110 * @param parentsToDelete the list of parents to delete (the boolean part will be {@code true} if the user wants 111 * to delete the relation). 112 * @return {@code true} if the user confirms the deletion 113 * @since 18395 114 */ 115 default boolean confirmDeletionFromRelation(Collection<RelationToChildReference> references, 116 Collection<Pair<Relation, Boolean>> parentsToDelete) { 117 // This is a default method. Ensure that all the booleans are false. 118 parentsToDelete.forEach(pair -> pair.b = false); 119 return confirmDeletionFromRelation(references); 120 } 104 121 } 105 122 … … 438 455 } 439 456 457 // remove the objects from their parent relations 458 // 459 final Set<Relation> relationsToBeChanged = primitivesToDelete.stream() 460 .flatMap(p -> p.referrers(Relation.class)) 461 .collect(Collectors.toSet()); 462 final Set<Relation> additionalRelationsToDelete = new HashSet<>(); 463 for (Relation cur : relationsToBeChanged) { 464 List<RelationMember> newMembers = cur.getMembers(); 465 cur.getMembersFor(primitivesToDelete).forEach(newMembers::remove); 466 cmds.add(new ChangeMembersCommand(cur, newMembers)); 467 // If we don't have any members, we probably ought to delete the relation as well. 468 if (newMembers.isEmpty()) { 469 additionalRelationsToDelete.add(cur); 470 } 471 } 472 473 440 474 // get a confirmation that the objects to delete can be removed from their parent relations 441 475 // … … 443 477 Set<RelationToChildReference> references = RelationToChildReference.getRelationToChildReferences(primitivesToDelete); 444 478 references.removeIf(ref -> ref.getParent().isDeleted()); 445 if (!references.isEmpty() && !callback.confirmDeletionFromRelation(references)) { 479 final Collection<Pair<Relation, Boolean>> pairedRelations = additionalRelationsToDelete.stream() 480 /* 481 * Default to true, so that users have to make a choice to not delete. 482 * Default implementation converts it to false, so this should be safe. 483 */ 484 .map(relation -> new Pair<>(relation, true)).collect(Collectors.toSet()); 485 if (!references.isEmpty() && !callback.confirmDeletionFromRelation(references, pairedRelations)) { 446 486 return null; 447 487 } 448 } 449 450 // remove the objects from their parent relations 451 // 452 final Set<Relation> relationsToBeChanged = primitivesToDelete.stream() 453 .flatMap(p -> p.referrers(Relation.class)) 454 .collect(Collectors.toSet()); 455 for (Relation cur : relationsToBeChanged) { 456 List<RelationMember> newMembers = cur.getMembers(); 457 cur.getMembersFor(primitivesToDelete).forEach(newMembers::remove); 458 cmds.add(new ChangeMembersCommand(cur, newMembers)); 488 pairedRelations.stream().filter(pair -> Boolean.TRUE.equals(pair.b)).map(pair -> pair.a) 489 .forEach(primitivesToDelete::add); 459 490 } 460 491 -
trunk/src/org/openstreetmap/josm/gui/dialogs/DeleteFromRelationConfirmationDialog.java
r17440 r18395 9 9 import java.awt.Dimension; 10 10 import java.awt.FlowLayout; 11 import java.awt.GridBagLayout; 11 12 import java.awt.event.ActionEvent; 12 13 import java.awt.event.WindowAdapter; … … 35 36 import org.openstreetmap.josm.data.osm.NameFormatter; 36 37 import org.openstreetmap.josm.data.osm.OsmPrimitive; 38 import org.openstreetmap.josm.data.osm.Relation; 37 39 import org.openstreetmap.josm.data.osm.RelationToChildReference; 38 40 import org.openstreetmap.josm.gui.MainApplication; … … 43 45 import org.openstreetmap.josm.gui.util.WindowGeometry; 44 46 import org.openstreetmap.josm.gui.widgets.HtmlPanel; 47 import org.openstreetmap.josm.tools.GBC; 45 48 import org.openstreetmap.josm.tools.I18n; 46 49 import org.openstreetmap.josm.tools.ImageProvider; 50 import org.openstreetmap.josm.tools.Pair; 51 import org.openstreetmap.josm.tools.Utils; 47 52 48 53 /** … … 69 74 /** the data model */ 70 75 private RelationMemberTableModel model; 76 /** The data model for deleting relations */ 77 private RelationDeleteModel deletedRelationsModel; 78 /** The table to hide/show if the relations to delete are not empty*/ 71 79 private final HtmlPanel htmlPanel = new HtmlPanel(); 72 80 private boolean canceled; … … 75 83 protected JPanel buildRelationMemberTablePanel() { 76 84 JTable table = new JTable(model, new RelationMemberTableColumnModel()); 77 JPanel pnl = new JPanel(new BorderLayout()); 78 pnl.add(new JScrollPane(table)); 85 JPanel pnl = new JPanel(new GridBagLayout()); 86 pnl.add(new JScrollPane(table), GBC.eol().fill()); 87 JTable deletedRelationsTable = new JTable(this.deletedRelationsModel, new RelationDeleteTableColumnModel()); 88 JScrollPane deletedRelationsModelTableScrollPane = new JScrollPane(deletedRelationsTable); 89 this.deletedRelationsModel.addTableModelListener( 90 e -> deletedRelationsModelTableScrollPane.setVisible(this.deletedRelationsModel.getRowCount() > 0)); 91 // Default to not visible 92 deletedRelationsModelTableScrollPane.setVisible(false); 93 pnl.add(deletedRelationsModelTableScrollPane, GBC.eol().fill()); 79 94 return pnl; 80 95 } … … 92 107 model = new RelationMemberTableModel(); 93 108 model.addTableModelListener(this); 109 this.deletedRelationsModel = new RelationDeleteModel(); 110 this.deletedRelationsModel.addTableModelListener(this); 94 111 getContentPane().setLayout(new BorderLayout()); 95 112 getContentPane().add(htmlPanel, BorderLayout.NORTH); … … 103 120 104 121 protected void updateMessage() { 105 int numObjectsToDelete = model.getNumObjectsToDelete();106 int numParentRelations = model.getNumParentRelations();122 int numObjectsToDelete = this.model.getNumObjectsToDelete() + this.deletedRelationsModel.getNumObjectsToDelete(); 123 int numParentRelations = this.model.getNumParentRelations() + this.deletedRelationsModel.getNumParentRelations(); 107 124 final String msg1 = trn( 108 125 "Please confirm to remove <strong>{0} object</strong>.", … … 120 137 121 138 protected void updateTitle() { 122 int numObjectsToDelete = model.getNumObjectsToDelete();139 int numObjectsToDelete = this.model.getNumObjectsToDelete() + this.deletedRelationsModel.getNumObjectsToDelete(); 123 140 if (numObjectsToDelete > 0) { 124 141 setTitle(trn("Deleting {0} object", "Deleting {0} objects", numObjectsToDelete, numObjectsToDelete)); … … 143 160 public RelationMemberTableModel getModel() { 144 161 return model; 162 } 163 164 /** 165 * Replies the data model used for relations that should probably be deleted. 166 * @return the data model 167 * @since 18395 168 */ 169 public RelationDeleteModel getDeletedRelationsModel() { 170 return this.deletedRelationsModel; 145 171 } 146 172 … … 174 200 } 175 201 model.data.clear(); 202 this.deletedRelationsModel.data.clear(); 176 203 } 177 204 super.setVisible(visible); … … 326 353 } 327 354 355 /** 356 * The table model which manages relations that will be deleted, if their children are deleted. 357 * @since 18395 358 */ 359 public static class RelationDeleteModel extends DefaultTableModel { 360 private final transient List<Pair<Relation, Boolean>> data = new ArrayList<>(); 361 362 @Override 363 public int getRowCount() { 364 // This is called in the super constructor. Before we have instantiated the list. Removing the null check 365 // WILL LEAD TO A SILENT NPE! 366 if (this.data == null) { 367 return 0; 368 } 369 return this.data.size(); 370 } 371 372 /** 373 * Sets the data that should be displayed in the list. 374 * @param references A list of references to display 375 */ 376 public void populate(Collection<Pair<Relation, Boolean>> references) { 377 this.data.clear(); 378 if (references != null) { 379 this.data.addAll(references); 380 } 381 this.data.sort(Comparator.comparing(pair -> pair.a)); 382 fireTableDataChanged(); 383 } 384 385 /** 386 * Gets the list of children that are currently displayed. 387 * @return The children. 388 */ 389 public Set<Relation> getObjectsToDelete() { 390 return this.data.stream().filter(relation -> relation.b).map(relation -> relation.a).collect(Collectors.toSet()); 391 } 392 393 /** 394 * Gets the number of elements {@link #getObjectsToDelete()} would return. 395 * @return That number. 396 */ 397 public int getNumObjectsToDelete() { 398 return getObjectsToDelete().size(); 399 } 400 401 /** 402 * Gets the set of parent relations 403 * @return All parent relations of the references 404 */ 405 public Set<OsmPrimitive> getParentRelations() { 406 return this.data.stream() 407 .flatMap(pair -> Utils.filteredCollection(pair.a.getReferrers(), Relation.class).stream()) 408 .collect(Collectors.toSet()); 409 } 410 411 /** 412 * Gets the number of elements {@link #getParentRelations()} would return. 413 * @return That number. 414 */ 415 public int getNumParentRelations() { 416 return getParentRelations().size(); 417 } 418 419 @Override 420 public Object getValueAt(int rowIndex, int columnIndex) { 421 if (this.data.isEmpty()) { 422 return null; 423 } 424 Pair<Relation, Boolean> ref = this.data.get(rowIndex); 425 switch(columnIndex) { 426 case 0: return ref.a; 427 case 1: return ref.b; 428 default: 429 assert false : "Illegal column index"; 430 } 431 return null; 432 } 433 434 @Override 435 public boolean isCellEditable(int row, int column) { 436 return !this.data.isEmpty() && column == 1; 437 } 438 439 @Override 440 public void setValueAt(Object aValue, int row, int column) { 441 if (this.data.size() > row && column == 1 && aValue instanceof Boolean) { 442 this.data.get(row).b = ((Boolean) aValue); 443 } 444 } 445 446 @Override 447 public Class<?> getColumnClass(int columnIndex) { 448 switch (columnIndex) { 449 case 0: 450 return Relation.class; 451 case 1: 452 return Boolean.class; 453 default: 454 return super.getColumnClass(columnIndex); 455 } 456 } 457 } 458 459 private static class RelationDeleteTableColumnModel extends DefaultTableColumnModel { 460 protected final void createColumns() { 461 // column 0 - To Delete 462 TableColumn col = new TableColumn(0); 463 col.setHeaderValue(tr("Relation")); 464 col.setResizable(true); 465 col.setWidth(100); 466 col.setPreferredWidth(100); 467 col.setCellRenderer(new PrimitiveRenderer()); 468 addColumn(col); 469 470 // column 0 - From Relation 471 col = new TableColumn(1); 472 final String toDelete = tr("To delete"); 473 col.setHeaderValue(toDelete); 474 col.setResizable(true); 475 col.setPreferredWidth(toDelete.length()); 476 addColumn(col); 477 } 478 479 RelationDeleteTableColumnModel() { 480 createColumns(); 481 } 482 } 483 328 484 class OKAction extends AbstractAction { 329 485 OKAction() {
Note:
See TracChangeset
for help on using the changeset viewer.