Changeset 1169 in josm


Ignore:
Timestamp:
2008-12-23T15:07:05+01:00 (11 years ago)
Author:
stoecker
Message:

removed usage of tab stops

Location:
trunk/src/org/openstreetmap/josm
Files:
256 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/Main.java

    r1163 r1169  
    182182
    183183    /**
    184      * Remove the specified layer from the map. If it is the last layer, 
     184     * Remove the specified layer from the map. If it is the last layer,
    185185     * remove the map as well.
    186186     */
     
    219219
    220220    /**
    221      * Load all plugins specified in preferences. If the parameter is 
     221     * Load all plugins specified in preferences. If the parameter is
    222222     * <code>true</code>, all early plugins are loaded (before constructor).
    223223     */
     
    281281                Main.pref.put("pluginmanager.lastupdate",Long.toString(tim));
    282282            } else if (d > maxTime) {
    283                 JOptionPane.showMessageDialog(Main.parent, 
    284                    "<html>" + 
     283                JOptionPane.showMessageDialog(Main.parent,
     284                   "<html>" +
    285285                   tr("Last plugin update more than {0} days ago.", d) +
    286                    "<br><em>" + 
     286                   "<br><em>" +
    287287                   tr("(You can change the number of days after which this warning appears<br>by setting the config option 'pluginmanager.warntime'.)") +
    288288                   "</html>");
     
    512512        } else if (os.toLowerCase().startsWith("windows")) {
    513513            platform = new PlatformHookWindows();
    514         } else if (os.equals("Linux") || os.equals("Solaris") || 
    515             os.equals("SunOS") || os.equals("AIX") || 
     514        } else if (os.equals("Linux") || os.equals("Solaris") ||
     515            os.equals("SunOS") || os.equals("AIX") ||
    516516            os.equals("FreeBSD") || os.equals("NetBSD") || os.equals("OpenBSD")) {
    517517            platform = new PlatformHookUnixoid();
  • trunk/src/org/openstreetmap/josm/actions/AboutAction.java

    r1138 r1169  
    5151public class AboutAction extends JosmAction {
    5252
    53         private static final String version;
    54 
    55         private final static JTextArea revision;
    56         private static String time;
     53    private static final String version;
     54
     55    private final static JTextArea revision;
     56    private static String time;
    5757
    5858    static {
     
    6060        if(u == null) {
    6161            try {
    62                 u = new URL("jar:" + Main.class.getProtectionDomain().getCodeSource().getLocation().toString() 
     62                u = new URL("jar:" + Main.class.getProtectionDomain().getCodeSource().getLocation().toString()
    6363                        + "!/META-INF/MANIFEST.MF");
    6464            } catch (MalformedURLException e) {
     
    6666            }
    6767        }
    68                 revision = loadFile(u);
    69 
    70                 Pattern versionPattern = Pattern.compile(".*?(?:Revision|Main-Version): ([0-9]*(?: SVN)?).*", Pattern.CASE_INSENSITIVE|Pattern.DOTALL);
    71                 Matcher match = versionPattern.matcher(revision.getText());
    72                 version = match.matches() ? match.group(1) : tr("UNKNOWN");
    73 
    74                 Pattern timePattern = Pattern.compile(".*?(?:Last Changed Date|Main-Date): ([^\n]*).*", Pattern.CASE_INSENSITIVE|Pattern.DOTALL);
    75                 match = timePattern.matcher(revision.getText());
    76                 time = match.matches() ? match.group(1) : tr("UNKNOWN");
    77         }
    78 
    79         /**
    80         * Return string describing version.
    81         * Note that the strinc contains the version number plus an optional suffix of " SVN" to indicate an unofficial development build.
    82         * @return version string
    83         */
    84         static public String getVersionString() {
    85                 return version;
    86         }
     68        revision = loadFile(u);
     69
     70        Pattern versionPattern = Pattern.compile(".*?(?:Revision|Main-Version): ([0-9]*(?: SVN)?).*", Pattern.CASE_INSENSITIVE|Pattern.DOTALL);
     71        Matcher match = versionPattern.matcher(revision.getText());
     72        version = match.matches() ? match.group(1) : tr("UNKNOWN");
     73
     74        Pattern timePattern = Pattern.compile(".*?(?:Last Changed Date|Main-Date): ([^\n]*).*", Pattern.CASE_INSENSITIVE|Pattern.DOTALL);
     75        match = timePattern.matcher(revision.getText());
     76        time = match.matches() ? match.group(1) : tr("UNKNOWN");
     77    }
     78
     79    /**
     80    * Return string describing version.
     81    * Note that the strinc contains the version number plus an optional suffix of " SVN" to indicate an unofficial development build.
     82    * @return version string
     83    */
     84    static public String getVersionString() {
     85        return version;
     86    }
    8787
    8888    /**
     
    9999        return myVersion;
    100100    }
    101        
     101
    102102    /**
    103103     * check whether the version is a development build out of SVN.
     
    107107        return version.endsWith(" SVN");
    108108    }
    109        
    110         public AboutAction() {
    111                 super(tr("About"), "about", tr("Display the about screen."), Shortcut.registerShortcut("system:about", tr("About"), KeyEvent.VK_F1, Shortcut.GROUP_DIRECT, Shortcut.SHIFT_DEFAULT), true);
    112         }
    113 
    114         public void actionPerformed(ActionEvent e) {
    115                 JTabbedPane about = new JTabbedPane();
    116 
    117                 JTextArea readme = loadFile(Main.class.getResource("/README"));
    118                 JTextArea contribution = loadFile(Main.class.getResource("/CONTRIBUTION"));
    119 
    120                 JPanel info = new JPanel(new GridBagLayout());
    121                 info.add(new JLabel(tr("Java OpenStreetMap Editor Version {0}",version)), GBC.eol().fill(GBC.HORIZONTAL));
    122                 info.add(new JLabel(tr("last change at {0}",time)), GBC.eol().fill(GBC.HORIZONTAL));
    123                 info.add(new JLabel(tr("Java Version {0}",System.getProperty("java.version"))), GBC.eol().fill(GBC.HORIZONTAL));
    124                 info.add(GBC.glue(0,10), GBC.eol());
    125                 info.add(new JLabel(tr("Homepage")), GBC.std().insets(0,0,10,0));
    126                 info.add(new UrlLabel("http://josm.openstreetmap.de"), GBC.eol().fill(GBC.HORIZONTAL));
    127                 info.add(new JLabel(tr("Bug Reports")), GBC.std().insets(0,0,10,0));
    128                 info.add(new UrlLabel("http://josm.openstreetmap.de/newticket"), GBC.eol().fill(GBC.HORIZONTAL));
    129                 info.add(new JLabel(tr("News about JOSM")), GBC.std().insets(0,0,10,0));
    130                 info.add(new UrlLabel("http://www.opengeodata.org/?cat=17"), GBC.eol().fill(GBC.HORIZONTAL));
    131 
    132                 about.addTab(tr("Info"), info);
    133                 about.addTab(tr("Readme"), createScrollPane(readme));
    134                 about.addTab(tr("Revision"), createScrollPane(revision));
    135                 about.addTab(tr("Contribution"), createScrollPane(contribution));
    136 
    137                 JPanel pluginTab = new JPanel(new GridBagLayout());
    138                 for (final PluginProxy p : Main.plugins) {
    139                         String name = p.info.name + (p.info.version != null && !p.info.version.equals("") ? " Version: "+p.info.version : "");
    140                         pluginTab.add(new JLabel(name), GBC.std());
    141                         pluginTab.add(Box.createHorizontalGlue(), GBC.std().fill(GBC.HORIZONTAL));
    142                         pluginTab.add(new JButton(new AbstractAction(tr("Information")){
    143                                 public void actionPerformed(ActionEvent event) {
    144                                         StringBuilder b = new StringBuilder();
    145                                         for (Entry<String,String> e : p.info.attr.entrySet()) {
    146                                                 b.append(e.getKey());
    147                                                 b.append(": ");
    148                                                 b.append(e.getValue());
    149                                                 b.append("\n");
    150                                         }
    151                                         JTextArea a = new JTextArea(10,40);
    152                                         a.setEditable(false);
    153                                         a.setText(b.toString());
    154                                         JOptionPane.showMessageDialog(Main.parent, new JScrollPane(a));
    155                                 }
    156                         }), GBC.eol());
    157                         JLabel label = new JLabel("<html><i>"+(p.info.description==null?tr("no description available"):p.info.description)+"</i></html>");
    158                         label.setBorder(BorderFactory.createEmptyBorder(0,20,0,0));
    159                         label.setMaximumSize(new Dimension(450,1000));
    160                         pluginTab.add(label, GBC.eop().fill(GBC.HORIZONTAL));
    161                 }
    162                 about.addTab(tr("Plugins"), new JScrollPane(pluginTab));
    163 
    164                 about.setPreferredSize(new Dimension(500,300));
    165 
    166                 JOptionPane.showMessageDialog(Main.parent, about, tr("About JOSM..."),
    167                                 JOptionPane.INFORMATION_MESSAGE, ImageProvider.get("logo"));
    168         }
    169 
    170         private JScrollPane createScrollPane(JTextArea area) {
    171                 area.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    172                 area.setOpaque(false);
    173                 JScrollPane sp = new JScrollPane(area);
    174                 sp.setBorder(null);
    175                 sp.setOpaque(false);
    176                 return sp;
    177         }
    178 
    179         /**
    180         * Retrieve the latest JOSM version from the JOSM homepage.
    181         * @return An string with the latest version or "UNKNOWN" in case
    182          *              of problems (e.g. no internet connection).
    183         */
    184         public static String checkLatestVersion() {
    185                 String latest;
    186                 try {
    187                         InputStream s = new URL("http://josm.openstreetmap.de/current").openStream();
    188                         latest = new BufferedReader(new InputStreamReader(s)).readLine();
    189                         s.close();
    190                 } catch (IOException x) {
    191                         x.printStackTrace();
    192                         return tr("UNKNOWN");
    193                 }
    194                 return latest;
    195         }
    196 
    197         /**
    198         * Load the specified resource into an TextArea and return it.
    199         * @param resource The resource url to load
    200          * @return      An read-only text area with the content of "resource"
    201         */
    202         private static JTextArea loadFile(URL resource) {
    203                 JTextArea area = new JTextArea(tr("File could not be found."));
    204                 area.setEditable(false);
    205                 Font font = Font.getFont("monospaced");
    206                 if (font != null)
    207                         area.setFont(font);
    208                 if (resource == null)
    209                         return area;
    210                 BufferedReader in;
    211                 try {
    212                         in = new BufferedReader(new InputStreamReader(resource.openStream()));
    213                         StringBuilder sb = new StringBuilder();
    214                         for (String line = in.readLine(); line != null; line = in.readLine()) {
    215                                 sb.append(line);
    216                                 sb.append('\n');
    217                         }
    218                         area.setText(sb.toString());
    219                         area.setCaretPosition(0);
    220                 } catch (IOException e) {
    221                         e.printStackTrace();
    222                 }
    223                 return area;
    224         }
     109
     110    public AboutAction() {
     111        super(tr("About"), "about", tr("Display the about screen."), Shortcut.registerShortcut("system:about", tr("About"), KeyEvent.VK_F1, Shortcut.GROUP_DIRECT, Shortcut.SHIFT_DEFAULT), true);
     112    }
     113
     114    public void actionPerformed(ActionEvent e) {
     115        JTabbedPane about = new JTabbedPane();
     116
     117        JTextArea readme = loadFile(Main.class.getResource("/README"));
     118        JTextArea contribution = loadFile(Main.class.getResource("/CONTRIBUTION"));
     119
     120        JPanel info = new JPanel(new GridBagLayout());
     121        info.add(new JLabel(tr("Java OpenStreetMap Editor Version {0}",version)), GBC.eol().fill(GBC.HORIZONTAL));
     122        info.add(new JLabel(tr("last change at {0}",time)), GBC.eol().fill(GBC.HORIZONTAL));
     123        info.add(new JLabel(tr("Java Version {0}",System.getProperty("java.version"))), GBC.eol().fill(GBC.HORIZONTAL));
     124        info.add(GBC.glue(0,10), GBC.eol());
     125        info.add(new JLabel(tr("Homepage")), GBC.std().insets(0,0,10,0));
     126        info.add(new UrlLabel("http://josm.openstreetmap.de"), GBC.eol().fill(GBC.HORIZONTAL));
     127        info.add(new JLabel(tr("Bug Reports")), GBC.std().insets(0,0,10,0));
     128        info.add(new UrlLabel("http://josm.openstreetmap.de/newticket"), GBC.eol().fill(GBC.HORIZONTAL));
     129        info.add(new JLabel(tr("News about JOSM")), GBC.std().insets(0,0,10,0));
     130        info.add(new UrlLabel("http://www.opengeodata.org/?cat=17"), GBC.eol().fill(GBC.HORIZONTAL));
     131
     132        about.addTab(tr("Info"), info);
     133        about.addTab(tr("Readme"), createScrollPane(readme));
     134        about.addTab(tr("Revision"), createScrollPane(revision));
     135        about.addTab(tr("Contribution"), createScrollPane(contribution));
     136
     137        JPanel pluginTab = new JPanel(new GridBagLayout());
     138        for (final PluginProxy p : Main.plugins) {
     139            String name = p.info.name + (p.info.version != null && !p.info.version.equals("") ? " Version: "+p.info.version : "");
     140            pluginTab.add(new JLabel(name), GBC.std());
     141            pluginTab.add(Box.createHorizontalGlue(), GBC.std().fill(GBC.HORIZONTAL));
     142            pluginTab.add(new JButton(new AbstractAction(tr("Information")){
     143                public void actionPerformed(ActionEvent event) {
     144                    StringBuilder b = new StringBuilder();
     145                    for (Entry<String,String> e : p.info.attr.entrySet()) {
     146                        b.append(e.getKey());
     147                        b.append(": ");
     148                        b.append(e.getValue());
     149                        b.append("\n");
     150                    }
     151                    JTextArea a = new JTextArea(10,40);
     152                    a.setEditable(false);
     153                    a.setText(b.toString());
     154                    JOptionPane.showMessageDialog(Main.parent, new JScrollPane(a));
     155                }
     156            }), GBC.eol());
     157            JLabel label = new JLabel("<html><i>"+(p.info.description==null?tr("no description available"):p.info.description)+"</i></html>");
     158            label.setBorder(BorderFactory.createEmptyBorder(0,20,0,0));
     159            label.setMaximumSize(new Dimension(450,1000));
     160            pluginTab.add(label, GBC.eop().fill(GBC.HORIZONTAL));
     161        }
     162        about.addTab(tr("Plugins"), new JScrollPane(pluginTab));
     163
     164        about.setPreferredSize(new Dimension(500,300));
     165
     166        JOptionPane.showMessageDialog(Main.parent, about, tr("About JOSM..."),
     167                JOptionPane.INFORMATION_MESSAGE, ImageProvider.get("logo"));
     168    }
     169
     170    private JScrollPane createScrollPane(JTextArea area) {
     171        area.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
     172        area.setOpaque(false);
     173        JScrollPane sp = new JScrollPane(area);
     174        sp.setBorder(null);
     175        sp.setOpaque(false);
     176        return sp;
     177    }
     178
     179    /**
     180    * Retrieve the latest JOSM version from the JOSM homepage.
     181    * @return An string with the latest version or "UNKNOWN" in case
     182     *      of problems (e.g. no internet connection).
     183    */
     184    public static String checkLatestVersion() {
     185        String latest;
     186        try {
     187            InputStream s = new URL("http://josm.openstreetmap.de/current").openStream();
     188            latest = new BufferedReader(new InputStreamReader(s)).readLine();
     189            s.close();
     190        } catch (IOException x) {
     191            x.printStackTrace();
     192            return tr("UNKNOWN");
     193        }
     194        return latest;
     195    }
     196
     197    /**
     198    * Load the specified resource into an TextArea and return it.
     199    * @param resource The resource url to load
     200     * @return  An read-only text area with the content of "resource"
     201    */
     202    private static JTextArea loadFile(URL resource) {
     203        JTextArea area = new JTextArea(tr("File could not be found."));
     204        area.setEditable(false);
     205        Font font = Font.getFont("monospaced");
     206        if (font != null)
     207            area.setFont(font);
     208        if (resource == null)
     209            return area;
     210        BufferedReader in;
     211        try {
     212            in = new BufferedReader(new InputStreamReader(resource.openStream()));
     213            StringBuilder sb = new StringBuilder();
     214            for (String line = in.readLine(); line != null; line = in.readLine()) {
     215                sb.append(line);
     216                sb.append('\n');
     217            }
     218            area.setText(sb.toString());
     219            area.setCaretPosition(0);
     220        } catch (IOException e) {
     221            e.printStackTrace();
     222        }
     223        return area;
     224    }
    225225}
  • trunk/src/org/openstreetmap/josm/actions/AddNodeAction.java

    r1138 r1169  
    4141
    4242/**
    43  * This action displays a dialog where the user can enter a latitude and longitude, 
     43 * This action displays a dialog where the user can enter a latitude and longitude,
    4444 * and when ok is pressed, a new node is created at the specified position.
    4545 */
     
    4747
    4848    public AddNodeAction() {
    49         super(tr("Add Node"), "addnode", tr("Add a node by entering latitude and longitude."),
    50                 Shortcut.registerShortcut("addnode", tr("Edit: {0}", tr("Add Node")), KeyEvent.VK_D, Shortcut.GROUP_EDIT,
    51                 Shortcut.SHIFT_DEFAULT), true);
     49        super(tr("Add Node"), "addnode", tr("Add a node by entering latitude and longitude."),
     50        Shortcut.registerShortcut("addnode", tr("Edit: {0}", tr("Add Node")), KeyEvent.VK_D, Shortcut.GROUP_EDIT,
     51        Shortcut.SHIFT_DEFAULT), true);
    5252    }
    5353
    54         public void actionPerformed(ActionEvent e) {   
     54    public void actionPerformed(ActionEvent e) {
    5555        JPanel p = new JPanel(new GridBagLayout());
    5656        p.add(new JLabel("<html>"+
    57                 tr("Enter the coordinates for the new node.") + 
    58                 "<br>" + tr("Use decimal degrees.") + 
    59                 "<br>" + tr("Negative values denote Western/Southern hemisphere.")), 
     57                tr("Enter the coordinates for the new node.") +
     58                "<br>" + tr("Use decimal degrees.") +
     59                "<br>" + tr("Negative values denote Western/Southern hemisphere.")),
    6060                GBC.eol());
    61        
     61
    6262        p.add(new JLabel(tr("Latitude")), GBC.std().insets(0,10,5,0));
    6363        final JTextField lat = new JTextField(12);
     
    6565        p.add(new JLabel(tr("Longitude")), GBC.std().insets(0,0,5,10));
    6666        final JTextField lon = new JTextField(12);
    67         p.add(lon, GBC.eol().insets(0,0,0,10));   
    68        
     67        p.add(lon, GBC.eol().insets(0,0,0,10));
     68
    6969        Node nnew = null;
    7070
     
    7979            } catch (Exception ex) { }
    8080        }
    81        
    82                 /* Now execute the commands to add the dupicated contents of the paste buffer to the map */
    83                
    84                 Main.main.undoRedo.add(new AddCommand(nnew));
    85                 Main.ds.setSelected(nnew);
    86                 Main.map.mapView.repaint();
     81
     82        /* Now execute the commands to add the dupicated contents of the paste buffer to the map */
     83
     84        Main.main.undoRedo.add(new AddCommand(nnew));
     85        Main.ds.setSelected(nnew);
     86        Main.map.mapView.repaint();
    8787    }
    8888}
  • trunk/src/org/openstreetmap/josm/actions/AlignInCircleAction.java

    r1160 r1169  
    2424/**
    2525 * Aligns all selected nodes within a circle. (Useful for roundabouts)
    26  * 
     26 *
    2727 * @author Matthew Newton
    2828 * @author Petr Dlouhý
     
    3131
    3232    public AlignInCircleAction() {
    33         super(tr("Align Nodes in Circle"), "aligncircle", tr("Move the selected nodes into a circle."), 
    34                 Shortcut.registerShortcut("tools:aligncircle", tr("Tool: {0}", tr("Align Nodes in Circle")), 
     33        super(tr("Align Nodes in Circle"), "aligncircle", tr("Move the selected nodes into a circle."),
     34                Shortcut.registerShortcut("tools:aligncircle", tr("Tool: {0}", tr("Align Nodes in Circle")),
    3535                        KeyEvent.VK_O, Shortcut.GROUP_EDIT), true);
    3636    }
  • trunk/src/org/openstreetmap/josm/actions/AlignInLineAction.java

    r1084 r1169  
    2929public final class AlignInLineAction extends JosmAction {
    3030
    31         public AlignInLineAction() {
    32                 super(tr("Align Nodes in Line"), "alignline", tr("Move the selected nodes onto a line."),
    33                 Shortcut.registerShortcut("tools:alignline", tr("Tool: {0}", tr("Align Nodes in Line")), KeyEvent.VK_L, Shortcut.GROUP_EDIT), true);
    34         }
     31    public AlignInLineAction() {
     32        super(tr("Align Nodes in Line"), "alignline", tr("Move the selected nodes onto a line."),
     33        Shortcut.registerShortcut("tools:alignline", tr("Tool: {0}", tr("Align Nodes in Line")), KeyEvent.VK_L, Shortcut.GROUP_EDIT), true);
     34    }
    3535
    36         /**
    37         * The general algorithm here is to find the two selected nodes
    38         * that are furthest apart, and then to align all other selected
    39         * nodes onto the straight line between these nodes.
    40         */
    41         public void actionPerformed(ActionEvent e) {
    42                 Collection<OsmPrimitive> sel = Main.ds.getSelected();
    43                 Collection<Node> nodes = new LinkedList<Node>();
    44                 Collection<Node> itnodes = new LinkedList<Node>();
    45                 for (OsmPrimitive osm : sel)
    46                         if (osm instanceof Node) {
    47                                 nodes.add((Node)osm);
    48                                 itnodes.add((Node)osm);
    49                         }
    50                 // special case if no single nodes are selected and exactly one way is:
    51                 // then use the way's nodes
    52                 if ((nodes.size() == 0) && (sel.size() == 1))
    53                         for (OsmPrimitive osm : sel)
    54                                 if (osm instanceof Way) {
    55                                         nodes.addAll(((Way)osm).nodes);
    56                                         itnodes.addAll(((Way)osm).nodes);
    57                                 }
    58                 if (nodes.size() < 3) {
    59                         JOptionPane.showMessageDialog(Main.parent, tr("Please select at least three nodes."));
    60                         return;
    61                 }
     36    /**
     37    * The general algorithm here is to find the two selected nodes
     38    * that are furthest apart, and then to align all other selected
     39    * nodes onto the straight line between these nodes.
     40    */
     41    public void actionPerformed(ActionEvent e) {
     42        Collection<OsmPrimitive> sel = Main.ds.getSelected();
     43        Collection<Node> nodes = new LinkedList<Node>();
     44        Collection<Node> itnodes = new LinkedList<Node>();
     45        for (OsmPrimitive osm : sel)
     46            if (osm instanceof Node) {
     47                nodes.add((Node)osm);
     48                itnodes.add((Node)osm);
     49            }
     50        // special case if no single nodes are selected and exactly one way is:
     51        // then use the way's nodes
     52        if ((nodes.size() == 0) && (sel.size() == 1))
     53            for (OsmPrimitive osm : sel)
     54                if (osm instanceof Way) {
     55                    nodes.addAll(((Way)osm).nodes);
     56                    itnodes.addAll(((Way)osm).nodes);
     57                }
     58        if (nodes.size() < 3) {
     59            JOptionPane.showMessageDialog(Main.parent, tr("Please select at least three nodes."));
     60            return;
     61        }
    6262
    63                 // Find from the selected nodes two that are the furthest apart.
    64                 // Let's call them A and B.
    65                 double distance = 0;
     63        // Find from the selected nodes two that are the furthest apart.
     64        // Let's call them A and B.
     65        double distance = 0;
    6666
    67                 Node nodea = null;
    68                 Node nodeb = null;
     67        Node nodea = null;
     68        Node nodeb = null;
    6969
    70                 for (Node n : nodes) {
    71                         itnodes.remove(n);
    72                         for (Node m : itnodes) {
    73                                 double dist = Math.sqrt(n.eastNorth.distance(m.eastNorth));
    74                                 if (dist > distance) {
    75                                         nodea = n;
    76                                         nodeb = m;
    77                                         distance = dist;
    78                                 }
    79                         }
    80                 }
     70        for (Node n : nodes) {
     71            itnodes.remove(n);
     72            for (Node m : itnodes) {
     73                double dist = Math.sqrt(n.eastNorth.distance(m.eastNorth));
     74                if (dist > distance) {
     75                    nodea = n;
     76                    nodeb = m;
     77                    distance = dist;
     78                }
     79            }
     80        }
    8181
    82                 // Remove the nodes A and B from the list of nodes to move
    83                 nodes.remove(nodea);
    84                 nodes.remove(nodeb);
     82        // Remove the nodes A and B from the list of nodes to move
     83        nodes.remove(nodea);
     84        nodes.remove(nodeb);
    8585
    86                 // Find out co-ords of A and B
    87                 double ax = nodea.eastNorth.east();
    88                 double ay = nodea.eastNorth.north();
    89                 double bx = nodeb.eastNorth.east();
    90                 double by = nodeb.eastNorth.north();
     86        // Find out co-ords of A and B
     87        double ax = nodea.eastNorth.east();
     88        double ay = nodea.eastNorth.north();
     89        double bx = nodeb.eastNorth.east();
     90        double by = nodeb.eastNorth.north();
    9191
    92                 // A list of commands to do
    93                 Collection<Command> cmds = new LinkedList<Command>();
     92        // A list of commands to do
     93        Collection<Command> cmds = new LinkedList<Command>();
    9494
    95                 // OK, for each node to move, work out where to move it!
    96                 for (Node n : nodes) {
    97                         // Get existing co-ords of node to move
    98                         double nx = n.eastNorth.east();
    99                         double ny = n.eastNorth.north();
     95        // OK, for each node to move, work out where to move it!
     96        for (Node n : nodes) {
     97            // Get existing co-ords of node to move
     98            double nx = n.eastNorth.east();
     99            double ny = n.eastNorth.north();
    100100
    101                         if (ax == bx) {
    102                                 // Special case if AB is vertical...
    103                                 nx = ax;
    104                         } else if (ay == by) {
    105                                 // ...or horizontal
    106                                 ny = ay;
    107                         } else {
    108                                 // Otherwise calculate position by solving y=mx+c
    109                                 double m1 = (by - ay) / (bx - ax);
    110                                 double c1 = ay - (ax * m1);
    111                                 double m2 = (-1) / m1;
    112                                 double c2 = n.eastNorth.north() - (n.eastNorth.east() * m2);
     101            if (ax == bx) {
     102                // Special case if AB is vertical...
     103                nx = ax;
     104            } else if (ay == by) {
     105                // ...or horizontal
     106                ny = ay;
     107            } else {
     108                // Otherwise calculate position by solving y=mx+c
     109                double m1 = (by - ay) / (bx - ax);
     110                double c1 = ay - (ax * m1);
     111                double m2 = (-1) / m1;
     112                double c2 = n.eastNorth.north() - (n.eastNorth.east() * m2);
    113113
    114                                 nx = (c2 - c1) / (m1 - m2);
    115                                 ny = (m1 * nx) + c1;
    116                         }
     114                nx = (c2 - c1) / (m1 - m2);
     115                ny = (m1 * nx) + c1;
     116            }
    117117
    118                         // Add the command to move the node to its new position.
    119                         cmds.add(new MoveCommand(n, nx - n.eastNorth.east(), ny - n.eastNorth.north() ));
    120                 }
     118            // Add the command to move the node to its new position.
     119            cmds.add(new MoveCommand(n, nx - n.eastNorth.east(), ny - n.eastNorth.north() ));
     120        }
    121121
    122                 // Do it!
    123                 Main.main.undoRedo.add(new SequenceCommand(tr("Align Nodes in Line"), cmds));
    124                 Main.map.repaint();
    125         }
     122        // Do it!
     123        Main.main.undoRedo.add(new SequenceCommand(tr("Align Nodes in Line"), cmds));
     124        Main.map.repaint();
     125    }
    126126}
  • trunk/src/org/openstreetmap/josm/actions/AutoScaleAction.java

    r1084 r1169  
    4747    public AutoScaleAction(String mode) {
    4848        super(tr("Zoom to {0}", tr(mode)), "dialogs/autoscale/" + mode, tr("Zoom the view to {0}.", tr(mode)),
    49                                 Shortcut.registerShortcut("view:zoom"+mode, tr("View: {0}", tr("Zoom to {0}", tr(mode))), getModeShortcut(mode), Shortcut.GROUP_EDIT), true);
     49                Shortcut.registerShortcut("view:zoom"+mode, tr("View: {0}", tr("Zoom to {0}", tr(mode))), getModeShortcut(mode), Shortcut.GROUP_EDIT), true);
    5050        String modeHelp = Character.toUpperCase(mode.charAt(0)) + mode.substring(1);
    5151        putValue("help", "Action/AutoScale/" + modeHelp);
  • trunk/src/org/openstreetmap/josm/actions/CombineWayAction.java

    r1084 r1169  
    4949public class CombineWayAction extends JosmAction implements SelectionChangedListener {
    5050
    51         public CombineWayAction() {
    52                 super(tr("Combine Way"), "combineway", tr("Combine several ways into one."),
    53                 Shortcut.registerShortcut("tools:combineway", tr("Tool: {0}", tr("Combine Way")), KeyEvent.VK_C, Shortcut.GROUP_EDIT), true);
    54                 DataSet.selListeners.add(this);
    55         }
    56 
    57         public void actionPerformed(ActionEvent event) {
    58                 Collection<OsmPrimitive> selection = Main.ds.getSelected();
    59                 LinkedList<Way> selectedWays = new LinkedList<Way>();
    60 
    61                 for (OsmPrimitive osm : selection)
    62                         if (osm instanceof Way)
    63                                 selectedWays.add((Way)osm);
    64 
    65                 if (selectedWays.size() < 2) {
    66                         JOptionPane.showMessageDialog(Main.parent, tr("Please select at least two ways to combine."));
    67                         return;
    68                 }
    69 
    70                 // Check whether all ways have identical relationship membership. More
    71                 // specifically: If one of the selected ways is a member of relation X
    72                 // in role Y, then all selected ways must be members of X in role Y.
    73 
    74                 // FIXME: In a later revision, we should display some sort of conflict
    75                 // dialog like we do for tags, to let the user choose which relations
    76                 // should be kept.
    77 
    78                 // Step 1, iterate over all relations and figure out which of our
    79                 // selected ways are members of a relation.
    80                 HashMap<Pair<Relation,String>, HashSet<Way>> backlinks =
    81                         new HashMap<Pair<Relation,String>, HashSet<Way>>();
    82                 HashSet<Relation> relationsUsingWays = new HashSet<Relation>();
    83                 for (Relation r : Main.ds.relations) {
    84                         if (r.deleted || r.incomplete) continue;
    85                         for (RelationMember rm : r.members) {
    86                                 if (rm.member instanceof Way) {
    87                                         for(Way w : selectedWays) {
    88                                                 if (rm.member == w) {
    89                                                         Pair<Relation,String> pair = new Pair<Relation,String>(r, rm.role);
    90                                                         HashSet<Way> waylinks = new HashSet<Way>();
    91                                                         if (backlinks.containsKey(pair)) {
    92                                                                 waylinks = backlinks.get(pair);
    93                                                         } else {
    94                                                                 waylinks = new HashSet<Way>();
    95                                                                 backlinks.put(pair, waylinks);
    96                                                         }
    97                                                         waylinks.add(w);
    98 
    99                                                         // this is just a cache for later use
    100                                                         relationsUsingWays.add(r);
    101                                                 }
    102                                         }
    103                                 }
    104                         }
    105                 }
    106 
    107                 // Complain to the user if the ways don't have equal memberships.
    108                 for (HashSet<Way> waylinks : backlinks.values()) {
    109                         if (!waylinks.containsAll(selectedWays)) {
    110                                 int option = JOptionPane.showConfirmDialog(Main.parent,
    111                                         tr("The selected ways have differing relation memberships.  "
    112                                                 + "Do you still want to combine them?"),
    113                                         tr("Combine ways with different memberships?"),
    114                                         JOptionPane.YES_NO_OPTION);
    115                                 if (option == JOptionPane.YES_OPTION)
    116                                         break;
    117                                 return;
    118                         }
    119                 }
    120 
    121                 // collect properties for later conflict resolving
    122                 Map<String, Set<String>> props = new TreeMap<String, Set<String>>();
    123                 for (Way w : selectedWays) {
    124                         for (Entry<String,String> e : w.entrySet()) {
    125                                 if (!props.containsKey(e.getKey()))
    126                                         props.put(e.getKey(), new TreeSet<String>());
    127                                 props.get(e.getKey()).add(e.getValue());
    128                         }
    129                 }
    130 
    131                 List<Node> nodeList = null;
    132                 Object firstTry = actuallyCombineWays(selectedWays, false);
    133                 if (firstTry instanceof List) {
    134                         nodeList = (List<Node>) firstTry;
    135                 } else {
    136                         Object secondTry = actuallyCombineWays(selectedWays, true);
    137                         if (secondTry instanceof List) {
    138                                 int option = JOptionPane.showConfirmDialog(Main.parent,
    139                                         tr("The ways can not be combined in their current directions.  "
    140                                         + "Do you want to reverse some of them?"), tr("Change directions?"),
    141                                         JOptionPane.YES_NO_OPTION);
    142                                 if (option != JOptionPane.YES_OPTION) {
    143                                         return;
    144                                 }
    145                                 nodeList = (List<Node>) secondTry;
    146                         } else {
    147                                 JOptionPane.showMessageDialog(Main.parent, secondTry);
    148                                 return;
    149                         }
    150                 }
    151 
    152                 // Find the most appropriate way to modify.
    153 
    154                 // Eventually this might want to be the way with the longest
    155                 // history or the longest selected way but for now just attempt
    156                 // to reuse an existing id.
    157                 Way modifyWay = selectedWays.peek();
    158                 for (Way w : selectedWays) {
    159                         modifyWay = w;
    160                         if (w.id != 0) break;
    161                 }
    162                 Way newWay = new Way(modifyWay);
    163 
    164                 newWay.nodes.clear();
    165                 newWay.nodes.addAll(nodeList);
    166 
    167                 // display conflict dialog
    168                 Map<String, JComboBox> components = new HashMap<String, JComboBox>();
    169                 JPanel p = new JPanel(new GridBagLayout());
    170                 for (Entry<String, Set<String>> e : props.entrySet()) {
    171                         if (TigerUtils.isTigerTag(e.getKey())) {
    172                                 String combined = TigerUtils.combineTags(e.getKey(), e.getValue());
    173                                 newWay.put(e.getKey(), combined);
    174                         } else if (e.getValue().size() > 1) {
    175                                 if("created_by".equals(e.getKey()))
    176                                 {
    177                                         newWay.put("created_by", "JOSM");
    178                                 }
    179                                 else
    180                                 {
    181                                         JComboBox c = new JComboBox(e.getValue().toArray());
    182                                         c.setEditable(true);
    183                                         p.add(new JLabel(e.getKey()), GBC.std());
    184                                         p.add(Box.createHorizontalStrut(10), GBC.std());
    185                                         p.add(c, GBC.eol());
    186                                         components.put(e.getKey(), c);
    187                                 }
    188                         } else
    189                                 newWay.put(e.getKey(), e.getValue().iterator().next());
    190                 }
    191 
    192                 if (!components.isEmpty()) {
    193                         int answer = JOptionPane.showConfirmDialog(Main.parent, p, tr("Enter values for all conflicts."), JOptionPane.OK_CANCEL_OPTION);
    194                         if (answer != JOptionPane.OK_OPTION)
    195                                 return;
    196                         for (Entry<String, JComboBox> e : components.entrySet())
    197                                 newWay.put(e.getKey(), e.getValue().getEditor().getItem().toString());
    198                 }
    199 
    200                 LinkedList<Command> cmds = new LinkedList<Command>();
    201                 LinkedList<Way> deletedWays = new LinkedList<Way>(selectedWays);
    202                 deletedWays.remove(modifyWay);
    203                 cmds.add(new DeleteCommand(deletedWays));
    204                 cmds.add(new ChangeCommand(modifyWay, newWay));
    205 
    206                 // modify all relations containing the now-deleted ways
    207                 for (Relation r : relationsUsingWays) {
    208                         Relation newRel = new Relation(r);
    209                         newRel.members.clear();
    210                         HashSet<String> rolesToReAdd = new HashSet<String>();
    211                         for (RelationMember rm : r.members) {
    212                                 // Don't copy the member if it to one of our ways, just keep a
    213                                 // note to re-add it later on.
    214                                 if (selectedWays.contains(rm.member)) {
    215                                         rolesToReAdd.add(rm.role);
    216                                 } else {
    217                                         newRel.members.add(rm);
    218                                 }
    219                         }
    220                         for (String role : rolesToReAdd) {
    221                                 newRel.members.add(new RelationMember(role, modifyWay));
    222                         }
    223                         cmds.add(new ChangeCommand(r, newRel));
    224                 }
    225                 Main.main.undoRedo.add(new SequenceCommand(tr("Combine {0} ways", selectedWays.size()), cmds));
    226                 Main.ds.setSelected(modifyWay);
    227         }
    228 
    229         /**
    230         * @return a message if combining failed, else a list of nodes.
    231         */
    232         private Object actuallyCombineWays(List<Way> ways, boolean ignoreDirection) {
    233                 // Battle plan:
    234                 //  1. Split the ways into small chunks of 2 nodes and weed out
    235                 //         duplicates.
    236                 //  2. Take a chunk and see if others could be appended or prepended,
    237                 //         if so, do it and remove it from the list of remaining chunks.
    238                 //         Rather, rinse, repeat.
    239                 //  3. If this algorithm does not produce a single way,
    240                 //     complain to the user.
    241                 //  4. Profit!
    242 
    243                 HashSet<Pair<Node,Node>> chunkSet = new HashSet<Pair<Node,Node>>();
    244                 for (Way w : ways)
    245                         chunkSet.addAll(w.getNodePairs(ignoreDirection));
    246 
    247                 LinkedList<Pair<Node,Node>> chunks = new LinkedList<Pair<Node,Node>>(chunkSet);
    248 
    249                 if (chunks.isEmpty()) {
    250                         return tr("All the ways were empty");
    251                 }
    252 
    253                 List<Node> nodeList = Pair.toArrayList(chunks.poll());
    254                 while (!chunks.isEmpty()) {
    255                         ListIterator<Pair<Node,Node>> it = chunks.listIterator();
    256                         boolean foundChunk = false;
    257                         while (it.hasNext()) {
    258                                 Pair<Node,Node> curChunk = it.next();
    259                                 if (curChunk.a == nodeList.get(nodeList.size() - 1)) { // append
    260                                         nodeList.add(curChunk.b);
    261                                 } else if (curChunk.b == nodeList.get(0)) { // prepend
    262                                         nodeList.add(0, curChunk.a);
    263                                 } else if (ignoreDirection && curChunk.b == nodeList.get(nodeList.size() - 1)) { // append
    264                                         nodeList.add(curChunk.a);
    265                                 } else if (ignoreDirection && curChunk.a == nodeList.get(0)) { // prepend
    266                                         nodeList.add(0, curChunk.b);
    267                                 } else {
    268                                         continue;
    269                                 }
    270 
    271                                 foundChunk = true;
    272                                 it.remove();
    273                                 break;
    274                         }
    275                         if (!foundChunk) break;
    276                 }
    277 
    278                 if (!chunks.isEmpty()) {
    279                         return tr("Could not combine ways "
    280                                 + "(They could not be merged into a single string of nodes)");
    281                 }
    282 
    283                 return nodeList;
    284         }
    285 
    286         /**
    287         * Enable the "Combine way" menu option if more then one way is selected
    288         */
    289         public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
    290                 boolean first = false;
    291                 for (OsmPrimitive osm : newSelection) {
    292                         if (osm instanceof Way) {
    293                                 if (first) {
    294                                         setEnabled(true);
    295                                         return;
    296                                 }
    297                                 first = true;
    298                         }
    299                 }
    300                 setEnabled(false);
    301         }
     51    public CombineWayAction() {
     52        super(tr("Combine Way"), "combineway", tr("Combine several ways into one."),
     53        Shortcut.registerShortcut("tools:combineway", tr("Tool: {0}", tr("Combine Way")), KeyEvent.VK_C, Shortcut.GROUP_EDIT), true);
     54        DataSet.selListeners.add(this);
     55    }
     56
     57    public void actionPerformed(ActionEvent event) {
     58        Collection<OsmPrimitive> selection = Main.ds.getSelected();
     59        LinkedList<Way> selectedWays = new LinkedList<Way>();
     60
     61        for (OsmPrimitive osm : selection)
     62            if (osm instanceof Way)
     63                selectedWays.add((Way)osm);
     64
     65        if (selectedWays.size() < 2) {
     66            JOptionPane.showMessageDialog(Main.parent, tr("Please select at least two ways to combine."));
     67            return;
     68        }
     69
     70        // Check whether all ways have identical relationship membership. More
     71        // specifically: If one of the selected ways is a member of relation X
     72        // in role Y, then all selected ways must be members of X in role Y.
     73
     74        // FIXME: In a later revision, we should display some sort of conflict
     75        // dialog like we do for tags, to let the user choose which relations
     76        // should be kept.
     77
     78        // Step 1, iterate over all relations and figure out which of our
     79        // selected ways are members of a relation.
     80        HashMap<Pair<Relation,String>, HashSet<Way>> backlinks =
     81            new HashMap<Pair<Relation,String>, HashSet<Way>>();
     82        HashSet<Relation> relationsUsingWays = new HashSet<Relation>();
     83        for (Relation r : Main.ds.relations) {
     84            if (r.deleted || r.incomplete) continue;
     85            for (RelationMember rm : r.members) {
     86                if (rm.member instanceof Way) {
     87                    for(Way w : selectedWays) {
     88                        if (rm.member == w) {
     89                            Pair<Relation,String> pair = new Pair<Relation,String>(r, rm.role);
     90                            HashSet<Way> waylinks = new HashSet<Way>();
     91                            if (backlinks.containsKey(pair)) {
     92                                waylinks = backlinks.get(pair);
     93                            } else {
     94                                waylinks = new HashSet<Way>();
     95                                backlinks.put(pair, waylinks);
     96                            }
     97                            waylinks.add(w);
     98
     99                            // this is just a cache for later use
     100                            relationsUsingWays.add(r);
     101                        }
     102                    }
     103                }
     104            }
     105        }
     106
     107        // Complain to the user if the ways don't have equal memberships.
     108        for (HashSet<Way> waylinks : backlinks.values()) {
     109            if (!waylinks.containsAll(selectedWays)) {
     110                int option = JOptionPane.showConfirmDialog(Main.parent,
     111                    tr("The selected ways have differing relation memberships.  "
     112                        + "Do you still want to combine them?"),
     113                    tr("Combine ways with different memberships?"),
     114                    JOptionPane.YES_NO_OPTION);
     115                if (option == JOptionPane.YES_OPTION)
     116                    break;
     117                return;
     118            }
     119        }
     120
     121        // collect properties for later conflict resolving
     122        Map<String, Set<String>> props = new TreeMap<String, Set<String>>();
     123        for (Way w : selectedWays) {
     124            for (Entry<String,String> e : w.entrySet()) {
     125                if (!props.containsKey(e.getKey()))
     126                    props.put(e.getKey(), new TreeSet<String>());
     127                props.get(e.getKey()).add(e.getValue());
     128            }
     129        }
     130
     131        List<Node> nodeList = null;
     132        Object firstTry = actuallyCombineWays(selectedWays, false);
     133        if (firstTry instanceof List) {
     134            nodeList = (List<Node>) firstTry;
     135        } else {
     136            Object secondTry = actuallyCombineWays(selectedWays, true);
     137            if (secondTry instanceof List) {
     138                int option = JOptionPane.showConfirmDialog(Main.parent,
     139                    tr("The ways can not be combined in their current directions.  "
     140                    + "Do you want to reverse some of them?"), tr("Change directions?"),
     141                    JOptionPane.YES_NO_OPTION);
     142                if (option != JOptionPane.YES_OPTION) {
     143                    return;
     144                }
     145                nodeList = (List<Node>) secondTry;
     146            } else {
     147                JOptionPane.showMessageDialog(Main.parent, secondTry);
     148                return;
     149            }
     150        }
     151
     152        // Find the most appropriate way to modify.
     153
     154        // Eventually this might want to be the way with the longest
     155        // history or the longest selected way but for now just attempt
     156        // to reuse an existing id.
     157        Way modifyWay = selectedWays.peek();
     158        for (Way w : selectedWays) {
     159            modifyWay = w;
     160            if (w.id != 0) break;
     161        }
     162        Way newWay = new Way(modifyWay);
     163
     164        newWay.nodes.clear();
     165        newWay.nodes.addAll(nodeList);
     166
     167        // display conflict dialog
     168        Map<String, JComboBox> components = new HashMap<String, JComboBox>();
     169        JPanel p = new JPanel(new GridBagLayout());
     170        for (Entry<String, Set<String>> e : props.entrySet()) {
     171            if (TigerUtils.isTigerTag(e.getKey())) {
     172                String combined = TigerUtils.combineTags(e.getKey(), e.getValue());
     173                newWay.put(e.getKey(), combined);
     174            } else if (e.getValue().size() > 1) {
     175                if("created_by".equals(e.getKey()))
     176                {
     177                    newWay.put("created_by", "JOSM");
     178                }
     179                else
     180                {
     181                    JComboBox c = new JComboBox(e.getValue().toArray());
     182                    c.setEditable(true);
     183                    p.add(new JLabel(e.getKey()), GBC.std());
     184                    p.add(Box.createHorizontalStrut(10), GBC.std());
     185                    p.add(c, GBC.eol());
     186                    components.put(e.getKey(), c);
     187                }
     188            } else
     189                newWay.put(e.getKey(), e.getValue().iterator().next());
     190        }
     191
     192        if (!components.isEmpty()) {
     193            int answer = JOptionPane.showConfirmDialog(Main.parent, p, tr("Enter values for all conflicts."), JOptionPane.OK_CANCEL_OPTION);
     194            if (answer != JOptionPane.OK_OPTION)
     195                return;
     196            for (Entry<String, JComboBox> e : components.entrySet())
     197                newWay.put(e.getKey(), e.getValue().getEditor().getItem().toString());
     198        }
     199
     200        LinkedList<Command> cmds = new LinkedList<Command>();
     201        LinkedList<Way> deletedWays = new LinkedList<Way>(selectedWays);
     202        deletedWays.remove(modifyWay);
     203        cmds.add(new DeleteCommand(deletedWays));
     204        cmds.add(new ChangeCommand(modifyWay, newWay));
     205
     206        // modify all relations containing the now-deleted ways
     207        for (Relation r : relationsUsingWays) {
     208            Relation newRel = new Relation(r);
     209            newRel.members.clear();
     210            HashSet<String> rolesToReAdd = new HashSet<String>();
     211            for (RelationMember rm : r.members) {
     212                // Don't copy the member if it to one of our ways, just keep a
     213                // note to re-add it later on.
     214                if (selectedWays.contains(rm.member)) {
     215                    rolesToReAdd.add(rm.role);
     216                } else {
     217                    newRel.members.add(rm);
     218                }
     219            }
     220            for (String role : rolesToReAdd) {
     221                newRel.members.add(new RelationMember(role, modifyWay));
     222            }
     223            cmds.add(new ChangeCommand(r, newRel));
     224        }
     225        Main.main.undoRedo.add(new SequenceCommand(tr("Combine {0} ways", selectedWays.size()), cmds));
     226        Main.ds.setSelected(modifyWay);
     227    }
     228
     229    /**
     230    * @return a message if combining failed, else a list of nodes.
     231    */
     232    private Object actuallyCombineWays(List<Way> ways, boolean ignoreDirection) {
     233        // Battle plan:
     234        //  1. Split the ways into small chunks of 2 nodes and weed out
     235        //     duplicates.
     236        //  2. Take a chunk and see if others could be appended or prepended,
     237        //     if so, do it and remove it from the list of remaining chunks.
     238        //     Rather, rinse, repeat.
     239        //  3. If this algorithm does not produce a single way,
     240        //     complain to the user.
     241        //  4. Profit!
     242
     243        HashSet<Pair<Node,Node>> chunkSet = new HashSet<Pair<Node,Node>>();
     244        for (Way w : ways)
     245            chunkSet.addAll(w.getNodePairs(ignoreDirection));
     246
     247        LinkedList<Pair<Node,Node>> chunks = new LinkedList<Pair<Node,Node>>(chunkSet);
     248
     249        if (chunks.isEmpty()) {
     250            return tr("All the ways were empty");
     251        }
     252
     253        List<Node> nodeList = Pair.toArrayList(chunks.poll());
     254        while (!chunks.isEmpty()) {
     255            ListIterator<Pair<Node,Node>> it = chunks.listIterator();
     256            boolean foundChunk = false;
     257            while (it.hasNext()) {
     258                Pair<Node,Node> curChunk = it.next();
     259                if (curChunk.a == nodeList.get(nodeList.size() - 1)) { // append
     260                    nodeList.add(curChunk.b);
     261                } else if (curChunk.b == nodeList.get(0)) { // prepend
     262                    nodeList.add(0, curChunk.a);
     263                } else if (ignoreDirection && curChunk.b == nodeList.get(nodeList.size() - 1)) { // append
     264                    nodeList.add(curChunk.a);
     265                } else if (ignoreDirection && curChunk.a == nodeList.get(0)) { // prepend
     266                    nodeList.add(0, curChunk.b);
     267                } else {
     268                    continue;
     269                }
     270
     271                foundChunk = true;
     272                it.remove();
     273                break;
     274            }
     275            if (!foundChunk) break;
     276        }
     277
     278        if (!chunks.isEmpty()) {
     279            return tr("Could not combine ways "
     280                + "(They could not be merged into a single string of nodes)");
     281        }
     282
     283        return nodeList;
     284    }
     285
     286    /**
     287    * Enable the "Combine way" menu option if more then one way is selected
     288    */
     289    public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
     290        boolean first = false;
     291        for (OsmPrimitive osm : newSelection) {
     292            if (osm instanceof Way) {
     293                if (first) {
     294                    setEnabled(true);
     295                    return;
     296                }
     297                first = true;
     298            }
     299        }
     300        setEnabled(false);
     301    }
    302302}
  • trunk/src/org/openstreetmap/josm/actions/CopyAction.java

    r1084 r1169  
    2828public final class CopyAction extends JosmAction implements SelectionChangedListener {
    2929
    30         private LinkedList<JosmAction> listeners;
     30    private LinkedList<JosmAction> listeners;
    3131
    32         public CopyAction() {
    33                 super(tr("Copy"), "copy",
    34                                 tr("Copy selected objects to paste buffer."),
    35                                 Shortcut.registerShortcut("system:copy", tr("Edit: {0}", tr("Copy")), KeyEvent.VK_C, Shortcut.GROUP_MENU), true);
    36                 setEnabled(false);
    37                 DataSet.selListeners.add(this);
    38                 listeners = new LinkedList<JosmAction>();
    39         }
     32    public CopyAction() {
     33        super(tr("Copy"), "copy",
     34                tr("Copy selected objects to paste buffer."),
     35                Shortcut.registerShortcut("system:copy", tr("Edit: {0}", tr("Copy")), KeyEvent.VK_C, Shortcut.GROUP_MENU), true);
     36        setEnabled(false);
     37        DataSet.selListeners.add(this);
     38        listeners = new LinkedList<JosmAction>();
     39    }
    4040
    41         @Override public void addListener(JosmAction a) {
    42                 listeners.add(a);
    43         }
     41    @Override public void addListener(JosmAction a) {
     42        listeners.add(a);
     43    }
    4444
    45         public void actionPerformed(ActionEvent e) {
    46                 Collection<OsmPrimitive> sel = Main.ds.getSelected();
    47                 if (sel.isEmpty()) {
    48                         JOptionPane.showMessageDialog(Main.parent,
    49                                         tr("Please select something to copy."));
    50                         return;
    51                 }
     45    public void actionPerformed(ActionEvent e) {
     46        Collection<OsmPrimitive> sel = Main.ds.getSelected();
     47        if (sel.isEmpty()) {
     48            JOptionPane.showMessageDialog(Main.parent,
     49                    tr("Please select something to copy."));
     50            return;
     51        }
    5252
    53                 /* New pasteBuffer - will be assigned to the global one at the end */
    54                 final DataSet pasteBuffer = new DataSet();
    55                 final HashMap<OsmPrimitive,OsmPrimitive> map = new HashMap<OsmPrimitive,OsmPrimitive>();
    56                 /* temporarily maps old nodes to new so we can do a true deep copy */
     53        /* New pasteBuffer - will be assigned to the global one at the end */
     54        final DataSet pasteBuffer = new DataSet();
     55        final HashMap<OsmPrimitive,OsmPrimitive> map = new HashMap<OsmPrimitive,OsmPrimitive>();
     56        /* temporarily maps old nodes to new so we can do a true deep copy */
    5757
    58                 /* scan the selected objects, mapping them to copies; when copying a way or relation,
    59                 * the copy references the copies of their child objects */
    60                 new Visitor(){
    61                         public void visit(Node n) {
    62                                 /* check if already in pasteBuffer - e.g. two ways are selected which share a node;
    63                                 * or a way and a node in that way is selected, we'll see it twice, once via the
    64                                 * way and once directly; and so on. */
    65                                 if (map.containsKey(n)) { return; }
    66                                 Node nnew = new Node(n);
    67                                 map.put(n, nnew);
    68                                 pasteBuffer.addPrimitive(nnew);
    69                         }
    70                         public void visit(Way w) {
    71                                 /* check if already in pasteBuffer - could have come from a relation, and directly etc. */
    72                                 if (map.containsKey(w)) { return; }
    73                                 Way wnew = new Way();
    74                                 wnew.cloneFrom(w);
    75                                 wnew.nodes.clear();
    76                                 List<Node> nodes = new ArrayList<Node>();
    77                                 for (Node n : w.nodes) {
    78                                         if (! map.containsKey(n)) {
    79                                                 n.visit(this);
    80                                         }
    81                                         nodes.add((Node)map.get(n));
    82                                 }
    83                                 wnew.nodes.clear();
    84                                 wnew.nodes.addAll(nodes);
    85                                 pasteBuffer.addPrimitive(wnew);
    86                         }
    87                         public void visit(Relation e) {
    88                                 if (map.containsKey(e)) { return; }
    89                                 Relation enew = new Relation(e);
    90                                 List<RelationMember> members = new ArrayList<RelationMember>();
    91                                 for (RelationMember m : e.members) {
    92                                         if (! map.containsKey(m.member)) {
    93                                                 m.member.visit(this);
    94                                         }
    95                                         RelationMember mnew = new RelationMember(m);
    96                                         mnew.member = map.get(m.member);
    97                                         members.add(mnew);
    98                                 }
    99                                 enew.members.addAll(members);
    100                                 pasteBuffer.addPrimitive(enew);
    101                         }
    102                         public void visitAll() {
    103                                 for (OsmPrimitive osm : Main.ds.getSelected())
    104                                         osm.visit(this);
    105                         }
    106                 }.visitAll();
     58        /* scan the selected objects, mapping them to copies; when copying a way or relation,
     59        * the copy references the copies of their child objects */
     60        new Visitor(){
     61            public void visit(Node n) {
     62                /* check if already in pasteBuffer - e.g. two ways are selected which share a node;
     63                * or a way and a node in that way is selected, we'll see it twice, once via the
     64                * way and once directly; and so on. */
     65                if (map.containsKey(n)) { return; }
     66                Node nnew = new Node(n);
     67                map.put(n, nnew);
     68                pasteBuffer.addPrimitive(nnew);
     69            }
     70            public void visit(Way w) {
     71                /* check if already in pasteBuffer - could have come from a relation, and directly etc. */
     72                if (map.containsKey(w)) { return; }
     73                Way wnew = new Way();
     74                wnew.cloneFrom(w);
     75                wnew.nodes.clear();
     76                List<Node> nodes = new ArrayList<Node>();
     77                for (Node n : w.nodes) {
     78                    if (! map.containsKey(n)) {
     79                        n.visit(this);
     80                    }
     81                    nodes.add((Node)map.get(n));
     82                }
     83                wnew.nodes.clear();
     84                wnew.nodes.addAll(nodes);
     85                pasteBuffer.addPrimitive(wnew);
     86            }
     87            public void visit(Relation e) {
     88                if (map.containsKey(e)) { return; }
     89                Relation enew = new Relation(e);
     90                List<RelationMember> members = new ArrayList<RelationMember>();
     91                for (RelationMember m : e.members) {
     92                    if (! map.containsKey(m.member)) {
     93                        m.member.visit(this);
     94                    }
     95                    RelationMember mnew = new RelationMember(m);
     96                    mnew.member = map.get(m.member);
     97                    members.add(mnew);
     98                }
     99                enew.members.addAll(members);
     100                pasteBuffer.addPrimitive(enew);
     101            }
     102            public void visitAll() {
     103                for (OsmPrimitive osm : Main.ds.getSelected())
     104                    osm.visit(this);
     105            }
     106        }.visitAll();
    107107
    108                 Main.pasteBuffer = pasteBuffer;
    109                 Main.main.menu.paste.setEnabled(true); /* now we have a paste buffer we can make paste available */
     108        Main.pasteBuffer = pasteBuffer;
     109        Main.main.menu.paste.setEnabled(true); /* now we have a paste buffer we can make paste available */
    110110
    111                 for(JosmAction a : listeners) {
    112                         a.pasteBufferChanged(Main.pasteBuffer);
    113                 }
    114         }
     111        for(JosmAction a : listeners) {
     112            a.pasteBufferChanged(Main.pasteBuffer);
     113        }
     114    }
    115115
    116         public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
    117                 setEnabled(! newSelection.isEmpty());
    118         }
     116    public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
     117        setEnabled(! newSelection.isEmpty());
     118    }
    119119}
  • trunk/src/org/openstreetmap/josm/actions/CreateCircleAction.java

    r1084 r1169  
    3434public final class CreateCircleAction extends JosmAction {
    3535
    36         public CreateCircleAction() {
    37                 super(tr("Create Circle"), "createcircle", tr("Create a circle from three selected nodes."),
    38                 Shortcut.registerShortcut("tools:createcircle", tr("Tool: {0}", tr("Create Circle")), KeyEvent.VK_O, Shortcut.GROUP_EDIT, Shortcut.SHIFT_DEFAULT), true);
    39         }
     36    public CreateCircleAction() {
     37        super(tr("Create Circle"), "createcircle", tr("Create a circle from three selected nodes."),
     38        Shortcut.registerShortcut("tools:createcircle", tr("Tool: {0}", tr("Create Circle")), KeyEvent.VK_O, Shortcut.GROUP_EDIT, Shortcut.SHIFT_DEFAULT), true);
     39    }
    4040
    41         private double calcang(double xc, double yc, double x, double y) {
    42                 // calculate the angle from xc|yc to x|y
    43                 if (xc == x && yc == y) {
    44                         return 0; // actually invalid, but we won't have this case in this context
    45                 }
    46                 double yd = Math.abs(y - yc);
    47                 if (yd == 0 && xc < x) {
    48                         return 0;
    49                 }
    50                 if (yd == 0 && xc > x) {
    51                         return Math.PI;
    52                 }
    53                 double xd = Math.abs(x - xc);
    54                 double a = Math.atan2(xd, yd);
    55                 if (y > yc) {
    56                         a = Math.PI - a;
    57                 }
    58                 if (x < xc) {
    59                         a = -a;
    60                 }
    61                 a = 1.5*Math.PI + a;
    62                 if (a < 0) {
    63                         a += 2*Math.PI;
    64                 }
    65                 if (a >= 2*Math.PI) {
    66                         a -= 2*Math.PI;
    67                 }
    68                 return a;
    69         }
     41    private double calcang(double xc, double yc, double x, double y) {
     42        // calculate the angle from xc|yc to x|y
     43        if (xc == x && yc == y) {
     44            return 0; // actually invalid, but we won't have this case in this context
     45        }
     46        double yd = Math.abs(y - yc);
     47        if (yd == 0 && xc < x) {
     48            return 0;
     49        }
     50        if (yd == 0 && xc > x) {
     51            return Math.PI;
     52        }
     53        double xd = Math.abs(x - xc);
     54        double a = Math.atan2(xd, yd);
     55        if (y > yc) {
     56            a = Math.PI - a;
     57        }
     58        if (x < xc) {
     59            a = -a;
     60        }
     61        a = 1.5*Math.PI + a;
     62        if (a < 0) {
     63            a += 2*Math.PI;
     64        }
     65        if (a >= 2*Math.PI) {
     66            a -= 2*Math.PI;
     67        }
     68        return a;
     69    }
    7070
    71         public void actionPerformed(ActionEvent e) {
    72                 int numberOfNodesInCircle = Integer.parseInt(Main.pref.get("createcircle.nodecount", "8"));
    73                 if (numberOfNodesInCircle < 1) {
    74                         numberOfNodesInCircle = 1;
    75                 } else if (numberOfNodesInCircle > 100) {
    76                         numberOfNodesInCircle = 100;
    77                 }
     71    public void actionPerformed(ActionEvent e) {
     72        int numberOfNodesInCircle = Integer.parseInt(Main.pref.get("createcircle.nodecount", "8"));
     73        if (numberOfNodesInCircle < 1) {
     74            numberOfNodesInCircle = 1;
     75        } else if (numberOfNodesInCircle > 100) {
     76            numberOfNodesInCircle = 100;
     77        }
    7878
    79                 Collection<OsmPrimitive> sel = Main.ds.getSelected();
    80                 Collection<Node> nodes = new LinkedList<Node>();
    81                 Way existingWay = null;
     79        Collection<OsmPrimitive> sel = Main.ds.getSelected();
     80        Collection<Node> nodes = new LinkedList<Node>();
     81        Way existingWay = null;
    8282
    83                 for (OsmPrimitive osm : sel)
    84                         if (osm instanceof Node)
    85                                 nodes.add((Node)osm);
     83        for (OsmPrimitive osm : sel)
     84            if (osm instanceof Node)
     85                nodes.add((Node)osm);
    8686
    87                 // special case if no single nodes are selected and exactly one way is:
    88                 // then use the way's nodes
    89                 if ((nodes.size() == 0) && (sel.size() == 1))
    90                         for (OsmPrimitive osm : sel)
    91                                 if (osm instanceof Way) {
    92                                         existingWay = ((Way)osm);
    93                                         for (Node n : ((Way)osm).nodes)
    94                                         {
    95                                                 if(!nodes.contains(n))
    96                                                         nodes.add(n);
    97                                         }
    98                                 }
     87        // special case if no single nodes are selected and exactly one way is:
     88        // then use the way's nodes
     89        if ((nodes.size() == 0) && (sel.size() == 1))
     90            for (OsmPrimitive osm : sel)
     91                if (osm instanceof Way) {
     92                    existingWay = ((Way)osm);
     93                    for (Node n : ((Way)osm).nodes)
     94                    {
     95                        if(!nodes.contains(n))
     96                            nodes.add(n);
     97                    }
     98                }
    9999
    100                 if (nodes.size() != 3) {
    101                         JOptionPane.showMessageDialog(Main.parent, tr("Please select exactly three nodes or one way with exactly three nodes."));
    102                         return;
    103                 }
     100        if (nodes.size() != 3) {
     101            JOptionPane.showMessageDialog(Main.parent, tr("Please select exactly three nodes or one way with exactly three nodes."));
     102            return;
     103        }
    104104
    105                 // let's get some shorter names
    106                 Node   n1 = ((Node)nodes.toArray()[0]);
    107                 double x1 = n1.eastNorth.east();
    108                 double y1 = n1.eastNorth.north();
    109                 Node   n2 = ((Node)nodes.toArray()[1]);
    110                 double x2 = n2.eastNorth.east();
    111                 double y2 = n2.eastNorth.north();
    112                 Node   n3 = ((Node)nodes.toArray()[2]);
    113                 double x3 = n3.eastNorth.east();
    114                 double y3 = n3.eastNorth.north();
     105        // let's get some shorter names
     106        Node   n1 = ((Node)nodes.toArray()[0]);
     107        double x1 = n1.eastNorth.east();
     108        double y1 = n1.eastNorth.north();
     109        Node   n2 = ((Node)nodes.toArray()[1]);
     110        double x2 = n2.eastNorth.east();
     111        double y2 = n2.eastNorth.north();
     112        Node   n3 = ((Node)nodes.toArray()[2]);
     113        double x3 = n3.eastNorth.east();
     114        double y3 = n3.eastNorth.north();
    115115
    116                 // calculate the center (xc/yc)
    117                 double s = 0.5*((x2 - x3)*(x1 - x3) - (y2 - y3)*(y3 - y1));
    118                 double sUnder = (x1 - x2)*(y3 - y1) - (y2 - y1)*(x1 - x3);
     116        // calculate the center (xc/yc)
     117        double s = 0.5*((x2 - x3)*(x1 - x3) - (y2 - y3)*(y3 - y1));
     118        double sUnder = (x1 - x2)*(y3 - y1) - (y2 - y1)*(x1 - x3);
    119119
    120                 if (sUnder == 0) {
    121                         JOptionPane.showMessageDialog(Main.parent, tr("Those nodes are not in a circle."));
    122                         return;
    123                 }
     120        if (sUnder == 0) {
     121            JOptionPane.showMessageDialog(Main.parent, tr("Those nodes are not in a circle."));
     122            return;
     123        }
    124124
    125                 s /= sUnder;
     125        s /= sUnder;
    126126
    127                 double xc = 0.5*(x1 + x2) + s*(y2 - y1);
    128                 double yc = 0.5*(y1 + y2) + s*(x1 - x2);
     127        double xc = 0.5*(x1 + x2) + s*(y2 - y1);
     128        double yc = 0.5*(y1 + y2) + s*(x1 - x2);
    129129
    130                 // calculate the radius (r)
    131                 double r = Math.sqrt(Math.pow(xc-x1,2) + Math.pow(yc-y1,2));
     130        // calculate the radius (r)
     131        double r = Math.sqrt(Math.pow(xc-x1,2) + Math.pow(yc-y1,2));
    132132
    133                 // find where to put the existing nodes
    134                 double a1 = calcang(xc, yc, x1, y1);
    135                 double a2 = calcang(xc, yc, x2, y2);
    136                 double a3 = calcang(xc, yc, x3, y3);
    137                 if (a1 < a2) { double at = a1; Node nt = n1; a1 = a2; n1 = n2; a2 = at; n2 = nt; }
    138                 if (a2 < a3) { double at = a2; Node nt = n2; a2 = a3; n2 = n3; a3 = at; n3 = nt; }
    139                 if (a1 < a2) { double at = a1; Node nt = n1; a1 = a2; n1 = n2; a2 = at; n2 = nt; }
     133        // find where to put the existing nodes
     134        double a1 = calcang(xc, yc, x1, y1);
     135        double a2 = calcang(xc, yc, x2, y2);
     136        double a3 = calcang(xc, yc, x3, y3);
     137        if (a1 < a2) { double at = a1; Node nt = n1; a1 = a2; n1 = n2; a2 = at; n2 = nt; }
     138        if (a2 < a3) { double at = a2; Node nt = n2; a2 = a3; n2 = n3; a3 = at; n3 = nt; }
     139        if (a1 < a2) { double at = a1; Node nt = n1; a1 = a2; n1 = n2; a2 = at; n2 = nt; }
    140140
    141                 // now we can start doing thigs to OSM data
    142                 Collection<Command> cmds = new LinkedList<Command>();
     141        // now we can start doing thigs to OSM data
     142        Collection<Command> cmds = new LinkedList<Command>();
    143143
    144                 // build a way for the circle
    145                 Way wayToAdd;
    146                 if (existingWay == null) {
    147                         wayToAdd = new Way();
    148                 } else {
    149                         // re-use existing way if it was selected
    150                         wayToAdd = new Way(existingWay);
    151                         wayToAdd.nodes.clear();
    152                 }
    153                 for (int i = 1; i <= numberOfNodesInCircle; i++) {
    154                         double a = 2*Math.PI*(1.0 - i/(double)numberOfNodesInCircle); // "1-" to get it clock-wise
    155                         // insert existing nodes if they fit before this new node (999 means "already added this node")
    156                         if (a1 < 999 && a1 > a) {
    157                                 wayToAdd.nodes.add(n1);
    158                                 a1 = 999;
    159                         }
    160                         if (a2 < 999 && a2 > a) {
    161                                 wayToAdd.nodes.add(n2);
    162                                 a2 = 999;
    163                         }
    164                         if (a3 < 999 && a3 > a) {
    165                                 wayToAdd.nodes.add(n3);
    166                                 a3 = 999;
    167                         }
    168                         // get the position of the new node and insert it
    169                         double x = xc + r*Math.cos(a);
    170                         double y = yc + r*Math.sin(a);
    171                         Node n = new Node(Main.proj.eastNorth2latlon(new EastNorth(x,y)));
    172                         wayToAdd.nodes.add(n);
    173                         cmds.add(new AddCommand(n));
    174                 }
    175                 wayToAdd.nodes.add(wayToAdd.nodes.get(0)); // close the circle
    176                 if (existingWay == null) {
    177                         cmds.add(new AddCommand(wayToAdd));
    178                 } else {
    179                         cmds.add(new ChangeCommand(existingWay, wayToAdd));
    180                 }
     144        // build a way for the circle
     145        Way wayToAdd;
     146        if (existingWay == null) {
     147            wayToAdd = new Way();
     148        } else {
     149            // re-use existing way if it was selected
     150            wayToAdd = new Way(existingWay);
     151            wayToAdd.nodes.clear();
     152        }
     153        for (int i = 1; i <= numberOfNodesInCircle; i++) {
     154            double a = 2*Math.PI*(1.0 - i/(double)numberOfNodesInCircle); // "1-" to get it clock-wise
     155            // insert existing nodes if they fit before this new node (999 means "already added this node")
     156            if (a1 < 999 && a1 > a) {
     157                wayToAdd.nodes.add(n1);
     158                a1 = 999;
     159            }
     160            if (a2 < 999 && a2 > a) {
     161                wayToAdd.nodes.add(n2);
     162                a2 = 999;
     163            }
     164            if (a3 < 999 && a3 > a) {
     165                wayToAdd.nodes.add(n3);
     166                a3 = 999;
     167            }
     168            // get the position of the new node and insert it
     169            double x = xc + r*Math.cos(a);
     170            double y = yc + r*Math.sin(a);
     171            Node n = new Node(Main.proj.eastNorth2latlon(new EastNorth(x,y)));
     172            wayToAdd.nodes.add(n);
     173            cmds.add(new AddCommand(n));
     174        }
     175        wayToAdd.nodes.add(wayToAdd.nodes.get(0)); // close the circle
     176        if (existingWay == null) {
     177            cmds.add(new AddCommand(wayToAdd));
     178        } else {
     179            cmds.add(new ChangeCommand(existingWay, wayToAdd));
     180        }
    181181
    182                 Main.main.undoRedo.add(new SequenceCommand(tr("Create Circle"), cmds));
    183                 Main.map.repaint();
    184         }
     182        Main.main.undoRedo.add(new SequenceCommand(tr("Create Circle"), cmds));
     183        Main.map.repaint();
     184    }
    185185}
  • trunk/src/org/openstreetmap/josm/actions/DeleteAction.java

    r1087 r1169  
    1717public final class DeleteAction extends JosmAction implements SelectionChangedListener {
    1818
    19         public DeleteAction() {
    20                 super(tr("Delete"), "dialogs/delete", tr("Delete selected objects."),
    21                 Shortcut.registerShortcut("system:delete", tr("Edit: {0}", tr("Delete")), KeyEvent.VK_DELETE, Shortcut.GROUP_DIRECT), true);
     19    public DeleteAction() {
     20        super(tr("Delete"), "dialogs/delete", tr("Delete selected objects."),
     21        Shortcut.registerShortcut("system:delete", tr("Edit: {0}", tr("Delete")), KeyEvent.VK_DELETE, Shortcut.GROUP_DIRECT), true);
    2222        DataSet.selListeners.add(this);
    23                 setEnabled(false);
    24         }
     23        setEnabled(false);
     24    }
    2525
    26         public void actionPerformed(ActionEvent e) {
    27                 new org.openstreetmap.josm.actions.mapmode.DeleteAction(Main.map)
    28                         .doActionPerformed(e);
    29         }
     26    public void actionPerformed(ActionEvent e) {
     27        new org.openstreetmap.josm.actions.mapmode.DeleteAction(Main.map)
     28                .doActionPerformed(e);
     29    }
    3030    public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
    3131        setEnabled(! newSelection.isEmpty());
  • trunk/src/org/openstreetmap/josm/actions/DiskAccessAction.java

    r1084 r1169  
    1717abstract public class DiskAccessAction extends JosmAction {
    1818
    19         public DiskAccessAction(String name, String iconName, String tooltip, Shortcut shortcut) {
    20                 super(name, iconName, tooltip, shortcut, true);
    21         }
     19    public DiskAccessAction(String name, String iconName, String tooltip, Shortcut shortcut) {
     20        super(name, iconName, tooltip, shortcut, true);
     21    }
    2222
    23         @Deprecated
    24         public DiskAccessAction(String name, String iconName, String tooltip, int shortcut, int modifiers) {
    25                 super(name, iconName, tooltip, shortcut, modifiers, true);
    26         }
     23    @Deprecated
     24    public DiskAccessAction(String name, String iconName, String tooltip, int shortcut, int modifiers) {
     25        super(name, iconName, tooltip, shortcut, modifiers, true);
     26    }
    2727
    28         protected static JFileChooser createAndOpenFileChooser(boolean open, boolean multiple, String title) {
    29                 String curDir = Main.pref.get("lastDirectory");
    30                 if (curDir.equals(""))
    31                         curDir = ".";
    32                 JFileChooser fc = new JFileChooser(new File(curDir));
    33                 if(title != null)
    34                         fc.setDialogTitle(title);
     28    protected static JFileChooser createAndOpenFileChooser(boolean open, boolean multiple, String title) {
     29        String curDir = Main.pref.get("lastDirectory");
     30        if (curDir.equals(""))
     31            curDir = ".";
     32        JFileChooser fc = new JFileChooser(new File(curDir));
     33        if(title != null)
     34            fc.setDialogTitle(title);
    3535
    36                 fc.setMultiSelectionEnabled(multiple);
    37                 for (int i = 0; i < ExtensionFileFilter.filters.length; ++i)
    38                         fc.addChoosableFileFilter(ExtensionFileFilter.filters[i]);
    39                 fc.setAcceptAllFileFilterUsed(true);
     36        fc.setMultiSelectionEnabled(multiple);
     37        for (int i = 0; i < ExtensionFileFilter.filters.length; ++i)
     38            fc.addChoosableFileFilter(ExtensionFileFilter.filters[i]);
     39        fc.setAcceptAllFileFilterUsed(true);
    4040
    41                 int answer = open ? fc.showOpenDialog(Main.parent) : fc.showSaveDialog(Main.parent);
    42                 if (answer != JFileChooser.APPROVE_OPTION)
    43                         return null;
     41        int answer = open ? fc.showOpenDialog(Main.parent) : fc.showSaveDialog(Main.parent);
     42        if (answer != JFileChooser.APPROVE_OPTION)
     43            return null;
    4444
    45                 if (!fc.getCurrentDirectory().getAbsolutePath().equals(curDir))
    46                         Main.pref.put("lastDirectory", fc.getCurrentDirectory().getAbsolutePath());
     45        if (!fc.getCurrentDirectory().getAbsolutePath().equals(curDir))
     46            Main.pref.put("lastDirectory", fc.getCurrentDirectory().getAbsolutePath());
    4747
    48                 if (!open) {
    49                         File file = fc.getSelectedFile();
    50                         if (file == null || (file.exists() && JOptionPane.YES_OPTION !=
    51                                         JOptionPane.showConfirmDialog(Main.parent, tr("File exists. Overwrite?"), tr("Overwrite"), JOptionPane.YES_NO_OPTION)))
    52                                 return null;
    53                 }
     48        if (!open) {
     49            File file = fc.getSelectedFile();
     50            if (file == null || (file.exists() && JOptionPane.YES_OPTION !=
     51                    JOptionPane.showConfirmDialog(Main.parent, tr("File exists. Overwrite?"), tr("Overwrite"), JOptionPane.YES_NO_OPTION)))
     52                return null;
     53        }
    5454
    55                 return fc;
    56         }
     55        return fc;
     56    }
    5757}
  • trunk/src/org/openstreetmap/josm/actions/DownloadAction.java

    r1084 r1169  
    2828public class DownloadAction extends JosmAction {
    2929
    30         public DownloadDialog dialog;
     30    public DownloadDialog dialog;
    3131
    32         public DownloadAction() {
    33                 super(tr("Download from OSM ..."), "download", tr("Download map data from the OSM server."),
    34                 Shortcut.registerShortcut("file:download", tr("File: {0}", tr("Download from OSM ...")), KeyEvent.VK_D, Shortcut.GROUPS_ALT1+Shortcut.GROUP_HOTKEY), true);
    35         }
     32    public DownloadAction() {
     33        super(tr("Download from OSM ..."), "download", tr("Download map data from the OSM server."),
     34        Shortcut.registerShortcut("file:download", tr("File: {0}", tr("Download from OSM ...")), KeyEvent.VK_D, Shortcut.GROUPS_ALT1+Shortcut.GROUP_HOTKEY), true);
     35    }
    3636
    37         public void actionPerformed(ActionEvent e) {
    38                 dialog = new DownloadDialog();
     37    public void actionPerformed(ActionEvent e) {
     38        dialog = new DownloadDialog();
    3939
    40                 JPanel downPanel = new JPanel(new GridBagLayout());
    41                 downPanel.add(dialog, GBC.eol().fill(GBC.BOTH));
     40        JPanel downPanel = new JPanel(new GridBagLayout());
     41        downPanel.add(dialog, GBC.eol().fill(GBC.BOTH));
    4242
    43                 JOptionPane pane = new JOptionPane(downPanel, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
    44                 JDialog dlg = pane.createDialog(Main.parent, tr("Download"));
    45                 dlg.setResizable(true);
    46                 dialog.setOptionPane(pane);
     43        JOptionPane pane = new JOptionPane(downPanel, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
     44        JDialog dlg = pane.createDialog(Main.parent, tr("Download"));
     45        dlg.setResizable(true);
     46        dialog.setOptionPane(pane);
    4747
    48                 if (dlg.getWidth() > 1000)
    49                         dlg.setSize(1000, dlg.getHeight());
    50                 if (dlg.getHeight() > 600)
    51                         dlg.setSize(dlg.getWidth(),600);
     48        if (dlg.getWidth() > 1000)
     49            dlg.setSize(1000, dlg.getHeight());
     50        if (dlg.getHeight() > 600)
     51            dlg.setSize(dlg.getWidth(),600);
    5252
    53                 boolean finish = false;
     53        boolean finish = false;
    5454        while (!finish) {
    5555            dlg.setVisible(true);
    5656            Main.pref.put("download.newlayer", dialog.newLayer.isSelected());
    57                 if (pane.getValue() instanceof Integer && (Integer)pane.getValue() == JOptionPane.OK_OPTION) {
    58                         Main.pref.put("download.tab", Integer.toString(dialog.getSelectedTab()));
    59                         for (DownloadTask task : dialog.downloadTasks) {
    60                                 Main.pref.put("download."+task.getPreferencesSuffix(), task.getCheckBox().isSelected());
    61                                 if (task.getCheckBox().isSelected()) {
    62                                         task.download(this, dialog.minlat, dialog.minlon, dialog.maxlat, dialog.maxlon);
    63                                         finish = true;
    64                                 }
    65                         }
    66                 } else
    67                         finish = true;
    68                 if (!finish)
    69                         JOptionPane.showMessageDialog(Main.parent, tr("Please select at least one task to download"));
     57            if (pane.getValue() instanceof Integer && (Integer)pane.getValue() == JOptionPane.OK_OPTION) {
     58                Main.pref.put("download.tab", Integer.toString(dialog.getSelectedTab()));
     59                for (DownloadTask task : dialog.downloadTasks) {
     60                    Main.pref.put("download."+task.getPreferencesSuffix(), task.getCheckBox().isSelected());
     61                    if (task.getCheckBox().isSelected()) {
     62                        task.download(this, dialog.minlat, dialog.minlon, dialog.maxlat, dialog.maxlon);
     63                        finish = true;
     64                    }
     65                }
     66            } else
     67                finish = true;
     68            if (!finish)
     69                JOptionPane.showMessageDialog(Main.parent, tr("Please select at least one task to download"));
    7070        }
    7171
    7272                dialog = null;
    73                 dlg.dispose();
    74         }
     73        dlg.dispose();
     74    }
    7575}
  • trunk/src/org/openstreetmap/josm/actions/DuplicateAction.java

    r1084 r1169  
    1818
    1919    public DuplicateAction() {
    20         super(tr("Duplicate"), "duplicate",
    21                         tr("Duplicate selection by copy and immediate paste."),
    22                         Shortcut.registerShortcut("system:duplicate", tr("Edit: {0}", tr("Duplicate")), KeyEvent.VK_D, Shortcut.GROUP_MENU), true);
    23         setEnabled(false);
    24                         DataSet.selListeners.add(this);
     20        super(tr("Duplicate"), "duplicate",
     21            tr("Duplicate selection by copy and immediate paste."),
     22            Shortcut.registerShortcut("system:duplicate", tr("Edit: {0}", tr("Duplicate")), KeyEvent.VK_D, Shortcut.GROUP_MENU), true);
     23        setEnabled(false);
     24            DataSet.selListeners.add(this);
    2525    }
    2626
    27         public void actionPerformed(ActionEvent e) {
    28                 Main.main.menu.copy.actionPerformed(e);
    29                 Main.main.menu.paste.actionPerformed(e);
     27    public void actionPerformed(ActionEvent e) {
     28        Main.main.menu.copy.actionPerformed(e);
     29        Main.main.menu.paste.actionPerformed(e);
    3030    }
    3131
    32         public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
    33                 setEnabled(! newSelection.isEmpty());
    34         }
     32    public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
     33        setEnabled(! newSelection.isEmpty());
     34    }
    3535}
  • trunk/src/org/openstreetmap/josm/actions/ExitAction.java

    r1084 r1169  
    1616 */
    1717public class ExitAction extends JosmAction {
    18         /**
    19         * Construct the action with "Exit" as label
    20         */
    21         public ExitAction() {
    22                 super(tr("Exit"), "exit", tr("Exit the application."),
    23                 Shortcut.registerShortcut("system:menuexit", tr("Exit"), KeyEvent.VK_Q, Shortcut.GROUP_MENU), true);
    24         }
     18    /**
     19    * Construct the action with "Exit" as label
     20    */
     21    public ExitAction() {
     22        super(tr("Exit"), "exit", tr("Exit the application."),
     23        Shortcut.registerShortcut("system:menuexit", tr("Exit"), KeyEvent.VK_Q, Shortcut.GROUP_MENU), true);
     24    }
    2525
    26         public void actionPerformed(ActionEvent e) {
    27                 if (!Main.breakBecauseUnsavedChanges())
    28                         System.exit(0);
    29         }
     26    public void actionPerformed(ActionEvent e) {
     27        if (!Main.breakBecauseUnsavedChanges())
     28            System.exit(0);
     29    }
    3030}
  • trunk/src/org/openstreetmap/josm/actions/ExtensionFileFilter.java

    r929 r1169  
    99
    1010/**
    11  * A file filter that filters after the extension. Also includes a list of file 
     11 * A file filter that filters after the extension. Also includes a list of file
    1212 * filters used in JOSM.
    13  * 
     13 *
    1414 * @author imi
    1515 */
    1616public class ExtensionFileFilter extends FileFilter {
    17         private final String extension;
    18         private final String description;
    19         public final String defaultExtension;
     17    private final String extension;
     18    private final String description;
     19    public final String defaultExtension;
    2020
    21         public static final int OSM = 0;
    22         public static final int GPX = 1;
    23         public static final int NMEA = 2;
    24        
    25         public static ExtensionFileFilter[] filters = {
    26                 new ExtensionFileFilter("osm,xml", "osm", tr("OSM Server Files (*.osm *.xml)")),
    27                 new ExtensionFileFilter("gpx,gpx.gz", "gpx", tr("GPX Files (*.gpx *.gpx.gz)")),
    28                 new ExtensionFileFilter("nmea,txt", "nmea", tr("NMEA-0183 Files (*.nmea *.txt)")),
    29         };
     21    public static final int OSM = 0;
     22    public static final int GPX = 1;
     23    public static final int NMEA = 2;
    3024
    31         /**
    32          * Construct an extension file filter by giving the extension to check after.
    33          *
    34          */
    35         public ExtensionFileFilter(String extension, String defExt, String description) {
    36                 this.extension = extension;
    37                 defaultExtension = defExt;
    38                 this.description = description;
    39         }
     25    public static ExtensionFileFilter[] filters = {
     26        new ExtensionFileFilter("osm,xml", "osm", tr("OSM Server Files (*.osm *.xml)")),
     27        new ExtensionFileFilter("gpx,gpx.gz", "gpx", tr("GPX Files (*.gpx *.gpx.gz)")),
     28        new ExtensionFileFilter("nmea,txt", "nmea", tr("NMEA-0183 Files (*.nmea *.txt)")),
     29    };
    4030
    41         public boolean acceptName(String filename) {
    42                 String name = filename.toLowerCase();
    43                 for (String ext : extension.split(","))
    44                         if (name.endsWith("."+ext))
    45                                 return true;
    46                 return false;
    47         }
     31    /**
     32     * Construct an extension file filter by giving the extension to check after.
     33     *
     34     */
     35    public ExtensionFileFilter(String extension, String defExt, String description) {
     36        this.extension = extension;
     37        defaultExtension = defExt;
     38        this.description = description;
     39    }
    4840
    49         @Override public boolean accept(File pathname) {
    50                 if (pathname.isDirectory())
    51                         return true;
    52                 return acceptName(pathname.getName());
    53         }
     41    public boolean acceptName(String filename) {
     42        String name = filename.toLowerCase();
     43        for (String ext : extension.split(","))
     44            if (name.endsWith("."+ext))
     45                return true;
     46        return false;
     47    }
    5448
    55         @Override public String getDescription() {
    56                 return description;
    57         }
     49    @Override public boolean accept(File pathname) {
     50        if (pathname.isDirectory())
     51            return true;
     52        return acceptName(pathname.getName());
     53    }
     54
     55    @Override public String getDescription() {
     56        return description;
     57    }
    5858}
  • trunk/src/org/openstreetmap/josm/actions/GpxExportAction.java

    r1084 r1169  
    4040public class GpxExportAction extends DiskAccessAction {
    4141
    42         private final static String warningGpl = "<html><font color='red' size='-2'>"+tr("Note: GPL is not compatible with the OSM license. Do not upload GPL licensed tracks.")+"</html>";
    43 
    44         private final Layer layer;
    45 
    46         public GpxExportAction(Layer layer) {
    47                 super(tr("Export to GPX ..."), "exportgpx", tr("Export the data to GPX file."),
    48                 Shortcut.registerShortcut("file:exportgpx", tr("Export to GPX ..."), KeyEvent.VK_E, Shortcut.GROUP_MENU));
    49                 this.layer = layer;
    50         }
    51 
    52         public void actionPerformed(ActionEvent e) {
    53                 if (layer == null && Main.map == null) {
    54                         JOptionPane.showMessageDialog(Main.parent, tr("Nothing to export. Get some data first."));
    55                         return;
    56                 }
    57 
    58                 JFileChooser fc = createAndOpenFileChooser(false, false, null);
    59                 if (fc == null)
    60                         return;
    61                 File file = fc.getSelectedFile();
    62                 if (file == null)
    63                         return;
    64 
    65                 exportGpx(file, this.layer == null ? Main.main.editLayer() : this.layer);
    66         }
    67 
    68         public static void exportGpx(File file, Layer layer) {
    69                 String fn = file.getPath();
    70                 if (fn.indexOf('.') == -1) {
    71                         fn += ".gpx";
    72                         file = new File(fn);
    73                 }
    74 
    75                 // open the dialog asking for options
    76                 JPanel p = new JPanel(new GridBagLayout());
    77 
    78                 p.add(new JLabel(tr("gps track description")), GBC.eol());
    79                 JTextArea desc = new JTextArea(3,40);
    80                 desc.setWrapStyleWord(true);
    81                 desc.setLineWrap(true);
    82                 p.add(new JScrollPane(desc), GBC.eop().fill(GBC.BOTH));
    83 
    84                 JCheckBox author = new JCheckBox(tr("Add author information"), Main.pref.getBoolean("lastAddAuthor", true));
    85                 author.setSelected(true);
    86                 p.add(author, GBC.eol());
    87                 JLabel nameLabel = new JLabel(tr("Real name"));
    88                 p.add(nameLabel, GBC.std().insets(10,0,5,0));
    89                 JTextField authorName = new JTextField(Main.pref.get("lastAuthorName"));
    90                 p.add(authorName, GBC.eol().fill(GBC.HORIZONTAL));
    91                 JLabel emailLabel = new JLabel(tr("Email"));
    92                 p.add(emailLabel, GBC.std().insets(10,0,5,0));
    93                 JTextField email = new JTextField(Main.pref.get("osm-server.username"));
    94                 p.add(email, GBC.eol().fill(GBC.HORIZONTAL));
    95                 JLabel copyrightLabel = new JLabel(tr("Copyright (URL)"));
    96                 p.add(copyrightLabel, GBC.std().insets(10,0,5,0));
    97                 JTextField copyright = new JTextField();
    98                 p.add(copyright, GBC.std().fill(GBC.HORIZONTAL));
    99                 JButton predefined = new JButton(tr("Predefined"));
    100                 p.add(predefined, GBC.eol().insets(5,0,0,0));
    101                 JLabel copyrightYearLabel = new JLabel(tr("Copyright year"));
    102                 p.add(copyrightYearLabel, GBC.std().insets(10,0,5,5));
    103                 JTextField copyrightYear = new JTextField("");
    104                 p.add(copyrightYear, GBC.eol().fill(GBC.HORIZONTAL));
    105                 JLabel warning = new JLabel("<html><font size='-2'>&nbsp;</html");
    106                 p.add(warning, GBC.eol().fill(GBC.HORIZONTAL).insets(15,0,0,0));
    107                 addDependencies(author, authorName, email, copyright, predefined, copyrightYear, nameLabel, emailLabel, copyrightLabel, copyrightYearLabel, warning);
    108 
    109                 p.add(new JLabel(tr("Keywords")), GBC.eol());
    110                 JTextField keywords = new JTextField();
    111                 p.add(keywords, GBC.eop().fill(GBC.HORIZONTAL));
    112 
    113                 int answer = JOptionPane.showConfirmDialog(Main.parent, p, tr("Export options"), JOptionPane.OK_CANCEL_OPTION);
    114                 if (answer != JOptionPane.OK_OPTION)
    115                         return;
    116 
    117                 Main.pref.put("lastAddAuthor", author.isSelected());
    118                 if (authorName.getText().length() != 0)
    119                         Main.pref.put("lastAuthorName", authorName.getText());
    120                 if (copyright.getText().length() != 0)
    121                         Main.pref.put("lastCopyright", copyright.getText());
    122 
    123                 GpxData gpxData;
    124                 if (layer instanceof OsmDataLayer)
    125                         gpxData = ((OsmDataLayer)layer).toGpxData();
    126                 else if (layer instanceof GpxLayer)
    127                         gpxData = ((GpxLayer)layer).data;
    128                 else
    129                         gpxData = OsmDataLayer.toGpxData(Main.ds);
    130                 // TODO: add copyright, etc.
    131                 try {
    132                         FileOutputStream fo = new FileOutputStream(file);
    133                         new GpxWriter(fo).write(gpxData);
    134                         fo.flush();
    135                         fo.close();
    136                 } catch (IOException x) {
    137                         x.printStackTrace();
    138                         JOptionPane.showMessageDialog(Main.parent, tr("Error while exporting {0}", fn)+":\n"+x.getMessage(), tr("Error"), JOptionPane.ERROR_MESSAGE);
    139                 }
    140         }
    141 
    142         /**
    143         * Add all those listeners to handle the enable state of the fields.
    144         * @param copyrightYearLabel
    145         * @param copyrightLabel
    146         * @param emailLabel
    147         * @param nameLabel
    148         * @param warning
    149         */
    150         private static void addDependencies(
    151                         final JCheckBox author,
    152                         final JTextField authorName,
    153                         final JTextField email,
    154                         final JTextField copyright,
    155                         final JButton predefined,
    156                         final JTextField copyrightYear,
    157                         final JLabel nameLabel,
    158                         final JLabel emailLabel,
    159                         final JLabel copyrightLabel,
    160                         final JLabel copyrightYearLabel,
    161                         final JLabel warning) {
    162 
    163                 ActionListener authorActionListener = new ActionListener(){
    164                         public void actionPerformed(ActionEvent e) {
    165                                 boolean b = author.isSelected();
    166                                 authorName.setEnabled(b);
    167                                 email.setEnabled(b);
    168                                 nameLabel.setEnabled(b);
    169                                 emailLabel.setEnabled(b);
    170                                 authorName.setText(b ? Main.pref.get("lastAuthorName") : "");
    171                                 email.setText(b ? Main.pref.get("osm-server.username") : "");
    172 
    173                                 boolean authorSet = authorName.getText().length() != 0;
    174                                 enableCopyright(copyright, predefined, copyrightYear, copyrightLabel, copyrightYearLabel, warning, b && authorSet);
    175                         }
    176                 };
    177                 author.addActionListener(authorActionListener);
    178 
    179                 KeyAdapter authorNameListener = new KeyAdapter(){
    180                                         @Override public void keyReleased(KeyEvent e) {
    181                                                 boolean b = authorName.getText().length()!=0 && author.isSelected();
    182                                                 enableCopyright(copyright, predefined, copyrightYear, copyrightLabel, copyrightYearLabel, warning, b);
    183                                         }
    184                                 };
    185                 authorName.addKeyListener(authorNameListener);
    186 
    187                 predefined.addActionListener(new ActionListener(){
    188                         public void actionPerformed(ActionEvent e) {
    189                                 JList l = new JList(new String[]{"Creative Commons By-SA", "public domain", "GNU Lesser Public License (LGPL)", "BSD License (MIT/X11)"});
    190                                 l.setVisibleRowCount(4);
    191                                 l.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
    192                                 int answer = JOptionPane.showConfirmDialog(Main.parent, new JScrollPane(l),tr("Choose a predefined license"), JOptionPane.OK_CANCEL_OPTION);
    193                                 if (answer != JOptionPane.OK_OPTION || l.getSelectedIndex() == -1)
    194                                         return;
    195                                 final String[] urls = {
    196                                                 "http://creativecommons.org/licenses/by-sa/2.5",
    197                                                 "public domain",
    198                                                 "http://www.gnu.org/copyleft/lesser.html",
    199                                                 "http://www.opensource.org/licenses/bsd-license.php"};
    200                                 String license = "";
    201                                 for (int i : l.getSelectedIndices()) {
    202                                         if (i == 1) {
    203                                                 license = "public domain";
    204                                                 break;
    205                                         }
    206                                         license += license.length()==0 ? urls[i] : ", "+urls[i];
    207                                 }
    208                                 copyright.setText(license);
    209                                 copyright.setCaretPosition(0);
    210                         }
    211                 });
    212 
    213                 authorActionListener.actionPerformed(null);
    214                 authorNameListener.keyReleased(null);
    215         }
    216 
    217         private static void enableCopyright(final JTextField copyright, final JButton predefined, final JTextField copyrightYear, final JLabel copyrightLabel, final JLabel copyrightYearLabel, final JLabel warning, boolean enable) {
    218                 copyright.setEnabled(enable);
    219                 predefined.setEnabled(enable);
    220                 copyrightYear.setEnabled(enable);
    221                 copyrightLabel.setEnabled(enable);
    222                 copyrightYearLabel.setEnabled(enable);
    223                 warning.setText(enable ? warningGpl : "<html><font size='-2'>&nbsp;</html");
    224 
    225                 if (enable && copyrightYear.getText().length()==0) {
    226                         copyrightYear.setText(enable ? Integer.toString(Calendar.getInstance().get(Calendar.YEAR)) : "");
    227                 } else if (!enable)
    228                         copyrightYear.setText("");
    229 
    230                 if (enable && copyright.getText().length()==0) {
    231                         copyright.setText(enable ? Main.pref.get("lastCopyright", "http://creativecommons.org/licenses/by-sa/2.5") : "");
    232                         copyright.setCaretPosition(0);
    233                 } else if (!enable)
    234                         copyright.setText("");
    235         }
     42    private final static String warningGpl = "<html><font color='red' size='-2'>"+tr("Note: GPL is not compatible with the OSM license. Do not upload GPL licensed tracks.")+"</html>";
     43
     44    private final Layer layer;
     45
     46    public GpxExportAction(Layer layer) {
     47        super(tr("Export to GPX ..."), "exportgpx", tr("Export the data to GPX file."),
     48        Shortcut.registerShortcut("file:exportgpx", tr("Export to GPX ..."), KeyEvent.VK_E, Shortcut.GROUP_MENU));
     49        this.layer = layer;
     50    }
     51
     52    public void actionPerformed(ActionEvent e) {
     53        if (layer == null && Main.map == null) {
     54            JOptionPane.showMessageDialog(Main.parent, tr("Nothing to export. Get some data first."));
     55            return;
     56        }
     57
     58        JFileChooser fc = createAndOpenFileChooser(false, false, null);
     59        if (fc == null)
     60            return;
     61        File file = fc.getSelectedFile();
     62        if (file == null)
     63            return;
     64
     65        exportGpx(file, this.layer == null ? Main.main.editLayer() : this.layer);
     66    }
     67
     68    public static void exportGpx(File file, Layer layer) {
     69        String fn = file.getPath();
     70        if (fn.indexOf('.') == -1) {
     71            fn += ".gpx";
     72            file = new File(fn);
     73        }
     74
     75        // open the dialog asking for options
     76        JPanel p = new JPanel(new GridBagLayout());
     77
     78        p.add(new JLabel(tr("gps track description")), GBC.eol());
     79        JTextArea desc = new JTextArea(3,40);
     80        desc.setWrapStyleWord(true);
     81        desc.setLineWrap(true);
     82        p.add(new JScrollPane(desc), GBC.eop().fill(GBC.BOTH));
     83
     84        JCheckBox author = new JCheckBox(tr("Add author information"), Main.pref.getBoolean("lastAddAuthor", true));
     85        author.setSelected(true);
     86        p.add(author, GBC.eol());
     87        JLabel nameLabel = new JLabel(tr("Real name"));
     88        p.add(nameLabel, GBC.std().insets(10,0,5,0));
     89        JTextField authorName = new JTextField(Main.pref.get("lastAuthorName"));
     90        p.add(authorName, GBC.eol().fill(GBC.HORIZONTAL));
     91        JLabel emailLabel = new JLabel(tr("Email"));
     92        p.add(emailLabel, GBC.std().insets(10,0,5,0));
     93        JTextField email = new JTextField(Main.pref.get("osm-server.username"));
     94        p.add(email, GBC.eol().fill(GBC.HORIZONTAL));
     95        JLabel copyrightLabel = new JLabel(tr("Copyright (URL)"));
     96        p.add(copyrightLabel, GBC.std().insets(10,0,5,0));
     97        JTextField copyright = new JTextField();
     98        p.add(copyright, GBC.std().fill(GBC.HORIZONTAL));
     99        JButton predefined = new JButton(tr("Predefined"));
     100        p.add(predefined, GBC.eol().insets(5,0,0,0));
     101        JLabel copyrightYearLabel = new JLabel(tr("Copyright year"));
     102        p.add(copyrightYearLabel, GBC.std().insets(10,0,5,5));
     103        JTextField copyrightYear = new JTextField("");
     104        p.add(copyrightYear, GBC.eol().fill(GBC.HORIZONTAL));
     105        JLabel warning = new JLabel("<html><font size='-2'>&nbsp;</html");
     106        p.add(warning, GBC.eol().fill(GBC.HORIZONTAL).insets(15,0,0,0));
     107        addDependencies(author, authorName, email, copyright, predefined, copyrightYear, nameLabel, emailLabel, copyrightLabel, copyrightYearLabel, warning);
     108
     109        p.add(new JLabel(tr("Keywords")), GBC.eol());
     110        JTextField keywords = new JTextField();
     111        p.add(keywords, GBC.eop().fill(GBC.HORIZONTAL));
     112
     113        int answer = JOptionPane.showConfirmDialog(Main.parent, p, tr("Export options"), JOptionPane.OK_CANCEL_OPTION);
     114        if (answer != JOptionPane.OK_OPTION)
     115            return;
     116
     117        Main.pref.put("lastAddAuthor", author.isSelected());
     118        if (authorName.getText().length() != 0)
     119            Main.pref.put("lastAuthorName", authorName.getText());
     120        if (copyright.getText().length() != 0)
     121            Main.pref.put("lastCopyright", copyright.getText());
     122
     123        GpxData gpxData;
     124        if (layer instanceof OsmDataLayer)
     125            gpxData = ((OsmDataLayer)layer).toGpxData();
     126        else if (layer instanceof GpxLayer)
     127            gpxData = ((GpxLayer)layer).data;
     128        else
     129            gpxData = OsmDataLayer.toGpxData(Main.ds);
     130        // TODO: add copyright, etc.
     131        try {
     132            FileOutputStream fo = new FileOutputStream(file);
     133            new GpxWriter(fo).write(gpxData);
     134            fo.flush();
     135            fo.close();
     136        } catch (IOException x) {
     137            x.printStackTrace();
     138            JOptionPane.showMessageDialog(Main.parent, tr("Error while exporting {0}", fn)+":\n"+x.getMessage(), tr("Error"), JOptionPane.ERROR_MESSAGE);
     139        }
     140    }
     141
     142    /**
     143    * Add all those listeners to handle the enable state of the fields.
     144    * @param copyrightYearLabel
     145    * @param copyrightLabel
     146    * @param emailLabel
     147    * @param nameLabel
     148    * @param warning
     149    */
     150    private static void addDependencies(
     151            final JCheckBox author,
     152            final JTextField authorName,
     153            final JTextField email,
     154            final JTextField copyright,
     155            final JButton predefined,
     156            final JTextField copyrightYear,
     157            final JLabel nameLabel,
     158            final JLabel emailLabel,
     159            final JLabel copyrightLabel,
     160            final JLabel copyrightYearLabel,
     161            final JLabel warning) {
     162
     163        ActionListener authorActionListener = new ActionListener(){
     164            public void actionPerformed(ActionEvent e) {
     165                boolean b = author.isSelected();
     166                authorName.setEnabled(b);
     167                email.setEnabled(b);
     168                nameLabel.setEnabled(b);
     169                emailLabel.setEnabled(b);
     170                authorName.setText(b ? Main.pref.get("lastAuthorName") : "");
     171                email.setText(b ? Main.pref.get("osm-server.username") : "");
     172
     173                boolean authorSet = authorName.getText().length() != 0;
     174                enableCopyright(copyright, predefined, copyrightYear, copyrightLabel, copyrightYearLabel, warning, b && authorSet);
     175            }
     176        };
     177        author.addActionListener(authorActionListener);
     178
     179        KeyAdapter authorNameListener = new KeyAdapter(){
     180                    @Override public void keyReleased(KeyEvent e) {
     181                        boolean b = authorName.getText().length()!=0 && author.isSelected();
     182                        enableCopyright(copyright, predefined, copyrightYear, copyrightLabel, copyrightYearLabel, warning, b);
     183                    }
     184                };
     185        authorName.addKeyListener(authorNameListener);
     186
     187        predefined.addActionListener(new ActionListener(){
     188            public void actionPerformed(ActionEvent e) {
     189                JList l = new JList(new String[]{"Creative Commons By-SA", "public domain", "GNU Lesser Public License (LGPL)", "BSD License (MIT/X11)"});
     190                l.setVisibleRowCount(4);
     191                l.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
     192                int answer = JOptionPane.showConfirmDialog(Main.parent, new JScrollPane(l),tr("Choose a predefined license"), JOptionPane.OK_CANCEL_OPTION);
     193                if (answer != JOptionPane.OK_OPTION || l.getSelectedIndex() == -1)
     194                    return;
     195                final String[] urls = {
     196                        "http://creativecommons.org/licenses/by-sa/2.5",
     197                        "public domain",
     198                        "http://www.gnu.org/copyleft/lesser.html",
     199                        "http://www.opensource.org/licenses/bsd-license.php"};
     200                String license = "";
     201                for (int i : l.getSelectedIndices()) {
     202                    if (i == 1) {
     203                        license = "public domain";
     204                        break;
     205                    }
     206                    license += license.length()==0 ? urls[i] : ", "+urls[i];
     207                }
     208                copyright.setText(license);
     209                copyright.setCaretPosition(0);
     210            }
     211        });
     212
     213        authorActionListener.actionPerformed(null);
     214        authorNameListener.keyReleased(null);
     215    }
     216
     217    private static void enableCopyright(final JTextField copyright, final JButton predefined, final JTextField copyrightYear, final JLabel copyrightLabel, final JLabel copyrightYearLabel, final JLabel warning, boolean enable) {
     218        copyright.setEnabled(enable);
     219        predefined.setEnabled(enable);
     220        copyrightYear.setEnabled(enable);
     221        copyrightLabel.setEnabled(enable);
     222        copyrightYearLabel.setEnabled(enable);
     223        warning.setText(enable ? warningGpl : "<html><font size='-2'>&nbsp;</html");
     224
     225        if (enable && copyrightYear.getText().length()==0) {
     226            copyrightYear.setText(enable ? Integer.toString(Calendar.getInstance().get(Calendar.YEAR)) : "");
     227        } else if (!enable)
     228            copyrightYear.setText("");
     229
     230        if (enable && copyright.getText().length()==0) {
     231            copyright.setText(enable ? Main.pref.get("lastCopyright", "http://creativecommons.org/licenses/by-sa/2.5") : "");
     232            copyright.setCaretPosition(0);
     233        } else if (!enable)
     234            copyright.setText("");
     235    }
    236236}
  • trunk/src/org/openstreetmap/josm/actions/HelpAction.java

    r1163 r1169  
    4242public class HelpAction extends AbstractAction {
    4343
    44         public interface Helpful {
    45                 String helpTopic();
     44    public interface Helpful {
     45        String helpTopic();
    4646    }
    4747
    4848        private String languageCode = Main.getLanguageCodeU();
    49         private JFrame helpBrowser = new JFrame(tr("JOSM Online Help"));
    50         private String baseurl = Main.pref.get("help.baseurl", "http://josm.openstreetmap.de");
    51         private JEditorPane help = new JEditorPane();
    52         private WikiReader reader = new WikiReader(baseurl);
    53         private String url;
    54 
    55         public HelpAction() {
    56                 super(tr("Help"), ImageProvider.get("help"));
    57                 help.setEditable(false);
    58                 help.addHyperlinkListener(new HyperlinkListener(){
    59                         public void hyperlinkUpdate(HyperlinkEvent e) {
    60                                 if (e.getEventType() != HyperlinkEvent.EventType.ACTIVATED)
    61                                         return;
    62                                 if (e.getURL() == null)
    63                                         help.setText("<html>404 not found</html>");
    64                                 else if (e.getURL().toString().startsWith(WikiReader.JOSM_EXTERN))
    65                                         OpenBrowser.displayUrl("http://"+e.getURL().toString().substring(WikiReader.JOSM_EXTERN.length())+"?action=edit");
    66                                 else
    67                                         setHelpUrl(e.getURL().toString());
    68                         }
    69                 });
    70                 help.setContentType("text/html");
    71 
    72                 JPanel p = new JPanel(new BorderLayout());
    73                 helpBrowser.setContentPane(p);
    74 
    75                 p.add(new JScrollPane(help), BorderLayout.CENTER);
    76                 String[] bounds = Main.pref.get("help.window.bounds", "0,0,800,600").split(",");
    77                 helpBrowser.setBounds(
    78                                 Integer.parseInt(bounds[0]),
    79                                 Integer.parseInt(bounds[1]),
    80                                 Integer.parseInt(bounds[2]),
    81                                 Integer.parseInt(bounds[3]));
    82 
    83                 JPanel buttons = new JPanel();
    84                 p.add(buttons, BorderLayout.SOUTH);
    85                 createButton(buttons, tr("Open in Browser"));
    86                 createButton(buttons, tr("Edit"));
    87                 createButton(buttons, tr("Reload"));
    88 
    89                 helpBrowser.addWindowListener(new WindowAdapter(){
    90                         @Override public void windowClosing(WindowEvent e) {
    91                                 closeHelp();
    92                         }
    93                 });
     49    private JFrame helpBrowser = new JFrame(tr("JOSM Online Help"));
     50    private String baseurl = Main.pref.get("help.baseurl", "http://josm.openstreetmap.de");
     51    private JEditorPane help = new JEditorPane();
     52    private WikiReader reader = new WikiReader(baseurl);
     53    private String url;
     54
     55    public HelpAction() {
     56        super(tr("Help"), ImageProvider.get("help"));
     57        help.setEditable(false);
     58        help.addHyperlinkListener(new HyperlinkListener(){
     59            public void hyperlinkUpdate(HyperlinkEvent e) {
     60                if (e.getEventType() != HyperlinkEvent.EventType.ACTIVATED)
     61                    return;
     62                if (e.getURL() == null)
     63                    help.setText("<html>404 not found</html>");
     64                else if (e.getURL().toString().startsWith(WikiReader.JOSM_EXTERN))
     65                    OpenBrowser.displayUrl("http://"+e.getURL().toString().substring(WikiReader.JOSM_EXTERN.length())+"?action=edit");
     66                else
     67                    setHelpUrl(e.getURL().toString());
     68            }
     69        });
     70        help.setContentType("text/html");
     71
     72        JPanel p = new JPanel(new BorderLayout());
     73        helpBrowser.setContentPane(p);
     74
     75        p.add(new JScrollPane(help), BorderLayout.CENTER);
     76        String[] bounds = Main.pref.get("help.window.bounds", "0,0,800,600").split(",");
     77        helpBrowser.setBounds(
     78                Integer.parseInt(bounds[0]),
     79                Integer.parseInt(bounds[1]),
     80                Integer.parseInt(bounds[2]),
     81                Integer.parseInt(bounds[3]));
     82
     83        JPanel buttons = new JPanel();
     84        p.add(buttons, BorderLayout.SOUTH);
     85        createButton(buttons, tr("Open in Browser"));
     86        createButton(buttons, tr("Edit"));
     87        createButton(buttons, tr("Reload"));
     88
     89        helpBrowser.addWindowListener(new WindowAdapter(){
     90            @Override public void windowClosing(WindowEvent e) {
     91                closeHelp();
     92            }
     93        });
    9494
    9595        help.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "Close");
    9696        help.getActionMap().put("Close", new AbstractAction(){
    97                         public void actionPerformed(ActionEvent e) {
    98                                 closeHelp();
     97            public void actionPerformed(ActionEvent e) {
     98                closeHelp();
    9999            }
    100100        });
    101         }
    102 
    103         public void actionPerformed(ActionEvent e) {
    104                 if (tr("Open in Browser").equals(e.getActionCommand())) {
    105                         OpenBrowser.displayUrl(url);
    106                 } else if (tr("Edit").equals(e.getActionCommand())) {
    107                         if (!url.startsWith(baseurl)) {
    108                                 JOptionPane.showMessageDialog(Main.parent, tr("Can only edit help pages from JOSM Online Help"));
    109                                 return;
    110                         }
    111                         OpenBrowser.displayUrl(url+"?action=edit");
    112                 } else if (tr("Reload").equals(e.getActionCommand())) {
    113                         setHelpUrl(url);
    114                 } else if (e.getActionCommand() == null) {
    115                         String topic = null;
    116                         Point mouse = Main.parent.getMousePosition();
    117                         if (mouse != null)
    118                                 topic = contextSensitiveHelp(SwingUtilities.getDeepestComponentAt(Main.parent, mouse.x, mouse.y));
    119                         if (topic == null) {
    120                                 helpBrowser.setVisible(false);
    121                                 setHelpUrl(baseurl+"/wiki/Help");
    122                         } else
    123                                 help(topic);
    124                 } else {
    125                         helpBrowser.setVisible(false);
    126                         setHelpUrl(baseurl+"/wiki/Help");
    127                 }
    128         }
    129 
    130         /**
    131         * @return The topic of the help. <code>null</code> for "don't know"
    132         */
    133         private String contextSensitiveHelp(Object c) {
    134                 if (c instanceof Helpful)
    135                         return ((Helpful)c).helpTopic();
    136                 if (c instanceof JMenu)
    137                         return "Menu/"+((JMenu)c).getText();
    138                 if (c instanceof AbstractButton) {
    139                         AbstractButton b = (AbstractButton)c;
    140                         if (b.getClientProperty("help") != null)
    141                                 return (String)b.getClientProperty("help");
    142                         return contextSensitiveHelp(((AbstractButton)c).getAction());
    143                 }
    144                 if (c instanceof Action)
    145                         return (String)((Action)c).getValue("help");
    146                 if (c instanceof Component)
    147                         return contextSensitiveHelp(((Component)c).getParent());
    148                 return null;
    149     }
    150 
    151         /**
    152         * Displays the help (or browse on the already open help) on the online page
    153         * with the given help topic. Use this for larger help descriptions.
    154         */
    155         public void help(String topic) {
    156                 helpBrowser.setVisible(false);
    157                 setHelpUrl(baseurl+"/wiki/Help/"+topic);
    158         }
    159 
    160         /**
    161         * Set the content of the help window to a specific text (in html format)
    162         * @param url The url this content is the representation of
    163         */
    164         public void setHelpUrl(String url) {
    165                 int i = url.lastIndexOf("/")+1;
    166                 String title = url.substring(i);
    167                 if(!title.startsWith(languageCode))
    168                         title = languageCode + title;
    169                 String langurl = url.substring(0, i) + title;
    170                 if(langurl.equals(this.url) || langurl.equals(url))
    171                 {
    172                         this.url = url;
    173                         try {
    174                                 help.read(new StringReader(reader.read(url)), help.getEditorKit().createDefaultDocument());
    175                         } catch (IOException ex) {
    176                                 help.setText(tr("Error while loading page {0}",url));
    177                         }
    178                 }
    179                 else
    180                 {
    181                         try {
    182                                 help.read(new StringReader(reader.read(langurl)), help.getEditorKit().createDefaultDocument());
    183                                 String message = help.getText();
    184                                 String le = "http://josm-extern." + langurl.substring(7);
    185                                 if(message.indexOf("Describe &quot;") >= 0 && message.indexOf(le) >= 0)
    186                                         throw new IOException();
    187                                 this.url = langurl;
    188                         } catch (IOException e) {
    189                                 this.url = url;
    190                                 try {
    191                                         help.read(new StringReader(reader.read(url)), help.getEditorKit().createDefaultDocument());
    192                                 } catch (IOException ex) {
    193                                         help.setText(tr("Error while loading page {0}",url));
    194                                 }
    195                         }
    196                 }
    197                 helpBrowser.setVisible(true);
    198         }
    199 
    200         /**
    201         * Closes the help window
    202         */
    203         public void closeHelp() {
    204                 String bounds = helpBrowser.getX()+","+helpBrowser.getY()+","+helpBrowser.getWidth()+","+helpBrowser.getHeight();
    205                 Main.pref.put("help.window.bounds", bounds);
    206                 helpBrowser.setVisible(false);
    207         }
    208 
    209         private void createButton(JPanel buttons, String name) {
    210                 JButton b = new JButton(tr(name));
    211                 b.setActionCommand(name);
    212                 b.addActionListener(this);
    213                 buttons.add(b);
    214         }
     101    }
     102
     103    public void actionPerformed(ActionEvent e) {
     104        if (tr("Open in Browser").equals(e.getActionCommand())) {
     105            OpenBrowser.displayUrl(url);
     106        } else if (tr("Edit").equals(e.getActionCommand())) {
     107            if (!url.startsWith(baseurl)) {
     108                JOptionPane.showMessageDialog(Main.parent, tr("Can only edit help pages from JOSM Online Help"));
     109                return;
     110            }
     111            OpenBrowser.displayUrl(url+"?action=edit");
     112        } else if (tr("Reload").equals(e.getActionCommand())) {
     113            setHelpUrl(url);
     114        } else if (e.getActionCommand() == null) {
     115            String topic = null;
     116            Point mouse = Main.parent.getMousePosition();
     117            if (mouse != null)
     118                topic = contextSensitiveHelp(SwingUtilities.getDeepestComponentAt(Main.parent, mouse.x, mouse.y));
     119            if (topic == null) {
     120                helpBrowser.setVisible(false);
     121                setHelpUrl(baseurl+"/wiki/Help");
     122            } else
     123                help(topic);
     124        } else {
     125            helpBrowser.setVisible(false);
     126            setHelpUrl(baseurl+"/wiki/Help");
     127        }
     128    }
     129
     130    /**
     131    * @return The topic of the help. <code>null</code> for "don't know"
     132    */
     133    private String contextSensitiveHelp(Object c) {
     134        if (c instanceof Helpful)
     135            return ((Helpful)c).helpTopic();
     136        if (c instanceof JMenu)
     137            return "Menu/"+((JMenu)c).getText();
     138        if (c instanceof AbstractButton) {
     139            AbstractButton b = (AbstractButton)c;
     140            if (b.getClientProperty("help") != null)
     141                return (String)b.getClientProperty("help");
     142            return contextSensitiveHelp(((AbstractButton)c).getAction());
     143        }
     144        if (c instanceof Action)
     145            return (String)((Action)c).getValue("help");
     146        if (c instanceof Component)
     147            return contextSensitiveHelp(((Component)c).getParent());
     148        return null;
     149    }
     150
     151    /**
     152    * Displays the help (or browse on the already open help) on the online page
     153    * with the given help topic. Use this for larger help descriptions.
     154    */
     155    public void help(String topic) {
     156        helpBrowser.setVisible(false);
     157        setHelpUrl(baseurl+"/wiki/Help/"+topic);
     158    }
     159
     160    /**
     161    * Set the content of the help window to a specific text (in html format)
     162    * @param url The url this content is the representation of
     163    */
     164    public void setHelpUrl(String url) {
     165        int i = url.lastIndexOf("/")+1;
     166        String title = url.substring(i);
     167        if(!title.startsWith(languageCode))
     168            title = languageCode + title;
     169        String langurl = url.substring(0, i) + title;
     170        if(langurl.equals(this.url) || langurl.equals(url))
     171        {
     172            this.url = url;
     173            try {
     174                help.read(new StringReader(reader.read(url)), help.getEditorKit().createDefaultDocument());
     175            } catch (IOException ex) {
     176                help.setText(tr("Error while loading page {0}",url));
     177            }
     178        }
     179        else
     180        {
     181            try {
     182                help.read(new StringReader(reader.read(langurl)), help.getEditorKit().createDefaultDocument());
     183                String message = help.getText();
     184                String le = "http://josm-extern." + langurl.substring(7);
     185                if(message.indexOf("Describe &quot;") >= 0 && message.indexOf(le) >= 0)
     186                    throw new IOException();
     187                this.url = langurl;
     188            } catch (IOException e) {
     189                this.url = url;
     190                try {
     191                    help.read(new StringReader(reader.read(url)), help.getEditorKit().createDefaultDocument());
     192                } catch (IOException ex) {
     193                    help.setText(tr("Error while loading page {0}",url));
     194                }
     195            }
     196        }
     197        helpBrowser.setVisible(true);
     198    }
     199
     200    /**
     201    * Closes the help window
     202    */
     203    public void closeHelp() {
     204        String bounds = helpBrowser.getX()+","+helpBrowser.getY()+","+helpBrowser.getWidth()+","+helpBrowser.getHeight();
     205        Main.pref.put("help.window.bounds", bounds);
     206        helpBrowser.setVisible(false);
     207    }
     208
     209    private void createButton(JPanel buttons, String name) {
     210        JButton b = new JButton(tr(name));
     211        b.setActionCommand(name);
     212        b.addActionListener(this);
     213        buttons.add(b);
     214    }
    215215}
  • trunk/src/org/openstreetmap/josm/actions/HistoryInfoAction.java

    r1084 r1169  
    1818public class HistoryInfoAction extends JosmAction {
    1919
    20         public HistoryInfoAction() {
    21                 super(tr("OSM History Information"), "about",tr("Display history information about OSM ways or nodes."),
    22                 Shortcut.registerShortcut("core:history", tr("OSM History Information"), KeyEvent.VK_H, Shortcut.GROUP_HOTKEY), true);
    23         }
     20    public HistoryInfoAction() {
     21        super(tr("OSM History Information"), "about",tr("Display history information about OSM ways or nodes."),
     22        Shortcut.registerShortcut("core:history", tr("OSM History Information"), KeyEvent.VK_H, Shortcut.GROUP_HOTKEY), true);
     23    }
    2424
    25         public void actionPerformed(ActionEvent e) {
     25    public void actionPerformed(ActionEvent e) {
    2626                new Visitor() {
    2727                        public void visit(Node n) {
    28                                 OpenBrowser.displayUrl("http://www.openstreetmap.org/browse/node/" + n.id + "/history");
    29                         }
     28                OpenBrowser.displayUrl("http://www.openstreetmap.org/browse/node/" + n.id + "/history");
     29            }
    3030
    3131                        public void visit(Way w) {
     
    4343                }.visitAll();
    4444
    45         }
     45    }
    4646
    4747}
  • trunk/src/org/openstreetmap/josm/actions/JoinNodeWayAction.java

    r1084 r1169  
    2626
    2727public class JoinNodeWayAction extends JosmAction {
    28         public JoinNodeWayAction() {
    29             super(tr("Join node to way"), "joinnodeway", tr("Join a node into the nearest way segments"),
    30                         Shortcut.registerShortcut("tools:joinnodeway", tr("Tool: {0}", tr("Join node to way")), KeyEvent.VK_J, Shortcut.GROUP_EDIT), true);
    31         }
     28    public JoinNodeWayAction() {
     29        super(tr("Join node to way"), "joinnodeway", tr("Join a node into the nearest way segments"),
     30            Shortcut.registerShortcut("tools:joinnodeway", tr("Tool: {0}", tr("Join node to way")), KeyEvent.VK_J, Shortcut.GROUP_EDIT), true);
     31    }
    3232
    33         public void actionPerformed(ActionEvent e) {
    34                 Collection<OsmPrimitive> sel = Main.ds.getSelected();
    35                 if (sel.size() != 1 || !(sel.iterator().next() instanceof Node)) return;
    36                 Node node = (Node) sel.iterator().next();
     33    public void actionPerformed(ActionEvent e) {
     34        Collection<OsmPrimitive> sel = Main.ds.getSelected();
     35        if (sel.size() != 1 || !(sel.iterator().next() instanceof Node)) return;
     36        Node node = (Node) sel.iterator().next();
    3737
    38                 List<WaySegment> wss = Main.map.mapView.getNearestWaySegments(
    39                         Main.map.mapView.getPoint(node.eastNorth));
    40                 HashMap<Way, List<Integer>> insertPoints = new HashMap<Way, List<Integer>>();
    41                 for (WaySegment ws : wss) {
    42                         List<Integer> is;
    43                         if (insertPoints.containsKey(ws.way)) {
    44                                 is = insertPoints.get(ws.way);
    45                         } else {
    46                                 is = new ArrayList<Integer>();
    47                                 insertPoints.put(ws.way, is);
    48                         }
     38        List<WaySegment> wss = Main.map.mapView.getNearestWaySegments(
     39            Main.map.mapView.getPoint(node.eastNorth));
     40        HashMap<Way, List<Integer>> insertPoints = new HashMap<Way, List<Integer>>();
     41        for (WaySegment ws : wss) {
     42            List<Integer> is;
     43            if (insertPoints.containsKey(ws.way)) {
     44                is = insertPoints.get(ws.way);
     45            } else {
     46                is = new ArrayList<Integer>();
     47                insertPoints.put(ws.way, is);
     48            }
    4949
    50                         if (ws.way.nodes.get(ws.lowerIndex) != node
    51                                         && ws.way.nodes.get(ws.lowerIndex+1) != node) {
    52                                 is.add(ws.lowerIndex);
    53                         }
    54                 }
     50            if (ws.way.nodes.get(ws.lowerIndex) != node
     51                    && ws.way.nodes.get(ws.lowerIndex+1) != node) {
     52                is.add(ws.lowerIndex);
     53            }
     54        }
    5555
    56                 Collection<Command> cmds = new LinkedList<Command>();
    57                 for (Map.Entry<Way, List<Integer>> insertPoint : insertPoints.entrySet()) {
    58                         Way w = insertPoint.getKey();
    59                         Way wnew = new Way(w);
    60                         List<Integer> is = insertPoint.getValue();
    61                         pruneSuccsAndReverse(is);
    62                         for (int i : is) wnew.nodes.add(i+1, node);
    63                         cmds.add(new ChangeCommand(w, wnew));
    64                 }
     56        Collection<Command> cmds = new LinkedList<Command>();
     57        for (Map.Entry<Way, List<Integer>> insertPoint : insertPoints.entrySet()) {
     58            Way w = insertPoint.getKey();
     59            Way wnew = new Way(w);
     60            List<Integer> is = insertPoint.getValue();
     61            pruneSuccsAndReverse(is);
     62            for (int i : is) wnew.nodes.add(i+1, node);
     63            cmds.add(new ChangeCommand(w, wnew));
     64        }
    6565
    66                 Main.main.undoRedo.add(new SequenceCommand(tr("Join Node and Line"), cmds));
    67                 Main.map.repaint();
    68         }
     66        Main.main.undoRedo.add(new SequenceCommand(tr("Join Node and Line"), cmds));
     67        Main.map.repaint();
     68    }
    6969
    70         private static void pruneSuccsAndReverse(List<Integer> is) {
    71                 //if (is.size() < 2) return;
     70    private static void pruneSuccsAndReverse(List<Integer> is) {
     71        //if (is.size() < 2) return;
    7272
    73                 HashSet<Integer> is2 = new HashSet<Integer>();
    74                 for (int i : is) {
    75                         if (!is2.contains(i - 1) && !is2.contains(i + 1)) {
    76                                 is2.add(i);
    77                         }
    78                 }
    79                 is.clear();
    80                 is.addAll(is2);
    81                 Collections.sort(is);
    82                 Collections.reverse(is);
    83         }
     73        HashSet<Integer> is2 = new HashSet<Integer>();
     74        for (int i : is) {
     75            if (!is2.contains(i - 1) && !is2.contains(i + 1)) {
     76                is2.add(i);
     77            }
     78        }
     79        is.clear();
     80        is.addAll(is2);
     81        Collections.sort(is);
     82        Collections.reverse(is);
     83    }
    8484}
  • trunk/src/org/openstreetmap/josm/actions/JosmAction.java

    r1084 r1169  
    2525abstract public class JosmAction extends AbstractAction implements Destroyable {
    2626
    27         @Deprecated
    28         public KeyStroke shortcut;
    29         protected Shortcut sc;
     27    @Deprecated
     28    public KeyStroke shortcut;
     29    protected Shortcut sc;
    3030
    31         public Shortcut getShortcut() {
    32                 if (sc == null) {
    33                         sc = Shortcut.registerShortcut("core:none", "No Shortcut", 0, Shortcut.GROUP_NONE);
    34                         sc.setAutomatic(); // as this shortcut is shared by all action that don't want to have a shortcut,
    35                                            // we shouldn't allow the user to change it...
    36                 }
    37                 return sc;
    38         }
     31    public Shortcut getShortcut() {
     32        if (sc == null) {
     33            sc = Shortcut.registerShortcut("core:none", "No Shortcut", 0, Shortcut.GROUP_NONE);
     34            sc.setAutomatic(); // as this shortcut is shared by all action that don't want to have a shortcut,
     35                               // we shouldn't allow the user to change it...
     36        }
     37        return sc;
     38    }
    3939
    40         @Deprecated
    41         public JosmAction(String name, String iconName, String tooltip, int shortcut, int modifier, boolean register) {
    42                 super(name, iconName == null ? null : ImageProvider.get(iconName));
    43                 setHelpId();
    44                 if (shortcut != 0) {
    45                         int group = Shortcut.GROUP_LAYER; //GROUP_NONE;
    46                         if (((modifier & InputEvent.CTRL_MASK) != 0) || ((modifier & InputEvent.CTRL_DOWN_MASK) != 0)) {
    47                                 group = Shortcut.GROUP_MENU;
    48                         } else if (modifier == 0) {
    49                                 group = Shortcut.GROUP_EDIT;
    50                         }
    51                         sc = Shortcut.registerShortcut("auto:"+name, name, shortcut, group);
    52                         this.shortcut = sc.getKeyStroke();
    53                         Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(sc.getKeyStroke(), name);
    54                         Main.contentPane.getActionMap().put(name, this);
    55                 }
    56                 putValue(SHORT_DESCRIPTION, Main.platform.makeTooltip(tooltip, sc));
    57                 putValue("toolbar", iconName);
     40    @Deprecated
     41    public JosmAction(String name, String iconName, String tooltip, int shortcut, int modifier, boolean register) {
     42        super(name, iconName == null ? null : ImageProvider.get(iconName));
     43        setHelpId();
     44        if (shortcut != 0) {
     45            int group = Shortcut.GROUP_LAYER; //GROUP_NONE;
     46            if (((modifier & InputEvent.CTRL_MASK) != 0) || ((modifier & InputEvent.CTRL_DOWN_MASK) != 0)) {
     47                group = Shortcut.GROUP_MENU;
     48            } else if (modifier == 0) {
     49                group = Shortcut.GROUP_EDIT;
     50            }
     51            sc = Shortcut.registerShortcut("auto:"+name, name, shortcut, group);
     52            this.shortcut = sc.getKeyStroke();
     53            Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(sc.getKeyStroke(), name);
     54            Main.contentPane.getActionMap().put(name, this);
     55        }
     56        putValue(SHORT_DESCRIPTION, Main.platform.makeTooltip(tooltip, sc));
     57        putValue("toolbar", iconName);
    5858    if (register)
    59         Main.toolbar.register(this);
    60         }
     59        Main.toolbar.register(this);
     60    }
    6161
    62         /**
    63         * The new super for all actions.
    64         *
    65         * Use this super constructor to setup your action. It takes 5 parameters:
    66         *
    67         * name - the action's text as displayed on the menu (if it is added to a menu)
    68         * iconName - the filename of the icon to use
    69         * tooltip - a longer description of the action that will be displayed in the tooltip. Please note
    70         *           that html is not supported for menu action on some platforms
    71         * shortcut - a ready-created shortcut object or null if you don't want a shortcut. But you always
    72         *            do want a shortcut, remember you can alway register it with group=none, so you
    73         *            won't be assigned a shurtcut unless the user configures one. If you pass null here,
    74         *            the user CANNOT configure a shortcut for your action.
    75         * register - register this action for the toolbar preferences?
    76         */
    77         public JosmAction(String name, String iconName, String tooltip, Shortcut shortcut, boolean register) {
    78                 super(name, iconName == null ? null : ImageProvider.get(iconName));
    79                 setHelpId();
    80                 sc = shortcut;
    81                 if (sc != null) {
    82                         this.shortcut = sc.getKeyStroke();
    83                         Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(sc.getKeyStroke(), name);
    84                         Main.contentPane.getActionMap().put(name, this);
    85                 }
    86                 putValue(SHORT_DESCRIPTION, Main.platform.makeTooltip(tooltip, sc));
    87                 putValue("toolbar", iconName);
     62    /**
     63    * The new super for all actions.
     64    *
     65    * Use this super constructor to setup your action. It takes 5 parameters:
     66    *
     67    * name - the action's text as displayed on the menu (if it is added to a menu)
     68    * iconName - the filename of the icon to use
     69    * tooltip - a longer description of the action that will be displayed in the tooltip. Please note
     70    *           that html is not supported for menu action on some platforms
     71    * shortcut - a ready-created shortcut object or null if you don't want a shortcut. But you always
     72    *            do want a shortcut, remember you can alway register it with group=none, so you
     73    *            won't be assigned a shurtcut unless the user configures one. If you pass null here,
     74    *            the user CANNOT configure a shortcut for your action.
     75    * register - register this action for the toolbar preferences?
     76    */
     77    public JosmAction(String name, String iconName, String tooltip, Shortcut shortcut, boolean register) {
     78        super(name, iconName == null ? null : ImageProvider.get(iconName));
     79        setHelpId();
     80        sc = shortcut;
     81        if (sc != null) {
     82            this.shortcut = sc.getKeyStroke();
     83            Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(sc.getKeyStroke(), name);
     84            Main.contentPane.getActionMap().put(name, this);
     85        }
     86        putValue(SHORT_DESCRIPTION, Main.platform.makeTooltip(tooltip, sc));
     87        putValue("toolbar", iconName);
    8888    if (register)
    89         Main.toolbar.register(this);
    90         }
     89        Main.toolbar.register(this);
     90    }
    9191
    92         public void destroy() {
    93                 if (shortcut != null) {
    94                         Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).remove(sc.getKeyStroke());
    95                         Main.contentPane.getActionMap().remove(sc.getKeyStroke());
    96                 }
    97         }
     92    public void destroy() {
     93        if (shortcut != null) {
     94            Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).remove(sc.getKeyStroke());
     95            Main.contentPane.getActionMap().remove(sc.getKeyStroke());
     96        }
     97    }
    9898
    99         public JosmAction() {
    100                 setHelpId();
    101         }
     99    public JosmAction() {
     100        setHelpId();
     101    }
    102102
    103         /**
    104         * needs to be overridden to be useful
    105         */
    106         public void pasteBufferChanged(DataSet newPasteBuffer) {
    107                 return;
    108         }
     103    /**
     104    * needs to be overridden to be useful
     105    */
     106    public void pasteBufferChanged(DataSet newPasteBuffer) {
     107        return;
     108    }
    109109
    110         /**
    111         * needs to be overridden to be useful
    112         */
    113         public void addListener(JosmAction a) {
    114                 return;
    115         }
     110    /**
     111    * needs to be overridden to be useful
     112    */
     113    public void addListener(JosmAction a) {
     114        return;
     115    }
    116116
    117         private void setHelpId() {
    118                 String helpId = "Action/"+getClass().getName().substring(getClass().getName().lastIndexOf('.')+1);
    119                 if (helpId.endsWith("Action"))
    120                         helpId = helpId.substring(0, helpId.length()-6);
    121                 putValue("help", helpId);
    122         }
     117    private void setHelpId() {
     118        String helpId = "Action/"+getClass().getName().substring(getClass().getName().lastIndexOf('.')+1);
     119        if (helpId.endsWith("Action"))
     120            helpId = helpId.substring(0, helpId.length()-6);
     121        putValue("help", helpId);
     122    }
    123123}
  • trunk/src/org/openstreetmap/josm/actions/MergeNodesAction.java

    r1084 r1169  
    5252public class MergeNodesAction extends JosmAction implements SelectionChangedListener {
    5353
    54         public MergeNodesAction() {
    55                 super(tr("Merge Nodes"), "mergenodes", tr("Merge nodes into the oldest one."),
    56                 Shortcut.registerShortcut("tools:mergenodes", tr("Tool: {0}", tr("Merge Nodes")), KeyEvent.VK_M, Shortcut.GROUP_EDIT), true);
    57                 DataSet.selListeners.add(this);
    58         }
    59 
    60         public void actionPerformed(ActionEvent event) {
    61                 Collection<OsmPrimitive> selection = Main.ds.getSelected();
    62                 LinkedList<Node> selectedNodes = new LinkedList<Node>();
    63 
    64                 // the selection check should stop this procedure starting if
    65                 // nothing but node are selected - otherwise we don't care
    66                 // anyway as long as we have at least two nodes
    67                 for (OsmPrimitive osm : selection)
    68                         if (osm instanceof Node)
    69                                 selectedNodes.add((Node)osm);
    70 
    71                 if (selectedNodes.size() < 2) {
    72                         JOptionPane.showMessageDialog(Main.parent, tr("Please select at least two nodes to merge."));
    73                         return;
    74                 }
    75 
    76                 // Find which node to merge into (i.e. which one will be left)
    77                 // - this should be combined from two things:
    78                 //   1. It will be the first node in the list that has a
    79                 //      positive ID number, OR the first node.
    80                 //   2. It will be at the position of the first node in the
    81                 //      list.
    82                 //
    83                 // *However* - there is the problem that the selection list is
    84                 // _not_ in the order that the nodes were clicked on, meaning
    85                 // that the user doesn't know which node will be chosen (so
    86                 // (2) is not implemented yet.)  :-(
    87                 Node useNode = null;
    88                 for (Node n: selectedNodes) {
    89                         if (n.id > 0) {
    90                                 useNode = n;
    91                                 break;
    92                         }
    93                 }
    94                 if (useNode == null)
    95                         useNode = selectedNodes.iterator().next();
    96 
    97                 mergeNodes(selectedNodes, useNode);
    98         }
    99 
    100         /**
    101         * really do the merging - returns the node that is left
    102         */
    103         public static Node mergeNodes(LinkedList<Node> allNodes, Node dest) {
    104                 Node newNode = new Node(dest);
    105 
    106                 // Check whether all ways have identical relationship membership. More
    107                 // specifically: If one of the selected ways is a member of relation X
    108                 // in role Y, then all selected ways must be members of X in role Y.
    109 
    110                 // FIXME: In a later revision, we should display some sort of conflict
    111                 // dialog like we do for tags, to let the user choose which relations
    112                 // should be kept.
    113 
    114                 // Step 1, iterate over all relations and figure out which of our
    115                 // selected ways are members of a relation.
    116                 HashMap<Pair<Relation,String>, HashSet<Node>> backlinks =
    117                         new HashMap<Pair<Relation,String>, HashSet<Node>>();
    118                 HashSet<Relation> relationsUsingNodes = new HashSet<Relation>();
    119                 for (Relation r : Main.ds.relations) {
    120                         if (r.deleted || r.incomplete) continue;
    121                         for (RelationMember rm : r.members) {
    122                                 if (rm.member instanceof Node) {
    123                                         for (Node n : allNodes) {
    124                                                 if (rm.member == n) {
    125                                                         Pair<Relation,String> pair = new Pair<Relation,String>(r, rm.role);
    126                                                         HashSet<Node> nodelinks = new HashSet<Node>();
    127                                                         if (backlinks.containsKey(pair)) {
    128                                                                 nodelinks = backlinks.get(pair);
    129                                                         } else {
    130                                                                 nodelinks = new HashSet<Node>();
    131                                                                 backlinks.put(pair, nodelinks);
    132                                                         }
    133                                                         nodelinks.add(n);
    134 
    135                                                         // this is just a cache for later use
    136                                                         relationsUsingNodes.add(r);
    137                                                 }
    138                                         }
    139                                 }
    140                         }
    141                 }
    142 
    143                 // Complain to the user if the ways don't have equal memberships.
    144                 for (HashSet<Node> nodelinks : backlinks.values()) {
    145                         if (!nodelinks.containsAll(allNodes)) {
    146                                 int option = JOptionPane.showConfirmDialog(Main.parent,
    147                                         tr("The selected nodes have differing relation memberships.  "
    148                                                 + "Do you still want to merge them?"),
    149                                         tr("Merge nodes with different memberships?"),
    150                                         JOptionPane.YES_NO_OPTION);
    151                                 if (option == JOptionPane.YES_OPTION)
    152                                         break;
    153                                 return null;
    154                         }
    155                 }
    156 
    157                 // collect properties for later conflict resolving
    158                 Map<String, Set<String>> props = new TreeMap<String, Set<String>>();
    159                 for (Node n : allNodes) {
    160                         for (Entry<String,String> e : n.entrySet()) {
    161                                 if (!props.containsKey(e.getKey()))
    162                                         props.put(e.getKey(), new TreeSet<String>());
    163                                 props.get(e.getKey()).add(e.getValue());
    164                         }
    165                 }
    166 
    167                 // display conflict dialog
    168                 Map<String, JComboBox> components = new HashMap<String, JComboBox>();
    169                 JPanel p = new JPanel(new GridBagLayout());
    170                 for (Entry<String, Set<String>> e : props.entrySet()) {
    171                         if (TigerUtils.isTigerTag(e.getKey())) {
    172                                 String combined = TigerUtils.combineTags(e.getKey(), e.getValue());
    173                                 newNode.put(e.getKey(), combined);
    174                         } else if (e.getValue().size() > 1) {
    175                                 if("created_by".equals(e.getKey()))
    176                                 {
    177                                         newNode.put("created_by", "JOSM");
    178                                 }
    179                                 else
    180                                 {
    181                                         JComboBox c = new JComboBox(e.getValue().toArray());
    182                                         c.setEditable(true);
    183                                         p.add(new JLabel(e.getKey()), GBC.std());
    184                                         p.add(Box.createHorizontalStrut(10), GBC.std());
    185                                         p.add(c, GBC.eol());
    186                                         components.put(e.getKey(), c);
    187                                 }
    188                         } else
    189                                 newNode.put(e.getKey(), e.getValue().iterator().next());
    190                 }
    191 
    192                 if (!components.isEmpty()) {
    193                         int answer = JOptionPane.showConfirmDialog(Main.parent, p, tr("Enter values for all conflicts."), JOptionPane.OK_CANCEL_OPTION);
    194                         if (answer != JOptionPane.OK_OPTION)
    195                                 return null;
    196                         for (Entry<String, JComboBox> e : components.entrySet())
    197                                 newNode.put(e.getKey(), e.getValue().getEditor().getItem().toString());
    198                 }
    199 
    200                 LinkedList<Command> cmds = new LinkedList<Command>();
    201                 cmds.add(new ChangeCommand(dest, newNode));
    202 
    203                 Collection<OsmPrimitive> del = new HashSet<OsmPrimitive>();
    204 
    205                 for (Way w : Main.ds.ways) {
    206                         if (w.deleted || w.incomplete || w.nodes.size() < 1) continue;
    207                         boolean modify = false;
    208                         for (Node sn : allNodes) {
    209                                 if (sn == dest) continue;
    210                                 if (w.nodes.contains(sn)) {
    211                                         modify = true;
    212                                 }
    213                         }
    214                         if (!modify) continue;
    215                         // OK - this way contains one or more nodes to change
    216                         ArrayList<Node> nn = new ArrayList<Node>();
    217                         Node lastNode = null;
    218                         for (int i = 0; i < w.nodes.size(); i++) {
    219                                 Node pushNode = w.nodes.get(i);
    220                                 if (allNodes.contains(pushNode)) {
    221                                         pushNode = dest;
    222                                 }
    223                                 if (pushNode != lastNode) {
    224                                         nn.add(pushNode);
    225                                 }
    226                                 lastNode = pushNode;
    227                         }
    228                         if (nn.size() < 2) {
    229                                 CollectBackReferencesVisitor backRefs =
    230                                         new CollectBackReferencesVisitor(Main.ds, false);
    231                                 w.visit(backRefs);
    232                                 if (!backRefs.data.isEmpty()) {
    233                                         JOptionPane.showMessageDialog(Main.parent,
    234                                                 tr("Cannot merge nodes: " +
    235                                                         "Would have to delete a way that is still used."));
    236                                         return null;
    237                                 }
    238                                 del.add(w);
    239                         } else {
    240                                 Way newWay = new Way(w);
    241                                 newWay.nodes.clear();
    242                                 newWay.nodes.addAll(nn);
    243                                 cmds.add(new ChangeCommand(w, newWay));
    244                         }
    245                 }
    246 
    247                 // delete any merged nodes
    248                 del.addAll(allNodes);
    249                 del.remove(dest);
    250                 if (!del.isEmpty()) cmds.add(new DeleteCommand(del));
    251 
    252                 // modify all relations containing the now-deleted nodes
    253                 for (Relation r : relationsUsingNodes) {
    254                         Relation newRel = new Relation(r);
    255                         newRel.members.clear();
    256                         HashSet<String> rolesToReAdd = new HashSet<String>();
    257                         for (RelationMember rm : r.members) {
    258                                 // Don't copy the member if it points to one of our nodes,
    259                                 // just keep a note to re-add it later on.
    260                                 if (allNodes.contains(rm.member)) {
    261                                         rolesToReAdd.add(rm.role);
    262                                 } else {
    263                                         newRel.members.add(rm);
    264                                 }
    265                         }
    266                         for (String role : rolesToReAdd) {
    267                                 newRel.members.add(new RelationMember(role, dest));
    268                         }
    269                         cmds.add(new ChangeCommand(r, newRel));
    270                 }
    271 
    272                 Main.main.undoRedo.add(new SequenceCommand(tr("Merge {0} nodes", allNodes.size()), cmds));
    273                 Main.ds.setSelected(dest);
    274 
    275                 return dest;
    276         }
    277 
    278 
    279         /**
    280         * Enable the "Merge Nodes" menu option if more then one node is selected
    281         */
    282         public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
    283                 boolean ok = true;
    284                 if (newSelection.size() < 2) {
    285                         setEnabled(false);
    286                         return;
    287                 }
    288                 for (OsmPrimitive osm : newSelection) {
    289                         if (!(osm instanceof Node)) {
    290                                 ok = false;
    291                                 break;
    292                         }
    293                 }
    294                 setEnabled(ok);
    295         }
     54    public MergeNodesAction() {
     55        super(tr("Merge Nodes"), "mergenodes", tr("Merge nodes into the oldest one."),
     56        Shortcut.registerShortcut("tools:mergenodes", tr("Tool: {0}", tr("Merge Nodes")), KeyEvent.VK_M, Shortcut.GROUP_EDIT), true);
     57        DataSet.selListeners.add(this);
     58    }
     59
     60    public void actionPerformed(ActionEvent event) {
     61        Collection<OsmPrimitive> selection = Main.ds.getSelected();
     62        LinkedList<Node> selectedNodes = new LinkedList<Node>();
     63
     64        // the selection check should stop this procedure starting if
     65        // nothing but node are selected - otherwise we don't care
     66        // anyway as long as we have at least two nodes
     67        for (OsmPrimitive osm : selection)
     68            if (osm instanceof Node)
     69                selectedNodes.add((Node)osm);
     70
     71        if (selectedNodes.size() < 2) {
     72            JOptionPane.showMessageDialog(Main.parent, tr("Please select at least two nodes to merge."));
     73            return;
     74        }
     75
     76        // Find which node to merge into (i.e. which one will be left)
     77        // - this should be combined from two things:
     78        //   1. It will be the first node in the list that has a
     79        //      positive ID number, OR the first node.
     80        //   2. It will be at the position of the first node in the
     81        //      list.
     82        //
     83        // *However* - there is the problem that the selection list is
     84        // _not_ in the order that the nodes were clicked on, meaning
     85        // that the user doesn't know which node will be chosen (so
     86        // (2) is not implemented yet.)  :-(
     87        Node useNode = null;
     88        for (Node n: selectedNodes) {
     89            if (n.id > 0) {
     90                useNode = n;
     91                break;
     92            }
     93        }
     94        if (useNode == null)
     95            useNode = selectedNodes.iterator().next();
     96
     97        mergeNodes(selectedNodes, useNode);
     98    }
     99
     100    /**
     101    * really do the merging - returns the node that is left
     102    */
     103    public static Node mergeNodes(LinkedList<Node> allNodes, Node dest) {
     104        Node newNode = new Node(dest);
     105
     106        // Check whether all ways have identical relationship membership. More
     107        // specifically: If one of the selected ways is a member of relation X
     108        // in role Y, then all selected ways must be members of X in role Y.
     109
     110        // FIXME: In a later revision, we should display some sort of conflict
     111        // dialog like we do for tags, to let the user choose which relations
     112        // should be kept.
     113
     114        // Step 1, iterate over all relations and figure out which of our
     115        // selected ways are members of a relation.
     116        HashMap<Pair<Relation,String>, HashSet<Node>> backlinks =
     117            new HashMap<Pair<Relation,String>, HashSet<Node>>();
     118        HashSet<Relation> relationsUsingNodes = new HashSet<Relation>();
     119        for (Relation r : Main.ds.relations) {
     120            if (r.deleted || r.incomplete) continue;
     121            for (RelationMember rm : r.members) {
     122                if (rm.member instanceof Node) {
     123                    for (Node n : allNodes) {
     124                        if (rm.member == n) {
     125                            Pair<Relation,String> pair = new Pair<Relation,String>(r, rm.role);
     126                            HashSet<Node> nodelinks = new HashSet<Node>();
     127                            if (backlinks.containsKey(pair)) {
     128                                nodelinks = backlinks.get(pair);
     129                            } else {
     130                                nodelinks = new HashSet<Node>();
     131                                backlinks.put(pair, nodelinks);
     132                            }
     133                            nodelinks.add(n);
     134
     135                            // this is just a cache for later use
     136                            relationsUsingNodes.add(r);
     137                        }
     138                    }
     139                }
     140            }
     141        }
     142
     143        // Complain to the user if the ways don't have equal memberships.
     144        for (HashSet<Node> nodelinks : backlinks.values()) {
     145            if (!nodelinks.containsAll(allNodes)) {
     146                int option = JOptionPane.showConfirmDialog(Main.parent,
     147                    tr("The selected nodes have differing relation memberships.  "
     148                        + "Do you still want to merge them?"),
     149                    tr("Merge nodes with different memberships?"),
     150                    JOptionPane.YES_NO_OPTION);
     151                if (option == JOptionPane.YES_OPTION)
     152                    break;
     153                return null;
     154            }
     155        }
     156
     157        // collect properties for later conflict resolving
     158        Map<String, Set<String>> props = new TreeMap<String, Set<String>>();
     159        for (Node n : allNodes) {
     160            for (Entry<String,String> e : n.entrySet()) {
     161                if (!props.containsKey(e.getKey()))
     162                    props.put(e.getKey(), new TreeSet<String>());
     163                props.get(e.getKey()).add(e.getValue());
     164            }
     165        }
     166
     167        // display conflict dialog
     168        Map<String, JComboBox> components = new HashMap<String, JComboBox>();
     169        JPanel p = new JPanel(new GridBagLayout());
     170        for (Entry<String, Set<String>> e : props.entrySet()) {
     171            if (TigerUtils.isTigerTag(e.getKey())) {
     172                String combined = TigerUtils.combineTags(e.getKey(), e.getValue());
     173                newNode.put(e.getKey(), combined);
     174            } else if (e.getValue().size() > 1) {
     175                if("created_by".equals(e.getKey()))
     176                {
     177                    newNode.put("created_by", "JOSM");
     178                }
     179                else
     180                {
     181                    JComboBox c = new JComboBox(e.getValue().toArray());
     182                    c.setEditable(true);
     183                    p.add(new JLabel(e.getKey()), GBC.std());
     184                    p.add(Box.createHorizontalStrut(10), GBC.std());
     185                    p.add(c, GBC.eol());
     186                    components.put(e.getKey(), c);
     187                }
     188            } else
     189                newNode.put(e.getKey(), e.getValue().iterator().next());
     190        }
     191
     192        if (!components.isEmpty()) {
     193            int answer = JOptionPane.showConfirmDialog(Main.parent, p, tr("Enter values for all conflicts."), JOptionPane.OK_CANCEL_OPTION);
     194            if (answer != JOptionPane.OK_OPTION)
     195                return null;
     196            for (Entry<String, JComboBox> e : components.entrySet())
     197                newNode.put(e.getKey(), e.getValue().getEditor().getItem().toString());
     198        }
     199
     200        LinkedList<Command> cmds = new LinkedList<Command>();
     201        cmds.add(new ChangeCommand(dest, newNode));
     202
     203        Collection<OsmPrimitive> del = new HashSet<OsmPrimitive>();
     204
     205        for (Way w : Main.ds.ways) {
     206            if (w.deleted || w.incomplete || w.nodes.size() < 1) continue;
     207            boolean modify = false;
     208            for (Node sn : allNodes) {
     209                if (sn == dest) continue;
     210                if (w.nodes.contains(sn)) {
     211                    modify = true;
     212                }
     213            }
     214            if (!modify) continue;
     215            // OK - this way contains one or more nodes to change
     216            ArrayList<Node> nn = new ArrayList<Node>();
     217            Node lastNode = null;
     218            for (int i = 0; i < w.nodes.size(); i++) {
     219                Node pushNode = w.nodes.get(i);
     220                if (allNodes.contains(pushNode)) {
     221                    pushNode = dest;
     222                }
     223                if (pushNode != lastNode) {
     224                    nn.add(pushNode);
     225                }
     226                lastNode = pushNode;
     227            }
     228            if (nn.size() < 2) {
     229                CollectBackReferencesVisitor backRefs =
     230                    new CollectBackReferencesVisitor(Main.ds, false);
     231                w.visit(backRefs);
     232                if (!backRefs.data.isEmpty()) {
     233                    JOptionPane.showMessageDialog(Main.parent,
     234                        tr("Cannot merge nodes: " +
     235                            "Would have to delete a way that is still used."));
     236                    return null;
     237                }
     238                del.add(w);
     239            } else {
     240                Way newWay = new Way(w);
     241                newWay.nodes.clear();
     242                newWay.nodes.addAll(nn);
     243                cmds.add(new ChangeCommand(w, newWay));
     244            }
     245        }
     246
     247        // delete any merged nodes
     248        del.addAll(allNodes);
     249        del.remove(dest);
     250        if (!del.isEmpty()) cmds.add(new DeleteCommand(del));
     251
     252        // modify all relations containing the now-deleted nodes
     253        for (Relation r : relationsUsingNodes) {
     254            Relation newRel = new Relation(r);
     255            newRel.members.clear();
     256            HashSet<String> rolesToReAdd = new HashSet<String>();
     257            for (RelationMember rm : r.members) {
     258                // Don't copy the member if it points to one of our nodes,
     259                // just keep a note to re-add it later on.
     260                if (allNodes.contains(rm.member)) {
     261                    rolesToReAdd.add(rm.role);
     262                } else {
     263                    newRel.members.add(rm);
     264                }
     265            }
     266            for (String role : rolesToReAdd) {
     267                newRel.members.add(new RelationMember(role, dest));
     268            }
     269            cmds.add(new ChangeCommand(r, newRel));
     270        }
     271
     272        Main.main.undoRedo.add(new SequenceCommand(tr("Merge {0} nodes", allNodes.size()), cmds));
     273        Main.ds.setSelected(dest);
     274
     275        return dest;
     276    }
     277
     278
     279    /**
     280    * Enable the "Merge Nodes" menu option if more then one node is selected
     281    */
     282    public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
     283        boolean ok = true;
     284        if (newSelection.size() < 2) {
     285            setEnabled(false);
     286            return;
     287        }
     288        for (OsmPrimitive osm : newSelection) {
     289            if (!(osm instanceof Node)) {
     290                ok = false;
     291                break;
     292            }
     293        }
     294        setEnabled(ok);
     295    }
    296296}
  • trunk/src/org/openstreetmap/josm/actions/MoveAction.java

    r1084 r1169  
    2626public class MoveAction extends JosmAction {
    2727
    28         public enum Direction { UP, LEFT, RIGHT, DOWN }
    29         private Direction myDirection;
     28    public enum Direction { UP, LEFT, RIGHT, DOWN }
     29    private Direction myDirection;
    3030
    31         // any better idea?
    32         private static Object calltosupermustbefirststatementinconstructor(Direction dir, boolean text) {
    33                 Shortcut sc;
    34                 String directiontext;
    35                 if        (dir == Direction.UP)   {
    36                         directiontext = tr("up");
    37                         sc = Shortcut.registerShortcut("core:moveup",    tr("Move objects {0}", directiontext), KeyEvent.VK_UP,    Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT);
    38                 } else if (dir == Direction.DOWN)  {
    39                         directiontext = tr("down");
    40                         sc = Shortcut.registerShortcut("core:movedown",  tr("Move objects {0}", directiontext), KeyEvent.VK_DOWN,  Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT);
    41                 } else if (dir == Direction.LEFT)  {
    42                         directiontext = tr("left");
    43                         sc = Shortcut.registerShortcut("core:moveleft",  tr("Move objects {0}", directiontext), KeyEvent.VK_LEFT,  Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT);
    44                 } else { //dir == Direction.RIGHT) {
    45                         directiontext = tr("right");
    46                         sc = Shortcut.registerShortcut("core:moveright", tr("Move objects {0}", directiontext), KeyEvent.VK_RIGHT, Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT);
    47                 }
    48                 if (text) {
    49                         return directiontext;
    50                 } else {
    51                         return sc;
    52                 }
    53         }
     31    // any better idea?
     32    private static Object calltosupermustbefirststatementinconstructor(Direction dir, boolean text) {
     33        Shortcut sc;
     34        String directiontext;
     35        if        (dir == Direction.UP)   {
     36            directiontext = tr("up");
     37            sc = Shortcut.registerShortcut("core:moveup",    tr("Move objects {0}", directiontext), KeyEvent.VK_UP,    Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT);
     38        } else if (dir == Direction.DOWN)  {
     39            directiontext = tr("down");
     40            sc = Shortcut.registerShortcut("core:movedown",  tr("Move objects {0}", directiontext), KeyEvent.VK_DOWN,  Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT);
     41        } else if (dir == Direction.LEFT)  {
     42            directiontext = tr("left");
     43            sc = Shortcut.registerShortcut("core:moveleft",  tr("Move objects {0}", directiontext), KeyEvent.VK_LEFT,  Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT);
     44        } else { //dir == Direction.RIGHT) {
     45            directiontext = tr("right");
     46            sc = Shortcut.registerShortcut("core:moveright", tr("Move objects {0}", directiontext), KeyEvent.VK_RIGHT, Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT);
     47        }
     48        if (text) {
     49            return directiontext;
     50        } else {
     51            return sc;
     52        }
     53    }
    5454
    55         public MoveAction(Direction dir) {
    56                 super(tr("Move {0}", calltosupermustbefirststatementinconstructor(dir, true)), null,
    57                       tr("Moves Objects {0}", calltosupermustbefirststatementinconstructor(dir, true)),
    58                       (Shortcut)calltosupermustbefirststatementinconstructor(dir, false), true);
    59                 myDirection = dir;
    60         }
     55    public MoveAction(Direction dir) {
     56        super(tr("Move {0}", calltosupermustbefirststatementinconstructor(dir, true)), null,
     57              tr("Moves Objects {0}", calltosupermustbefirststatementinconstructor(dir, true)),
     58              (Shortcut)calltosupermustbefirststatementinconstructor(dir, false), true);
     59        myDirection = dir;
     60    }
    6161
    62         public void actionPerformed(ActionEvent event) {
     62    public void actionPerformed(ActionEvent event) {
    6363
    64                 // find out how many "real" units the objects have to be moved in order to
    65                 // achive an 1-pixel movement
     64        // find out how many "real" units the objects have to be moved in order to
     65        // achive an 1-pixel movement
    6666
    67                 EastNorth en1 = Main.map.mapView.getEastNorth(100, 100);
    68                 EastNorth en2 = Main.map.mapView.getEastNorth(101, 101);
     67        EastNorth en1 = Main.map.mapView.getEastNorth(100, 100);
     68        EastNorth en2 = Main.map.mapView.getEastNorth(101, 101);
    6969
    70                 double distx = en2.east() - en1.east();
    71                 double disty = en2.north() - en1.north();
     70        double distx = en2.east() - en1.east();
     71        double disty = en2.north() - en1.north();
    7272
    73                 switch (myDirection) {
    74                 case UP:
    75                         distx = 0;
    76                         disty = -disty;
    77                         break;
    78                 case DOWN:
    79                         distx = 0;
    80                         break;
    81                 case LEFT:
    82                         disty = 0;
    83                         distx = -distx;
    84                 default:
    85                         disty = 0;
    86                 }
     73        switch (myDirection) {
     74        case UP:
     75            distx = 0;
     76            disty = -disty;
     77            break;
     78        case DOWN:
     79            distx = 0;
     80            break;
     81        case LEFT:
     82            disty = 0;
     83            distx = -distx;
     84        default:
     85            disty = 0;
     86        }
    8787
    88                 Collection<OsmPrimitive> selection = Main.ds.getSelected();
    89                 Collection<Node> affectedNodes = AllNodesVisitor.getAllNodes(selection);
     88        Collection<OsmPrimitive> selection = Main.ds.getSelected();
     89        Collection<Node> affectedNodes = AllNodesVisitor.getAllNodes(selection);
    9090
    91                 Command c = !Main.main.undoRedo.commands.isEmpty()
    92                 ? Main.main.undoRedo.commands.getLast() : null;
     91        Command c = !Main.main.undoRedo.commands.isEmpty()
     92        ? Main.main.undoRedo.commands.getLast() : null;
    9393
    94                 if (c instanceof MoveCommand && affectedNodes.equals(((MoveCommand)c).objects))
    95                         ((MoveCommand)c).moveAgain(distx, disty);
    96                 else
    97                         Main.main.undoRedo.add(
    98                                         c = new MoveCommand(selection, distx, disty));
     94        if (c instanceof MoveCommand && affectedNodes.equals(((MoveCommand)c).objects))
     95            ((MoveCommand)c).moveAgain(distx, disty);
     96        else
     97            Main.main.undoRedo.add(
     98                    c = new MoveCommand(selection, distx, disty));
    9999
    100                 for (Node n : affectedNodes) {
    101                         if (n.coor.isOutSideWorld()) {
    102                                 // Revert move
    103                                 ((MoveCommand) c).moveAgain(-distx, -disty);
    104                                 JOptionPane.showMessageDialog(Main.parent,
    105                                                 tr("Cannot move objects outside of the world."));
    106                                 return;
    107                         }
    108                 }
     100        for (Node n : affectedNodes) {
     101            if (n.coor.isOutSideWorld()) {
     102                // Revert move
     103                ((MoveCommand) c).moveAgain(-distx, -disty);
     104                JOptionPane.showMessageDialog(Main.parent,
     105                        tr("Cannot move objects outside of the world."));
     106                return;
     107            }
     108        }
    109109
    110                 Main.map.mapView.repaint();
    111         }
     110        Main.map.mapView.repaint();
     111    }
    112112}
  • trunk/src/org/openstreetmap/josm/actions/NewAction.java

    r1084 r1169  
    1414public class NewAction extends JosmAction {
    1515
    16         public NewAction() {
    17                 super(tr("New"), "new", tr("Create a new map."),
    18                 Shortcut.registerShortcut("system:new", tr("File: {0}", tr("New")), KeyEvent.VK_N, Shortcut.GROUP_MENU), true);
    19         }
     16    public NewAction() {
     17        super(tr("New"), "new", tr("Create a new map."),
     18        Shortcut.registerShortcut("system:new", tr("File: {0}", tr("New")), KeyEvent.VK_N, Shortcut.GROUP_MENU), true);
     19    }
    2020
    21         public void actionPerformed(ActionEvent e) {
    22                 Main.main.addLayer(new OsmDataLayer(new DataSet(), tr("unnamed"), null));
    23         }
     21    public void actionPerformed(ActionEvent e) {
     22        Main.main.addLayer(new OsmDataLayer(new DataSet(), tr("unnamed"), null));
     23    }
    2424}
  • trunk/src/org/openstreetmap/josm/actions/OpenFileAction.java

    r1167 r1169  
    3535public class OpenFileAction extends DiskAccessAction {
    3636
    37         /**
    38          * Create an open action. The name is "Open a file".
    39          */
    40         public OpenFileAction() {
    41                 super(tr("Open ..."), "open", tr("Open a file."),
    42                 Shortcut.registerShortcut("system:open", tr("File: {0}", tr("Open ...")), KeyEvent.VK_O, Shortcut.GROUP_MENU));
    43         }
    44 
    45         public void actionPerformed(ActionEvent e) {
    46                 JFileChooser fc = createAndOpenFileChooser(true, true, null);
    47                 if (fc == null)
    48                         return;
    49                 File[] files = fc.getSelectedFiles();
    50                 for (int i = files.length; i > 0; --i)
    51                         openFile(files[i-1]);
    52         }
    53 
    54         /**
    55          * Open the given file.
    56          */
    57         public void openFile(File file) {
    58                 try {
    59                         if (asGpxData(file.getName()))
    60                                 openFileAsGpx(file);
    61                         else if (asNmeaData(file.getName()))
    62                                 openFileAsNmea(file);
    63                         else
    64                                 openAsData(file);
    65                 } catch (SAXException x) {
    66                         x.printStackTrace();
    67                         JOptionPane.showMessageDialog(Main.parent, tr("Error while parsing {0}",file.getName())+": "+x.getMessage());
    68                 } catch (IOException x) {
    69                         x.printStackTrace();
    70                         JOptionPane.showMessageDialog(Main.parent, tr("Could not read \"{0}\"",file.getName())+"\n"+x.getMessage());
    71                 }
    72         }
    73 
    74         private void openAsData(File file) throws SAXException, IOException, FileNotFoundException {
    75                 String fn = file.getName();
    76                 if (ExtensionFileFilter.filters[ExtensionFileFilter.OSM].acceptName(fn)) {
    77                         DataSet dataSet = OsmReader.parseDataSet(new FileInputStream(file), null, Main.pleaseWaitDlg);
    78                         OsmDataLayer layer = new OsmDataLayer(dataSet, file.getName(), file);
    79                         Main.main.addLayer(layer);
    80                         layer.fireDataChange();
    81                 }
    82                 else
    83                         JOptionPane.showMessageDialog(Main.parent, fn+": "+tr("Unknown file extension: {0}", fn.substring(file.getName().lastIndexOf('.')+1)));
    84         }
    85 
    86         private void openFileAsGpx(File file) throws SAXException, IOException, FileNotFoundException {
    87                 String fn = file.getName();
    88                 if (ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(fn)) {
    89                         GpxReader r = null;
    90                         InputStream is;
    91                         if (file.getName().endsWith(".gpx.gz")) {
    92                                 is = new GZIPInputStream(new FileInputStream(file));
    93                         } else {
    94                                 is = new FileInputStream(file);
    95                         }
    96                         // Workaround for SAX BOM bug
    97                         // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6206835
    98                         if(!((is.read()==0xef)&&(is.read()==0xbb)&&(is.read()==0xbf))) {
    99                                 is.close();
    100                                 if (file.getName().endsWith(".gpx.gz")) {
    101                                         is = new GZIPInputStream(new FileInputStream(file));
    102                                 } else {
    103                                         is = new FileInputStream(file);
    104                                 }
    105                         }
    106                         r = new GpxReader(is,file.getAbsoluteFile().getParentFile());
    107                         r.data.storageFile = file;
    108                         GpxLayer gpxLayer = new GpxLayer(r.data, fn);
    109                         Main.main.addLayer(gpxLayer);
    110                         if (Main.pref.getBoolean("marker.makeautomarkers", true)) {
    111                                 MarkerLayer ml = new MarkerLayer(r.data, tr("Markers from {0}", fn), file, gpxLayer);
    112                                 if (ml.data.size() > 0) {
    113                                         Main.main.addLayer(ml);
    114                                 }
    115                         }
    116 
    117                 } else {
    118                         throw new IllegalStateException();
    119                 }
    120     }
    121        
    122         private void showNmeaInfobox(boolean success, NmeaReader r) {
    123                 String msg = tr("Coordinates imported: ") + r.getNumberOfCoordinates() + "\n" +
    124                 tr("Malformed sentences: ") + r.getParserMalformed() + "\n" +
    125                 tr("Checksum errors: ") + r.getParserChecksumErrors() + "\n";
    126                 if(!success) // don't scare the user unneccessarily
    127                         msg += tr("Unknown sentences: ") + r.getParserUnknown() + "\n";
    128                 msg += tr("Zero coordinates: ") + r.getParserZeroCoordinates();
    129                 if(success) {   
    130                         JOptionPane.showMessageDialog(
    131                                 Main.parent, msg,
    132                                 tr("NMEA import success"),JOptionPane.INFORMATION_MESSAGE);
    133                 } else {
    134                         JOptionPane.showMessageDialog(
    135                                 Main.parent, msg,
    136                                 tr("NMEA import faliure!"),JOptionPane.ERROR_MESSAGE);
    137                 }
    138         }
    139 
    140         private void openFileAsNmea(File file) throws IOException, FileNotFoundException {
    141                 String fn = file.getName();
    142                 if (ExtensionFileFilter.filters[ExtensionFileFilter.NMEA].acceptName(fn)) {
    143                         NmeaReader r = new NmeaReader(new FileInputStream(file), file.getAbsoluteFile().getParentFile());
    144                         if(r.getNumberOfCoordinates()>0) {
    145                                 r.data.storageFile = file;
    146                                 GpxLayer gpxLayer = new GpxLayer(r.data, fn);
    147                                 Main.main.addLayer(gpxLayer);
    148                                 if (Main.pref.getBoolean("marker.makeautomarkers", true)) {
    149                                         MarkerLayer ml = new MarkerLayer(r.data, tr("Markers from {0}", fn), file, gpxLayer);
    150                                         if (ml.data.size() > 0) {
    151                                                 Main.main.addLayer(ml);
    152                                         }
    153                                 }
    154                         }
    155                         showNmeaInfobox(r.getNumberOfCoordinates()>0, r);
    156                 } else {
    157                         throw new IllegalStateException();
    158                 }
     37    /**
     38     * Create an open action. The name is "Open a file".
     39     */
     40    public OpenFileAction() {
     41        super(tr("Open ..."), "open", tr("Open a file."),
     42        Shortcut.registerShortcut("system:open", tr("File: {0}", tr("Open ...")), KeyEvent.VK_O, Shortcut.GROUP_MENU));
    15943    }
    16044
    161         private boolean asGpxData(String fn) {
    162                 return ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(fn);
    163         }
     45    public void actionPerformed(ActionEvent e) {
     46        JFileChooser fc = createAndOpenFileChooser(true, true, null);
     47        if (fc == null)
     48            return;
     49        File[] files = fc.getSelectedFiles();
     50        for (int i = files.length; i > 0; --i)
     51            openFile(files[i-1]);
     52    }
    16453
    165         private boolean asNmeaData(String fn) {
    166                 return ExtensionFileFilter.filters[ExtensionFileFilter.NMEA].acceptName(fn);
    167         }
     54    /**
     55     * Open the given file.
     56     */
     57    public void openFile(File file) {
     58        try {
     59            if (asGpxData(file.getName()))
     60                openFileAsGpx(file);
     61            else if (asNmeaData(file.getName()))
     62                openFileAsNmea(file);
     63            else
     64                openAsData(file);
     65        } catch (SAXException x) {
     66            x.printStackTrace();
     67            JOptionPane.showMessageDialog(Main.parent, tr("Error while parsing {0}",file.getName())+": "+x.getMessage());
     68        } catch (IOException x) {
     69            x.printStackTrace();
     70            JOptionPane.showMessageDialog(Main.parent, tr("Could not read \"{0}\"",file.getName())+"\n"+x.getMessage());
     71        }
     72    }
     73
     74    private void openAsData(File file) throws SAXException, IOException, FileNotFoundException {
     75        String fn = file.getName();
     76        if (ExtensionFileFilter.filters[ExtensionFileFilter.OSM].acceptName(fn)) {
     77            DataSet dataSet = OsmReader.parseDataSet(new FileInputStream(file), null, Main.pleaseWaitDlg);
     78            OsmDataLayer layer = new OsmDataLayer(dataSet, file.getName(), file);
     79            Main.main.addLayer(layer);
     80            layer.fireDataChange();
     81        }
     82        else
     83            JOptionPane.showMessageDialog(Main.parent, fn+": "+tr("Unknown file extension: {0}", fn.substring(file.getName().lastIndexOf('.')+1)));
     84    }
     85
     86    private void openFileAsGpx(File file) throws SAXException, IOException, FileNotFoundException {
     87        String fn = file.getName();
     88        if (ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(fn)) {
     89            GpxReader r = null;
     90            InputStream is;
     91            if (file.getName().endsWith(".gpx.gz")) {
     92                is = new GZIPInputStream(new FileInputStream(file));
     93            } else {
     94                is = new FileInputStream(file);
     95            }
     96            // Workaround for SAX BOM bug
     97            // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6206835
     98            if(!((is.read()==0xef)&&(is.read()==0xbb)&&(is.read()==0xbf))) {
     99                is.close();
     100                if (file.getName().endsWith(".gpx.gz")) {
     101                    is = new GZIPInputStream(new FileInputStream(file));
     102                } else {
     103                    is = new FileInputStream(file);
     104                }
     105            }
     106            r = new GpxReader(is,file.getAbsoluteFile().getParentFile());
     107            r.data.storageFile = file;
     108            GpxLayer gpxLayer = new GpxLayer(r.data, fn);
     109            Main.main.addLayer(gpxLayer);
     110            if (Main.pref.getBoolean("marker.makeautomarkers", true)) {
     111                MarkerLayer ml = new MarkerLayer(r.data, tr("Markers from {0}", fn), file, gpxLayer);
     112                if (ml.data.size() > 0) {
     113                    Main.main.addLayer(ml);
     114                }
     115            }
     116
     117        } else {
     118            throw new IllegalStateException();
     119        }
     120    }
     121
     122    private void showNmeaInfobox(boolean success, NmeaReader r) {
     123        String msg = tr("Coordinates imported: ") + r.getNumberOfCoordinates() + "\n" +
     124        tr("Malformed sentences: ") + r.getParserMalformed() + "\n" +
     125        tr("Checksum errors: ") + r.getParserChecksumErrors() + "\n";
     126        if(!success) // don't scare the user unneccessarily
     127            msg += tr("Unknown sentences: ") + r.getParserUnknown() + "\n";
     128        msg += tr("Zero coordinates: ") + r.getParserZeroCoordinates();
     129        if(success) {
     130            JOptionPane.showMessageDialog(
     131                Main.parent, msg,
     132                tr("NMEA import success"),JOptionPane.INFORMATION_MESSAGE);
     133        } else {
     134            JOptionPane.showMessageDialog(
     135                Main.parent, msg,
     136                tr("NMEA import faliure!"),JOptionPane.ERROR_MESSAGE);
     137        }
     138    }
     139
     140    private void openFileAsNmea(File file) throws IOException, FileNotFoundException {
     141        String fn = file.getName();
     142        if (ExtensionFileFilter.filters[ExtensionFileFilter.NMEA].acceptName(fn)) {
     143            NmeaReader r = new NmeaReader(new FileInputStream(file), file.getAbsoluteFile().getParentFile());
     144            if(r.getNumberOfCoordinates()>0) {
     145                r.data.storageFile = file;
     146                GpxLayer gpxLayer = new GpxLayer(r.data, fn);
     147                Main.main.addLayer(gpxLayer);
     148                if (Main.pref.getBoolean("marker.makeautomarkers", true)) {
     149                    MarkerLayer ml = new MarkerLayer(r.data, tr("Markers from {0}", fn), file, gpxLayer);
     150                    if (ml.data.size() > 0) {
     151                        Main.main.addLayer(ml);
     152                    }
     153                }
     154            }
     155            showNmeaInfobox(r.getNumberOfCoordinates()>0, r);
     156        } else {
     157            throw new IllegalStateException();
     158        }
     159    }
     160
     161    private boolean asGpxData(String fn) {
     162        return ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(fn);
     163    }
     164
     165    private boolean asNmeaData(String fn) {
     166        return ExtensionFileFilter.filters[ExtensionFileFilter.NMEA].acceptName(fn);
     167    }
    168168
    169169
  • trunk/src/org/openstreetmap/josm/actions/OpenLocationAction.java

    r1148 r1169  
    4242public class OpenLocationAction extends JosmAction {
    4343
    44         /**
    45         * Create an open action. The name is "Open a file".
    46         */
    47         public OpenLocationAction() {
    48                 super(tr("Open Location..."), "openlocation", tr("Open a URL."),
    49                 Shortcut.registerShortcut("system:open_location", tr("File: {0}", tr("Open Location...")), KeyEvent.VK_L, Shortcut.GROUP_MENU), true);
    50         }
     44    /**
     45    * Create an open action. The name is "Open a file".
     46    */
     47    public OpenLocationAction() {
     48        super(tr("Open Location..."), "openlocation", tr("Open a URL."),
     49        Shortcut.registerShortcut("system:open_location", tr("File: {0}", tr("Open Location...")), KeyEvent.VK_L, Shortcut.GROUP_MENU), true);
     50    }
    5151
    52         public void actionPerformed(ActionEvent e) {
     52    public void actionPerformed(ActionEvent e) {
    5353
    54             JCheckBox layer = new JCheckBox(tr("Separate Layer"));
    55             layer.setSelected(Main.pref.getBoolean("download.newlayer"));
    56             JPanel all = new JPanel(new GridBagLayout());
    57             all.add(new JLabel("Enter URL to download:"), GBC.eol());
    58             JTextField urltext = new JTextField(40);
    59             all.add(urltext, GBC.eol());
    60             all.add(layer, GBC.eol());
    61             int answer = JOptionPane.showConfirmDialog(Main.parent, all, tr("Download Location"), JOptionPane.OK_CANCEL_OPTION);
    62             if (answer != JOptionPane.OK_OPTION)
    63                 return;
    64             openUrl(layer.isSelected(), urltext.getText());
    65         }
     54        JCheckBox layer = new JCheckBox(tr("Separate Layer"));
     55        layer.setSelected(Main.pref.getBoolean("download.newlayer"));
     56        JPanel all = new JPanel(new GridBagLayout());
     57        all.add(new JLabel("Enter URL to download:"), GBC.eol());
     58        JTextField urltext = new JTextField(40);
     59        all.add(urltext, GBC.eol());
     60        all.add(layer, GBC.eol());
     61        int answer = JOptionPane.showConfirmDialog(Main.parent, all, tr("Download Location"), JOptionPane.OK_CANCEL_OPTION);
     62        if (answer != JOptionPane.OK_OPTION)
     63            return;
     64        openUrl(layer.isSelected(), urltext.getText());
     65    }
    6666
    67         /**
    68         * Open the given file.
    69         */
    70         public void openUrl(boolean new_layer, String url) {
    71             new DownloadOsmTask().loadUrl(new_layer, url);
    72         }
     67    /**
     68    * Open the given file.
     69    */
     70    public void openUrl(boolean new_layer, String url) {
     71        new DownloadOsmTask().loadUrl(new_layer, url);
     72    }
    7373
    7474}
  • trunk/src/org/openstreetmap/josm/actions/OrthogonalizeAction.java

    r1090 r1169  
    2828
    2929/**
    30  * Align edges of a way so all angles are right angles. 
    31  * 
     30 * Align edges of a way so all angles are right angles.
     31 *
    3232 * 1. Find orientation of all edges
    3333 * 2. Compute main orientation, weighted by length of edge, normalized to angles between 0 and pi/2
     
    3838public final class OrthogonalizeAction extends JosmAction {
    3939
    40         public OrthogonalizeAction() {
    41         super(tr("Orthogonalize shape"), 
    42             "ortho", 
     40    public OrthogonalizeAction() {
     41        super(tr("Orthogonalize shape"),
     42            "ortho",
    4343            tr("Move nodes so all angles are 90 or 270deg"),
    44             Shortcut.registerShortcut("tools:orthogonalize", tr("Tool: {0}", tr("Orthogonalize")), 
    45             KeyEvent.VK_Q, 
     44            Shortcut.registerShortcut("tools:orthogonalize", tr("Tool: {0}", tr("Orthogonalize")),
     45            KeyEvent.VK_Q,
    4646            Shortcut.GROUP_EDIT), true);
    47         }
     47    }
    4848
    4949    public void actionPerformed(ActionEvent e) {
     
    6060                    JOptionPane.showMessageDialog(Main.parent, tr("Only two nodes allowed"));
    6161                    return;
    62                 } 
     62                }
    6363                dirnodes.add((Node) osm);
    6464                continue;
     
    6868                JOptionPane.showMessageDialog(Main.parent, tr("Selection must consist only of ways."));
    6969                return;
    70             } 
     70            }
    7171
    7272            // Check if every way is made of at least four segments and closed
     
    7878
    7979            // Check if every edge in the way is a definite edge of at least 45 degrees of direction change
    80             // Otherwise, two segments could be turned into same direction and intersection would fail. 
     80            // Otherwise, two segments could be turned into same direction and intersection would fail.
    8181            // Or changes of shape would be too serious.
    8282            for (int i1=0; i1 < way.nodes.size()-1; i1++) {
     
    116116        boolean use_dirnodes = false;
    117117
    118         if (dirnodes.size() == 2) { 
    119             // When selection contains two nodes, use the nodes to compute a direction 
     118        if (dirnodes.size() == 2) {
     119            // When selection contains two nodes, use the nodes to compute a direction
    120120            // to align all ways to
    121121            align_to_heading = normalize_angle(dirnodes.get(0).eastNorth.heading(dirnodes.get(1).eastNorth));
     
    124124
    125125        for (OsmPrimitive osm : sel) {
    126             if(!(osm instanceof Way)) 
     126            if(!(osm instanceof Way))
    127127                continue;
    128128
     
    164164
    165165                if (angle_diff_max > Math.PI/3) {
    166                     // rearrange headings: everything < 0 gets PI/2-rotated 
     166                    // rearrange headings: everything < 0 gets PI/2-rotated
    167167                    for (int i=0; i < sides; i++) {
    168                         if (headings[i] < 0) 
     168                        if (headings[i] < 0)
    169169                            headings[i] += Math.PI/2;
    170170                    }
     
    183183                    sum_weights += weights[i];
    184184                }
    185                 align_to_heading = normalize_angle(sum_weighted_headings/sum_weights); 
     185                align_to_heading = normalize_angle(sum_weighted_headings/sum_weights);
    186186            }
    187187
    188188
    189189            for (int i=0; i < sides; i++) {
    190                 // Compute handy indices of three nodes to be used in one loop iteration. 
    191                 // We use segments (i1,i2) and (i2,i3), align them and compute the new 
     190                // Compute handy indices of three nodes to be used in one loop iteration.
     191                // We use segments (i1,i2) and (i2,i3), align them and compute the new
    192192                // position of the i2-node as the intersection of the realigned (i1,i2), (i2,i3) segments
    193193                // Not the most efficient algorithm, but we don't handle millions of nodes...
     
    212212
    213213                // compute intersection of segments
    214                 double u=det(B.east() - A.east(), B.north() - A.north(), 
     214                double u=det(B.east() - A.east(), B.north() - A.north(),
    215215                        C.east() - D.east(), C.north() - D.north());
    216216
    217217                // Check for parallel segments and do nothing if they are
    218                 // In practice this will probably only happen when a way has 
     218                // In practice this will probably only happen when a way has
    219219                // been duplicated
    220220
     
    225225                // if the segment is scaled to length 1
    226226
    227                 double q = det(B.north() - C.north(), B.east() - C.east(), 
     227                double q = det(B.north() - C.north(), B.east() - C.east(),
    228228                        D.north() - C.north(), D.east() - C.east()) / u;
    229229                EastNorth intersection = new EastNorth(
     
    239239                    cmds.add(new MoveCommand(n, dx, dy));
    240240                }
    241             } 
     241            }
    242242        }
    243243
  • trunk/src/org/openstreetmap/josm/actions/PasteAction.java

    r1084 r1169  
    2929
    3030    public PasteAction() {
    31         super(tr("Paste"), "paste", tr("Paste contents of paste buffer."),
    32                         Shortcut.registerShortcut("system:paste", tr("Edit: {0}", tr("Paste")), KeyEvent.VK_V, Shortcut.GROUP_MENU), true);
    33                         setEnabled(false);
     31        super(tr("Paste"), "paste", tr("Paste contents of paste buffer."),
     32            Shortcut.registerShortcut("system:paste", tr("Edit: {0}", tr("Paste")), KeyEvent.VK_V, Shortcut.GROUP_MENU), true);
     33            setEnabled(false);
    3434    }
    3535
    36         public void actionPerformed(ActionEvent e) {
    37                 DataSet pasteBuffer = Main.pasteBuffer;
     36    public void actionPerformed(ActionEvent e) {
     37        DataSet pasteBuffer = Main.pasteBuffer;
    3838
    39                 /* Find the middle of the pasteBuffer area */
    40                 double maxEast = -1E100, minEast = 1E100, maxNorth = -1E100, minNorth = 1E100;
    41                 for (Node n : pasteBuffer.nodes) {
    42                         double east = n.eastNorth.east();
    43                         double north = n.eastNorth.north();
    44                         if (east > maxEast) { maxEast = east; }
    45                         if (east < minEast) { minEast = east; }
    46                         if (north > maxNorth) { maxNorth = north; }
    47                         if (north < minNorth) { minNorth = north; }
    48                 }
     39        /* Find the middle of the pasteBuffer area */
     40        double maxEast = -1E100, minEast = 1E100, maxNorth = -1E100, minNorth = 1E100;
     41        for (Node n : pasteBuffer.nodes) {
     42            double east = n.eastNorth.east();
     43            double north = n.eastNorth.north();
     44            if (east > maxEast) { maxEast = east; }
     45            if (east < minEast) { minEast = east; }
     46            if (north > maxNorth) { maxNorth = north; }
     47            if (north < minNorth) { minNorth = north; }
     48        }
    4949
    50                 EastNorth mPosition;
    51                 if((e.getModifiers() & ActionEvent.CTRL_MASK) ==0){
    52                         mPosition = Main.map.mapView.getCenter();
    53                 } else {
    54                         mPosition = Main.map.mapView.getEastNorth(Main.map.mapView.lastMEvent.getX(), Main.map.mapView.lastMEvent.getY());
    55                 }
     50        EastNorth mPosition;
     51        if((e.getModifiers() & ActionEvent.CTRL_MASK) ==0){
     52            mPosition = Main.map.mapView.getCenter();
     53        } else {
     54            mPosition = Main.map.mapView.getEastNorth(Main.map.mapView.lastMEvent.getX(), Main.map.mapView.lastMEvent.getY());
     55        }
    5656
    57                 double offsetEast  = mPosition.east() - (maxEast + minEast)/2.0;
    58                 double offsetNorth = mPosition.north() - (maxNorth + minNorth)/2.0;
     57        double offsetEast  = mPosition.east() - (maxEast + minEast)/2.0;
     58        double offsetNorth = mPosition.north() - (maxNorth + minNorth)/2.0;
    5959
    60                 HashMap<OsmPrimitive,OsmPrimitive> map = new HashMap<OsmPrimitive,OsmPrimitive>();
    61                   /* temporarily maps old nodes to new so we can do a true deep copy */
     60        HashMap<OsmPrimitive,OsmPrimitive> map = new HashMap<OsmPrimitive,OsmPrimitive>();
     61          /* temporarily maps old nodes to new so we can do a true deep copy */
    6262
    63                 /* do the deep copy of the paste buffer contents, leaving the pasteBuffer unchanged */
    64                 for (Node n : pasteBuffer.nodes) {
    65                         Node nnew = new Node(n);
    66                         nnew.id = 0;
    67                         /* adjust the coordinates to the middle of the visible map area */
    68                         nnew.eastNorth = new EastNorth(nnew.eastNorth.east() + offsetEast, nnew.eastNorth.north() + offsetNorth);
    69                         nnew.coor = Main.proj.eastNorth2latlon(nnew.eastNorth);
    70                         map.put(n, nnew);
    71                 }
    72                 for (Way w : pasteBuffer.ways) {
    73                         Way wnew = new Way();
    74                         wnew.cloneFrom(w);
    75                         wnew.id = 0;
    76                         /* make sure we reference the new nodes corresponding to the old ones */
    77                         List<Node> nodes = new ArrayList<Node>();
    78                         for (Node n : w.nodes) {
    79                                 nodes.add((Node)map.get(n));
    80                         }
    81                         wnew.nodes.clear();
    82                         wnew.nodes.addAll(nodes);
    83                         map.put(w, wnew);
    84                 }
    85                 for (Relation r : pasteBuffer.relations) {
    86                         Relation rnew = new Relation(r);
    87                         rnew.id = 0;
    88                         List<RelationMember> members = new ArrayList<RelationMember>();
    89                         for (RelationMember m : r.members) {
    90                                 RelationMember mnew = new RelationMember(m);
    91                                 mnew.member = map.get(m.member);
    92                                 members.add(mnew);
    93                         }
    94                         rnew.members.clear();
    95                         rnew.members.addAll(members);
    96                         map.put(r, rnew);
    97                 }
     63        /* do the deep copy of the paste buffer contents, leaving the pasteBuffer unchanged */
     64        for (Node n : pasteBuffer.nodes) {
     65            Node nnew = new Node(n);
     66            nnew.id = 0;
     67            /* adjust the coordinates to the middle of the visible map area */
     68            nnew.eastNorth = new EastNorth(nnew.eastNorth.east() + offsetEast, nnew.eastNorth.north() + offsetNorth);
     69            nnew.coor = Main.proj.eastNorth2latlon(nnew.eastNorth);
     70            map.put(n, nnew);
     71        }
     72        for (Way w : pasteBuffer.ways) {
     73            Way wnew = new Way();
     74            wnew.cloneFrom(w);
     75            wnew.id = 0;
     76            /* make sure we reference the new nodes corresponding to the old ones */
     77            List<Node> nodes = new ArrayList<Node>();
     78            for (Node n : w.nodes) {
     79                nodes.add((Node)map.get(n));
     80            }
     81            wnew.nodes.clear();
     82            wnew.nodes.addAll(nodes);
     83            map.put(w, wnew);
     84        }
     85        for (Relation r : pasteBuffer.relations) {
     86            Relation rnew = new Relation(r);
     87            rnew.id = 0;
     88            List<RelationMember> members = new ArrayList<RelationMember>();
     89            for (RelationMember m : r.members) {
     90                RelationMember mnew = new RelationMember(m);
     91                mnew.member = map.get(m.member);
     92                members.add(mnew);
     93            }
     94            rnew.members.clear();
     95            rnew.members.addAll(members);
     96            map.put(r, rnew);
     97        }
    9898
    99                 /* Now execute the commands to add the dupicated contents of the paste buffer to the map */
    100                 Collection<OsmPrimitive> osms = map.values();
    101                 Collection<Command> clist = new LinkedList<Command>();
    102                 for (OsmPrimitive osm : osms) {
    103                         clist.add(new AddCommand(osm));
    104                 }
     99        /* Now execute the commands to add the dupicated contents of the paste buffer to the map */
     100        Collection<OsmPrimitive> osms = map.values();
     101        Collection<Command> clist = new LinkedList<Command>();
     102        for (OsmPrimitive osm : osms) {
     103            clist.add(new AddCommand(osm));
     104        }
    105105
    106                 Main.main.undoRedo.add(new SequenceCommand(tr("Paste"), clist));
    107                 Main.ds.setSelected(osms);
    108                 Main.map.mapView.repaint();
     106        Main.main.undoRedo.add(new SequenceCommand(tr("Paste"), clist));
     107        Main.ds.setSelected(osms);
     108        Main.map.mapView.repaint();
    109109    }
    110110}
  • trunk/src/org/openstreetmap/josm/actions/PasteTagsAction.java

    r1084 r1169  
    2424public final class PasteTagsAction extends JosmAction implements SelectionChangedListener {
    2525
    26         public PasteTagsAction(JosmAction copyAction) {
    27                 super(tr("Paste Tags"), "pastetags",
    28                         tr("Apply tags of contents of paste buffer to all selected items."),
    29                         Shortcut.registerShortcut("system:pastestyle", tr("Edit: {0}", tr("Paste Tags")), KeyEvent.VK_V, Shortcut.GROUP_MENU, Shortcut.SHIFT_DEFAULT), true);
    30                 DataSet.selListeners.add(this);
    31                 copyAction.addListener(this);
    32                 setEnabled(false);
    33         }
     26    public PasteTagsAction(JosmAction copyAction) {
     27        super(tr("Paste Tags"), "pastetags",
     28            tr("Apply tags of contents of paste buffer to all selected items."),
     29            Shortcut.registerShortcut("system:pastestyle", tr("Edit: {0}", tr("Paste Tags")), KeyEvent.VK_V, Shortcut.GROUP_MENU, Shortcut.SHIFT_DEFAULT), true);
     30        DataSet.selListeners.add(this);
     31        copyAction.addListener(this);
     32        setEnabled(false);
     33    }
    3434
    35         private void pasteKeys(Collection<Command> clist, Collection<? extends OsmPrimitive> pasteBufferSubset, Collection<OsmPrimitive> selectionSubset) {
    36                 /* scan the paste buffer, and add tags to each of the selected objects.
    37                 * If a tag already exists, it is overwritten */
    38                 if (selectionSubset != null && ! selectionSubset.isEmpty()) {
    39                         for (Iterator<? extends OsmPrimitive> it = pasteBufferSubset.iterator(); it.hasNext();) {
    40                                 OsmPrimitive osm = it.next();
    41                                 Map<String, String> m = osm.keys;
    42                                 if(m != null)
    43                                 {
    44                                         for (String key : m.keySet()) {
    45                                                 if (! key.equals("created_by"))
    46                                                         clist.add(new ChangePropertyCommand(selectionSubset, key, osm.keys.get(key)));
    47                                         }
    48                                 }
    49                         }
    50                 }
    51         }
     35    private void pasteKeys(Collection<Command> clist, Collection<? extends OsmPrimitive> pasteBufferSubset, Collection<OsmPrimitive> selectionSubset) {
     36        /* scan the paste buffer, and add tags to each of the selected objects.
     37        * If a tag already exists, it is overwritten */
     38        if (selectionSubset != null && ! selectionSubset.isEmpty()) {
     39            for (Iterator<? extends OsmPrimitive> it = pasteBufferSubset.iterator(); it.hasNext();) {
     40                OsmPrimitive osm = it.next();
     41                Map<String, String> m = osm.keys;
     42                if(m != null)
     43                {
     44                    for (String key : m.keySet()) {
     45                        if (! key.equals("created_by"))
     46                            clist.add(new ChangePropertyCommand(selectionSubset, key, osm.keys.get(key)));
     47                    }
     48                }
     49            }
     50        }
     51    }
    5252
    53         public void actionPerformed(ActionEvent e) {
    54                 Collection<Command> clist = new LinkedList<Command>();
    55                 pasteKeys(clist, Main.pasteBuffer.nodes, Main.ds.getSelectedNodes());
    56                 pasteKeys(clist, Main.pasteBuffer.ways, Main.ds.getSelectedWays());
    57                 pasteKeys(clist, Main.pasteBuffer.relations, Main.ds.getSelectedRelations());
    58                 Main.main.undoRedo.add(new SequenceCommand(tr("Paste Tags"), clist));
    59                 Main.ds.setSelected(Main.ds.getSelected()); // to force selection listeners, in particular the tag panel, to update
    60                 Main.map.mapView.repaint();
    61         }
     53    public void actionPerformed(ActionEvent e) {
     54        Collection<Command> clist = new LinkedList<Command>();
     55        pasteKeys(clist, Main.pasteBuffer.nodes, Main.ds.getSelectedNodes());
     56        pasteKeys(clist, Main.pasteBuffer.ways, Main.ds.getSelectedWays());
     57        pasteKeys(clist, Main.pasteBuffer.relations, Main.ds.getSelectedRelations());
     58        Main.main.undoRedo.add(new SequenceCommand(tr("Paste Tags"), clist));
     59        Main.ds.setSelected(Main.ds.getSelected()); // to force selection listeners, in particular the tag panel, to update
     60        Main.map.mapView.repaint();
     61    }
    6262
    63         private boolean containsSameKeysWithDifferentValues(Collection<? extends OsmPrimitive> osms) {
    64                 Map<String,String> kvSeen = new HashMap<String,String>();
    65                 for (Iterator<? extends OsmPrimitive> it = osms.iterator(); it.hasNext();) {
    66                         OsmPrimitive osm = it.next();
    67                         if (osm.keys == null || osm.keys.isEmpty())
    68                                 continue;
    69                         for (String key : osm.keys.keySet()) {
    70                                 if (key.equals("created_by")) // we ignore created_by
    71                                         continue;
    72                                 String value = osm.keys.get(key);
    73                                 if (! kvSeen.containsKey(key))
    74                                         kvSeen.put(key, value);
    75                                 else if (! kvSeen.get(key).equals(value))
    76                                         return true;
    77                         }
    78                 }
    79                 return false;
    80         }
     63    private boolean containsSameKeysWithDifferentValues(Collection<? extends OsmPrimitive> osms) {
     64        Map<String,String> kvSeen = new HashMap<String,String>();
     65        for (Iterator<? extends OsmPrimitive> it = osms.iterator(); it.hasNext();) {
     66            OsmPrimitive osm = it.next();
     67            if (osm.keys == null || osm.keys.isEmpty())
     68                continue;
     69            for (String key : osm.keys.keySet()) {
     70                if (key.equals("created_by")) // we ignore created_by
     71                    continue;
     72                String value = osm.keys.get(key);
     73                if (! kvSeen.containsKey(key))
     74                    kvSeen.put(key, value);
     75                else if (! kvSeen.get(key).equals(value))
     76                    return true;
     77            }
     78        }
     79        return false;
     80    }
    8181
    82         /**
    83         * Determines whether to enable the widget depending on the contents of the paste
    84         * buffer and current selection
    85         * @param pasteBuffer
    86         */
    87         private void possiblyEnable(Collection<? extends OsmPrimitive> selection, DataSet pasteBuffer) {