001 // License: GPL. Copyright 2007 by Immanuel Scholz and others
002 package org.openstreetmap.josm.actions;
003
004 import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
005 import static org.openstreetmap.josm.tools.I18n.tr;
006
007 import java.awt.event.ActionEvent;
008 import java.awt.event.KeyEvent;
009 import java.util.ArrayList;
010 import java.util.Collection;
011 import java.util.Collections;
012 import java.util.LinkedList;
013 import java.util.List;
014
015 import javax.swing.JOptionPane;
016
017 import org.openstreetmap.josm.Main;
018 import org.openstreetmap.josm.command.ChangeCommand;
019 import org.openstreetmap.josm.command.Command;
020 import org.openstreetmap.josm.command.SequenceCommand;
021 import org.openstreetmap.josm.corrector.ReverseWayTagCorrector;
022 import org.openstreetmap.josm.corrector.UserCancelException;
023 import org.openstreetmap.josm.data.osm.Node;
024 import org.openstreetmap.josm.data.osm.OsmPrimitive;
025 import org.openstreetmap.josm.data.osm.Way;
026 import org.openstreetmap.josm.tools.Shortcut;
027 import org.openstreetmap.josm.tools.Utils;
028
029 public final class ReverseWayAction extends JosmAction {
030
031 public static class ReverseWayResult {
032 private Way newWay;
033 private Collection<Command> tagCorrectionCommands;
034 private Command reverseCommand;
035
036 public ReverseWayResult(Way newWay, Collection<Command> tagCorrectionCommands, Command reverseCommand) {
037 this.newWay = newWay;
038 this.tagCorrectionCommands = tagCorrectionCommands;
039 this.reverseCommand = reverseCommand;
040 }
041
042 public Way getNewWay() {
043 return newWay;
044 }
045
046 public Collection<Command> getCommands() {
047 List<Command> c = new ArrayList<Command>();
048 c.addAll(tagCorrectionCommands);
049 c.add(reverseCommand);
050 return c;
051 }
052
053 public Command getAsSequenceCommand() {
054 return new SequenceCommand(tr("Reverse way"), getCommands());
055 }
056
057 public Command getReverseCommand() {
058 return reverseCommand;
059 }
060
061 public Collection<Command> getTagCorrectionCommands() {
062 return tagCorrectionCommands;
063 }
064 }
065
066 public ReverseWayAction() {
067 super(tr("Reverse Ways"), "wayflip", tr("Reverse the direction of all selected ways."),
068 Shortcut.registerShortcut("tools:reverse", tr("Tool: {0}", tr("Reverse Ways")), KeyEvent.VK_R, Shortcut.DIRECT), true);
069 putValue("help", ht("/Action/ReverseWays"));
070 }
071
072 public void actionPerformed(ActionEvent e) {
073 if (! isEnabled())
074 return;
075 if (getCurrentDataSet() == null)
076 return;
077
078 final Collection<Way> sel = getCurrentDataSet().getSelectedWays();
079 if (sel.isEmpty()) {
080 JOptionPane.showMessageDialog(
081 Main.parent,
082 tr("Please select at least one way."),
083 tr("Information"),
084 JOptionPane.INFORMATION_MESSAGE
085 );
086 return;
087 }
088
089 boolean propertiesUpdated = false;
090 Collection<Command> c = new LinkedList<Command>();
091 for (Way w : sel) {
092 ReverseWayResult revResult;
093 try {
094 revResult = reverseWay(w);
095 } catch (UserCancelException ex) {
096 return;
097 }
098 c.addAll(revResult.getCommands());
099 propertiesUpdated |= !revResult.getTagCorrectionCommands().isEmpty();
100 }
101 Main.main.undoRedo.add(new SequenceCommand(tr("Reverse ways"), c));
102 if (propertiesUpdated) {
103 getCurrentDataSet().fireSelectionChanged();
104 }
105 Main.map.repaint();
106 }
107
108 /**
109 * @param w the way
110 * @return the reverse command and the tag correction commands
111 */
112 public static ReverseWayResult reverseWay(Way w) throws UserCancelException {
113 Way wnew = new Way(w);
114 List<Node> nodesCopy = wnew.getNodes();
115 Collections.reverse(nodesCopy);
116 wnew.setNodes(nodesCopy);
117
118 Collection<Command> corrCmds = Collections.<Command>emptyList();
119 if (Main.pref.getBoolean("tag-correction.reverse-way", true)) {
120 corrCmds = (new ReverseWayTagCorrector()).execute(w, wnew);
121 }
122 return new ReverseWayResult(wnew, corrCmds, new ChangeCommand(w, wnew));
123 }
124
125 protected int getNumWaysInSelection() {
126 if (getCurrentDataSet() == null) return 0;
127 int ret = 0;
128 for (OsmPrimitive primitive : getCurrentDataSet().getSelected()) {
129 if (primitive instanceof Way) {
130 ret++;
131 }
132 }
133 return ret;
134 }
135
136 @Override
137 protected void updateEnabledState() {
138 if (getCurrentDataSet() == null) {
139 setEnabled(false);
140 } else {
141 updateEnabledState(getCurrentDataSet().getSelected());
142 }
143 }
144
145 @Override
146 protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
147 setEnabled(Utils.exists(selection, OsmPrimitive.wayPredicate));
148 }
149 }