source: josm/src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java@ 104

Last change on this file since 104 was 104, checked in by imi, 18 years ago
  • started i18n
  • started "download incomplete ways" action
  • added straight line selection mode
File size: 6.6 KB
Line 
1package org.openstreetmap.josm.actions.mapmode;
2
3import static org.openstreetmap.josm.tools.I18n.tr;
4
5import java.awt.event.ActionEvent;
6import java.awt.event.KeyEvent;
7import java.awt.event.MouseEvent;
8import java.util.ArrayList;
9import java.util.Arrays;
10import java.util.Collection;
11import java.util.Collections;
12import java.util.HashSet;
13import java.util.Map.Entry;
14
15import javax.swing.JOptionPane;
16
17import org.openstreetmap.josm.Main;
18import org.openstreetmap.josm.command.ChangeCommand;
19import org.openstreetmap.josm.command.Command;
20import org.openstreetmap.josm.command.DeleteCommand;
21import org.openstreetmap.josm.command.SequenceCommand;
22import org.openstreetmap.josm.data.osm.Node;
23import org.openstreetmap.josm.data.osm.OsmPrimitive;
24import org.openstreetmap.josm.data.osm.Segment;
25import org.openstreetmap.josm.data.osm.Way;
26import org.openstreetmap.josm.data.osm.visitor.CollectBackReferencesVisitor;
27import org.openstreetmap.josm.gui.MapFrame;
28import org.openstreetmap.josm.tools.ImageProvider;
29
30/**
31 * An action that enables the user to delete nodes and other objects.
32 *
33 * The user can click on an object, which get deleted if possible. When Ctrl is
34 * pressed when releasing the button, the objects and all its references are
35 * deleted. The exact definition of "all its references" are in
36 * @see #deleteWithReferences(OsmPrimitive)
37 *
38 * Pressing Alt will select the way instead of a segment, as usual.
39 *
40 * If the user did not press Ctrl and the object has any references, the user
41 * is informed and nothing is deleted.
42 *
43 * If the user enters the mapmode and any object is selected, all selected
44 * objects that can be deleted will.
45 *
46 * @author imi
47 */
48public class DeleteAction extends MapMode {
49
50 /**
51 * Construct a new DeleteAction. Mnemonic is the delete - key.
52 * @param mapFrame The frame this action belongs to.
53 */
54 public DeleteAction(MapFrame mapFrame) {
55 super(tr("Delete"),
56 "delete",
57 tr("Delete nodes, streets or segments."),
58 "D",
59 KeyEvent.VK_D,
60 mapFrame,
61 ImageProvider.getCursor("normal", "delete"));
62 }
63
64 @Override public void enterMode() {
65 super.enterMode();
66 Main.map.mapView.addMouseListener(this);
67 }
68
69 @Override public void exitMode() {
70 super.exitMode();
71 Main.map.mapView.removeMouseListener(this);
72 }
73
74
75 @Override public void actionPerformed(ActionEvent e) {
76 super.actionPerformed(e);
77 boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
78 if (ctrl)
79 deleteWithReferences(Main.ds.getSelected());
80 else
81 delete(Main.ds.getSelected(), false);
82 Main.map.repaint();
83 }
84
85 /**
86 * If user clicked with the left button, delete the nearest object.
87 * position.
88 */
89 @Override public void mouseClicked(MouseEvent e) {
90 if (e.getButton() != MouseEvent.BUTTON1)
91 return;
92
93 OsmPrimitive sel = Main.map.mapView.getNearest(e.getPoint(), (e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) != 0);
94 if (sel == null)
95 return;
96
97 if ((e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) != 0)
98 deleteWithReferences(Collections.singleton(sel));
99 else
100 delete(Collections.singleton(sel), true);
101
102 Main.map.mapView.repaint();
103 }
104
105 /**
106 * Delete the primitives and everything they references.
107 *
108 * If a node is deleted, the node and all segments, ways and areas
109 * the node is part of are deleted as well.
110 *
111 * If a segment is deleted, all ways the segment is part of
112 * are deleted as well. No nodes are deleted.
113 *
114 * If a way is deleted, only the way and no segments or nodes are
115 * deleted.
116 *
117 * If an area is deleted, only the area gets deleted.
118 *
119 * @param selection The list of all object to be deleted.
120 */
121 private void deleteWithReferences(Collection<OsmPrimitive> selection) {
122 CollectBackReferencesVisitor v = new CollectBackReferencesVisitor(Main.ds);
123 for (OsmPrimitive osm : selection)
124 osm.visit(v);
125 v.data.addAll(selection);
126 if (!v.data.isEmpty())
127 Main.main.editLayer().add(new DeleteCommand(v.data));
128 }
129
130 /**
131 * Try to delete all given primitives. If a primitive is
132 * used somewhere and that "somewhere" is not going to be deleted,
133 * inform the user and do not delete.
134 *
135 * If deleting a node which is part of exactly two segments, and both segments
136 * have no conflicting keys, join them and remove the node.
137 *
138 * @param selection The objects to delete.
139 * @param msgBox Whether a message box for errors should be shown
140 */
141 private void delete(Collection<OsmPrimitive> selection, boolean msgBox) {
142 Collection<OsmPrimitive> del = new HashSet<OsmPrimitive>();
143 for (OsmPrimitive osm : selection) {
144 CollectBackReferencesVisitor v = new CollectBackReferencesVisitor(Main.ds);
145 osm.visit(v);
146 if (!selection.containsAll(v.data)) {
147 if (osm instanceof Node) {
148 String reason = deleteNodeAndJoinSegment((Node)osm);
149 if (reason != null && msgBox) {
150 JOptionPane.showMessageDialog(Main.parent,tr("Cannot delete node.")+" "+reason);
151 return;
152 }
153 } else if (msgBox) {
154 JOptionPane.showMessageDialog(Main.parent, tr("This object is in use."));
155 return;
156 }
157 } else {
158 del.addAll(v.data);
159 del.add(osm);
160 }
161 }
162 if (!del.isEmpty())
163 Main.main.editLayer().add(new DeleteCommand(del));
164 }
165
166 private String deleteNodeAndJoinSegment(Node n) {
167 ArrayList<Segment> segs = new ArrayList<Segment>(2);
168 for (Segment s : Main.ds.segments) {
169 if (!s.deleted && (s.from == n || s.to == n)) {
170 if (segs.size() > 1)
171 return tr("Used by more than two segments.");
172 segs.add(s);
173 }
174 }
175 if (segs.size() != 2)
176 return tr("Used by only one segment.");
177 Segment seg1 = segs.get(0);
178 Segment seg2 = segs.get(1);
179 if (seg1.from == seg2.to) {
180 Segment s = seg1;
181 seg1 = seg2;
182 seg2 = s;
183 }
184 for (Way w : Main.ds.ways)
185 if (!w.deleted && (w.segments.contains(seg1) || w.segments.contains(seg2)))
186 return tr("Used in a way.");
187 if (seg1.from == seg2.from || seg1.to == seg2.to)
188 return tr("Wrong direction of segments.");
189 for (Entry<String, String> e : seg1.entrySet())
190 if (seg2.keySet().contains(e.getKey()) && !seg2.get(e.getKey()).equals(e.getValue()))
191 return tr("Conflicting keys");
192 Segment s = new Segment(seg1);
193 s.to = seg2.to;
194 if (s.keys == null)
195 s.keys = seg2.keys;
196 else if (seg2.keys != null)
197 s.keys.putAll(seg2.keys);
198 Command[] cmds = new Command[]{
199 new ChangeCommand(seg1, s),
200 new DeleteCommand(Arrays.asList(new OsmPrimitive[]{n, seg2}))};
201 Main.main.editLayer().add(new SequenceCommand(tr("Delete Node"), Arrays.asList(cmds)));
202 return null;
203 }
204}
Note: See TracBrowser for help on using the repository browser.