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 }