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    }