source: josm/trunk/src/org/openstreetmap/josm/actions/PurgeAction.java@ 3479

Last change on this file since 3479 was 3479, checked in by jttt, 14 years ago

cosmetics

  • Property svn:eol-style set to native
File size: 10.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.actions;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Component;
7import java.awt.Dimension;
8import java.awt.GridBagLayout;
9import java.awt.Insets;
10import java.awt.event.ActionEvent;
11import java.awt.event.KeyEvent;
12import java.util.ArrayList;
13import java.util.Collection;
14import java.util.Collections;
15import java.util.Comparator;
16import java.util.HashSet;
17import java.util.List;
18import java.util.Set;
19
20import javax.swing.AbstractAction;
21import javax.swing.BorderFactory;
22import javax.swing.Box;
23import javax.swing.JButton;
24import javax.swing.JCheckBox;
25import javax.swing.JLabel;
26import javax.swing.JList;
27import javax.swing.JPanel;
28import javax.swing.JScrollPane;
29import javax.swing.JSeparator;
30
31import org.openstreetmap.josm.Main;
32import org.openstreetmap.josm.command.PurgeCommand;
33import org.openstreetmap.josm.data.osm.Node;
34import org.openstreetmap.josm.data.osm.OsmPrimitive;
35import org.openstreetmap.josm.data.osm.Relation;
36import org.openstreetmap.josm.data.osm.Way;
37import org.openstreetmap.josm.gui.ExtendedDialog;
38import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
39import org.openstreetmap.josm.gui.help.HelpUtil;
40import org.openstreetmap.josm.gui.layer.OsmDataLayer;
41import org.openstreetmap.josm.tools.GBC;
42import org.openstreetmap.josm.tools.ImageProvider;
43import org.openstreetmap.josm.tools.Shortcut;
44
45/**
46 * The action to purge the selected primitives, i.e. remove them from the
47 * data layer, or remove their content and make them incomplete.
48 *
49 * This means, the deleted flag is not affected and JOSM simply forgets
50 * about these primitives.
51 *
52 * This action is undo-able. In order not to break previous commands in the
53 * undo buffer, we must re-add the identical object (and not semantically
54 * equal ones).
55 */
56public class PurgeAction extends JosmAction {
57
58 public PurgeAction() {
59 /* translator note: other expressions for "purge" might be "forget", "clean", "obliterate", "prune" */
60 super(tr("Purge..."), "purge", tr("Forget objects but do not delete them on server when uploading."),
61 Shortcut.registerShortcut("system:purge", tr("Edit: {0}", tr("Purge")), KeyEvent.VK_P, Shortcut.GROUP_MENU, Shortcut.SHIFT_DEFAULT)
62 , true);
63 putValue("help", HelpUtil.ht("/Action/Purge"));
64 }
65
66 protected OsmDataLayer layer;
67 JCheckBox cbClearUndoRedo;
68
69 protected Set<OsmPrimitive> toPurge;
70 /**
71 * finally, contains all objects that are purged
72 */
73 protected Set<OsmPrimitive> toPurgeChecked;
74 /**
75 * Subset of toPurgeChecked. Marks primitives that remain in the
76 * dataset, but incomplete.
77 */
78 protected Set<OsmPrimitive> makeIncomplete;
79 /**
80 * Subset of toPurgeChecked. Those that have not been in the selection.
81 */
82 protected List<OsmPrimitive> toPurgeAdditionally;
83
84 @Override
85 public void actionPerformed(ActionEvent e) {
86 if (!isEnabled())
87 return;
88
89 Collection<OsmPrimitive> sel = getCurrentDataSet().getSelected();
90 layer = Main.map.mapView.getEditLayer();
91
92 toPurge = new HashSet<OsmPrimitive>(sel);
93 toPurgeAdditionally = new ArrayList<OsmPrimitive>();
94 toPurgeChecked = new HashSet<OsmPrimitive>();
95
96 // Add referrer, unless the object to purge is not new
97 // and the parent is a relation
98 while (!toPurge.isEmpty()) {
99 OsmPrimitive osm = toPurge.iterator().next();
100 for (OsmPrimitive parent: osm.getReferrers()) {
101 if (toPurge.contains(parent) || toPurgeChecked.contains(parent)) {
102 continue;
103 }
104 if (parent instanceof Way || (parent instanceof Relation && osm.isNew())) {
105 toPurgeAdditionally.add(parent);
106 toPurge.add(parent);
107 }
108 }
109 toPurge.remove(osm);
110 toPurgeChecked.add(osm);
111 }
112
113 makeIncomplete = new HashSet<OsmPrimitive>();
114
115 // Find the objects that will be incomplete after purging.
116 // At this point, all parents of new to-be-purged primitives are
117 // also to-be-purged and
118 // all parents of not-new to-be-purged primitives are either
119 // to-be-purged or of type relation.
120 TOP:
121 for (OsmPrimitive child : toPurgeChecked) {
122 if (child.isNew()) {
123 continue;
124 }
125 for (OsmPrimitive parent : child.getReferrers()) {
126 if (parent instanceof Relation && !toPurgeChecked.contains(parent)) {
127 makeIncomplete.add(child);
128 continue TOP;
129 }
130 }
131 }
132
133 // Add untagged way nodes. Do not add nodes that have other
134 // referrers not yet to-be-purged.
135 if (Main.pref.getBoolean("purge.add_untagged_waynodes", true)) {
136 Set<OsmPrimitive> wayNodes = new HashSet<OsmPrimitive>();
137 for (OsmPrimitive osm : toPurgeChecked) {
138 if (osm instanceof Way) {
139 Way w = (Way) osm;
140 NODE:
141 for (Node n : w.getNodes()) {
142 if (n.isTagged() || toPurgeChecked.contains(n)) {
143 continue;
144 }
145 for (OsmPrimitive ref : n.getReferrers()) {
146 if (ref != w && !toPurgeChecked.contains(ref)) {
147 continue NODE;
148 }
149 }
150 wayNodes.add(n);
151 }
152 }
153 }
154 toPurgeChecked.addAll(wayNodes);
155 toPurgeAdditionally.addAll(wayNodes);
156 }
157
158 boolean modified = false;
159 for (OsmPrimitive osm : toPurgeChecked) {
160 if (osm.isModified()) {
161 modified = true;
162 break;
163 }
164 }
165
166 ExtendedDialog confirmDlg = new ExtendedDialog(Main.parent, tr("Confirm Purging"), new String[] {tr("Purge"), tr("Cancel")});
167 confirmDlg.setContent(buildPanel(modified), false);
168 confirmDlg.setButtonIcons(new String[] {"ok", "cancel"});
169
170 int answer = confirmDlg.showDialog().getValue();
171 if (answer != 1)
172 return;
173
174 Main.pref.put("purge.clear_undo_redo", cbClearUndoRedo.isSelected());
175
176 Main.main.undoRedo.add(new PurgeCommand(Main.map.mapView.getEditLayer(), toPurgeChecked, makeIncomplete));
177
178 if (cbClearUndoRedo.isSelected()) {
179 Main.main.undoRedo.clean();
180 Main.map.selectionListDialog.clearSelectionHistory();
181 }
182 }
183
184 private JPanel buildPanel(boolean modified) {
185 JPanel pnl = new JPanel(new GridBagLayout());
186
187 pnl.add(Box.createRigidArea(new Dimension(400,0)), GBC.eol().fill(GBC.HORIZONTAL));
188
189 pnl.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
190 pnl.add(new JLabel("<html>"+
191 tr("This operation makes JOSM forget the selected objects.<br> " +
192 "They will be removed from the layer, but <i>not</i> deleted<br> " +
193 "on the server when uploading.")+"</html>",
194 ImageProvider.get("purge"), JLabel.LEFT), GBC.eol().fill(GBC.HORIZONTAL));
195
196 if (!toPurgeAdditionally.isEmpty()) {
197 pnl.add(new JSeparator(), GBC.eol().fill(GBC.HORIZONTAL).insets(0,5,0,5));
198 pnl.add(new JLabel("<html>"+
199 tr("The following dependent objects will be purged<br> " +
200 "in addition to the selected objects:")+"</html>",
201 ImageProvider.get("warning-small"), JLabel.LEFT), GBC.eol().fill(GBC.HORIZONTAL));
202
203 Collections.sort(toPurgeAdditionally, new Comparator<OsmPrimitive>() {
204 public int compare(OsmPrimitive o1, OsmPrimitive o2) {
205 int type = o1.getType().compareTo(o2.getType());
206 if (type != 0)
207 return -type;
208 return (Long.valueOf(o1.getUniqueId())).compareTo(o2.getUniqueId());
209 }
210 });
211 JList list = new JList(toPurgeAdditionally.toArray(new OsmPrimitive[0]));
212 /* force selection to be active for all entries */
213 list.setCellRenderer(new OsmPrimitivRenderer() {
214 @Override
215 public Component getListCellRendererComponent(JList list,
216 Object value,
217 int index,
218 boolean isSelected,
219 boolean cellHasFocus) {
220 return super.getListCellRendererComponent(list, value, index, true, false);
221 }
222 });
223 JScrollPane scroll = new JScrollPane(list);
224 scroll.setPreferredSize(new Dimension(250, 300));
225 scroll.setMinimumSize(new Dimension(250, 300));
226 pnl.add(scroll, GBC.std().fill(GBC.VERTICAL).weight(0.0, 1.0));
227
228 JButton addToSelection = new JButton(new AbstractAction() {
229 {
230 putValue(SHORT_DESCRIPTION, tr("Add to selection"));
231 putValue(SMALL_ICON, ImageProvider.get("dialogs","select"));
232 }
233
234 public void actionPerformed(ActionEvent e) {
235 layer.data.addSelected(toPurgeAdditionally);
236 }
237 });
238 addToSelection.setMargin(new Insets(0,0,0,0));
239 pnl.add(addToSelection, GBC.eol().anchor(GBC.SOUTHWEST).weight(1.0, 1.0).insets(2,0,0,3));
240 }
241
242 if (modified) {
243 pnl.add(new JSeparator(), GBC.eol().fill(GBC.HORIZONTAL).insets(0,5,0,5));
244 pnl.add(new JLabel("<html>"+tr("Some of the objects are modified.<br> " +
245 "Proceed, if these changes should be discarded."+"</html>"),
246 ImageProvider.get("warning-small"), JLabel.LEFT),
247 GBC.eol().fill(GBC.HORIZONTAL));
248 }
249
250 cbClearUndoRedo = new JCheckBox(tr("Clear Undo/Redo buffer"));
251 cbClearUndoRedo.setSelected(Main.pref.getBoolean("purge.clear_undo_redo", false));
252
253 pnl.add(new JSeparator(), GBC.eol().fill(GBC.HORIZONTAL).insets(0,5,0,5));
254 pnl.add(cbClearUndoRedo, GBC.eol());
255 return pnl;
256 }
257
258 @Override
259 protected void updateEnabledState() {
260 if (getCurrentDataSet() == null) {
261 setEnabled(false);
262 } else {
263 setEnabled(!(getCurrentDataSet().selectionEmpty()));
264 }
265 }
266
267 @Override
268 protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
269 setEnabled(selection != null && !selection.isEmpty());
270 }
271}
Note: See TracBrowser for help on using the repository browser.