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

Last change on this file was 17358, checked in by GerdP, 3 years ago

see #19885: memory leak with "temporary" objects in validator and actions

  • (hopefully) fix memory leaks in complex actions
  • handle complex cases with presets and RelationEditor

I hope these changes don't break plugins which extend or overwrite RelationEditor

  • Property svn:eol-style set to native
File size: 5.8 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;
6
7import java.awt.event.ActionEvent;
8import java.awt.event.KeyEvent;
9import java.util.ArrayList;
10import java.util.Collection;
11import java.util.Collections;
12import java.util.LinkedHashSet;
13import java.util.LinkedList;
14import java.util.List;
15
16import javax.swing.JOptionPane;
17
18import org.openstreetmap.josm.actions.corrector.ReverseWayNoTagCorrector;
19import org.openstreetmap.josm.actions.corrector.ReverseWayTagCorrector;
20import org.openstreetmap.josm.command.ChangeNodesCommand;
21import org.openstreetmap.josm.command.Command;
22import org.openstreetmap.josm.command.SequenceCommand;
23import org.openstreetmap.josm.data.UndoRedoHandler;
24import org.openstreetmap.josm.data.osm.DataSet;
25import org.openstreetmap.josm.data.osm.Node;
26import org.openstreetmap.josm.data.osm.OsmPrimitive;
27import org.openstreetmap.josm.data.osm.Way;
28import org.openstreetmap.josm.gui.Notification;
29import org.openstreetmap.josm.spi.preferences.Config;
30import org.openstreetmap.josm.tools.Logging;
31import org.openstreetmap.josm.tools.Shortcut;
32import org.openstreetmap.josm.tools.UserCancelException;
33
34/**
35 * Reverses the ways that are currently selected by the user
36 */
37public final class ReverseWayAction extends JosmAction {
38
39 /**
40 * The resulting way after reversing it and the commands to get there.
41 */
42 public static class ReverseWayResult {
43 private final Collection<Command> tagCorrectionCommands;
44 private final Command reverseCommand;
45
46 /**
47 * Create a new {@link ReverseWayResult}
48 * @param tagCorrectionCommands The commands to correct the tags
49 * @param reverseCommand The command to reverse the way
50 */
51 public ReverseWayResult(Collection<Command> tagCorrectionCommands, Command reverseCommand) {
52 this.tagCorrectionCommands = tagCorrectionCommands;
53 this.reverseCommand = reverseCommand;
54 }
55
56 /**
57 * Gets the commands that will be required to do a full way reversal including changing the tags
58 * @return The commands
59 */
60 public Collection<Command> getCommands() {
61 List<Command> c = new ArrayList<>();
62 c.addAll(tagCorrectionCommands);
63 c.add(reverseCommand);
64 return c;
65 }
66
67 /**
68 * Gets a single sequence command for reversing this way including changing the tags
69 * @return the command
70 */
71 public Command getAsSequenceCommand() {
72 return new SequenceCommand(tr("Reverse way"), getCommands());
73 }
74
75 /**
76 * Gets the basic reverse command that only changes the order of the nodes.
77 * @return The reorder nodes command
78 */
79 public Command getReverseCommand() {
80 return reverseCommand;
81 }
82
83 /**
84 * Gets the command to change the tags of the way
85 * @return The command to reverse the tags
86 */
87 public Collection<Command> getTagCorrectionCommands() {
88 return tagCorrectionCommands;
89 }
90 }
91
92 /**
93 * Creates a new {@link ReverseWayAction} and binds the shortcut
94 */
95 public ReverseWayAction() {
96 super(tr("Reverse Ways"), "wayflip", tr("Reverse the direction of all selected ways."),
97 Shortcut.registerShortcut("tools:reverse", tr("Tools: {0}", tr("Reverse Ways")), KeyEvent.VK_R, Shortcut.DIRECT), true);
98 setHelpId(ht("/Action/ReverseWays"));
99 }
100
101 @Override
102 public void actionPerformed(ActionEvent e) {
103 DataSet ds = getLayerManager().getEditDataSet();
104 if (!isEnabled() || ds == null)
105 return;
106
107 final Collection<Way> sel = new LinkedHashSet<>(ds.getSelectedWays());
108 sel.removeIf(w -> w.isIncomplete() || w.isEmpty());
109 if (sel.isEmpty()) {
110 new Notification(
111 tr("Please select at least one way."))
112 .setIcon(JOptionPane.INFORMATION_MESSAGE)
113 .setDuration(Notification.TIME_SHORT)
114 .show();
115 return;
116 }
117
118 Collection<Command> c = new LinkedList<>();
119 for (Way w : sel) {
120 try {
121 c.addAll(reverseWay(w).getCommands());
122 } catch (IllegalArgumentException ex) {
123 Logging.error(ex);
124 } catch (UserCancelException ex) {
125 Logging.trace(ex);
126 return;
127 }
128 }
129 UndoRedoHandler.getInstance().add(new SequenceCommand(tr("Reverse Ways"), c));
130 }
131
132 /**
133 * Reverses a given way.
134 * @param w the way
135 * @return the reverse command and the tag correction commands
136 * @throws IllegalArgumentException if sanity checks fail
137 * @throws UserCancelException if user cancels a reverse warning dialog
138 */
139 public static ReverseWayResult reverseWay(Way w) throws UserCancelException {
140 ReverseWayNoTagCorrector.checkAndConfirmReverseWay(w);
141 List<Node> nodesCopy = w.getNodes();
142 Collections.reverse(nodesCopy);
143
144 Collection<Command> corrCmds = Collections.<Command>emptyList();
145 if (Config.getPref().getBoolean("tag-correction.reverse-way", true)) {
146 corrCmds = new ReverseWayTagCorrector().execute(w, w);
147 }
148 return new ReverseWayResult(corrCmds, new ChangeNodesCommand(w, new ArrayList<>(nodesCopy)));
149 }
150
151 @Override
152 protected void updateEnabledState() {
153 updateEnabledStateOnCurrentSelection();
154 }
155
156 @Override
157 protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
158 setEnabled(selection.stream().anyMatch(
159 o -> o instanceof Way && !o.isIncomplete() && !o.getDataSet().isLocked()));
160 }
161}
Note: See TracBrowser for help on using the repository browser.