source: josm/trunk/src/org/openstreetmap/josm/actions/DeleteAction.java

Last change on this file was 19078, checked in by taylor.smock, 5 months ago

Fix #4142: Track fully downloaded objects (patch by stoecker, GerdP, and myself)

The serialization move from PrimitiveData to AbstractPrimitive should be
reverted prior to 24.05 (see #23677).

The serialization move was required since we want to ensure that all downstream
users of AbstractPrimitive were not using the flags field, which was done by
making the field private instead of protected. They may still be using that
field (via updateFlags) which would not be caught by compile-time or runtime
errors.

Additionally, a good chunk of common functionality was moved up from
OsmPrimitive, even though much of it wasn't useful for PrimitiveData.

  • Property svn:eol-style set to native
File size: 7.4 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.actions;
3
4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
5import static org.openstreetmap.josm.tools.I18n.tr;
6import static org.openstreetmap.josm.tools.I18n.trn;
7
8import java.awt.GridBagLayout;
9import java.awt.event.ActionEvent;
10import java.awt.event.KeyEvent;
11import java.util.Collection;
12import java.util.Collections;
13
14import javax.swing.JOptionPane;
15import javax.swing.JPanel;
16
17import org.openstreetmap.josm.command.DeleteCommand.DeletionCallback;
18import org.openstreetmap.josm.data.osm.DefaultNameFormatter;
19import org.openstreetmap.josm.data.osm.INode;
20import org.openstreetmap.josm.data.osm.IRelation;
21import org.openstreetmap.josm.data.osm.IWay;
22import org.openstreetmap.josm.data.osm.OsmPrimitive;
23import org.openstreetmap.josm.data.osm.Relation;
24import org.openstreetmap.josm.data.osm.RelationToChildReference;
25import org.openstreetmap.josm.gui.ConditionalOptionPaneUtil;
26import org.openstreetmap.josm.gui.MainApplication;
27import org.openstreetmap.josm.gui.MapFrame;
28import org.openstreetmap.josm.gui.dialogs.DeleteFromRelationConfirmationDialog;
29import org.openstreetmap.josm.gui.util.GuiHelper;
30import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
31import org.openstreetmap.josm.tools.Pair;
32import org.openstreetmap.josm.tools.Shortcut;
33
34/**
35 * Action that deletes selected objects.
36 * @since 770
37 */
38public final class DeleteAction extends JosmAction {
39
40 /**
41 * The default {@link DeletionCallback} for {@code DeleteCommand}.
42 * @since 12760
43 */
44 public static final DeletionCallback defaultDeletionCallback = new DeletionCallback() {
45 @Override
46 public boolean checkAndConfirmOutlyingDelete(Collection<? extends OsmPrimitive> primitives,
47 Collection<? extends OsmPrimitive> ignore) {
48 return DeleteAction.checkAndConfirmOutlyingDelete(primitives, ignore);
49 }
50
51 @Override
52 public boolean confirmRelationDeletion(Collection<Relation> relations) {
53 return DeleteAction.confirmRelationDeletion(relations);
54 }
55
56 @Override
57 public boolean confirmDeletionFromRelation(Collection<RelationToChildReference> references) {
58 return this.confirmDeletionFromRelation(references, Collections.emptyList());
59 }
60
61 @Override
62 public boolean confirmDeletionFromRelation(Collection<RelationToChildReference> references,
63 Collection<Pair<Relation, Boolean>> parentsToDelete) {
64 DeleteFromRelationConfirmationDialog dialog = DeleteFromRelationConfirmationDialog.getInstance();
65 dialog.getModel().populate(references);
66 dialog.getDeletedRelationsModel().populate(parentsToDelete);
67 dialog.setVisible(true);
68 return !dialog.isCanceled();
69 }
70 };
71
72 /**
73 * Constructs a new {@code DeleteAction}.
74 */
75 public DeleteAction() {
76 super(tr("Delete"), "dialogs/delete", tr("Delete selected objects."),
77 Shortcut.registerShortcut("system:delete", tr("Edit: {0}", tr("Delete")), KeyEvent.VK_DELETE, Shortcut.DIRECT), true);
78 setHelpId(ht("/Action/Delete"));
79 }
80
81 @Override
82 public void actionPerformed(ActionEvent e) {
83 MapFrame map = MainApplication.getMap();
84 if (!isEnabled() || !map.mapView.isActiveLayerVisible())
85 return;
86 map.mapModeDelete.doActionPerformed(e);
87 }
88
89 @Override
90 protected void updateEnabledState() {
91 updateEnabledStateOnCurrentSelection();
92 }
93
94 @Override
95 protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
96 updateEnabledStateOnModifiableSelection(selection);
97 }
98
99 /**
100 * Check whether user is about to delete data outside of the download area.
101 * Request confirmation if he is.
102 * @param primitives the primitives to operate on
103 * @param ignore {@code null} or a primitive to be ignored
104 * @return true, if operating on outlying primitives is OK; false, otherwise
105 * @since 12749 (moved from DeleteCommand)
106 */
107 public static boolean checkAndConfirmOutlyingDelete(Collection<? extends OsmPrimitive> primitives,
108 Collection<? extends OsmPrimitive> ignore) {
109 final boolean nodes = primitives.stream().anyMatch(INode.class::isInstance);
110 final boolean ways = primitives.stream().anyMatch(IWay.class::isInstance);
111 final boolean relations = primitives.stream().anyMatch(IRelation.class::isInstance);
112 final String type;
113 if (nodes && !ways && !relations) {
114 type = tr("You are about to delete nodes which can have other referrers not yet downloaded.");
115 } else if (!nodes && ways && !relations) {
116 type = tr("You are about to delete ways which can have other referrers not yet downloaded.");
117 } else if (!nodes && !ways && relations) {
118 type = tr("You are about to delete relations which can have other referrers not yet downloaded.");
119 } else {
120 // OK. We have multiple types being deleted.
121 type = tr("You are about to delete primitives which can have other referrers not yet downloaded.");
122 }
123 return Boolean.TRUE.equals(GuiHelper.runInEDTAndWaitAndReturn(() -> checkAndConfirmOutlyingOperation("delete",
124 tr("Delete confirmation"),
125 tr("{0}"
126 + "<br>"
127 + "This can cause problems because other objects (that you do not see) might use them."
128 + "<br>"
129 + "Do you really want to delete?", type),
130 tr("You are about to delete incomplete objects."
131 + "<br>"
132 + "This will cause problems because you don''t see the real object."
133 + "<br>" + "Do you really want to delete?"),
134 primitives, ignore)));
135 }
136
137 /**
138 * Confirm before deleting a relation, as it is a common newbie error.
139 * @param relations relation to check for deletion
140 * @return {@code true} if user confirms the deletion
141 * @since 12760
142 */
143 public static boolean confirmRelationDeletion(Collection<Relation> relations) {
144 if (relations.stream().allMatch(Relation::isNew)) {
145 return true;
146 }
147 JPanel msg = new JPanel(new GridBagLayout());
148 msg.add(new JMultilineLabel("<html>" + trn(
149 "You are about to delete {0} relation: {1}"
150 + "<br/>"
151 + "This step is rarely necessary and cannot be undone easily after being uploaded to the server."
152 + "<br/>"
153 + "Do you really want to delete?",
154 "You are about to delete {0} relations: {1}"
155 + "<br/>"
156 + "This step is rarely necessary and cannot be undone easily after being uploaded to the server."
157 + "<br/>"
158 + "Do you really want to delete?",
159 relations.size(), relations.size(), DefaultNameFormatter.getInstance().formatAsHtmlUnorderedList(relations, 20))
160 + "</html>"));
161 return ConditionalOptionPaneUtil.showConfirmationDialog(
162 "delete_relations",
163 MainApplication.getMainFrame(),
164 msg,
165 tr("Delete relation?"),
166 JOptionPane.YES_NO_OPTION,
167 JOptionPane.QUESTION_MESSAGE,
168 JOptionPane.YES_OPTION);
169 }
170}
Note: See TracBrowser for help on using the repository browser.