Changeset 1169 in josm


Ignore:
Timestamp:
2008-12-23T15:07:05+01:00 (16 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) {
    88                 /* only enable if there is something selected to paste into and
    89                         if we don't have conflicting keys in the pastebuffer */
    90                 setEnabled(selection != null &&
    91                                 ! selection.isEmpty() &&
    92                                 ! pasteBuffer.allPrimitives().isEmpty() &&
    93                                 (Main.ds.getSelectedNodes().isEmpty() ||
    94                                         ! containsSameKeysWithDifferentValues(pasteBuffer.nodes)) &&
    95                                 (Main.ds.getSelectedWays().isEmpty() ||
    96                                         ! containsSameKeysWithDifferentValues(pasteBuffer.ways)) &&
    97                                 (Main.ds.getSelectedRelations().isEmpty() ||
    98                                         ! containsSameKeysWithDifferentValues(pasteBuffer.relations)));
    99         }
     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) {
     88        /* only enable if there is something selected to paste into and
     89            if we don't have conflicting keys in the pastebuffer */
     90        setEnabled(selection != null &&
     91                ! selection.isEmpty() &&
     92                ! pasteBuffer.allPrimitives().isEmpty() &&
     93                (Main.ds.getSelectedNodes().isEmpty() ||
     94                    ! containsSameKeysWithDifferentValues(pasteBuffer.nodes)) &&
     95                (Main.ds.getSelectedWays().isEmpty() ||
     96                    ! containsSameKeysWithDifferentValues(pasteBuffer.ways)) &&
     97                (Main.ds.getSelectedRelations().isEmpty() ||
     98                    ! containsSameKeysWithDifferentValues(pasteBuffer.relations)));
     99    }
    100100
    101         @Override public void pasteBufferChanged(DataSet newPasteBuffer) {
    102                 possiblyEnable(Main.ds.getSelected(), newPasteBuffer);
    103         }
     101    @Override public void pasteBufferChanged(DataSet newPasteBuffer) {
     102        possiblyEnable(Main.ds.getSelected(), newPasteBuffer);
     103    }
    104104
    105         public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
    106                 possiblyEnable(newSelection, Main.pasteBuffer);
    107         }
     105    public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
     106        possiblyEnable(newSelection, Main.pasteBuffer);
     107    }
    108108}
  • trunk/src/org/openstreetmap/josm/actions/PreferencesAction.java

    r1084 r1169  
    2525public class PreferencesAction extends JosmAction {
    2626
    27         /**
    28         * Create the preference action with "&Preferences" as label.
    29         */
    30         public PreferencesAction() {
    31                 super(tr("Preferences ..."), "preference", tr("Open a preferences page for global settings."),
    32                 Shortcut.registerShortcut("system:preferences", tr("Preferences"), KeyEvent.VK_F12, Shortcut.GROUP_DIRECT), true);
    33         }
     27    /**
     28    * Create the preference action with "&Preferences" as label.
     29    */
     30    public PreferencesAction() {
     31        super(tr("Preferences ..."), "preference", tr("Open a preferences page for global settings."),
     32        Shortcut.registerShortcut("system:preferences", tr("Preferences"), KeyEvent.VK_F12, Shortcut.GROUP_DIRECT), true);
     33    }
    3434
    35         /**
    36         * Launch the preferences dialog.
    37         */
    38         public void actionPerformed(ActionEvent e) {
    39                 PreferenceDialog prefDlg = new PreferenceDialog();
    40                 prefDlg.setMinimumSize(new Dimension(400,300));
    41                 JPanel prefPanel = new JPanel(new GridBagLayout());
    42                 prefPanel.add(prefDlg, GBC.eol().fill(GBC.BOTH));
     35    /**
     36    * Launch the preferences dialog.
     37    */
     38    public void actionPerformed(ActionEvent e) {
     39        PreferenceDialog prefDlg = new PreferenceDialog();
     40        prefDlg.setMinimumSize(new Dimension(400,300));
     41        JPanel prefPanel = new JPanel(new GridBagLayout());
     42        prefPanel.add(prefDlg, GBC.eol().fill(GBC.BOTH));
    4343
    44                 JOptionPane pane = new JOptionPane(prefPanel, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
    45                 JDialog dlg = pane.createDialog(Main.parent, tr("Preferences"));
    46                 dlg.setResizable(true);
    47                 dlg.setMinimumSize(new Dimension(500,400));
     44        JOptionPane pane = new JOptionPane(prefPanel, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
     45        JDialog dlg = pane.createDialog(Main.parent, tr("Preferences"));
     46        dlg.setResizable(true);
     47        dlg.setMinimumSize(new Dimension(500,400));
    4848
    49 //              if (dlg.getWidth() > 600)
    50 //                      dlg.setSize(600, dlg.getHeight());
    51 //              if (dlg.getHeight() > 600)
    52 //                      dlg.setSize(dlg.getWidth(),600);
     49//      if (dlg.getWidth() > 600)
     50//          dlg.setSize(600, dlg.getHeight());
     51//      if (dlg.getHeight() > 600)
     52//          dlg.setSize(dlg.getWidth(),600);
    5353
    54                 int JOSMWidth = Main.parent.getWidth();
    55                 int JOSMHeight = Main.parent.getHeight();
     54        int JOSMWidth = Main.parent.getWidth();
     55        int JOSMHeight = Main.parent.getHeight();
    5656
    57                 if (JOSMWidth > 2000 && JOSMWidth >  JOSMHeight * 2)
    58                         // don't center on horizontal span monitor configurations (yes, can be selfish sometimes)
    59                         JOSMWidth /= 2;
     57        if (JOSMWidth > 2000 && JOSMWidth >  JOSMHeight * 2)
     58            // don't center on horizontal span monitor configurations (yes, can be selfish sometimes)
     59            JOSMWidth /= 2;
    6060
    61                 int targetWidth = JOSMWidth / 2;
    62                 if (targetWidth < 600) targetWidth = 600;
    63                 if (targetWidth > 1200) targetWidth = 1200;
    64                 int targetHeight = (JOSMHeight * 3) / 4;
    65                 if (targetHeight < 600) targetHeight = 600;
    66                 if (targetHeight > 1200) targetHeight = 1200;
     61        int targetWidth = JOSMWidth / 2;
     62        if (targetWidth < 600) targetWidth = 600;
     63        if (targetWidth > 1200) targetWidth = 1200;
     64        int targetHeight = (JOSMHeight * 3) / 4;
     65        if (targetHeight < 600) targetHeight = 600;
     66        if (targetHeight > 1200) targetHeight = 1200;
    6767
    68                 int targetX = Main.parent.getX() + JOSMWidth / 2 - targetWidth / 2;
    69                 int targetY = Main.parent.getY() + JOSMHeight / 2 - targetHeight / 2;
     68        int targetX = Main.parent.getX() + JOSMWidth / 2 - targetWidth / 2;
     69        int targetY = Main.parent.getY() + JOSMHeight / 2 - targetHeight / 2;
    7070
    71                 dlg.setBounds(targetX, targetY, targetWidth, targetHeight);
     71        dlg.setBounds(targetX, targetY, targetWidth, targetHeight);
    7272
    73                 dlg.setVisible(true);
    74                 if (pane.getValue() instanceof Integer && (Integer)pane.getValue() == JOptionPane.OK_OPTION)
    75                         prefDlg.ok();
    76         }
     73        dlg.setVisible(true);
     74        if (pane.getValue() instanceof Integer && (Integer)pane.getValue() == JOptionPane.OK_OPTION)
     75            prefDlg.ok();
     76    }
    7777}
  • trunk/src/org/openstreetmap/josm/actions/RedoAction.java

    r1084 r1169  
    1717public class RedoAction extends JosmAction {
    1818
    19         /**
    20         * Construct the action with "Redo" as label.
    21         */
    22         public RedoAction() {
    23                 super(tr("Redo"), "redo", tr("Redo the last undone action."),
    24                 Shortcut.registerShortcut("system:redo", tr("Edit: {0}", tr("Redo")), KeyEvent.VK_Y, Shortcut.GROUP_MENU), true);
    25                 setEnabled(false);
    26         }
     19    /**
     20    * Construct the action with "Redo" as label.
     21    */
     22    public RedoAction() {
     23        super(tr("Redo"), "redo", tr("Redo the last undone action."),
     24        Shortcut.registerShortcut("system:redo", tr("Edit: {0}", tr("Redo")), KeyEvent.VK_Y, Shortcut.GROUP_MENU), true);
     25        setEnabled(false);
     26    }
    2727
    28         public void actionPerformed(ActionEvent e) {
    29                 if (Main.map == null)
    30                         return;
    31                 Main.map.repaint();
    32                 Main.main.undoRedo.redo();
    33         }
     28    public void actionPerformed(ActionEvent e) {
     29        if (Main.map == null)
     30            return;
     31        Main.map.repaint();
     32        Main.main.undoRedo.redo();
     33    }
    3434}
  • trunk/src/org/openstreetmap/josm/actions/RenameLayerAction.java

    r655 r1169  
    2121 * Action to rename an specific layer. Provides the option to rename the
    2222 * file, this layer was loaded from as well (if it was loaded from a file).
    23  * 
     23 *
    2424 * @author Imi
    2525 */
    2626public class RenameLayerAction extends AbstractAction {
    2727
    28         private File file;
    29         private Layer layer;
     28    private File file;
     29    private Layer layer;
    3030
    31         /**
    32         * @param file The file of the original location of this layer.
    33          *              If null, no possibility to "rename the file as well" is provided. 
    34         */
    35         public RenameLayerAction(File file, Layer layer) {
    36                 super(tr("Rename layer"), ImageProvider.get("dialogs", "edit"));
    37                 this.file = file;
    38                 this.layer = layer;
    39                 this.putValue("help", "Action/LayerRename");
    40         }
     31    /**
     32    * @param file The file of the original location of this layer.
     33     *      If null, no possibility to "rename the file as well" is provided.
     34    */
     35    public RenameLayerAction(File file, Layer layer) {
     36        super(tr("Rename layer"), ImageProvider.get("dialogs", "edit"));
     37        this.file = file;
     38        this.layer = layer;
     39        this.putValue("help", "Action/LayerRename");
     40    }
    4141
    42         public void actionPerformed(ActionEvent e) {
    43                 Box panel = Box.createVerticalBox();
    44                 final JTextField name = new JTextField(layer.name);
    45                 panel.add(name);
    46                 JCheckBox filerename = new JCheckBox(tr("Also rename the file"));
    47                 if (Main.applet) {
    48                         filerename.setEnabled(false);
    49                         filerename.setSelected(false);
    50                 } else {
    51                         panel.add(filerename);
    52                         filerename.setEnabled(file != null);
    53                 }
    54                 if (filerename.isEnabled())
    55                         filerename.setSelected(Main.pref.getBoolean("layer.rename-file", true));
     42    public void actionPerformed(ActionEvent e) {
     43        Box panel = Box.createVerticalBox();
     44        final JTextField name = new JTextField(layer.name);
     45        panel.add(name);
     46        JCheckBox filerename = new JCheckBox(tr("Also rename the file"));
     47        if (Main.applet) {
     48            filerename.setEnabled(false);
     49            filerename.setSelected(false);
     50        } else {
     51            panel.add(filerename);
     52            filerename.setEnabled(file != null);
     53        }
     54        if (filerename.isEnabled())
     55            filerename.setSelected(Main.pref.getBoolean("layer.rename-file", true));
    5656
    57                 final JOptionPane optionPane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION){
    58                         @Override public void selectInitialValue() {
    59                                 name.requestFocusInWindow();
    60                                 name.selectAll();
    61                         }
    62                 };
    63                 final JDialog dlg = optionPane.createDialog(Main.parent, tr("Rename layer"));
    64                 dlg.setVisible(true);
     57        final JOptionPane optionPane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION){
     58            @Override public void selectInitialValue() {
     59                name.requestFocusInWindow();
     60                name.selectAll();
     61            }
     62        };
     63        final JDialog dlg = optionPane.createDialog(Main.parent, tr("Rename layer"));
     64        dlg.setVisible(true);
    6565
    66                 Object answer = optionPane.getValue();
    67                 if (answer == null || answer == JOptionPane.UNINITIALIZED_VALUE ||
    68                                 (answer instanceof Integer && (Integer)answer != JOptionPane.OK_OPTION)) {
    69                         return;
    70                 }
     66        Object answer = optionPane.getValue();
     67        if (answer == null || answer == JOptionPane.UNINITIALIZED_VALUE ||
     68                (answer instanceof Integer && (Integer)answer != JOptionPane.OK_OPTION)) {
     69            return;
     70        }
    7171
    72                 String nameText = name.getText();
    73                 if (filerename.isEnabled()) {
    74                         Main.pref.put("layer.rename-file", filerename.isSelected());
    75                         if (filerename.isSelected()) {
    76                                 String newname = nameText;
    77                                 if (newname.indexOf("/") == -1 && newname.indexOf("\\") == -1)
    78                                         newname = file.getParent() + File.separator + newname;
    79                                 String oldname = file.getName();
    80                                 if (name.getText().indexOf('.') == -1 && oldname.indexOf('.') >= 0)
    81                                         newname += oldname.substring(oldname.lastIndexOf('.'));
    82                                 File newFile = new File(newname);
    83                                 if (file.renameTo(newFile)) {
    84                                         layer.associatedFile = newFile;
    85                                         nameText = newFile.getName();
    86                                 } else {
    87                                         JOptionPane.showMessageDialog(Main.parent, tr("Could not rename the file \"{0}\".", file.getPath()));
    88                                         return;
    89                                 }
    90                         }
    91                 }
    92                 layer.name = nameText;
    93                 Main.parent.repaint();
    94         }
     72        String nameText = name.getText();
     73        if (filerename.isEnabled()) {
     74            Main.pref.put("layer.rename-file", filerename.isSelected());
     75            if (filerename.isSelected()) {
     76                String newname = nameText;
     77                if (newname.indexOf("/") == -1 && newname.indexOf("\\") == -1)
     78                    newname = file.getParent() + File.separator + newname;
     79                String oldname = file.getName();
     80                if (name.getText().indexOf('.') == -1 && oldname.indexOf('.') >= 0)
     81                    newname += oldname.substring(oldname.lastIndexOf('.'));
     82                File newFile = new File(newname);
     83                if (file.renameTo(newFile)) {
     84                    layer.associatedFile = newFile;
     85                    nameText = newFile.getName();
     86                } else {
     87                    JOptionPane.showMessageDialog(Main.parent, tr("Could not rename the file \"{0}\".", file.getPath()));
     88                    return;
     89                }
     90            }
     91        }
     92        layer.name = nameText;
     93        Main.parent.repaint();
     94    }
    9595}
  • trunk/src/org/openstreetmap/josm/actions/ReverseWayAction.java

    r1084 r1169  
    2828public final class ReverseWayAction extends JosmAction {
    2929
    30         public ReverseWayAction() {
    31                 super(tr("Reverse ways"), "wayflip", tr("Reverse the direction of all selected ways."),
    32                 Shortcut.registerShortcut("tools:reverse", tr("Tool: {0}", tr("Reverse ways")), KeyEvent.VK_R, Shortcut.GROUP_EDIT), true);
    33         }
     30    public ReverseWayAction() {
     31        super(tr("Reverse ways"), "wayflip", tr("Reverse the direction of all selected ways."),
     32        Shortcut.registerShortcut("tools:reverse", tr("Tool: {0}", tr("Reverse ways")), KeyEvent.VK_R, Shortcut.GROUP_EDIT), true);
     33    }
    3434
    35         public void actionPerformed(ActionEvent e) {
    36                 final Collection<Way> sel = new LinkedList<Way>();
    37                 new Visitor() {
    38                         public void visit(Node n) {
    39                         }
     35    public void actionPerformed(ActionEvent e) {
     36        final Collection<Way> sel = new LinkedList<Way>();
     37        new Visitor() {
     38            public void visit(Node n) {
     39            }
    4040
    41                         public void visit(Way w) {
    42                                 sel.add(w);
    43                         }
     41            public void visit(Way w) {
     42                sel.add(w);
     43            }
    4444
    45                         public void visit(Relation e) {
    46                         }
     45            public void visit(Relation e) {
     46            }
    4747
    48                         public void visitAll() {
    49                                 for (OsmPrimitive osm : Main.ds.getSelected())
    50                                         osm.visit(this);
    51                         }
    52                 }.visitAll();
     48            public void visitAll() {
     49                for (OsmPrimitive osm : Main.ds.getSelected())
     50                    osm.visit(this);
     51            }
     52        }.visitAll();
    5353
    54                 if (sel.isEmpty()) {
    55                         JOptionPane.showMessageDialog(Main.parent,
    56                                 tr("Please select at least one way."));
    57                         return;
    58                 }
     54        if (sel.isEmpty()) {
     55            JOptionPane.showMessageDialog(Main.parent,
     56                    tr("Please select at least one way."));
     57            return;
     58        }
    5959
    60                 boolean propertiesUpdated = false;
    61                 ReverseWayTagCorrector reverseWayTagCorrector = new ReverseWayTagCorrector();
    62                 Collection<Command> c = new LinkedList<Command>();
    63                 for (Way w : sel) {
    64                         Way wnew = new Way(w);
    65                         Collections.reverse(wnew.nodes);
    66                         if (Main.pref.getBoolean("tag-correction.reverse-way", true)) {
    67                                 try
    68                                 {
    69                                         final Collection<Command> changePropertyCommands = reverseWayTagCorrector.execute(wnew);
    70                                         propertiesUpdated = propertiesUpdated
    71                                         || (changePropertyCommands != null && !changePropertyCommands.isEmpty());
    72                                         c.addAll(changePropertyCommands);
    73                                 }
    74                                 catch(UserCancelException ex)
    75                                 {
    76                                         return;
    77                                 }
    78                         }
    79                         c.add(new ChangeCommand(w, wnew));
    80                 }
    81                 Main.main.undoRedo.add(new SequenceCommand(tr("Reverse ways"), c));
    82                 if (propertiesUpdated)
    83                         DataSet.fireSelectionChanged(Main.ds.getSelected());
    84                 Main.map.repaint();
    85         }
     60        boolean propertiesUpdated = false;
     61        ReverseWayTagCorrector reverseWayTagCorrector = new ReverseWayTagCorrector();
     62        Collection<Command> c = new LinkedList<Command>();
     63        for (Way w : sel) {
     64            Way wnew = new Way(w);
     65            Collections.reverse(wnew.nodes);
     66            if (Main.pref.getBoolean("tag-correction.reverse-way", true)) {
     67                try
     68                {
     69                    final Collection<Command> changePropertyCommands = reverseWayTagCorrector.execute(wnew);
     70                    propertiesUpdated = propertiesUpdated
     71                        || (changePropertyCommands != null && !changePropertyCommands.isEmpty());
     72                    c.addAll(changePropertyCommands);
     73                }
     74                catch(UserCancelException ex)
     75                {
     76                    return;
     77                }
     78            }
     79            c.add(new ChangeCommand(w, wnew));
     80        }
     81        Main.main.undoRedo.add(new SequenceCommand(tr("Reverse ways"), c));
     82        if (propertiesUpdated)
     83            DataSet.fireSelectionChanged(Main.ds.getSelected());
     84        Main.map.repaint();
     85    }
    8686}
  • trunk/src/org/openstreetmap/josm/actions/SaveAction.java

    r1084 r1169  
    1919public class SaveAction extends SaveActionBase {
    2020
    21         /**
    22         * Construct the action with "Save" as label.
    23         * @param layer Save this layer.
    24         */
    25         public SaveAction(Layer layer) {
    26                 super(tr("Save"), "save", tr("Save the current data."),
    27                 Shortcut.registerShortcut("system:save", tr("File: {0}", tr("Save")), KeyEvent.VK_S, Shortcut.GROUP_MENU), layer);
    28         }
     21    /**
     22    * Construct the action with "Save" as label.
     23    * @param layer Save this layer.
     24    */
     25    public SaveAction(Layer layer) {
     26        super(tr("Save"), "save", tr("Save the current data."),
     27        Shortcut.registerShortcut("system:save", tr("File: {0}", tr("Save")), KeyEvent.VK_S, Shortcut.GROUP_MENU), layer);
     28    }
    2929
    30         @Override public File getFile(Layer layer) {
    31                 if (layer instanceof OsmDataLayer) {
    32                         File f = ((OsmDataLayer)layer).associatedFile;
    33                         if (f != null) {
    34                                 return f;
    35                         }
    36                 }
    37                 if (layer instanceof GpxLayer) {
    38                         File f = ((GpxLayer)layer).data.storageFile;
    39                         if (f != null) {
    40                                 return f;
    41                         }
    42                 }
    43                 return openFileDialog(layer);
    44         }
     30    @Override public File getFile(Layer layer) {
     31        if (layer instanceof OsmDataLayer) {
     32            File f = ((OsmDataLayer)layer).associatedFile;
     33            if (f != null) {
     34                return f;
     35            }
     36        }
     37        if (layer instanceof GpxLayer) {
     38            File f = ((GpxLayer)layer).data.storageFile;
     39            if (f != null) {
     40                return f;
     41            }
     42        }
     43        return openFileDialog(layer);
     44    }
    4545}
  • trunk/src/org/openstreetmap/josm/actions/SaveActionBase.java

    r1084 r1169  
    2626public abstract class SaveActionBase extends DiskAccessAction {
    2727
    28         private Layer layer;
    29 
    30         public SaveActionBase(String name, String iconName, String tooltip, Shortcut shortcut, Layer layer) {
    31                 super(name, iconName, tooltip, shortcut);
    32                 this.layer = layer;
    33         }
    34 
    35         @Deprecated
    36         public SaveActionBase(String name, String iconName, String tooltip, int shortcut, int modifiers, Layer layer) {
    37                 super(name, iconName, tooltip, shortcut, modifiers);
    38                 this.layer = layer;
    39         }
    40 
    41         public void actionPerformed(ActionEvent e) {
    42                 Layer layer = this.layer;
    43                 if (layer == null && Main.map != null && (Main.map.mapView.getActiveLayer() instanceof OsmDataLayer
    44                                 || Main.map.mapView.getActiveLayer() instanceof GpxLayer))
    45                         layer = Main.map.mapView.getActiveLayer();
    46                 if (layer == null)
    47                         layer = Main.main.editLayer();
    48 
    49                 if (!checkSaveConditions(layer))
    50                         return;
    51 
    52 
    53                 File file = getFile(layer);
    54                 if (file == null)
    55                         return;
    56 
    57                 save(file, layer);
    58 
    59                 layer.name = file.getName();
    60                 layer.associatedFile = file;
    61                 Main.parent.repaint();
    62         }
    63 
    64         protected abstract File getFile(Layer layer);
    65 
    66         /**
    67         * Checks whether it is ok to launch a save (whether we have data,
    68         * there is no conflict etc.)
    69         * @return <code>true</code>, if it is safe to save.
    70         */
    71         public boolean checkSaveConditions(Layer layer) {
    72                 if (layer == null) {
    73                         JOptionPane.showMessageDialog(Main.parent, tr("Internal Error: cannot check conditions for no layer. Please report this as a bug."));
    74                         return false;
    75                 }
    76                 if (Main.map == null) {
    77                         JOptionPane.showMessageDialog(Main.parent, tr("No document open so nothing to save."));
    78                         return false;
    79                 }
    80 
    81                 if (layer instanceof OsmDataLayer && isDataSetEmpty((OsmDataLayer)layer) && JOptionPane.NO_OPTION == JOptionPane.showConfirmDialog(Main.parent,tr("The document contains no data. Save anyway?"), tr("Empty document"), JOptionPane.YES_NO_OPTION)) {
    82                         return false;
    83                 }
    84                 if (layer instanceof GpxLayer && ((GpxLayer)layer).data == null) {
    85                         return false;
    86                 }
    87                 if (!Main.map.conflictDialog.conflicts.isEmpty()) {
    88                         int answer = JOptionPane.showConfirmDialog(Main.parent,
    89                                         tr("There are unresolved conflicts. Conflicts will not be saved and handled as if you rejected all. Continue?"),tr("Conflicts"), JOptionPane.YES_NO_OPTION);
    90                         if (answer != JOptionPane.YES_OPTION)
    91                                 return false;
    92                 }
    93                 return true;
    94         }
    95 
    96         public static File openFileDialog(Layer layer) {
    97                 JFileChooser fc = createAndOpenFileChooser(false, false, layer instanceof GpxLayer ? tr("Save GPX file") : tr("Save OSM file"));
    98                 if (fc == null)
    99                         return null;
    100 
    101                 File file = fc.getSelectedFile();
    102 
    103                 String fn = file.getPath();
    104                 if (fn.indexOf('.') == -1) {
    105                         FileFilter ff = fc.getFileFilter();
    106                         if (ff instanceof ExtensionFileFilter)
    107                                 fn += "." + ((ExtensionFileFilter)ff).defaultExtension;
    108                         else if (layer instanceof GpxLayer)
    109                                 fn += ".gpx";
    110                         else
    111                                 fn += ".osm";
    112                         file = new File(fn);
    113                 }
    114                 return file;
    115         }
    116 
    117         private static void copy(File src, File dst) throws IOException {
    118                 FileInputStream srcStream;
    119                 FileOutputStream dstStream;
    120                 try {
    121                         srcStream = new FileInputStream(src);
    122                         dstStream = new FileOutputStream(dst);
    123                 } catch (FileNotFoundException e) {
    124                         JOptionPane.showMessageDialog(Main.parent, tr("Could not back up file.")+"\n"+e.getMessage());
    125                         return;
    126                 }
    127                 byte buf[] = new byte[1<<16];
    128                 int len;
    129                 while ((len = srcStream.read(buf)) != -1) {
    130                         dstStream.write(buf, 0, len);
    131                 }
    132                 srcStream.close();
    133                 dstStream.close();
    134         }
    135 
    136         public static void save(File file, Layer layer) {
    137                 if (layer instanceof GpxLayer) {
    138                         save(file, (GpxLayer)layer);
    139                         ((GpxLayer)layer).data.storageFile = file;
    140                 } else if (layer instanceof OsmDataLayer) {
    141                         save(file, (OsmDataLayer)layer);
    142                 }
    143         }
    144 
    145         public static void save(File file, OsmDataLayer layer) {
    146                 File tmpFile = null;
    147                 try {
    148                         if (ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(file.getPath())) {
    149                                 GpxExportAction.exportGpx(file, layer);
    150                         } else if (ExtensionFileFilter.filters[ExtensionFileFilter.OSM].acceptName(file.getPath())) {
    151                                 // use a tmp file because if something errors out in the
    152                                 // process of writing the file, we might just end up with
    153                                 // a truncated file.  That can destroy lots of work.
    154                                 if (file.exists()) {
    155                                         tmpFile = new File(file.getPath() + "~");
    156                                         copy(file, tmpFile);
    157                                 }
    158                                 OsmWriter.output(new FileOutputStream(file), new OsmWriter.All(layer.data, false));
    159                                 if (!Main.pref.getBoolean("save.keepbackup") && (tmpFile != null))
    160                                         tmpFile.delete();
    161                         } else {
    162                                 JOptionPane.showMessageDialog(Main.parent, tr("Unknown file extension."));
    163                                 return;
    164                         }
    165                         layer.cleanData(null, false);
    166                 } catch (IOException e) {
    167                         e.printStackTrace();
    168                         JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while saving.")+"\n"+e.getMessage());
    169 
    170                         try {
    171                                 // if the file save failed, then the tempfile will not
    172                                 // be deleted.  So, restore the backup if we made one.
    173                                 if (tmpFile != null && tmpFile.exists()) {
    174                                         copy(tmpFile, file);
    175                                 }
    176                         } catch (IOException e2) {
    177                                 e2.printStackTrace();
    178                                 JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while restoring backup file.")+"\n"+e2.getMessage());
    179                         }
    180                 }
    181         }
    182 
    183         public static void save(File file, GpxLayer layer) {
    184                 File tmpFile = null;
    185                 try {
    186                         if (ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(file.getPath())) {
    187 
    188                                 // use a tmp file because if something errors out in the
    189                                 // process of writing the file, we might just end up with
    190                                 // a truncated file.  That can destroy lots of work.
    191                                 if (file.exists()) {
    192                                         tmpFile = new File(file.getPath() + "~");
    193                                         copy(file, tmpFile);
    194                                 }
    195                                 FileOutputStream fo = new FileOutputStream(file);
    196                                 new GpxWriter(fo).write(layer.data);
    197                                 fo.flush();
    198                                 fo.close();
    199 
    200                                 if (!Main.pref.getBoolean("save.keepbackup") && (tmpFile != null)) {
    201                                         tmpFile.delete();
    202                                 }
    203                         } else {
    204                                 JOptionPane.showMessageDialog(Main.parent, tr("Unknown file extension."));
    205                                 return;
    206                         }
    207                 } catch (IOException e) {
    208                         e.printStackTrace();
    209                         JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while saving.")+"\n"+e.getMessage());
    210                 }
    211                 try {
    212                         // if the file save failed, then the tempfile will not
    213                         // be deleted.  So, restore the backup if we made one.
    214                         if (tmpFile != null && tmpFile.exists()) {
    215                                 copy(tmpFile, file);
    216                         }
    217                 } catch (IOException e) {
    218                         e.printStackTrace();
    219                         JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while restoring backup file.")+"\n"+e.getMessage());
    220                 }
    221         }
    222 
    223         /**
    224         * Check the data set if it would be empty on save. It is empty, if it contains
    225         * no objects (after all objects that are created and deleted without being
    226         * transfered to the server have been removed).
    227         *
    228         * @return <code>true</code>, if a save result in an empty data set.
    229         */
    230         private boolean isDataSetEmpty(OsmDataLayer layer) {
    231                 for (OsmPrimitive osm : layer.data.allNonDeletedPrimitives())
    232                         if (!osm.deleted || osm.id > 0)
    233                                 return false;
    234                 return true;
    235         }
     28    private Layer layer;
     29
     30    public SaveActionBase(String name, String iconName, String tooltip, Shortcut shortcut, Layer layer) {
     31        super(name, iconName, tooltip, shortcut);
     32        this.layer = layer;
     33    }
     34
     35    @Deprecated
     36    public SaveActionBase(String name, String iconName, String tooltip, int shortcut, int modifiers, Layer layer) {
     37        super(name, iconName, tooltip, shortcut, modifiers);
     38        this.layer = layer;
     39    }
     40
     41    public void actionPerformed(ActionEvent e) {
     42        Layer layer = this.layer;
     43        if (layer == null && Main.map != null && (Main.map.mapView.getActiveLayer() instanceof OsmDataLayer
     44                || Main.map.mapView.getActiveLayer() instanceof GpxLayer))
     45            layer = Main.map.mapView.getActiveLayer();
     46        if (layer == null)
     47            layer = Main.main.editLayer();
     48
     49        if (!checkSaveConditions(layer))
     50            return;
     51
     52
     53        File file = getFile(layer);
     54        if (file == null)
     55            return;
     56
     57        save(file, layer);
     58
     59        layer.name = file.getName();
     60        layer.associatedFile = file;
     61        Main.parent.repaint();
     62    }
     63
     64    protected abstract File getFile(Layer layer);
     65
     66    /**
     67    * Checks whether it is ok to launch a save (whether we have data,
     68    * there is no conflict etc.)
     69    * @return <code>true</code>, if it is safe to save.
     70    */
     71    public boolean checkSaveConditions(Layer layer) {
     72        if (layer == null) {
     73            JOptionPane.showMessageDialog(Main.parent, tr("Internal Error: cannot check conditions for no layer. Please report this as a bug."));
     74            return false;
     75        }
     76        if (Main.map == null) {
     77            JOptionPane.showMessageDialog(Main.parent, tr("No document open so nothing to save."));
     78            return false;
     79        }
     80
     81        if (layer instanceof OsmDataLayer && isDataSetEmpty((OsmDataLayer)layer) && JOptionPane.NO_OPTION == JOptionPane.showConfirmDialog(Main.parent,tr("The document contains no data. Save anyway?"), tr("Empty document"), JOptionPane.YES_NO_OPTION)) {
     82            return false;
     83        }
     84        if (layer instanceof GpxLayer && ((GpxLayer)layer).data == null) {
     85            return false;
     86        }
     87        if (!Main.map.conflictDialog.conflicts.isEmpty()) {
     88            int answer = JOptionPane.showConfirmDialog(Main.parent,
     89                    tr("There are unresolved conflicts. Conflicts will not be saved and handled as if you rejected all. Continue?"),tr("Conflicts"), JOptionPane.YES_NO_OPTION);
     90            if (answer != JOptionPane.YES_OPTION)
     91                return false;
     92        }
     93        return true;
     94    }
     95
     96    public static File openFileDialog(Layer layer) {
     97        JFileChooser fc = createAndOpenFileChooser(false, false, layer instanceof GpxLayer ? tr("Save GPX file") : tr("Save OSM file"));
     98        if (fc == null)
     99            return null;
     100
     101        File file = fc.getSelectedFile();
     102
     103        String fn = file.getPath();
     104        if (fn.indexOf('.') == -1) {
     105            FileFilter ff = fc.getFileFilter();
     106            if (ff instanceof ExtensionFileFilter)
     107                fn += "." + ((ExtensionFileFilter)ff).defaultExtension;
     108            else if (layer instanceof GpxLayer)
     109                fn += ".gpx";
     110            else
     111                fn += ".osm";
     112            file = new File(fn);
     113        }
     114        return file;
     115    }
     116
     117    private static void copy(File src, File dst) throws IOException {
     118        FileInputStream srcStream;
     119        FileOutputStream dstStream;
     120        try {
     121            srcStream = new FileInputStream(src);
     122            dstStream = new FileOutputStream(dst);
     123        } catch (FileNotFoundException e) {
     124            JOptionPane.showMessageDialog(Main.parent, tr("Could not back up file.")+"\n"+e.getMessage());
     125            return;
     126        }
     127        byte buf[] = new byte[1<<16];
     128        int len;
     129        while ((len = srcStream.read(buf)) != -1) {
     130            dstStream.write(buf, 0, len);
     131        }
     132        srcStream.close();
     133        dstStream.close();
     134    }
     135
     136    public static void save(File file, Layer layer) {
     137        if (layer instanceof GpxLayer) {
     138            save(file, (GpxLayer)layer);
     139            ((GpxLayer)layer).data.storageFile = file;
     140        } else if (layer instanceof OsmDataLayer) {
     141            save(file, (OsmDataLayer)layer);
     142        }
     143    }
     144
     145    public static void save(File file, OsmDataLayer layer) {
     146        File tmpFile = null;
     147        try {
     148            if (ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(file.getPath())) {
     149                GpxExportAction.exportGpx(file, layer);
     150            } else if (ExtensionFileFilter.filters[ExtensionFileFilter.OSM].acceptName(file.getPath())) {
     151                // use a tmp file because if something errors out in the
     152                // process of writing the file, we might just end up with
     153                // a truncated file.  That can destroy lots of work.
     154                if (file.exists()) {
     155                    tmpFile = new File(file.getPath() + "~");
     156                    copy(file, tmpFile);
     157                }
     158                OsmWriter.output(new FileOutputStream(file), new OsmWriter.All(layer.data, false));
     159                if (!Main.pref.getBoolean("save.keepbackup") && (tmpFile != null))
     160                    tmpFile.delete();
     161            } else {
     162                JOptionPane.showMessageDialog(Main.parent, tr("Unknown file extension."));
     163                return;
     164            }
     165            layer.cleanData(null, false);
     166        } catch (IOException e) {
     167            e.printStackTrace();
     168            JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while saving.")+"\n"+e.getMessage());
     169
     170            try {
     171                // if the file save failed, then the tempfile will not
     172                // be deleted.  So, restore the backup if we made one.
     173                if (tmpFile != null && tmpFile.exists()) {
     174                    copy(tmpFile, file);
     175                }
     176            } catch (IOException e2) {
     177                e2.printStackTrace();
     178                JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while restoring backup file.")+"\n"+e2.getMessage());
     179            }
     180        }
     181    }
     182
     183    public static void save(File file, GpxLayer layer) {
     184        File tmpFile = null;
     185        try {
     186            if (ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(file.getPath())) {
     187
     188                // use a tmp file because if something errors out in the
     189                // process of writing the file, we might just end up with
     190                // a truncated file.  That can destroy lots of work.
     191                if (file.exists()) {
     192                    tmpFile = new File(file.getPath() + "~");
     193                    copy(file, tmpFile);
     194                }
     195                FileOutputStream fo = new FileOutputStream(file);
     196                new GpxWriter(fo).write(layer.data);
     197                fo.flush();
     198                fo.close();
     199
     200                if (!Main.pref.getBoolean("save.keepbackup") && (tmpFile != null)) {
     201                    tmpFile.delete();
     202                }
     203            } else {
     204                JOptionPane.showMessageDialog(Main.parent, tr("Unknown file extension."));
     205                return;
     206            }
     207        } catch (IOException e) {
     208            e.printStackTrace();
     209            JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while saving.")+"\n"+e.getMessage());
     210        }
     211        try {
     212            // if the file save failed, then the tempfile will not
     213            // be deleted.  So, restore the backup if we made one.
     214            if (tmpFile != null && tmpFile.exists()) {
     215                copy(tmpFile, file);
     216            }
     217        } catch (IOException e) {
     218            e.printStackTrace();
     219            JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while restoring backup file.")+"\n"+e.getMessage());
     220        }
     221    }
     222
     223    /**
     224    * Check the data set if it would be empty on save. It is empty, if it contains
     225    * no objects (after all objects that are created and deleted without being
     226    * transfered to the server have been removed).
     227    *
     228    * @return <code>true</code>, if a save result in an empty data set.
     229    */
     230    private boolean isDataSetEmpty(OsmDataLayer layer) {
     231        for (OsmPrimitive osm : layer.data.allNonDeletedPrimitives())
     232            if (!osm.deleted || osm.id > 0)
     233                return false;
     234        return true;
     235    }
    236236}
  • trunk/src/org/openstreetmap/josm/actions/SaveAsAction.java

    r1084 r1169  
    1717public class SaveAsAction extends SaveActionBase {
    1818
    19         /**
    20         * Construct the action with "Save" as label.
    21         * @param layer Save this layer.
    22         */
    23         public SaveAsAction(Layer layer) {
    24                 super(tr("Save as ..."), "save_as", tr("Save the current data to a new file."),
    25                 Shortcut.registerShortcut("system:saveas", tr("File: {0}", tr("Save as ...")), KeyEvent.VK_S, Shortcut.GROUP_MENU, Shortcut.SHIFT_DEFAULT), layer);
    26         }
     19    /**
     20    * Construct the action with "Save" as label.
     21    * @param layer Save this layer.
     22    */
     23    public SaveAsAction(Layer layer) {
     24        super(tr("Save as ..."), "save_as", tr("Save the current data to a new file."),
     25        Shortcut.registerShortcut("system:saveas", tr("File: {0}", tr("Save as ...")), KeyEvent.VK_S, Shortcut.GROUP_MENU, Shortcut.SHIFT_DEFAULT), layer);
     26    }
    2727
    28         @Override protected File getFile(Layer layer) {
    29                 return openFileDialog(layer);
    30         }
     28    @Override protected File getFile(Layer layer) {
     29        return openFileDialog(layer);
     30    }
    3131}
  • trunk/src/org/openstreetmap/josm/actions/SelectAllAction.java

    r1084 r1169  
    1212public class SelectAllAction extends JosmAction {
    1313
    14         public SelectAllAction() {
    15                 super(tr("Select All"),"selectall", tr("Select all undeleted objects in the data layer. This selects incomplete objects too."),
    16                 Shortcut.registerShortcut("system:selectall", tr("Edit: {0}", tr("Select All")), KeyEvent.VK_A, Shortcut.GROUP_MENU), true);
    17         }
     14    public SelectAllAction() {
     15        super(tr("Select All"),"selectall", tr("Select all undeleted objects in the data layer. This selects incomplete objects too."),
     16        Shortcut.registerShortcut("system:selectall", tr("Edit: {0}", tr("Select All")), KeyEvent.VK_A, Shortcut.GROUP_MENU), true);
     17    }
    1818
    19         public void actionPerformed(ActionEvent e) {
    20                 Main.ds.setSelected(Main.ds.allNonDeletedPhysicalPrimitives());
    21         }
     19    public void actionPerformed(ActionEvent e) {
     20        Main.ds.setSelected(Main.ds.allNonDeletedPhysicalPrimitives());
     21    }
    2222}
  • trunk/src/org/openstreetmap/josm/actions/SplitWayAction.java

    r1084 r1169  
    4444public class SplitWayAction extends JosmAction implements SelectionChangedListener {
    4545
    46         private Way selectedWay;
    47         private List<Node> selectedNodes;
    48 
    49         /**
    50         * Create a new SplitWayAction.
    51         */
    52         public SplitWayAction() {
    53                 super(tr("Split Way"), "splitway", tr("Split a way at the selected node."),
    54                 Shortcut.registerShortcut("tools:splitway", tr("Tool: {0}", tr("Split Way")), KeyEvent.VK_P, Shortcut.GROUP_EDIT), true);
    55                 DataSet.selListeners.add(this);
    56         }
    57 
    58         /**
    59         * Called when the action is executed.
    60         *
    61         * This method performs an expensive check whether the selection clearly defines one
    62         * of the split actions outlined above, and if yes, calls the splitWay method.
    63         */
    64         public void actionPerformed(ActionEvent e) {
    65 
    66                 Collection<OsmPrimitive> selection = Main.ds.getSelected();
    67 
    68                 if (!checkSelection(selection)) {
    69                         JOptionPane.showMessageDialog(Main.parent, tr("The current selection cannot be used for splitting."));
    70                         return;
    71                 }
    72 
    73                 selectedWay = null;
    74                 selectedNodes = null;
    75 
    76                 Visitor splitVisitor = new Visitor(){
    77                         public void visit(Node n) {
    78                                 if (selectedNodes == null)
    79                                         selectedNodes = new LinkedList<Node>();
    80                                 selectedNodes.add(n);
    81             }
    82                         public void visit(Way w) {
    83                                 selectedWay = w;
    84             }
    85                         public void visit(Relation e) {
    86                                 // enties are not considered
    87                         }
    88                 };
    89 
    90                 for (OsmPrimitive p : selection)
    91                         p.visit(splitVisitor);
    92 
    93                 // If only nodes are selected, try to guess which way to split. This works if there
    94                 // is exactly one way that all nodes are part of.
    95                 if (selectedWay == null && selectedNodes != null) {
    96                         HashMap<Way, Integer> wayOccurenceCounter = new HashMap<Way, Integer>();
    97                         for (Node n : selectedNodes) {
    98                                 for (Way w : Main.ds.ways) {
    99                                         if (w.deleted || w.incomplete) continue;
    100                                         int last = w.nodes.size()-1;
    101                                         if(last <= 0) continue; // zero or one node ways
    102                                         Boolean circular = w.nodes.get(0).equals(w.nodes.get(last));
    103                                         int i = 0;
    104                                         for (Node wn : w.nodes) {
    105                                                 if ((circular || (i > 0 && i < last)) && n.equals(wn)) {
    106                                                         Integer old = wayOccurenceCounter.get(w);
    107                                                         wayOccurenceCounter.put(w, (old == null) ? 1 : old+1);
    108                                                         break;
    109                                                 }
    110                                                 i++;
    111                                         }
    112                                 }
    113                         }
    114                         if (wayOccurenceCounter.isEmpty()) {
    115                                 JOptionPane.showMessageDialog(Main.parent,
    116                                                 trn("The selected node is no inner part of any way.",
    117                                                                 "The selected nodes are no inner part of any way.", selectedNodes.size()));
    118                                 return;
    119                         }
    120 
    121                         for (Entry<Way, Integer> entry : wayOccurenceCounter.entrySet()) {
    122                                 if (entry.getValue().equals(selectedNodes.size())) {
    123                                         if (selectedWay != null) {
    124                                                 JOptionPane.showMessageDialog(Main.parent, tr("There is more than one way using the node(s) you selected. Please select the way also."));
    125                                                 return;
    126                                         }
    127                                         selectedWay = entry.getKey();
    128                                 }
    129                         }
    130 
    131                         if (selectedWay == null) {
    132                                 JOptionPane.showMessageDialog(Main.parent, tr("The selected nodes do not share the same way."));
    133                                 return;
    134                         }
    135 
    136                 // If a way and nodes are selected, verify that the nodes are part of the way.
    137                 } else if (selectedWay != null && selectedNodes != null) {
    138 
    139                         HashSet<Node> nds = new HashSet<Node>(selectedNodes);
    140                         for (Node n : selectedWay.nodes) {
    141                                 nds.remove(n);
    142                         }
    143                         if (!nds.isEmpty()) {
    144                                 JOptionPane.showMessageDialog(Main.parent,
    145                                                 trn("The selected way does not contain the selected node.",
    146                                                                 "The selected way does not contain all the selected nodes.", selectedNodes.size()));
    147                                 return;
    148                         }
    149                 }
    150 
    151                 // and then do the work.
    152                 splitWay();
    153         }
    154 
    155         /**
    156         * Checks if the selection consists of something we can work with.
    157         * Checks only if the number and type of items selected looks good;
    158         * does not check whether the selected items are really a valid
    159         * input for splitting (this would be too expensive to be carried
    160         * out from the selectionChanged listener).
    161         */
    162         private boolean checkSelection(Collection<? extends OsmPrimitive> selection) {
    163                 boolean way = false;
    164                 boolean node = false;
    165                 for (OsmPrimitive p : selection) {
    166                         if (p instanceof Way && !way) {
    167                                 way = true;
    168                         } else if (p instanceof Node) {
    169                                 node = true;
    170                         } else {
    171                                 return false;
    172                 }
    173                 }
    174                 return node;
    175         }
    176 
    177         /**
    178         * Split a way into two or more parts, starting at a selected node.
    179         */
    180         private void splitWay() {
    181                 // We take our way's list of nodes and copy them to a way chunk (a
    182                 // list of nodes).  Whenever we stumble upon a selected node, we start
    183                 // a new way chunk.
    184 
    185                 Set<Node> nodeSet = new HashSet<Node>(selectedNodes);
    186                 List<List<Node>> wayChunks = new LinkedList<List<Node>>();
    187                 List<Node> currentWayChunk = new ArrayList<Node>();
    188                 wayChunks.add(currentWayChunk);
    189 
    190                 Iterator<Node> it = selectedWay.nodes.iterator();
    191                 while (it.hasNext()) {
    192                         Node currentNode = it.next();
    193                         boolean atEndOfWay = currentWayChunk.isEmpty() || !it.hasNext();
    194                         currentWayChunk.add(currentNode);
    195                         if (nodeSet.contains(currentNode) && !atEndOfWay) {
    196                                 currentWayChunk = new ArrayList<Node>();
    197                                 currentWayChunk.add(currentNode);
    198                                 wayChunks.add(currentWayChunk);
    199                         }
    200                 }
    201 
    202                 // Handle circular ways specially.
    203                 // If you split at a circular way at two nodes, you just want to split
    204                 // it at these points, not also at the former endpoint.
    205                 // So if the last node is the same first node, join the last and the
    206                 // first way chunk.
    207                 List<Node> lastWayChunk = wayChunks.get(wayChunks.size() - 1);
    208                 if (wayChunks.size() >= 2
    209                                 && wayChunks.get(0).get(0) == lastWayChunk.get(lastWayChunk.size() - 1)
    210                                 && !nodeSet.contains(wayChunks.get(0).get(0))) {
    211                         if (wayChunks.size() == 2) {
    212                                 JOptionPane.showMessageDialog(Main.parent, tr("You must select two or more nodes to split a circular way."));
    213                                 return;
    214                         }
    215                         lastWayChunk.remove(lastWayChunk.size() - 1);
    216                         lastWayChunk.addAll(wayChunks.get(0));
    217                         wayChunks.remove(wayChunks.size() - 1);
    218                         wayChunks.set(0, lastWayChunk);
    219                 }
    220 
    221                 if (wayChunks.size() < 2) {
    222                         if(wayChunks.get(0).get(0) == wayChunks.get(0).get(wayChunks.get(0).size()-1))
    223                                 JOptionPane.showMessageDialog(Main.parent, tr("You must select two or more nodes to split a circular way."));
    224                         else
    225                                 JOptionPane.showMessageDialog(Main.parent, tr("The way cannot be split at the selected nodes. (Hint: Select nodes in the middle of the way.)"));
    226                         return;
    227                 }
    228                 //Main.debug("wayChunks.size(): " + wayChunks.size());
    229                 //Main.debug("way id: " + selectedWay.id);
    230 
    231                 // build a list of commands, and also a new selection list
    232                 Collection<Command> commandList = new ArrayList<Command>(wayChunks.size());
    233                 Collection<Way> newSelection = new ArrayList<Way>(wayChunks.size());
    234 
    235                 Iterator<List<Node>> chunkIt = wayChunks.iterator();
    236 
    237                 // First, change the original way
    238                 Way changedWay = new Way(selectedWay);
    239                 changedWay.nodes.clear();
    240                 changedWay.nodes.addAll(chunkIt.next());
    241                 commandList.add(new ChangeCommand(selectedWay, changedWay));
    242                 newSelection.add(selectedWay);
    243 
    244                 Collection<Way> newWays = new ArrayList<Way>();
    245                 // Second, create new ways
    246                 while (chunkIt.hasNext()) {
    247                         Way wayToAdd = new Way();
    248                         if (selectedWay.keys != null) {
    249                                 wayToAdd.keys = new HashMap<String, String>(selectedWay.keys);
    250                                 wayToAdd.checkTagged();
     46    private Way selectedWay;
     47    private List<Node> selectedNodes;
     48
     49    /**
     50    * Create a new SplitWayAction.
     51    */
     52    public SplitWayAction() {
     53        super(tr("Split Way"), "splitway", tr("Split a way at the selected node."),
     54        Shortcut.registerShortcut("tools:splitway", tr("Tool: {0}", tr("Split Way")), KeyEvent.VK_P, Shortcut.GROUP_EDIT), true);
     55        DataSet.selListeners.add(this);
     56    }
     57
     58    /**
     59    * Called when the action is executed.
     60    *
     61    * This method performs an expensive check whether the selection clearly defines one
     62    * of the split actions outlined above, and if yes, calls the splitWay method.
     63    */
     64    public void actionPerformed(ActionEvent e) {
     65
     66        Collection<OsmPrimitive> selection = Main.ds.getSelected();
     67
     68        if (!checkSelection(selection)) {
     69            JOptionPane.showMessageDialog(Main.parent, tr("The current selection cannot be used for splitting."));
     70            return;
     71        }
     72
     73        selectedWay = null;
     74        selectedNodes = null;
     75
     76        Visitor splitVisitor = new Visitor(){
     77            public void visit(Node n) {
     78                if (selectedNodes == null)
     79                    selectedNodes = new LinkedList<Node>();
     80                selectedNodes.add(n);
     81            }
     82            public void visit(Way w) {
     83                selectedWay = w;
     84            }
     85            public void visit(Relation e) {
     86                // enties are not considered
     87            }
     88        };
     89
     90        for (OsmPrimitive p : selection)
     91            p.visit(splitVisitor);
     92
     93        // If only nodes are selected, try to guess which way to split. This works if there
     94        // is exactly one way that all nodes are part of.
     95        if (selectedWay == null && selectedNodes != null) {
     96            HashMap<Way, Integer> wayOccurenceCounter = new HashMap<Way, Integer>();
     97            for (Node n : selectedNodes) {
     98                for (Way w : Main.ds.ways) {
     99                    if (w.deleted || w.incomplete) continue;
     100                    int last = w.nodes.size()-1;
     101                    if(last <= 0) continue; // zero or one node ways
     102                    Boolean circular = w.nodes.get(0).equals(w.nodes.get(last));
     103                    int i = 0;
     104                    for (Node wn : w.nodes) {
     105                        if ((circular || (i > 0 && i < last)) && n.equals(wn)) {
     106                            Integer old = wayOccurenceCounter.get(w);
     107                            wayOccurenceCounter.put(w, (old == null) ? 1 : old+1);
     108                            break;
     109                        }
     110                        i++;
     111                    }
     112                }
     113            }
     114            if (wayOccurenceCounter.isEmpty()) {
     115                JOptionPane.showMessageDialog(Main.parent,
     116                        trn("The selected node is no inner part of any way.",
     117                                "The selected nodes are no inner part of any way.", selectedNodes.size()));
     118                return;
     119            }
     120
     121            for (Entry<Way, Integer> entry : wayOccurenceCounter.entrySet()) {
     122                if (entry.getValue().equals(selectedNodes.size())) {
     123                    if (selectedWay != null) {
     124                        JOptionPane.showMessageDialog(Main.parent, tr("There is more than one way using the node(s) you selected. Please select the way also."));
     125                        return;
     126                    }
     127                    selectedWay = entry.getKey();
     128                }
     129            }
     130
     131            if (selectedWay == null) {
     132                JOptionPane.showMessageDialog(Main.parent, tr("The selected nodes do not share the same way."));
     133                return;
     134            }
     135
     136        // If a way and nodes are selected, verify that the nodes are part of the way.
     137        } else if (selectedWay != null && selectedNodes != null) {
     138
     139            HashSet<Node> nds = new HashSet<Node>(selectedNodes);
     140            for (Node n : selectedWay.nodes) {
     141                nds.remove(n);
     142            }
     143            if (!nds.isEmpty()) {
     144                JOptionPane.showMessageDialog(Main.parent,
     145                        trn("The selected way does not contain the selected node.",
     146                                "The selected way does not contain all the selected nodes.", selectedNodes.size()));
     147                return;
     148            }
     149        }
     150
     151        // and then do the work.
     152        splitWay();
     153    }
     154
     155    /**
     156    * Checks if the selection consists of something we can work with.
     157    * Checks only if the number and type of items selected looks good;
     158    * does not check whether the selected items are really a valid
     159    * input for splitting (this would be too expensive to be carried
     160    * out from the selectionChanged listener).
     161    */
     162    private boolean checkSelection(Collection<? extends OsmPrimitive> selection) {
     163        boolean way = false;
     164        boolean node = false;
     165        for (OsmPrimitive p : selection) {
     166            if (p instanceof Way && !way) {
     167                way = true;
     168            } else if (p instanceof Node) {
     169                node = true;
     170            } else {
     171                return false;
     172        }
     173        }
     174        return node;
     175    }
     176
     177    /**
     178    * Split a way into two or more parts, starting at a selected node.
     179    */
     180    private void splitWay() {
     181        // We take our way's list of nodes and copy them to a way chunk (a
     182        // list of nodes).  Whenever we stumble upon a selected node, we start
     183        // a new way chunk.
     184
     185        Set<Node> nodeSet = new HashSet<Node>(selectedNodes);
     186        List<List<Node>> wayChunks = new LinkedList<List<Node>>();
     187        List<Node> currentWayChunk = new ArrayList<Node>();
     188        wayChunks.add(currentWayChunk);
     189
     190        Iterator<Node> it = selectedWay.nodes.iterator();
     191        while (it.hasNext()) {
     192            Node currentNode = it.next();
     193            boolean atEndOfWay = currentWayChunk.isEmpty() || !it.hasNext();
     194            currentWayChunk.add(currentNode);
     195            if (nodeSet.contains(currentNode) && !atEndOfWay) {
     196                currentWayChunk = new ArrayList<Node>();
     197                currentWayChunk.add(currentNode);
     198                wayChunks.add(currentWayChunk);
     199            }
     200        }
     201
     202        // Handle circular ways specially.
     203        // If you split at a circular way at two nodes, you just want to split
     204        // it at these points, not also at the former endpoint.
     205        // So if the last node is the same first node, join the last and the
     206        // first way chunk.
     207        List<Node> lastWayChunk = wayChunks.get(wayChunks.size() - 1);
     208        if (wayChunks.size() >= 2
     209                && wayChunks.get(0).get(0) == lastWayChunk.get(lastWayChunk.size() - 1)
     210                && !nodeSet.contains(wayChunks.get(0).get(0))) {
     211            if (wayChunks.size() == 2) {
     212                JOptionPane.showMessageDialog(Main.parent, tr("You must select two or more nodes to split a circular way."));
     213                return;
     214            }
     215            lastWayChunk.remove(lastWayChunk.size() - 1);
     216            lastWayChunk.addAll(wayChunks.get(0));
     217            wayChunks.remove(wayChunks.size() - 1);
     218            wayChunks.set(0, lastWayChunk);
     219        }
     220
     221        if (wayChunks.size() < 2) {
     222            if(wayChunks.get(0).get(0) == wayChunks.get(0).get(wayChunks.get(0).size()-1))
     223                JOptionPane.showMessageDialog(Main.parent, tr("You must select two or more nodes to split a circular way."));
     224            else
     225                JOptionPane.showMessageDialog(Main.parent, tr("The way cannot be split at the selected nodes. (Hint: Select nodes in the middle of the way.)"));
     226            return;
     227        }
     228        //Main.debug("wayChunks.size(): " + wayChunks.size());
     229        //Main.debug("way id: " + selectedWay.id);
     230
     231        // build a list of commands, and also a new selection list
     232        Collection<Command> commandList = new ArrayList<Command>(wayChunks.size());
     233        Collection<Way> newSelection = new ArrayList<Way>(wayChunks.size());
     234
     235        Iterator<List<Node>> chunkIt = wayChunks.iterator();
     236
     237        // First, change the original way
     238        Way changedWay = new Way(selectedWay);
     239        changedWay.nodes.clear();
     240        changedWay.nodes.addAll(chunkIt.next());
     241        commandList.add(new ChangeCommand(selectedWay, changedWay));
     242        newSelection.add(selectedWay);
     243
     244        Collection<Way> newWays = new ArrayList<Way>();
     245        // Second, create new ways
     246        while (chunkIt.hasNext()) {
     247            Way wayToAdd = new Way();
     248            if (selectedWay.keys != null) {
     249                wayToAdd.keys = new HashMap<String, String>(selectedWay.keys);
     250                wayToAdd.checkTagged();
    251251                                wayToAdd.checkDirectionTagged();
    252                         }
    253                         newWays.add(wayToAdd);
    254                         wayToAdd.nodes.addAll(chunkIt.next());
    255                         commandList.add(new AddCommand(wayToAdd));
    256                         //Main.debug("wayToAdd: " + wayToAdd);
    257                         newSelection.add(wayToAdd);
    258 
    259                 }
    260                 Boolean warnme=false;
    261                 // now copy all relations to new way also
    262                 for (Relation r : Main.ds.relations) {
    263                         if (r.deleted || r.incomplete) continue;
    264                         for (RelationMember rm : r.members) {
    265                                 if (rm.member instanceof Way) {
    266                                         if (rm.member == selectedWay)
    267                                         {
    268                                                 Relation c = new Relation(r);
    269                                                 for(Way wayToAdd : newWays)
    270                                                 {
    271                                                         RelationMember em = new RelationMember();
    272                                                         em.member = wayToAdd;
    273                                                         em.role = rm.role;
    274                                                         if(em.role.length() > 0)
    275                                                                 warnme = true;
    276                                                         c.members.add(em);
    277                                                 }
    278                                                 commandList.add(new ChangeCommand(r, c));
    279                                                 break;
    280                                         }
    281                                 }
    282                         }
    283                 }
    284                 if(warnme)
    285                         JOptionPane.showMessageDialog(Main.parent, tr("A role based relation membership was copied to all new ways.\nYou should verify this and correct it when necessary."));
    286 
    287                 NameVisitor v = new NameVisitor();
    288                 v.visit(selectedWay);
    289                 Main.main.undoRedo.add(
    290                         new SequenceCommand(tr("Split way {0} into {1} parts",
    291                                 v.name, wayChunks.size()),
    292                         commandList));
    293                 Main.ds.setSelected(newSelection);
    294         }
    295 
    296         /**
    297         * Enable the "split way" menu option if the selection looks like we could use it.
    298         */
    299         public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
    300                 setEnabled(checkSelection(newSelection));
    301         }
     252            }
     253            newWays.add(wayToAdd);
     254            wayToAdd.nodes.addAll(chunkIt.next());
     255            commandList.add(new AddCommand(wayToAdd));
     256            //Main.debug("wayToAdd: " + wayToAdd);
     257            newSelection.add(wayToAdd);
     258
     259        }
     260        Boolean warnme=false;
     261        // now copy all relations to new way also
     262        for (Relation r : Main.ds.relations) {
     263            if (r.deleted || r.incomplete) continue;
     264            for (RelationMember rm : r.members) {
     265                if (rm.member instanceof Way) {
     266                    if (rm.member == selectedWay)
     267                    {
     268                        Relation c = new Relation(r);
     269                        for(Way wayToAdd : newWays)
     270                        {
     271                            RelationMember em = new RelationMember();
     272                            em.member = wayToAdd;
     273                            em.role = rm.role;
     274                            if(em.role.length() > 0)
     275                                warnme = true;
     276                            c.members.add(em);
     277                        }
     278                        commandList.add(new ChangeCommand(r, c));
     279                        break;
     280                    }
     281                }
     282            }
     283        }
     284        if(warnme)
     285            JOptionPane.showMessageDialog(Main.parent, tr("A role based relation membership was copied to all new ways.\nYou should verify this and correct it when necessary."));
     286
     287        NameVisitor v = new NameVisitor();
     288        v.visit(selectedWay);
     289        Main.main.undoRedo.add(
     290            new SequenceCommand(tr("Split way {0} into {1} parts",
     291                v.name, wayChunks.size()),
     292            commandList));
     293        Main.ds.setSelected(newSelection);
     294    }
     295
     296    /**
     297    * Enable the "split way" menu option if the selection looks like we could use it.
     298    */
     299    public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
     300        setEnabled(checkSelection(newSelection));
     301    }
    302302}
  • trunk/src/org/openstreetmap/josm/actions/ToggleGPXLinesAction.java

    r1138 r1169  
    1212public class ToggleGPXLinesAction extends JosmAction {
    1313
    14         public ToggleGPXLinesAction() {
    15                 super(tr("Toggle GPX Lines"), "gps-lines", tr("Toggles the global setting ''{0}''.", tr("Draw lines between raw gps points.")),
    16                 Shortcut.registerShortcut("view:gpxlines", tr("View: {0}", tr("Toggle GPX Lines")), KeyEvent.VK_X, Shortcut.GROUP_MENU, Shortcut.SHIFT_DEFAULT), true);
    17         }
     14    public ToggleGPXLinesAction() {
     15        super(tr("Toggle GPX Lines"), "gps-lines", tr("Toggles the global setting ''{0}''.", tr("Draw lines between raw gps points.")),
     16        Shortcut.registerShortcut("view:gpxlines", tr("View: {0}", tr("Toggle GPX Lines")), KeyEvent.VK_X, Shortcut.GROUP_MENU, Shortcut.SHIFT_DEFAULT), true);
     17    }
    1818
    19         public void actionPerformed(ActionEvent e) {
    20                 Main.pref.put("draw.rawgps.lines", !Main.pref.getBoolean("draw.rawgps.lines"));
    21                 Main.map.mapView.repaint();
    22         }
     19    public void actionPerformed(ActionEvent e) {
     20        Main.pref.put("draw.rawgps.lines", !Main.pref.getBoolean("draw.rawgps.lines"));
     21        Main.map.mapView.repaint();
     22    }
    2323}
  • trunk/src/org/openstreetmap/josm/actions/UnGlueAction.java

    r1084 r1169  
    3636public class UnGlueAction extends JosmAction { //implements SelectionChangedListener {
    3737
    38         private Node selectedNode;
    39         private Way selectedWay;
    40         private ArrayList<Node> selectedNodes;
    41 
    42         /**
    43         * Create a new UnGlueAction.
    44         */
    45         public UnGlueAction() {
    46                 super(tr("UnGlue Ways"), "unglueways", tr("Duplicate nodes that are used by multiple ways."),
    47                 Shortcut.registerShortcut("tools:unglue", tr("Tool: {0}", tr("UnGlue Ways")), KeyEvent.VK_G, Shortcut.GROUP_EDIT), true);
    48                 //DataSet.selListeners.add(this);
    49         }
    50 
    51         /**
    52         * Called when the action is executed.
    53         *
    54         * This method does some checking on the selection and calls the matching unGlueWay method.
    55         */
    56         public void actionPerformed(ActionEvent e) {
    57 
    58                 Collection<OsmPrimitive> selection = Main.ds.getSelected();
    59 
    60                 if (checkSelection(selection)) {
    61                         int count = 0;
    62                         for (Way w : Main.ds.ways) {
    63                                 if (w.deleted || w.incomplete || w.nodes.size() < 1) continue;
    64                                 if (!w.nodes.contains(selectedNode)) continue;
    65                                 count++;
    66                         }
    67                         if (count < 2) {
    68                                 JOptionPane.showMessageDialog(Main.parent, tr("This node is not glued to anything else."));
    69                         } else {
    70                                 // and then do the work.
    71                                 unglueWays();
    72                         }
    73                 } else if (checkSelection2(selection)) {
    74                         ArrayList<Node> tmpNodes = new ArrayList<Node>();
    75                         for (Node n : selectedNodes) {
    76                                 int count = 0;
    77                                 for (Way w : Main.ds.ways) {
    78                                         if (w.deleted || w.incomplete || w.nodes.size() < 1) continue;
    79                                         if (!w.nodes.contains(n)) continue;
    80                                         count++;
    81                                 }
    82                                 if (count >= 2) {
    83                                         tmpNodes.add(n);
    84                                 }
    85                         }
    86                         if (tmpNodes.size() < 1) {
    87                                 if (selection.size() > 1) {
    88                                         JOptionPane.showMessageDialog(Main.parent, tr("None of these nodes is glued to anything else."));
    89                                 } else {
    90                                         JOptionPane.showMessageDialog(Main.parent, tr("None of this way's nodes is glued to anything else."));
    91                                 }
    92                         } else {
    93                                 // and then do the work.
    94                                 selectedNodes = tmpNodes;
    95                                 unglueWays2();
    96                         }
    97                 } else {
    98                         JOptionPane.showMessageDialog(Main.parent,
    99                                 tr("The current selection cannot be used for unglueing.")+"\n"+
    100                                 "\n"+
    101                                 tr("Select either:")+"\n"+
    102                                 tr("* One node that is used by more than one way, or")+"\n"+
    103                                 tr("* One node that is used by more than one way and one of those ways, or")+"\n"+
    104                                 tr("* One way that has one or more nodes that are used by more than one way, or")+"\n"+
    105                                 tr("* One way and one or more of its nodes that are used by more than one way.")+"\n"+
    106                                 "\n"+
    107                                 tr("Note: If a way is selected, this way will get fresh copies of the unglued\n"+
    108                                    "nodes and the new nodes will be selected. Otherwise, all ways will get their\n"+
    109                                    "own copy and all nodes will be selected.")
    110                         );
    111                 }
    112                 selectedNode = null;
    113                 selectedWay = null;
    114                 selectedNodes = null;
    115         }
    116 
    117         /**
    118         * Checks if the selection consists of something we can work with.
    119         * Checks only if the number and type of items selected looks good;
    120         * does not check whether the selected items are really a valid
    121         * input for splitting (this would be too expensive to be carried
    122         * out from the selectionChanged listener).
    123         *
    124         * If this method returns "true", selectedNode and selectedWay will
    125         * be set.
    126         *
    127         * Returns true if either one node is selected or one node and one
    128         * way are selected and the node is part of the way.
    129         *
    130         * The way will be put into the object variable "selectedWay", the
    131         * node into "selectedNode".
    132         */
    133         private boolean checkSelection(Collection<? extends OsmPrimitive> selection) {
    134 
    135                 int size = selection.size();
    136                 if (size < 1 || size > 2)
    137                         return false;
    138 
    139                 selectedNode = null;
    140                 selectedWay = null;
    141 
    142                 for (OsmPrimitive p : selection) {
    143                         if (p instanceof Node) {
    144                                 selectedNode = (Node) p;
    145                                 if (size == 1 || selectedWay != null)
    146                                         return size == 1 || selectedWay.nodes.contains(selectedNode);
    147                         } else if (p instanceof Way) {
    148                                 selectedWay = (Way) p;
    149                                 if (size == 2 && selectedNode != null)
    150                                         return selectedWay.nodes.contains(selectedNode);
    151                         }
    152                 }
    153 
    154                 return false;
    155         }
    156 
    157         /**
    158         * Checks if the selection consists of something we can work with.
    159         * Checks only if the number and type of items selected looks good;
    160         * does not check whether the selected items are really a valid
    161         * input for splitting (this would be too expensive to be carried
    162         * out from the selectionChanged listener).
    163         *
    164         * Returns true if one way and any number of nodes that are part of
    165         * that way are selected. Note: "any" can be none, then all nodes of
    166         * the way are used.
    167         *
    168         * The way will be put into the object variable "selectedWay", the
    169         * nodes into "selectedNodes".
    170         */
    171         private boolean checkSelection2(Collection<? extends OsmPrimitive> selection) {
    172                 if (selection.size() < 1)
    173                         return false;
    174 
    175                 selectedWay = null;
    176                 for (OsmPrimitive p : selection) {
    177                         if (p instanceof Way) {
    178                                 if (selectedWay != null) {
    179                                         return false;
    180                                 }
    181                                 selectedWay = (Way) p;
    182                         }
    183                 }
    184                 if (selectedWay == null) {
    185                         return false;
    186                 }
    187 
    188                 selectedNodes = new ArrayList<Node>();
    189                 for (OsmPrimitive p : selection) {
    190                         if (p instanceof Node) {
    191                                 Node n = (Node) p;
    192                                 if (!selectedWay.nodes.contains(n)) {
    193                                         return false;
    194                                 }
    195                                 selectedNodes.add(n);
    196                         }
    197                 }
    198 
    199                 if (selectedNodes.size() < 1) {
    200                         selectedNodes.addAll(selectedWay.nodes);
    201                 }
    202 
    203                 return true;
    204         }
    205 
    206         /**
    207         * dupe the given node of the given way
    208         *
    209         * -> the new node will be put into the parameter newNodes.
    210         * -> the add-node command will be put into the parameter cmds.
    211         * -> the changed way will be returned and must be put into cmds by the caller!
    212         */
    213         private Way modifyWay(Node originalNode, Way w, List<Command> cmds, List<Node> newNodes) {
    214                 ArrayList<Node> nn = new ArrayList<Node>();
    215                 for (Node pushNode : w.nodes) {
    216                         if (originalNode == pushNode) {
    217                                 // clone the node for all other ways
    218                                 pushNode = new Node(pushNode);
    219                                 pushNode.id = 0;
    220                                 newNodes.add(pushNode);
    221                                 cmds.add(new AddCommand(pushNode));
    222                         }
    223                         nn.add(pushNode);
    224                 }
    225                 Way newWay = new Way(w);
    226                 newWay.nodes.clear();
    227                 newWay.nodes.addAll(nn);
    228 
    229                 return newWay;
    230         }
    231 
    232         /**
    233         * put all newNodes into the same relation(s) that originalNode is in
    234         */
    235         private void fixRelations(Node originalNode, List<Command> cmds, List<Node> newNodes) {
    236                 // modify all relations containing the node
    237                 Relation newRel = null;
    238                 HashSet<String> rolesToReAdd = null;
    239                 for (Relation r : Main.ds.relations) {
    240                         if (r.deleted || r.incomplete) continue;
    241                         newRel = null;
    242                         rolesToReAdd = null;
    243                         for (RelationMember rm : r.members) {
    244                                 if (rm.member instanceof Node) {
    245                                         if (rm.member == originalNode) {
    246                                                 if (newRel == null) {
    247                                                         newRel = new Relation(r);
    248                                                         newRel.members.clear();
    249                                                         rolesToReAdd = new HashSet<String>();
    250                                                 }
    251                                                 rolesToReAdd.add(rm.role);
    252                                         }
    253                                 }
    254                         }
    255                         if (newRel != null) {
    256                                 for (RelationMember rm : r.members) {
    257                                         //if (rm.member != selectedNode) {
    258                                                 newRel.members.add(rm);
    259                                         //}
    260                                 }
    261                                 for (Node n : newNodes) {
    262                                         for (String role : rolesToReAdd) {
    263                                                 newRel.members.add(new RelationMember(role, n));
    264                                         }
    265                                 }
    266                                 cmds.add(new ChangeCommand(r, newRel));
    267                         }
    268                 }
    269         }
    270 
    271 
    272         /**
    273         * dupe a single node into as many nodes as there are ways using it, OR
    274         *
    275         * dupe a single node once, and put the copy on the selected way
    276         */
    277         private void unglueWays() {
    278                 LinkedList<Command> cmds = new LinkedList<Command>();
    279                 List<Node> newNodes = new LinkedList<Node>();
    280 
    281                 if (selectedWay == null) {
    282                         boolean firstway = true;
    283                         // modify all ways containing the nodes
    284                         for (Way w : Main.ds.ways) {
    285                                 if (w.deleted || w.incomplete || w.nodes.size() < 1) continue;
    286                                 if (!w.nodes.contains(selectedNode)) continue;
    287                                 if (!firstway) cmds.add(new ChangeCommand(w, modifyWay(selectedNode, w, cmds, newNodes)));
    288                                 firstway = false;
    289                         }
    290                 } else {
    291                         cmds.add(new ChangeCommand(selectedWay, modifyWay(selectedNode, selectedWay, cmds, newNodes)));
    292                 }
    293 
    294                 fixRelations(selectedNode, cmds, newNodes);
    295 
    296                 Main.main.undoRedo.add(new SequenceCommand(tr("Dupe into {0} nodes", newNodes.size()+1), cmds));
    297                 if (selectedWay == null) { // if a node has been selected, new selection is ALL nodes
    298                         newNodes.add(selectedNode);
    299                 } // if a node and a way has been selected, new selection is only the new node that was added to the selected way
    300                 Main.ds.setSelected(newNodes);
    301         }
    302 
    303         /**
    304         * dupe all nodes that are selected, and put the copies on the selected way
    305         *
    306         */
    307         private void unglueWays2() {
    308                 LinkedList<Command> cmds = new LinkedList<Command>();
    309                 List<Node> allNewNodes = new LinkedList<Node>();
    310                 Way tmpWay = selectedWay;
    311 
    312                 for (Node n : selectedNodes) {
    313                         List<Node> newNodes = new LinkedList<Node>();
    314                         tmpWay = modifyWay(n, tmpWay, cmds, newNodes);
    315                         fixRelations(n, cmds, newNodes);
    316                         allNewNodes.addAll(newNodes);
    317                 }
    318                 cmds.add(new ChangeCommand(selectedWay, tmpWay)); // only one changeCommand for a way, else garbage will happen
    319 
    320                 Main.main.undoRedo.add(new SequenceCommand(tr("Dupe {0} nodes into {1} nodes", selectedNodes.size(), selectedNodes.size()+allNewNodes.size()), cmds));
    321                 Main.ds.setSelected(allNewNodes);
    322         }
     38    private Node selectedNode;
     39    private Way selectedWay;
     40    private ArrayList<Node> selectedNodes;
     41
     42    /**
     43    * Create a new UnGlueAction.
     44    */
     45    public UnGlueAction() {
     46        super(tr("UnGlue Ways"), "unglueways", tr("Duplicate nodes that are used by multiple ways."),
     47        Shortcut.registerShortcut("tools:unglue", tr("Tool: {0}", tr("UnGlue Ways")), KeyEvent.VK_G, Shortcut.GROUP_EDIT), true);
     48        //DataSet.selListeners.add(this);
     49    }
     50
     51    /**
     52    * Called when the action is executed.
     53    *
     54    * This method does some checking on the selection and calls the matching unGlueWay method.
     55    */
     56    public void actionPerformed(ActionEvent e) {
     57
     58        Collection<OsmPrimitive> selection = Main.ds.getSelected();
     59
     60        if (checkSelection(selection)) {
     61            int count = 0;
     62            for (Way w : Main.ds.ways) {
     63                if (w.deleted || w.incomplete || w.nodes.size() < 1) continue;
     64                if (!w.nodes.contains(selectedNode)) continue;
     65                count++;
     66            }
     67            if (count < 2) {
     68                JOptionPane.showMessageDialog(Main.parent, tr("This node is not glued to anything else."));
     69            } else {
     70                // and then do the work.
     71                unglueWays();
     72            }
     73        } else if (checkSelection2(selection)) {
     74            ArrayList<Node> tmpNodes = new ArrayList<Node>();
     75            for (Node n : selectedNodes) {
     76                int count = 0;
     77                for (Way w : Main.ds.ways) {
     78                    if (w.deleted || w.incomplete || w.nodes.size() < 1) continue;
     79                    if (!w.nodes.contains(n)) continue;
     80                    count++;
     81                }
     82                if (count >= 2) {
     83                    tmpNodes.add(n);
     84                }
     85            }
     86            if (tmpNodes.size() < 1) {
     87                if (selection.size() > 1) {
     88                    JOptionPane.showMessageDialog(Main.parent, tr("None of these nodes is glued to anything else."));
     89                } else {
     90                    JOptionPane.showMessageDialog(Main.parent, tr("None of this way's nodes is glued to anything else."));
     91                }
     92            } else {
     93                // and then do the work.
     94                selectedNodes = tmpNodes;
     95                unglueWays2();
     96            }
     97        } else {
     98            JOptionPane.showMessageDialog(Main.parent,
     99                tr("The current selection cannot be used for unglueing.")+"\n"+
     100                "\n"+
     101                tr("Select either:")+"\n"+
     102                tr("* One node that is used by more than one way, or")+"\n"+
     103                tr("* One node that is used by more than one way and one of those ways, or")+"\n"+
     104                tr("* One way that has one or more nodes that are used by more than one way, or")+"\n"+
     105                tr("* One way and one or more of its nodes that are used by more than one way.")+"\n"+
     106                "\n"+
     107                tr("Note: If a way is selected, this way will get fresh copies of the unglued\n"+
     108                   "nodes and the new nodes will be selected. Otherwise, all ways will get their\n"+
     109                   "own copy and all nodes will be selected.")
     110            );
     111        }
     112        selectedNode = null;
     113        selectedWay = null;
     114        selectedNodes = null;
     115    }
     116
     117    /**
     118    * Checks if the selection consists of something we can work with.
     119    * Checks only if the number and type of items selected looks good;
     120    * does not check whether the selected items are really a valid
     121    * input for splitting (this would be too expensive to be carried
     122    * out from the selectionChanged listener).
     123    *
     124    * If this method returns "true", selectedNode and selectedWay will
     125    * be set.
     126    *
     127    * Returns true if either one node is selected or one node and one
     128    * way are selected and the node is part of the way.
     129    *
     130    * The way will be put into the object variable "selectedWay", the
     131    * node into "selectedNode".
     132    */
     133    private boolean checkSelection(Collection<? extends OsmPrimitive> selection) {
     134
     135        int size = selection.size();
     136        if (size < 1 || size > 2)
     137            return false;
     138
     139        selectedNode = null;
     140        selectedWay = null;
     141
     142        for (OsmPrimitive p : selection) {
     143            if (p instanceof Node) {
     144                selectedNode = (Node) p;
     145                if (size == 1 || selectedWay != null)
     146                    return size == 1 || selectedWay.nodes.contains(selectedNode);
     147            } else if (p instanceof Way) {
     148                selectedWay = (Way) p;
     149                if (size == 2 && selectedNode != null)
     150                    return selectedWay.nodes.contains(selectedNode);
     151            }
     152        }
     153
     154        return false;
     155    }
     156
     157    /**
     158    * Checks if the selection consists of something we can work with.
     159    * Checks only if the number and type of items selected looks good;
     160    * does not check whether the selected items are really a valid
     161    * input for splitting (this would be too expensive to be carried
     162    * out from the selectionChanged listener).
     163    *
     164    * Returns true if one way and any number of nodes that are part of
     165    * that way are selected. Note: "any" can be none, then all nodes of
     166    * the way are used.
     167    *
     168    * The way will be put into the object variable "selectedWay", the
     169    * nodes into "selectedNodes".
     170    */
     171    private boolean checkSelection2(Collection<? extends OsmPrimitive> selection) {
     172        if (selection.size() < 1)
     173            return false;
     174
     175        selectedWay = null;
     176        for (OsmPrimitive p : selection) {
     177            if (p instanceof Way) {
     178                if (selectedWay != null) {
     179                    return false;
     180                }
     181                selectedWay = (Way) p;
     182            }
     183        }
     184        if (selectedWay == null) {
     185            return false;
     186        }
     187
     188        selectedNodes = new ArrayList<Node>();
     189        for (OsmPrimitive p : selection) {
     190            if (p instanceof Node) {
     191                Node n = (Node) p;
     192                if (!selectedWay.nodes.contains(n)) {
     193                    return false;
     194                }
     195                selectedNodes.add(n);
     196            }
     197        }
     198
     199        if (selectedNodes.size() < 1) {
     200            selectedNodes.addAll(selectedWay.nodes);
     201        }
     202
     203        return true;
     204    }
     205
     206    /**
     207    * dupe the given node of the given way
     208    *
     209    * -> the new node will be put into the parameter newNodes.
     210    * -> the add-node command will be put into the parameter cmds.
     211    * -> the changed way will be returned and must be put into cmds by the caller!
     212    */
     213    private Way modifyWay(Node originalNode, Way w, List<Command> cmds, List<Node> newNodes) {
     214        ArrayList<Node> nn = new ArrayList<Node>();
     215        for (Node pushNode : w.nodes) {
     216            if (originalNode == pushNode) {
     217                // clone the node for all other ways
     218                pushNode = new Node(pushNode);
     219                pushNode.id = 0;
     220                newNodes.add(pushNode);
     221                cmds.add(new AddCommand(pushNode));
     222            }
     223            nn.add(pushNode);
     224        }
     225        Way newWay = new Way(w);
     226        newWay.nodes.clear();
     227        newWay.nodes.addAll(nn);
     228
     229        return newWay;
     230    }
     231
     232    /**
     233    * put all newNodes into the same relation(s) that originalNode is in
     234    */
     235    private void fixRelations(Node originalNode, List<Command> cmds, List<Node> newNodes) {
     236        // modify all relations containing the node
     237        Relation newRel = null;
     238        HashSet<String> rolesToReAdd = null;
     239        for (Relation r : Main.ds.relations) {
     240            if (r.deleted || r.incomplete) continue;
     241            newRel = null;
     242            rolesToReAdd = null;
     243            for (RelationMember rm : r.members) {
     244                if (rm.member instanceof Node) {
     245                    if (rm.member == originalNode) {
     246                        if (newRel == null) {
     247                            newRel = new Relation(r);
     248                            newRel.members.clear();
     249                            rolesToReAdd = new HashSet<String>();
     250                        }
     251                        rolesToReAdd.add(rm.role);
     252                    }
     253                }
     254            }
     255            if (newRel != null) {
     256                for (RelationMember rm : r.members) {
     257                    //if (rm.member != selectedNode) {
     258                        newRel.members.add(rm);
     259                    //}
     260                }
     261                for (Node n : newNodes) {
     262                    for (String role : rolesToReAdd) {
     263                        newRel.members.add(new RelationMember(role, n));
     264                    }
     265                }
     266                cmds.add(new ChangeCommand(r, newRel));
     267            }
     268        }
     269    }
     270
     271
     272    /**
     273    * dupe a single node into as many nodes as there are ways using it, OR
     274    *
     275    * dupe a single node once, and put the copy on the selected way
     276    */
     277    private void unglueWays() {
     278        LinkedList<Command> cmds = new LinkedList<Command>();
     279        List<Node> newNodes = new LinkedList<Node>();
     280
     281        if (selectedWay == null) {
     282            boolean firstway = true;
     283            // modify all ways containing the nodes
     284            for (Way w : Main.ds.ways) {
     285                if (w.deleted || w.incomplete || w.nodes.size() < 1) continue;
     286                if (!w.nodes.contains(selectedNode)) continue;
     287                if (!firstway) cmds.add(new ChangeCommand(w, modifyWay(selectedNode, w, cmds, newNodes)));
     288                firstway = false;
     289            }
     290        } else {
     291            cmds.add(new ChangeCommand(selectedWay, modifyWay(selectedNode, selectedWay, cmds, newNodes)));
     292        }
     293
     294        fixRelations(selectedNode, cmds, newNodes);
     295
     296        Main.main.undoRedo.add(new SequenceCommand(tr("Dupe into {0} nodes", newNodes.size()+1), cmds));
     297        if (selectedWay == null) { // if a node has been selected, new selection is ALL nodes
     298            newNodes.add(selectedNode);
     299        } // if a node and a way has been selected, new selection is only the new node that was added to the selected way
     300        Main.ds.setSelected(newNodes);
     301    }
     302
     303    /**
     304    * dupe all nodes that are selected, and put the copies on the selected way
     305    *
     306    */
     307    private void unglueWays2() {
     308        LinkedList<Command> cmds = new LinkedList<Command>();
     309        List<Node> allNewNodes = new LinkedList<Node>();
     310        Way tmpWay = selectedWay;
     311
     312        for (Node n : selectedNodes) {
     313            List<Node> newNodes = new LinkedList<Node>();
     314            tmpWay = modifyWay(n, tmpWay, cmds, newNodes);
     315            fixRelations(n, cmds, newNodes);
     316            allNewNodes.addAll(newNodes);
     317        }
     318        cmds.add(new ChangeCommand(selectedWay, tmpWay)); // only one changeCommand for a way, else garbage will happen
     319
     320        Main.main.undoRedo.add(new SequenceCommand(tr("Dupe {0} nodes into {1} nodes", selectedNodes.size(), selectedNodes.size()+allNewNodes.size()), cmds));
     321        Main.ds.setSelected(allNewNodes);
     322    }
    323323
    324324// Disabled because we have such a nice help text that would not be shown otherwise.
    325325//
    326 //      /**
    327 //      * Enable the menu option if the selection looks like we could use it.
    328 //      */
    329 //      public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
    330 //              setEnabled(checkSelection(newSelection) || checkSelection2(newSelection));
    331 //              selectedNode = null;
    332 //              selectedWay = null;
    333 //              selectedNodes = null;
    334 //      }
     326//  /**
     327//  * Enable the menu option if the selection looks like we could use it.
     328//  */
     329//  public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
     330//      setEnabled(checkSelection(newSelection) || checkSelection2(newSelection));
     331//      selectedNode = null;
     332//      selectedWay = null;
     333//      selectedNodes = null;
     334//  }
    335335}
  • trunk/src/org/openstreetmap/josm/actions/UndoAction.java

    r1084 r1169  
    1717public class UndoAction extends JosmAction {
    1818
    19         /**
    20         * Construct the action with "Undo" as label.
    21         */
    22         public UndoAction() {
    23                 super(tr("Undo"), "undo", tr("Undo the last action."),
    24                 Shortcut.registerShortcut("system:undo", tr("Edit: {0}", tr("Undo")), KeyEvent.VK_Z, Shortcut.GROUP_MENU), true);
    25                 setEnabled(false);
    26         }
     19    /**
     20    * Construct the action with "Undo" as label.
     21    */
     22    public UndoAction() {
     23        super(tr("Undo"), "undo", tr("Undo the last action."),
     24        Shortcut.registerShortcut("system:undo", tr("Edit: {0}", tr("Undo")), KeyEvent.VK_Z, Shortcut.GROUP_MENU), true);
     25        setEnabled(false);
     26    }
    2727
    28         public void actionPerformed(ActionEvent e) {
    29                 if (Main.map == null)
    30                         return;
    31                 Main.map.repaint();
    32                 Main.main.undoRedo.undo();
    33         }
     28    public void actionPerformed(ActionEvent e) {
     29        if (Main.map == null)
     30            return;
     31        Main.map.repaint();
     32        Main.main.undoRedo.undo();
     33    }
    3434}
  • trunk/src/org/openstreetmap/josm/actions/UnselectAllAction.java

    r1084 r1169  
    1313public class UnselectAllAction extends JosmAction {
    1414
    15         public UnselectAllAction() {
    16                 super(tr("Unselect All"), "unselectall", tr("Unselect all objects."),
    17                 Shortcut.registerShortcut("edit:unselectall", tr("Edit: {0}", tr("Unselect All")), KeyEvent.VK_U, Shortcut.GROUP_EDIT), true);
    18                 // this is not really GROUP_EDIT, but users really would complain if the yhad to reconfigure because we put
    19                 // the correct group in
     15    public UnselectAllAction() {
     16        super(tr("Unselect All"), "unselectall", tr("Unselect all objects."),
     17        Shortcut.registerShortcut("edit:unselectall", tr("Edit: {0}", tr("Unselect All")), KeyEvent.VK_U, Shortcut.GROUP_EDIT), true);
     18        // this is not really GROUP_EDIT, but users really would complain if the yhad to reconfigure because we put
     19        // the correct group in
    2020
    21                 // Add extra shortcut C-S-a
    22                 Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
    23                 Shortcut.registerShortcut("edit:unselectallfocus", tr("Edit: {0}", tr("Unselect All (Focus)")),
    24                 KeyEvent.VK_A, Shortcut.GROUP_MENU, Shortcut.SHIFT_DEFAULT).getKeyStroke(),
    25                 tr("Unselect All"));
     21        // Add extra shortcut C-S-a
     22        Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
     23        Shortcut.registerShortcut("edit:unselectallfocus", tr("Edit: {0}", tr("Unselect All (Focus)")),
     24        KeyEvent.VK_A, Shortcut.GROUP_MENU, Shortcut.SHIFT_DEFAULT).getKeyStroke(),
     25        tr("Unselect All"));
    2626
    27                 // Add extra shortcut ESCAPE
    28                 /*
    29                 * FIXME: this isn't optimal. In a better world the mapmode actions
    30                 * would be able to capture keyboard events and react accordingly. But
    31                 * for now this is a reasonable approximation.
    32                 */
    33                 Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
    34                 Shortcut.registerShortcut("edit:unselectallescape", tr("Edit: {0}", tr("Unselect All (Escape)")),
    35                 KeyEvent.VK_ESCAPE, Shortcut.GROUP_DIRECT).getKeyStroke(),
    36                 tr("Unselect All"));
    37         }
     27        // Add extra shortcut ESCAPE
     28        /*
     29        * FIXME: this isn't optimal. In a better world the mapmode actions
     30        * would be able to capture keyboard events and react accordingly. But
     31        * for now this is a reasonable approximation.
     32        */
     33        Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
     34        Shortcut.registerShortcut("edit:unselectallescape", tr("Edit: {0}", tr("Unselect All (Escape)")),
     35        KeyEvent.VK_ESCAPE, Shortcut.GROUP_DIRECT).getKeyStroke(),
     36        tr("Unselect All"));
     37    }
    3838
    39         public void actionPerformed(ActionEvent e) {
    40                 Main.ds.setSelected();
    41         }
     39    public void actionPerformed(ActionEvent e) {
     40        Main.ds.setSelected();
     41    }
    4242}
  • trunk/src/org/openstreetmap/josm/actions/UploadAction.java

    r1084 r1169  
    3535public class UploadAction extends JosmAction {
    3636
    37         /** Upload Hook */
    38         public interface UploadHook {
    39                 /**
    40                 * Checks the upload.
    41                 * @param add The added primitives
    42                 * @param update The updated primitives
    43                 * @param delete The deleted primitives
    44                 * @return true, if the upload can continue
    45                 */
    46                 public boolean checkUpload(Collection<OsmPrimitive> add, Collection<OsmPrimitive> update, Collection<OsmPrimitive> delete);
    47         }
     37    /** Upload Hook */
     38    public interface UploadHook {
     39        /**
     40        * Checks the upload.
     41        * @param add The added primitives
     42        * @param update The updated primitives
     43        * @param delete The deleted primitives
     44        * @return true, if the upload can continue
     45        */
     46        public boolean checkUpload(Collection<OsmPrimitive> add, Collection<OsmPrimitive> update, Collection<OsmPrimitive> delete);
     47    }
    4848
    49         /**
    50         * The list of upload hooks. These hooks will be called one after the other
    51         * when the user wants to upload data. Plugins can insert their own hooks here
    52         * if they want to be able to veto an upload.
    53         *
    54         * Be default, the standard upload dialog is the only element in the list.
    55         * Plugins should normally insert their code before that, so that the upload
    56         * dialog is the last thing shown before upload really starts; on occasion
    57         * however, a plugin might also want to insert something after that.
    58         */
    59         public final LinkedList<UploadHook> uploadHooks = new LinkedList<UploadHook>();
     49    /**
     50    * The list of upload hooks. These hooks will be called one after the other
     51    * when the user wants to upload data. Plugins can insert their own hooks here
     52    * if they want to be able to veto an upload.
     53    *
     54    * Be default, the standard upload dialog is the only element in the list.
     55    * Plugins should normally insert their code before that, so that the upload
     56    * dialog is the last thing shown before upload really starts; on occasion
     57    * however, a plugin might also want to insert something after that.
     58    */
     59    public final LinkedList<UploadHook> uploadHooks = new LinkedList<UploadHook>();
    6060
    61         public UploadAction() {
    62                 super(tr("Upload to OSM ..."), "upload", tr("Upload all changes to the OSM server."),
    63                 Shortcut.registerShortcut("file:upload", tr("File: {0}", tr("Upload to OSM ...")), KeyEvent.VK_U, Shortcut.GROUPS_ALT1+Shortcut.GROUP_HOTKEY), true);
     61    public UploadAction() {
     62        super(tr("Upload to OSM ..."), "upload", tr("Upload all changes to the OSM server."),
     63        Shortcut.registerShortcut("file:upload", tr("File: {0}", tr("Upload to OSM ...")), KeyEvent.VK_U, Shortcut.GROUPS_ALT1+Shortcut.GROUP_HOTKEY), true);
    6464
    65                 /**
    66                 * Displays a screen where the actions that would be taken are displayed and
    67                 * give the user the possibility to cancel the upload.
    68                 */
    69                 uploadHooks.add(new UploadHook() {
    70                         public boolean checkUpload(Collection<OsmPrimitive> add, Collection<OsmPrimitive> update, Collection<OsmPrimitive> delete) {
     65        /**
     66        * Displays a screen where the actions that would be taken are displayed and
     67        * give the user the possibility to cancel the upload.
     68        */
     69        uploadHooks.add(new UploadHook() {
     70            public boolean checkUpload(Collection<OsmPrimitive> add, Collection<OsmPrimitive> update, Collection<OsmPrimitive> delete) {
    7171
    72                                 JPanel p = new JPanel(new GridBagLayout());
     72                JPanel p = new JPanel(new GridBagLayout());
    7373
    74                                 OsmPrimitivRenderer renderer = new OsmPrimitivRenderer();
     74                OsmPrimitivRenderer renderer = new OsmPrimitivRenderer();
    7575
    76                                 if (!add.isEmpty()) {
    77                                         p.add(new JLabel(tr("Objects to add:")), GBC.eol());
    78                                         JList l = new JList(add.toArray());
    79                                         l.setCellRenderer(renderer);
    80                                         l.setVisibleRowCount(l.getModel().getSize() < 6 ? l.getModel().getSize() : 10);
    81                                         p.add(new JScrollPane(l), GBC.eol().fill());
    82                                 }
     76                if (!add.isEmpty()) {
     77                    p.add(new JLabel(tr("Objects to add:")), GBC.eol());
     78                    JList l = new JList(add.toArray());
     79                    l.setCellRenderer(renderer);
     80                    l.setVisibleRowCount(l.getModel().getSize() < 6 ? l.getModel().getSize() : 10);
     81                    p.add(new JScrollPane(l), GBC.eol().fill());
     82                }
    8383
    84                                 if (!update.isEmpty()) {
    85                                         p.add(new JLabel(tr("Objects to modify:")), GBC.eol());
    86                                         JList l = new JList(update.toArray());
    87                                         l.setCellRenderer(renderer);
    88                                         l.setVisibleRowCount(l.getModel().getSize() < 6 ? l.getModel().getSize() : 10);
    89                                         p.add(new JScrollPane(l), GBC.eol().fill());
    90                                 }
     84                if (!update.isEmpty()) {
     85                    p.add(new JLabel(tr("Objects to modify:")), GBC.eol());
     86                    JList l = new JList(update.toArray());
     87                    l.setCellRenderer(renderer);
     88                    l.setVisibleRowCount(l.getModel().getSize() < 6 ? l.getModel().getSize() : 10);
     89                    p.add(new JScrollPane(l), GBC.eol().fill());
     90                }
    9191
    92                                 if (!delete.isEmpty()) {
    93                                         p.add(new JLabel(tr("Objects to delete:")), GBC.eol());
    94                                         JList l = new JList(delete.toArray());
    95                                         l.setCellRenderer(renderer);
    96                                         l.setVisibleRowCount(l.getModel().getSize() < 6 ? l.getModel().getSize() : 10);
    97                                         p.add(new JScrollPane(l), GBC.eol().fill());
    98                                 }
     92                if (!delete.isEmpty()) {
     93                    p.add(new JLabel(tr("Objects to delete:")), GBC.eol());
     94                    JList l = new JList(delete.toArray());
     95                    l.setCellRenderer(renderer);
     96                    l.setVisibleRowCount(l.getModel().getSize() < 6 ? l.getModel().getSize() : 10);
     97                    p.add(new JScrollPane(l), GBC.eol().fill());
     98                }
    9999
    100                                 return JOptionPane.showConfirmDialog(Main.parent, p, tr("Upload these changes?"),
    101                                                 JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION;
    102                         }
    103                 });
    104         }
     100                return JOptionPane.showConfirmDialog(Main.parent, p, tr("Upload these changes?"),
     101                        JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION;
     102            }
     103        });
     104    }
    105105
    106         public void actionPerformed(ActionEvent e) {
    107                 if (Main.map == null) {
    108                         JOptionPane.showMessageDialog(Main.parent,tr("Nothing to upload. Get some data first."));
    109                         return;
    110                 }
     106    public void actionPerformed(ActionEvent e) {
     107        if (Main.map == null) {
     108            JOptionPane.showMessageDialog(Main.parent,tr("Nothing to upload. Get some data first."));
     109            return;
     110        }
    111111
    112                 if (!Main.map.conflictDialog.conflicts.isEmpty()) {
    113                         JOptionPane.showMessageDialog(Main.parent,tr("There are unresolved conflicts. You have to resolve these first."));
    114                         Main.map.conflictDialog.action.button.setSelected(true);
    115                         Main.map.conflictDialog.action.actionPerformed(null);
    116                         return;
    117                 }
     112        if (!Main.map.conflictDialog.conflicts.isEmpty()) {
     113            JOptionPane.showMessageDialog(Main.parent,tr("There are unresolved conflicts. You have to resolve these first."));
     114            Main.map.conflictDialog.action.button.setSelected(true);
     115            Main.map.conflictDialog.action.actionPerformed(null);
     116            return;
     117        }
    118118
    119                 final LinkedList<OsmPrimitive> add = new LinkedList<OsmPrimitive>();
    120                 final LinkedList<OsmPrimitive> update = new LinkedList<OsmPrimitive>();
    121                 final LinkedList<OsmPrimitive> delete = new LinkedList<OsmPrimitive>();
    122                 for (OsmPrimitive osm : Main.ds.allPrimitives()) {
    123                         if (osm.get("josm/ignore") != null)
    124                                 continue;
    125                         if (osm.id == 0 && !osm.deleted)
    126                                 add.addLast(osm);
    127                         else if (osm.modified && !osm.deleted)
    128                                 update.addLast(osm);
    129                         else if (osm.deleted && osm.id != 0)
    130                                 delete.addFirst(osm);
    131                 }
     119        final LinkedList<OsmPrimitive> add = new LinkedList<OsmPrimitive>();
     120        final LinkedList<OsmPrimitive> update = new LinkedList<OsmPrimitive>();
     121        final LinkedList<OsmPrimitive> delete = new LinkedList<OsmPrimitive>();
     122        for (OsmPrimitive osm : Main.ds.allPrimitives()) {
     123            if (osm.get("josm/ignore") != null)
     124                continue;
     125            if (osm.id == 0 && !osm.deleted)
     126                add.addLast(osm);
     127            else if (osm.modified && !osm.deleted)
     128                update.addLast(osm);
     129            else if (osm.deleted && osm.id != 0)
     130                delete.addFirst(osm);
     131        }
    132132
    133                 if (add.isEmpty() && update.isEmpty() && delete.isEmpty()) {
    134                         JOptionPane.showMessageDialog(Main.parent,tr("No changes to upload."));
    135                         return;
    136                 }
     133        if (add.isEmpty() && update.isEmpty() && delete.isEmpty()) {
     134            JOptionPane.showMessageDialog(Main.parent,tr("No changes to upload."));
     135            return;
     136        }
    137137
    138                 // Call all upload hooks in sequence. The upload confirmation dialog
    139                 // is one of these.
    140                 for(UploadHook hook : uploadHooks)
    141                         if(!hook.checkUpload(add, update, delete))
    142                                 return;
     138        // Call all upload hooks in sequence. The upload confirmation dialog
     139        // is one of these.
     140        for(UploadHook hook : uploadHooks)
     141            if(!hook.checkUpload(add, update, delete))
     142                return;
    143143
    144                 final OsmServerWriter server = new OsmServerWriter();
    145                 final Collection<OsmPrimitive> all = new LinkedList<OsmPrimitive>();
    146                 all.addAll(add);
    147                 all.addAll(update);
    148                 all.addAll(delete);
     144        final OsmServerWriter server = new OsmServerWriter();
     145        final Collection<OsmPrimitive> all = new LinkedList<OsmPrimitive>();
     146        all.addAll(add);
     147        all.addAll(update);
     148        all.addAll(delete);
    149149
    150                 PleaseWaitRunnable uploadTask = new PleaseWaitRunnable(tr("Uploading data")){
    151                         @Override protected void realRun() throws SAXException {
    152                                 server.uploadOsm(all);
    153                         }
    154                         @Override protected void finish() {
    155                                 Main.main.editLayer().cleanData(server.processed, !add.isEmpty());
    156                         }
    157                         @Override protected void cancel() {
    158                                 server.cancel();
    159                         }
    160                 };
    161                 Main.worker.execute(uploadTask);
    162         }
     150        PleaseWaitRunnable uploadTask = new PleaseWaitRunnable(tr("Uploading data")){
     151            @Override protected void realRun() throws SAXException {
     152                server.uploadOsm(all);
     153            }
     154            @Override protected void finish() {
     155                Main.main.editLayer().cleanData(server.processed, !add.isEmpty());
     156            }
     157            @Override protected void cancel() {
     158                server.cancel();
     159            }
     160        };
     161        Main.worker.execute(uploadTask);
     162    }
    163163}
  • trunk/src/org/openstreetmap/josm/actions/ZoomInAction.java

    r1087 r1169  
    1212public final class ZoomInAction extends JosmAction {
    1313
    14         public ZoomInAction() {
    15                 super(tr("Zoom in"), "dialogs/zoomin", tr("Zoom in"),
    16                 Shortcut.registerShortcut("view:zoomin", tr("View: {0}", tr("Zoom in")), KeyEvent.VK_PLUS, Shortcut.GROUP_DIRECT), true);
    17                 setEnabled(true);
    18         }
     14    public ZoomInAction() {
     15        super(tr("Zoom in"), "dialogs/zoomin", tr("Zoom in"),
     16        Shortcut.registerShortcut("view:zoomin", tr("View: {0}", tr("Zoom in")), KeyEvent.VK_PLUS, Shortcut.GROUP_DIRECT), true);
     17        setEnabled(true);
     18    }
    1919
    20         public void actionPerformed(ActionEvent e) {
     20    public void actionPerformed(ActionEvent e) {
    2121        if (Main.map == null) return;
    22                 double zoom = Main.map.mapView.getScale();
    23                 Main.map.mapView.zoomTo(Main.map.mapView.getCenter(), zoom * .9);
    24         }
     22        double zoom = Main.map.mapView.getScale();
     23        Main.map.mapView.zoomTo(Main.map.mapView.getCenter(), zoom * .9);
     24    }
    2525}
  • trunk/src/org/openstreetmap/josm/actions/ZoomOutAction.java

    r1087 r1169  
    1212public final class ZoomOutAction extends JosmAction {
    1313
    14         public ZoomOutAction() {
    15                 super(tr("Zoom out"), "dialogs/zoomout", tr("Zoom out"),
    16                 Shortcut.registerShortcut("view:zoomout", tr("View: {0}", tr("Zoom out")), KeyEvent.VK_MINUS, Shortcut.GROUP_DIRECT), true);
    17                 setEnabled(true);
    18         }
     14    public ZoomOutAction() {
     15        super(tr("Zoom out"), "dialogs/zoomout", tr("Zoom out"),
     16        Shortcut.registerShortcut("view:zoomout", tr("View: {0}", tr("Zoom out")), KeyEvent.VK_MINUS, Shortcut.GROUP_DIRECT), true);
     17        setEnabled(true);
     18    }
    1919
    20         public void actionPerformed(ActionEvent e) {
     20    public void actionPerformed(ActionEvent e) {
    2121        if (Main.map == null) return;
    22                 double zoom = Main.map.mapView.getScale();
    23                 Main.map.mapView.zoomTo(Main.map.mapView.getCenter(), zoom /.9);
    24         }
     22        double zoom = Main.map.mapView.getScale();
     23        Main.map.mapView.zoomTo(Main.map.mapView.getCenter(), zoom /.9);
     24    }
    2525}
  • trunk/src/org/openstreetmap/josm/actions/audio/AudioBackAction.java

    r1084 r1169  
    1515public class AudioBackAction extends JosmAction {
    1616
    17         private double amount; // note, normally negative, i.e. jump backwards in time
     17    private double amount; // note, normally negative, i.e. jump backwards in time
    1818
    19         public AudioBackAction() {
    20                 super(tr("Back"), "audio-back", tr("Jump back."),
    21                 Shortcut.registerShortcut("audio:back", tr("Audio: {0}", tr("Back")), KeyEvent.VK_F6, Shortcut.GROUP_DIRECT), true);
    22                 try {
    23                         amount = - Double.parseDouble(Main.pref.get("audio.forwardbackamount","10.0"));
    24                 } catch (NumberFormatException e) {
    25                         amount = 10.0;
    26                 }
    27                 this.putValue("help", "Action/Back");
    28         }
     19    public AudioBackAction() {
     20        super(tr("Back"), "audio-back", tr("Jump back."),
     21        Shortcut.registerShortcut("audio:back", tr("Audio: {0}", tr("Back")), KeyEvent.VK_F6, Shortcut.GROUP_DIRECT), true);
     22        try {
     23            amount = - Double.parseDouble(Main.pref.get("audio.forwardbackamount","10.0"));
     24        } catch (NumberFormatException e) {
     25            amount = 10.0;
     26        }
     27        this.putValue("help", "Action/Back");
     28    }
    2929
    30         public void actionPerformed(ActionEvent e) {
    31                 try {
    32                         if (AudioPlayer.playing() || AudioPlayer.paused())
    33                                 AudioPlayer.play(AudioPlayer.url(), AudioPlayer.position() + amount);
    34                         else
    35                                 MarkerLayer.playAudio();
    36                 } catch (Exception ex) {
    37                         AudioPlayer.audioMalfunction(ex);
    38                 }
    39         }
     30    public void actionPerformed(ActionEvent e) {
     31        try {
     32            if (AudioPlayer.playing() || AudioPlayer.paused())
     33                AudioPlayer.play(AudioPlayer.url(), AudioPlayer.position() + amount);
     34            else
     35                MarkerLayer.playAudio();
     36        } catch (Exception ex) {
     37            AudioPlayer.audioMalfunction(ex);
     38        }
     39    }
    4040}
  • trunk/src/org/openstreetmap/josm/actions/audio/AudioFastSlowAction.java

    r1084 r1169  
    1111abstract public class AudioFastSlowAction extends JosmAction {
    1212
    13         private double multiplier;
     13    private double multiplier;
    1414
    15         public AudioFastSlowAction(String name, String iconName, String tooltip, Shortcut shortcut, boolean fast) {
    16                 super(name, iconName, tooltip, shortcut, true);
    17                 try {
    18                         multiplier = Double.parseDouble(Main.pref.get("audio.fastfwdmultiplier","1.3"));
    19                 } catch (NumberFormatException e) {
    20                         multiplier = 1.3;
    21                 }
    22                 if (! fast)
    23                         multiplier = 1.0 / multiplier;
    24         }
     15    public AudioFastSlowAction(String name, String iconName, String tooltip, Shortcut shortcut, boolean fast) {
     16        super(name, iconName, tooltip, shortcut, true);
     17        try {
     18            multiplier = Double.parseDouble(Main.pref.get("audio.fastfwdmultiplier","1.3"));
     19        } catch (NumberFormatException e) {
     20            multiplier = 1.3;
     21        }
     22        if (! fast)
     23            multiplier = 1.0 / multiplier;
     24    }
    2525
    26         @Deprecated
    27         public AudioFastSlowAction(String name, String iconName, String tooltip, int shortcut, int modifier, boolean fast) {
    28                 super(name, iconName, tooltip, shortcut, modifier, true);
    29                 try {
    30                         multiplier = Double.parseDouble(Main.pref.get("audio.fastfwdmultiplier","1.3"));
    31                 } catch (NumberFormatException e) {
    32                         multiplier = 1.3;
    33                 }
    34                 if (! fast)
    35                         multiplier = 1.0 / multiplier;
    36         }
     26    @Deprecated
     27    public AudioFastSlowAction(String name, String iconName, String tooltip, int shortcut, int modifier, boolean fast) {
     28        super(name, iconName, tooltip, shortcut, modifier, true);
     29        try {
     30            multiplier = Double.parseDouble(Main.pref.get("audio.fastfwdmultiplier","1.3"));
     31        } catch (NumberFormatException e) {
     32            multiplier = 1.3;
     33        }
     34        if (! fast)
     35            multiplier = 1.0 / multiplier;
     36    }
    3737
    38         public void actionPerformed(ActionEvent e) {
    39                 double speed = AudioPlayer.speed();
    40                 if (speed * multiplier <= 0.1)
    41                         return;
    42                 try {
    43                         if (AudioPlayer.playing() || AudioPlayer.paused())
    44                                 AudioPlayer.play(AudioPlayer.url(), AudioPlayer.position(), speed * multiplier);
    45                 } catch (Exception ex) {
    46                         AudioPlayer.audioMalfunction(ex);
    47                 }
    48         }
     38    public void actionPerformed(ActionEvent e) {
     39        double speed = AudioPlayer.speed();
     40        if (speed * multiplier <= 0.1)
     41            return;
     42        try {
     43            if (AudioPlayer.playing() || AudioPlayer.paused())
     44                AudioPlayer.play(AudioPlayer.url(), AudioPlayer.position(), speed * multiplier);
     45        } catch (Exception ex) {
     46            AudioPlayer.audioMalfunction(ex);
     47        }
     48    }
    4949}
  • trunk/src/org/openstreetmap/josm/actions/audio/AudioFasterAction.java

    r1084 r1169  
    99public class AudioFasterAction extends AudioFastSlowAction {
    1010
    11         public AudioFasterAction() {
    12                 super(tr("Faster"), "audio-faster", tr("Faster Forward"),
    13                 Shortcut.registerShortcut("audio:faster", tr("Audio: {0}", tr("Faster")), KeyEvent.VK_F9, Shortcut.GROUP_DIRECT), true);
    14         }
     11    public AudioFasterAction() {
     12        super(tr("Faster"), "audio-faster", tr("Faster Forward"),
     13        Shortcut.registerShortcut("audio:faster", tr("Audio: {0}", tr("Faster")), KeyEvent.VK_F9, Shortcut.GROUP_DIRECT), true);
     14    }
    1515}
  • trunk/src/org/openstreetmap/josm/actions/audio/AudioFwdAction.java

    r1084 r1169  
    1515public class AudioFwdAction extends JosmAction {
    1616
    17         private double amount;
     17    private double amount;
    1818
    19         public AudioFwdAction() {
    20                 super(tr("Forward"), "audio-fwd", tr("Jump forward"),
    21                 Shortcut.registerShortcut("audio:forward", tr("Audio: {0}", tr("Forward")), KeyEvent.VK_F7, Shortcut.GROUP_DIRECT), true);
    22                 try {
    23                         amount = Double.parseDouble(Main.pref.get("audio.forwardbackamount","10.0"));
    24                 } catch (NumberFormatException e) {
    25                         amount = 10.0;
    26                 }
    27         }
     19    public AudioFwdAction() {
     20        super(tr("Forward"), "audio-fwd", tr("Jump forward"),
     21        Shortcut.registerShortcut("audio:forward", tr("Audio: {0}", tr("Forward")), KeyEvent.VK_F7, Shortcut.GROUP_DIRECT), true);
     22        try {
     23            amount = Double.parseDouble(Main.pref.get("audio.forwardbackamount","10.0"));
     24        } catch (NumberFormatException e) {
     25            amount = 10.0;
     26        }
     27    }
    2828
    29         public void actionPerformed(ActionEvent e) {
    30                 try {
    31                         if (AudioPlayer.playing() || AudioPlayer.paused())
    32                                 AudioPlayer.play(AudioPlayer.url(), AudioPlayer.position() + amount);
    33                         else
    34                                 MarkerLayer.playAudio();
    35                 } catch (Exception ex) {
    36                         AudioPlayer.audioMalfunction(ex);
    37                 }
    38         }
     29    public void actionPerformed(ActionEvent e) {
     30        try {
     31            if (AudioPlayer.playing() || AudioPlayer.paused())
     32                AudioPlayer.play(AudioPlayer.url(), AudioPlayer.position() + amount);
     33            else
     34                MarkerLayer.playAudio();
     35        } catch (Exception ex) {
     36            AudioPlayer.audioMalfunction(ex);
     37        }
     38    }
    3939}
  • trunk/src/org/openstreetmap/josm/actions/audio/AudioNextAction.java

    r1084 r1169  
    1313public class AudioNextAction extends JosmAction {
    1414
    15         public AudioNextAction() {
    16                 super(tr("Next Marker"), "audio-next", tr("Play next marker."),
    17                 Shortcut.registerShortcut("audio:next", tr("Audio: {0}", tr("Next Marker")), KeyEvent.VK_F8, Shortcut.GROUP_DIRECT), true);
    18         }
     15    public AudioNextAction() {
     16        super(tr("Next Marker"), "audio-next", tr("Play next marker."),
     17        Shortcut.registerShortcut("audio:next", tr("Audio: {0}", tr("Next Marker")), KeyEvent.VK_F8, Shortcut.GROUP_DIRECT), true);
     18    }
    1919
    20         public void actionPerformed(ActionEvent e) {
    21                 MarkerLayer.playNextMarker();
    22         }
     20    public void actionPerformed(ActionEvent e) {
     21        MarkerLayer.playNextMarker();
     22    }
    2323}
  • trunk/src/org/openstreetmap/josm/actions/audio/AudioPlayPauseAction.java

    r1084 r1169  
    1515public class AudioPlayPauseAction extends JosmAction {
    1616
    17         public AudioPlayPauseAction() {
    18                 super(tr("Play/pause"), "audio-playpause", tr("Play/pause audio."),
    19                 Shortcut.registerShortcut("audio:pause", tr("Audio: {0}", tr("Play/pause")), KeyEvent.VK_PERIOD, Shortcut.GROUP_DIRECT), true);
    20         }
     17    public AudioPlayPauseAction() {
     18        super(tr("Play/pause"), "audio-playpause", tr("Play/pause audio."),
     19        Shortcut.registerShortcut("audio:pause", tr("Audio: {0}", tr("Play/pause")), KeyEvent.VK_PERIOD, Shortcut.GROUP_DIRECT), true);
     20    }
    2121
    22         public void actionPerformed(ActionEvent e) {
    23                 URL url = AudioPlayer.url();
    24                 try {
    25                         if (AudioPlayer.paused() && url != null) {
    26                                 AudioPlayer.play(url);
    27                         } else if (AudioPlayer.playing()){
    28                                 if (AudioPlayer.speed() != 1.0)
    29                                         AudioPlayer.play(url, AudioPlayer.position());
    30                                 else
    31                                         AudioPlayer.pause();
    32                         } else {
    33                                 // find first audio marker to play
    34                                 MarkerLayer.playAudio();
    35                         }
    36                 } catch (Exception ex) {
    37                         AudioPlayer.audioMalfunction(ex);
    38                 }
    39         }
     22    public void actionPerformed(ActionEvent e) {
     23        URL url = AudioPlayer.url();
     24        try {
     25            if (AudioPlayer.paused() && url != null) {
     26                AudioPlayer.play(url);
     27            } else if (AudioPlayer.playing()){
     28                if (AudioPlayer.speed() != 1.0)
     29                    AudioPlayer.play(url, AudioPlayer.position());
     30                else
     31                    AudioPlayer.pause();
     32            } else {
     33                // find first audio marker to play
     34                MarkerLayer.playAudio();
     35            }
     36        } catch (Exception ex) {
     37            AudioPlayer.audioMalfunction(ex);
     38        }
     39    }
    4040}
  • trunk/src/org/openstreetmap/josm/actions/audio/AudioPrevAction.java

    r1084 r1169  
    1313public class AudioPrevAction extends JosmAction {
    1414
    15         public AudioPrevAction() {
    16                 super(tr("Previous Marker"), "audio-prev", tr("Play previous marker."),
    17                 Shortcut.registerShortcut("audio:prev", tr("Audio: {0}", tr("Previous Marker")), KeyEvent.VK_F5, Shortcut.GROUP_DIRECT), true);
    18         }
     15    public AudioPrevAction() {
     16        super(tr("Previous Marker"), "audio-prev", tr("Play previous marker."),
     17        Shortcut.registerShortcut("audio:prev", tr("Audio: {0}", tr("Previous Marker")), KeyEvent.VK_F5, Shortcut.GROUP_DIRECT), true);
     18    }
    1919
    20         public void actionPerformed(ActionEvent e) {
    21                 MarkerLayer.playPreviousMarker();
    22         }
     20    public void actionPerformed(ActionEvent e) {
     21        MarkerLayer.playPreviousMarker();
     22    }
    2323}
  • trunk/src/org/openstreetmap/josm/actions/audio/AudioSlowerAction.java

    r1084 r1169  
    99public class AudioSlowerAction extends AudioFastSlowAction {
    1010
    11         public AudioSlowerAction() {
    12                 super(tr("Slower"), "audio-slower", tr("Slower Forward"),
    13                 Shortcut.registerShortcut("audio:slower", tr("Audio: {0}", tr("Slower")), KeyEvent.VK_F4, Shortcut.GROUP_DIRECT), true);
    14         }
     11    public AudioSlowerAction() {
     12        super(tr("Slower"), "audio-slower", tr("Slower Forward"),
     13        Shortcut.registerShortcut("audio:slower", tr("Audio: {0}", tr("Slower")), KeyEvent.VK_F4, Shortcut.GROUP_DIRECT), true);
     14    }
    1515}
  • trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadGpsTask.java

    r1148 r1169  
    2121public class DownloadGpsTask implements DownloadTask {
    2222
    23         private static class Task extends PleaseWaitRunnable {
    24                 private BoundingBoxDownloader reader;
    25                 private GpxData rawData;
    26                 private final boolean newLayer;
     23    private static class Task extends PleaseWaitRunnable {
     24        private BoundingBoxDownloader reader;
     25        private GpxData rawData;
     26        private final boolean newLayer;
    2727
    28                 public Task(boolean newLayer, BoundingBoxDownloader reader) {
    29                         super(tr("Downloading GPS data"));
    30                         this.reader = reader;
    31                         this.newLayer = newLayer;
    32                 }
     28        public Task(boolean newLayer, BoundingBoxDownloader reader) {
     29            super(tr("Downloading GPS data"));
     30            this.reader = reader;
     31            this.newLayer = newLayer;
     32        }
    3333
    34                 @Override public void realRun() throws IOException, SAXException {
    35                         rawData = reader.parseRawGps();
    36                 }
     34        @Override public void realRun() throws IOException, SAXException {
     35            rawData = reader.parseRawGps();
     36        }
    3737
    38                 @Override protected void finish() {
    39                         if (rawData == null)
    40                                 return;
     38        @Override protected void finish() {
     39            if (rawData == null)
     40                return;
    4141                        rawData.recalculateBounds();
    4242                        Bounds b = rawData.bounds;
    43                                                 String name = b.min.lat() + " " + b.min.lon() + " x " + b.max.lat() + " " + b.max.lon();
    44                                                 GpxLayer layer = new GpxLayer(rawData, name);
    45                         if (newLayer || findMergeLayer() == null)
    46                     Main.main.addLayer(layer);
    47                         else
    48                                 findMergeLayer().mergeFrom(layer);
    49                 }
    50 
    51                 private Layer findMergeLayer() {
    52                         if (Main.map == null)
    53                                 return null;
    54                 Layer active = Main.map.mapView.getActiveLayer();
    55                 if (active != null && active instanceof GpxLayer)
    56                         return active;
    57                 for (Layer l : Main.map.mapView.getAllLayers())
    58                                 if (l instanceof GpxLayer)
    59                                 return l;
    60                 return null;
     43                        String name = b.min.lat() + " " + b.min.lon() + " x " + b.max.lat() + " " + b.max.lon();
     44                        GpxLayer layer = new GpxLayer(rawData, name);
     45            if (newLayer || findMergeLayer() == null)
     46                Main.main.addLayer(layer);
     47            else
     48                findMergeLayer().mergeFrom(layer);
    6149        }
    6250
    63                 @Override protected void cancel() {
    64                         if (reader != null)
    65                                 reader.cancel();
    66                 }
    67         }
     51        private Layer findMergeLayer() {
     52            if (Main.map == null)
     53                return null;
     54            Layer active = Main.map.mapView.getActiveLayer();
     55            if (active != null && active instanceof GpxLayer)
     56                return active;
     57            for (Layer l : Main.map.mapView.getAllLayers())
     58                if (l instanceof GpxLayer)
     59                    return l;
     60            return null;
     61        }
    6862
    69         private JCheckBox checkBox = new JCheckBox(tr("Raw GPS data"));
    70 
    71         public void download(DownloadAction action, double minlat, double minlon, double maxlat, double maxlon) {
    72                 Task task = new Task(action.dialog.newLayer.isSelected(), new BoundingBoxDownloader(minlat, minlon, maxlat, maxlon));
    73                 Main.worker.execute(task);
    74         }
    75 
    76         public JCheckBox getCheckBox() {
    77             return checkBox;
     63        @Override protected void cancel() {
     64            if (reader != null)
     65                reader.cancel();
     66        }
    7867    }
    7968
    80         public String getPreferencesSuffix() {
    81             return "gps";
     69    private JCheckBox checkBox = new JCheckBox(tr("Raw GPS data"));
     70
     71    public void download(DownloadAction action, double minlat, double minlon, double maxlat, double maxlon) {
     72        Task task = new Task(action.dialog.newLayer.isSelected(), new BoundingBoxDownloader(minlat, minlon, maxlat, maxlon));
     73        Main.worker.execute(task);
    8274    }
    8375
    84     public void loadUrl(boolean a,java.lang.String b) {
     76    public JCheckBox getCheckBox() {
     77        return checkBox;
     78    }
     79
     80    public String getPreferencesSuffix() {
     81        return "gps";
     82    }
     83
     84    public void loadUrl(boolean a,java.lang.String b) {
    8585        // FIXME this is not currently used
    8686    }
  • trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java

    r1146 r1169  
    3131    private static Bounds currentBounds;
    3232
    33         private static class Task extends PleaseWaitRunnable {
    34                 private OsmServerReader reader;
    35                 private DataSet dataSet;
    36                 private boolean newLayer;
     33    private static class Task extends PleaseWaitRunnable {
     34        private OsmServerReader reader;
     35        private DataSet dataSet;
     36        private boolean newLayer;
    3737
    38                 public Task(boolean newLayer, OsmServerReader reader) {
    39                         super(tr("Downloading data"));
    40                         this.reader = reader;
    41                         this.newLayer = newLayer;
    42                 }
     38        public Task(boolean newLayer, OsmServerReader reader) {
     39            super(tr("Downloading data"));
     40            this.reader = reader;
     41            this.newLayer = newLayer;
     42        }
    4343
    44                 @Override public void realRun() throws IOException, SAXException {
    45                         dataSet = reader.parseOsm();
    46                 }
     44        @Override public void realRun() throws IOException, SAXException {
     45            dataSet = reader.parseOsm();
     46        }
    4747
    48                 @Override protected void finish() {
    49                         if (dataSet == null)
    50                                 return; // user cancelled download or error occoured
    51                         if (dataSet.allPrimitives().isEmpty()) {
    52                                 errorMessage = tr("No data imported.");
     48        @Override protected void finish() {
     49            if (dataSet == null)
     50                return; // user cancelled download or error occoured
     51            if (dataSet.allPrimitives().isEmpty()) {
     52                errorMessage = tr("No data imported.");
    5353                // need to synthesize a download bounds lest the visual indication of downloaded
    5454                // area doesn't work
     
    5656            }
    5757
    58                         OsmDataLayer layer = new OsmDataLayer(dataSet, tr("Data Layer"), null);
    59                         if (newLayer)
    60                                 Main.main.addLayer(layer);
    61                         else
    62                                 Main.main.editLayer().mergeFrom(layer);
    63                 }
     58            OsmDataLayer layer = new OsmDataLayer(dataSet, tr("Data Layer"), null);
     59            if (newLayer)
     60                Main.main.addLayer(layer);
     61            else
     62                Main.main.editLayer().mergeFrom(layer);
     63        }
    6464
    65                 @Override protected void cancel() {
    66                         if (reader != null)
    67                                 reader.cancel();
    68                 }
    69         }
    70         private JCheckBox checkBox = new JCheckBox(tr("OpenStreetMap data"), true);
     65        @Override protected void cancel() {
     66            if (reader != null)
     67                reader.cancel();
     68        }
     69    }
     70    private JCheckBox checkBox = new JCheckBox(tr("OpenStreetMap data"), true);
    7171
    72         public void download(DownloadAction action, double minlat, double minlon, double maxlat, double maxlon) {
    73                 // Swap min and max if user has specified them the wrong way round
    74                 // (easy to do if you are crossing 0, for example)
    75                 // FIXME should perhaps be done in download dialog?
    76                 if (minlat > maxlat) {
    77                         double t = minlat; minlat = maxlat; maxlat = t;
    78                 }
    79                 if (minlon > maxlon) {
    80                         double t = minlon; minlon = maxlon; maxlon = t;
    81                 }
    82    
    83                 Task task = new Task(action != null && (action.dialog == null || action.dialog.newLayer.isSelected()), new BoundingBoxDownloader(minlat, minlon, maxlat, maxlon));
     72    public void download(DownloadAction action, double minlat, double minlon, double maxlat, double maxlon) {
     73        // Swap min and max if user has specified them the wrong way round
     74        // (easy to do if you are crossing 0, for example)
     75        // FIXME should perhaps be done in download dialog?
     76        if (minlat > maxlat) {
     77            double t = minlat; minlat = maxlat; maxlat = t;
     78        }
     79        if (minlon > maxlon) {
     80            double t = minlon; minlon = maxlon; maxlon = t;
     81        }
     82
     83        Task task = new Task(action != null && (action.dialog == null || action.dialog.newLayer.isSelected()), new BoundingBoxDownloader(minlat, minlon, maxlat, maxlon));
    8484        currentBounds = new Bounds(new LatLon(minlat, minlon), new LatLon(maxlat, maxlon));
    85                 Main.worker.execute(task);
     85        Main.worker.execute(task);
    8686    }
    87    
     87
    8888    public void loadUrl(boolean new_layer, String url) {
    8989        Task task = new Task(new_layer, new OsmServerLocationReader(url));
    9090        Main.worker.execute(task);
    9191    }
    92    
    93    
    94    
    9592
    96         public JCheckBox getCheckBox() {
    97             return checkBox;
     93
     94
     95
     96    public JCheckBox getCheckBox() {
     97        return checkBox;
    9898    }
    9999
    100         public String getPreferencesSuffix() {
    101             return "osm";
     100    public String getPreferencesSuffix() {
     101        return "osm";
    102102    }
    103103}
  • trunk/src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java

    r1150 r1169  
    3636public class DeleteAction extends MapMode {
    3737
    38         /**
    39         * Construct a new DeleteAction. Mnemonic is the delete - key.
    40         * @param mapFrame The frame this action belongs to.
    41         */
    42         public DeleteAction(MapFrame mapFrame) {
    43                 super(tr("Delete Mode"),
    44                                 "delete",
    45                                 tr("Delete nodes or ways."),
    46                                 Shortcut.registerShortcut("mapmode:delete", tr("Mode: {0}",tr("Delete")), KeyEvent.VK_D, Shortcut.GROUP_EDIT),
    47                                 mapFrame,
    48                                 ImageProvider.getCursor("normal", "delete"));
    49         }
     38    /**
     39    * Construct a new DeleteAction. Mnemonic is the delete - key.
     40    * @param mapFrame The frame this action belongs to.
     41    */
     42    public DeleteAction(MapFrame mapFrame) {
     43        super(tr("Delete Mode"),
     44                "delete",
     45                tr("Delete nodes or ways."),
     46                Shortcut.registerShortcut("mapmode:delete", tr("Mode: {0}",tr("Delete")), KeyEvent.VK_D, Shortcut.GROUP_EDIT),
     47                mapFrame,
     48                ImageProvider.getCursor("normal", "delete"));
     49    }
    5050
    51         @Override public void enterMode() {
    52                 super.enterMode();
    53                 Main.map.mapView.addMouseListener(this);
    54         }
     51    @Override public void enterMode() {
     52        super.enterMode();
     53        Main.map.mapView.addMouseListener(this);
     54    }
    5555
    56         @Override public void exitMode() {
    57                 super.exitMode();
    58                 Main.map.mapView.removeMouseListener(this);
    59         }
     56    @Override public void exitMode() {
     57        super.exitMode();
     58        Main.map.mapView.removeMouseListener(this);
     59    }
    6060
    6161
    62         @Override public void actionPerformed(ActionEvent e) {
    63                 super.actionPerformed(e);
    64                 if(!Main.map.mapView.isDrawableLayer())
    65                         return;
    66                 doActionPerformed(e);
    67         }
     62    @Override public void actionPerformed(ActionEvent e) {
     63        super.actionPerformed(e);
     64        if(!Main.map.mapView.isDrawableLayer())
     65            return;
     66        doActionPerformed(e);
     67    }
    6868
    69         public void doActionPerformed(ActionEvent e) {
    70                 if(!Main.map.mapView.isDrawableLayer())
    71                         return;
    72                 boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
    73                 boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
     69    public void doActionPerformed(ActionEvent e) {
     70        if(!Main.map.mapView.isDrawableLayer())
     71            return;
     72        boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
     73        boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
    7474
    75                 Command c;
    76                 if (ctrl) {
    77                         c = DeleteCommand.deleteWithReferences(Main.ds.getSelected());
    78                 } else {
    79                         c = DeleteCommand.delete(Main.ds.getSelected(), !alt);
    80                 }
    81                 if (c != null) {
    82                         Main.main.undoRedo.add(c);
    83                 }
     75        Command c;
     76        if (ctrl) {
     77            c = DeleteCommand.deleteWithReferences(Main.ds.getSelected());
     78        } else {
     79            c = DeleteCommand.delete(Main.ds.getSelected(), !alt);
     80        }
     81        if (c != null) {
     82            Main.main.undoRedo.add(c);
     83        }
    8484
    85                 Main.ds.setSelected();
    86                 Main.map.repaint();
    87         }
     85        Main.ds.setSelected();
     86        Main.map.repaint();
     87    }
    8888
    89         /**
    90         * If user clicked with the left button, delete the nearest object.
    91         * position.
    92         */
    93         @Override public void mouseClicked(MouseEvent e) {
    94                 if (e.getButton() != MouseEvent.BUTTON1)
    95                         return;
    96                 if(!Main.map.mapView.isDrawableLayer())
    97                         return;
    98                 boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
    99                 boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
    100                 boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
     89    /**
     90    * If user clicked with the left button, delete the nearest object.
     91    * position.
     92    */
     93    @Override public void mouseClicked(MouseEvent e) {
     94        if (e.getButton() != MouseEvent.BUTTON1)
     95            return;
     96        if(!Main.map.mapView.isDrawableLayer())
     97            return;
     98        boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
     99        boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
     100        boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
    101101
    102                 OsmPrimitive sel = Main.map.mapView.getNearestNode(e.getPoint());
    103                 Command c = null;
    104                 if (sel == null) {
    105                         WaySegment ws = Main.map.mapView.getNearestWaySegment(e.getPoint());
    106                         if (ws != null) {
    107                                 if (shift) {
    108                                         c = DeleteCommand.deleteWaySegment(ws);
    109                                 } else if (ctrl) {
    110                                         c = DeleteCommand.deleteWithReferences(Collections.singleton((OsmPrimitive)ws.way));
    111                                 } else {
    112                                         c = DeleteCommand.delete(Collections.singleton((OsmPrimitive)ws.way), !alt);
    113                                 }
    114                         }
    115                 } else if (ctrl) {
    116                         c = DeleteCommand.deleteWithReferences(Collections.singleton(sel));
    117                 } else {
    118                         c = DeleteCommand.delete(Collections.singleton(sel), !alt);
    119                 }
    120                 if (c != null) {
    121                         Main.main.undoRedo.add(c);
    122                 }
     102        OsmPrimitive sel = Main.map.mapView.getNearestNode(e.getPoint());
     103        Command c = null;
     104        if (sel == null) {
     105            WaySegment ws = Main.map.mapView.getNearestWaySegment(e.getPoint());
     106            if (ws != null) {
     107                if (shift) {
     108                    c = DeleteCommand.deleteWaySegment(ws);
     109                } else if (ctrl) {
     110                    c = DeleteCommand.deleteWithReferences(Collections.singleton((OsmPrimitive)ws.way));
     111                } else {
     112                    c = DeleteCommand.delete(Collections.singleton((OsmPrimitive)ws.way), !alt);
     113                }
     114            }
     115        } else if (ctrl) {
     116            c = DeleteCommand.deleteWithReferences(Collections.singleton(sel));
     117        } else {
     118            c = DeleteCommand.delete(Collections.singleton(sel), !alt);
     119        }
     120        if (c != null) {
     121            Main.main.undoRedo.add(c);
     122        }
    123123
    124                 Main.ds.setSelected();
    125                 Main.map.mapView.repaint();
    126         }
     124        Main.ds.setSelected();
     125        Main.map.mapView.repaint();
     126    }
    127127
    128         @Override public String getModeHelpText() {
    129                 return tr("Click to delete. Shift: delete way segment. Alt: don't delete unused nodes when deleting a way. Ctrl: delete referring objects.");
    130         }
     128    @Override public String getModeHelpText() {
     129        return tr("Click to delete. Shift: delete way segment. Alt: don't delete unused nodes when deleting a way. Ctrl: delete referring objects.");
     130    }
    131131}
  • trunk/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java

    r1084 r1169  
    5858public class DrawAction extends MapMode implements MapViewPaintable, SelectionChangedListener, AWTEventListener {
    5959
    60         private static Node lastUsedNode = null;
    61         private double PHI=Math.toRadians(90);
    62 
    63         private boolean ctrl;
    64         private boolean alt;
    65         private boolean shift;
    66         private boolean mouseOnExistingNode;
    67         private boolean drawHelperLine;
    68         private Point mousePos;
    69         private Color selectedColor;
    70 
    71         private Node currentBaseNode;
    72         private EastNorth currentMouseEastNorth;
    73 
    74         public DrawAction(MapFrame mapFrame) {
    75                 super(tr("Draw"), "node/autonode", tr("Draw nodes"),
    76                                 Shortcut.registerShortcut("mapmode:draw", tr("Mode: {0}", tr("Draw")), KeyEvent.VK_A, Shortcut.GROUP_EDIT),
    77                                 mapFrame, getCursor());
    78 
    79                 // Add extra shortcut N
    80                 Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
    81                         Shortcut.registerShortcut("mapmode:drawfocus", tr("Mode: Draw Focus"), KeyEvent.VK_N, Shortcut.GROUP_EDIT).getKeyStroke(), tr("Draw"));
    82 
    83                 //putValue("help", "Action/AddNode/Autnode");
    84                 selectedColor = Main.pref.getColor(marktr("selected"), Color.YELLOW);
    85 
    86                 drawHelperLine = Main.pref.getBoolean("draw.helper-line", true);
    87         }
    88 
    89         private static Cursor getCursor() {
    90                 try {
    91                 return ImageProvider.getCursor("crosshair", null);
     60    private static Node lastUsedNode = null;
     61    private double PHI=Math.toRadians(90);
     62
     63    private boolean ctrl;
     64    private boolean alt;
     65    private boolean shift;
     66    private boolean mouseOnExistingNode;
     67    private boolean drawHelperLine;
     68    private Point mousePos;
     69    private Color selectedColor;
     70
     71    private Node currentBaseNode;
     72    private EastNorth currentMouseEastNorth;
     73
     74    public DrawAction(MapFrame mapFrame) {
     75        super(tr("Draw"), "node/autonode", tr("Draw nodes"),
     76                Shortcut.registerShortcut("mapmode:draw", tr("Mode: {0}", tr("Draw")), KeyEvent.VK_A, Shortcut.GROUP_EDIT),
     77                mapFrame, getCursor());
     78
     79        // Add extra shortcut N
     80        Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
     81            Shortcut.registerShortcut("mapmode:drawfocus", tr("Mode: Draw Focus"), KeyEvent.VK_N, Shortcut.GROUP_EDIT).getKeyStroke(), tr("Draw"));
     82
     83        //putValue("help", "Action/AddNode/Autnode");
     84        selectedColor = Main.pref.getColor(marktr("selected"), Color.YELLOW);
     85
     86        drawHelperLine = Main.pref.getBoolean("draw.helper-line", true);
     87    }
     88
     89    private static Cursor getCursor() {
     90        try {
     91            return ImageProvider.getCursor("crosshair", null);
    9292        } catch (Exception e) {
    9393        }
    94             return Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
    95     }
    96 
    97         @Override public void enterMode() {
    98                 super.enterMode();
    99                 Main.map.mapView.addMouseListener(this);
    100                 Main.map.mapView.addMouseMotionListener(this);
    101                 Main.map.mapView.addTemporaryLayer(this);
    102                 DataSet.selListeners.add(this);
    103                 try {
    104                         Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.KEY_EVENT_MASK);
    105                 } catch (SecurityException ex) {
    106                 }
    107                 // would like to but haven't got mouse position yet:
    108                 // computeHelperLine(false, false, false);
    109         }
    110         @Override public void exitMode() {
    111                 super.exitMode();
    112                 Main.map.mapView.removeMouseListener(this);
    113                 Main.map.mapView.removeMouseMotionListener(this);
    114                 Main.map.mapView.removeTemporaryLayer(this);
    115                 DataSet.selListeners.remove(this);
    116                 try {
    117                         Toolkit.getDefaultToolkit().removeAWTEventListener(this);
    118                 } catch (SecurityException ex) {
    119                 }
    120         }
    121 
    122         /**
    123         * redraw to (possibly) get rid of helper line if selection changes.
    124         */
    125         public void eventDispatched(AWTEvent event) {
    126                 if(!Main.map.mapView.isDrawableLayer())
    127                         return;
    128                 InputEvent e = (InputEvent) event;
    129                 ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
    130                 alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
    131                 shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
    132                 computeHelperLine();
    133         }
    134         /**
    135         * redraw to (possibly) get rid of helper line if selection changes.
    136         */
    137         public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
    138                 if(!Main.map.mapView.isDrawableLayer())
    139                         return;
    140                 computeHelperLine();
    141         }
    142 
    143         /**
    144         * If user clicked with the left button, add a node at the current mouse
    145         * position.
    146         *
    147         * If in nodeway mode, insert the node into the way.
    148         */
    149         @Override public void mouseClicked(MouseEvent e) {
    150 
    151                 if (e.getButton() != MouseEvent.BUTTON1)
    152                         return;
    153                 if(!Main.map.mapView.isDrawableLayer())
    154                         return;
    155 
    156                 // we copy ctrl/alt/shift from the event just in case our global
    157                 // AWTEvent didn't make it through the security manager. Unclear
    158                 // if that can ever happen but better be safe.
    159                 ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
    160                 alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
    161                 shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
    162                 mousePos = e.getPoint();
    163 
    164                 Collection<OsmPrimitive> selection = Main.ds.getSelected();
    165                 Collection<Command> cmds = new LinkedList<Command>();
    166 
    167                 ArrayList<Way> reuseWays = new ArrayList<Way>(),
    168                         replacedWays = new ArrayList<Way>();
    169                 boolean newNode = false;
    170                 Node n = null;
    171 
    172                 if (!ctrl) {
    173                         n = Main.map.mapView.getNearestNode(mousePos);
    174                 }
    175 
    176                 if (n != null) {
    177                         // user clicked on node
    178                         if (shift || selection.isEmpty()) {
    179                                 // select the clicked node and do nothing else
    180                                 // (this is just a convenience option so that people don't
    181                                 // have to switch modes)
    182                                 Main.ds.setSelected(n);
    183                                 return;
    184                         }
    185 
    186                 } else {
    187                         // no node found in clicked area
    188                         n = new Node(Main.map.mapView.getLatLon(e.getX(), e.getY()));
    189                         if (n.coor.isOutSideWorld()) {
    190                                 JOptionPane.showMessageDialog(Main.parent,
    191                                         tr("Cannot add a node outside of the world."));
    192                                 return;
    193                         }
    194                         newNode = true;
    195 
    196                         cmds.add(new AddCommand(n));
    197 
    198                         if (!ctrl) {
    199                                 // Insert the node into all the nearby way segments
    200                                 List<WaySegment> wss = Main.map.mapView.getNearestWaySegments(e.getPoint());
    201                                 Map<Way, List<Integer>> insertPoints = new HashMap<Way, List<Integer>>();
    202                                 for (WaySegment ws : wss) {
    203                                         List<Integer> is;
    204                                         if (insertPoints.containsKey(ws.way)) {
    205                                                 is = insertPoints.get(ws.way);
    206                                         } else {
    207                                                 is = new ArrayList<Integer>();
    208                                                 insertPoints.put(ws.way, is);
    209                                         }
    210 
    211                                         is.add(ws.lowerIndex);
    212                                 }
    213 
    214                                 Set<Pair<Node,Node>> segSet = new HashSet<Pair<Node,Node>>();
    215 
    216                                 for (Map.Entry<Way, List<Integer>> insertPoint : insertPoints.entrySet()) {
    217                                         Way w = insertPoint.getKey();
    218                                         List<Integer> is = insertPoint.getValue();
    219 
    220                                         Way wnew = new Way(w);
    221 
    222                                         pruneSuccsAndReverse(is);
    223                                         for (int i : is) segSet.add(
    224                                                 Pair.sort(new Pair<Node,Node>(w.nodes.get(i), w.nodes.get(i+1))));
    225                                         for (int i : is) wnew.nodes.add(i + 1, n);
    226 
    227                                         cmds.add(new ChangeCommand(insertPoint.getKey(), wnew));
    228                                         replacedWays.add(insertPoint.getKey());
    229                                         reuseWays.add(wnew);
    230                                 }
    231 
    232                                 adjustNode(segSet, n);
    233                         }
    234                 }
    235 
    236                 // This part decides whether or not a "segment" (i.e. a connection) is made to an
    237                 // existing node.
    238 
    239                 // For a connection to be made, the user must either have a node selected (connection
    240                 // is made to that node), or he must have a way selected *and* one of the endpoints
    241                 // of that way must be the last used node (connection is made to last used node), or
    242                 // he must have a way and a node selected (connection is made to the selected node).
    243 
    244                 boolean extendedWay = false;
    245 
    246                 if (!shift && selection.size() > 0 && selection.size() < 3) {
    247 
    248                         Node selectedNode = null;
    249                         Way selectedWay = null;
    250 
    251                         for (OsmPrimitive p : selection) {
    252                                 if (p instanceof Node) {
    253                                         if (selectedNode != null) return;
    254                                         selectedNode = (Node) p;
    255                                 } else if (p instanceof Way) {
    256                                         if (selectedWay != null) return;
    257                                         selectedWay = (Way) p;
    258                                 }
    259                         }
    260 
    261                         // the node from which we make a connection
    262                         Node n0 = null;
    263 
    264                         if (selectedNode == null) {
    265                                 if (selectedWay == null) return;
    266                                 if (lastUsedNode == selectedWay.nodes.get(0) || lastUsedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1)) {
    267                                         n0 = lastUsedNode;
    268                                 }
    269                         } else if (selectedWay == null) {
    270                                 n0 = selectedNode;
    271                         } else {
    272                                 if (selectedNode == selectedWay.nodes.get(0) || selectedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1)) {
    273                                         n0 = selectedNode;
    274                                 }
    275                         }
    276 
    277                         if (n0 == null || n0 == n) {
    278                                 return; // Don't create zero length way segments.
    279                         }
    280 
    281                         // Ok we know now that we'll insert a line segment, but will it connect to an
    282                         // existing way or make a new way of its own? The "alt" modifier means that the
    283                         // user wants a new way.
    284 
    285                         Way way = alt ? null : (selectedWay != null) ? selectedWay : getWayForNode(n0);
    286                         if (way == null) {
    287                                 way = new Way();
    288                                 way.nodes.add(n0);
    289                                 cmds.add(new AddCommand(way));
    290                         } else {
    291                                 int i;
    292                                 if ((i = replacedWays.indexOf(way)) != -1) {
    293                                         way = reuseWays.get(i);
    294                                 } else {
    295                                         Way wnew = new Way(way);
    296                                         cmds.add(new ChangeCommand(way, wnew));
    297                                         way = wnew;
    298                                 }
    299                         }
    300 
    301                         if (way.nodes.get(way.nodes.size() - 1) == n0) {
    302                                 way.nodes.add(n);
    303                         } else {
    304                                 way.nodes.add(0, n);
    305                         }
    306 
    307                         extendedWay = true;
    308                         Main.ds.setSelected(way);
    309                 }
    310 
    311                 String title;
    312                 if (!extendedWay && !newNode) {
    313                         return; // We didn't do anything.
    314                 } else if (!extendedWay) {
    315                         if (reuseWays.isEmpty()) {
    316                                 title = tr("Add node");
    317                         } else {
    318                                 title = tr("Add node into way");
    319                         }
    320                         for (Way w : reuseWays) w.selected = false;
    321                         Main.ds.setSelected(n);
    322                 } else if (!newNode) {
    323                         title = tr("Connect existing way to node");
    324                 } else if (reuseWays.isEmpty()) {
    325                         title = tr("Add a new node to an existing way");
    326                 } else {
    327                         title = tr("Add node into way and connect");
    328                 }
    329 
    330                 Command c = new SequenceCommand(title, cmds);
    331 
    332                 Main.main.undoRedo.add(c);
    333                 lastUsedNode = n;
    334                 computeHelperLine();
    335                 Main.map.mapView.repaint();
    336         }
    337 
    338         @Override public void mouseMoved(MouseEvent e) {
    339                 if(!Main.map.mapView.isDrawableLayer())
    340                         return;
    341 
    342                 // we copy ctrl/alt/shift from the event just in case our global
    343                 // AWTEvent didn't make it through the security manager. Unclear
    344                 // if that can ever happen but better be safe.
    345 
    346                 ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
    347                 alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
    348                 shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
    349                 mousePos = e.getPoint();
    350 
    351                 computeHelperLine();
    352         }
    353 
    354         /**
    355         * This method prepares data required for painting the "helper line" from
    356         * the last used position to the mouse cursor. It duplicates some code from
    357         * mouseClicked() (FIXME).
    358         */
    359         private void computeHelperLine() {
    360                 if (mousePos == null) {
    361                         // Don't draw the line.
    362                         currentMouseEastNorth = null;
    363                         currentBaseNode = null;
    364                         return;
    365                 }
    366 
    367                 double distance = -1;
    368                 double angle = -1;
    369 
    370                 Collection<OsmPrimitive> selection = Main.ds.getSelected();
    371 
    372                 Node selectedNode = null;
    373                 Way selectedWay = null;
    374                 Node currentMouseNode = null;
    375                 mouseOnExistingNode = false;
    376 
    377                 Main.map.statusLine.setAngle(-1);
    378                 Main.map.statusLine.setHeading(-1);
    379                 Main.map.statusLine.setDist(-1);
    380 
    381                 if (!ctrl && mousePos != null) {
    382                         currentMouseNode = Main.map.mapView.getNearestNode(mousePos);
    383                 }
    384 
    385                 if (currentMouseNode != null) {
    386                         // user clicked on node
    387                         if (selection.isEmpty()) return;
    388                         currentMouseEastNorth = currentMouseNode.eastNorth;
    389                         mouseOnExistingNode = true;
    390                 } else {
    391                         // no node found in clicked area
    392                         currentMouseEastNorth = Main.map.mapView.getEastNorth(mousePos.x, mousePos.y);
    393                 }
    394 
    395                 for (OsmPrimitive p : selection) {
    396                         if (p instanceof Node) {
    397                                 if (selectedNode != null) return;
    398                                 selectedNode = (Node) p;
    399                         } else if (p instanceof Way) {
    400                                 if (selectedWay != null) return;
    401                                 selectedWay = (Way) p;
    402                         }
    403                 }
    404 
    405                 // the node from which we make a connection
    406                 currentBaseNode = null;
    407                 Node previousNode = null;
    408 
    409                 if (selectedNode == null) {
    410                         if (selectedWay == null) return;
    411                         if (lastUsedNode == selectedWay.nodes.get(0) || lastUsedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1)) {
    412                                 currentBaseNode = lastUsedNode;
    413                                 if (lastUsedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1) && selectedWay.nodes.size() > 1) {
    414                                         previousNode = selectedWay.nodes.get(selectedWay.nodes.size()-2);
    415                                 }
    416                         }
    417                 } else if (selectedWay == null) {
    418                         currentBaseNode = selectedNode;
    419                 } else {
    420                         if (selectedNode == selectedWay.nodes.get(0) || selectedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1)) {
    421                                 currentBaseNode = selectedNode;
    422                         }
    423                 }
    424 
    425                 if (currentBaseNode == null || currentBaseNode == currentMouseNode) {
    426                         return; // Don't create zero length way segments.
    427                 }
    428 
    429                 // find out the distance, in metres, between the base point and the mouse cursor
    430                 LatLon mouseLatLon = Main.proj.eastNorth2latlon(currentMouseEastNorth);
    431                 distance = currentBaseNode.coor.greatCircleDistance(mouseLatLon);
    432                 double hdg = Math.toDegrees(currentBaseNode.coor.heading(mouseLatLon));
    433                 if (previousNode != null) {
    434                         angle = hdg - Math.toDegrees(previousNode.coor.heading(currentBaseNode.coor));
    435                         if (angle < 0) angle += 360;
    436                 }
    437                 Main.map.statusLine.setAngle(angle);
    438                 Main.map.statusLine.setHeading(hdg);
    439                 Main.map.statusLine.setDist(distance);
    440                 updateStatusLine();
    441 
    442                 if (!drawHelperLine) return;
    443 
    444                 Main.map.mapView.repaint();
    445         }
    446 
    447         /**
    448         * Repaint on mouse exit so that the helper line goes away.
    449         */
    450         @Override public void mouseExited(MouseEvent e) {
    451                 if(!Main.map.mapView.isDrawableLayer())
    452                         return;
    453                 mousePos = e.getPoint();
    454                 Main.map.mapView.repaint();
    455         }
    456 
    457         /**
    458         * @return If the node is the end of exactly one way, return this.
    459          *      <code>null</code> otherwise.
    460         */
    461         public static Way getWayForNode(Node n) {
    462                 Way way = null;
    463                 for (Way w : Main.ds.ways) {
    464                         if (w.deleted || w.incomplete || w.nodes.size() < 1) continue;
    465                         Node firstNode = w.nodes.get(0);
    466                         Node lastNode = w.nodes.get(w.nodes.size() - 1);
    467                         if ((firstNode == n || lastNode == n) && (firstNode != lastNode)) {
    468                                 if (way != null)
    469                                         return null;
    470                                 way = w;
    471                         }
    472                 }
    473                 return way;
    474         }
    475 
    476         private static void pruneSuccsAndReverse(List<Integer> is) {
    477                 //if (is.size() < 2) return;
    478 
    479                 HashSet<Integer> is2 = new HashSet<Integer>();
    480                 for (int i : is) {
    481                         if (!is2.contains(i - 1) && !is2.contains(i + 1)) {
    482                                 is2.add(i);
    483                         }
    484                 }
    485                 is.clear();
    486                 is.addAll(is2);
    487                 Collections.sort(is);
    488                 Collections.reverse(is);
    489         }
    490 
    491         /**
    492         * Adjusts the position of a node to lie on a segment (or a segment
    493         * intersection).
    494         *
    495         * If one or more than two segments are passed, the node is adjusted
    496         * to lie on the first segment that is passed.
    497         *
    498         * If two segments are passed, the node is adjusted to be at their
    499         * intersection.
    500         *
    501         * No action is taken if no segments are passed.
    502         *
    503         * @param segs the segments to use as a reference when adjusting
    504         * @param n the node to adjust
    505         */
    506         private static void adjustNode(Collection<Pair<Node,Node>> segs, Node n) {
    507 
    508                 switch (segs.size()) {
    509                 case 0:
    510                         return;
    511                 case 2:
    512                         // This computes the intersection between
    513                         // the two segments and adjusts the node position. 
    514                         Iterator<Pair<Node,Node>> i = segs.iterator();
    515                         Pair<Node,Node> seg = i.next();
    516                         EastNorth A = seg.a.eastNorth;
    517                         EastNorth B = seg.b.eastNorth;
    518                         seg = i.next();
    519                         EastNorth C = seg.a.eastNorth;
    520                         EastNorth D = seg.b.eastNorth;
    521 
    522                         double u=det(B.east() - A.east(), B.north() - A.north(), C.east() - D.east(), C.north() - D.north());
    523                        
    524                         // Check for parallel segments and do nothing if they are
    525                         // In practice this will probably only happen when a way has been duplicated
    526                        
    527                         if (u == 0) return;
    528                        
    529                         // q is a number between 0 and 1
    530                         // It is the point in the segment where the intersection occurs
    531                         // if the segment is scaled to lenght 1
    532                        
    533                         double q = det(B.north() - C.north(), B.east() - C.east(), D.north() - C.north(), D.east() - C.east()) / u;
    534                         EastNorth intersection = new EastNorth(
    535                                         B.east() + q * (A.east() - B.east()),
    536                                         B.north() + q * (A.north() - B.north()));
    537 
    538                         int snapToIntersectionThreshold=0;
    539                         try { snapToIntersectionThreshold = Integer.parseInt(Main.pref.get("edit.snap-intersection-threshold","10")); } catch (NumberFormatException x) {}
    540 
    541                         // only adjust to intersection if within snapToIntersectionThreshold pixel of mouse click; otherwise
    542                         // fall through to default action.
    543                         // (for semi-parallel lines, intersection might be miles away!)
    544                         if (Main.map.mapView.getPoint(n.eastNorth).distance(Main.map.mapView.getPoint(intersection)) < snapToIntersectionThreshold) {
    545                                 n.eastNorth = intersection;
    546                                 return;
    547                         }
    548 
    549                 default:
    550                         EastNorth P = n.eastNorth;
    551                         seg = segs.iterator().next();
    552                         A = seg.a.eastNorth;
    553                         B = seg.b.eastNorth;
    554                         double a = P.distanceSq(B);
    555                         double b = P.distanceSq(A);
    556                         double c = A.distanceSq(B);
     94        return Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
     95    }
     96
     97    @Override public void enterMode() {
     98        super.enterMode();
     99        Main.map.mapView.addMouseListener(this);
     100        Main.map.mapView.addMouseMotionListener(this);
     101        Main.map.mapView.addTemporaryLayer(this);
     102        DataSet.selListeners.add(this);
     103        try {
     104            Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.KEY_EVENT_MASK);
     105        } catch (SecurityException ex) {
     106        }
     107        // would like to but haven't got mouse position yet:
     108        // computeHelperLine(false, false, false);
     109    }
     110    @Override public void exitMode() {
     111        super.exitMode();
     112        Main.map.mapView.removeMouseListener(this);
     113        Main.map.mapView.removeMouseMotionListener(this);
     114        Main.map.mapView.removeTemporaryLayer(this);
     115        DataSet.selListeners.remove(this);
     116        try {
     117            Toolkit.getDefaultToolkit().removeAWTEventListener(this);
     118        } catch (SecurityException ex) {
     119        }
     120    }
     121
     122    /**
     123    * redraw to (possibly) get rid of helper line if selection changes.
     124    */
     125    public void eventDispatched(AWTEvent event) {
     126        if(!Main.map.mapView.isDrawableLayer())
     127            return;
     128        InputEvent e = (InputEvent) event;
     129        ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
     130        alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
     131        shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
     132        computeHelperLine();
     133    }
     134    /**
     135    * redraw to (possibly) get rid of helper line if selection changes.
     136    */
     137    public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
     138        if(!Main.map.mapView.isDrawableLayer())
     139            return;
     140        computeHelperLine();
     141    }
     142
     143    /**
     144    * If user clicked with the left button, add a node at the current mouse
     145    * position.
     146    *
     147    * If in nodeway mode, insert the node into the way.
     148    */
     149    @Override public void mouseClicked(MouseEvent e) {
     150
     151        if (e.getButton() != MouseEvent.BUTTON1)
     152            return;
     153        if(!Main.map.mapView.isDrawableLayer())
     154            return;
     155
     156        // we copy ctrl/alt/shift from the event just in case our global
     157        // AWTEvent didn't make it through the security manager. Unclear
     158        // if that can ever happen but better be safe.
     159        ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
     160        alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
     161        shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
     162        mousePos = e.getPoint();
     163
     164        Collection<OsmPrimitive> selection = Main.ds.getSelected();
     165        Collection<Command> cmds = new LinkedList<Command>();
     166
     167        ArrayList<Way> reuseWays = new ArrayList<Way>(),
     168            replacedWays = new ArrayList<Way>();
     169        boolean newNode = false;
     170        Node n = null;
     171
     172        if (!ctrl) {
     173            n = Main.map.mapView.getNearestNode(mousePos);
     174        }
     175
     176        if (n != null) {
     177            // user clicked on node
     178            if (shift || selection.isEmpty()) {
     179                // select the clicked node and do nothing else
     180                // (this is just a convenience option so that people don't
     181                // have to switch modes)
     182                Main.ds.setSelected(n);
     183                return;
     184            }
     185
     186        } else {
     187            // no node found in clicked area
     188            n = new Node(Main.map.mapView.getLatLon(e.getX(), e.getY()));
     189            if (n.coor.isOutSideWorld()) {
     190                JOptionPane.showMessageDialog(Main.parent,
     191                    tr("Cannot add a node outside of the world."));
     192                return;
     193            }
     194            newNode = true;
     195
     196            cmds.add(new AddCommand(n));
     197
     198            if (!ctrl) {
     199                // Insert the node into all the nearby way segments
     200                List<WaySegment> wss = Main.map.mapView.getNearestWaySegments(e.getPoint());
     201                Map<Way, List<Integer>> insertPoints = new HashMap<Way, List<Integer>>();
     202                for (WaySegment ws : wss) {
     203                    List<Integer> is;
     204                    if (insertPoints.containsKey(ws.way)) {
     205                        is = insertPoints.get(ws.way);
     206                    } else {
     207                        is = new ArrayList<Integer>();
     208                        insertPoints.put(ws.way, is);
     209                    }
     210
     211                    is.add(ws.lowerIndex);
     212                }
     213
     214                Set<Pair<Node,Node>> segSet = new HashSet<Pair<Node,Node>>();
     215
     216                for (Map.Entry<Way, List<Integer>> insertPoint : insertPoints.entrySet()) {
     217                    Way w = insertPoint.getKey();
     218                    List<Integer> is = insertPoint.getValue();
     219
     220                    Way wnew = new Way(w);
     221
     222                    pruneSuccsAndReverse(is);
     223                    for (int i : is) segSet.add(
     224                        Pair.sort(new Pair<Node,Node>(w.nodes.get(i), w.nodes.get(i+1))));
     225                    for (int i : is) wnew.nodes.add(i + 1, n);
     226
     227                    cmds.add(new ChangeCommand(insertPoint.getKey(), wnew));
     228                    replacedWays.add(insertPoint.getKey());
     229                    reuseWays.add(wnew);
     230                }
     231
     232                adjustNode(segSet, n);
     233            }
     234        }
     235
     236        // This part decides whether or not a "segment" (i.e. a connection) is made to an
     237        // existing node.
     238
     239        // For a connection to be made, the user must either have a node selected (connection
     240        // is made to that node), or he must have a way selected *and* one of the endpoints
     241        // of that way must be the last used node (connection is made to last used node), or
     242        // he must have a way and a node selected (connection is made to the selected node).
     243
     244        boolean extendedWay = false;
     245
     246        if (!shift && selection.size() > 0 && selection.size() < 3) {
     247
     248            Node selectedNode = null;
     249            Way selectedWay = null;
     250
     251            for (OsmPrimitive p : selection) {
     252                if (p instanceof Node) {
     253                    if (selectedNode != null) return;
     254                    selectedNode = (Node) p;
     255                } else if (p instanceof Way) {
     256                    if (selectedWay != null) return;
     257                    selectedWay = (Way) p;
     258                }
     259            }
     260
     261            // the node from which we make a connection
     262            Node n0 = null;
     263
     264            if (selectedNode == null) {
     265                if (selectedWay == null) return;
     266                if (lastUsedNode == selectedWay.nodes.get(0) || lastUsedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1)) {
     267                    n0 = lastUsedNode;
     268                }
     269            } else if (selectedWay == null) {
     270                n0 = selectedNode;
     271            } else {
     272                if (selectedNode == selectedWay.nodes.get(0) || selectedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1)) {
     273                    n0 = selectedNode;
     274                }
     275            }
     276
     277            if (n0 == null || n0 == n) {
     278                return; // Don't create zero length way segments.
     279            }
     280
     281            // Ok we know now that we'll insert a line segment, but will it connect to an
     282            // existing way or make a new way of its own? The "alt" modifier means that the
     283            // user wants a new way.
     284
     285            Way way = alt ? null : (selectedWay != null) ? selectedWay : getWayForNode(n0);
     286            if (way == null) {
     287                way = new Way();
     288                way.nodes.add(n0);
     289                cmds.add(new AddCommand(way));
     290            } else {
     291                int i;
     292                if ((i = replacedWays.indexOf(way)) != -1) {
     293                    way = reuseWays.get(i);
     294                } else {
     295                    Way wnew = new Way(way);
     296                    cmds.add(new ChangeCommand(way, wnew));
     297                    way = wnew;
     298                }
     299            }
     300
     301            if (way.nodes.get(way.nodes.size() - 1) == n0) {
     302                way.nodes.add(n);
     303            } else {
     304                way.nodes.add(0, n);
     305            }
     306
     307            extendedWay = true;
     308            Main.ds.setSelected(way);
     309        }
     310
     311        String title;
     312        if (!extendedWay && !newNode) {
     313            return; // We didn't do anything.
     314        } else if (!extendedWay) {
     315            if (reuseWays.isEmpty()) {
     316                title = tr("Add node");
     317            } else {
     318                title = tr("Add node into way");
     319            }
     320            for (Way w : reuseWays) w.selected = false;
     321            Main.ds.setSelected(n);
     322        } else if (!newNode) {
     323            title = tr("Connect existing way to node");
     324        } else if (reuseWays.isEmpty()) {
     325            title = tr("Add a new node to an existing way");
     326        } else {
     327            title = tr("Add node into way and connect");
     328        }
     329
     330        Command c = new SequenceCommand(title, cmds);
     331
     332        Main.main.undoRedo.add(c);
     333        lastUsedNode = n;
     334        computeHelperLine();
     335        Main.map.mapView.repaint();
     336    }
     337
     338    @Override public void mouseMoved(MouseEvent e) {
     339        if(!Main.map.mapView.isDrawableLayer())
     340            return;
     341
     342        // we copy ctrl/alt/shift from the event just in case our global
     343        // AWTEvent didn't make it through the security manager. Unclear
     344        // if that can ever happen but better be safe.
     345
     346        ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
     347        alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
     348        shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
     349        mousePos = e.getPoint();
     350
     351        computeHelperLine();
     352    }
     353
     354    /**
     355    * This method prepares data required for painting the "helper line" from
     356    * the last used position to the mouse cursor. It duplicates some code from
     357    * mouseClicked() (FIXME).
     358    */
     359    private void computeHelperLine() {
     360        if (mousePos == null) {
     361            // Don't draw the line.
     362            currentMouseEastNorth = null;
     363            currentBaseNode = null;
     364            return;
     365        }
     366
     367        double distance = -1;
     368        double angle = -1;
     369
     370        Collection<OsmPrimitive> selection = Main.ds.getSelected();
     371
     372        Node selectedNode = null;
     373        Way selectedWay = null;
     374        Node currentMouseNode = null;
     375        mouseOnExistingNode = false;
     376
     377        Main.map.statusLine.setAngle(-1);
     378        Main.map.statusLine.setHeading(-1);
     379        Main.map.statusLine.setDist(-1);
     380
     381        if (!ctrl && mousePos != null) {
     382            currentMouseNode = Main.map.mapView.getNearestNode(mousePos);
     383        }
     384
     385        if (currentMouseNode != null) {
     386            // user clicked on node
     387            if (selection.isEmpty()) return;
     388            currentMouseEastNorth = currentMouseNode.eastNorth;
     389            mouseOnExistingNode = true;
     390        } else {
     391            // no node found in clicked area
     392            currentMouseEastNorth = Main.map.mapView.getEastNorth(mousePos.x, mousePos.y);
     393        }
     394
     395        for (OsmPrimitive p : selection) {
     396            if (p instanceof Node) {
     397                if (selectedNode != null) return;
     398                selectedNode = (Node) p;
     399            } else if (p instanceof Way) {
     400                if (selectedWay != null) return;
     401                selectedWay = (Way) p;
     402            }
     403        }
     404
     405        // the node from which we make a connection
     406        currentBaseNode = null;
     407        Node previousNode = null;
     408
     409        if (selectedNode == null) {
     410            if (selectedWay == null) return;
     411            if (lastUsedNode == selectedWay.nodes.get(0) || lastUsedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1)) {
     412                currentBaseNode = lastUsedNode;
     413                if (lastUsedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1) && selectedWay.nodes.size() > 1) {
     414                    previousNode = selectedWay.nodes.get(selectedWay.nodes.size()-2);
     415                }
     416            }
     417        } else if (selectedWay == null) {
     418            currentBaseNode = selectedNode;
     419        } else {
     420            if (selectedNode == selectedWay.nodes.get(0) || selectedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1)) {
     421                currentBaseNode = selectedNode;
     422            }
     423        }
     424
     425        if (currentBaseNode == null || currentBaseNode == currentMouseNode) {
     426            return; // Don't create zero length way segments.
     427        }
     428
     429        // find out the distance, in metres, between the base point and the mouse cursor
     430        LatLon mouseLatLon = Main.proj.eastNorth2latlon(currentMouseEastNorth);
     431        distance = currentBaseNode.coor.greatCircleDistance(mouseLatLon);
     432        double hdg = Math.toDegrees(currentBaseNode.coor.heading(mouseLatLon));
     433        if (previousNode != null) {
     434            angle = hdg - Math.toDegrees(previousNode.coor.heading(currentBaseNode.coor));
     435            if (angle < 0) angle += 360;
     436        }
     437        Main.map.statusLine.setAngle(angle);
     438        Main.map.statusLine.setHeading(hdg);
     439        Main.map.statusLine.setDist(distance);
     440        updateStatusLine();
     441
     442        if (!drawHelperLine) return;
     443
     444        Main.map.mapView.repaint();
     445    }
     446
     447    /**
     448    * Repaint on mouse exit so that the helper line goes away.
     449    */
     450    @Override public void mouseExited(MouseEvent e) {
     451        if(!Main.map.mapView.isDrawableLayer())
     452            return;
     453        mousePos = e.getPoint();
     454        Main.map.mapView.repaint();
     455    }
     456
     457    /**
     458    * @return If the node is the end of exactly one way, return this.
     459     *  <code>null</code> otherwise.
     460    */
     461    public static Way getWayForNode(Node n) {
     462        Way way = null;
     463        for (Way w : Main.ds.ways) {
     464            if (w.deleted || w.incomplete || w.nodes.size() < 1) continue;
     465            Node firstNode = w.nodes.get(0);
     466            Node lastNode = w.nodes.get(w.nodes.size() - 1);
     467            if ((firstNode == n || lastNode == n) && (firstNode != lastNode)) {
     468                if (way != null)
     469                    return null;
     470                way = w;
     471            }
     472        }
     473        return way;
     474    }
     475
     476    private static void pruneSuccsAndReverse(List<Integer> is) {
     477        //if (is.size() < 2) return;
     478
     479        HashSet<Integer> is2 = new HashSet<Integer>();
     480        for (int i : is) {
     481            if (!is2.contains(i - 1) && !is2.contains(i + 1)) {
     482                is2.add(i);
     483            }
     484        }
     485        is.clear();
     486        is.addAll(is2);
     487        Collections.sort(is);
     488        Collections.reverse(is);
     489    }
     490
     491    /**
     492    * Adjusts the position of a node to lie on a segment (or a segment
     493    * intersection).
     494    *
     495    * If one or more than two segments are passed, the node is adjusted
     496    * to lie on the first segment that is passed.
     497    *
     498    * If two segments are passed, the node is adjusted to be at their
     499    * intersection.
     500    *
     501    * No action is taken if no segments are passed.
     502    *
     503    * @param segs the segments to use as a reference when adjusting
     504    * @param n the node to adjust
     505    */
     506    private static void adjustNode(Collection<Pair<Node,Node>> segs, Node n) {
     507
     508        switch (segs.size()) {
     509        case 0:
     510            return;
     511        case 2:
     512            // This computes the intersection between
     513            // the two segments and adjusts the node position.
     514            Iterator<Pair<Node,Node>> i = segs.iterator();
     515            Pair<Node,Node> seg = i.next();
     516            EastNorth A = seg.a.eastNorth;
     517            EastNorth B = seg.b.eastNorth;
     518            seg = i.next();
     519            EastNorth C = seg.a.eastNorth;
     520            EastNorth D = seg.b.eastNorth;
     521
     522            double u=det(B.east() - A.east(), B.north() - A.north(), C.east() - D.east(), C.north() - D.north());
     523
     524            // Check for parallel segments and do nothing if they are
     525            // In practice this will probably only happen when a way has been duplicated
     526
     527            if (u == 0) return;
     528
     529            // q is a number between 0 and 1
     530            // It is the point in the segment where the intersection occurs
     531            // if the segment is scaled to lenght 1
     532
     533            double q = det(B.north() - C.north(), B.east() - C.east(), D.north() - C.north(), D.east() - C.east()) / u;
     534            EastNorth intersection = new EastNorth(
     535                    B.east() + q * (A.east() - B.east()),
     536                    B.north() + q * (A.north() - B.north()));
     537
     538            int snapToIntersectionThreshold=0;
     539            try { snapToIntersectionThreshold = Integer.parseInt(Main.pref.get("edit.snap-intersection-threshold","10")); } catch (NumberFormatException x) {}
     540
     541            // only adjust to intersection if within snapToIntersectionThreshold pixel of mouse click; otherwise
     542            // fall through to default action.
     543            // (for semi-parallel lines, intersection might be miles away!)
     544            if (Main.map.mapView.getPoint(n.eastNorth).distance(Main.map.mapView.getPoint(intersection)) < snapToIntersectionThreshold) {
     545                n.eastNorth = intersection;
     546                return;
     547            }
     548
     549        default:
     550            EastNorth P = n.eastNorth;
     551            seg = segs.iterator().next();
     552            A = seg.a.eastNorth;
     553            B = seg.b.eastNorth;
     554            double a = P.distanceSq(B);
     555            double b = P.distanceSq(A);
     556            double c = A.distanceSq(B);
    557557            q = (a - b + c) / (2*c);
    558                         n.eastNorth = new EastNorth(
    559                                 B.east() + q * (A.east() - B.east()),
    560                                 B.north() + q * (A.north() - B.north()));
    561                 }
    562         }
    563 
    564         // helper for adjustNode
    565         static double det(double a, double b, double c, double d)
    566         {
    567                 return a * d - b * c;
    568         }
    569 
    570         public void paint(Graphics g, MapView mv) {
    571 
    572                 // don't draw line if disabled in prefs
    573                 if (!drawHelperLine) return;
    574 
    575                 // sanity checks
    576                 if (Main.map.mapView == null) return;
    577                 if (mousePos == null) return;
    578 
    579                 // if shift key is held ("no auto-connect"), don't draw a line
    580                 if (shift) return;
    581 
    582                 // don't draw line if we don't know where from or where to
    583                 if (currentBaseNode == null) return;
    584                 if (currentMouseEastNorth == null) return;
    585 
    586                 // don't draw line if mouse is outside window
    587                 if (!Main.map.mapView.getBounds().contains(mousePos)) return;
    588 
    589                 Graphics2D g2 = (Graphics2D) g;
    590                 g2.setColor(selectedColor);
    591                 g2.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
    592                 GeneralPath b = new GeneralPath();
    593                 Point p1=mv.getPoint(currentBaseNode.eastNorth);
    594                 Point p2=mv.getPoint(currentMouseEastNorth);
    595 
    596                 double t = Math.atan2(p2.y-p1.y, p2.x-p1.x) + Math.PI;
    597 
    598                 b.moveTo(p1.x,p1.y); b.lineTo(p2.x, p2.y);
    599 
    600                 // if alt key is held ("start new way"), draw a little perpendicular line
    601                 if (alt) {
    602                         b.moveTo((int)(p1.x + 8*Math.cos(t+PHI)), (int)(p1.y + 8*Math.sin(t+PHI)));
    603                         b.lineTo((int)(p1.x + 8*Math.cos(t-PHI)), (int)(p1.y + 8*Math.sin(t-PHI)));
    604                 }
    605 
    606                 g2.draw(b);
    607                 g2.setStroke(new BasicStroke(1));
    608 
    609         }
    610 
    611         @Override public String getModeHelpText() {
    612                 String rv;
    613 
    614                 if (currentBaseNode != null && !shift) {
    615                         if (mouseOnExistingNode) {
    616                                 if (alt && /* FIXME: way exists */true)
    617                                     rv = tr("Click to create a new way to the existing node.");
    618                                 else
    619                                         rv =tr("Click to make a connection to the existing node.");
    620                         } else {
    621                                 if (alt && /* FIXME: way exists */true)
    622                                     rv = tr("Click to insert a node and create a new way.");
    623                                 else
    624                                         rv = tr("Click to insert a new node and make a connection.");
    625                         }
    626                 }
    627                 else {
    628                         rv = tr("Click to insert a new node.");
    629                 }
    630 
    631                 //rv.append(tr("Click to add a new node. Ctrl: no node re-use/auto-insert. Shift: no auto-connect. Alt: new way"));
    632                 //rv.append(tr("Click to add a new node. Ctrl: no node re-use/auto-insert. Shift: no auto-connect. Alt: new way"));
    633                 return rv.toString();
    634         }
     558            n.eastNorth = new EastNorth(
     559                B.east() + q * (A.east() - B.east()),
     560                B.north() + q * (A.north() - B.north()));
     561        }
     562    }
     563
     564    // helper for adjustNode
     565    static double det(double a, double b, double c, double d)
     566    {
     567        return a * d - b * c;
     568    }
     569
     570    public void paint(Graphics g, MapView mv) {
     571
     572        // don't draw line if disabled in prefs
     573        if (!drawHelperLine) return;
     574
     575        // sanity checks
     576        if (Main.map.mapView == null) return;
     577        if (mousePos == null) return;
     578
     579        // if shift key is held ("no auto-connect"), don't draw a line
     580        if (shift) return;
     581
     582        // don't draw line if we don't know where from or where to
     583        if (currentBaseNode == null) return;
     584        if (currentMouseEastNorth == null) return;
     585
     586        // don't draw line if mouse is outside window
     587        if (!Main.map.mapView.getBounds().contains(mousePos)) return;
     588
     589        Graphics2D g2 = (Graphics2D) g;
     590        g2.setColor(selectedColor);
     591        g2.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
     592        GeneralPath b = new GeneralPath();
     593        Point p1=mv.getPoint(currentBaseNode.eastNorth);
     594        Point p2=mv.getPoint(currentMouseEastNorth);
     595
     596        double t = Math.atan2(p2.y-p1.y, p2.x-p1.x) + Math.PI;
     597
     598        b.moveTo(p1.x,p1.y); b.lineTo(p2.x, p2.y);
     599
     600        // if alt key is held ("start new way"), draw a little perpendicular line
     601        if (alt) {
     602            b.moveTo((int)(p1.x + 8*Math.cos(t+PHI)), (int)(p1.y + 8*Math.sin(t+PHI)));
     603            b.lineTo((int)(p1.x + 8*Math.cos(t-PHI)), (int)(p1.y + 8*Math.sin(t-PHI)));
     604        }
     605
     606        g2.draw(b);
     607        g2.setStroke(new BasicStroke(1));
     608
     609    }
     610
     611    @Override public String getModeHelpText() {
     612        String rv;
     613
     614        if (currentBaseNode != null && !shift) {
     615            if (mouseOnExistingNode) {
     616                if (alt && /* FIXME: way exists */true)
     617                    rv = tr("Click to create a new way to the existing node.");
     618                else
     619                    rv =tr("Click to make a connection to the existing node.");
     620            } else {
     621                if (alt && /* FIXME: way exists */true)
     622                    rv = tr("Click to insert a node and create a new way.");
     623                else
     624                    rv = tr("Click to insert a new node and make a connection.");
     625            }
     626        }
     627        else {
     628            rv = tr("Click to insert a new node.");
     629        }
     630
     631        //rv.append(tr("Click to add a new node. Ctrl: no node re-use/auto-insert. Shift: no auto-connect. Alt: new way"));
     632        //rv.append(tr("Click to add a new node. Ctrl: no node re-use/auto-insert. Shift: no auto-connect. Alt: new way"));
     633        return rv.toString();
     634    }
    635635}
  • trunk/src/org/openstreetmap/josm/actions/mapmode/ExtrudeAction.java

    r1158 r1169  
    4040public class ExtrudeAction extends MapMode implements MapViewPaintable {
    4141
    42         enum Mode { EXTRUDE, rotate, select }
    43         private Mode mode = null;
    44         private long mouseDownTime = 0;
    45         private WaySegment selectedSegment = null;
    46         private Color selectedColor;
    47 
    48         double xoff;
    49         double yoff;
    50         double distance;
    51 
    52         /**
    53         * The old cursor before the user pressed the mouse button.
    54         */
    55         private Cursor oldCursor;
    56         /**
    57         * The current position of the mouse
    58         */
    59         private Point mousePos;
    60         /**
    61         * The position of the mouse cursor when the drag action was initiated.
    62         */
    63         private Point initialMousePos;
    64         /**
    65         * The time which needs to pass between click and release before something
    66         * counts as a move, in milliseconds
    67         */
    68         private int initialMoveDelay = 200;
    69 
    70         /**
    71         * Create a new SelectAction
    72         * @param mapFrame The MapFrame this action belongs to.
    73         */
    74         public ExtrudeAction(MapFrame mapFrame) {
    75                 super(tr("Extrude"), "extrude/extrude", tr("Create areas"),
    76                                 Shortcut.registerShortcut("mapmode:extrude", tr("Mode: {0}", tr("Extrude")), KeyEvent.VK_X, Shortcut.GROUP_EDIT),
    77                         mapFrame,
    78                         getCursor("normal", "rectangle", Cursor.DEFAULT_CURSOR));
    79                 putValue("help", "Action/Extrude/Extrude");
    80                 initialMoveDelay = Main.pref.getInteger("edit.initial-move-delay",200);
    81                 selectedColor = Main.pref.getColor(marktr("selected"), Color.YELLOW);
    82         }
    83 
    84         private static Cursor getCursor(String name, String mod, int def) {
    85                 try {
    86                 return ImageProvider.getCursor(name, mod);
     42    enum Mode { EXTRUDE, rotate, select }
     43    private Mode mode = null;
     44    private long mouseDownTime = 0;
     45    private WaySegment selectedSegment = null;
     46    private Color selectedColor;
     47
     48    double xoff;
     49    double yoff;
     50    double distance;
     51
     52    /**
     53    * The old cursor before the user pressed the mouse button.
     54    */
     55    private Cursor oldCursor;
     56    /**
     57    * The current position of the mouse
     58    */
     59    private Point mousePos;
     60    /**
     61    * The position of the mouse cursor when the drag action was initiated.
     62    */
     63    private Point initialMousePos;
     64    /**
     65    * The time which needs to pass between click and release before something
     66    * counts as a move, in milliseconds
     67    */
     68    private int initialMoveDelay = 200;
     69
     70    /**
     71    * Create a new SelectAction
     72    * @param mapFrame The MapFrame this action belongs to.
     73    */
     74    public ExtrudeAction(MapFrame mapFrame) {
     75        super(tr("Extrude"), "extrude/extrude", tr("Create areas"),
     76                Shortcut.registerShortcut("mapmode:extrude", tr("Mode: {0}", tr("Extrude")), KeyEvent.VK_X, Shortcut.GROUP_EDIT),
     77            mapFrame,
     78            getCursor("normal", "rectangle", Cursor.DEFAULT_CURSOR));
     79        putValue("help", "Action/Extrude/Extrude");
     80        initialMoveDelay = Main.pref.getInteger("edit.initial-move-delay",200);
     81        selectedColor = Main.pref.getColor(marktr("selected"), Color.YELLOW);
     82    }
     83
     84    private static Cursor getCursor(String name, String mod, int def) {
     85        try {
     86            return ImageProvider.getCursor(name, mod);
    8787        } catch (Exception e) {
    8888        }
    89             return Cursor.getPredefinedCursor(def);
    90     }
    91 
    92         private void setCursor(Cursor c) {
    93                 if (oldCursor == null) {
    94                         oldCursor = Main.map.mapView.getCursor();
    95                         Main.map.mapView.setCursor(c);
    96                 }
    97         }
    98 
    99         private void restoreCursor() {
    100                 if (oldCursor != null) {
    101                         Main.map.mapView.setCursor(oldCursor);
    102                         oldCursor = null;
    103                 }
    104         }
    105 
    106         @Override public void enterMode() {
    107                 super.enterMode();
    108                 Main.map.mapView.addMouseListener(this);
    109                 Main.map.mapView.addMouseMotionListener(this);
    110         }
    111 
    112         @Override public void exitMode() {
    113                 super.exitMode();
    114                 Main.map.mapView.removeMouseListener(this);
    115                 Main.map.mapView.removeMouseMotionListener(this);
    116                 Main.map.mapView.removeTemporaryLayer(this);
    117 
    118         }
    119 
    120         /**
    121         * If the left mouse button is pressed, move all currently selected
    122         * objects (if one of them is under the mouse) or the current one under the
    123         * mouse (which will become selected).
    124         */
    125         @Override public void mouseDragged(MouseEvent e) {
    126                 if (mode == Mode.select) return;
    127 
    128                 // do not count anything as a move if it lasts less than 100 milliseconds.
    129                 if ((mode == Mode.EXTRUDE) && (System.currentTimeMillis() - mouseDownTime < initialMoveDelay)) return;
    130 
    131                 if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == 0)
    132                         return;
    133 
    134                 if (mode == Mode.EXTRUDE) {
    135                         setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
    136                 }
    137 
    138                 if (mousePos == null) {
    139                         mousePos = e.getPoint();
    140                         return;
    141                 }
    142 
    143                 Main.map.mapView.repaint();
    144                 mousePos = e.getPoint();
    145 
    146         }
    147 
    148         public void paint(Graphics g, MapView mv) {
    149                 if (selectedSegment != null) {
    150                         Node n1 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex);
    151                         Node n2 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex+1);
    152 
    153                         EastNorth en1 = n1.eastNorth;
    154                         EastNorth en2 = n2.eastNorth;
    155                         if (en1.east() < en2.east()) { en2 = en1; en1 = n2.eastNorth; }
    156                         EastNorth en3 = mv.getEastNorth(mousePos.x, mousePos.y);
    157 
    158                         double u = ((en3.east()-en1.east())*(en2.east()-en1.east()) + (en3.north()-en1.north())*(en2.north()-en1.north()))/en2.distanceSq(en1);
    159                         // the point on the segment from which the distance to mouse pos is shortest
    160                         EastNorth base = new EastNorth(en1.east()+u*(en2.east()-en1.east()), en1.north()+u*(en2.north()-en1.north()));
    161 
    162                         // the distance, in projection units, between the base point and the mouse cursor
    163                         double len = base.distance(en3);
    164 
    165                         // find out the distance, in metres, between the base point and the mouse cursor
    166                         distance = Main.proj.eastNorth2latlon(base).greatCircleDistance(Main.proj.eastNorth2latlon(en3));
    167                         Main.map.statusLine.setDist(distance);
    168                         updateStatusLine();
    169 
    170                         // compute the angle at which the segment is drawn
    171                         // and use it to compute the x and y offsets for the
    172                         // corner points.
    173                         double sin_alpha = (en2.north()-en1.north())/en2.distance(en1);
    174 
    175                         // this is a kludge because sometimes extrusion just goes the wrong direction
    176                         if ((en3.east()>base.east()) ^ (sin_alpha < 0)) len=-len;
    177                         xoff = sin_alpha * len;
    178                         yoff = Math.sqrt(1-sin_alpha*sin_alpha) * len;
    179 
    180                         Graphics2D g2 = (Graphics2D) g;
    181                         g2.setColor(selectedColor);
    182                         g2.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
    183                         GeneralPath b = new GeneralPath();
    184                         Point p1=mv.getPoint(en1);
    185                         Point p2=mv.getPoint(en2);
    186                         Point p3=mv.getPoint(en1.add(-xoff, -yoff));
    187                         Point p4=mv.getPoint(en2.add(-xoff, -yoff));
    188 
    189                         b.moveTo(p1.x,p1.y); b.lineTo(p3.x, p3.y);
    190                         b.lineTo(p4.x, p4.y); b.lineTo(p2.x, p2.y);
    191                         b.lineTo(p1.x,p1.y);
    192                         g2.draw(b);
    193                         g2.setStroke(new BasicStroke(1));
    194                 }
    195         }
    196 
    197         /**
    198         */
    199         @Override public void mousePressed(MouseEvent e) {
    200                 if (!(Boolean)this.getValue("active")) return;
    201                 if (e.getButton() != MouseEvent.BUTTON1)
    202                         return;
    203                 // boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
    204                 // boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
    205                 // boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
    206 
    207                 mouseDownTime = System.currentTimeMillis();
    208 
    209                 selectedSegment =
    210                         Main.map.mapView.getNearestWaySegment(e.getPoint());
    211 
    212                 mode = (selectedSegment == null) ? Mode.select : Mode.EXTRUDE;
    213                 oldCursor = Main.map.mapView.getCursor();
    214 
    215                 updateStatusLine();
    216                 Main.map.mapView.addTemporaryLayer(this);
    217                 Main.map.mapView.repaint();
    218 
    219                 mousePos = e.getPoint();
    220                 initialMousePos = e.getPoint();
    221         }
    222 
    223         /**
    224         * Restore the old mouse cursor.
    225         */
    226         @Override public void mouseReleased(MouseEvent e) {
    227                 restoreCursor();
    228                 if (selectedSegment == null) return;
    229                 if (mousePos.distance(initialMousePos) > 10) {
    230                         Node n1 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex);
    231                         Node n2 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex+1);
    232                         EastNorth en3 = n2.eastNorth.add(-xoff, -yoff);
    233                         Node n3 = new Node(Main.proj.eastNorth2latlon(en3));
    234                         EastNorth en4 = n1.eastNorth.add(-xoff, -yoff);
    235                         Node n4 = new Node(Main.proj.eastNorth2latlon(en4));
    236                         Way wnew = new Way(selectedSegment.way);
    237                         wnew.nodes.add(selectedSegment.lowerIndex+1, n3);
    238                         wnew.nodes.add(selectedSegment.lowerIndex+1, n4);
    239                         if (wnew.nodes.size() == 4) wnew.nodes.add(n1);
    240                         Collection<Command> cmds = new LinkedList<Command>();
    241                         cmds.add(new AddCommand(n4));
    242                         cmds.add(new AddCommand(n3));
    243                         cmds.add(new ChangeCommand(selectedSegment.way, wnew));
    244                         Command c = new SequenceCommand(tr("Extrude Way"), cmds);
    245                         Main.main.undoRedo.add(c);
    246                 }
    247 
    248                 Main.map.mapView.removeTemporaryLayer(this);
    249                 selectedSegment = null;
    250                 mode = null;
    251                 updateStatusLine();
    252                 Main.map.mapView.repaint();
    253         }
    254 
    255         @Override public String getModeHelpText() {
    256                 if (mode == Mode.select) {
    257                         return tr("Release the mouse button to select the objects in the rectangle.");
    258                 } else if (mode == Mode.EXTRUDE) {
    259                         return tr("Draw a rectangle of the desired size, then release the mouse button.");
    260                 } else if (mode == Mode.rotate) {
    261                         return tr("Release the mouse button to stop rotating.");
    262                 } else {
    263                         return tr("Drag a way segment to make a rectangle.");
    264                 }
    265         }
     89        return Cursor.getPredefinedCursor(def);
     90    }
     91
     92    private void setCursor(Cursor c) {
     93        if (oldCursor == null) {
     94            oldCursor = Main.map.mapView.getCursor();
     95            Main.map.mapView.setCursor(c);
     96        }
     97    }
     98
     99    private void restoreCursor() {
     100        if (oldCursor != null) {
     101            Main.map.mapView.setCursor(oldCursor);
     102            oldCursor = null;
     103        }
     104    }
     105
     106    @Override public void enterMode() {
     107        super.enterMode();
     108        Main.map.mapView.addMouseListener(this);
     109        Main.map.mapView.addMouseMotionListener(this);
     110    }
     111
     112    @Override public void exitMode() {
     113        super.exitMode();
     114        Main.map.mapView.removeMouseListener(this);
     115        Main.map.mapView.removeMouseMotionListener(this);
     116        Main.map.mapView.removeTemporaryLayer(this);
     117
     118    }
     119
     120    /**
     121    * If the left mouse button is pressed, move all currently selected
     122    * objects (if one of them is under the mouse) or the current one under the
     123    * mouse (which will become selected).
     124    */
     125    @Override public void mouseDragged(MouseEvent e) {
     126        if (mode == Mode.select) return;
     127
     128        // do not count anything as a move if it lasts less than 100 milliseconds.
     129        if ((mode == Mode.EXTRUDE) && (System.currentTimeMillis() - mouseDownTime < initialMoveDelay)) return;
     130
     131        if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == 0)
     132            return;
     133
     134        if (mode == Mode.EXTRUDE) {
     135            setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
     136        }
     137
     138        if (mousePos == null) {
     139            mousePos = e.getPoint();
     140            return;
     141        }
     142
     143        Main.map.mapView.repaint();
     144        mousePos = e.getPoint();
     145
     146    }
     147
     148    public void paint(Graphics g, MapView mv) {
     149        if (selectedSegment != null) {
     150            Node n1 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex);
     151            Node n2 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex+1);
     152
     153            EastNorth en1 = n1.eastNorth;
     154            EastNorth en2 = n2.eastNorth;
     155            if (en1.east() < en2.east()) { en2 = en1; en1 = n2.eastNorth; }
     156            EastNorth en3 = mv.getEastNorth(mousePos.x, mousePos.y);
     157
     158            double u = ((en3.east()-en1.east())*(en2.east()-en1.east()) + (en3.north()-en1.north())*(en2.north()-en1.north()))/en2.distanceSq(en1);
     159            // the point on the segment from which the distance to mouse pos is shortest
     160            EastNorth base = new EastNorth(en1.east()+u*(en2.east()-en1.east()), en1.north()+u*(en2.north()-en1.north()));
     161
     162            // the distance, in projection units, between the base point and the mouse cursor
     163            double len = base.distance(en3);
     164
     165            // find out the distance, in metres, between the base point and the mouse cursor
     166            distance = Main.proj.eastNorth2latlon(base).greatCircleDistance(Main.proj.eastNorth2latlon(en3));
     167            Main.map.statusLine.setDist(distance);
     168            updateStatusLine();
     169
     170            // compute the angle at which the segment is drawn
     171            // and use it to compute the x and y offsets for the
     172            // corner points.
     173            double sin_alpha = (en2.north()-en1.north())/en2.distance(en1);
     174
     175            // this is a kludge because sometimes extrusion just goes the wrong direction
     176            if ((en3.east()>base.east()) ^ (sin_alpha < 0)) len=-len;
     177            xoff = sin_alpha * len;
     178            yoff = Math.sqrt(1-sin_alpha*sin_alpha) * len;
     179
     180            Graphics2D g2 = (Graphics2D) g;
     181            g2.setColor(selectedColor);
     182            g2.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
     183            GeneralPath b = new GeneralPath();
     184            Point p1=mv.getPoint(en1);
     185            Point p2=mv.getPoint(en2);
     186            Point p3=mv.getPoint(en1.add(-xoff, -yoff));
     187            Point p4=mv.getPoint(en2.add(-xoff, -yoff));
     188
     189            b.moveTo(p1.x,p1.y); b.lineTo(p3.x, p3.y);
     190            b.lineTo(p4.x, p4.y); b.lineTo(p2.x, p2.y);
     191            b.lineTo(p1.x,p1.y);
     192            g2.draw(b);
     193            g2.setStroke(new BasicStroke(1));
     194        }
     195    }
     196
     197    /**
     198    */
     199    @Override public void mousePressed(MouseEvent e) {
     200        if (!(Boolean)this.getValue("active")) return;
     201        if (e.getButton() != MouseEvent.BUTTON1)
     202            return;
     203        // boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
     204        // boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
     205        // boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
     206
     207        mouseDownTime = System.currentTimeMillis();
     208
     209        selectedSegment =
     210            Main.map.mapView.getNearestWaySegment(e.getPoint());
     211
     212        mode = (selectedSegment == null) ? Mode.select : Mode.EXTRUDE;
     213        oldCursor = Main.map.mapView.getCursor();
     214
     215        updateStatusLine();
     216        Main.map.mapView.addTemporaryLayer(this);
     217        Main.map.mapView.repaint();
     218
     219        mousePos = e.getPoint();
     220        initialMousePos = e.getPoint();
     221    }
     222
     223    /**
     224    * Restore the old mouse cursor.
     225    */
     226    @Override public void mouseReleased(MouseEvent e) {
     227        restoreCursor();
     228        if (selectedSegment == null) return;
     229        if (mousePos.distance(initialMousePos) > 10) {
     230            Node n1 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex);
     231            Node n2 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex+1);
     232            EastNorth en3 = n2.eastNorth.add(-xoff, -yoff);
     233            Node n3 = new Node(Main.proj.eastNorth2latlon(en3));
     234            EastNorth en4 = n1.eastNorth.add(-xoff, -yoff);
     235            Node n4 = new Node(Main.proj.eastNorth2latlon(en4));
     236            Way wnew = new Way(selectedSegment.way);
     237            wnew.nodes.add(selectedSegment.lowerIndex+1, n3);
     238            wnew.nodes.add(selectedSegment.lowerIndex+1, n4);
     239            if (wnew.nodes.size() == 4) wnew.nodes.add(n1);
     240            Collection<Command> cmds = new LinkedList<Command>();
     241            cmds.add(new AddCommand(n4));
     242            cmds.add(new AddCommand(n3));
     243            cmds.add(new ChangeCommand(selectedSegment.way, wnew));
     244            Command c = new SequenceCommand(tr("Extrude Way"), cmds);
     245            Main.main.undoRedo.add(c);
     246        }
     247
     248        Main.map.mapView.removeTemporaryLayer(this);
     249        selectedSegment = null;
     250        mode = null;
     251        updateStatusLine();
     252        Main.map.mapView.repaint();
     253    }
     254
     255    @Override public String getModeHelpText() {
     256        if (mode == Mode.select) {
     257            return tr("Release the mouse button to select the objects in the rectangle.");
     258        } else if (mode == Mode.EXTRUDE) {
     259            return tr("Draw a rectangle of the desired size, then release the mouse button.");
     260        } else if (mode == Mode.rotate) {
     261            return tr("Release the mouse button to stop rotating.");
     262        } else {
     263            return tr("Drag a way segment to make a rectangle.");
     264        }
     265    }
    266266}
  • trunk/src/org/openstreetmap/josm/actions/mapmode/MapMode.java

    r1084 r1169  
    2323 */
    2424abstract public class MapMode extends JosmAction implements MouseListener, MouseMotionListener {
    25         private final Cursor cursor;
    26         private Cursor oldCursor;
     25    private final Cursor cursor;
     26    private Cursor oldCursor;
    2727
    28         /**
    29         * Constructor for mapmodes without an menu
    30         */
    31         public MapMode(String name, String iconName, String tooltip, Shortcut shortcut, MapFrame mapFrame, Cursor cursor) {
    32                 super(name, "mapmode/"+iconName, tooltip, shortcut, false);
    33                 this.cursor = cursor;
    34                 putValue("active", false);
    35         }
     28    /**
     29    * Constructor for mapmodes without an menu
     30    */
     31    public MapMode(String name, String iconName, String tooltip, Shortcut shortcut, MapFrame mapFrame, Cursor cursor) {
     32        super(name, "mapmode/"+iconName, tooltip, shortcut, false);
     33        this.cursor = cursor;
     34        putValue("active", false);
     35    }
    3636
    37         /**
    38         * Constructor for mapmodes without an menu
    39         */
    40         @Deprecated
    41         public MapMode(String name, String iconName, String tooltip, int keystroke, MapFrame mapFrame, Cursor cursor) {
    42                 super(name, "mapmode/"+iconName, tooltip, keystroke, 0, false);
    43                 this.cursor = cursor;
    44                 putValue("active", false);
    45         }
     37    /**
     38    * Constructor for mapmodes without an menu
     39    */
     40    @Deprecated
     41    public MapMode(String name, String iconName, String tooltip, int keystroke, MapFrame mapFrame, Cursor cursor) {
     42        super(name, "mapmode/"+iconName, tooltip, keystroke, 0, false);
     43        this.cursor = cursor;
     44        putValue("active", false);
     45    }
    4646
    47         /**
    48         * Constructor for mapmodes with an menu (no shortcut will be registered)
    49         */
    50         public MapMode(String name, String iconName, String tooltip, MapFrame mapFrame, Cursor cursor) {
    51                 putValue(NAME, name);
    52                 putValue(SMALL_ICON, ImageProvider.get("mapmode", iconName));
    53                 putValue(SHORT_DESCRIPTION, tooltip);
    54                 this.cursor = cursor;
    55         }
     47    /**
     48    * Constructor for mapmodes with an menu (no shortcut will be registered)
     49    */
     50    public MapMode(String name, String iconName, String tooltip, MapFrame mapFrame, Cursor cursor) {
     51        putValue(NAME, name);
     52        putValue(SMALL_ICON, ImageProvider.get("mapmode", iconName));
     53        putValue(SHORT_DESCRIPTION, tooltip);
     54        this.cursor = cursor;
     55    }
    5656
    57         public void enterMode() {
    58                 putValue("active", true);
    59                 oldCursor = Main.map.mapView.getCursor();
    60                 Main.map.mapView.setCursor(cursor);
    61                 updateStatusLine();
    62         }
    63         public void exitMode() {
    64                 putValue("active", false);
    65                 Main.map.mapView.setCursor(oldCursor);
    66         }
     57    public void enterMode() {
     58        putValue("active", true);
     59        oldCursor = Main.map.mapView.getCursor();
     60        Main.map.mapView.setCursor(cursor);
     61        updateStatusLine();
     62    }
     63    public void exitMode() {
     64        putValue("active", false);
     65        Main.map.mapView.setCursor(oldCursor);
     66    }
    6767
    68         protected void updateStatusLine() {
    69                 Main.map.statusLine.setHelpText(getModeHelpText());
    70                 Main.map.statusLine.repaint();
    71         }
     68    protected void updateStatusLine() {
     69        Main.map.statusLine.setHelpText(getModeHelpText());
     70        Main.map.statusLine.repaint();
     71    }
    7272
    73         public String getModeHelpText() {
    74                 return "";
    75         }
    76         /**
    77         * Call selectMapMode(this) on the parent mapFrame.
    78         */
    79         public void actionPerformed(ActionEvent e) {
    80                 if (Main.map != null)
    81                         Main.map.selectMapMode(this);
    82         }
     73    public String getModeHelpText() {
     74        return "";
     75    }
     76    /**
     77    * Call selectMapMode(this) on the parent mapFrame.
     78    */
     79    public void actionPerformed(ActionEvent e) {
     80        if (Main.map != null)
     81            Main.map.selectMapMode(this);
     82    }
    8383
    84         public void mouseReleased(MouseEvent e) {}
    85         public void mouseExited(MouseEvent e) {}
    86         public void mousePressed(MouseEvent e) {}
    87         public void mouseClicked(MouseEvent e) {}
    88         public void mouseEntered(MouseEvent e) {}
    89         public void mouseMoved(MouseEvent e) {}
    90         public void mouseDragged(MouseEvent e) {}
     84    public void mouseReleased(MouseEvent e) {}
     85    public void mouseExited(MouseEvent e) {}
     86    public void mousePressed(MouseEvent e) {}
     87    public void mouseClicked(MouseEvent e) {}
     88    public void mouseEntered(MouseEvent e) {}
     89    public void mouseMoved(MouseEvent e) {}
     90    public void mouseDragged(MouseEvent e) {}
    9191}
  • trunk/src/org/openstreetmap/josm/actions/mapmode/PlayHeadDragMode.java

    r1047 r1169  
    2121public class PlayHeadDragMode extends MapMode {
    2222
    23         private boolean dragging = false;
    24         private Point mousePos = null;
    25         private Point mouseStart = null;
    26         private PlayHeadMarker playHeadMarker = null;
     23    private boolean dragging = false;
     24    private Point mousePos = null;
     25    private Point mouseStart = null;
     26    private PlayHeadMarker playHeadMarker = null;
    2727
    28         public PlayHeadDragMode(PlayHeadMarker m) {
    29                 super("play head drag", "playheaddrag", "play head drag", null,
    30                 Main.map, Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
    31                 playHeadMarker = m;
    32         }
     28    public PlayHeadDragMode(PlayHeadMarker m) {
     29        super("play head drag", "playheaddrag", "play head drag", null,
     30        Main.map, Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
     31        playHeadMarker = m;
     32    }
    3333
    34         @Override public void enterMode() {
    35                 super.enterMode();
    36                 Main.map.mapView.addMouseListener(this);
    37                 Main.map.mapView.addMouseMotionListener(this);
    38         }
     34    @Override public void enterMode() {
     35        super.enterMode();
     36        Main.map.mapView.addMouseListener(this);
     37        Main.map.mapView.addMouseMotionListener(this);
     38    }
    3939
    40         @Override public void exitMode() {
    41                 super.exitMode();
    42                 Main.map.mapView.removeMouseListener(this);
    43                 Main.map.mapView.removeMouseMotionListener(this);
    44         }
     40    @Override public void exitMode() {
     41        super.exitMode();
     42        Main.map.mapView.removeMouseListener(this);
     43        Main.map.mapView.removeMouseMotionListener(this);
     44    }
    4545
    46         @Override public void mousePressed(MouseEvent ev) {
    47                 mouseStart = mousePos = ev.getPoint();
    48         }
     46    @Override public void mousePressed(MouseEvent ev) {
     47        mouseStart = mousePos = ev.getPoint();
     48    }
    4949
    50         @Override public void mouseDragged(MouseEvent ev) {
    51                 if (mouseStart == null || mousePos == null) return;
    52                 if ((ev.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == 0) return;
    53                 Point p = ev.getPoint();
    54                 if (p == null) return;
    55                 if (! dragging) {
    56                         if (p.distance(mouseStart) < 3) return;
    57                         playHeadMarker.startDrag();
    58                         dragging = true;
    59                 }
    60                 if (p.distance(mousePos) == 0) return;
    61                 playHeadMarker.drag(Main.map.mapView.getEastNorth(ev.getX(), ev.getY()));
    62                 mousePos = p;
    63         }
     50    @Override public void mouseDragged(MouseEvent ev) {
     51        if (mouseStart == null || mousePos == null) return;
     52        if ((ev.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == 0) return;
     53        Point p = ev.getPoint();
     54        if (p == null) return;
     55        if (! dragging) {
     56            if (p.distance(mouseStart) < 3) return;
     57            playHeadMarker.startDrag();
     58            dragging = true;
     59        }
     60        if (p.distance(mousePos) == 0) return;
     61        playHeadMarker.drag(Main.map.mapView.getEastNorth(ev.getX(), ev.getY()));
     62        mousePos = p;
     63    }
    6464
    65         @Override public void mouseReleased(MouseEvent ev) {
    66                 Point p = ev.getPoint();
    67                 mouseStart = null;
    68                 if (ev.getButton() != MouseEvent.BUTTON1 || p == null || ! dragging)
    69                         return;
    70                 boolean shift = (ev.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
    71                 EastNorth en = Main.map.mapView.getEastNorth(ev.getX(), ev.getY());
    72                 if (! shift) {
    73                         playHeadMarker.reposition(en);
    74                 } else {
    75                         playHeadMarker.synchronize(en);
    76                 }
    77                 mousePos = null;
    78                 dragging = false;
     65    @Override public void mouseReleased(MouseEvent ev) {
     66        Point p = ev.getPoint();
     67        mouseStart = null;
     68        if (ev.getButton() != MouseEvent.BUTTON1 || p == null || ! dragging)
     69            return;
     70        boolean shift = (ev.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
     71        EastNorth en = Main.map.mapView.getEastNorth(ev.getX(), ev.getY());
     72        if (! shift) {
     73            playHeadMarker.reposition(en);
     74        } else {
     75            playHeadMarker.synchronize(en);
     76        }
     77        mousePos = null;
     78        dragging = false;
    7979
    80         /*
    81                 boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
    82                 boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
    83         */
    84         }
     80    /*
     81        boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
     82        boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
     83    */
     84    }
    8585
    86         @Override public String getModeHelpText() {
    87                 return tr("Drag play head and release near track to play audio from there; SHIFT+release to synchronize audio at that point.");
    88         }
     86    @Override public String getModeHelpText() {
     87        return tr("Drag play head and release near track to play audio from there; SHIFT+release to synchronize audio at that point.");
     88    }
    8989}
  • trunk/src/org/openstreetmap/josm/actions/mapmode/ZoomAction.java

    r1084 r1169  
    3030public class ZoomAction extends MapMode implements SelectionEnded {
    3131
    32         /**
    33         * Shortcut to the mapview.
    34         */
    35         private final MapView mv;
    36         /**
    37         * Manager that manages the selection rectangle with the aspect ratio of the
    38         * MapView.
    39         */
    40         private final SelectionManager selectionManager;
     32    /**
     33    * Shortcut to the mapview.
     34    */
     35    private final MapView mv;
     36    /**
     37    * Manager that manages the selection rectangle with the aspect ratio of the
     38    * MapView.
     39    */
     40    private final SelectionManager selectionManager;
    4141
    4242
    43         /**
    44         * Construct a ZoomAction without a label.
    45         * @param mapFrame The MapFrame, whose zoom mode should be enabled.
    46         */
    47         public ZoomAction(MapFrame mapFrame) {
    48                 super(tr("Zoom"), "zoom", tr("Zoom and move map"),
    49                 Shortcut.registerShortcut("mapmode:zoom", tr("Mode: {0}", tr("Zoom")), KeyEvent.VK_Z, Shortcut.GROUP_EDIT),
    50                 mapFrame, ImageProvider.getCursor("normal", "zoom"));
    51                 mv = mapFrame.mapView;
    52                 selectionManager = new SelectionManager(this, true, mv);
    53         }
     43    /**
     44    * Construct a ZoomAction without a label.
     45    * @param mapFrame The MapFrame, whose zoom mode should be enabled.
     46    */
     47    public ZoomAction(MapFrame mapFrame) {
     48        super(tr("Zoom"), "zoom", tr("Zoom and move map"),
     49        Shortcut.registerShortcut("mapmode:zoom", tr("Mode: {0}", tr("Zoom")), KeyEvent.VK_Z, Shortcut.GROUP_EDIT),
     50        mapFrame, ImageProvider.getCursor("normal", "zoom"));
     51        mv = mapFrame.mapView;
     52        selectionManager = new SelectionManager(this, true, mv);
     53    }
    5454
    55         /**
    56         * Zoom to the rectangle on the map.
    57         */
    58         public void selectionEnded(Rectangle r, boolean alt, boolean shift, boolean ctrl) {
    59                 if (r.width >= 3 && r.height >= 3) {
    60                         double scale = mv.getScale() * r.getWidth()/mv.getWidth();
    61                         EastNorth newCenter = mv.getEastNorth(r.x+r.width/2, r.y+r.height/2);
    62                         mv.zoomTo(newCenter, scale);
    63                 }
    64         }
     55    /**
     56    * Zoom to the rectangle on the map.
     57    */
     58    public void selectionEnded(Rectangle r, boolean alt, boolean shift, boolean ctrl) {
     59        if (r.width >= 3 && r.height >= 3) {
     60            double scale = mv.getScale() * r.getWidth()/mv.getWidth();
     61            EastNorth newCenter = mv.getEastNorth(r.x+r.width/2, r.y+r.height/2);
     62            mv.zoomTo(newCenter, scale);
     63        }
     64    }
    6565
    66         @Override public void enterMode() {
    67                 super.enterMode();
    68                 selectionManager.register(mv);
    69         }
     66    @Override public void enterMode() {
     67        super.enterMode();
     68        selectionManager.register(mv);
     69    }
    7070
    71         @Override public void exitMode() {
    72                 super.exitMode();
    73                 selectionManager.unregister(mv);
    74         }
     71    @Override public void exitMode() {
     72        super.exitMode();
     73        selectionManager.unregister(mv);
     74    }
    7575
    76         @Override public String getModeHelpText() {
    77                 return tr("Zoom by dragging or Ctrl+. or Ctrl+,; move with Ctrl+up,left,down,right; move zoom with right button");
    78         }
     76    @Override public String getModeHelpText() {
     77        return tr("Zoom by dragging or Ctrl+. or Ctrl+,; move with Ctrl+up,left,down,right; move zoom with right button");
     78    }
    7979}
  • trunk/src/org/openstreetmap/josm/actions/search/PushbackTokenizer.java

    r1149 r1169  
    77
    88public class PushbackTokenizer {
    9         private PushbackReader search;
     9    private PushbackReader search;
    1010
    11         private LinkedList<String> pushBackBuf = new LinkedList<String>();
     11    private LinkedList<String> pushBackBuf = new LinkedList<String>();
    1212
    13         public PushbackTokenizer(PushbackReader search) {
    14                 this.search = search;
    15         }
     13    public PushbackTokenizer(PushbackReader search) {
     14        this.search = search;
     15    }
    1616
    17         /**
    18         * The token returned is <code>null</code> or starts with an identifier character:
    19         * - for an '-'. This will be the only character
    20         * : for an key. The value is the next token
    21         * | for "OR"
    22         * ' ' for anything else.
    23         * @return The next token in the stream.
    24         */
    25         public String nextToken() {
    26                 if (!pushBackBuf.isEmpty()) {
    27                         return pushBackBuf.removeLast();
    28                 }
     17    /**
     18    * The token returned is <code>null</code> or starts with an identifier character:
     19    * - for an '-'. This will be the only character
     20    * : for an key. The value is the next token
     21    * | for "OR"
     22    * ' ' for anything else.
     23    * @return The next token in the stream.
     24    */
     25    public String nextToken() {
     26        if (!pushBackBuf.isEmpty()) {
     27            return pushBackBuf.removeLast();
     28        }
    2929
    30                 try {
    31                         int next;
    32                         char c = ' ';
    33                         while (c == ' ' || c == '\t' || c == '\n') {
    34                                 next = search.read();
    35                                 if (next == -1)
    36                                         return null;
    37                                 c = (char)next;
    38                         }
    39                         StringBuilder s;
    40                         switch (c) {
    41                         case ':':
    42                                 next = search.read();
    43                                 c = (char) next;
    44                                 if (next == -1 || c == ' ' || c == '\t') {
    45                                         pushBack(" ");
    46                                 } else {
    47                                         search.unread(next);
    48                                 }
    49                                 return ":";
    50                         case '-':
    51                                 return "-";
    52                         case '(':
    53                                 return "(";
    54                         case ')':
    55                                 return ")";
    56                         case '|':
    57                                 return "|";
    58                         case '"':
    59                                 s = new StringBuilder(" ");
    60                                 for (int nc = search.read(); nc != -1 && nc != '"'; nc = search.read())
    61                                         s.append((char)nc);
    62                                 return s.toString();
    63                         default:
    64                                 s = new StringBuilder();
    65                         for (;;) {
    66                                 s.append(c);
    67                                 next = search.read();
    68                                 if (next == -1) {
    69                                         if (s.toString().equals("OR"))
    70                                                 return "|";
    71                                         return " "+s.toString();
    72                                 }
    73                                 c = (char)next;
    74                                 if (c == ' ' || c == '\t' || c == '"' || c == ':' || c == '(' || c == ')' || c == '|') {
    75                                         search.unread(next);
    76                                         if (s.toString().equals("OR"))
    77                                                 return "|";
    78                                         return " "+s.toString();
    79                                 }
    80                         }
    81                         }
    82                 } catch (IOException e) {
    83                         throw new RuntimeException(e.getMessage(), e);
    84                 }               
    85         }
     30        try {
     31            int next;
     32            char c = ' ';
     33            while (c == ' ' || c == '\t' || c == '\n') {
     34                next = search.read();
     35                if (next == -1)
     36                    return null;
     37                c = (char)next;
     38            }
     39            StringBuilder s;
     40            switch (c) {
     41            case ':':
     42                next = search.read();
     43                c = (char) next;
     44                if (next == -1 || c == ' ' || c == '\t') {
     45                    pushBack(" ");
     46                } else {
     47                    search.unread(next);
     48                }
     49                return ":";
     50            case '-':
     51                return "-";
     52            case '(':
     53                return "(";
     54            case ')':
     55                return ")";
     56            case '|':
     57                return "|";
     58            case '"':
     59                s = new StringBuilder(" ");
     60                for (int nc = search.read(); nc != -1 && nc != '"'; nc = search.read())
     61                    s.append((char)nc);
     62                return s.toString();
     63            default:
     64                s = new StringBuilder();
     65            for (;;) {
     66                s.append(c);
     67                next = search.read();
     68                if (next == -1) {
     69                    if (s.toString().equals("OR"))
     70                        return "|";
     71                    return " "+s.toString();
     72                }
     73                c = (char)next;
     74                if (c == ' ' || c == '\t' || c == '"' || c == ':' || c == '(' || c == ')' || c == '|') {
     75                    search.unread(next);
     76                    if (s.toString().equals("OR"))
     77                        return "|";
     78                    return " "+s.toString();
     79                }
     80            }
     81            }
     82        } catch (IOException e) {
     83            throw new RuntimeException(e.getMessage(), e);
     84        }
     85    }
    8686
    87         public boolean readIfEqual(String tok) {
    88                 String nextTok = nextToken();
    89                 if (nextTok == null ? tok == null : nextTok.equals(tok)) 
    90                         return true;
    91                 pushBack(nextTok);
    92                 return false;
    93         }
     87    public boolean readIfEqual(String tok) {
     88        String nextTok = nextToken();
     89        if (nextTok == null ? tok == null : nextTok.equals(tok))
     90            return true;
     91        pushBack(nextTok);
     92        return false;
     93    }
    9494
    95         public String readText() {
    96                 String nextTok = nextToken();
    97                 if (nextTok != null && nextTok.startsWith(" "))
    98                         return nextTok.substring(1);
    99                 pushBack(nextTok);
    100                 return null;
    101         }
     95    public String readText() {
     96        String nextTok = nextToken();
     97        if (nextTok != null && nextTok.startsWith(" "))
     98            return nextTok.substring(1);
     99        pushBack(nextTok);
     100        return null;
     101    }
    102102
    103         public void pushBack(String tok) {
    104                 pushBackBuf.addLast(tok);
    105         }
     103    public void pushBack(String tok) {
     104        pushBackBuf.addLast(tok);
     105    }
    106106}
  • trunk/src/org/openstreetmap/josm/actions/search/SearchCompiler.java

    r1168 r1169  
    2020public class SearchCompiler {
    2121
    22         private boolean caseSensitive = false;
    23         private PushbackTokenizer tokenizer;
    24 
    25         public SearchCompiler(boolean caseSensitive, PushbackTokenizer tokenizer) {
    26                 this.caseSensitive = caseSensitive;
    27                 this.tokenizer = tokenizer;
    28         }
    29        
    30         abstract public static class Match {
    31                 abstract public boolean match(OsmPrimitive osm);
    32         }
    33 
    34         private static class Always extends Match {
    35                 @Override public boolean match(OsmPrimitive osm) {
    36                         return true;
    37                 }
    38         }
    39 
    40         private static class Not extends Match {
    41                 private final Match match;
    42                 public Not(Match match) {this.match = match;}
    43                 @Override public boolean match(OsmPrimitive osm) {
    44                         return !match.match(osm);
    45                 }
    46                 @Override public String toString() {return "!"+match;}
    47         }
    48 
    49         private static class And extends Match {
    50                 private Match lhs;
    51                 private Match rhs;
    52                 public And(Match lhs, Match rhs) {this.lhs = lhs; this.rhs = rhs;}
    53                 @Override public boolean match(OsmPrimitive osm) {
    54                         return lhs.match(osm) && rhs.match(osm);
    55                 }
    56                 @Override public String toString() {return lhs+" && "+rhs;}
    57         }
    58 
    59         private static class Or extends Match {
    60                 private Match lhs;
    61                 private Match rhs;
    62                 public Or(Match lhs, Match rhs) {this.lhs = lhs; this.rhs = rhs;}
    63                 @Override public boolean match(OsmPrimitive osm) {
    64                         return lhs.match(osm) || rhs.match(osm);
    65                 }
    66                 @Override public String toString() {return lhs+" || "+rhs;}
    67         }
    68 
    69         private static class Id extends Match {
    70                 private long id;
    71                 public Id(long id) {this.id = id;}
    72                 @Override public boolean match(OsmPrimitive osm) {
    73                         return osm.id == id;
    74                 }
    75                 @Override public String toString() {return "id="+id;}
    76         }
    77 
    78         private class KeyValue extends Match {
    79                 private String key;
    80                 private String value;
    81                 public KeyValue(String key, String value) {this.key = key; this.value = value; }
    82                 @Override public boolean match(OsmPrimitive osm) {
    83                         String value = null;
    84                         if (key.equals("timestamp"))
    85                                 value = osm.getTimeStr();
    86                         else
    87                                 value = osm.get(key);
    88                         if (value == null)
    89                                 return false;
    90                         String v1 = caseSensitive ? value : value.toLowerCase();
    91                         String v2 = caseSensitive ? this.value : this.value.toLowerCase();
    92                         // is not Java 1.5
    93                         //v1 = java.text.Normalizer.normalize(v1, java.text.Normalizer.Form.NFC);
    94                         //v2 = java.text.Normalizer.normalize(v2, java.text.Normalizer.Form.NFC);
    95                         return v1.indexOf(v2) != -1;
    96                 }
    97                 @Override public String toString() {return key+"="+value;}
    98         }
    99 
    100         private class Any extends Match {
    101                 private String s;
    102                 public Any(String s) {this.s = s;}
    103                 @Override public boolean match(OsmPrimitive osm) {
    104                         if (osm.keys == null)
    105                                 return s.equals("");
    106                         String search = caseSensitive ? s : s.toLowerCase();
    107                         // is not Java 1.5
    108                         //search = java.text.Normalizer.normalize(search, java.text.Normalizer.Form.NFC);
    109                         for (Entry<String, String> e : osm.keys.entrySet()) {
    110                                 String key = caseSensitive ? e.getKey() : e.getKey().toLowerCase();
    111                                 String value = caseSensitive ? e.getValue() : e.getValue().toLowerCase();
    112                                 // is not Java 1.5
    113                                 //value = java.text.Normalizer.normalize(value, java.text.Normalizer.Form.NFC);
    114                                 if (key.indexOf(search) != -1 || value.indexOf(search) != -1)
    115                                         return true;
    116                         }
    117                         if (osm.user != null) {
    118                                 String name = osm.user.name;
    119                                 // is not Java 1.5
    120                                 //String name = java.text.Normalizer.normalize(name, java.text.Normalizer.Form.NFC);
    121                                 if (!caseSensitive)
    122                                         name = name.toLowerCase();
    123                                 if (name.indexOf(search) != -1)
    124                                         return true;
    125                         }
    126                         return false;
    127                 }
    128                 @Override public String toString() {return s;}
    129         }
    130 
    131         private static class ExactType extends Match {
    132                 private String type;
    133                 public ExactType(String type) {this.type = type;}
    134                 @Override public boolean match(OsmPrimitive osm) {
    135                         if (osm instanceof Node)
    136                                 return type.equals("node");
    137                         if (osm instanceof Way)
    138                                 return type.equals("way");
    139                         if (osm instanceof Relation)
    140                                 return type.equals("relation");
    141                         throw new IllegalStateException("unknown class "+osm.getClass());
    142                 }
    143                 @Override public String toString() {return "type="+type;}
    144         }
    145 
    146         private static class UserMatch extends Match {
    147                 private User user;
    148                 public UserMatch(String user) { this.user = User.get(user); }
    149                 @Override public boolean match(OsmPrimitive osm) {
    150                         return osm.user == user;
    151                 }
    152                 @Override public String toString() { return "user=" + user.name; }
    153         }
    154 
    155         private static class NodeCount extends Match {
    156                 private int count;
    157                 public NodeCount(int count) {this.count = count;}
    158                 @Override public boolean match(OsmPrimitive osm) {
    159                         return osm instanceof Way && ((Way) osm).nodes.size() == count;
    160                 }
    161                 @Override public String toString() {return "nodes="+count;}
    162         }
    163 
    164         private static class Modified extends Match {
    165                 @Override public boolean match(OsmPrimitive osm) {
    166                         return osm.modified || osm.id == 0;
    167                 }
    168                 @Override public String toString() {return "modified";}
    169         }
    170        
    171         private static class Selected extends Match {
    172                 @Override public boolean match(OsmPrimitive osm) {
    173                         return osm.selected;
    174                 }
    175                 @Override public String toString() {return "selected";}
    176         }
    177 
    178         private static class Incomplete extends Match {
    179                 @Override public boolean match(OsmPrimitive osm) {
     22    private boolean caseSensitive = false;
     23    private PushbackTokenizer tokenizer;
     24
     25    public SearchCompiler(boolean caseSensitive, PushbackTokenizer tokenizer) {
     26        this.caseSensitive = caseSensitive;
     27        this.tokenizer = tokenizer;
     28    }
     29
     30    abstract public static class Match {
     31        abstract public boolean match(OsmPrimitive osm);
     32    }
     33
     34    private static class Always extends Match {
     35        @Override public boolean match(OsmPrimitive osm) {
     36            return true;
     37        }
     38    }
     39
     40    private static class Not extends Match {
     41        private final Match match;
     42        public Not(Match match) {this.match = match;}
     43        @Override public boolean match(OsmPrimitive osm) {
     44            return !match.match(osm);
     45        }
     46        @Override public String toString() {return "!"+match;}
     47    }
     48
     49    private static class And extends Match {
     50        private Match lhs;
     51        private Match rhs;
     52        public And(Match lhs, Match rhs) {this.lhs = lhs; this.rhs = rhs;}
     53        @Override public boolean match(OsmPrimitive osm) {
     54            return lhs.match(osm) && rhs.match(osm);
     55        }
     56        @Override public String toString() {return lhs+" && "+rhs;}
     57    }
     58
     59    private static class Or extends Match {
     60        private Match lhs;
     61        private Match rhs;
     62        public Or(Match lhs, Match rhs) {this.lhs = lhs; this.rhs = rhs;}
     63        @Override public boolean match(OsmPrimitive osm) {
     64            return lhs.match(osm) || rhs.match(osm);
     65        }
     66        @Override public String toString() {return lhs+" || "+rhs;}
     67    }
     68
     69    private static class Id extends Match {
     70        private long id;
     71        public Id(long id) {this.id = id;}
     72        @Override public boolean match(OsmPrimitive osm) {
     73            return osm.id == id;
     74        }
     75        @Override public String toString() {return "id="+id;}
     76    }
     77
     78    private class KeyValue extends Match {
     79        private String key;
     80        private String value;
     81        public KeyValue(String key, String value) {this.key = key; this.value = value; }
     82        @Override public boolean match(OsmPrimitive osm) {
     83            String value = null;
     84            if (key.equals("timestamp"))
     85                value = osm.getTimeStr();
     86            else
     87                value = osm.get(key);
     88            if (value == null)
     89                return false;
     90            String v1 = caseSensitive ? value : value.toLowerCase();
     91            String v2 = caseSensitive ? this.value : this.value.toLowerCase();
     92            // is not Java 1.5
     93            //v1 = java.text.Normalizer.normalize(v1, java.text.Normalizer.Form.NFC);
     94            //v2 = java.text.Normalizer.normalize(v2, java.text.Normalizer.Form.NFC);
     95            return v1.indexOf(v2) != -1;
     96        }
     97        @Override public String toString() {return key+"="+value;}
     98    }
     99
     100    private class Any extends Match {
     101        private String s;
     102        public Any(String s) {this.s = s;}
     103        @Override public boolean match(OsmPrimitive osm) {
     104            if (osm.keys == null)
     105                return s.equals("");
     106            String search = caseSensitive ? s : s.toLowerCase();
     107            // is not Java 1.5
     108            //search = java.text.Normalizer.normalize(search, java.text.Normalizer.Form.NFC);
     109            for (Entry<String, String> e : osm.keys.entrySet()) {
     110                String key = caseSensitive ? e.getKey() : e.getKey().toLowerCase();
     111                String value = caseSensitive ? e.getValue() : e.getValue().toLowerCase();
     112                // is not Java 1.5
     113                //value = java.text.Normalizer.normalize(value, java.text.Normalizer.Form.NFC);
     114                if (key.indexOf(search) != -1 || value.indexOf(search) != -1)
     115                    return true;
     116            }
     117            if (osm.user != null) {
     118                String name = osm.user.name;
     119                // is not Java 1.5
     120                //String name = java.text.Normalizer.normalize(name, java.text.Normalizer.Form.NFC);
     121                if (!caseSensitive)
     122                    name = name.toLowerCase();
     123                if (name.indexOf(search) != -1)
     124                    return true;
     125            }
     126            return false;
     127        }
     128        @Override public String toString() {return s;}
     129    }
     130
     131    private static class ExactType extends Match {
     132        private String type;
     133        public ExactType(String type) {this.type = type;}
     134        @Override public boolean match(OsmPrimitive osm) {
     135            if (osm instanceof Node)
     136                return type.equals("node");
     137            if (osm instanceof Way)
     138                return type.equals("way");
     139            if (osm instanceof Relation)
     140                return type.equals("relation");
     141            throw new IllegalStateException("unknown class "+osm.getClass());
     142        }
     143        @Override public String toString() {return "type="+type;}
     144    }
     145
     146    private static class UserMatch extends Match {
     147        private User user;
     148        public UserMatch(String user) { this.user = User.get(user); }
     149        @Override public boolean match(OsmPrimitive osm) {
     150            return osm.user == user;
     151        }
     152        @Override public String toString() { return "user=" + user.name; }
     153    }
     154
     155    private static class NodeCount extends Match {
     156        private int count;
     157        public NodeCount(int count) {this.count = count;}
     158        @Override public boolean match(OsmPrimitive osm) {
     159            return osm instanceof Way && ((Way) osm).nodes.size() == count;
     160        }
     161        @Override public String toString() {return "nodes="+count;}
     162    }
     163
     164    private static class Modified extends Match {
     165        @Override public boolean match(OsmPrimitive osm) {
     166            return osm.modified || osm.id == 0;
     167        }
     168        @Override public String toString() {return "modified";}
     169    }
     170
     171    private static class Selected extends Match {
     172        @Override public boolean match(OsmPrimitive osm) {
     173            return osm.selected;
     174        }
     175        @Override public String toString() {return "selected";}
     176    }
     177
     178    private static class Incomplete extends Match {
     179        @Override public boolean match(OsmPrimitive osm) {
    180180            return osm.incomplete;
    181                 }
    182                 @Override public String toString() {return "incomplete";}
    183         }
    184 
    185         public static class ParseError extends Exception {
    186                 public ParseError(String msg) {
    187                         super(msg);
    188                 }
    189         }
    190        
    191         public static Match compile(String searchStr, boolean caseSensitive)
    192                         throws ParseError {
    193                 return new SearchCompiler(caseSensitive,
    194                                 new PushbackTokenizer(
    195                                         new PushbackReader(new StringReader(searchStr))))
    196                         .parse();
    197         }
    198 
    199         public Match parse() throws ParseError {
    200                 Match m = parseJuxta();
    201                 if (!tokenizer.readIfEqual(null)) {
    202                         throw new ParseError("Unexpected token: " + tokenizer.nextToken());
    203                 }
    204                 return m;
    205         }
    206 
    207         private Match parseJuxta() throws ParseError {
    208                 Match juxta = new Always();
    209 
    210                 Match m;
    211                 while ((m = parseOr()) != null) {
    212                         juxta = new And(m, juxta);
    213                 }
    214 
    215                 return juxta;
    216         }
    217 
    218         private Match parseOr() throws ParseError {
    219                 Match a = parseNot();
    220                 if (tokenizer.readIfEqual("|")) {
    221                         Match b = parseNot();
    222                         if (a == null || b == null) {
    223                                 throw new ParseError(tr("Missing arguments for or."));
    224                         }
    225                         return new Or(a, b);
    226                 }
    227                 return a;
    228         }
    229 
    230         private Match parseNot() throws ParseError {
    231                 if (tokenizer.readIfEqual("-")) {
    232                         Match m = parseParens();
    233                         if (m == null) {
    234                                 throw new ParseError(tr("Missing argument for not."));
    235                         }
    236                         return new Not(m);
    237                 }
    238                 return parseParens();
    239         }
    240 
    241         private Match parseParens() throws ParseError {
    242                 if (tokenizer.readIfEqual("(")) {
    243                         Match m = parseJuxta();
    244                         if (!tokenizer.readIfEqual(")")) {
    245                                 throw new ParseError(tr("Expected closing parenthesis."));
    246                         }
    247                         return m;
    248                 }
    249                 return parsePat();
    250         }
    251 
    252         private Match parsePat() {
    253                 String tok = tokenizer.readText();
    254 
    255                 if (tokenizer.readIfEqual(":")) {
    256                         String tok2 = tokenizer.readText();
    257                         if (tok == null) tok = "";
    258                         if (tok2 == null) tok2 = "";
    259                         return parseKV(tok, tok2);
    260                 }
    261 
    262                 if (tok == null) {
    263                         return null;
    264                 } else if (tok.equals("modified")) {
    265                         return new Modified();
    266                 } else if (tok.equals("incomplete")) {
    267                         return new Incomplete();
    268                 } else if (tok.equals("selected")) {
    269                         return new Selected();
    270                 } else {
    271                         return new Any(tok);
    272                 }
    273         }
    274 
    275         private Match parseKV(String key, String value) {
    276                 if (key.equals("type")) {
    277                         return new ExactType(value);
    278                 } else if (key.equals("user")) {
    279                         return new UserMatch(value);
    280                 } else if (key.equals("nodes")) {
    281                         return new NodeCount(Integer.parseInt(value));
    282                 } else if (key.equals("id")) {
    283                         try {
    284                                 return new Id(Long.parseLong(value));
    285                         } catch (NumberFormatException x) {
    286                                 return new Id(0);
    287                         }
    288                 } else {
    289                         return new KeyValue(key, value);
    290                 }
    291         }
     181        }
     182        @Override public String toString() {return "incomplete";}
     183    }
     184
     185    public static class ParseError extends Exception {
     186        public ParseError(String msg) {
     187            super(msg);
     188        }
     189    }
     190
     191    public static Match compile(String searchStr, boolean caseSensitive)
     192            throws ParseError {
     193        return new SearchCompiler(caseSensitive,
     194                new PushbackTokenizer(
     195                    new PushbackReader(new StringReader(searchStr))))
     196            .parse();
     197    }
     198
     199    public Match parse() throws ParseError {
     200        Match m = parseJuxta();
     201        if (!tokenizer.readIfEqual(null)) {
     202            throw new ParseError("Unexpected token: " + tokenizer.nextToken());
     203        }
     204        return m;
     205    }
     206
     207    private Match parseJuxta() throws ParseError {
     208        Match juxta = new Always();
     209
     210        Match m;
     211        while ((m = parseOr()) != null) {
     212            juxta = new And(m, juxta);
     213        }
     214
     215        return juxta;
     216    }
     217
     218    private Match parseOr() throws ParseError {
     219        Match a = parseNot();
     220        if (tokenizer.readIfEqual("|")) {
     221            Match b = parseNot();
     222            if (a == null || b == null) {
     223                throw new ParseError(tr("Missing arguments for or."));
     224            }
     225            return new Or(a, b);
     226        }
     227        return a;
     228    }
     229
     230    private Match parseNot() throws ParseError {
     231        if (tokenizer.readIfEqual("-")) {
     232            Match m = parseParens();
     233            if (m == null) {
     234                throw new ParseError(tr("Missing argument for not."));
     235            }
     236            return new Not(m);
     237        }
     238        return parseParens();
     239    }
     240
     241    private Match parseParens() throws ParseError {
     242        if (tokenizer.readIfEqual("(")) {
     243            Match m = parseJuxta();
     244            if (!tokenizer.readIfEqual(")")) {
     245                throw new ParseError(tr("Expected closing parenthesis."));
     246            }
     247            return m;
     248        }
     249        return parsePat();
     250    }
     251
     252    private Match parsePat() {
     253        String tok = tokenizer.readText();
     254
     255        if (tokenizer.readIfEqual(":")) {
     256            String tok2 = tokenizer.readText();
     257            if (tok == null) tok = "";
     258            if (tok2 == null) tok2 = "";
     259            return parseKV(tok, tok2);
     260        }
     261
     262        if (tok == null) {
     263            return null;
     264        } else if (tok.equals("modified")) {
     265            return new Modified();
     266        } else if (tok.equals("incomplete")) {
     267            return new Incomplete();
     268        } else if (tok.equals("selected")) {
     269            return new Selected();
     270        } else {
     271            return new Any(tok);
     272        }
     273    }
     274
     275    private Match parseKV(String key, String value) {
     276        if (key.equals("type")) {
     277            return new ExactType(value);
     278        } else if (key.equals("user")) {
     279            return new UserMatch(value);
     280        } else if (key.equals("nodes")) {
     281            return new NodeCount(Integer.parseInt(value));
     282        } else if (key.equals("id")) {
     283            try {
     284                return new Id(Long.parseLong(value));
     285            } catch (NumberFormatException x) {
     286                return new Id(0);
     287            }
     288        } else {
     289            return new KeyValue(key, value);
     290        }
     291    }
    292292}
  • trunk/src/org/openstreetmap/josm/actions/search/SelectionWebsiteLoader.java

    r627 r1169  
    11// License: GPL. Copyright 2007 by Immanuel Scholz and others
    22/**
    3  * 
     3 *
    44 */
    55package org.openstreetmap.josm.actions.search;
     
    2626
    2727public class SelectionWebsiteLoader extends PleaseWaitRunnable {
    28         public final URL url;
    29         public Collection<OsmPrimitive> sel;
    30         private final SearchAction.SearchMode mode;
    31         private OsmIdReader idReader = new OsmIdReader();
    32         public SelectionWebsiteLoader(String urlStr, SearchAction.SearchMode mode) {
    33                 super(tr("Load Selection"));
    34                 this.mode = mode;
    35                 URL u = null;
    36                 try {u = new URL(urlStr);} catch (MalformedURLException e) {}
    37                 this.url = u;
    38         }
    39         @Override protected void realRun() {
    40                 Main.pleaseWaitDlg.currentAction.setText(tr("Contact {0}...", url.getHost()));
    41                 sel = mode != SearchAction.SearchMode.remove ? new LinkedList<OsmPrimitive>() : Main.ds.allNonDeletedPrimitives();
    42                 try {
    43                         URLConnection con = url.openConnection();
    44                         InputStream in = new ProgressInputStream(con, Main.pleaseWaitDlg);
    45                         Main.pleaseWaitDlg.currentAction.setText(tr("Downloading..."));
    46                         Map<Long, String> ids = idReader.parseIds(in);
    47                         for (OsmPrimitive osm : Main.ds.allNonDeletedPrimitives()) {
    48                                 if (ids.containsKey(osm.id) && osm.getClass().getName().toLowerCase().endsWith(ids.get(osm.id))) {
    49                                         if (mode == SearchAction.SearchMode.remove)
    50                                                 sel.remove(osm);
    51                                         else
    52                                                 sel.add(osm);
    53                                 }
    54                         }
    55                 } catch (IOException e) {
    56                         e.printStackTrace();
    57                         JOptionPane.showMessageDialog(Main.parent, tr("Could not read from url: \"{0}\"",url));
    58                 } catch (SAXException e) {
    59                         e.printStackTrace();
    60                         JOptionPane.showMessageDialog(Main.parent,tr("Parsing error in url: \"{0}\"",url));
    61                 }
    62         }
    63         @Override protected void cancel() {
    64                 sel = null;
    65                 idReader.cancel();
    66         }
    67         @Override protected void finish() {
    68                 if (sel != null)
    69                         Main.ds.setSelected(sel);
    70         }
     28    public final URL url;
     29    public Collection<OsmPrimitive> sel;
     30    private final SearchAction.SearchMode mode;
     31    private OsmIdReader idReader = new OsmIdReader();
     32    public SelectionWebsiteLoader(String urlStr, SearchAction.SearchMode mode) {
     33        super(tr("Load Selection"));
     34        this.mode = mode;
     35        URL u = null;
     36        try {u = new URL(urlStr);} catch (MalformedURLException e) {}
     37        this.url = u;
     38    }
     39    @Override protected void realRun() {
     40        Main.pleaseWaitDlg.currentAction.setText(tr("Contact {0}...", url.getHost()));
     41        sel = mode != SearchAction.SearchMode.remove ? new LinkedList<OsmPrimitive>() : Main.ds.allNonDeletedPrimitives();
     42        try {
     43            URLConnection con = url.openConnection();
     44            InputStream in = new ProgressInputStream(con, Main.pleaseWaitDlg);
     45            Main.pleaseWaitDlg.currentAction.setText(tr("Downloading..."));
     46            Map<Long, String> ids = idReader.parseIds(in);
     47            for (OsmPrimitive osm : Main.ds.allNonDeletedPrimitives()) {
     48                if (ids.containsKey(osm.id) && osm.getClass().getName().toLowerCase().endsWith(ids.get(osm.id))) {
     49                    if (mode == SearchAction.SearchMode.remove)
     50                        sel.remove(osm);
     51                    else
     52                        sel.add(osm);
     53                }
     54            }
     55        } catch (IOException e) {
     56            e.printStackTrace();
     57            JOptionPane.showMessageDialog(Main.parent, tr("Could not read from url: \"{0}\"",url));
     58        } catch (SAXException e) {
     59            e.printStackTrace();
     60            JOptionPane.showMessageDialog(Main.parent,tr("Parsing error in url: \"{0}\"",url));
     61        }
     62    }
     63    @Override protected void cancel() {
     64        sel = null;
     65        idReader.cancel();
     66    }
     67    @Override protected void finish() {
     68        if (sel != null)
     69            Main.ds.setSelected(sel);
     70    }
    7171}
  • trunk/src/org/openstreetmap/josm/command/AddCommand.java

    r655 r1169  
    2222 * A command that adds an osm primitive to a dataset. Keys cannot be added this
    2323 * way.
    24  * 
     24 *
    2525 * See {@link ChangeCommand ChangeCommand} for comments on relation back references.
    26  * 
     26 *
    2727 * @author imi
    2828 */
    2929public class AddCommand extends Command {
    3030
    31         /**
    32          * The primitive to add to the dataset.
    33          */
    34         private final OsmPrimitive osm;
    35        
    36         private DataSet ds;
     31    /**
     32     * The primitive to add to the dataset.
     33     */
     34    private final OsmPrimitive osm;
    3735
    38         /**
    39          * Create the command and specify the element to add.
    40          */
    41         public AddCommand(OsmPrimitive osm) {
    42                 this.osm = osm;
    43                 this.ds = Main.main.editLayer().data;
    44         }
     36    private DataSet ds;
    4537
    46         @Override public boolean executeCommand() {
    47                 osm.visit(new AddVisitor(ds));
    48                 return true;
    49         }
    50 
    51         @Override public void undoCommand() {
    52                 osm.visit(new DeleteVisitor(ds));
    53         }
    54 
    55         @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
    56                 added.add(osm);
    57         }
    58 
    59         // faster implementation
    60         @Override public boolean invalidBecauselayerRemoved(Layer oldLayer) {
    61             return oldLayer instanceof OsmDataLayer && ((OsmDataLayer)oldLayer).data == ds;
     38    /**
     39     * Create the command and specify the element to add.
     40     */
     41    public AddCommand(OsmPrimitive osm) {
     42        this.osm = osm;
     43        this.ds = Main.main.editLayer().data;
    6244    }
    6345
    64         @Override public MutableTreeNode description() {
    65                 NameVisitor v = new NameVisitor();
    66                 osm.visit(v);
    67                 return new DefaultMutableTreeNode(new JLabel(tr("Add")+" "+tr(v.className)+" "+v.name, v.icon, JLabel.HORIZONTAL));
     46    @Override public boolean executeCommand() {
     47        osm.visit(new AddVisitor(ds));
     48        return true;
     49    }
     50
     51    @Override public void undoCommand() {
     52        osm.visit(new DeleteVisitor(ds));
     53    }
     54
     55    @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
     56        added.add(osm);
     57    }
     58
     59    // faster implementation
     60    @Override public boolean invalidBecauselayerRemoved(Layer oldLayer) {
     61        return oldLayer instanceof OsmDataLayer && ((OsmDataLayer)oldLayer).data == ds;
     62    }
     63
     64    @Override public MutableTreeNode description() {
     65        NameVisitor v = new NameVisitor();
     66        osm.visit(v);
     67        return new DefaultMutableTreeNode(new JLabel(tr("Add")+" "+tr(v.className)+" "+v.name, v.icon, JLabel.HORIZONTAL));
    6868    }
    6969}
  • trunk/src/org/openstreetmap/josm/command/ChangeCommand.java

    r630 r1169  
    1414
    1515/**
    16  * Command that basically replaces one OSM primitive by another of the 
     16 * Command that basically replaces one OSM primitive by another of the
    1717 * same type.
    18  * 
     18 *
    1919 * @author Imi
    2020 */
    2121public class ChangeCommand extends Command {
    2222
    23         private final OsmPrimitive osm;
    24         private final OsmPrimitive newOsm;
     23    private final OsmPrimitive osm;
     24    private final OsmPrimitive newOsm;
    2525
    26         public ChangeCommand(OsmPrimitive osm, OsmPrimitive newOsm) {
    27                 this.osm = osm;
    28                 this.newOsm = newOsm;
     26    public ChangeCommand(OsmPrimitive osm, OsmPrimitive newOsm) {
     27        this.osm = osm;
     28        this.newOsm = newOsm;
    2929    }
    3030
    31         @Override public boolean executeCommand() {
    32             super.executeCommand();
    33             osm.cloneFrom(newOsm);
    34             osm.modified = true;
    35                 return true;
     31    @Override public boolean executeCommand() {
     32        super.executeCommand();
     33        osm.cloneFrom(newOsm);
     34        osm.modified = true;
     35        return true;
    3636    }
    3737
    38         @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
    39                 modified.add(osm);
     38    @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
     39        modified.add(osm);
    4040    }
    4141
    42         @Override public MutableTreeNode description() {
    43                 NameVisitor v = new NameVisitor();
    44                 osm.visit(v);
    45                 return new DefaultMutableTreeNode(new JLabel(tr("Change")+" "+tr(v.className)+" "+v.name, v.icon, JLabel.HORIZONTAL));
     42    @Override public MutableTreeNode description() {
     43        NameVisitor v = new NameVisitor();
     44        osm.visit(v);
     45        return new DefaultMutableTreeNode(new JLabel(tr("Change")+" "+tr(v.className)+" "+v.name, v.icon, JLabel.HORIZONTAL));
    4646    }
    4747}
  • trunk/src/org/openstreetmap/josm/command/ChangePropertyCommand.java

    r1101 r1169  
    2020 * Command that manipulate the key/value structure of several objects. Manages deletion,
    2121 * adding and modify of values and keys.
    22  * 
     22 *
    2323 * @author imi
    2424 */
    2525public class ChangePropertyCommand extends Command {
    26         /**
    27          * All primitives that are affected with this command.
    28          */
    29         private final List<OsmPrimitive> objects;
    30         /**
    31          * The key that is subject to change.
    32          */
    33         private final String key;
    34         /**
    35          * The key value. If it is <code>null</code>, delete all key references with the given
    36          * key. Otherwise, change the properties of all objects to the given value or create keys of
    37          * those objects that do not have the key yet.
    38          */
    39         private final String value;
    40        
    41         public ChangePropertyCommand(Collection<? extends OsmPrimitive> objects, String key, String value) {
    42                 this.objects = new LinkedList<OsmPrimitive>();
    43                 this.key = key;
    44                 this.value = value;
    45                 if (value == null) {
    46                         for (OsmPrimitive osm : objects) {
    47                                 if(osm.get(key) != null)
    48                                         this.objects.add(osm);
    49                         }
    50                 } else {
    51                         for (OsmPrimitive osm : objects) {
    52                                 String val = osm.get(key);
    53                                 if (val == null || !value.equals(val)) {
    54                                         this.objects.add(osm);
    55                                 }
    56                         }
    57                 }
    58         }
     26    /**
     27     * All primitives that are affected with this command.
     28     */
     29    private final List<OsmPrimitive> objects;
     30    /**
     31     * The key that is subject to change.
     32     */
     33    private final String key;
     34    /**
     35     * The key value. If it is <code>null</code>, delete all key references with the given
     36     * key. Otherwise, change the properties of all objects to the given value or create keys of
     37     * those objects that do not have the key yet.
     38     */
     39    private final String value;
    5940
    60         public ChangePropertyCommand(OsmPrimitive object, String key, String value) {
    61                 this.objects = new LinkedList<OsmPrimitive>();
    62                 this.key = key;
    63                 this.value = value;
    64                 String val = object.get(key);
    65                 if ((value == null && val != null)
    66                 || (value != null && (val == null || !value.equals(val))))
    67                         this.objects.add(object);
    68         }
    69        
    70         @Override public boolean executeCommand() {
    71                 super.executeCommand(); // save old
    72                 if (value == null) {
    73                         for (OsmPrimitive osm : objects) {
    74                                 osm.modified = true;
    75                                 osm.remove(key);
    76                         }
    77                 } else {
    78                         for (OsmPrimitive osm : objects) {
    79                                 osm.modified = true;
    80                                 osm.put(key, value);
    81                         }
    82                 }
    83                 return true;
    84         }
     41    public ChangePropertyCommand(Collection<? extends OsmPrimitive> objects, String key, String value) {
     42        this.objects = new LinkedList<OsmPrimitive>();
     43        this.key = key;
     44        this.value = value;
     45        if (value == null) {
     46            for (OsmPrimitive osm : objects) {
     47                if(osm.get(key) != null)
     48                    this.objects.add(osm);
     49            }
     50        } else {
     51            for (OsmPrimitive osm : objects) {
     52                String val = osm.get(key);
     53                if (val == null || !value.equals(val)) {
     54                    this.objects.add(osm);
     55                }
     56            }
     57        }
     58    }
    8559
    86         @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
    87                 modified.addAll(objects);
    88         }
     60    public ChangePropertyCommand(OsmPrimitive object, String key, String value) {
     61        this.objects = new LinkedList<OsmPrimitive>();
     62        this.key = key;
     63        this.value = value;
     64        String val = object.get(key);
     65        if ((value == null && val != null)
     66        || (value != null && (val == null || !value.equals(val))))
     67            this.objects.add(object);
     68    }
    8969
    90         @Override public MutableTreeNode description() {
    91                 String text = value == null ? tr( "Remove \"{0}\" for", key) : tr("Set {0}={1} for",key,value);
    92                 if (objects.size() == 1) {
    93                         NameVisitor v = new NameVisitor();
    94                         objects.iterator().next().visit(v);
    95                         text += " "+tr(v.className)+" "+v.name;
    96                 } else
    97                         text += " "+objects.size()+" "+trn("object","objects",objects.size());
    98                 DefaultMutableTreeNode root = new DefaultMutableTreeNode(new JLabel(text, ImageProvider.get("data", "key"), JLabel.HORIZONTAL));
    99                 if (objects.size() == 1)
    100                         return root;
    101                 NameVisitor v = new NameVisitor();
    102                 for (OsmPrimitive osm : objects) {
    103                         osm.visit(v);
    104                         root.add(new DefaultMutableTreeNode(v.toLabel()));
    105                 }
    106                 return root;
     70    @Override public boolean executeCommand() {
     71        super.executeCommand(); // save old
     72        if (value == null) {
     73            for (OsmPrimitive osm : objects) {
     74                osm.modified = true;
     75                osm.remove(key);
     76            }
     77        } else {
     78            for (OsmPrimitive osm : objects) {
     79                osm.modified = true;
     80                osm.put(key, value);
     81            }
     82        }
     83        return true;
     84    }
     85
     86    @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
     87        modified.addAll(objects);
     88    }
     89
     90    @Override public MutableTreeNode description() {
     91        String text = value == null ? tr( "Remove \"{0}\" for", key) : tr("Set {0}={1} for",key,value);
     92        if (objects.size() == 1) {
     93            NameVisitor v = new NameVisitor();
     94            objects.iterator().next().visit(v);
     95            text += " "+tr(v.className)+" "+v.name;
     96        } else
     97            text += " "+objects.size()+" "+trn("object","objects",objects.size());
     98        DefaultMutableTreeNode root = new DefaultMutableTreeNode(new JLabel(text, ImageProvider.get("data", "key"), JLabel.HORIZONTAL));
     99        if (objects.size() == 1)
     100            return root;
     101        NameVisitor v = new NameVisitor();
     102        for (OsmPrimitive osm : objects) {
     103            osm.visit(v);
     104            root.add(new DefaultMutableTreeNode(v.toLabel()));
     105        }
     106        return root;
    107107    }
    108108}
  • trunk/src/org/openstreetmap/josm/command/Command.java

    r655 r1169  
    2525 * one atomic action on a specific dataset, such as move or delete.
    2626 *
    27  * Remember that the command must be executable and undoable, even if the 
     27 * Remember that the command must be executable and undoable, even if the
    2828 * Main.ds has changed, so the command must save the dataset it operates on
    2929 * if necessary.
     
    4747   }
    4848
    49    private CloneVisitor orig; 
     49   private CloneVisitor orig;
    5050
    5151   protected DataSet ds;
     
    7070
    7171   /**
    72     * Undoes the command. 
     72    * Undoes the command.
    7373    * It can be assumed that all objects are in the same state they were before.
    7474    * It can also be assumed that executeCommand was called exactly once before.
    75     * 
     75    *
    7676    * This implementation undoes all objects stored by a former call to executeCommand.
    7777    */
     
    122122    * Fill in the changed data this command operates on.
    123123    * Add to the lists, don't clear them.
    124     * 
     124    *
    125125    * @param modified The modified primitives
    126126    * @param deleted The deleted primitives
  • trunk/src/org/openstreetmap/josm/command/ConflictResolveCommand.java

    r630 r1169  
    2525public class ConflictResolveCommand extends Command {
    2626
    27         private final Collection<ConflictItem> conflicts;
    28         private final Map<OsmPrimitive, OsmPrimitive> resolved;
    29         private Map<OsmPrimitive, OsmPrimitive> origAllConflicts;
    30         private final ConflictDialog conflictDialog;
     27    private final Collection<ConflictItem> conflicts;
     28    private final Map<OsmPrimitive, OsmPrimitive> resolved;
     29    private Map<OsmPrimitive, OsmPrimitive> origAllConflicts;
     30    private final ConflictDialog conflictDialog;
    3131
    32         public ConflictResolveCommand(List<ConflictItem> conflicts, Map<OsmPrimitive, OsmPrimitive> resolved) {
    33                 this.conflicts = conflicts;
    34                 this.resolved = resolved;
    35                 conflictDialog = Main.map.conflictDialog;
    36         }
     32    public ConflictResolveCommand(List<ConflictItem> conflicts, Map<OsmPrimitive, OsmPrimitive> resolved) {
     33        this.conflicts = conflicts;
     34        this.resolved = resolved;
     35        conflictDialog = Main.map.conflictDialog;
     36    }
    3737
    38         @Override public boolean executeCommand() {
    39                 super.executeCommand();
     38    @Override public boolean executeCommand() {
     39        super.executeCommand();
    4040
    41                 origAllConflicts = new HashMap<OsmPrimitive, OsmPrimitive>(conflictDialog.conflicts);
    42                
    43                 Set<OsmPrimitive> completed = new HashSet<OsmPrimitive>(resolved.keySet());
    44                 for (ConflictItem ci : conflicts) {
    45                         for (Entry<OsmPrimitive, OsmPrimitive> e : resolved.entrySet()) {
    46                                 if (ci.resolution == ConflictResolver.Resolution.THEIR)
    47                                         ci.apply(e.getKey(), e.getValue());
    48                                 else if (ci.resolution == ConflictResolver.Resolution.MY)
    49                                         ci.apply(e.getValue(), e.getKey());
    50                                 else if (ci.hasConflict(e.getKey(), e.getValue()))
    51                                         completed.remove(e.getKey());
    52                         }
    53                 }
    54                 if (!completed.isEmpty()) {
    55                         for (OsmPrimitive k : completed)
    56                                 conflictDialog.conflicts.remove(k);
    57                         conflictDialog.rebuildList();
    58                 }
    59                 return true;
    60         }
     41        origAllConflicts = new HashMap<OsmPrimitive, OsmPrimitive>(conflictDialog.conflicts);
    6142
    62         @Override public void undoCommand() {
    63                 super.undoCommand();
    64                 Main.map.conflictDialog.conflicts.clear();
    65                 Main.map.conflictDialog.conflicts.putAll(origAllConflicts);
    66                 Main.map.conflictDialog.rebuildList();
    67         }
     43        Set<OsmPrimitive> completed = new HashSet<OsmPrimitive>(resolved.keySet());
     44        for (ConflictItem ci : conflicts) {
     45            for (Entry<OsmPrimitive, OsmPrimitive> e : resolved.entrySet()) {
     46                if (ci.resolution == ConflictResolver.Resolution.THEIR)
     47                    ci.apply(e.getKey(), e.getValue());
     48                else if (ci.resolution == ConflictResolver.Resolution.MY)
     49                    ci.apply(e.getValue(), e.getKey());
     50                else if (ci.hasConflict(e.getKey(), e.getValue()))
     51                    completed.remove(e.getKey());
     52            }
     53        }
     54        if (!completed.isEmpty()) {
     55            for (OsmPrimitive k : completed)
     56                conflictDialog.conflicts.remove(k);
     57            conflictDialog.rebuildList();
     58        }
     59        return true;
     60    }
    6861
    69         @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
    70                 modified.addAll(resolved.keySet());
    71         }
     62    @Override public void undoCommand() {
     63        super.undoCommand();
     64        Main.map.conflictDialog.conflicts.clear();
     65        Main.map.conflictDialog.conflicts.putAll(origAllConflicts);
     66        Main.map.conflictDialog.rebuildList();
     67    }
    7268
    73         @Override public MutableTreeNode description() {
    74                 int i = 0;
    75                 for (ConflictItem c : conflicts)
    76                         if (c.resolution != null)
    77                                 i++;
    78                 return new DefaultMutableTreeNode(new JLabel(tr("Resolve {0} conflicts in {1} objects",i,resolved.size()), ImageProvider.get("data", "object"), JLabel.HORIZONTAL));
     69    @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
     70        modified.addAll(resolved.keySet());
     71    }
     72
     73    @Override public MutableTreeNode description() {
     74        int i = 0;
     75        for (ConflictItem c : conflicts)
     76            if (c.resolution != null)
     77                i++;
     78        return new DefaultMutableTreeNode(new JLabel(tr("Resolve {0} conflicts in {1} objects",i,resolved.size()), ImageProvider.get("data", "object"), JLabel.HORIZONTAL));
    7979    }
    8080}
  • trunk/src/org/openstreetmap/josm/command/DeleteCommand.java

    r1047 r1169  
    105105    /**
    106106     * Delete the primitives and everything they reference.
    107      * 
     107     *
    108108     * If a node is deleted, the node and all ways and relations the node is part of are deleted as
    109109     * well.
    110      * 
     110     *
    111111     * If a way is deleted, all relations the way is member of are also deleted.
    112      * 
     112     *
    113113     * If a way is deleted, only the way and no nodes are deleted.
    114      * 
     114     *
    115115     * @param selection The list of all object to be deleted.
    116116     * @return command A command to perform the deletions, or null of there is nothing to delete.
     
    130130    /**
    131131     * Try to delete all given primitives.
    132      * 
     132     *
    133133     * If a node is used by a way, it's removed from that way. If a node or a way is used by a
    134134     * relation, inform the user and do not delete.
    135      * 
     135     *
    136136     * If this would cause ways with less than 2 nodes to be created, delete these ways instead. If
    137137     * they are part of a relation, inform the user and do not delete.
    138      * 
     138     *
    139139     * @param selection The objects to delete.
    140140     * @param alsoDeleteNodesInWay <code>true</code> if nodes should be deleted as well
     
    341341                            // leave message in one tr() as there is a grammatical connection.
    342342                            tr("You are about to delete nodes outside of the area you have downloaded." +
    343                             "<br>" + 
     343                            "<br>" +
    344344                            "This can cause problems because other objects (that you don't see) might use them." +
    345                             "<br>" + 
     345                            "<br>" +
    346346                            "Do you really want to delete?") + "</html>"));
    347347                        return DontShowAgainInfo.show("delete_outside_nodes", msg, false, JOptionPane.YES_NO_OPTION, JOptionPane.YES_OPTION);
  • trunk/src/org/openstreetmap/josm/command/MoveCommand.java

    r655 r1169  
    2626 * MoveCommand moves a set of OsmPrimitives along the map. It can be moved again
    2727 * to collect several MoveCommands into one command.
    28  * 
     28 *
    2929 * @author imi
    3030 */
    3131public class MoveCommand extends Command {
    32         /**
    33         * The objects that should be moved.
    34         */
    35         public Collection<Node> objects = new LinkedList<Node>();
    36         /**
    37         * x difference movement. Coordinates are in northern/eastern 
    38         */
    39         private double x;
    40         /**
    41         * y difference movement. Coordinates are in northern/eastern 
    42         */
    43         private double y;
     32    /**
     33    * The objects that should be moved.
     34    */
     35    public Collection<Node> objects = new LinkedList<Node>();
     36    /**
     37    * x difference movement. Coordinates are in northern/eastern
     38    */
     39    private double x;
     40    /**
     41    * y difference movement. Coordinates are in northern/eastern
     42    */
     43    private double y;
    4444
    45         /**
    46          * Small helper for holding the interesting part of the old data state of the
    47          * objects.
    48          */
    49         public static class OldState {
    50                 LatLon latlon;
    51                 EastNorth eastNorth;
    52                 boolean modified;
    53         }
    54        
    55         /**
    56          * List of all old states of the objects.
    57          */
    58         private List<OldState> oldState = new LinkedList<OldState>();
     45    /**
     46     * Small helper for holding the interesting part of the old data state of the
     47     * objects.
     48     */
     49    public static class OldState {
     50        LatLon latlon;
     51        EastNorth eastNorth;
     52        boolean modified;
     53    }
    5954
    60        
    61         public MoveCommand(OsmPrimitive osm, double x, double y) {
    62                 this(Collections.singleton(osm), x, y);
    63         }
    64         /**
    65          * Create a MoveCommand and assign the initial object set and movement vector.
    66          */
    67         public MoveCommand(Collection<OsmPrimitive> objects, double x, double y) {
    68                 this.x = x;
    69                 this.y = y;
    70                 this.objects = AllNodesVisitor.getAllNodes(objects);
    71                 for (Node n : this.objects) {
    72                         OldState os = new OldState();
    73                         os.eastNorth = n.eastNorth;
    74                         os.latlon = n.coor;
    75                         os.modified = n.modified;
    76                         oldState.add(os);
    77                 }
    78         }
     55    /**
     56     * List of all old states of the objects.
     57     */
     58    private List<OldState> oldState = new LinkedList<OldState>();
    7959
    80         /**
    81          * Move the same set of objects again by the specified vector. The vectors
    82          * are added together and so the resulting will be moved to the previous
    83          * vector plus this one.
    84          *
    85          * The move is immediately executed and any undo will undo both vectors to
    86          * the original position the objects had before first moving.
    87          */
    88         public void moveAgain(double x, double y) {
    89                 for (Node n : objects) {
    90                         n.eastNorth = new EastNorth(n.eastNorth.east()+x, n.eastNorth.north()+y);
    91                         n.coor = Main.proj.eastNorth2latlon(n.eastNorth);
    92                 }
    93                 this.x += x;
    94                 this.y += y;
    95         }
    96        
    97         @Override public boolean executeCommand() {
    98                 for (Node n : objects) {
    99                         n.eastNorth = new EastNorth(n.eastNorth.east()+x, n.eastNorth.north()+y);
    100                         n.coor = Main.proj.eastNorth2latlon(n.eastNorth);
    101                         n.modified = true;
    102                 }
    103                 return true;
    104         }
    10560
    106         @Override public void undoCommand() {
    107                 Iterator<OldState> it = oldState.iterator();
    108                 for (Node n : objects) {
    109                         OldState os = it.next();
    110                         n.eastNorth = os.eastNorth;
    111                         n.coor = os.latlon;
    112                         n.modified = os.modified;
    113                 }
    114         }
     61    public MoveCommand(OsmPrimitive osm, double x, double y) {
     62        this(Collections.singleton(osm), x, y);
     63    }
     64    /**
     65     * Create a MoveCommand and assign the initial object set and movement vector.
     66     */
     67    public MoveCommand(Collection<OsmPrimitive> objects, double x, double y) {
     68        this.x = x;
     69        this.y = y;
     70        this.objects = AllNodesVisitor.getAllNodes(objects);
     71        for (Node n : this.objects) {
     72            OldState os = new OldState();
     73            os.eastNorth = n.eastNorth;
     74            os.latlon = n.coor;
     75            os.modified = n.modified;
     76            oldState.add(os);
     77        }
     78    }
    11579
    116         @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
    117                 for (OsmPrimitive osm : objects)
    118                         modified.add(osm);
    119         }
     80    /**
     81     * Move the same set of objects again by the specified vector. The vectors
     82     * are added together and so the resulting will be moved to the previous
     83     * vector plus this one.
     84     *
     85     * The move is immediately executed and any undo will undo both vectors to
     86     * the original position the objects had before first moving.
     87     */
     88    public void moveAgain(double x, double y) {
     89        for (Node n : objects) {
     90            n.eastNorth = new EastNorth(n.eastNorth.east()+x, n.eastNorth.north()+y);
     91            n.coor = Main.proj.eastNorth2latlon(n.eastNorth);
     92        }
     93        this.x += x;
     94        this.y += y;
     95    }
    12096
    121         @Override public MutableTreeNode description() {
    122                 return new DefaultMutableTreeNode(new JLabel(tr("Move")+" "+objects.size()+" "+trn("node","nodes",objects.size()), ImageProvider.get("data", "node"), JLabel.HORIZONTAL));
     97    @Override public boolean executeCommand() {
     98        for (Node n : objects) {
     99            n.eastNorth = new EastNorth(n.eastNorth.east()+x, n.eastNorth.north()+y);
     100            n.coor = Main.proj.eastNorth2latlon(n.eastNorth);
     101            n.modified = true;
     102        }
     103        return true;
     104    }
     105
     106    @Override public void undoCommand() {
     107        Iterator<OldState> it = oldState.iterator();
     108        for (Node n : objects) {
     109            OldState os = it.next();
     110            n.eastNorth = os.eastNorth;
     111            n.coor = os.latlon;
     112            n.modified = os.modified;
     113        }
     114    }
     115
     116    @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
     117        for (OsmPrimitive osm : objects)
     118            modified.add(osm);
     119    }
     120
     121    @Override public MutableTreeNode description() {
     122        return new DefaultMutableTreeNode(new JLabel(tr("Move")+" "+objects.size()+" "+trn("node","nodes",objects.size()), ImageProvider.get("data", "node"), JLabel.HORIZONTAL));
    123123    }
    124124}
  • trunk/src/org/openstreetmap/josm/command/RotateCommand.java

    r748 r1169  
    2323/**
    2424 * RotateCommand rotates a number of objects around their centre.
    25  * 
     25 *
    2626 * @author Frederik Ramm <frederik@remote.org>
    2727 */
    2828public class RotateCommand extends Command {
    29        
    30         /**
    31          * The objects to rotate.
    32          */
    33         public Collection<Node> objects = new LinkedList<Node>();
    34        
    35         /**
    36          * pivot point
    37          */
    38         private Node pivot;
    39        
    40         /**
    41          * angle of rotation starting click to pivot
    42          */
    43         private double startAngle;
    44        
    45         /**
    46          * computed rotation angle between starting click and current mouse pos
    47          */
    48         private double rotationAngle;
    49        
    50         /**
    51          * List of all old states of the objects.
    52          */
    53         private Map<Node, MoveCommand.OldState> oldState = new HashMap<Node, MoveCommand.OldState>();
    54        
    55         /**
    56          * Creates a RotateCommand.
    57          * Assign the initial object set, compute pivot point and rotation angle.
    58          * Computation of pivot point is done by the same rules that are used in
    59          * the "align nodes in circle" action.
    60          */
    61         public RotateCommand(Collection<OsmPrimitive> objects, EastNorth start, EastNorth end) {
    6229
    63                 this.objects = AllNodesVisitor.getAllNodes(objects);
    64                 pivot = new Node(new LatLon(0,0));
    65                 pivot.eastNorth = new EastNorth(0,0);
     30    /**
     31     * The objects to rotate.
     32     */
     33    public Collection<Node> objects = new LinkedList<Node>();
    6634
    67                 for (Node n : this.objects) {
    68                         MoveCommand.OldState os = new MoveCommand.OldState();
    69                         os.eastNorth = n.eastNorth;
    70                         os.latlon = n.coor;
    71                         os.modified = n.modified;
    72                         oldState.put(n, os);
    73                         pivot.eastNorth = new EastNorth(pivot.eastNorth.east()+os.eastNorth.east(), pivot.eastNorth.north()+os.eastNorth.north());
    74                 }
    75                 pivot.eastNorth = new EastNorth(pivot.eastNorth.east()/this.objects.size(), pivot.eastNorth.north()/this.objects.size());
    76                 pivot.coor = Main.proj.eastNorth2latlon(pivot.eastNorth);
     35    /**
     36     * pivot point
     37     */
     38    private Node pivot;
    7739
    78                 rotationAngle = Math.PI/2;
    79                 rotateAgain(start, end);
    80         }
     40    /**
     41     * angle of rotation starting click to pivot
     42     */
     43    private double startAngle;
    8144
    82         /**
    83          * Rotate the same set of objects again, by the angle between given
    84          * start and end nodes. Internally this is added to the existing
    85          * rotation so a later undo will undo the whole rotation.
    86          */
    87         public void rotateAgain(EastNorth start, EastNorth end) {
    88                 // compute angle
    89                 startAngle = Math.atan2(start.east()-pivot.eastNorth.east(), start.north()-pivot.eastNorth.north());
    90                 double endAngle = Math.atan2(end.east()-pivot.eastNorth.east(), end.north()-pivot.eastNorth.north());
    91                 rotationAngle += startAngle - endAngle;
    92                 rotateNodes(false);
    93         }
     45    /**
     46     * computed rotation angle between starting click and current mouse pos
     47     */
     48    private double rotationAngle;
    9449
    95         /**
    96          * Helper for actually rotationg the nodes.
    97          * @param setModified - true if rotated nodes should be flagged "modified"
    98          */
    99         private void rotateNodes(boolean setModified) {
    100                 for (Node n : objects) {
    101                         double cosPhi = Math.cos(rotationAngle);
    102                         double sinPhi = Math.sin(rotationAngle);
    103                         EastNorth oldEastNorth = oldState.get(n).eastNorth;
    104                         double x = oldEastNorth.east() - pivot.eastNorth.east();
    105                         double y = oldEastNorth.north() - pivot.eastNorth.north();
    106                         double nx =  sinPhi * x + cosPhi * y + pivot.eastNorth.east();
    107                         double ny = -cosPhi * x + sinPhi * y + pivot.eastNorth.north();
    108                         n.eastNorth = new EastNorth(nx, ny);
    109                         n.coor = Main.proj.eastNorth2latlon(n.eastNorth);
    110                         if (setModified)
    111                                 n.modified = true;     
    112                 }
    113         }
    114        
    115         @Override public boolean executeCommand() {
    116                 rotateNodes(true);
    117                 return true;
    118         }
     50    /**
     51     * List of all old states of the objects.
     52     */
     53    private Map<Node, MoveCommand.OldState> oldState = new HashMap<Node, MoveCommand.OldState>();
    11954
    120         @Override public void undoCommand() {
    121                 for (Node n : objects) {
    122                         MoveCommand.OldState os = oldState.get(n);
    123                         n.eastNorth = os.eastNorth;
    124                         n.coor = os.latlon;
    125                         n.modified = os.modified;
    126                 }
    127         }
     55    /**
     56     * Creates a RotateCommand.
     57     * Assign the initial object set, compute pivot point and rotation angle.
     58     * Computation of pivot point is done by the same rules that are used in
     59     * the "align nodes in circle" action.
     60     */
     61    public RotateCommand(Collection<OsmPrimitive> objects, EastNorth start, EastNorth end) {
    12862
    129         @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
    130                 for (OsmPrimitive osm : objects)
    131                         modified.add(osm);
    132         }
     63        this.objects = AllNodesVisitor.getAllNodes(objects);
     64        pivot = new Node(new LatLon(0,0));
     65        pivot.eastNorth = new EastNorth(0,0);
    13366
    134         @Override public MutableTreeNode description() {
    135                 return new DefaultMutableTreeNode(new JLabel(tr("Rotate")+" "+objects.size()+" "+trn("node","nodes",objects.size()), ImageProvider.get("data", "node"), JLabel.HORIZONTAL));
     67        for (Node n : this.objects) {
     68            MoveCommand.OldState os = new MoveCommand.OldState();
     69            os.eastNorth = n.eastNorth;
     70            os.latlon = n.coor;
     71            os.modified = n.modified;
     72            oldState.put(n, os);
     73            pivot.eastNorth = new EastNorth(pivot.eastNorth.east()+os.eastNorth.east(), pivot.eastNorth.north()+os.eastNorth.north());
     74        }
     75        pivot.eastNorth = new EastNorth(pivot.eastNorth.east()/this.objects.size(), pivot.eastNorth.north()/this.objects.size());
     76        pivot.coor = Main.proj.eastNorth2latlon(pivot.eastNorth);
     77
     78        rotationAngle = Math.PI/2;
     79        rotateAgain(start, end);
     80    }
     81
     82    /**
     83     * Rotate the same set of objects again, by the angle between given
     84     * start and end nodes. Internally this is added to the existing
     85     * rotation so a later undo will undo the whole rotation.
     86     */
     87    public void rotateAgain(EastNorth start, EastNorth end) {
     88        // compute angle
     89        startAngle = Math.atan2(start.east()-pivot.eastNorth.east(), start.north()-pivot.eastNorth.north());
     90        double endAngle = Math.atan2(end.east()-pivot.eastNorth.east(), end.north()-pivot.eastNorth.north());
     91        rotationAngle += startAngle - endAngle;
     92        rotateNodes(false);
     93    }
     94
     95    /**
     96     * Helper for actually rotationg the nodes.
     97     * @param setModified - true if rotated nodes should be flagged "modified"
     98     */
     99    private void rotateNodes(boolean setModified) {
     100        for (Node n : objects) {
     101            double cosPhi = Math.cos(rotationAngle);
     102            double sinPhi = Math.sin(rotationAngle);
     103            EastNorth oldEastNorth = oldState.get(n).eastNorth;
     104            double x = oldEastNorth.east() - pivot.eastNorth.east();
     105            double y = oldEastNorth.north() - pivot.eastNorth.north();
     106            double nx =  sinPhi * x + cosPhi * y + pivot.eastNorth.east();
     107            double ny = -cosPhi * x + sinPhi * y + pivot.eastNorth.north();
     108            n.eastNorth = new EastNorth(nx, ny);
     109            n.coor = Main.proj.eastNorth2latlon(n.eastNorth);
     110            if (setModified)
     111                n.modified = true;
     112        }
     113    }
     114
     115    @Override public boolean executeCommand() {
     116        rotateNodes(true);
     117        return true;
     118    }
     119
     120    @Override public void undoCommand() {
     121        for (Node n : objects) {
     122            MoveCommand.OldState os = oldState.get(n);
     123            n.eastNorth = os.eastNorth;
     124            n.coor = os.latlon;
     125            n.modified = os.modified;
     126        }
     127    }
     128
     129    @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
     130        for (OsmPrimitive osm : objects)
     131            modified.add(osm);
     132    }
     133
     134    @Override public MutableTreeNode description() {
     135        return new DefaultMutableTreeNode(new JLabel(tr("Rotate")+" "+objects.size()+" "+trn("node","nodes",objects.size()), ImageProvider.get("data", "node"), JLabel.HORIZONTAL));
    136136    }
    137137}
  • trunk/src/org/openstreetmap/josm/command/SequenceCommand.java

    r853 r1169  
    2020public class SequenceCommand extends Command {
    2121
    22         /**
    23         * The command sequenz to be executed.
    24         */
    25         private Command[] sequence;
    26         private boolean sequence_complete;
    27         private final String name;
    28         public boolean continueOnError = false;
     22    /**
     23    * The command sequenz to be executed.
     24    */
     25    private Command[] sequence;
     26    private boolean sequence_complete;
     27    private final String name;
     28    public boolean continueOnError = false;
    2929
    30         /**
    31         * Create the command by specifying the list of commands to execute.
    32         * @param sequenz The sequence that should be executed.
    33         */
    34         public SequenceCommand(String name, Collection<Command> sequenz) {
    35                 this.name = name;
    36                 this.sequence = new Command[sequenz.size()];
    37                 this.sequence = sequenz.toArray(this.sequence);
    38         }
     30    /**
     31    * Create the command by specifying the list of commands to execute.
     32    * @param sequenz The sequence that should be executed.
     33    */
     34    public SequenceCommand(String name, Collection<Command> sequenz) {
     35        this.name = name;
     36        this.sequence = new Command[sequenz.size()];
     37        this.sequence = sequenz.toArray(this.sequence);
     38    }
    3939
    40         /**
    41          * Convenient constructor, if the commands are known at compile time.
    42          */
    43         public SequenceCommand(String name, Command... sequenz) {
    44                 this(name, Arrays.asList(sequenz));
    45         }
    46        
    47         public int executed_commands = 0;
    48         @Override public boolean executeCommand() {
    49                 for (int i=0; i < sequence.length; i++) {
    50                         Command c = sequence[i];
    51                         boolean result = c.executeCommand();
    52                         if (!result)
    53                                 Main.debug("SequenceCommand, executing command[" + i + "] " +  c + " result: " + result);
    54                         if (!result && !continueOnError) {
    55                                 this.undoCommands(i-1);
    56                                 return false;
    57                         }
    58                 }
    59                 sequence_complete = true;
    60                 return true;
    61         }
     40    /**
     41     * Convenient constructor, if the commands are known at compile time.
     42     */
     43    public SequenceCommand(String name, Command... sequenz) {
     44        this(name, Arrays.asList(sequenz));
     45    }
    6246
    63         public Command getLastCommand() {
    64                 if(sequence.length == 0)
    65                         return null;
    66                 return sequence[sequence.length-1];
    67         }
    68         private void undoCommands(int start) {
    69                 // We probably aborted this halfway though the
    70                 // execution sequence because of a sub-command
    71                 // error.  We already undid the sub-commands.
    72                 if (!sequence_complete)
    73                         return;
    74                 for (int i = start; i >= 0; --i)
    75                         sequence[i].undoCommand();
    76         }
     47    public int executed_commands = 0;
     48    @Override public boolean executeCommand() {
     49        for (int i=0; i < sequence.length; i++) {
     50            Command c = sequence[i];
     51            boolean result = c.executeCommand();
     52            if (!result)
     53                Main.debug("SequenceCommand, executing command[" + i + "] " +  c + " result: " + result);
     54            if (!result && !continueOnError) {
     55                this.undoCommands(i-1);
     56                return false;
     57            }
     58        }
     59        sequence_complete = true;
     60        return true;
     61    }
    7762
    78         @Override public void undoCommand() {
    79                 this.undoCommands(sequence.length-1);
    80         }
     63    public Command getLastCommand() {
     64        if(sequence.length == 0)
     65            return null;
     66        return sequence[sequence.length-1];
     67    }
     68    private void undoCommands(int start) {
     69        // We probably aborted this halfway though the
     70        // execution sequence because of a sub-command
     71        // error.  We already undid the sub-commands.
     72        if (!sequence_complete)
     73            return;
     74        for (int i = start; i >= 0; --i)
     75            sequence[i].undoCommand();
     76    }
    8177
    82         @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
    83                 for (Command c : sequence)
    84                         c.fillModifiedData(modified, deleted, added);
    85         }
     78    @Override public void undoCommand() {
     79        this.undoCommands(sequence.length-1);
     80    }
    8681
    87         @Override public MutableTreeNode description() {
    88                 DefaultMutableTreeNode root = new DefaultMutableTreeNode(tr("Sequence")+": "+name);
    89                 for (Command c : sequence)
    90                         root.add(c.description());
    91             return root;
     82    @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
     83        for (Command c : sequence)
     84            c.fillModifiedData(modified, deleted, added);
     85    }
     86
     87    @Override public MutableTreeNode description() {
     88        DefaultMutableTreeNode root = new DefaultMutableTreeNode(tr("Sequence")+": "+name);
     89        for (Command c : sequence)
     90            root.add(c.description());
     91        return root;
    9292    }
    9393}
  • trunk/src/org/openstreetmap/josm/corrector/CorrectionTable.java

    r1001 r1169  
    1313        extends JTable {
    1414
    15         private static final int MAX_VISIBLE_LINES = 10;
     15    private static final int MAX_VISIBLE_LINES = 10;
    1616
    1717    public static class BoldRenderer extends JLabel implements
    18                 TableCellRenderer {
     18            TableCellRenderer {
    1919
    20                 public Component getTableCellRendererComponent(JTable table,
    21                         Object value, boolean isSelected, boolean hasFocus, int row,
    22                         int column) {
     20        public Component getTableCellRendererComponent(JTable table,
     21                Object value, boolean isSelected, boolean hasFocus, int row,
     22                int column) {
    2323
    24                         Font f = getFont();
    25                         setFont(new Font(f.getName(), f.getStyle() | Font.BOLD, f.getSize()));
     24            Font f = getFont();
     25            setFont(new Font(f.getName(), f.getStyle() | Font.BOLD, f.getSize()));
    2626
    27                         setText((String)value);
     27            setText((String)value);
    2828
    29                         return this;
    30                 }
    31         }
     29            return this;
     30        }
     31    }
    3232
    33         private static BoldRenderer boldRenderer = null;
     33    private static BoldRenderer boldRenderer = null;
    3434
    35         protected CorrectionTable(TM correctionTableModel) {
    36                 super(correctionTableModel);
     35    protected CorrectionTable(TM correctionTableModel) {
     36        super(correctionTableModel);
    3737
    38                 final int correctionsSize = correctionTableModel.getCorrections().size();
    39                 final int lines = correctionsSize > MAX_VISIBLE_LINES ? MAX_VISIBLE_LINES
     38        final int correctionsSize = correctionTableModel.getCorrections().size();
     39        final int lines = correctionsSize > MAX_VISIBLE_LINES ? MAX_VISIBLE_LINES
    4040                : correctionsSize;
    41                 setPreferredScrollableViewportSize(new Dimension(400, lines
    42                         * getRowHeight()));
    43                 getColumnModel().getColumn(correctionTableModel.getApplyColumn())
     41        setPreferredScrollableViewportSize(new Dimension(400, lines
     42                * getRowHeight()));
     43        getColumnModel().getColumn(correctionTableModel.getApplyColumn())
    4444                .setPreferredWidth(40);
    45                 setRowSelectionAllowed(false);
    46         }
     45        setRowSelectionAllowed(false);
     46    }
    4747
    48         public TableCellRenderer getCellRenderer(int row, int column) {
    49                 if (getCorrectionTableModel().isBoldCell(row, column)) {
    50                         if (boldRenderer == null)
    51                                 boldRenderer = new BoldRenderer();
    52                         return boldRenderer;
    53                 }
    54                 return super.getCellRenderer(row, column);
    55         }
     48    public TableCellRenderer getCellRenderer(int row, int column) {
     49        if (getCorrectionTableModel().isBoldCell(row, column)) {
     50            if (boldRenderer == null)
     51                boldRenderer = new BoldRenderer();
     52            return boldRenderer;
     53        }
     54        return super.getCellRenderer(row, column);
     55    }
    5656
    57         @SuppressWarnings("unchecked")
     57    @SuppressWarnings("unchecked")
    5858    public TM getCorrectionTableModel() {
    59                 return (TM)getModel();
    60         }
     59        return (TM)getModel();
     60    }
    6161
    6262}
  • trunk/src/org/openstreetmap/josm/corrector/CorrectionTableModel.java

    r1001 r1169  
    1212        AbstractTableModel {
    1313
    14         private List<C> corrections;
    15         private boolean[] apply;
    16         private int applyColumn;
     14    private List<C> corrections;
     15    private boolean[] apply;
     16    private int applyColumn;
    1717
    18         public CorrectionTableModel(List<C> corrections) {
    19                 super();
    20                 this.corrections = corrections;
    21                 apply = new boolean[this.corrections.size()];
    22                 Arrays.fill(apply, true);
    23                 applyColumn = getColumnCount() - 1;
    24         }
    25 
    26         abstract public int getColumnCount();
    27 
    28         abstract protected boolean isBoldCell(int row, int column);
    29         abstract public String getCorrectionColumnName(int colIndex);
    30         abstract public Object getCorrectionValueAt(int rowIndex, int colIndex);
    31 
    32         public List<C> getCorrections() {
    33                 return corrections;
    34         }
    35        
    36         public int getApplyColumn() {
    37                 return applyColumn;
    38         }
    39        
    40     public boolean getApply(int i) {
    41         return apply[i];
     18    public CorrectionTableModel(List<C> corrections) {
     19        super();
     20        this.corrections = corrections;
     21        apply = new boolean[this.corrections.size()];
     22        Arrays.fill(apply, true);
     23        applyColumn = getColumnCount() - 1;
    4224    }
    4325
    44         public int getRowCount() {
    45         return corrections.size();
     26    abstract public int getColumnCount();
     27
     28    abstract protected boolean isBoldCell(int row, int column);
     29    abstract public String getCorrectionColumnName(int colIndex);
     30    abstract public Object getCorrectionValueAt(int rowIndex, int colIndex);
     31
     32    public List<C> getCorrections() {
     33        return corrections;
    4634    }
    4735
    48         @Override
    49     public Class<?> getColumnClass(int columnIndex) {
    50         if (columnIndex == applyColumn)
    51                 return Boolean.class;
    52         return String.class;
     36    public int getApplyColumn() {
     37        return applyColumn;
    5338    }
    5439
    55         @Override
    56         public String getColumnName(int columnIndex) {
    57         if (columnIndex == applyColumn)
    58                 return tr("Apply?");
    59                
    60                 return getCorrectionColumnName(columnIndex);
    61         }
    62 
    63         @Override
    64     public boolean isCellEditable(int rowIndex, int columnIndex) {
    65         return columnIndex == applyColumn;
     40    public boolean getApply(int i) {
     41        return apply[i];
    6642    }
    6743
    68         @Override
     44    public int getRowCount() {
     45        return corrections.size();
     46    }
     47
     48    @Override
     49    public Class<?> getColumnClass(int columnIndex) {
     50        if (columnIndex == applyColumn)
     51            return Boolean.class;
     52        return String.class;
     53    }
     54
     55    @Override
     56    public String getColumnName(int columnIndex) {
     57        if (columnIndex == applyColumn)
     58            return tr("Apply?");
     59
     60        return getCorrectionColumnName(columnIndex);
     61    }
     62
     63    @Override
     64    public boolean isCellEditable(int rowIndex, int columnIndex) {
     65        return columnIndex == applyColumn;
     66    }
     67
     68    @Override
    6969    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
    70         if (columnIndex == applyColumn && aValue instanceof Boolean)
    71                 apply[rowIndex] = (Boolean)aValue;
     70        if (columnIndex == applyColumn && aValue instanceof Boolean)
     71            apply[rowIndex] = (Boolean)aValue;
    7272    }
    7373
    7474    public Object getValueAt(int rowIndex, int colIndex) {
    75         if (colIndex == applyColumn)
    76                 return apply[rowIndex];
    77        
    78         return getCorrectionValueAt(rowIndex, colIndex);
    79         }
     75        if (colIndex == applyColumn)
     76            return apply[rowIndex];
     77
     78        return getCorrectionValueAt(rowIndex, colIndex);
     79    }
    8080}
  • trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java

    r1002 r1169  
    2222public class ReverseWayTagCorrector extends TagCorrector<Way> {
    2323
    24         private static class PrefixSuffixSwitcher {
     24    private static class PrefixSuffixSwitcher {
    2525
    26                 private final String a;
    27                 private final String b;
    28                 private final Pattern startPattern;
    29                 private final Pattern endPattern;
     26        private final String a;
     27        private final String b;
     28        private final Pattern startPattern;
     29        private final Pattern endPattern;
    3030
    31                 private final String SEPARATOR = "[:_]?";
    32                
    33                 public PrefixSuffixSwitcher(String a, String b) {
     31        private final String SEPARATOR = "[:_]?";
     32
     33        public PrefixSuffixSwitcher(String a, String b) {
    3434            this.a = a;
    3535            this.b = b;
     
    4040                    SEPARATOR + "(" + a + "|" + b + ")$",
    4141                    Pattern.CASE_INSENSITIVE);
    42                 }
     42        }
    4343
    44                 public String apply(String text) {
    45                         Matcher m = startPattern.matcher(text);
    46                         if (!m.lookingAt())
    47                                 m = endPattern.matcher(text);
     44        public String apply(String text) {
     45            Matcher m = startPattern.matcher(text);
     46            if (!m.lookingAt())
     47                m = endPattern.matcher(text);
    4848
    49                         if (m.lookingAt()) {
    50                                 String leftRight = m.group(1).toLowerCase();
     49            if (m.lookingAt()) {
     50                String leftRight = m.group(1).toLowerCase();
    5151
    52                                 StringBuilder result = new StringBuilder();
    53                                 result.append(text.substring(0, m.start(1)));
    54                                 result.append(leftRight.equals(a) ? b : a);
    55                                 result.append(text.substring(m.end(1)));
    56                                
    57                                 return result.toString();
    58                         }
    59                         return text;
    60                 }
    61         }
     52                StringBuilder result = new StringBuilder();
     53                result.append(text.substring(0, m.start(1)));
     54                result.append(leftRight.equals(a) ? b : a);
     55                result.append(text.substring(m.end(1)));
    6256
    63         private static PrefixSuffixSwitcher[] prefixSuffixSwitchers =
    64                 new PrefixSuffixSwitcher[] {
    65                     new PrefixSuffixSwitcher("left", "right"),
    66                     new PrefixSuffixSwitcher("forward", "backward")
    67                 };
     57                return result.toString();
     58            }
     59            return text;
     60        }
     61    }
    6862
    69         @Override
    70         public Collection<Command> execute(Way way) throws UserCancelException {
    71                 Map<OsmPrimitive, List<TagCorrection>> tagCorrectionsMap =
    72                         new HashMap<OsmPrimitive, List<TagCorrection>>();
     63    private static PrefixSuffixSwitcher[] prefixSuffixSwitchers =
     64            new PrefixSuffixSwitcher[] {
     65                new PrefixSuffixSwitcher("left", "right"),
     66                new PrefixSuffixSwitcher("forward", "backward")
     67            };
    7368
    74                 ArrayList<OsmPrimitive> primitives = new ArrayList<OsmPrimitive>();
    75                 primitives.add(way);
    76                 primitives.addAll(way.nodes);
     69    @Override
     70    public Collection<Command> execute(Way way) throws UserCancelException {
     71        Map<OsmPrimitive, List<TagCorrection>> tagCorrectionsMap =
     72                new HashMap<OsmPrimitive, List<TagCorrection>>();
    7773
    78                 for (OsmPrimitive primitive : primitives) {
    79                         tagCorrectionsMap.put(primitive, new ArrayList<TagCorrection>());
     74        ArrayList<OsmPrimitive> primitives = new ArrayList<OsmPrimitive>();
     75        primitives.add(way);
     76        primitives.addAll(way.nodes);
    8077
    81                         for (String key : primitive.keySet()) {
    82                                 String newKey = key;
    83                                 String value = primitive.get(key);
    84                                 String newValue = value;
     78        for (OsmPrimitive primitive : primitives) {
     79            tagCorrectionsMap.put(primitive, new ArrayList<TagCorrection>());
    8580
    86                                 if (key.equals("oneway")) {
    87                                         if (value.equals("-1"))
    88                                                 newValue = OsmUtils.trueval;
    89                                         else {
    90                                                 Boolean boolValue = OsmUtils.getOsmBoolean(value);
    91                                                 if (boolValue != null && boolValue.booleanValue()) {
    92                                                         newValue = "-1";
    93                                                 }
    94                                         }
    95                                 } else {
    96                                         for (PrefixSuffixSwitcher prefixSuffixSwitcher : prefixSuffixSwitchers) {
    97                                                 newKey = prefixSuffixSwitcher.apply(key);
    98                                                 if (!key.equals(newKey))
    99                                                         break;
    100                                         }
    101                                 }
     81            for (String key : primitive.keySet()) {
     82                String newKey = key;
     83                String value = primitive.get(key);
     84                String newValue = value;
    10285
    103                                 if (!key.equals(newKey) || !value.equals(newValue))
    104                                         tagCorrectionsMap.get(primitive).add(
    105                                                 new TagCorrection(key, value, newKey, newValue));
    106                         }
    107                 }
     86                if (key.equals("oneway")) {
     87                    if (value.equals("-1"))
     88                        newValue = OsmUtils.trueval;
     89                    else {
     90                        Boolean boolValue = OsmUtils.getOsmBoolean(value);
     91                        if (boolValue != null && boolValue.booleanValue()) {
     92                            newValue = "-1";
     93                        }
     94                    }
     95                } else {
     96                    for (PrefixSuffixSwitcher prefixSuffixSwitcher : prefixSuffixSwitchers) {
     97                        newKey = prefixSuffixSwitcher.apply(key);
     98                        if (!key.equals(newKey))
     99                            break;
     100                    }
     101                }
    108102
    109                 Map<OsmPrimitive, List<RoleCorrection>> roleCorrectionMap =
    110                         new HashMap<OsmPrimitive, List<RoleCorrection>>();
    111                 roleCorrectionMap.put(way, new ArrayList<RoleCorrection>());
     103                if (!key.equals(newKey) || !value.equals(newValue))
     104                    tagCorrectionsMap.get(primitive).add(
     105                            new TagCorrection(key, value, newKey, newValue));
     106            }
     107        }
    112108
    113                 for (Relation relation : Main.ds.relations) {
    114                         for (RelationMember member : relation.members) {
    115                                 if (!member.member.realEqual(way, true)
    116                                         || member.role.length() == 0)
    117                                         continue;
     109        Map<OsmPrimitive, List<RoleCorrection>> roleCorrectionMap =
     110                new HashMap<OsmPrimitive, List<RoleCorrection>>();
     111        roleCorrectionMap.put(way, new ArrayList<RoleCorrection>());
    118112
    119                                 boolean found = false;
    120                                 String newRole = null;
    121                                 for (PrefixSuffixSwitcher prefixSuffixSwitcher : prefixSuffixSwitchers) {
    122                                         newRole = prefixSuffixSwitcher.apply(member.role);
    123                                         if (!newRole.equals(member.role)) {
    124                                                 found = true;
    125                                                 break;
    126                                         }
    127                                 }
     113        for (Relation relation : Main.ds.relations) {
     114            for (RelationMember member : relation.members) {
     115                if (!member.member.realEqual(way, true)
     116                        || member.role.length() == 0)
     117                    continue;
    128118
    129                                 if (found)
    130                                         roleCorrectionMap.get(way).add(
    131                                                 new RoleCorrection(relation, member, newRole));
    132                         }
    133                 }
     119                boolean found = false;
     120                String newRole = null;
     121                for (PrefixSuffixSwitcher prefixSuffixSwitcher : prefixSuffixSwitchers) {
     122                    newRole = prefixSuffixSwitcher.apply(member.role);
     123                    if (!newRole.equals(member.role)) {
     124                        found = true;
     125                        break;
     126                    }
     127                }
    134128
    135                 return applyCorrections(tagCorrectionsMap, roleCorrectionMap,
    136                         tr("When reverting this way, following changes to properties "
    137                                 + "of the way and its nodes are suggested in order "
    138                                 + "to maintain data consistency."));
    139         }
     129                if (found)
     130                    roleCorrectionMap.get(way).add(
     131                            new RoleCorrection(relation, member, newRole));
     132            }
     133        }
     134
     135        return applyCorrections(tagCorrectionsMap, roleCorrectionMap,
     136                tr("When reverting this way, following changes to properties "
     137                        + "of the way and its nodes are suggested in order "
     138                        + "to maintain data consistency."));
     139    }
    140140}
  • trunk/src/org/openstreetmap/josm/corrector/TagCorrection.java

    r1000 r1169  
    44public class TagCorrection implements Correction {
    55
    6         public final String oldKey;
    7         public final String newKey;
    8         public final String oldValue;
    9         public final String newValue;
     6    public final String oldKey;
     7    public final String newKey;
     8    public final String oldValue;
     9    public final String newValue;
    1010
    11         public TagCorrection(String oldKey, String oldValue, String newKey,
     11    public TagCorrection(String oldKey, String oldValue, String newKey,
    1212            String newValue) {
    13                 this.oldKey = oldKey;
    14                 this.oldValue = oldValue;
    15                 this.newKey = newKey;
    16                 this.newValue = newValue;
    17         }
     13        this.oldKey = oldKey;
     14        this.oldValue = oldValue;
     15        this.newKey = newKey;
     16        this.newValue = newValue;
     17    }
    1818
    19         public boolean isKeyChanged() {
    20                 return !newKey.equals(oldKey);
    21         }
     19    public boolean isKeyChanged() {
     20        return !newKey.equals(oldKey);
     21    }
    2222
    23         public boolean isValueChanged() {
    24                 return !newValue.equals(oldValue);
    25         }
     23    public boolean isValueChanged() {
     24        return !newValue.equals(oldValue);
     25    }
    2626}
  • trunk/src/org/openstreetmap/josm/corrector/TagCorrectionTable.java

    r1000 r1169  
    77        CorrectionTable<TagCorrectionTableModel> {
    88
    9         public TagCorrectionTable(List<TagCorrection> tagCorrections) {
    10                 super(new TagCorrectionTableModel(tagCorrections));
    11         }
     9    public TagCorrectionTable(List<TagCorrection> tagCorrections) {
     10        super(new TagCorrectionTableModel(tagCorrections));
     11    }
    1212
    1313}
  • trunk/src/org/openstreetmap/josm/corrector/TagCorrectionTableModel.java

    r1000 r1169  
    88public class TagCorrectionTableModel extends CorrectionTableModel<TagCorrection> {
    99
    10         public TagCorrectionTableModel(List<TagCorrection> tagCorrections) {
    11                 super(tagCorrections);
    12         }
     10    public TagCorrectionTableModel(List<TagCorrection> tagCorrections) {
     11        super(tagCorrections);
     12    }
    1313
    14         @Override
    15         public int getColumnCount() {
    16                 return 5;
    17         }
     14    @Override
     15    public int getColumnCount() {
     16        return 5;
     17    }
    1818
    19         @Override
    20         public String getCorrectionColumnName(int colIndex) {
    21                 switch (colIndex) {
    22                 case 0:
    23                         return tr("Old key");
    24                 case 1:
    25                         return tr("Old value");
    26                 case 2:
    27                         return tr("New key");
    28                 case 3:
    29                         return tr("New value");
    30                 }
    31                 return null;
    32         }
     19    @Override
     20    public String getCorrectionColumnName(int colIndex) {
     21        switch (colIndex) {
     22        case 0:
     23            return tr("Old key");
     24        case 1:
     25            return tr("Old value");
     26        case 2:
     27            return tr("New key");
     28        case 3:
     29            return tr("New value");
     30        }
     31        return null;
     32    }
    3333
    3434    public Object getCorrectionValueAt(int rowIndex, int colIndex) {
    35                 TagCorrection tagCorrection = getCorrections().get(rowIndex);
     35        TagCorrection tagCorrection = getCorrections().get(rowIndex);
    3636
    37                 switch (colIndex) {
    38                 case 0:
    39                         return tagCorrection.oldKey;
    40                 case 1:
    41                         return tagCorrection.oldValue;
    42                 case 2:
    43                         return tagCorrection.newKey;
    44                 case 3:
    45                         return tagCorrection.newValue;
    46                 }
    47                 return null;
    48         }
     37        switch (colIndex) {
     38        case 0:
     39            return tagCorrection.oldKey;
     40        case 1:
     41            return tagCorrection.oldValue;
     42        case 2:
     43            return tagCorrection.newKey;
     44        case 3:
     45            return tagCorrection.newValue;
     46        }
     47        return null;
     48    }
    4949
    50         protected boolean isBoldCell(int row, int column) {
    51                 TagCorrection tagCorrection = getCorrections().get(row);
    52                 return (column == 2 && tagCorrection.isKeyChanged())
    53                         || (column == 3 && tagCorrection.isValueChanged());
    54         }
     50    protected boolean isBoldCell(int row, int column) {
     51        TagCorrection tagCorrection = getCorrections().get(row);
     52        return (column == 2 && tagCorrection.isKeyChanged())
     53                || (column == 3 && tagCorrection.isValueChanged());
     54    }
    5555
    5656}
  • trunk/src/org/openstreetmap/josm/corrector/TagCorrector.java

    r1107 r1169  
    3333public abstract class TagCorrector<P extends OsmPrimitive> {
    3434
    35         public abstract Collection<Command> execute(P primitive) 
    36             throws UserCancelException;
     35    public abstract Collection<Command> execute(P primitive)
     36        throws UserCancelException;
    3737
    38     private String[] applicationOptions = new String[] { 
    39         tr("Apply selected changes"), 
    40         tr("Don't apply changes"), 
    41         tr("Cancel") 
     38    private String[] applicationOptions = new String[] {
     39        tr("Apply selected changes"),
     40        tr("Don't apply changes"),
     41        tr("Cancel")
    4242    };
    43    
    44         protected Collection<Command> applyCorrections(
    45                 Map<OsmPrimitive, List<TagCorrection>> tagCorrectionsMap,
    46                 Map<OsmPrimitive, List<RoleCorrection>> roleCorrectionMap,
    47                 String description) throws UserCancelException {
    4843
    49                 boolean hasCorrections = false;
    50                 for (List<TagCorrection> tagCorrectionList : tagCorrectionsMap.values()) {
    51                         if (!tagCorrectionList.isEmpty()) {
    52                                 hasCorrections = true;
    53                                 break;
    54                         }
    55                 }
     44    protected Collection<Command> applyCorrections(
     45            Map<OsmPrimitive, List<TagCorrection>> tagCorrectionsMap,
     46            Map<OsmPrimitive, List<RoleCorrection>> roleCorrectionMap,
     47            String description) throws UserCancelException {
    5648
    57                 if (!hasCorrections)
    58                         for (List<RoleCorrection> roleCorrectionList : roleCorrectionMap
    59                                 .values()) {
    60                                 if (!roleCorrectionList.isEmpty()) {
    61                                         hasCorrections = true;
    62                                         break;
    63                                 }
    64                         }
     49        boolean hasCorrections = false;
     50        for (List<TagCorrection> tagCorrectionList : tagCorrectionsMap.values()) {
     51            if (!tagCorrectionList.isEmpty()) {
     52                hasCorrections = true;
     53                break;
     54            }
     55        }
    6556
    66                 if (hasCorrections) {
    67                         Collection<Command> commands = new ArrayList<Command>();
    68                         Map<OsmPrimitive, TagCorrectionTable> tagTableMap =
    69                             new HashMap<OsmPrimitive, TagCorrectionTable>();
    70                         Map<OsmPrimitive, RoleCorrectionTable> roleTableMap =
    71                             new HashMap<OsmPrimitive, RoleCorrectionTable>();
     57        if (!hasCorrections)
     58            for (List<RoleCorrection> roleCorrectionList : roleCorrectionMap
     59                    .values()) {
     60                if (!roleCorrectionList.isEmpty()) {
     61                    hasCorrections = true;
     62                    break;
     63                }
     64            }
    7265
    73                         NameVisitor nameVisitor = new NameVisitor();
     66        if (hasCorrections) {
     67            Collection<Command> commands = new ArrayList<Command>();
     68            Map<OsmPrimitive, TagCorrectionTable> tagTableMap =
     69                new HashMap<OsmPrimitive, TagCorrectionTable>();
     70            Map<OsmPrimitive, RoleCorrectionTable> roleTableMap =
     71                new HashMap<OsmPrimitive, RoleCorrectionTable>();
    7472
    75                         final JPanel p = new JPanel(new GridBagLayout());
     73            NameVisitor nameVisitor = new NameVisitor();
    7674
    77                         final JMultilineLabel label1 = new JMultilineLabel(description);
    78                         label1.setMaxWidth(400);
    79                         p.add(label1, GBC.eop());
     75            final JPanel p = new JPanel(new GridBagLayout());
    8076
    81                         final JMultilineLabel label2 = new JMultilineLabel(
    82                                 tr("Please select which property changes you want to apply."));
    83                         label2.setMaxWidth(400);
    84                         p.add(label2, GBC.eop());
     77            final JMultilineLabel label1 = new JMultilineLabel(description);
     78            label1.setMaxWidth(400);
     79            p.add(label1, GBC.eop());
    8580
    86                         for (OsmPrimitive primitive : tagCorrectionsMap.keySet()) {
    87                                 final List<TagCorrection> tagCorrections = tagCorrectionsMap
    88                                         .get(primitive);
     81            final JMultilineLabel label2 = new JMultilineLabel(
     82                    tr("Please select which property changes you want to apply."));
     83            label2.setMaxWidth(400);
     84            p.add(label2, GBC.eop());
    8985
    90                                 if (tagCorrections.isEmpty())
    91                                         continue;
     86            for (OsmPrimitive primitive : tagCorrectionsMap.keySet()) {
     87                final List<TagCorrection> tagCorrections = tagCorrectionsMap
     88                        .get(primitive);
    9289
    93                                 primitive.visit(nameVisitor);
     90                if (tagCorrections.isEmpty())
     91                    continue;
    9492
    95                                 final JLabel propertiesLabel = new JLabel(tr("Properties of "));
    96                                 p.add(propertiesLabel, GBC.std());
     93                primitive.visit(nameVisitor);
    9794
    98                                 final JLabel primitiveLabel = new JLabel(
    99                                         nameVisitor.name + ":", nameVisitor.icon, JLabel.LEFT);
    100                                 p.add(primitiveLabel, GBC.eol());
     95                final JLabel propertiesLabel = new JLabel(tr("Properties of "));
     96                p.add(propertiesLabel, GBC.std());
    10197
    102                                 final TagCorrectionTable table = new TagCorrectionTable(
    103                                         tagCorrections);
    104                                 final JScrollPane scrollPane = new JScrollPane(table);
    105                                 p.add(scrollPane, GBC.eop());
     98                final JLabel primitiveLabel = new JLabel(
     99                        nameVisitor.name + ":", nameVisitor.icon, JLabel.LEFT);
     100                p.add(primitiveLabel, GBC.eol());
    106101
    107                                 tagTableMap.put(primitive, table);
    108                         }
     102                final TagCorrectionTable table = new TagCorrectionTable(
     103                        tagCorrections);
     104                final JScrollPane scrollPane = new JScrollPane(table);
     105                p.add(scrollPane, GBC.eop());
    109106
    110                         for (OsmPrimitive primitive : roleCorrectionMap.keySet()) {
    111                                 final List<RoleCorrection> roleCorrections = roleCorrectionMap
    112                                         .get(primitive);
    113                                 if (roleCorrections.isEmpty())
    114                                         continue;
     107                tagTableMap.put(primitive, table);
     108            }
    115109
    116                                 primitive.visit(nameVisitor);
     110            for (OsmPrimitive primitive : roleCorrectionMap.keySet()) {
     111                final List<RoleCorrection> roleCorrections = roleCorrectionMap
     112                        .get(primitive);
     113                if (roleCorrections.isEmpty())
     114                    continue;
    117115
    118                                 final JLabel rolesLabel = new JLabel(
    119                                         tr("Roles in relations referring to"));
    120                                 p.add(rolesLabel, GBC.std());
     116                primitive.visit(nameVisitor);
    121117
    122                                 final JLabel primitiveLabel = new JLabel(
    123                                         nameVisitor.name + ":", nameVisitor.icon, JLabel.LEFT);
    124                                 p.add(primitiveLabel, GBC.eol());
     118                final JLabel rolesLabel = new JLabel(
     119                        tr("Roles in relations referring to"));
     120                p.add(rolesLabel, GBC.std());
    125121
    126                                 final RoleCorrectionTable table = new RoleCorrectionTable(
    127                                         roleCorrections);
    128                                 final JScrollPane scrollPane = new JScrollPane(table);
    129                                 p.add(scrollPane, GBC.eop());
     122                final JLabel primitiveLabel = new JLabel(
     123                        nameVisitor.name + ":", nameVisitor.icon, JLabel.LEFT);
     124                p.add(primitiveLabel, GBC.eol());
    130125
    131                                 roleTableMap.put(primitive, table);
    132                         }
     126                final RoleCorrectionTable table = new RoleCorrectionTable(
     127                        roleCorrections);
     128                final JScrollPane scrollPane = new JScrollPane(table);
     129                p.add(scrollPane, GBC.eop());
    133130
    134                         int answer = JOptionPane.showOptionDialog(Main.parent, p,
     131                roleTableMap.put(primitive, table);
     132            }
     133
     134            int answer = JOptionPane.showOptionDialog(Main.parent, p,
    135135                    tr("Automatic tag correction"), JOptionPane.YES_NO_CANCEL_OPTION,
    136                     JOptionPane.PLAIN_MESSAGE, null, 
     136                    JOptionPane.PLAIN_MESSAGE, null,
    137137                    applicationOptions, applicationOptions[0]);
    138138
    139                         if (answer == JOptionPane.YES_OPTION) {
    140                                 for (OsmPrimitive primitive : tagCorrectionsMap.keySet()) {
    141                                         List<TagCorrection> tagCorrections = 
     139            if (answer == JOptionPane.YES_OPTION) {
     140                for (OsmPrimitive primitive : tagCorrectionsMap.keySet()) {
     141                    List<TagCorrection> tagCorrections =
    142142                        tagCorrectionsMap.get(primitive);
    143                    
     143
    144144                    // create the clone
    145145                    OsmPrimitive clone = null;
     
    147147                    else if (primitive instanceof Node) clone = new Node((Node)primitive);
    148148                    else if (primitive instanceof Relation) clone = new Relation((Relation)primitive);
    149                    
     149
    150150                    // use this structure to remember keys that have been set already so that
    151151                    // they're not dropped by a later step
    152152                    Set<String> keysChanged = new HashSet<String>();
    153                    
     153
    154154                    // apply all changes to this clone
    155                                         for (int i = 0; i < tagCorrections.size(); i++) {
    156                                                 if (tagTableMap.get(primitive).getCorrectionTableModel().getApply(i)) {
    157                                                         TagCorrection tagCorrection = tagCorrections.get(i);
    158                                                         if (tagCorrection.isKeyChanged() && !keysChanged.contains(tagCorrection.oldKey)) clone.remove(tagCorrection.oldKey);
    159                                                         clone.put(tagCorrection.newKey, tagCorrection.newValue);
    160                                                         keysChanged.add(tagCorrection.newKey);
    161                                                 }
    162                                         }
    163                    
     155                    for (int i = 0; i < tagCorrections.size(); i++) {
     156                        if (tagTableMap.get(primitive).getCorrectionTableModel().getApply(i)) {
     157                            TagCorrection tagCorrection = tagCorrections.get(i);
     158                            if (tagCorrection.isKeyChanged() && !keysChanged.contains(tagCorrection.oldKey)) clone.remove(tagCorrection.oldKey);
     159                            clone.put(tagCorrection.newKey, tagCorrection.newValue);
     160                            keysChanged.add(tagCorrection.newKey);
     161                        }
     162                    }
     163
    164164                    // save the clone
    165165                    if (!keysChanged.isEmpty()) commands.add(new ChangeCommand(primitive, clone));
    166                                 }
    167                                 for (OsmPrimitive primitive : roleCorrectionMap.keySet()) {
    168                                         List<RoleCorrection> roleCorrections = roleCorrectionMap
    169                                                 .get(primitive);
    170                                         for (int i = 0; i < roleCorrections.size(); i++) {
    171                                                 if (roleTableMap.get(primitive)
    172                                                         .getCorrectionTableModel().getApply(i)) {
    173                                                         RoleCorrection roleCorrection = roleCorrections
    174                                                                 .get(i);
    175                                                         Relation newRelation = new Relation(
    176                                                                 roleCorrection.relation);
    177                                                         for (RelationMember member : newRelation.members)
    178                                                                 if (member.equals(roleCorrection.member))
    179                                                                         member.role = roleCorrection.newRole;
    180                                                         commands.add(new ChangeCommand(
    181                                                                 roleCorrection.relation, newRelation));
    182                                                 }
    183                                         }
    184                                 }
    185                         } else if (answer != JOptionPane.NO_OPTION) {
    186                             throw new UserCancelException();
    187                         }
    188                         return commands;
    189                 }
     166                }
     167                for (OsmPrimitive primitive : roleCorrectionMap.keySet()) {
     168                    List<RoleCorrection> roleCorrections = roleCorrectionMap
     169                            .get(primitive);
     170                    for (int i = 0; i < roleCorrections.size(); i++) {
     171                        if (roleTableMap.get(primitive)
     172                                .getCorrectionTableModel().getApply(i)) {
     173                            RoleCorrection roleCorrection = roleCorrections
     174                                    .get(i);
     175                            Relation newRelation = new Relation(
     176                                    roleCorrection.relation);
     177                            for (RelationMember member : newRelation.members)
     178                                if (member.equals(roleCorrection.member))
     179                                    member.role = roleCorrection.newRole;
     180                            commands.add(new ChangeCommand(
     181                                    roleCorrection.relation, newRelation));
     182                        }
     183                    }
     184                }
     185            } else if (answer != JOptionPane.NO_OPTION) {
     186                throw new UserCancelException();
     187            }
     188            return commands;
     189        }
    190190
    191                 return Collections.emptyList();
    192         }
     191        return Collections.emptyList();
     192    }
    193193}
  • trunk/src/org/openstreetmap/josm/data/Bounds.java

    r999 r1169  
    88
    99/**
    10  * This is a simple data class for "rectangular" areas of the world, given in 
     10 * This is a simple data class for "rectangular" areas of the world, given in
    1111 * lat/lon min/max values.
    12  * 
     12 *
    1313 * @author imi
    1414 */
    1515public class Bounds {
    16         /**
    17         * The minimum and maximum coordinates.
    18         */
    19         public LatLon min, max;
     16    /**
     17    * The minimum and maximum coordinates.
     18    */
     19    public LatLon min, max;
    2020
    21         /**
    22         * Construct bounds out of two points
    23         */
    24         public Bounds(LatLon min, LatLon max) {
    25                 this.min = min;
    26                 this.max = max;
    27         }
     21    /**
     22    * Construct bounds out of two points
     23    */
     24    public Bounds(LatLon min, LatLon max) {
     25        this.min = min;
     26        this.max = max;
     27    }
    2828
    29         /**
    30          * Construct bounds that span the whole world.
    31          */
    32         public Bounds() {
    33                 min = new LatLon(-Projection.MAX_LAT, -Projection.MAX_LON);
    34                 max = new LatLon(Projection.MAX_LAT, Projection.MAX_LON);
    35         }
    36        
    37         @Override public String toString() {
    38                 return "Bounds["+min.lat()+","+min.lon()+","+max.lat()+","+max.lon()+"]";
    39         }
     29    /**
     30     * Construct bounds that span the whole world.
     31     */
     32    public Bounds() {
     33        min = new LatLon(-Projection.MAX_LAT, -Projection.MAX_LON);
     34        max = new LatLon(Projection.MAX_LAT, Projection.MAX_LON);
     35    }
    4036
    41         /**
    42          * @return Center of the bounding box.
    43          */
    44         public LatLon center() {
    45                 // FIXME: not sure whether this calculation is right; maybe there is some
    46                 // more complex calculation needed to get a center of a spherical
    47                 // dimension?
    48                 return new LatLon((min.lat()+max.lat())/2, (min.lon()+max.lon())/2);
    49         }
    50        
    51         /**
    52          * Extend the bounds if necessary to include the given point.
    53          */
    54         public void extend(LatLon ll) {
    55                 if (ll.lat() < min.lat() || ll.lon() < min.lon())
    56                         min = new LatLon(Math.min(ll.lat(), min.lat()), Math.min(ll.lon(), min.lon()));
    57                 if (ll.lat() > max.lat() || ll.lon() > max.lon())
    58                         max = new LatLon(Math.max(ll.lat(), max.lat()), Math.max(ll.lon(), max.lon()));
    59         }
    60         /**
    61          * Is the given point within this bounds?
    62          */
    63         public boolean contains(LatLon ll) {
    64                 if (ll.lat() < min.lat() || ll.lon() < min.lon())
    65                         return false;
    66                 if (ll.lat() > max.lat() || ll.lon() > max.lon())
    67                         return false;
    68                 return true;
    69         }
    70        
    71         /**
    72          * Converts the lat/lon bounding box to an object of type Rectangle2D.Double
    73          * @return the bounding box to Rectangle2D.Double
    74          */
    75         public Rectangle2D.Double asRect() {
    76                 return new Rectangle2D.Double(min.lon(), min.lat(), max.lon()-min.lon(), max.lat()-min.lat());
    77         }
     37    @Override public String toString() {
     38        return "Bounds["+min.lat()+","+min.lon()+","+max.lat()+","+max.lon()+"]";
     39    }
     40
     41    /**
     42     * @return Center of the bounding box.
     43     */
     44    public LatLon center() {
     45        // FIXME: not sure whether this calculation is right; maybe there is some
     46        // more complex calculation needed to get a center of a spherical
     47        // dimension?
     48        return new LatLon((min.lat()+max.lat())/2, (min.lon()+max.lon())/2);
     49    }
     50
     51    /**
     52     * Extend the bounds if necessary to include the given point.
     53     */
     54    public void extend(LatLon ll) {
     55        if (ll.lat() < min.lat() || ll.lon() < min.lon())
     56            min = new LatLon(Math.min(ll.lat(), min.lat()), Math.min(ll.lon(), min.lon()));
     57        if (ll.lat() > max.lat() || ll.lon() > max.lon())
     58            max = new LatLon(Math.max(ll.lat(), max.lat()), Math.max(ll.lon(), max.lon()));
     59    }
     60    /**
     61     * Is the given point within this bounds?
     62     */
     63    public boolean contains(LatLon ll) {
     64        if (ll.lat() < min.lat() || ll.lon() < min.lon())
     65            return false;
     66        if (ll.lat() > max.lat() || ll.lon() > max.lon())
     67            return false;
     68        return true;
     69    }
     70
     71    /**
     72     * Converts the lat/lon bounding box to an object of type Rectangle2D.Double
     73     * @return the bounding box to Rectangle2D.Double
     74     */
     75    public Rectangle2D.Double asRect() {
     76        return new Rectangle2D.Double(min.lon(), min.lat(), max.lon()-min.lon(), max.lat()-min.lat());
     77    }
    7878
    7979}
  • trunk/src/org/openstreetmap/josm/data/DataSetChecker.java

    r627 r1169  
    1414public class DataSetChecker {
    1515
    16         public static void check() {
    17                 if (Main.map == null)
    18                         return;
     16    public static void check() {
     17        if (Main.map == null)
     18            return;
    1919
    20                 Set<OsmPrimitive> s = new HashSet<OsmPrimitive>();
    21                 for (Layer l : Main.map.mapView.getAllLayers()) {
    22                         if (l instanceof OsmDataLayer) {
    23                                 for (OsmPrimitive osm : ((OsmDataLayer)l).data.allPrimitives()) {
    24                                         if (s.contains(osm)) {
    25                                 JOptionPane.showMessageDialog(Main.parent, "cross references");
    26                                 return;
    27                                         }
    28                                         s.add(osm);
    29                                 }
    30                         }
    31                 }
    32                
    33                 if (Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) {
    34                         OsmDataLayer l = (OsmDataLayer)Main.map.mapView.getActiveLayer();
    35                         if (l.data != Main.ds) {
    36                                 JOptionPane.showMessageDialog(Main.parent, "Main.ds / active layer mismatch");
    37                                 return;
    38                         }
    39                 }
     20        Set<OsmPrimitive> s = new HashSet<OsmPrimitive>();
     21        for (Layer l : Main.map.mapView.getAllLayers()) {
     22            if (l instanceof OsmDataLayer) {
     23                for (OsmPrimitive osm : ((OsmDataLayer)l).data.allPrimitives()) {
     24                    if (s.contains(osm)) {
     25                        JOptionPane.showMessageDialog(Main.parent, "cross references");
     26                        return;
     27                    }
     28                    s.add(osm);
     29                }
     30            }
     31        }
    4032
    41                 JOptionPane.showMessageDialog(Main.parent, "working");
    42         }
     33        if (Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) {
     34            OsmDataLayer l = (OsmDataLayer)Main.map.mapView.getActiveLayer();
     35            if (l.data != Main.ds) {
     36                JOptionPane.showMessageDialog(Main.parent, "Main.ds / active layer mismatch");
     37                return;
     38            }
     39        }
     40
     41        JOptionPane.showMessageDialog(Main.parent, "working");
     42    }
    4343}
  • trunk/src/org/openstreetmap/josm/data/Preferences.java

    r1159 r1169  
    3535 */
    3636public class Preferences {
    37    
    38     /**
    39     * Internal storage for the preferenced directory. 
     37
     38    /**
     39    * Internal storage for the preferenced directory.
    4040    * Do not access this variable directly!
    4141    * @see #getPreferencesDirFile()
    4242    */
    4343    private File preferencesDirFile = null;
    44      
    45         public static interface PreferenceChangedListener {
    46                 void preferenceChanged(String key, String newValue);
    47         }
    48 
    49         /**
    50         * Class holding one bookmarkentry.
    51         * @author imi
    52         */
    53         public static class Bookmark implements Comparable<Bookmark> {
    54                 public String name;
    55                 public double[] latlon = new double[4]; // minlat, minlon, maxlat, maxlon
    56                 @Override public String toString() {
    57                         return name;
    58                 }
    59                 public int compareTo(Bookmark b) {
    60                         return name.toLowerCase().compareTo(b.name.toLowerCase());
    61                 }
    62         }
    63 
    64         public final ArrayList<PreferenceChangedListener> listener = new ArrayList<PreferenceChangedListener>();
    65 
    66         /**
    67         * Map the property name to the property object.
    68         */
    69         protected final SortedMap<String, String> properties = new TreeMap<String, String>();
    70         protected final SortedMap<String, String> defaults = new TreeMap<String, String>();
    71 
    72         /**
    73         * Override some values on read. This is intended to be used for technology previews
    74         * where we want to temporarily modify things without changing the user's preferences
    75         * file.
    76         */
    77         protected static final SortedMap<String, String> override = new TreeMap<String, String>();
    78         static {
    79                 //override.put("osm-server.version", "0.5");
    80                 //override.put("osm-server.additional-versions", "");
    81                 //override.put("osm-server.url", "http://openstreetmap.gryph.de/api");
    82                 //override.put("plugins", null);
    83         }
    84 
    85         /**
    86         * Return the location of the user defined preferences file
    87         */
    88         public String getPreferencesDir() {
    89                 final String path = getPreferencesDirFile().getPath();
    90                 if (path.endsWith(File.separator))
    91                         return path;
    92                 return path + File.separator;
    93         }
     44
     45    public static interface PreferenceChangedListener {
     46        void preferenceChanged(String key, String newValue);
     47    }
     48
     49    /**
     50    * Class holding one bookmarkentry.
     51    * @author imi
     52    */
     53    public static class Bookmark implements Comparable<Bookmark> {
     54        public String name;
     55        public double[] latlon = new double[4]; // minlat, minlon, maxlat, maxlon
     56        @Override public String toString() {
     57            return name;
     58        }
     59        public int compareTo(Bookmark b) {
     60            return name.toLowerCase().compareTo(b.name.toLowerCase());
     61        }
     62    }
     63
     64    public final ArrayList<PreferenceChangedListener> listener = new ArrayList<PreferenceChangedListener>();
     65
     66    /**
     67    * Map the property name to the property object.
     68    */
     69    protected final SortedMap<String, String> properties = new TreeMap<String, String>();
     70    protected final SortedMap<String, String> defaults = new TreeMap<String, String>();
     71
     72    /**
     73    * Override some values on read. This is intended to be used for technology previews
     74    * where we want to temporarily modify things without changing the user's preferences
     75    * file.
     76    */
     77    protected static final SortedMap<String, String> override = new TreeMap<String, String>();
     78    static {
     79        //override.put("osm-server.version", "0.5");
     80        //override.put("osm-server.additional-versions", "");
     81        //override.put("osm-server.url", "http://openstreetmap.gryph.de/api");
     82        //override.put("plugins", null);
     83    }
     84
     85    /**
     86    * Return the location of the user defined preferences file
     87    */
     88    public String getPreferencesDir() {
     89        final String path = getPreferencesDirFile().getPath();
     90        if (path.endsWith(File.separator))
     91            return path;
     92        return path + File.separator;
     93    }
    9494
    9595    public File getPreferencesDirFile() {
     
    110110        return preferencesDirFile;
    111111    }
    112    
    113         public File getPluginsDirFile() {
    114                 return new File(getPreferencesDirFile(), "plugins");
    115         }
    116 
    117         /**
    118         * @return A list of all existing directories where resources could be stored.
    119         */
    120         public Collection<String> getAllPossiblePreferenceDirs() {
    121                 LinkedList<String> locations = new LinkedList<String>();
    122                 locations.add(Main.pref.getPreferencesDir());
    123                 String s;
    124                 if ((s = System.getenv("JOSM_RESOURCES")) != null) {
    125                         if (!s.endsWith(File.separator))
    126                                 s = s + File.separator;
    127                         locations.add(s);
    128                 }
    129                 if ((s = System.getProperty("josm.resources")) != null) {
    130                         if (!s.endsWith(File.separator))
    131                                 s = s + File.separator;
    132                         locations.add(s);
    133                 }
    134                 String appdata = System.getenv("APPDATA");
    135                 if (System.getenv("ALLUSERSPROFILE") != null && appdata != null
    136                         && appdata.lastIndexOf(File.separator) != -1) {
    137                         appdata = appdata.substring(appdata.lastIndexOf(File.separator));
    138                         locations.add(new File(new File(System.getenv("ALLUSERSPROFILE"),
    139                                 appdata), "JOSM").getPath());
    140                 }
    141                 locations.add("/usr/local/share/josm/");
    142                 locations.add("/usr/local/lib/josm/");
    143                 locations.add("/usr/share/josm/");
    144                 locations.add("/usr/lib/josm/");
    145                 return locations;
    146         }
    147 
    148         synchronized public boolean hasKey(final String key) {
    149                 return override.containsKey(key) ? override.get(key) != null : properties.containsKey(key);
    150         }
    151 
    152         synchronized public String get(final String key) {
    153                 putDefault(key, null);
    154                 if (override.containsKey(key))
    155                         return override.get(key);
    156                 if (!properties.containsKey(key))
    157                         return "";
    158                 return properties.get(key);
    159         }
    160 
    161         synchronized public String get(final String key, final String def) {
    162                 putDefault(key, def);
    163                 if (override.containsKey(key))
    164                         return override.get(key);
    165                 final String prop = properties.get(key);
    166                 if (prop == null || prop.equals(""))
    167                         return def;
    168                 return prop;
    169         }
    170 
    171         synchronized public Map<String, String> getAllPrefix(final String prefix) {
    172                 final Map<String,String> all = new TreeMap<String,String>();
    173                 for (final Entry<String,String> e : properties.entrySet())
    174                         if (e.getKey().startsWith(prefix))
    175                                 all.put(e.getKey(), e.getValue());
    176                 for (final Entry<String,String> e : override.entrySet())
    177                         if (e.getKey().startsWith(prefix))
    178                                 if (e.getValue() == null)
    179                                         all.remove(e.getKey());
    180                                 else
    181                                         all.put(e.getKey(), e.getValue());
    182                 return all;
    183         }
    184 
    185         synchronized public Map<String, String> getDefaults() {
    186                 return defaults;
    187         }
    188 
    189         synchronized public void putDefault(final String key, final String def) {
    190                 if(!defaults.containsKey(key) || defaults.get(key) == null)
    191                         defaults.put(key, def);
    192                 else if(def != null && !defaults.get(key).equals(def))
    193                         System.out.println("Defaults for " + key + " differ: " + def + " != " + defaults.get(key));
    194         }
    195 
    196         synchronized public boolean getBoolean(final String key) {
    197                 putDefault(key, null);
    198                 if (override.containsKey(key))
    199                         return override.get(key) == null ? false : Boolean.parseBoolean(override.get(key));
    200                 return properties.containsKey(key) ? Boolean.parseBoolean(properties.get(key)) : false;
    201         }
    202 
    203         synchronized public boolean getBoolean(final String key, final boolean def) {
    204                 putDefault(key, Boolean.toString(def));
    205                 if (override.containsKey(key))
    206                         return override.get(key) == null ? def : Boolean.parseBoolean(override.get(key));
    207                 return properties.containsKey(key) ? Boolean.parseBoolean(properties.get(key)) : def;
    208         }
    209 
    210         synchronized public void put(final String key, String value) {
    211                 String oldvalue = properties.get(key);
    212                 if(value != null && value.length() == 0)
    213                         value = null;
    214                 if(!((oldvalue == null && value == null) || (value != null
    215                 && oldvalue != null && oldvalue.equals(value))))
    216                 {
    217                         if (value == null)
    218                                 properties.remove(key);
    219                         else
    220                                 properties.put(key, value);
    221                         save();
    222                         firePreferenceChanged(key, value);
    223                 }
    224         }
    225 
    226         synchronized public void put(final String key, final boolean value) {
    227                 put(key, Boolean.toString(value));
    228         }
    229 
    230         private final void firePreferenceChanged(final String key, final String value) {
    231                 for (final PreferenceChangedListener l : listener)
    232                         l.preferenceChanged(key, value);
    233         }
    234 
    235         /**
    236         * Called after every put. In case of a problem, do nothing but output the error
    237         * in log.
    238         */
    239         public void save() {
    240                 try {
    241                         setSystemProperties();
    242                         final PrintWriter out = new PrintWriter(new FileWriter(getPreferencesDir() + "preferences"), false);
    243                         for (final Entry<String, String> e : properties.entrySet()) {
    244                                 out.println(e.getKey() + "=" + e.getValue());
    245                         }
    246                         out.close();
    247                 } catch (final IOException e) {
    248                         e.printStackTrace();
    249                         // do not message anything, since this can be called from strange
    250                         // places.
    251                 }
    252         }
    253 
    254         public void load() throws IOException {
    255                 properties.clear();
    256                 final BufferedReader in = new BufferedReader(new FileReader(getPreferencesDir()+"preferences"));
    257                 int lineNumber = 0;
    258                 ArrayList<Integer> errLines = new ArrayList<Integer>();
    259                 for (String line = in.readLine(); line != null; line = in.readLine(), lineNumber++) {
    260                         final int i = line.indexOf('=');
    261                         if (i == -1 || i == 0) {
    262                                 errLines.add(lineNumber);
    263                                 continue;
    264                         }
    265                         properties.put(line.substring(0,i), line.substring(i+1));
    266                 }
    267                 if (!errLines.isEmpty()) {
    268                         throw new IOException("Malformed config file at lines " + errLines);
    269                 }
    270                 setSystemProperties();
    271         }
    272 
    273         public final void resetToDefault() {
    274                 properties.clear();
    275                 properties.put("projection", "org.openstreetmap.josm.data.projection.Epsg4326");
    276                 properties.put("draw.segment.direction", "true");
    277                 properties.put("draw.wireframe", "false");
    278                 properties.put("layerlist.visible", "true");
    279                 properties.put("propertiesdialog.visible", "true");
    280                 properties.put("selectionlist.visible", "true");
    281                 properties.put("commandstack.visible", "true");
    282                 properties.put("osm-server.url", "http://www.openstreetmap.org/api");
    283                 if (System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") == -1) {
    284                         properties.put("laf", "javax.swing.plaf.metal.MetalLookAndFeel");
    285                 } else {
    286                         properties.put("laf", "com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
    287                 }
    288                 save();
    289         }
    290 
    291         public Collection<Bookmark> loadBookmarks() throws IOException {
    292                 File bookmarkFile = new File(getPreferencesDir()+"bookmarks");
    293                 if (!bookmarkFile.exists())
    294                         bookmarkFile.createNewFile();
    295                 BufferedReader in = new BufferedReader(new FileReader(bookmarkFile));
    296 
    297                 LinkedList<Bookmark> bookmarks = new LinkedList<Bookmark>();
    298                 // use pattern matches to scan text, as text may contain a "," itself
    299                 for (String line = in.readLine(); line != null; line = in.readLine()) {
    300                         Matcher m = Pattern.compile("^(.+),(-?\\d+.\\d+),(-?\\d+.\\d+),(-?\\d+.\\d+),(-?\\d+.\\d+)$").matcher(line);
    301                         if(m.matches())
    302                         {
    303                                 Bookmark b = new Bookmark();
    304                                 b.name = m.group(1);
    305                                 for (int i = 0; i < b.latlon.length; ++i)
    306                                         b.latlon[i] = Double.parseDouble(m.group(i+2));
    307                                 bookmarks.add(b);
    308                         }
    309                 }
    310                 in.close();
    311                 Collections.sort(bookmarks);
    312                 return bookmarks;
    313         }
    314 
    315         public void saveBookmarks(Collection<Bookmark> bookmarks) throws IOException {
    316                 File bookmarkFile = new File(Main.pref.getPreferencesDir()+"bookmarks");
    317                 if (!bookmarkFile.exists())
    318                         bookmarkFile.createNewFile();
    319                 PrintWriter out = new PrintWriter(new FileWriter(bookmarkFile));
    320                 for (Bookmark b : bookmarks) {
    321                         out.print(b.name+",");
    322                         for (int i = 0; i < b.latlon.length; ++i)
    323                                 out.print(b.latlon[i]+(i<b.latlon.length-1?",":""));
    324                         out.println();
    325                 }
    326                 out.close();
    327         }
    328 
    329         /**
    330         * Convenience method for accessing colour preferences.
    331         *
    332         * @param colName name of the colour
    333         * @param def default value
    334         * @return a Color object for the configured colour, or the default value if none configured.
    335         */
    336         synchronized public Color getColor(String colName, Color def) {
    337                 String colStr = get("color."+colName);
    338                 if (colStr.equals("")) {
    339                         put("color."+colName, ColorHelper.color2html(def));
    340                         return def;
    341                 }
    342                 return ColorHelper.html2color(colStr);
    343         }
    344 
    345         // only for compatibility. Don't use any more.
    346         @Deprecated
    347         public static Color getPreferencesColor(String colName, Color def)
    348         {
    349                 return Main.pref.getColor(colName, def);
    350         }
    351 
    352         /**
    353         * Convenience method for accessing colour preferences.
    354         *
    355         * @param colName name of the colour
    356         * @param specName name of the special colour settings
    357         * @param def default value
    358         * @return a Color object for the configured colour, or the default value if none configured.
    359         */
    360         synchronized public Color getColor(String colName, String specName, Color def) {
    361                 String colStr = get("color."+specName);
    362                 if(colStr.equals(""))
    363                 {
    364                         colStr = get("color."+colName);
    365                         if (colStr.equals("")) {
    366                                 put("color."+colName, ColorHelper.color2html(def));
    367                                 return def;
    368                         }
    369                 }
    370                 putDefault("color."+colName, ColorHelper.color2html(def));
    371                 return ColorHelper.html2color(colStr);
    372         }
    373 
    374         synchronized public void putColor(String colName, Color val) {
    375                 put("color."+colName, val != null ? ColorHelper.color2html(val) : null);
    376         }
    377 
    378         synchronized public int getInteger(String key, int def) {
    379                 putDefault(key, Integer.toString(def));
    380                 String v = get(key);
    381                 if(null == v)
    382                         return def;
    383 
    384                 try {
    385                         return Integer.parseInt(v);
    386                 } catch(NumberFormatException e) {
    387                         // fall out
    388                 }
    389                 return def;
    390         }
    391 
    392         synchronized public long getLong(String key, long def) {
    393                 putDefault(key, Long.toString(def));
    394                 String v = get(key);
    395                 if(null == v)
    396                         return def;
    397 
    398                 try {
    399                         return Long.parseLong(v);
    400                 } catch(NumberFormatException e) {
    401                         // fall out
    402                 }
    403                 return def;
    404         }
    405 
    406         synchronized public double getDouble(String key, double def) {
    407                 putDefault(key, Double.toString(def));
    408                 String v = get(key);
    409                 if(null == v)
    410                         return def;
    411 
    412                 try {
    413                         return Double.parseDouble(v);
    414                 } catch(NumberFormatException e) {
    415                         // fall out
    416                 }
    417                 return def;
    418         }
    419 
    420         synchronized public Collection<String> getCollection(String key, Collection<String> def) {
    421                 String s = get(key);
    422                 if(s != null && s.length() != 0)
    423                 {
    424                         /* handle old comma separated stuff - remove in future */
    425                         if(s.indexOf(',') >= 0)
    426                                 return Arrays.asList(s.split(","));
    427                         /* handle space separated stuff - remove in future */
    428                         else if(s.indexOf(' ') >= 0)
    429                                 return Arrays.asList(s.split(","));
    430                         else
    431                                 return Arrays.asList(s.split(";"));
    432                 }
    433                 else if(def != null)
    434                         return def;
    435                 return null;
    436         }
    437         synchronized public void removeFromCollection(String key, String value) {
    438                 ArrayList<String> a = new ArrayList<String>(getCollection(key, null));
    439                 if(a != null)
    440                 {
    441                         a.remove(value);
    442                         putCollection(key, a);
    443                 }
    444         }
    445         synchronized public void putCollection(String key, Collection<String> val) {
    446                 String s = null;
    447                 if(val != null)
    448                 {
    449                         for(String a : val)
    450                         {
    451                                 if(s != null)
    452                                         s += ";" + a;
    453                                 else
    454                                         s = a;
    455                         }
    456                 }
    457 
    458                 put(key, s);
    459         }
    460 
    461         private void setSystemProperties() {
    462                 Properties sysProp = System.getProperties();
    463                 if (getBoolean(ProxyPreferences.PROXY_ENABLE)) {
    464                         sysProp.put("proxySet", "true");
    465                         sysProp.put("http.proxyHost", get(ProxyPreferences.PROXY_HOST));
    466                         sysProp.put("proxyPort", get(ProxyPreferences.PROXY_PORT));
    467                         if (!getBoolean(ProxyPreferences.PROXY_ANONYMOUS)) {
    468                                 sysProp.put("proxyUser", get(ProxyPreferences.PROXY_USER));
    469                                 sysProp.put("proxyPassword", get(ProxyPreferences.PROXY_PASS));
    470                         }
    471                 }/* else {
    472                         sysProp.put("proxySet", "false");
    473                         sysProp.remove("http.proxyHost");
    474                         sysProp.remove("proxyPort");
    475                         sysProp.remove("proxyUser");
    476                         sysProp.remove("proxyPassword");
    477                 }*/
    478                 System.setProperties(sysProp);
    479         }
     112
     113    public File getPluginsDirFile() {
     114        return new File(getPreferencesDirFile(), "plugins");
     115    }
     116
     117    /**
     118    * @return A list of all existing directories where resources could be stored.
     119    */
     120    public Collection<String> getAllPossiblePreferenceDirs() {
     121        LinkedList<String> locations = new LinkedList<String>();
     122        locations.add(Main.pref.getPreferencesDir());
     123        String s;
     124        if ((s = System.getenv("JOSM_RESOURCES")) != null) {
     125            if (!s.endsWith(File.separator))
     126                s = s + File.separator;
     127            locations.add(s);
     128        }
     129        if ((s = System.getProperty("josm.resources")) != null) {
     130            if (!s.endsWith(File.separator))
     131                s = s + File.separator;
     132            locations.add(s);
     133        }
     134        String appdata = System.getenv("APPDATA");
     135        if (System.getenv("ALLUSERSPROFILE") != null && appdata != null
     136                && appdata.lastIndexOf(File.separator) != -1) {
     137            appdata = appdata.substring(appdata.lastIndexOf(File.separator));
     138            locations.add(new File(new File(System.getenv("ALLUSERSPROFILE"),
     139                    appdata), "JOSM").getPath());
     140        }
     141        locations.add("/usr/local/share/josm/");
     142        locations.add("/usr/local/lib/josm/");
     143        locations.add("/usr/share/josm/");
     144        locations.add("/usr/lib/josm/");
     145        return locations;
     146    }
     147
     148    synchronized public boolean hasKey(final String key) {
     149        return override.containsKey(key) ? override.get(key) != null : properties.containsKey(key);
     150    }
     151
     152    synchronized public String get(final String key) {
     153        putDefault(key, null);
     154        if (override.containsKey(key))
     155            return override.get(key);
     156        if (!properties.containsKey(key))
     157            return "";
     158        return properties.get(key);
     159    }
     160
     161    synchronized public String get(final String key, final String def) {
     162        putDefault(key, def);
     163        if (override.containsKey(key))
     164            return override.get(key);
     165        final String prop = properties.get(key);
     166        if (prop == null || prop.equals(""))
     167            return def;
     168        return prop;
     169    }
     170
     171    synchronized public Map<String, String> getAllPrefix(final String prefix) {
     172        final Map<String,String> all = new TreeMap<String,String>();
     173        for (final Entry<String,String> e : properties.entrySet())
     174            if (e.getKey().startsWith(prefix))
     175                all.put(e.getKey(), e.getValue());
     176        for (final Entry<String,String> e : override.entrySet())
     177            if (e.getKey().startsWith(prefix))
     178                if (e.getValue() == null)
     179                    all.remove(e.getKey());
     180                else
     181                    all.put(e.getKey(), e.getValue());
     182        return all;
     183    }
     184
     185    synchronized public Map<String, String> getDefaults() {
     186        return defaults;
     187    }
     188
     189    synchronized public void putDefault(final String key, final String def) {
     190        if(!defaults.containsKey(key) || defaults.get(key) == null)
     191            defaults.put(key, def);
     192        else if(def != null && !defaults.get(key).equals(def))
     193            System.out.println("Defaults for " + key + " differ: " + def + " != " + defaults.get(key));
     194    }
     195
     196    synchronized public boolean getBoolean(final String key) {
     197        putDefault(key, null);
     198        if (override.containsKey(key))
     199            return override.get(key) == null ? false : Boolean.parseBoolean(override.get(key));
     200        return properties.containsKey(key) ? Boolean.parseBoolean(properties.get(key)) : false;
     201    }
     202
     203    synchronized public boolean getBoolean(final String key, final boolean def) {
     204        putDefault(key, Boolean.toString(def));
     205        if (override.containsKey(key))
     206            return override.get(key) == null ? def : Boolean.parseBoolean(override.get(key));
     207        return properties.containsKey(key) ? Boolean.parseBoolean(properties.get(key)) : def;
     208    }
     209
     210    synchronized public void put(final String key, String value) {
     211        String oldvalue = properties.get(key);
     212        if(value != null && value.length() == 0)
     213            value = null;
     214        if(!((oldvalue == null && value == null) || (value != null
     215        && oldvalue != null && oldvalue.equals(value))))
     216        {
     217            if (value == null)
     218                properties.remove(key);
     219            else
     220                properties.put(key, value);
     221            save();
     222            firePreferenceChanged(key, value);
     223        }
     224    }
     225
     226    synchronized public void put(final String key, final boolean value) {
     227        put(key, Boolean.toString(value));
     228    }
     229
     230    private final void firePreferenceChanged(final String key, final String value) {
     231        for (final PreferenceChangedListener l : listener)
     232            l.preferenceChanged(key, value);
     233    }
     234
     235    /**
     236    * Called after every put. In case of a problem, do nothing but output the error
     237    * in log.
     238    */
     239    public void save() {
     240        try {
     241            setSystemProperties();
     242            final PrintWriter out = new PrintWriter(new FileWriter(getPreferencesDir() + "preferences"), false);
     243            for (final Entry<String, String> e : properties.entrySet()) {
     244                out.println(e.getKey() + "=" + e.getValue());
     245            }
     246            out.close();
     247        } catch (final IOException e) {
     248            e.printStackTrace();
     249            // do not message anything, since this can be called from strange
     250            // places.
     251        }
     252    }
     253
     254    public void load() throws IOException {
     255        properties.clear();
     256        final BufferedReader in = new BufferedReader(new FileReader(getPreferencesDir()+"preferences"));
     257        int lineNumber = 0;
     258        ArrayList<Integer> errLines = new ArrayList<Integer>();
     259        for (String line = in.readLine(); line != null; line = in.readLine(), lineNumber++) {
     260            final int i = line.indexOf('=');
     261            if (i == -1 || i == 0) {
     262                errLines.add(lineNumber);
     263                continue;
     264            }
     265            properties.put(line.substring(0,i), line.substring(i+1));
     266        }
     267        if (!errLines.isEmpty()) {
     268            throw new IOException("Malformed config file at lines " + errLines);
     269        }
     270        setSystemProperties();
     271    }
     272
     273    public final void resetToDefault() {
     274        properties.clear();
     275        properties.put("projection", "org.openstreetmap.josm.data.projection.Epsg4326");
     276        properties.put("draw.segment.direction", "true");
     277        properties.put("draw.wireframe", "false");
     278        properties.put("layerlist.visible", "true");
     279        properties.put("propertiesdialog.visible", "true");
     280        properties.put("selectionlist.visible", "true");
     281        properties.put("commandstack.visible", "true");
     282        properties.put("osm-server.url", "http://www.openstreetmap.org/api");
     283        if (System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") == -1) {
     284            properties.put("laf", "javax.swing.plaf.metal.MetalLookAndFeel");
     285        } else {
     286            properties.put("laf", "com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
     287        }
     288        save();
     289    }
     290
     291    public Collection<Bookmark> loadBookmarks() throws IOException {
     292        File bookmarkFile = new File(getPreferencesDir()+"bookmarks");
     293        if (!bookmarkFile.exists())
     294            bookmarkFile.createNewFile();
     295        BufferedReader in = new BufferedReader(new FileReader(bookmarkFile));
     296
     297        LinkedList<Bookmark> bookmarks = new LinkedList<Bookmark>();
     298        // use pattern matches to scan text, as text may contain a "," itself
     299        for (String line = in.readLine(); line != null; line = in.readLine()) {
     300            Matcher m = Pattern.compile("^(.+),(-?\\d+.\\d+),(-?\\d+.\\d+),(-?\\d+.\\d+),(-?\\d+.\\d+)$").matcher(line);
     301            if(m.matches())
     302            {
     303                Bookmark b = new Bookmark();
     304                b.name = m.group(1);
     305                for (int i = 0; i < b.latlon.length; ++i)
     306                    b.latlon[i] = Double.parseDouble(m.group(i+2));
     307                bookmarks.add(b);
     308            }
     309        }
     310        in.close();
     311        Collections.sort(bookmarks);
     312        return bookmarks;
     313    }
     314
     315    public void saveBookmarks(Collection<Bookmark> bookmarks) throws IOException {
     316        File bookmarkFile = new File(Main.pref.getPreferencesDir()+"bookmarks");
     317        if (!bookmarkFile.exists())
     318            bookmarkFile.createNewFile();
     319        PrintWriter out = new PrintWriter(new FileWriter(bookmarkFile));
     320        for (Bookmark b : bookmarks) {
     321            out.print(b.name+",");
     322            for (int i = 0; i < b.latlon.length; ++i)
     323                out.print(b.latlon[i]+(i<b.latlon.length-1?",":""));
     324            out.println();
     325        }
     326        out.close();
     327    }
     328
     329    /**
     330    * Convenience method for accessing colour preferences.
     331    *
     332    * @param colName name of the colour
     333    * @param def default value
     334    * @return a Color object for the configured colour, or the default value if none configured.
     335    */
     336    synchronized public Color getColor(String colName, Color def) {
     337        String colStr = get("color."+colName);
     338        if (colStr.equals("")) {
     339            put("color."+colName, ColorHelper.color2html(def));
     340            return def;
     341        }
     342        return ColorHelper.html2color(colStr);
     343    }
     344
     345    // only for compatibility. Don't use any more.
     346    @Deprecated
     347    public static Color getPreferencesColor(String colName, Color def)
     348    {
     349        return Main.pref.getColor(colName, def);
     350    }
     351
     352    /**
     353    * Convenience method for accessing colour preferences.
     354    *
     355    * @param colName name of the colour
     356    * @param specName name of the special colour settings
     357    * @param def default value
     358    * @return a Color object for the configured colour, or the default value if none configured.
     359    */
     360    synchronized public Color getColor(String colName, String specName, Color def) {
     361        String colStr = get("color."+specName);
     362        if(colStr.equals(""))
     363        {
     364            colStr = get("color."+colName);
     365            if (colStr.equals("")) {
     366                put("color."+colName, ColorHelper.color2html(def));
     367                return def;
     368            }
     369        }
     370        putDefault("color."+colName, ColorHelper.color2html(def));
     371        return ColorHelper.html2color(colStr);
     372    }
     373
     374    synchronized public void putColor(String colName, Color val) {
     375        put("color."+colName, val != null ? ColorHelper.color2html(val) : null);
     376    }
     377
     378    synchronized public int getInteger(String key, int def) {
     379        putDefault(key, Integer.toString(def));
     380        String v = get(key);
     381        if(null == v)
     382            return def;
     383
     384        try {
     385            return Integer.parseInt(v);
     386        } catch(NumberFormatException e) {
     387            // fall out
     388        }
     389        return def;
     390    }
     391
     392    synchronized public long getLong(String key, long def) {
     393        putDefault(key, Long.toString(def));
     394        String v = get(key);
     395        if(null == v)
     396            return def;
     397
     398        try {
     399            return Long.parseLong(v);
     400        } catch(NumberFormatException e) {
     401            // fall out
     402        }
     403        return def;
     404    }
     405
     406    synchronized public double getDouble(String key, double def) {
     407        putDefault(key, Double.toString(def));
     408        String v = get(key);
     409        if(null == v)
     410            return def;
     411
     412        try {
     413            return Double.parseDouble(v);
     414        } catch(NumberFormatException e) {
     415            // fall out
     416        }
     417        return def;
     418    }
     419
     420    synchronized public Collection<String> getCollection(String key, Collection<String> def) {
     421        String s = get(key);
     422        if(s != null && s.length() != 0)
     423        {
     424            /* handle old comma separated stuff - remove in future */
     425            if(s.indexOf(',') >= 0)
     426                return Arrays.asList(s.split(","));
     427            /* handle space separated stuff - remove in future */
     428            else if(s.indexOf(' ') >= 0)
     429                return Arrays.asList(s.split(","));
     430            else
     431                return Arrays.asList(s.split(";"));
     432        }
     433        else if(def != null)
     434            return def;
     435        return null;
     436    }
     437    synchronized public void removeFromCollection(String key, String value) {
     438        ArrayList<String> a = new ArrayList<String>(getCollection(key, null));
     439        if(a != null)
     440        {
     441            a.remove(value);
     442            putCollection(key, a);
     443        }
     444    }
     445    synchronized public void putCollection(String key, Collection<String> val) {
     446        String s = null;
     447        if(val != null)
     448        {
     449            for(String a : val)
     450            {
     451                if(s != null)
     452                    s += ";" + a;
     453                else
     454                    s = a;
     455            }
     456        }
     457
     458        put(key, s);
     459    }
     460
     461    private void setSystemProperties() {
     462        Properties sysProp = System.getProperties();
     463        if (getBoolean(ProxyPreferences.PROXY_ENABLE)) {
     464            sysProp.put("proxySet", "true");
     465            sysProp.put("http.proxyHost", get(ProxyPreferences.PROXY_HOST));
     466            sysProp.put("proxyPort", get(ProxyPreferences.PROXY_PORT));
     467            if (!getBoolean(ProxyPreferences.PROXY_ANONYMOUS)) {
     468                sysProp.put("proxyUser", get(ProxyPreferences.PROXY_USER));
     469                sysProp.put("proxyPassword", get(ProxyPreferences.PROXY_PASS));
     470            }
     471        }/* else {
     472            sysProp.put("proxySet", "false");
     473            sysProp.remove("http.proxyHost");
     474            sysProp.remove("proxyPort");
     475            sysProp.remove("proxyUser");
     476            sysProp.remove("proxyPassword");
     477        }*/
     478        System.setProperties(sysProp);
     479    }
    480480}
  • trunk/src/org/openstreetmap/josm/data/SelectionChangedListener.java

    r655 r1169  
    1010 * a selection of any data member changes, the dataSet gets informed about this
    1111 * and fires a selectionChanged event.
    12  * 
     12 *
    1313 * Note that these events are not fired immediately but are inserted in the
    1414 * Swing event queue and packed together. So only one selection changed event
    1515 * is issued within a one message dispatch routine.
    16  * 
     16 *
    1717 * @author imi
    1818 */
    1919public interface SelectionChangedListener {
    2020
    21         /**
    22         * Informs the listener that the selection in the dataset has changed.
    23         * @param newSelection The new selection.
    24         */
    25         public void selectionChanged(Collection<? extends OsmPrimitive> newSelection);
     21    /**
     22    * Informs the listener that the selection in the dataset has changed.
     23    * @param newSelection The new selection.
     24    */
     25    public void selectionChanged(Collection<? extends OsmPrimitive> newSelection);
    2626}
  • trunk/src/org/openstreetmap/josm/data/ServerSidePreferences.java

    r733 r1169  
    3232 * This class tweak the Preferences class to provide server side preference settings, as example
    3333 * used in the applet version.
    34  * 
     34 *
    3535 * @author Imi
    3636 */
    3737public class ServerSidePreferences extends Preferences {
    3838
    39         private final Connection connection;
     39    private final Connection connection;
    4040
    41         private class Connection extends OsmConnection {
    42                 URL serverUrl;
    43                 public Connection(URL serverUrl) {
    44                         this.serverUrl = serverUrl;
    45                 }
    46                 public String download() {
    47                         try {
    48                                 System.out.println("reading preferences from "+serverUrl);
    49                                 URLConnection con = serverUrl.openConnection();
    50                                 if (con instanceof HttpURLConnection) addAuth((HttpURLConnection) con);
    51                                 con.connect();
    52                                 BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
    53                                 StringBuilder b = new StringBuilder();
    54                                 for (String line = reader.readLine(); line != null; line = reader.readLine()) {
    55                                         b.append(line);
    56                                         b.append("\n");
    57                                 }
    58                                 if (con instanceof HttpURLConnection) ((HttpURLConnection) con).disconnect();
    59                                 return b.toString();
    60                         } catch (IOException e) {
    61                                 e.printStackTrace();
    62                         }
    63                         return null;
    64                 }
    65                 public void upload(String s) {
    66                         try {
    67                                 URL u = new URL(getPreferencesDir());
    68                                 System.out.println("uploading preferences to "+u);
    69                                 HttpURLConnection con = (HttpURLConnection)u.openConnection();
    70                                 con.addRequestProperty("Authorization", "Basic "+Base64.encode(get("osm-server.username")+":"+get("osm-server.password")));
    71                                 con.setRequestMethod("POST");
    72                                 con.setDoOutput(true);
    73                                 con.connect();
    74                                 PrintWriter out = new PrintWriter(new OutputStreamWriter(con.getOutputStream()));
    75                                 out.println(s);
    76                                 out.close();
    77                                 con.getInputStream().close();
    78                                 con.disconnect();
    79                                 JOptionPane.showMessageDialog(Main.parent, tr("Preferences stored on {0}", u.getHost()));
    80                         } catch (Exception e) {
    81                                 e.printStackTrace();
    82                                 JOptionPane.showMessageDialog(Main.parent, tr("Could not upload preferences. Reason: {0}", e.getMessage()));
    83                         }
    84                 }
    85         }
     41    private class Connection extends OsmConnection {
     42        URL serverUrl;
     43        public Connection(URL serverUrl) {
     44            this.serverUrl = serverUrl;
     45        }
     46        public String download() {
     47            try {
     48                System.out.println("reading preferences from "+serverUrl);
     49                URLConnection con = serverUrl.openConnection();
     50                if (con instanceof HttpURLConnection) addAuth((HttpURLConnection) con);
     51                con.connect();
     52                BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
     53                StringBuilder b = new StringBuilder();
     54                for (String line = reader.readLine(); line != null; line = reader.readLine()) {
     55                    b.append(line);
     56                    b.append("\n");
     57                }
     58                if (con instanceof HttpURLConnection) ((HttpURLConnection) con).disconnect();
     59                return b.toString();
     60            } catch (IOException e) {
     61                e.printStackTrace();
     62            }
     63            return null;
     64        }
     65        public void upload(String s) {
     66            try {
     67                URL u = new URL(getPreferencesDir());
     68                System.out.println("uploading preferences to "+u);
     69                HttpURLConnection con = (HttpURLConnection)u.openConnection();
     70                con.addRequestProperty("Authorization", "Basic "+Base64.encode(get("osm-server.username")+":"+get("osm-server.password")));
     71                con.setRequestMethod("POST");
     72                con.setDoOutput(true);
     73                con.connect();
     74                PrintWriter out = new PrintWriter(new OutputStreamWriter(con.getOutputStream()));
     75                out.println(s);
     76                out.close();
     77                con.getInputStream().close();
     78                con.disconnect();
     79                JOptionPane.showMessageDialog(Main.parent, tr("Preferences stored on {0}", u.getHost()));
     80            } catch (Exception e) {
     81                e.printStackTrace();
     82                JOptionPane.showMessageDialog(Main.parent, tr("Could not upload preferences. Reason: {0}", e.getMessage()));
     83            }
     84        }
     85    }
    8686
    87         public ServerSidePreferences(URL serverUrl) {
    88                 Connection connection = null;
    89                 try {
    90                         connection = new Connection(new URL(serverUrl+"user/preferences"));
    91                 } catch (MalformedURLException e) {
    92                         e.printStackTrace();
    93                         JOptionPane.showMessageDialog(Main.parent, tr("Could not load preferences from server."));
    94                 }
    95                 this.connection = connection;
    96         }
     87    public ServerSidePreferences(URL serverUrl) {
     88        Connection connection = null;
     89        try {
     90            connection = new Connection(new URL(serverUrl+"user/preferences"));
     91        } catch (MalformedURLException e) {
     92            e.printStackTrace();
     93            JOptionPane.showMessageDialog(Main.parent, tr("Could not load preferences from server."));
     94        }
     95        this.connection = connection;
     96    }
    9797
    98         @Override public String getPreferencesDir() {
    99                 return connection.serverUrl.toString();
    100         }
     98    @Override public String getPreferencesDir() {
     99        return connection.serverUrl.toString();
     100    }
    101101
    102         /**
    103         * Do nothing on load. Preferences are loaded with download().
    104         */
    105         @Override public void load() {
    106         }
     102    /**
     103    * Do nothing on load. Preferences are loaded with download().
     104    */
     105    @Override public void load() {
     106    }
    107107
    108         /**
    109         * Do nothing on save. Preferences are uploaded using upload().
    110         */
    111         @Override public void save() {
    112         }
     108    /**
     109    * Do nothing on save. Preferences are uploaded using upload().
     110    */
     111    @Override public void save() {
     112    }
    113113
    114         public static class Prop {
    115                 public String key;
    116                 public String value;
    117         }
     114    public static class Prop {
     115        public String key;
     116        public String value;
     117    }
    118118
    119         public void download(String userName, String password) {
    120                 resetToDefault();
    121                 if (!properties.containsKey("osm-server.username") && userName != null)
    122                         properties.put("osm-server.username", userName);
    123                 if (!properties.containsKey("osm-server.password") && password != null)
    124                         properties.put("osm-server.password", password);
    125                 String cont = connection.download();
    126                 if (cont == null) return;
    127                 Reader in = new StringReader(cont);
    128                 try {
    129                         XmlObjectParser.Uniform<Prop> parser = new XmlObjectParser.Uniform<Prop>(in, "tag", Prop.class);
    130                         for (Prop p : parser)
    131                                 properties.put(p.key, p.value);
    132                 } catch (RuntimeException e) {
    133                         e.printStackTrace();
    134                 }
    135         }
     119    public void download(String userName, String password) {
     120        resetToDefault();
     121        if (!properties.containsKey("osm-server.username") && userName != null)
     122            properties.put("osm-server.username", userName);
     123        if (!properties.containsKey("osm-server.password") && password != null)
     124            properties.put("osm-server.password", password);
     125        String cont = connection.download();
     126        if (cont == null) return;
     127        Reader in = new StringReader(cont);
     128        try {
     129            XmlObjectParser.Uniform<Prop> parser = new XmlObjectParser.Uniform<Prop>(in, "tag", Prop.class);
     130            for (Prop p : parser)
     131                properties.put(p.key, p.value);
     132        } catch (RuntimeException e) {
     133            e.printStackTrace();
     134        }
     135    }
    136136
    137         /**
    138         * Use this instead of save() for the ServerSidePreferences, since uploads
    139         * are costly while save is called often.
    140          *
    141         * This is triggered by an explicit menu option.
    142         */
    143         public void upload() {
    144                 StringBuilder b = new StringBuilder("<preferences>\n");
    145                 for (Entry<String, String> p : properties.entrySet()) {
    146                         if (p.getKey().equals("osm-server.password"))
    147                                 continue; // do not upload password. It would get stored in plain!
    148                         b.append("<tag key='");
    149                         b.append(XmlWriter.encode(p.getKey()));
    150                         b.append("' value='");
    151                         b.append(XmlWriter.encode(p.getValue()));
    152                         b.append("' />\n");
    153                 }
    154                 b.append("</preferences>");
    155                 connection.upload(b.toString());
    156         }
     137    /**
     138    * Use this instead of save() for the ServerSidePreferences, since uploads
     139    * are costly while save is called often.
     140     *
     141    * This is triggered by an explicit menu option.
     142    */
     143    public void upload() {
     144        StringBuilder b = new StringBuilder("<preferences>\n");
     145        for (Entry<String, String> p : properties.entrySet()) {
     146            if (p.getKey().equals("osm-server.password"))
     147                continue; // do not upload password. It would get stored in plain!
     148            b.append("<tag key='");
     149            b.append(XmlWriter.encode(p.getKey()));
     150            b.append("' value='");
     151            b.append(XmlWriter.encode(p.getValue()));
     152            b.append("' />\n");
     153        }
     154        b.append("</preferences>");
     155        connection.upload(b.toString());
     156    }
    157157
    158         @Override public Collection<Bookmark> loadBookmarks() {
    159                 try {
    160                         Collection<Bookmark> bookmarks;
    161                         BufferedReader in = new BufferedReader(new InputStreamReader(new URL("http://"+connection.serverUrl.getHost()+"/josm/bookmarks").openStream()));
    162                         bookmarks = new LinkedList<Bookmark>();
    163                         for (String line = in.readLine(); line != null; line = in.readLine()) {
    164                                 StringTokenizer st = new StringTokenizer(line, ",");
    165                                 if (st.countTokens() < 5)
    166                                         continue;
    167                                 Bookmark b = new Bookmark();
    168                                 b.name = st.nextToken();
    169                                 try {
    170                                         for (int i = 0; i < b.latlon.length; ++i)
    171                                                 b.latlon[i] = Double.parseDouble(st.nextToken());
    172                                         bookmarks.add(b);
    173                                 } catch (NumberFormatException x) {
    174                                         // line not parsed
    175                                 }
    176                         }
    177                         in.close();
    178                         return bookmarks;
    179                 } catch (MalformedURLException e) {
    180                         e.printStackTrace();
    181                 } catch (IllegalArgumentException e) {
    182                         e.printStackTrace();
    183                 } catch (IOException e) {
    184                         e.printStackTrace();
    185                 }
    186                 return Collections.emptyList();
    187         }
     158    @Override public Collection<Bookmark> loadBookmarks() {
     159        try {
     160            Collection<Bookmark> bookmarks;
     161            BufferedReader in = new BufferedReader(new InputStreamReader(new URL("http://"+connection.serverUrl.getHost()+"/josm/bookmarks").openStream()));
     162            bookmarks = new LinkedList<Bookmark>();
     163            for (String line = in.readLine(); line != null; line = in.readLine()) {
     164                StringTokenizer st = new StringTokenizer(line, ",");
     165                if (st.countTokens() < 5)
     166                    continue;
     167                Bookmark b = new Bookmark();
     168                b.name = st.nextToken();
     169                try {
     170                    for (int i = 0; i < b.latlon.length; ++i)
     171                        b.latlon[i] = Double.parseDouble(st.nextToken());
     172                    bookmarks.add(b);
     173                } catch (NumberFormatException x) {
     174                    // line not parsed
     175                }
     176            }
     177            in.close();
     178            return bookmarks;
     179        } catch (MalformedURLException e) {
     180            e.printStackTrace();
     181        } catch (IllegalArgumentException e) {
     182            e.printStackTrace();
     183        } catch (IOException e) {
     184            e.printStackTrace();
     185        }
     186        return Collections.emptyList();
     187    }
    188188
    189         @Override public void saveBookmarks(Collection<Bookmark> bookmarks) {
    190         }
     189    @Override public void saveBookmarks(Collection<Bookmark> bookmarks) {
     190    }
    191191}
  • trunk/src/org/openstreetmap/josm/data/UndoRedoHandler.java

    r661 r1169  
    1515public class UndoRedoHandler implements LayerChangeListener {
    1616
    17         /**
    18         * All commands that were made on the dataset. Don't write from outside!
    19         */
    20         public final LinkedList<Command> commands = new LinkedList<Command>();
    21         /**
    22         * The stack for redoing commands
    23         */
    24         private final Stack<Command> redoCommands = new Stack<Command>();
     17    /**
     18    * All commands that were made on the dataset. Don't write from outside!
     19    */
     20    public final LinkedList<Command> commands = new LinkedList<Command>();
     21    /**
     22    * The stack for redoing commands
     23    */
     24    private final Stack<Command> redoCommands = new Stack<Command>();
    2525
    26         public final LinkedList<CommandQueueListener> listenerCommands = new LinkedList<CommandQueueListener>();
     26    public final LinkedList<CommandQueueListener> listenerCommands = new LinkedList<CommandQueueListener>();
    2727
    2828
    29         public UndoRedoHandler() {
    30                 Layer.listeners.add(this);
    31         }
     29    public UndoRedoHandler() {
     30        Layer.listeners.add(this);
     31    }
    3232
    3333
    34         /**
    35         * Execute the command and add it to the intern command queue.
    36         */
    37         public void add(final Command c) {
    38                 c.executeCommand();
    39                 commands.add(c);
    40                 redoCommands.clear();
    41                 if (Main.map != null && Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) {
    42                         OsmDataLayer data = (OsmDataLayer)Main.map.mapView.getActiveLayer();
    43                         data.setModified(true);
    44                         data.fireDataChange();
    45                 }
    46                 fireCommandsChanged();
    47         }
     34    /**
     35    * Execute the command and add it to the intern command queue.
     36    */
     37    public void add(final Command c) {
     38        c.executeCommand();
     39        commands.add(c);
     40        redoCommands.clear();
     41        if (Main.map != null && Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) {
     42            OsmDataLayer data = (OsmDataLayer)Main.map.mapView.getActiveLayer();
     43            data.setModified(true);
     44            data.fireDataChange();
     45        }
     46        fireCommandsChanged();
     47    }
    4848
    49         /**
    50         * Undoes the last added command.
    51         */
    52         public void undo() {
    53                 if (commands.isEmpty())
    54                         return;
    55                 final Command c = commands.removeLast();
    56                 c.undoCommand();
    57                 redoCommands.push(c);
    58                 if (Main.map != null && Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) {
    59                         OsmDataLayer data = (OsmDataLayer)Main.map.mapView.getActiveLayer();
    60                         data.setModified(data.uploadedModified || !commands.isEmpty());
    61                         data.fireDataChange();
    62                 }               
    63                 fireCommandsChanged();
    64                 Main.ds.setSelected();
    65         }
     49    /**
     50    * Undoes the last added command.
     51    */
     52    public void undo() {
     53        if (commands.isEmpty())
     54            return;
     55        final Command c = commands.removeLast();
     56        c.undoCommand();
     57        redoCommands.push(c);
     58        if (Main.map != null && Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) {
     59            OsmDataLayer data = (OsmDataLayer)Main.map.mapView.getActiveLayer();
     60            data.setModified(data.uploadedModified || !commands.isEmpty());
     61            data.fireDataChange();
     62        }
     63        fireCommandsChanged();
     64        Main.ds.setSelected();
     65    }
    6666
    67         /**
    68         * Redoes the last undoed command.
    69         * TODO: This has to be moved to a central place in order to support multiple layers.
    70         */
    71         public void redo() {
    72                 if (redoCommands.isEmpty())
    73                         return;
    74                 final Command c = redoCommands.pop();
    75                 c.executeCommand();
    76                 commands.add(c);
    77                 if (Main.map != null && Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) {
    78                         OsmDataLayer data = (OsmDataLayer)Main.map.mapView.getActiveLayer();
    79                         data.setModified(true);
    80                         data.fireDataChange();
    81                 }
    82                 fireCommandsChanged();
    83         }
     67    /**
     68    * Redoes the last undoed command.
     69    * TODO: This has to be moved to a central place in order to support multiple layers.
     70    */
     71    public void redo() {
     72        if (redoCommands.isEmpty())
     73            return;
     74        final Command c = redoCommands.pop();
     75        c.executeCommand();
     76        commands.add(c);
     77        if (Main.map != null && Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) {
     78            OsmDataLayer data = (OsmDataLayer)Main.map.mapView.getActiveLayer();
     79            data.setModified(true);
     80            data.fireDataChange();
     81        }
     82        fireCommandsChanged();
     83    }
    8484
    85         public void fireCommandsChanged() {
    86                 for (final CommandQueueListener l : listenerCommands)
    87                         l.commandChanged(commands.size(), redoCommands.size());
    88         }
     85    public void fireCommandsChanged() {
     86        for (final CommandQueueListener l : listenerCommands)
     87            l.commandChanged(commands.size(), redoCommands.size());
     88    }
    8989
    90         public void clean() {
    91                 redoCommands.clear();
    92                 commands.clear();
    93                 fireCommandsChanged();
    94         }
     90    public void clean() {
     91        redoCommands.clear();
     92        commands.clear();
     93        fireCommandsChanged();
     94    }
    9595
    96         public void layerRemoved(Layer oldLayer) {
    97                 boolean changed = false;
    98                 for (Iterator<Command> it = commands.iterator(); it.hasNext();) {
    99                         if (it.next().invalidBecauselayerRemoved(oldLayer)) {
    100                                 it.remove();
    101                                 changed = true;
    102                         }
    103                 }
    104                 for (Iterator<Command> it = redoCommands.iterator(); it.hasNext();) {
    105                         if (it.next().invalidBecauselayerRemoved(oldLayer)) {
    106                                 it.remove();
    107                                 changed = true;
    108                         }
    109                 }
    110                 if (changed)
    111                         fireCommandsChanged();
    112         }
     96    public void layerRemoved(Layer oldLayer) {
     97        boolean changed = false;
     98        for (Iterator<Command> it = commands.iterator(); it.hasNext();) {
     99            if (it.next().invalidBecauselayerRemoved(oldLayer)) {
     100                it.remove();
     101                changed = true;
     102            }
     103        }
     104        for (Iterator<Command> it = redoCommands.iterator(); it.hasNext();) {
     105            if (it.next().invalidBecauselayerRemoved(oldLayer)) {
     106                it.remove();
     107                changed = true;
     108            }
     109        }
     110        if (changed)
     111            fireCommandsChanged();
     112    }
    113113
    114         public void layerAdded(Layer newLayer) {}
    115         public void activeLayerChange(Layer oldLayer, Layer newLayer) {}
     114    public void layerAdded(Layer newLayer) {}
     115    public void activeLayerChange(Layer oldLayer, Layer newLayer) {}
    116116}
  • trunk/src/org/openstreetmap/josm/data/conflict/ConflictItem.java

    r627 r1169  
    1212public abstract class ConflictItem {
    1313
    14         public String my, their;
    15         public Resolution resolution = null;
     14    public String my, their;
     15    public Resolution resolution = null;
    1616
    17         public final void initialize(Map<OsmPrimitive,OsmPrimitive> conflicts) {
    18                 my = collectStr(conflicts.keySet());
    19                 their = collectStr(conflicts.values());
    20         }
     17    public final void initialize(Map<OsmPrimitive,OsmPrimitive> conflicts) {
     18        my = collectStr(conflicts.keySet());
     19        their = collectStr(conflicts.values());
     20    }
    2121
    22         abstract public boolean hasConflict(OsmPrimitive key, OsmPrimitive value);
    23         abstract protected String str(OsmPrimitive osm);
    24         abstract public String key();
    25         abstract public void apply(OsmPrimitive target, OsmPrimitive other);
     22    abstract public boolean hasConflict(OsmPrimitive key, OsmPrimitive value);
     23    abstract protected String str(OsmPrimitive osm);
     24    abstract public String key();
     25    abstract public void apply(OsmPrimitive target, OsmPrimitive other);
    2626
    27         protected final String collectStr(Collection<OsmPrimitive> c) {
    28                 String value = null;
    29                 for (OsmPrimitive osm : c) {
    30                         String v = str(osm);
    31                         if (value == null)
    32                                 value = v;
    33                         else if (!value.equals(v)) {
    34                                 value = "<html><i>&lt;"+tr("different")+"&gt;</i></html>";
    35                                 break;
    36                         }
    37                 }
    38                 return value == null ? "" : value;
    39         }
     27    protected final String collectStr(Collection<OsmPrimitive> c) {
     28        String value = null;
     29        for (OsmPrimitive osm : c) {
     30            String v = str(osm);
     31            if (value == null)
     32                value = v;
     33            else if (!value.equals(v)) {
     34                value = "<html><i>&lt;"+tr("different")+"&gt;</i></html>";
     35                break;
     36            }
     37        }
     38        return value == null ? "" : value;
     39    }
    4040}
  • trunk/src/org/openstreetmap/josm/data/conflict/DeleteConflict.java

    r627 r1169  
    88public class DeleteConflict extends ConflictItem {
    99
    10         @Override public boolean hasConflict(OsmPrimitive key, OsmPrimitive value) {
    11                 return key.deleted != value.deleted;
    12         }
     10    @Override public boolean hasConflict(OsmPrimitive key, OsmPrimitive value) {
     11        return key.deleted != value.deleted;
     12    }
    1313
    14         @Override public String key() {
    15                 return "deleted|"+tr("deleted");
    16         }
     14    @Override public String key() {
     15        return "deleted|"+tr("deleted");
     16    }
    1717
    18         @Override protected String str(OsmPrimitive osm) {
    19                 return osm.deleted ? tr("true") : tr("false");
    20         }
     18    @Override protected String str(OsmPrimitive osm) {
     19        return osm.deleted ? tr("true") : tr("false");
     20    }
    2121
    22         @Override public void apply(OsmPrimitive target, OsmPrimitive other) {
    23                 target.deleted = other.deleted;
    24         }
     22    @Override public void apply(OsmPrimitive target, OsmPrimitive other) {
     23        target.deleted = other.deleted;
     24    }
    2525}
  • trunk/src/org/openstreetmap/josm/data/conflict/PositionConflict.java

    r627 r1169  
    88
    99public class PositionConflict extends ConflictItem {
    10        
    11         @Override public boolean hasConflict(OsmPrimitive key, OsmPrimitive value) {
    12                 return key instanceof Node && !((Node)key).coor.equals(((Node)value).coor);
    13         }
    14        
    15         @Override protected String str(OsmPrimitive osm) {
    16                 return osm instanceof Node ? ((Node)osm).coor.lat()+", "+((Node)osm).coor.lon() : null;
    17         }
    18        
    19         @Override public String key() {
    20                 return "node|"+tr("position");
    21         }
    22        
    23         @Override public void apply(OsmPrimitive target, OsmPrimitive other) {
    24                 if (target instanceof Node) {
    25                         ((Node)target).coor = ((Node)other).coor;
    26                         ((Node)target).eastNorth = ((Node)other).eastNorth;
    27                 }
     10
     11    @Override public boolean hasConflict(OsmPrimitive key, OsmPrimitive value) {
     12        return key instanceof Node && !((Node)key).coor.equals(((Node)value).coor);
     13    }
     14
     15    @Override protected String str(OsmPrimitive osm) {
     16        return osm instanceof Node ? ((Node)osm).coor.lat()+", "+((Node)osm).coor.lon() : null;
     17    }
     18
     19    @Override public String key() {
     20        return "node|"+tr("position");
     21    }
     22
     23    @Override public void apply(OsmPrimitive target, OsmPrimitive other) {
     24        if (target instanceof Node) {
     25            ((Node)target).coor = ((Node)other).coor;
     26            ((Node)target).eastNorth = ((Node)other).eastNorth;
     27        }
    2828    }
    2929}
  • trunk/src/org/openstreetmap/josm/data/conflict/PropertyConflict.java

    r627 r1169  
    55
    66public class PropertyConflict extends ConflictItem {
    7         private String key;
    8        
    9         public PropertyConflict(String key) {
    10                 this.key = key;
    11         }
    12        
    13         @Override public boolean hasConflict(OsmPrimitive key, OsmPrimitive value) {
    14                 String k = key.get(this.key);
    15                 String v = value.get(this.key);
    16                 return k == null ? v!=null : !k.equals(v);
    17         }
    18        
    19         @Override protected String str(OsmPrimitive osm) {
    20                 String v = osm.get(key);
    21                 return v == null ? "" : v;
    22         }
    23        
    24         @Override public String key() {
    25                 return "key|"+key;
    26         }
    27        
    28         @Override public void apply(OsmPrimitive target, OsmPrimitive other) {
    29                 target.put(key, other.get(key));
     7    private String key;
     8
     9    public PropertyConflict(String key) {
     10        this.key = key;
     11    }
     12
     13    @Override public boolean hasConflict(OsmPrimitive key, OsmPrimitive value) {
     14        String k = key.get(this.key);
     15        String v = value.get(this.key);
     16        return k == null ? v!=null : !k.equals(v);
     17    }
     18
     19    @Override protected String str(OsmPrimitive osm) {
     20        String v = osm.get(key);
     21        return v == null ? "" : v;
     22    }
     23
     24    @Override public String key() {
     25        return "key|"+key;
     26    }
     27
     28    @Override public void apply(OsmPrimitive target, OsmPrimitive other) {
     29        target.put(key, other.get(key));
    3030    }
    3131}
  • trunk/src/org/openstreetmap/josm/data/coor/Coordinate.java

    r1094 r1169  
    77/**
    88 * Base class of points of both coordinate systems.
    9  * 
    10  * The variables are default package protected to allow routines in the 
     9 *
     10 * The variables are default package protected to allow routines in the
    1111 * data package to access them directly.
    12  * 
    13  * As the class itself is package protected too, it is not visible 
    14  * outside of the data package. Routines there should only use LatLon or 
     12 *
     13 * As the class itself is package protected too, it is not visible
     14 * outside of the data package. Routines there should only use LatLon or
    1515 * EastNorth.
    1616 *
    1717 * @author imi
    18  */ 
     18 */
    1919abstract class Coordinate extends Point2D implements Serializable {
    2020
    2121    protected double x;
    2222    protected double y;
    23    
    24         /**
    25         * Construct the point with latitude / longitude values.
    26          *
    27         * @param x X coordinate of the point.
    28         * @param y Y coordinate of the point.
    29         */
    30         Coordinate(double x, double y) {
     23
     24    /**
     25    * Construct the point with latitude / longitude values.
     26     *
     27    * @param x X coordinate of the point.
     28    * @param y Y coordinate of the point.
     29    */
     30    Coordinate(double x, double y) {
    3131        this.x = x; this.y = y;
    32         }
    33    
     32    }
     33
    3434    public double getX() {
    3535        return x;
    3636    }
    37    
     37
    3838    public double getY() {
    39         return y; 
     39        return y;
    4040    }
    41    
     41
    4242    public void setLocation (double x, double y) {
    43         this.x = x; 
     43        this.x = x;
    4444        this.y = y;
    4545    }
  • trunk/src/org/openstreetmap/josm/data/coor/EastNorth.java

    r1076 r1169  
    44/**
    55 * Northing, Easting of the projected coordinates.
    6  * 
     6 *
    77 * This class is immutable.
    8  * 
     8 *
    99 * @author Imi
    1010 */
    1111public class EastNorth extends Coordinate {
    1212
    13         public EastNorth(double east, double north) {
    14                 super(east,north);
    15         }
    16        
    17         public double east() {
    18                 return x;
    19         }
     13    public EastNorth(double east, double north) {
     14        super(east,north);
     15    }
    2016
    21         public double north() {
    22                 return y;
    23         }
     17    public double east() {
     18        return x;
     19    }
    2420
    25         public EastNorth add(double dx, double dy) {
    26                 return new EastNorth(x+dx, y+dy);
    27         }
    28        
    29         public EastNorth interpolate(EastNorth en2, double proportion) {
    30                 return new EastNorth(this.x + proportion * (en2.x - this.x),
     21    public double north() {
     22        return y;
     23    }
     24
     25    public EastNorth add(double dx, double dy) {
     26        return new EastNorth(x+dx, y+dy);
     27    }
     28
     29    public EastNorth interpolate(EastNorth en2, double proportion) {
     30        return new EastNorth(this.x + proportion * (en2.x - this.x),
    3131            this.y + proportion * (en2.y - this.y));
    32         }
    33    
     32    }
     33
    3434    /**
    35      * Returns the heading, in radians, that you have to use to get from 
     35     * Returns the heading, in radians, that you have to use to get from
    3636     * this EastNorth to another. Heading is mapped into [0, 2pi)
    37      * 
     37     *
    3838     * @param other the "destination" position
    39      * @return heading 
     39     * @return heading
    4040     */
    4141    public double heading(EastNorth other) {
    4242        double hd = Math.atan2(other.east() - east(), other.north() - north());
    4343        if(hd < 0) hd = 2 * Math.PI + hd;
    44         return hd;       
     44        return hd;
    4545    }
    46    
     46
    4747    public EastNorth sub(EastNorth en) {
    4848        return new EastNorth(en.east() - east(), en.north() - north());
    4949    }
    50  
     50
    5151    /**
    5252     * Returns an EastNorth representing the this EastNorth rotatedaround
     
    5454     * @param pivot the center of the rotation
    5555     * @param angle the angle of the rotation
    56      * @return EastNorth rotated object 
     56     * @return EastNorth rotated object
    5757     */
    5858    public EastNorth rotate(EastNorth pivot, double angle) {
     
    6565        return new EastNorth(nx, ny);
    6666    }
    67        
    68         @Override public String toString() {
    69                 return "EastNorth[e="+x+", n="+y+"]";
    70         }
     67
     68    @Override public String toString() {
     69        return "EastNorth[e="+x+", n="+y+"]";
     70    }
    7171
    7272    /**
  • trunk/src/org/openstreetmap/josm/data/coor/LatLon.java

    r1108 r1169  
    1313/**
    1414 * LatLon are unprojected latitude / longitude coordinates.
    15  * 
     15 *
    1616 * This class is immutable.
    17  * 
     17 *
    1818 * @author Imi
    1919 */
     
    2323    private static DecimalFormat cDmsSecondFormatter = new DecimalFormat("00.0");
    2424    private static DecimalFormat cDdFormatter = new DecimalFormat("###0.0000");
    25    
    26     /** 
    27      * Possible ways to display coordinates 
    28      */ 
    29     public enum CoordinateFormat { 
    30         DECIMAL_DEGREES {public String toString() {return tr("Decimal Degrees");}}, 
    31         DEGREES_MINUTES_SECONDS {public String toString() {return tr("Degrees Minutes Seconds");}}; 
    32     } 
    33    
    34     public static String dms(double pCoordinate) { 
     25
     26    /**
     27     * Possible ways to display coordinates
     28     */
     29    public enum CoordinateFormat {
     30        DECIMAL_DEGREES {public String toString() {return tr("Decimal Degrees");}},
     31        DEGREES_MINUTES_SECONDS {public String toString() {return tr("Degrees Minutes Seconds");}};
     32    }
     33
     34    public static String dms(double pCoordinate) {
    3535
    3636        double tAbsCoord = Math.abs(pCoordinate);
     
    4040        double tSeconds = (tTmpMinutes - tMinutes) * 60;
    4141
    42         return tDegree + "\u00B0" + cDmsMinuteFormatter.format(tMinutes) + "\'" 
     42        return tDegree + "\u00B0" + cDmsMinuteFormatter.format(tMinutes) + "\'"
    4343            + cDmsSecondFormatter.format(tSeconds) + "\"";
    44     } 
     44    }
    4545
    4646    public LatLon(double lat, double lon) {
     
    5151        return y;
    5252    }
    53    
     53
    5454    public String latToString(CoordinateFormat d) {
    5555        switch(d) {
     
    5959        }
    6060    }
    61    
     61
    6262    public double lon() {
    6363        return x;
    6464    }
    65    
     65
    6666    public String lonToString(CoordinateFormat d) {
    6767        switch(d) {
     
    7171        }
    7272    }
    73    
    74  
     73
     74
    7575
    7676    /**
     
    8686    /**
    8787     * @return <code>true</code>, if the coordinate is outside the world, compared
    88         * by using lat/lon.
    89         */
    90         public boolean isOutSideWorld() {
    91                 return lat() < -Projection.MAX_LAT || lat() > Projection.MAX_LAT || 
    92                         lon() < -Projection.MAX_LON || lon() > Projection.MAX_LON;
    93         }
     88    * by using lat/lon.
     89    */
     90    public boolean isOutSideWorld() {
     91        return lat() < -Projection.MAX_LAT || lat() > Projection.MAX_LAT ||
     92            lon() < -Projection.MAX_LON || lon() > Projection.MAX_LON;
     93    }
    9494
    95         /**
    96          * @return <code>true</code> if this is within the given bounding box.
    97          */
    98         public boolean isWithin(Bounds b) {
    99                 return lat() >= b.min.lat() && lat() <= b.max.lat() && lon() > b.min.lon() && lon() < b.max.lon();
    100         }
    101        
    102         /**
    103          * Computes the distance between this lat/lon and another point on the earth.
    104          * Uses spherical law of cosines formula, not Haversine.
    105          * @param other the other point.
    106          * @return distance in metres.
    107          */
    108         public double greatCircleDistance(LatLon other) {
    109                 return (Math.acos(
    110                         Math.sin(Math.toRadians(lat())) * Math.sin(Math.toRadians(other.lat())) +
    111                     Math.cos(Math.toRadians(lat()))*Math.cos(Math.toRadians(other.lat())) *
    112                                   Math.cos(Math.toRadians(other.lon()-lon()))) * 6378135);
    113         }
    114        
    115         /**
    116          * Returns the heading, in radians, that you have to use to get from
    117          * this lat/lon to another.
    118          *
    119          * @param other the "destination" position
    120          * @return heading
    121          */
    122         public double heading(LatLon other) {
    123                 double rv;
    124                 if (other.lat() == lat()) {
    125                         rv = (other.lon()>lon() ? Math.PI / 2 : Math.PI * 3 / 2);
    126                 } else {
    127                         rv = Math.atan((other.lon()-lon())/(other.lat()-lat()));
    128                         if (rv < 0) rv += Math.PI;
    129                         if (other.lon() < lon()) rv += Math.PI;
    130                 }
    131                 return rv;
    132         }
     95    /**
     96     * @return <code>true</code> if this is within the given bounding box.
     97     */
     98    public boolean isWithin(Bounds b) {
     99        return lat() >= b.min.lat() && lat() <= b.max.lat() && lon() > b.min.lon() && lon() < b.max.lon();
     100    }
    133101
    134         /**
    135          * Returns this lat/lon pair in human-readable format.
    136          *
    137          * @return String in the format "lat=1.23456°, lon=2.34567°"
    138          */
    139         public String toDisplayString() {
    140                 NumberFormat nf = NumberFormat.getInstance();
    141                 nf.setMaximumFractionDigits(5);
    142                 return "lat=" + nf.format(lat()) + "°, lon=" + nf.format(lon()) + "°";
    143         }
    144        
    145         @Override public String toString() {
    146                 return "LatLon[lat="+lat()+",lon="+lon()+"]";
     102    /**
     103     * Computes the distance between this lat/lon and another point on the earth.
     104     * Uses spherical law of cosines formula, not Haversine.
     105     * @param other the other point.
     106     * @return distance in metres.
     107     */
     108    public double greatCircleDistance(LatLon other) {
     109        return (Math.acos(
     110            Math.sin(Math.toRadians(lat())) * Math.sin(Math.toRadians(other.lat())) +
     111            Math.cos(Math.toRadians(lat()))*Math.cos(Math.toRadians(other.lat())) *
     112                          Math.cos(Math.toRadians(other.lon()-lon()))) * 6378135);
     113    }
     114
     115    /**
     116     * Returns the heading, in radians, that you have to use to get from
     117     * this lat/lon to another.
     118     *
     119     * @param other the "destination" position
     120     * @return heading
     121     */
     122    public double heading(LatLon other) {
     123        double rv;
     124        if (other.lat() == lat()) {
     125            rv = (other.lon()>lon() ? Math.PI / 2 : Math.PI * 3 / 2);
     126        } else {
     127            rv = Math.atan((other.lon()-lon())/(other.lat()-lat()));
     128            if (rv < 0) rv += Math.PI;
     129            if (other.lon() < lon()) rv += Math.PI;
     130        }
     131        return rv;
     132    }
     133
     134    /**
     135     * Returns this lat/lon pair in human-readable format.
     136     *
     137     * @return String in the format "lat=1.23456°, lon=2.34567°"
     138     */
     139    public String toDisplayString() {
     140        NumberFormat nf = NumberFormat.getInstance();
     141        nf.setMaximumFractionDigits(5);
     142        return "lat=" + nf.format(lat()) + "°, lon=" + nf.format(lon()) + "°";
     143    }
     144
     145    @Override public String toString() {
     146        return "LatLon[lat="+lat()+",lon="+lon()+"]";
    147147    }
    148148}
  • trunk/src/org/openstreetmap/josm/data/gpx/GpxData.java

    r655 r1169  
    1515 * It uses GPX v1.1, see {@link <a href="http://www.topografix.com/GPX/1/1/">the spec</a>}
    1616 * for details.
    17  * 
     17 *
    1818 * @author Raphael Mack <ramack@raphael-mack.de>
    1919 */
    2020public class GpxData extends WithAttributes {
    21         public File storageFile;
    22         public boolean fromServer;
     21    public File storageFile;
     22    public boolean fromServer;
    2323
    24         public Collection<GpxTrack> tracks = new LinkedList<GpxTrack>();
    25         public Collection<GpxRoute> routes = new LinkedList<GpxRoute>();
    26         public Collection<WayPoint> waypoints = new LinkedList<WayPoint>();
     24    public Collection<GpxTrack> tracks = new LinkedList<GpxTrack>();
     25    public Collection<GpxRoute> routes = new LinkedList<GpxRoute>();
     26    public Collection<WayPoint> waypoints = new LinkedList<WayPoint>();
    2727
    28         public Bounds bounds;
     28    public Bounds bounds;
    2929
    30         public void mergeFrom(GpxData other) {
    31                 if (storageFile == null && other.storageFile != null) {
    32                         storageFile = other.storageFile;
    33                 }
    34                 fromServer = fromServer && other.fromServer;
     30    public void mergeFrom(GpxData other) {
     31        if (storageFile == null && other.storageFile != null) {
     32            storageFile = other.storageFile;
     33        }
     34        fromServer = fromServer && other.fromServer;
    3535
    36                 for (Map.Entry<String, Object> ent : other.attr.entrySet()) {
    37                         // TODO: Detect conflicts.
    38                         String k = ent.getKey();
    39                         if (k.equals("link") && attr.containsKey("link")) {
    40                                 ((Collection<GpxLink>) attr.get("link")).addAll(
    41                                         (Collection<GpxLink>) ent.getValue());
    42                         } else {
    43                                 attr.put(k, ent.getValue());
    44                         }
    45                 }
    46                 tracks.addAll(other.tracks);
    47                 routes.addAll(other.routes);
    48                 waypoints.addAll(other.waypoints);
    49         }
     36        for (Map.Entry<String, Object> ent : other.attr.entrySet()) {
     37            // TODO: Detect conflicts.
     38            String k = ent.getKey();
     39            if (k.equals("link") && attr.containsKey("link")) {
     40                ((Collection<GpxLink>) attr.get("link")).addAll(
     41                    (Collection<GpxLink>) ent.getValue());
     42            } else {
     43                attr.put(k, ent.getValue());
     44            }
     45        }
     46        tracks.addAll(other.tracks);
     47        routes.addAll(other.routes);
     48        waypoints.addAll(other.waypoints);
     49    }
    5050
    51         public boolean hasTrackPoints() {
    52                 for (GpxTrack trk : tracks) {
    53                         for (Collection<WayPoint> trkseg : trk.trackSegs) {
    54                                 if (!trkseg.isEmpty())
    55                                         return true;
    56                         }
    57                 }
    58                 return false;
    59         }
     51    public boolean hasTrackPoints() {
     52        for (GpxTrack trk : tracks) {
     53            for (Collection<WayPoint> trkseg : trk.trackSegs) {
     54                if (!trkseg.isEmpty())
     55                    return true;
     56            }
     57        }
     58        return false;
     59    }
    6060
    61         public boolean hasRoutePoints() {
    62                 for (GpxRoute rte : routes) {
    63                         if (!rte.routePoints.isEmpty())
    64                                 return true;
    65                 }
    66                 return false;
    67         }
     61    public boolean hasRoutePoints() {
     62        for (GpxRoute rte : routes) {
     63            if (!rte.routePoints.isEmpty())
     64                return true;
     65        }
     66        return false;
     67    }
    6868
    69         // FIXME might perhaps use visitor pattern?
    70         public void recalculateBounds() {
    71                 bounds = null;
    72                 for (WayPoint wpt : waypoints) {
    73                         if (bounds == null) {
    74                                 bounds = new Bounds(wpt.latlon, wpt.latlon);
    75                         } else {
    76                                 bounds.extend(wpt.latlon);
    77                         }
    78                 }
    79                 for (GpxRoute rte : routes) {
    80                         for (WayPoint wpt : rte.routePoints) {
    81                                 if (bounds == null) {
    82                                         bounds = new Bounds(wpt.latlon, wpt.latlon);
    83                                 } else {
    84                                         bounds.extend(wpt.latlon);
    85                                 }
    86                         }
    87                 }
    88                 for (GpxTrack trk : tracks) {
    89                         for (Collection<WayPoint> trkseg : trk.trackSegs) {
    90                                 for (WayPoint wpt : trkseg) {
    91                                         if (bounds == null) {
    92                                                 bounds = new Bounds(wpt.latlon, wpt.latlon);
    93                                         } else {
    94                                                 bounds.extend(wpt.latlon);
    95                                         }
    96                                 }
    97                         }
    98                 }
    99                 if (bounds == null) {
    100                         bounds = new Bounds();
    101                 }
    102         }
    103    
     69    // FIXME might perhaps use visitor pattern?
     70    public void recalculateBounds() {
     71        bounds = null;
     72        for (WayPoint wpt : waypoints) {
     73            if (bounds == null) {
     74                bounds = new Bounds(wpt.latlon, wpt.latlon);
     75            } else {
     76                bounds.extend(wpt.latlon);
     77            }
     78        }
     79        for (GpxRoute rte : routes) {
     80            for (WayPoint wpt : rte.routePoints) {
     81                if (bounds == null) {
     82                    bounds = new Bounds(wpt.latlon, wpt.latlon);
     83                } else {
     84                    bounds.extend(wpt.latlon);
     85                }
     86            }
     87        }
     88        for (GpxTrack trk : tracks) {
     89            for (Collection<WayPoint> trkseg : trk.trackSegs) {
     90                for (WayPoint wpt : trkseg) {
     91                    if (bounds == null) {
     92                        bounds = new Bounds(wpt.latlon, wpt.latlon);
     93                    } else {
     94                        bounds.extend(wpt.latlon);
     95                    }
     96                }
     97            }
     98        }
     99        if (bounds == null) {
     100            bounds = new Bounds();
     101        }
     102    }
     103
    104104    /**
    105105     * calculates the sum of the lengths of all track segments
     
    108108        double result = 0.0; // in meters
    109109        WayPoint last = null;
    110                
     110
    111111        for (GpxTrack trk : tracks) {
    112112            for (Collection<WayPoint> trkseg : trk.trackSegs) {
     
    129129        double lat1, lon1, lat2, lon2;
    130130        double dlon, dlat;
    131            
     131
    132132        lat1 = p1.lat() * Math.PI / 180.0;
    133133        lon1 = p1.lon() * Math.PI / 180.0;
  • trunk/src/org/openstreetmap/josm/data/gpx/GpxLink.java

    r627 r1169  
    55
    66public class GpxLink {
    7         public String uri;
    8         public String text;
    9         public String type;
     7    public String uri;
     8    public String text;
     9    public String type;
    1010
    11         public GpxLink(String uri) {
    12                 this.uri = uri;
    13         }
     11    public GpxLink(String uri) {
     12        this.uri = uri;
     13    }
    1414}
  • trunk/src/org/openstreetmap/josm/data/gpx/GpxRoute.java

    r627 r1169  
    88
    99public class GpxRoute extends WithAttributes {
    10         public Collection<WayPoint> routePoints = new LinkedList<WayPoint>();
     10    public Collection<WayPoint> routePoints = new LinkedList<WayPoint>();
    1111}
  • trunk/src/org/openstreetmap/josm/data/gpx/GpxTrack.java

    r627 r1169  
    88
    99public class GpxTrack extends WithAttributes {
    10         public Collection<Collection<WayPoint>> trackSegs
    11                 = new LinkedList<Collection<WayPoint>>();
     10    public Collection<Collection<WayPoint>> trackSegs
     11        = new LinkedList<Collection<WayPoint>>();
    1212}
  • trunk/src/org/openstreetmap/josm/data/gpx/WayPoint.java

    r1167 r1169  
    1515public class WayPoint extends WithAttributes implements Comparable<WayPoint>
    1616{
    17         public final LatLon latlon;
    18         public final EastNorth eastNorth;
    19         public double time;
    20         public Color speedLineColor;
    21         public boolean drawLine;
    22         public int dir;
     17    public final LatLon latlon;
     18    public final EastNorth eastNorth;
     19    public double time;
     20    public Color speedLineColor;
     21    public boolean drawLine;
     22    public int dir;
    2323
    24         public WayPoint(LatLon ll) {
    25                 latlon = ll;
    26                 eastNorth = Main.proj.latlon2eastNorth(ll);
    27         }
     24    public WayPoint(LatLon ll) {
     25        latlon = ll;
     26        eastNorth = Main.proj.latlon2eastNorth(ll);
     27    }
    2828
    29         @Override
    30         public String toString() {
    31                 return "WayPoint (" + (attr.containsKey("name") ? attr.get("name") + ", " :"") + latlon.toString() + ", " + attr + ")";
    32         }
    33        
    34         /**
    35          * Convert the time stamp of the waypoint into seconds from the epoch
    36          */
    37         public final static SimpleDateFormat GPXTIMEFMT =
    38                 new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); // ignore timezone
    39        
    40         public void setTime() {
    41                 if (! attr.containsKey("time")) {
    42                         return;
    43                 }
    44                 Date d = GPXTIMEFMT.parse(attr.get("time").toString(), new ParsePosition(0));
    45                 if (d != null /* parsing ok */) {
    46                         time = d.getTime() / 1000.0; /* ms => seconds */
    47                 }
    48         }
     29    @Override
     30    public String toString() {
     31        return "WayPoint (" + (attr.containsKey("name") ? attr.get("name") + ", " :"") + latlon.toString() + ", " + attr + ")";
     32    }
    4933
    50         /**
    51          * Convert a time stamp of the waypoint from the <cmt> or <desc> field
    52          * into seconds from the epoch. Handles the date format as it is used by
    53          * Garmin handhelds. Does not overwrite an existing timestamp (!= 0.0).
    54          * A value of <time> fields overwrites values set with by method.
    55          * Does nothing if specified key does not exist or text cannot be parsed.
    56          *
    57          * @param key The key that contains the text to convert.
    58          */
    59         public void setGarminCommentTime(String key) {
    60                 // do not overwrite time if already set
    61                 if (time != 0.0) {
    62                         return;
    63                 }
    64                 if (! attr.containsKey(key)) {
    65                         return;
    66                 }
    67                 // example date format "18-AUG-08 13:33:03"
    68                 SimpleDateFormat f = new SimpleDateFormat("dd-MMM-yy HH:mm:ss"); // Garmin wpts have no timezone
    69                 Date d = f.parse(attr.get(key).toString(), new ParsePosition(0));
    70                 if (d != null /* parsing OK */) {
    71                         time = d.getTime() / 1000.0; /* ms => seconds */
    72                 }
    73         }
     34    /**
     35     * Convert the time stamp of the waypoint into seconds from the epoch
     36     */
     37    public final static SimpleDateFormat GPXTIMEFMT =
     38        new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); // ignore timezone
    7439
    75         public int compareTo(WayPoint w)
    76         {
    77                 return Double.compare(time, w.time);
    78         }
     40    public void setTime() {
     41        if (! attr.containsKey("time")) {
     42            return;
     43        }
     44        Date d = GPXTIMEFMT.parse(attr.get("time").toString(), new ParsePosition(0));
     45        if (d != null /* parsing ok */) {
     46            time = d.getTime() / 1000.0; /* ms => seconds */
     47        }
     48    }
     49
     50    /**
     51     * Convert a time stamp of the waypoint from the <cmt> or <desc> field
     52     * into seconds from the epoch. Handles the date format as it is used by
     53     * Garmin handhelds. Does not overwrite an existing timestamp (!= 0.0).
     54     * A value of <time> fields overwrites values set with by method.
     55     * Does nothing if specified key does not exist or text cannot be parsed.
     56     *
     57     * @param key The key that contains the text to convert.
     58     */
     59    public void setGarminCommentTime(String key) {
     60        // do not overwrite time if already set
     61        if (time != 0.0) {
     62            return;
     63        }
     64        if (! attr.containsKey(key)) {
     65            return;
     66        }
     67        // example date format "18-AUG-08 13:33:03"
     68        SimpleDateFormat f = new SimpleDateFormat("dd-MMM-yy HH:mm:ss"); // Garmin wpts have no timezone
     69        Date d = f.parse(attr.get(key).toString(), new ParsePosition(0));
     70        if (d != null /* parsing OK */) {
     71            time = d.getTime() / 1000.0; /* ms => seconds */
     72        }
     73    }
     74
     75    public int compareTo(WayPoint w)
     76    {
     77        return Double.compare(time, w.time);
     78    }
    7979}
  • trunk/src/org/openstreetmap/josm/data/gpx/WithAttributes.java

    r627 r1169  
    1 // License: GPL. 
     1// License: GPL.
    22package org.openstreetmap.josm.data.gpx;
    33
     
    99 * The "attr" hash is used to store the XML payload
    1010 * (not only XML attributes!)
    11  * 
     11 *
    1212 * @author Frederik Ramm <frederik@remote.org>
    1313 *
    1414 */
    1515public class WithAttributes {
    16        
    17         public Map<String, Object> attr = new HashMap<String, Object>(0);
    18        
    19         public String getString(String key) {
    20                 Object value = attr.get(key);
    21                 return (value instanceof String) ? (String)value : null;
    22         }
     16
     17    public Map<String, Object> attr = new HashMap<String, Object>(0);
     18
     19    public String getString(String key) {
     20        Object value = attr.get(key);
     21        return (value instanceof String) ? (String)value : null;
     22    }
    2323}
  • trunk/src/org/openstreetmap/josm/data/osm/Changeset.java

    r655 r1169  
    2020 */
    2121public final class Changeset /*extends OsmPrimitive*/ implements OsmWriterInterface {
    22         /**
    23         * The key/value list for this primitive.
    24         */
    25         public Map<String, String> keys;
     22    /**
     23    * The key/value list for this primitive.
     24    */
     25    public Map<String, String> keys;
    2626
    27         public long id = 0;
    28        
    29         /**
    30         * User that created this changeset, as specified by the server.
    31         * Never changed by JOSM.
    32         */
    33         public User user = null;
    34        
    35         /**
    36         * Time of last modification to this object. This is not set by JOSM but
    37         * read from the server and delivered back to the server unmodified. 
    38         */
    39         public String end_timestamp = null;
    40        
    41         /**
    42         * Time of first modification to this object. This is not set by JOSM but
    43         * read from the server and delivered back to the server unmodified.
    44         */
    45         public String start_timestamp = null;
     27    public long id = 0;
     28
     29    /**
     30    * User that created this changeset, as specified by the server.
     31    * Never changed by JOSM.
     32    */
     33    public User user = null;
     34
     35    /**
     36    * Time of last modification to this object. This is not set by JOSM but
     37    * read from the server and delivered back to the server unmodified.
     38    */
     39    public String end_timestamp = null;
     40
     41    /**
     42    * Time of first modification to this object. This is not set by JOSM but
     43    * read from the server and delivered back to the server unmodified.
     44    */
     45    public String start_timestamp = null;
    4646
    4747        private void addTags(PrintWriter out) {
     
    5353        }
    5454
    55         public final void header(PrintWriter out) {
    56                 out.print("<osm version='");
     55    public final void header(PrintWriter out) {
     56            out.print("<osm version='");
    5757                out.print(Main.pref.get("osm-server.version", "0.6"));
    5858                out.println("' generator='JOSM'>");
    59         }
    60         public final void write(PrintWriter out) {
    61                 out.print("  <changeset");
    62                 if (id != 0)
    63                         out.print(" id="+id);
    64                 if (this.user != null) {
    65                         out.print(" user='"+XmlWriter.encode(this.user.name)+"'");
    66                 }
    67                 out.println(">\n");
    68                 addTags( out );
    69                 out.println("  </changeset>");
    70         }
    71         public final void footer(PrintWriter out) {
    72                 out.println("</osm>");
    73         }
    74        
    75         /******************************************************
    76          * This tag stuff is copied from OsmPrimitive. Perhaps a changeset
    77          * really is a primitive, but it's not right now. Perhaps it should
    78          * be...
    79          ******************************************************/
    80          
    81         /**
    82          * Set the given value to the given key
    83          * @param key The key, for which the value is to be set.
    84          * @param value The value for the key.
    85          */
    86         public final void put(String key, String value) {
    87                 if (value == null)
    88                         remove(key);
    89                 else {
    90                         if (keys == null)
    91                                 keys = new HashMap<String, String>();
    92                         keys.put(key, value);
    93                 }
    94         }
    95         /**
    96          * Remove the given key from the list.
    97          */
    98         public final void remove(String key) {
    99                 if (keys != null) {
    100                         keys.remove(key);
    101                         if (keys.isEmpty())
    102                                 keys = null;
    103                 }
    104         }
     59    }
     60    public final void write(PrintWriter out) {
     61        out.print("  <changeset");
     62        if (id != 0)
     63            out.print(" id="+id);
     64        if (this.user != null) {
     65            out.print(" user='"+XmlWriter.encode(this.user.name)+"'");
     66        }
     67        out.println(">\n");
     68        addTags( out );
     69        out.println("  </changeset>");
     70    }
     71    public final void footer(PrintWriter out) {
     72        out.println("</osm>");
     73    }
    10574
    106         public final String get(String key) {
    107                 return keys == null ? null : keys.get(key);
    108         }
     75    /******************************************************
     76     * This tag stuff is copied from OsmPrimitive. Perhaps a changeset
     77     * really is a primitive, but it's not right now. Perhaps it should
     78     * be...
     79     ******************************************************/
    10980
    110         public final Collection<Entry<String, String>> entrySet() {
    111                 if (keys == null)
    112                         return Collections.emptyList();
    113                 return keys.entrySet();
    114         }
     81    /**
     82     * Set the given value to the given key
     83     * @param key The key, for which the value is to be set.
     84     * @param value The value for the key.
     85     */
     86    public final void put(String key, String value) {
     87        if (value == null)
     88            remove(key);
     89        else {
     90            if (keys == null)
     91                keys = new HashMap<String, String>();
     92            keys.put(key, value);
     93        }
     94    }
     95    /**
     96     * Remove the given key from the list.
     97     */
     98    public final void remove(String key) {
     99        if (keys != null) {
     100            keys.remove(key);
     101            if (keys.isEmpty())
     102                keys = null;
     103        }
     104    }
    115105
    116         public final Collection<String> keySet() {
    117                 if (keys == null)
    118                         return Collections.emptyList();
    119                 return keys.keySet();
    120         }
     106    public final String get(String key) {
     107        return keys == null ? null : keys.get(key);
     108    }
     109
     110    public final Collection<Entry<String, String>> entrySet() {
     111        if (keys == null)
     112            return Collections.emptyList();
     113        return keys.entrySet();
     114    }
     115
     116    public final Collection<String> keySet() {
     117        if (keys == null)
     118            return Collections.emptyList();
     119        return keys.keySet();
     120    }
    121121}
  • trunk/src/org/openstreetmap/josm/data/osm/DataSet.java

    r1004 r1169  
    1717 * DataSet is the data behind the application. It can consists of only a few points up to the whole
    1818 * osm database. DataSet's can be merged together, saved, (up/down/disk)loaded etc.
    19  * 
     19 *
    2020 * Note that DataSet is not an osm-primitive and so has no key association but a few members to
    2121 * store some information.
    22  * 
     22 *
    2323 * @author imi
    2424 */
     
    3333    /**
    3434     * All ways (Streets etc.) in the DataSet.
    35      * 
     35     *
    3636     * The way nodes are stored only in the way list.
    3737     */
     
    235235
    236236    // Provide well-defined sorting for collections of OsmPrimitives.
    237     // FIXME: probably not a good place to put this code. 
     237    // FIXME: probably not a good place to put this code.
    238238    public static OsmPrimitive[] sort(Collection<? extends OsmPrimitive> list) {
    239239        OsmPrimitive[] selArr = new OsmPrimitive[list.size()];
  • trunk/src/org/openstreetmap/josm/data/osm/DataSource.java

    r627 r1169  
    55
    66public class DataSource implements Cloneable {
    7         public final Bounds bounds;
    8         public final String origin;
    9        
    10         public DataSource(Bounds bounds, String origin) {
    11             this.bounds = bounds;
    12             this.origin = origin;
     7    public final Bounds bounds;
     8    public final String origin;
     9
     10    public DataSource(Bounds bounds, String origin) {
     11        this.bounds = bounds;
     12        this.origin = origin;
    1313    }
    1414
    15         @Override protected Object clone() throws CloneNotSupportedException {
    16             return new DataSource(bounds, origin);
     15    @Override protected Object clone() throws CloneNotSupportedException {
     16        return new DataSource(bounds, origin);
    1717    }
    1818}
  • trunk/src/org/openstreetmap/josm/data/osm/DateFormatter.java

    r627 r1169  
    99/**
    1010 * Outputs a date in a format suitable for an OSM XML file.
    11  * 
     11 *
    1212 * @author Brett Henderson
    1313 */
    1414public class DateFormatter {
    15        
    16         private GregorianCalendar calendar;
    17        
    18        
    19         /**
    20         * Creates a new instance.
    21         */
    22         public DateFormatter() {
    23                 calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
    24         }
    25        
    26        
    27         /**
    28         * Formats a date in XML format.
    29          *
    30         * @param date
    31         *            The date to be formatted.
    32         * @return The string representing the date.
    33         */
    34         public String format(Date date) {
    35                 StringBuilder result;
    36                 int year;
    37                 int month;
    38                 int day;
    39                 int hour;
    40                 int minute;
    41                 int second;
    42                
    43                 calendar.setTime(date);
    44                
    45                 result = new StringBuilder(20);
    46                
    47                 year = calendar.get(Calendar.YEAR);
    48                 month = calendar.get(Calendar.MONTH) + 1;
    49                 day = calendar.get(Calendar.DATE);
    50                 hour = calendar.get(Calendar.HOUR_OF_DAY);
    51                 minute = calendar.get(Calendar.MINUTE);
    52                 second = calendar.get(Calendar.SECOND);
    53                
    54                 result.append(year);
    55                 result.append('-');
    56                 if (month < 10) {
    57                         result.append('0');
    58                 }
    59                 result.append(month);
    60                 result.append('-');
    61                 if (day < 10) {
    62                         result.append('0');
    63                 }
    64                 result.append(day);
    65                 result.append('T');
    66                 if (hour < 10) {
    67                         result.append('0');
    68                 }
    69                 result.append(hour);
    70                 result.append(':');
    71                 if (minute < 10) {
    72                         result.append('0');
    73                 }
    74                 result.append(minute);
    75                 result.append(':');
    76                 if (second < 10) {
    77                         result.append('0');
    78                 }
    79                 result.append(second);
    80                 result.append('Z');
    81                
    82                 return result.toString();
    83         }
     15
     16    private GregorianCalendar calendar;
     17
     18
     19    /**
     20    * Creates a new instance.
     21    */
     22    public DateFormatter() {
     23        calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
     24    }
     25
     26
     27    /**
     28    * Formats a date in XML format.
     29     *
     30    * @param date
     31    *            The date to be formatted.
     32    * @return The string representing the date.
     33    */
     34    public String format(Date date) {
     35        StringBuilder result;
     36        int year;
     37        int month;
     38        int day;
     39        int hour;
     40        int minute;
     41        int second;
     42
     43        calendar.setTime(date);
     44
     45        result = new StringBuilder(20);
     46
     47        year = calendar.get(Calendar.YEAR);
     48        month = calendar.get(Calendar.MONTH) + 1;
     49        day = calendar.get(Calendar.DATE);
     50        hour = calendar.get(Calendar.HOUR_OF_DAY);
     51        minute = calendar.get(Calendar.MINUTE);
     52        second = calendar.get(Calendar.SECOND);
     53
     54        result.append(year);
     55        result.append('-');
     56        if (month < 10) {
     57            result.append('0');
     58        }
     59        result.append(month);
     60        result.append('-');
     61        if (day < 10) {
     62            result.append('0');
     63        }
     64        result.append(day);
     65        result.append('T');
     66        if (hour < 10) {
     67            result.append('0');
     68        }
     69        result.append(hour);
     70        result.append(':');
     71        if (minute < 10) {
     72            result.append('0');
     73        }
     74        result.append(minute);
     75        result.append(':');
     76        if (second < 10) {
     77            result.append('0');
     78        }
     79        result.append(second);
     80        result.append('Z');
     81
     82        return result.toString();
     83    }
    8484}
  • trunk/src/org/openstreetmap/josm/data/osm/Node.java

    r1108 r1169  
    1919 */
    2020public final class Node extends OsmPrimitive {
    21        
    22         public LatLon coor;
    23         public volatile EastNorth eastNorth;
    24    
     21
     22    public LatLon coor;
     23    public volatile EastNorth eastNorth;
     24
    2525    private static CoordinateFormat mCord;
    26    
     26
    2727    static {
    2828        try {
     
    3333    }
    3434
    35         /**
    36          * Create an incomplete Node object
    37          */
    38         public Node(long id) {
    39                 this.id = id;
    40                 incomplete = true;
    41         }
    42        
    43         /**
    44          * Create an identical clone of the argument (including the id)
    45          */
    46         public Node(Node clone) {
    47                 cloneFrom(clone);
    48         }
     35    /**
     36     * Create an incomplete Node object
     37     */
     38    public Node(long id) {
     39        this.id = id;
     40        incomplete = true;
     41    }
    4942
    50         public Node(LatLon latlon) {
    51                 this.coor = latlon;
    52                 eastNorth = Main.proj.latlon2eastNorth(latlon);
    53         }
     43    /**
     44     * Create an identical clone of the argument (including the id)
     45     */
     46    public Node(Node clone) {
     47        cloneFrom(clone);
     48    }
    5449
    55         @Override public void visit(Visitor visitor) {
    56                 visitor.visit(this);
    57         }
    58        
    59         @Override public void cloneFrom(OsmPrimitive osm) {
    60                 super.cloneFrom(osm);
    61                 coor = ((Node)osm).coor;
    62                 eastNorth = ((Node)osm).eastNorth;
    63         }
     50    public Node(LatLon latlon) {
     51        this.coor = latlon;
     52        eastNorth = Main.proj.latlon2eastNorth(latlon);
     53    }
    6454
    65         @Override public String toString() {
    66                 if (coor == null) return "{Node id="+id+"}";
    67                 return "{Node id="+id+",version="+version+",lat="+coor.lat()+",lon="+coor.lon()+"}";
    68         }
     55    @Override public void visit(Visitor visitor) {
     56        visitor.visit(this);
     57    }
    6958
    70         @Override public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) {
    71                 if (osm instanceof Node) {
     59    @Override public void cloneFrom(OsmPrimitive osm) {
     60        super.cloneFrom(osm);
     61        coor = ((Node)osm).coor;
     62        eastNorth = ((Node)osm).eastNorth;
     63    }
     64
     65    @Override public String toString() {
     66        if (coor == null) return "{Node id="+id+"}";
     67        return "{Node id="+id+",version="+version+",lat="+coor.lat()+",lon="+coor.lon()+"}";
     68    }
     69
     70    @Override public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) {
     71        if (osm instanceof Node) {
    7272            if (super.realEqual(osm, semanticOnly)) {
    7373                if ((coor == null) && ((Node)osm).coor == null)
     
    8080    }
    8181
    82         public int compareTo(OsmPrimitive o) {
    83             return o instanceof Node ? Long.valueOf(id).compareTo(o.id) : 1;
    84         }
     82    public int compareTo(OsmPrimitive o) {
     83        return o instanceof Node ? Long.valueOf(id).compareTo(o.id) : 1;
     84    }
    8585
    86         public String getName() {
    87                 String name;
    88                 if (incomplete) {
    89                         name = tr("incomplete");
    90                 } else {
    91                         name = get("name");
    92                         if (name == null)
    93                                 name = id == 0 ? "" : ""+id;
    94                         name += " (" + coor.latToString(mCord) + ", " + coor.lonToString(mCord) + ")";
    95                 }
    96                 return name;
    97         }
     86    public String getName() {
     87        String name;
     88        if (incomplete) {
     89            name = tr("incomplete");
     90        } else {
     91            name = get("name");
     92            if (name == null)
     93                name = id == 0 ? "" : ""+id;
     94            name += " (" + coor.latToString(mCord) + ", " + coor.lonToString(mCord) + ")";
     95        }
     96        return name;
     97    }
    9898}
  • trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java

    r795 r1169  
    3030abstract public class OsmPrimitive implements Comparable<OsmPrimitive> {
    3131
    32         /**
    33         * The key/value list for this primitive.
    34         */
    35         public Map<String, String> keys;
    36 
    37         /**
    38         * Unique identifier in OSM. This is used to identify objects on the server.
    39         * An id of 0 means an unknown id. The object has not been uploaded yet to
    40         * know what id it will get.
    41         *
    42         * Do not write to this attribute except you know exactly what you are doing.
    43         * More specific, it is not good to set this to 0 and think the object is now
    44         * new to the server! To create a new object, call the default constructor of
    45         * the respective class.
    46         */
    47         public long id = 0;
    48 
    49         /**
    50         * <code>true</code> if the object has been modified since it was loaded from
    51         * the server. In this case, on next upload, this object will be updated.
    52         * Deleted objects are deleted from the server. If the objects are added (id=0),
    53         * the modified is ignored and the object is added to the server.
    54         */
    55         public boolean modified = false;
    56 
    57         /**
    58         * <code>true</code>, if the object has been deleted.
    59         */
    60         public boolean deleted = false;
    61 
    62         /**
    63         * Visibility status as specified by the server. The visible attribute was
    64         * introduced with the 0.4 API to be able to communicate deleted objects
    65         * (they will have visible=false). Currently JOSM does never deal with
    66         * these, so this is really for future use only.
    67         */
    68         public boolean visible = true;
    69 
    70         /**
    71         * User that last modified this primitive, as specified by the server.
    72         * Never changed by JOSM.
    73         */
    74         public User user = null;
    75 
    76         /**
    77         * true if this object is considered "tagged". To be "tagged", an object
    78         * must have one or more "non-standard" tags. "created_by" and "source"
    79         * are typically considered "standard" tags and do not make an object
    80         * "tagged".
    81         */
    82         public boolean tagged = false;
    83 
    84         /**
    85         * true if this object has direction dependent tags (e.g. oneway)
    86         */
    87         public boolean hasDirectionKeys = false;
    88 
    89         /**
    90         * If set to true, this object is currently selected.
    91         */
    92         public volatile boolean selected = false;
    93 
    94         /**
    95         * Time of last modification to this object. This is not set by JOSM but
    96         * read from the server and delivered back to the server unmodified. It is
    97         * used to check against edit conflicts.
    98         */
    99         public String timestamp = null;
    100 
    101         /**
    102         * The timestamp is only parsed when this is really necessary, and this
    103         * is the cache for the result.
    104         */
    105         public Date parsedTimestamp = null;
    106 
    107         /**
    108         * If set to true, this object is incomplete, which means only the id
    109         * and type is known (type is the objects instance class)
    110         */
    111         public boolean incomplete = false;
    112 
    113         /**
    114         * Contains the version number as returned by the API. Needed to
    115         * ensure update consistency
    116         */
    117         public int version = -1;
    118 
    119         /**
    120         * Contains a list of "uninteresting" keys that do not make an object
    121         * "tagged".
    122         * Initialized by checkTagged()
    123         */
    124         private static Collection<String> uninteresting = null;
    125 
    126         /**
    127         * Contains a list of direction-dependent keys that make an object
    128         * direction dependent.
    129         * Initialized by checkDirectionTagged()
    130         */
    131         private static Collection<String> directionKeys = null;
    132 
    133         /**
    134         * Implementation of the visitor scheme. Subclasses have to call the correct
    135         * visitor function.
    136         * @param visitor The visitor from which the visit() function must be called.
    137         */
    138         abstract public void visit(Visitor visitor);
    139 
    140         public final void delete(boolean deleted) {
    141                 this.deleted = deleted;
    142                 selected = false;
    143                 modified = true;
    144         }
    145 
    146         /**
    147         * Returns the timestamp for this object, or the current time if none is set.
    148         * Internally, parses the timestamp from XML into a Date object and caches it
    149         * for possible repeated calls.
    150         */
    151         public Date getTimestamp() {
    152                 if (parsedTimestamp == null) {
    153                         try {
    154                                 parsedTimestamp = DateParser.parse(timestamp);
    155                         } catch (ParseException ex) {
    156                                 parsedTimestamp = new Date();
    157                         }
    158                 }
    159                 return parsedTimestamp;
    160         }
    161 
    162         /**
    163         * Equal, if the id (and class) is equal.
    164         *
    165         * An primitive is equal to its incomplete counter part.
    166         */
    167         @Override public boolean equals(Object obj) {
    168                 if (id == 0) return obj == this;
    169                 if (obj instanceof OsmPrimitive) { // not null too
    170                         return ((OsmPrimitive)obj).id == id && obj.getClass() == getClass();
    171                 }
    172                 return false;
    173         }
    174 
    175         /**
    176         * Return the id plus the class type encoded as hashcode or super's hashcode if id is 0.
    177         *
    178         * An primitive has the same hashcode as its incomplete counterpart.
    179         */
    180         @Override public final int hashCode() {
    181                 if (id == 0)
    182                         return super.hashCode();
    183                 final int[] ret = new int[1];
    184                 Visitor v = new Visitor(){
    185                         public void visit(Node n) { ret[0] = 1; }
    186                         public void visit(Way w) { ret[0] = 2; }
    187                         public void visit(Relation e) { ret[0] = 3; }
    188                 };
    189                 visit(v);
    190                 return id == 0 ? super.hashCode() : (int)(id<<2)+ret[0];
    191         }
    192 
    193         /**
    194         * Set the given value to the given key
    195         * @param key The key, for which the value is to be set.
    196         * @param value The value for the key.
    197         */
    198         public final void put(String key, String value) {
    199                 if (value == null)
    200                         remove(key);
    201                 else {
    202                         if (keys == null)
    203                                 keys = new HashMap<String, String>();
    204                         keys.put(key, value);
    205                 }
    206                 checkTagged();
    207                 checkDirectionTagged();
    208         }
    209         /**
    210         * Remove the given key from the list.
    211         */
    212         public final void remove(String key) {
    213                 if (keys != null) {
    214                         keys.remove(key);
    215                         if (keys.isEmpty())
    216                                 keys = null;
    217                 }
    218                 checkTagged();
    219                 checkDirectionTagged();
    220         }
    221 
    222         public String getName() {
    223                 return null;
    224         }
    225 
    226         public final String get(String key) {
    227                 return keys == null ? null : keys.get(key);
    228         }
    229 
    230         public final Collection<Entry<String, String>> entrySet() {
    231                 if (keys == null)
    232                         return Collections.emptyList();
    233                 return keys.entrySet();
    234         }
    235 
    236         public final Collection<String> keySet() {
    237                 if (keys == null)
    238                         return Collections.emptyList();
    239                 return keys.keySet();
    240         }
    241 
    242         /**
    243         * Get and write all attributes from the parameter. Does not fire any listener, so
    244         * use this only in the data initializing phase
    245         */
    246         public void cloneFrom(OsmPrimitive osm) {
    247                 keys = osm.keys == null ? null : new HashMap<String, String>(osm.keys);
    248                 id = osm.id;
    249                 modified = osm.modified;
    250                 deleted = osm.deleted;
    251                 selected = osm.selected;
    252                 timestamp = osm.timestamp;
    253                 version = osm.version;
    254                 tagged = osm.tagged;
    255                 incomplete = osm.incomplete;
    256         }
    257 
    258         /**
    259         * Perform an equality compare for all non-volatile fields not only for the id
    260         * but for the whole object (for conflict resolving)
    261         * @param semanticOnly if <code>true</code>, modified flag and timestamp are not compared
    262         */
    263         public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) {
    264                 return
    265                         id == osm.id &&
    266                         incomplete == osm.incomplete &&
    267                         (semanticOnly || (modified == osm.modified)) &&
    268                         deleted == osm.deleted &&
    269                         (semanticOnly || (timestamp == null ? osm.timestamp==null : timestamp.equals(osm.timestamp))) &&
    270                         (semanticOnly || (version==osm.version)) &&
    271                         (semanticOnly || (user == null ? osm.user==null : user==osm.user)) &&
    272                         (semanticOnly || (visible == osm.visible)) &&
    273                         (keys == null ? osm.keys==null : keys.equals(osm.keys));
    274         }
    275 
    276         public String getTimeStr() {
    277                 return timestamp == null ? null : new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(timestamp);
    278         }
    279 
    280         /**
    281         * Updates the "tagged" flag. "keys" property should probably be made private
    282         * to make sure this gets called when keys are set.
    283         */
    284         public void checkTagged() {
    285                 tagged = false;
    286                 if(uninteresting == null)
    287                         uninteresting = new HashSet<String>(Arrays.asList(Main.pref.get("tags.uninteresting",
    288                         "source;note;converted_by;created_by").split(";")));
    289                 if (keys != null) {
    290                         for (Entry<String,String> e : keys.entrySet()) {
    291                                 if (!uninteresting.contains(e.getKey())) {
    292                                         tagged = true;
    293                                         break;
    294                                 }
    295                         }
    296                 }
    297         }
    298         /**
    299         * Updates the "hasDirectionKeys" flag. "keys" property should probably be made private
    300         * to make sure this gets called when keys are set.
    301         */
    302         public void checkDirectionTagged() {
    303                 hasDirectionKeys = false;
    304                 if(directionKeys == null)
    305                         directionKeys = new HashSet<String>(Arrays.asList(Main.pref.get("tags.direction",
    306                         "oneway;incline;incline_step;aerialway").split(";")));
    307                 if (keys != null) {
    308                         for (Entry<String,String> e : keys.entrySet()) {
    309                                 if (directionKeys.contains(e.getKey())) {
    310                                         hasDirectionKeys = true;
    311                                         break;
    312                                 }
    313                         }
    314                 }
    315         }
     32    /**
     33    * The key/value list for this primitive.
     34    */
     35    public Map<String, String> keys;
     36
     37    /**
     38    * Unique identifier in OSM. This is used to identify objects on the server.
     39    * An id of 0 means an unknown id. The object has not been uploaded yet to
     40    * know what id it will get.
     41    *
     42    * Do not write to this attribute except you know exactly what you are doing.
     43    * More specific, it is not good to set this to 0 and think the object is now
     44    * new to the server! To create a new object, call the default constructor of
     45    * the respective class.
     46    */
     47    public long id = 0;
     48
     49    /**
     50    * <code>true</code> if the object has been modified since it was loaded from
     51    * the server. In this case, on next upload, this object will be updated.
     52    * Deleted objects are deleted from the server. If the objects are added (id=0),
     53    * the modified is ignored and the object is added to the server.
     54    */
     55    public boolean modified = false;
     56
     57    /**
     58    * <code>true</code>, if the object has been deleted.
     59    */
     60    public boolean deleted = false;
     61
     62    /**
     63    * Visibility status as specified by the server. The visible attribute was
     64    * introduced with the 0.4 API to be able to communicate deleted objects
     65    * (they will have visible=false). Currently JOSM does never deal with
     66    * these, so this is really for future use only.
     67    */
     68    public boolean visible = true;
     69
     70    /**
     71    * User that last modified this primitive, as specified by the server.
     72    * Never changed by JOSM.
     73    */
     74    public User user = null;
     75
     76    /**
     77    * true if this object is considered "tagged". To be "tagged", an object
     78    * must have one or more "non-standard" tags. "created_by" and "source"
     79    * are typically considered "standard" tags and do not make an object
     80    * "tagged".
     81    */
     82    public boolean tagged = false;
     83
     84    /**
     85    * true if this object has direction dependent tags (e.g. oneway)
     86    */
     87    public boolean hasDirectionKeys = false;
     88
     89    /**
     90    * If set to true, this object is currently selected.
     91    */
     92    public volatile boolean selected = false;
     93
     94    /**
     95    * Time of last modification to this object. This is not set by JOSM but
     96    * read from the server and delivered back to the server unmodified. It is
     97    * used to check against edit conflicts.
     98    */
     99    public String timestamp = null;
     100
     101    /**
     102    * The timestamp is only parsed when this is really necessary, and this
     103    * is the cache for the result.
     104    */
     105    public Date parsedTimestamp = null;
     106
     107    /**
     108    * If set to true, this object is incomplete, which means only the id
     109    * and type is known (type is the objects instance class)
     110    */
     111    public boolean incomplete = false;
     112
     113    /**
     114    * Contains the version number as returned by the API. Needed to
     115    * ensure update consistency
     116    */
     117    public int version = -1;
     118
     119    /**
     120    * Contains a list of "uninteresting" keys that do not make an object
     121    * "tagged".
     122    * Initialized by checkTagged()
     123    */
     124    private static Collection<String> uninteresting = null;
     125
     126    /**
     127    * Contains a list of direction-dependent keys that make an object
     128    * direction dependent.
     129    * Initialized by checkDirectionTagged()
     130    */
     131    private static Collection<String> directionKeys = null;
     132
     133    /**
     134    * Implementation of the visitor scheme. Subclasses have to call the correct
     135    * visitor function.
     136    * @param visitor The visitor from which the visit() function must be called.
     137    */
     138    abstract public void visit(Visitor visitor);
     139
     140    public final void delete(boolean deleted) {
     141        this.deleted = deleted;
     142        selected = false;
     143        modified = true;
     144    }
     145
     146    /**
     147    * Returns the timestamp for this object, or the current time if none is set.
     148    * Internally, parses the timestamp from XML into a Date object and caches it
     149    * for possible repeated calls.
     150    */
     151    public Date getTimestamp() {
     152        if (parsedTimestamp == null) {
     153            try {
     154                parsedTimestamp = DateParser.parse(timestamp);
     155            } catch (ParseException ex) {
     156                parsedTimestamp = new Date();
     157            }
     158        }
     159        return parsedTimestamp;
     160    }
     161
     162    /**
     163    * Equal, if the id (and class) is equal.
     164    *
     165    * An primitive is equal to its incomplete counter part.
     166    */
     167    @Override public boolean equals(Object obj) {
     168        if (id == 0) return obj == this;
     169        if (obj instanceof OsmPrimitive) { // not null too
     170            return ((OsmPrimitive)obj).id == id && obj.getClass() == getClass();
     171        }
     172        return false;
     173    }
     174
     175    /**
     176    * Return the id plus the class type encoded as hashcode or super's hashcode if id is 0.
     177    *
     178    * An primitive has the same hashcode as its incomplete counterpart.
     179    */
     180    @Override public final int hashCode() {
     181        if (id == 0)
     182            return super.hashCode();
     183        final int[] ret = new int[1];
     184        Visitor v = new Visitor(){
     185            public void visit(Node n) { ret[0] = 1; }
     186            public void visit(Way w) { ret[0] = 2; }
     187            public void visit(Relation e) { ret[0] = 3; }
     188        };
     189        visit(v);
     190        return id == 0 ? super.hashCode() : (int)(id<<2)+ret[0];
     191    }
     192
     193    /**
     194    * Set the given value to the given key
     195    * @param key The key, for which the value is to be set.
     196    * @param value The value for the key.
     197    */
     198    public final void put(String key, String value) {
     199        if (value == null)
     200            remove(key);
     201        else {
     202            if (keys == null)
     203                keys = new HashMap<String, String>();
     204            keys.put(key, value);
     205        }
     206        checkTagged();
     207        checkDirectionTagged();
     208    }
     209    /**
     210    * Remove the given key from the list.
     211    */
     212    public final void remove(String key) {
     213        if (keys != null) {
     214            keys.remove(key);
     215            if (keys.isEmpty())
     216                keys = null;
     217        }
     218        checkTagged();
     219        checkDirectionTagged();
     220    }
     221
     222    public String getName() {
     223        return null;
     224    }
     225
     226    public final String get(String key) {
     227        return keys == null ? null : keys.get(key);
     228    }
     229
     230    public final Collection<Entry<String, String>> entrySet() {
     231        if (keys == null)
     232            return Collections.emptyList();
     233        return keys.entrySet();
     234    }
     235
     236    public final Collection<String> keySet() {
     237        if (keys == null)
     238            return Collections.emptyList();
     239        return keys.keySet();
     240    }
     241
     242    /**
     243    * Get and write all attributes from the parameter. Does not fire any listener, so
     244    * use this only in the data initializing phase
     245    */
     246    public void cloneFrom(OsmPrimitive osm) {
     247        keys = osm.keys == null ? null : new HashMap<String, String>(osm.keys);
     248        id = osm.id;
     249        modified = osm.modified;
     250        deleted = osm.deleted;
     251        selected = osm.selected;
     252        timestamp = osm.timestamp;
     253        version = osm.version;
     254        tagged = osm.tagged;
     255        incomplete = osm.incomplete;
     256    }
     257
     258    /**
     259    * Perform an equality compare for all non-volatile fields not only for the id
     260    * but for the whole object (for conflict resolving)
     261    * @param semanticOnly if <code>true</code>, modified flag and timestamp are not compared
     262    */
     263    public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) {
     264        return
     265            id == osm.id &&
     266            incomplete == osm.incomplete &&
     267            (semanticOnly || (modified == osm.modified)) &&
     268            deleted == osm.deleted &&
     269            (semanticOnly || (timestamp == null ? osm.timestamp==null : timestamp.equals(osm.timestamp))) &&
     270            (semanticOnly || (version==osm.version)) &&
     271            (semanticOnly || (user == null ? osm.user==null : user==osm.user)) &&
     272            (semanticOnly || (visible == osm.visible)) &&
     273            (keys == null ? osm.keys==null : keys.equals(osm.keys));
     274    }
     275
     276    public String getTimeStr() {
     277        return timestamp == null ? null : new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(timestamp);
     278    }
     279
     280    /**
     281    * Updates the "tagged" flag. "keys" property should probably be made private
     282    * to make sure this gets called when keys are set.
     283    */
     284    public void checkTagged() {
     285        tagged = false;
     286        if(uninteresting == null)
     287            uninteresting = new HashSet<String>(Arrays.asList(Main.pref.get("tags.uninteresting",
     288            "source;note;converted_by;created_by").split(";")));
     289        if (keys != null) {
     290            for (Entry<String,String> e : keys.entrySet()) {
     291                if (!uninteresting.contains(e.getKey())) {
     292                    tagged = true;
     293                    break;
     294                }
     295            }
     296        }
     297    }
     298    /**
     299    * Updates the "hasDirectionKeys" flag. "keys" property should probably be made private
     300    * to make sure this gets called when keys are set.
     301    */
     302    public void checkDirectionTagged() {
     303        hasDirectionKeys = false;
     304        if(directionKeys == null)
     305            directionKeys = new HashSet<String>(Arrays.asList(Main.pref.get("tags.direction",
     306            "oneway;incline;incline_step;aerialway").split(";")));
     307        if (keys != null) {
     308            for (Entry<String,String> e : keys.entrySet()) {
     309                if (directionKeys.contains(e.getKey())) {
     310                    hasDirectionKeys = true;
     311                    break;
     312                }
     313            }
     314        }
     315    }
    316316}
  • trunk/src/org/openstreetmap/josm/data/osm/OsmUtils.java

    r702 r1169  
    88public class OsmUtils {
    99
    10         static ArrayList<String> TRUE_VALUES = new ArrayList<String>(Arrays
    11                 .asList(new String[] { "true", "yes", "1", "on" }));
    12         static ArrayList<String> FALSE_VALUES = new ArrayList<String>(Arrays
    13                 .asList(new String[] { "false", "no", "0", "off" }));
     10    static ArrayList<String> TRUE_VALUES = new ArrayList<String>(Arrays
     11            .asList(new String[] { "true", "yes", "1", "on" }));
     12    static ArrayList<String> FALSE_VALUES = new ArrayList<String>(Arrays
     13            .asList(new String[] { "false", "no", "0", "off" }));
    1414
    15         public static final String trueval = "yes";
    16         public static final String falseval = "no";
     15    public static final String trueval = "yes";
     16    public static final String falseval = "no";
    1717
    18         public static Boolean getOsmBoolean(String value) {
    19                 if(value == null) return null;
    20                 String lowerValue = value.toLowerCase(Locale.ENGLISH);
    21                 if (TRUE_VALUES.contains(lowerValue)) return Boolean.TRUE;
    22                 if (FALSE_VALUES.contains(lowerValue)) return Boolean.FALSE;
    23                 return null;
    24         }
    25         public static String getNamedOsmBoolean(String value) {
    26                 Boolean res = getOsmBoolean(value);
    27                 return res == null ? value : (res ? trueval : falseval);
    28         }
     18    public static Boolean getOsmBoolean(String value) {
     19        if(value == null) return null;
     20        String lowerValue = value.toLowerCase(Locale.ENGLISH);
     21        if (TRUE_VALUES.contains(lowerValue)) return Boolean.TRUE;
     22        if (FALSE_VALUES.contains(lowerValue)) return Boolean.FALSE;
     23        return null;
     24    }
     25    public static String getNamedOsmBoolean(String value) {
     26        Boolean res = getOsmBoolean(value);
     27        return res == null ? value : (res ? trueval : falseval);
     28    }
    2929}
  • trunk/src/org/openstreetmap/josm/data/osm/Relation.java

    r1162 r1169  
    1111/**
    1212 * An relation, having a set of tags and any number (0...n) of members.
    13  * 
     13 *
    1414 * @author Frederik Ramm <frederik@remote.org>
    1515 */
    1616public final class Relation extends OsmPrimitive {
    17        
    18         /**
    19          * All members of this relation. Note that after changing this,
    20          * makeBackReferences and/or removeBackReferences should be called.
    21          */
    22         public final List<RelationMember> members = new ArrayList<RelationMember>();
    2317
    24         @Override public void visit(Visitor visitor) {
    25                 visitor.visit(this);
    26         }
     18    /**
     19     * All members of this relation. Note that after changing this,
     20     * makeBackReferences and/or removeBackReferences should be called.
     21     */
     22    public final List<RelationMember> members = new ArrayList<RelationMember>();
    2723
    28         /**
    29          * Create an identical clone of the argument (including the id)
    30          */
    31         public Relation(Relation clone) {
    32                 cloneFrom(clone);
    33         }
    34        
    35         /**
    36          * Create an incomplete Relation.
    37          */
    38         public Relation(long id) {
    39                 this.id = id;
    40                 incomplete = true;
    41         }
    42        
    43         /**
    44          * Create an empty Relation. Use this only if you set meaningful values
    45          * afterwards.
    46          */
    47         public Relation() {     
    48         }
    49        
    50         @Override public void cloneFrom(OsmPrimitive osm) {
    51                 super.cloneFrom(osm);
    52                 members.clear();
    53                 // we must not add the members themselves, but instead
    54                 // add clones of the members
    55                 for (RelationMember em : ((Relation)osm).members) {
    56                         members.add(new RelationMember(em));
    57                 }
    58         }
     24    @Override public void visit(Visitor visitor) {
     25        visitor.visit(this);
     26    }
    5927
    60         @Override public String toString() {
    61                 // return "{Relation id="+id+" version="+version+" members="+Arrays.toString(members.toArray())+"}";
    62                 // adding members in string increases memory usage a lot and overflows for looped relations
    63                 return "{Relation id="+id+" version="+version+"}";
    64         }
     28    /**
     29     * Create an identical clone of the argument (including the id)
     30     */
     31    public Relation(Relation clone) {
     32        cloneFrom(clone);
     33    }
    6534
    66         @Override public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) {
    67                 return osm instanceof Relation ? super.realEqual(osm, semanticOnly) && members.equals(((Relation)osm).members) : false;
    68         }
     35    /**
     36     * Create an incomplete Relation.
     37     */
     38    public Relation(long id) {
     39        this.id = id;
     40        incomplete = true;
     41    }
    6942
    70         public int compareTo(OsmPrimitive o) {
    71             return o instanceof Relation ? Long.valueOf(id).compareTo(o.id) : -1;
    72         }
     43    /**
     44     * Create an empty Relation. Use this only if you set meaningful values
     45     * afterwards.
     46     */
     47    public Relation() {
     48    }
    7349
    74         public String getName() {
    75                 String name;
    76                 if (incomplete) {
    77                         name = tr("incomplete");
    78                 } else {
    79                         name = get("type");
    80                         // FIXME add names of members
    81                         if (name == null)
    82                                 name = tr("relation");
    83                        
    84                         name += " (";
    85                         String nameTag = get("name");
    86                         if (nameTag == null) nameTag = get("ref");
    87                         if (nameTag == null) nameTag = get("note");
    88                         if (nameTag != null) name += "\"" + nameTag + "\", ";
    89                         int mbno = members.size();
    90                         name += trn("{0} member", "{0} members", mbno, mbno) + ")";
    91                 }
    92                 return name;
    93         }
     50    @Override public void cloneFrom(OsmPrimitive osm) {
     51        super.cloneFrom(osm);
     52        members.clear();
     53        // we must not add the members themselves, but instead
     54        // add clones of the members
     55        for (RelationMember em : ((Relation)osm).members) {
     56            members.add(new RelationMember(em));
     57        }
     58    }
    9459
    95         public boolean isIncomplete() {
    96                 for (RelationMember m : members)
    97                         if (m.member == null)
    98                                 return true;
    99                 return false;
    100         }
     60    @Override public String toString() {
     61        // return "{Relation id="+id+" version="+version+" members="+Arrays.toString(members.toArray())+"}";
     62        // adding members in string increases memory usage a lot and overflows for looped relations
     63        return "{Relation id="+id+" version="+version+"}";
     64    }
     65
     66    @Override public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) {
     67        return osm instanceof Relation ? super.realEqual(osm, semanticOnly) && members.equals(((Relation)osm).members) : false;
     68    }
     69
     70    public int compareTo(OsmPrimitive o) {
     71        return o instanceof Relation ? Long.valueOf(id).compareTo(o.id) : -1;
     72    }
     73
     74    public String getName() {
     75        String name;
     76        if (incomplete) {
     77            name = tr("incomplete");
     78        } else {
     79            name = get("type");
     80            // FIXME add names of members
     81            if (name == null)
     82                name = tr("relation");
     83
     84            name += " (";
     85            String nameTag = get("name");
     86            if (nameTag == null) nameTag = get("ref");
     87            if (nameTag == null) nameTag = get("note");
     88            if (nameTag != null) name += "\"" + nameTag + "\", ";
     89            int mbno = members.size();
     90            name += trn("{0} member", "{0} members", mbno, mbno) + ")";
     91        }
     92        return name;
     93    }
     94
     95    public boolean isIncomplete() {
     96        for (RelationMember m : members)
     97            if (m.member == null)
     98                return true;
     99        return false;
     100    }
    101101}
  • trunk/src/org/openstreetmap/josm/data/osm/RelationMember.java

    r627 r1169  
    22
    33/**
    4  * A linkage class that can be used by an relation to keep a list of 
     4 * A linkage class that can be used by an relation to keep a list of
    55 * members. Since membership may be qualified by a "role", a simple
    66 * list is not sufficient.
    7  * 
     7 *
    88 * @author Frederik Ramm <frederik@remote.org>
    99 */
    1010public class RelationMember {
    1111
    12         public String role;
    13         public OsmPrimitive member;
    14        
    15         /**
    16          * Default constructor. Does nothing.
    17          */
    18         public RelationMember() { }
     12    public String role;
     13    public OsmPrimitive member;
    1914
    20         public RelationMember(String role, OsmPrimitive member) {
    21                 this.role = role;
    22                 this.member = member;
    23         }
    24        
    25         /**
    26          * Copy constructor.
    27          * @param other relation member to be copied.
    28          */
    29         public RelationMember(RelationMember other) {
    30                 role = other.role;
    31                 member = other.member;
    32         }
    33        
    34         @Override public boolean equals(Object other) {
    35                 if (!(other instanceof RelationMember)) return false;
    36                 RelationMember otherMember = (RelationMember) other;
    37                 return otherMember.role.equals(role) && otherMember.member.equals(member);
    38         }
     15    /**
     16     * Default constructor. Does nothing.
     17     */
     18    public RelationMember() { }
    3919
    40         @Override public String toString() {
    41                 return '"' + role + "\"=" + member;
    42         }
     20    public RelationMember(String role, OsmPrimitive member) {
     21        this.role = role;
     22        this.member = member;
     23    }
     24
     25    /**
     26     * Copy constructor.
     27     * @param other relation member to be copied.
     28     */
     29    public RelationMember(RelationMember other) {
     30        role = other.role;
     31        member = other.member;
     32    }
     33
     34    @Override public boolean equals(Object other) {
     35        if (!(other instanceof RelationMember)) return false;
     36        RelationMember otherMember = (RelationMember) other;
     37        return otherMember.role.equals(role) && otherMember.member.equals(member);
     38    }
     39
     40    @Override public String toString() {
     41        return '"' + role + "\"=" + member;
     42    }
    4343}
  • trunk/src/org/openstreetmap/josm/data/osm/TigerUtils.java

    r627 r1169  
    55import java.util.TreeSet;
    66
    7 /** 
     7/**
    88 * A simple class to keep helper functions for merging TIGER data
    9  * 
     9 *
    1010 * @author daveh
    1111 *
    1212 */
    1313public class TigerUtils {
    14        
    15         public static boolean isTigerTag(String tag)
    16         {       
    17                 if (tag.indexOf("tiger:") == -1)
    18                         return false;
    19                 return true;
    20         }
    21        
    22         public static boolean tagIsInt(String name) {
    23                 if (name.equals("tiger:tlid"))
    24                         return true;
    25                 return false;
    26         }
    27        
    28         public static Object tagObj(String name) {
    29                 if (tagIsInt(name))
    30                         return new Integer(name);
    31                 return name;
    32         }
    33        
    34         public static String combineTags(String name, Set<String> values) {
     14
     15    public static boolean isTigerTag(String tag)
     16    {
     17        if (tag.indexOf("tiger:") == -1)
     18            return false;
     19        return true;
     20    }
     21
     22    public static boolean tagIsInt(String name) {
     23        if (name.equals("tiger:tlid"))
     24            return true;
     25        return false;
     26    }
     27
     28    public static Object tagObj(String name) {
     29        if (tagIsInt(name))
     30            return new Integer(name);
     31        return name;
     32    }
     33
     34    public static String combineTags(String name, Set<String> values) {
    3535        TreeSet<Object> resultSet = new TreeSet<Object>();
    3636        for (String value: values) {
    37                 for (String part: value.split(":")) {
     37            for (String part: value.split(":")) {
    3838               resultSet.add(tagObj(part));
    3939            }
     
    4242        for (Object part : resultSet) {
    4343            if (combined.length() > 0)
    44                         combined += ":";
    45                 combined += part;
     44                combined += ":";
     45            combined += part;
    4646        }
    47                 return combined;
    48         }
    49        
    50         public static String combineTags(String name, String t1, String t2) {
    51                 Set<String> set = new TreeSet<String>();
    52                 set.add(t1);
    53                 set.add(t2);
    54                 return TigerUtils.combineTags(name, set);
    55         }
     47        return combined;
     48    }
     49
     50    public static String combineTags(String name, String t1, String t2) {
     51        Set<String> set = new TreeSet<String>();
     52        set.add(t1);
     53        set.add(t2);
     54        return TigerUtils.combineTags(name, set);
     55    }
    5656}
  • trunk/src/org/openstreetmap/josm/data/osm/User.java

    r655 r1169  
    44import java.util.HashMap;
    55
    6 /** 
     6/**
    77 * A simple class to keep a list of user names.
    8  * 
     8 *
    99 * Instead of storing user names as strings with every OSM primitive, we store
    1010 * a reference to an user object, and make sure that for each username there
    1111 * is only one user object.
    12  * 
     12 *
    1313 * @author fred
    1414 *
     
    1616public class User {
    1717
    18         /** storage for existing User objects. */
    19         private static HashMap<String,User> userMap = new HashMap<String,User>();
    20        
    21         /** the username. */
    22         public String name;
    23        
    24         /** private constructor, only called from get method. */
    25         private User(String name) {
    26                 this.name = name;
    27         }
    28        
    29         /** returns a new or existing User object that represents the given name. */
    30         public static User get(String name) {
    31                 User user = userMap.get(name);
    32                 if (user == null) {
    33                         user = new User(name);
    34                         userMap.put(name, user);
    35                 }
    36                 return user;
    37         }
     18    /** storage for existing User objects. */
     19    private static HashMap<String,User> userMap = new HashMap<String,User>();
     20
     21    /** the username. */
     22    public String name;
     23
     24    /** private constructor, only called from get method. */
     25    private User(String name) {
     26        this.name = name;
     27    }
     28
     29    /** returns a new or existing User object that represents the given name. */
     30    public static User get(String name) {
     31        User user = userMap.get(name);
     32        if (user == null) {
     33            user = new User(name);
     34            userMap.put(name, user);
     35        }
     36        return user;
     37    }
    3838}
  • trunk/src/org/openstreetmap/josm/data/osm/Way.java

    r755 r1169  
    2121public final class Way extends OsmPrimitive {
    2222
    23         /**
    24         * All way nodes in this way
    25         */
    26         public final List<Node> nodes = new ArrayList<Node>();
     23    /**
     24    * All way nodes in this way
     25    */
     26    public final List<Node> nodes = new ArrayList<Node>();
    2727
    28         public void visitNodes(Visitor v) {
    29                 for (Node n : this.nodes)
    30                         v.visit(n);
    31         }
     28    public void visitNodes(Visitor v) {
     29        for (Node n : this.nodes)
     30            v.visit(n);
     31    }
    3232
    33         public ArrayList<Pair<Node,Node>> getNodePairs(boolean sort) {
    34                 ArrayList<Pair<Node,Node>> chunkSet = new ArrayList<Pair<Node,Node>>();
    35                 Node lastN = null;
    36                 for (Node n : this.nodes) {
     33    public ArrayList<Pair<Node,Node>> getNodePairs(boolean sort) {
     34        ArrayList<Pair<Node,Node>> chunkSet = new ArrayList<Pair<Node,Node>>();
     35        Node lastN = null;
     36        for (Node n : this.nodes) {
    3737            if (lastN == null) {
    38                     lastN = n;
    39                         continue;
    40                     }
    41                         Pair<Node,Node> np = new Pair<Node,Node>(lastN, n);
    42                 if (sort) {
    43                         Pair.sort(np);
    44                 }
    45                 chunkSet.add(np);
    46                 lastN = n;
    47                 }
    48                 return chunkSet;
    49         }
     38                lastN = n;
     39                continue;
     40            }
     41            Pair<Node,Node> np = new Pair<Node,Node>(lastN, n);
     42            if (sort) {
     43                Pair.sort(np);
     44            }
     45            chunkSet.add(np);
     46            lastN = n;
     47        }
     48        return chunkSet;
     49    }
    5050
    5151
    52         @Override public void visit(Visitor visitor) {
    53                 visitor.visit(this);
    54         }
     52    @Override public void visit(Visitor visitor) {
     53        visitor.visit(this);
     54    }
    5555
    56         /**
    57         * Create an identical clone of the argument (including the id)
    58         */
    59         public Way(Way clone) {
    60             cloneFrom(clone);           
    61         }
    62        
    63         /**
    64         * Create an empty way without id. Use this only if you set meaningful 
    65         * values yourself.
    66         */
    67         public Way() {
    68         }
    69        
    70         /**
    71         * Create an incomplete Way.
    72         */
    73         public Way(long id) {
    74                 this.id = id;
    75                 incomplete = true;
    76         }
    77        
    78         @Override public void cloneFrom(OsmPrimitive osm) {
    79                 super.cloneFrom(osm);
    80                 nodes.clear();
    81                 nodes.addAll(((Way)osm).nodes);
     56    /**
     57    * Create an identical clone of the argument (including the id)
     58    */
     59    public Way(Way clone) {
     60            cloneFrom(clone);
     61    }
     62
     63    /**
     64    * Create an empty way without id. Use this only if you set meaningful
     65    * values yourself.
     66    */
     67    public Way() {
     68    }
     69
     70    /**
     71    * Create an incomplete Way.
     72    */
     73    public Way(long id) {
     74        this.id = id;
     75        incomplete = true;
     76    }
     77
     78    @Override public void cloneFrom(OsmPrimitive osm) {
     79        super.cloneFrom(osm);
     80        nodes.clear();
     81        nodes.addAll(((Way)osm).nodes);
    8282                checkDirectionTagged();
    83         }
     83    }
    8484
    8585    @Override public String toString() {
     
    8787    }
    8888
    89         @Override public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) {
    90                 return osm instanceof Way ? super.realEqual(osm, semanticOnly) && nodes.equals(((Way)osm).nodes) : false;
     89    @Override public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) {
     90        return osm instanceof Way ? super.realEqual(osm, semanticOnly) && nodes.equals(((Way)osm).nodes) : false;
    9191    }
    9292
    93         public int compareTo(OsmPrimitive o) {
    94                 if(o instanceof Relation)
    95                         return 1;
    96                 return o instanceof Way ? Long.valueOf(id).compareTo(o.id) : -1;
    97         }
     93    public int compareTo(OsmPrimitive o) {
     94        if(o instanceof Relation)
     95            return 1;
     96        return o instanceof Way ? Long.valueOf(id).compareTo(o.id) : -1;
     97    }
    9898
    99         public String getName() {
    100                 String name;
    101                 if (incomplete) {
    102                         name = tr("incomplete");
    103                 } else {
    104                         name = get("name");
    105                         if (name == null) name = get("ref");
    106                         if (name == null) {
    107                                 name =
    108                                         (get("highway") != null) ? tr("highway") :
    109                                         (get("railway") != null) ? tr("railway") :
    110                                         (get("waterway") != null) ? tr("waterway") :
    111                                         (get("landuse") != null) ? tr("landuse") : "";
    112                         }
     99    public String getName() {
     100        String name;
     101        if (incomplete) {
     102            name = tr("incomplete");
     103        } else {
     104            name = get("name");
     105            if (name == null) name = get("ref");
     106            if (name == null) {
     107                name =
     108                    (get("highway") != null) ? tr("highway") :
     109                    (get("railway") != null) ? tr("railway") :
     110                    (get("waterway") != null) ? tr("waterway") :
     111                    (get("landuse") != null) ? tr("landuse") : "";
     112            }
    113113
    114                         int nodesNo = new HashSet<Node>(nodes).size();
    115                         name += trn(" ({0} node)", " ({0} nodes)", nodesNo, nodesNo);
    116                 }
    117                 return name;
    118         }
     114            int nodesNo = new HashSet<Node>(nodes).size();
     115            name += trn(" ({0} node)", " ({0} nodes)", nodesNo, nodesNo);
     116        }
     117        return name;
     118    }
    119119
    120         @Deprecated
    121         public boolean isIncomplete() {
    122                 return incomplete;
    123         }
     120    @Deprecated
     121    public boolean isIncomplete() {
     122        return incomplete;
     123    }
    124124}
  • trunk/src/org/openstreetmap/josm/data/osm/WaySegment.java

    r627 r1169  
    66 */
    77public final class WaySegment {
    8         /**
    9         * The way.
    10         */
    11         public Way way;
     8    /**
     9    * The way.
     10    */
     11    public Way way;
    1212
    13         /**
    14         * The index of one of the 2 nodes in the way.  The other node has the
    15         * index <code>lowerIndex + 1</code>.
    16         */
    17         public int lowerIndex;
     13    /**
     14    * The index of one of the 2 nodes in the way.  The other node has the
     15    * index <code>lowerIndex + 1</code>.
     16    */
     17    public int lowerIndex;
    1818
    19         public WaySegment(Way w, int i) {
    20                 way = w;
    21                 lowerIndex = i;
    22         }
     19    public WaySegment(Way w, int i) {
     20        way = w;
     21        lowerIndex = i;
     22    }
    2323
    24         @Override public boolean equals(Object o) {
    25                 return o != null && o instanceof WaySegment
    26                         && ((WaySegment) o).way == way
    27                         && ((WaySegment) o).lowerIndex == lowerIndex;
    28         }
     24    @Override public boolean equals(Object o) {
     25        return o != null && o instanceof WaySegment
     26            && ((WaySegment) o).way == way
     27            && ((WaySegment) o).lowerIndex == lowerIndex;
     28    }
    2929
    30         @Override public int hashCode() {
    31                 return way.hashCode() ^ lowerIndex;
    32         }
     30    @Override public int hashCode() {
     31        return way.hashCode() ^ lowerIndex;
     32    }
    3333}
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/AddVisitor.java

    r655 r1169  
    99/**
    1010 * Visitor that adds the visited object to the dataset given at constructor.
    11  * 
     11 *
    1212 * Is not capable of adding keys.
    13  * 
     13 *
    1414 * @author imi
    1515 */
    1616public class AddVisitor implements Visitor {
    17        
    18         protected final DataSet ds;
    19        
    20         public AddVisitor(DataSet ds) {
    21                 this.ds = ds;
    22         }
    23        
    24         public void visit(Node n) {
    25                 ds.nodes.add(n);
    26         }
    27         public void visit(Way w) {
    28                 ds.ways.add(w);
    29         }
    30         public void visit(Relation e) {
    31                 ds.relations.add(e);
    32         }
     17
     18    protected final DataSet ds;
     19
     20    public AddVisitor(DataSet ds) {
     21        this.ds = ds;
     22    }
     23
     24    public void visit(Node n) {
     25        ds.nodes.add(n);
     26    }
     27    public void visit(Way w) {
     28        ds.ways.add(w);
     29    }
     30    public void visit(Relation e) {
     31        ds.relations.add(e);
     32    }
    3333}
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/AllNodesVisitor.java

    r627 r1169  
    1313/**
    1414 * Collect all nodes a specific osm primitive has.
    15  * 
     15 *
    1616 * @author imi
    1717 */
    1818public class AllNodesVisitor implements Visitor {
    1919
    20         /**
    21         * The resulting nodes collected so far.
    22         */
    23         public Collection<Node> nodes = new HashSet<Node>();
     20    /**
     21    * The resulting nodes collected so far.
     22    */
     23    public Collection<Node> nodes = new HashSet<Node>();
    2424
    25         /**
    26         * Nodes have only itself as nodes.
    27         */
    28         public void visit(Node n) {
    29                 nodes.add(n);
    30         }
     25    /**
     26    * Nodes have only itself as nodes.
     27    */
     28    public void visit(Node n) {
     29        nodes.add(n);
     30    }
    3131
    32         /**
    33         * Ways have their way nodes.
    34         */
    35         public void visit(Way w) {
    36                 w.visitNodes(this);
    37         }
     32    /**
     33    * Ways have their way nodes.
     34    */
     35    public void visit(Way w) {
     36        w.visitNodes(this);
     37    }
    3838
    39         /**
    40         * Relations may have any number of nodes.
    41         * FIXME: do we want to collect nodes from segs/ways that are relation members?
    42         * if so, use AutomatchVisitor!
    43         */
    44         public void visit(Relation e) {
    45                 for (RelationMember m : e.members)
    46                         if (m.member instanceof Node) visit((Node)m.member);
    47         }
    48         /**
    49         * @return All nodes the given primitive has.
    50         */
    51         public static Collection<Node> getAllNodes(Collection<? extends OsmPrimitive> osms) {
    52                 AllNodesVisitor v = new AllNodesVisitor();
    53                 for (OsmPrimitive osm : osms)
    54                         osm.visit(v);
    55                 return v.nodes;
    56         }
     39    /**
     40    * Relations may have any number of nodes.
     41    * FIXME: do we want to collect nodes from segs/ways that are relation members?
     42    * if so, use AutomatchVisitor!
     43    */
     44    public void visit(Relation e) {
     45        for (RelationMember m : e.members)
     46            if (m.member instanceof Node) visit((Node)m.member);
     47    }
     48    /**
     49    * @return All nodes the given primitive has.
     50    */
     51    public static Collection<Node> getAllNodes(Collection<? extends OsmPrimitive> osms) {
     52        AllNodesVisitor v = new AllNodesVisitor();
     53        for (OsmPrimitive osm : osms)
     54            osm.visit(v);
     55        return v.nodes;
     56    }
    5757}
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/BoundingXYVisitor.java

    r948 r1169  
    1212
    1313/**
    14  * Calculates the total bounding rectangle of a series of {@link OsmPrimitive} objects, using the 
     14 * Calculates the total bounding rectangle of a series of {@link OsmPrimitive} objects, using the
    1515 * EastNorth values as reference.
    1616 * @author imi
     
    6161
    6262    /**
    63      * Enlarges the calculated bounding box by 0.0001 degrees. 
     63     * Enlarges the calculated bounding box by 0.0001 degrees.
    6464     * If the bounding box has not been set (<code>min</code> or <code>max</code>
    6565     * equal <code>null</code>) this method does not do anything.
    66      *   
     66     *
    6767     * @param enlargeDegree
    6868     */
     
    7272
    7373    /**
    74      * Enlarges the calculated bounding box by the specified number of degrees. 
     74     * Enlarges the calculated bounding box by the specified number of degrees.
    7575     * If the bounding box has not been set (<code>min</code> or <code>max</code>
    7676     * equal <code>null</code>) this method does not do anything.
    77      *   
     77     *
    7878     * @param enlargeDegree
    7979     */
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/CollectBackReferencesVisitor.java

    r627 r1169  
    1414/**
    1515 * Helper that collect all ways a node is part of.
    16  * 
     16 *
    1717 * Deleted objects are not collected.
    18  * 
     18 *
    1919 * @author imi
    2020 */
    2121public class CollectBackReferencesVisitor implements Visitor {
    2222
    23         private final DataSet ds;
    24         private final boolean indirectRefs;
     23    private final DataSet ds;
     24    private final boolean indirectRefs;
    2525
    26         /**
    27         * The result list of primitives stored here.
    28         */
    29         public final Collection<OsmPrimitive> data = new HashSet<OsmPrimitive>();
     26    /**
     27    * The result list of primitives stored here.
     28    */
     29    public final Collection<OsmPrimitive> data = new HashSet<OsmPrimitive>();
    3030
    3131
    32         /**
    33         * Construct a back reference counter.
    34         * @param ds The dataset to operate on.
    35         */
    36         public CollectBackReferencesVisitor(DataSet ds) {
    37                 this.ds = ds;
    38                 this.indirectRefs = true;
    39         }
     32    /**
     33    * Construct a back reference counter.
     34    * @param ds The dataset to operate on.
     35    */
     36    public CollectBackReferencesVisitor(DataSet ds) {
     37        this.ds = ds;
     38        this.indirectRefs = true;
     39    }
    4040
    41         public CollectBackReferencesVisitor(DataSet ds, boolean indirectRefs) {
    42                 this.ds = ds;
    43                 this.indirectRefs = indirectRefs;
    44         }
     41    public CollectBackReferencesVisitor(DataSet ds, boolean indirectRefs) {
     42        this.ds = ds;
     43        this.indirectRefs = indirectRefs;
     44    }
    4545
    46         public void visit(Node n) {
    47                 for (Way w : ds.ways) {
    48                         if (w.deleted || w.incomplete) continue;
    49                         for (Node n2 : w.nodes) {
    50                                 if (n == n2) {
    51                                         data.add(w);
    52                                         if (indirectRefs) {
    53                                                 visit(w);
    54                                         }
    55                                 }
    56                         }
    57                 }
    58                 checkRelationMembership(n);
    59         }
    60        
    61         public void visit(Way w) {
    62                 checkRelationMembership(w);
    63         }
    64        
    65         public void visit(Relation r) {
    66                 checkRelationMembership(r);
    67         }
    68        
    69         private void checkRelationMembership(OsmPrimitive p) {
    70                 // FIXME - this might be a candidate for optimisation 
    71                 // if OSM primitives are made to hold a list of back
    72                 // references.
    73                 for (Relation r : ds.relations) {
    74                         if (r.incomplete || r.deleted) continue;
    75                         for (RelationMember m : r.members) {
    76                                 if (m.member == p) {
    77                                         if (!data.contains(r)) {
    78                                                 data.add(r);
    79                                                 if (indirectRefs) {
    80                                                         // move up the tree (there might be relations
    81                                                         // referring to this relation)
    82                                                         checkRelationMembership(r);
    83                                                 }
    84                                         }
    85                                         break;
    86                                 }
    87                         }
    88                 }
    89         }
     46    public void visit(Node n) {
     47        for (Way w : ds.ways) {
     48            if (w.deleted || w.incomplete) continue;
     49            for (Node n2 : w.nodes) {
     50                if (n == n2) {
     51                    data.add(w);
     52                    if (indirectRefs) {
     53                        visit(w);
     54                    }
     55                }
     56            }
     57        }
     58        checkRelationMembership(n);
     59    }
     60
     61    public void visit(Way w) {
     62        checkRelationMembership(w);
     63    }
     64
     65    public void visit(Relation r) {
     66        checkRelationMembership(r);
     67    }
     68
     69    private void checkRelationMembership(OsmPrimitive p) {
     70        // FIXME - this might be a candidate for optimisation
     71        // if OSM primitives are made to hold a list of back
     72        // references.
     73        for (Relation r : ds.relations) {
     74            if (r.incomplete || r.deleted) continue;
     75            for (RelationMember m : r.members) {
     76                if (m.member == p) {
     77                    if (!data.contains(r)) {
     78                        data.add(r);
     79                        if (indirectRefs) {
     80                            // move up the tree (there might be relations
     81                            // referring to this relation)
     82                            checkRelationMembership(r);
     83                        }
     84                    }
     85                    break;
     86                }
     87            }
     88        }
     89    }
    9090}
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/CreateOsmChangeVisitor.java

    r1071 r1169  
    1616/**
    1717 * Creates an OsmChange document from JOSM edits.
    18  * See http://wiki.openstreetmap.org/index.php/OsmChange for a documentation of the 
     18 * See http://wiki.openstreetmap.org/index.php/OsmChange for a documentation of the
    1919 * OsmChange format.
    20  * 
     20 *
    2121 * @author fred
    2222 *
     
    3030    StringWriter swriter;
    3131    OsmWriter osmwriter;
    32    
     32
    3333    public CreateOsmChangeVisitor(Changeset changeset) {
    3434        writer = new PrintWriter(swriter = new StringWriter());
    3535        writer.write("<osmChange version=\"");
    3636        writer.write(Main.pref.get("osm-server.version", "0.6"));
    37         writer.write("\" generator=\"JOSM\">\n"); 
     37        writer.write("\" generator=\"JOSM\">\n");
    3838        this.changeset = changeset;
    3939        osmwriter = new OsmWriter(writer, false, changeset);
    4040    }
    41    
     41
    4242    public void visit(Node n) {
    4343        if (n.deleted) {
     
    5555        }
    5656    }
    57    
     57
    5858    public void visit(Way w) {
    5959        if (w.deleted) {
     
    6969            switchMode((w.id == 0) ? "create" : "modify");
    7070            w.visit(osmwriter);
    71         }       
     71        }
    7272    }
    73    
     73
    7474    public void visit(Relation r) {
    7575        if (r.deleted) {
     
    8585            switchMode((r.id == 0) ? "create" : "modify");
    8686            r.visit(osmwriter);
    87         }           
     87        }
    8888    }
    89    
     89
    9090    private void switchMode(String newMode) {
    9191        if ((newMode != null && !newMode.equals(currentMode))||(newMode == null && currentMode != null)) {
     
    105105        }
    106106    }
    107    
     107
    108108    public String getDocument() {
    109109        switchMode(null);
    110110        return swriter.toString() + "</osmChange>\n";
    111111    }
    112    
     112
    113113    public Map<OsmPrimitive,Long> getNewIdMap() {
    114114        return osmwriter.usedNewIds;
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/DeleteVisitor.java

    r655 r1169  
    99/**
    1010 * Visitor that adds the visited object to the dataset given at constructor.
    11  * 
     11 *
    1212 * Is not capable of adding keys.
    13  * 
     13 *
    1414 * @author imi
    1515 */
    1616public class DeleteVisitor implements Visitor {
    17        
    18         private final DataSet ds;
    19        
    20         public DeleteVisitor(DataSet ds) {
    21                 this.ds = ds;
    22         }
    23        
    24         public void visit(Node n) {
    25                 ds.nodes.remove(n);
    26         }
    27         public void visit(Way w) {
    28                 ds.ways.remove(w);
    29         }
    30         public void visit(Relation e) {
    31                 ds.relations.remove(e);
    32         }
     17
     18    private final DataSet ds;
     19
     20    public DeleteVisitor(DataSet ds) {
     21        this.ds = ds;
     22    }
     23
     24    public void visit(Node n) {
     25        ds.nodes.remove(n);
     26    }
     27    public void visit(Way w) {
     28        ds.ways.remove(w);
     29    }
     30    public void visit(Relation e) {
     31        ds.relations.remove(e);
     32    }
    3333}
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/MapPaintVisitor.java

    r1077 r1169  
    3333
    3434public class MapPaintVisitor extends SimplePaintVisitor {
    35         protected boolean useRealWidth;
    36         protected boolean zoomLevelDisplay;
    37         protected boolean fillAreas;
    38         protected int fillAlpha;
    39         protected Color untaggedColor;
    40         protected Color textColor;
    41         protected boolean currentDashed = false;
    42         protected int currentWidth = 0;
    43         protected Stroke currentStroke = null;
    44         protected Font orderFont;
    45         protected ElemStyles styles;
    46         protected double circum;
    47         protected String regionalNameOrder[];
    48 
    49         protected boolean isZoomOk(ElemStyle e) {
    50                 if (!zoomLevelDisplay) /* show everything if the user wishes so */
    51                         return true;
    52 
    53                 if(e == null) /* the default for things that don't have a rule (show, if scale is smaller than 1500m) */
    54                         return (circum < 1500);
    55 
    56                 // formula to calculate a map scale: natural size / map size = scale
    57                 // example: 876000mm (876m as displayed) / 22mm (roughly estimated screen size of legend bar) = 39818
    58                 //
    59                 // so the exact "correcting value" below depends only on the screen size and resolution
    60                 // XXX - do we need a Preference setting for this (if things vary widely)?
    61                 return !(circum >= e.maxScale / 22 || circum < e.minScale / 22);
    62         }
    63 
    64         /**
    65         * Draw a small rectangle.
    66         * White if selected (as always) or red otherwise.
    67         *
    68         * @param n The node to draw.
    69         */
    70         public void visit(Node n) {
    71                 IconElemStyle nodeStyle = styles.get(n);
    72                 if (nodeStyle != null && isZoomOk(nodeStyle))
    73                         drawNode(n, nodeStyle.icon, nodeStyle.annotate);
    74                 else if (n.selected)
    75                         drawNode(n, selectedColor, selectedNodeSize, selectedNodeRadius, fillSelectedNode);
    76                 else if (n.tagged)
    77                         drawNode(n, nodeColor, taggedNodeSize, taggedNodeRadius, fillUnselectedNode);
    78                 else
    79                         drawNode(n, nodeColor, unselectedNodeSize, unselectedNodeRadius, fillUnselectedNode);
    80         }
    81 
    82         /**
    83         * Draw a line for all segments, according to tags.
    84         * @param w The way to draw.
    85         */
    86         public void visit(Way w) {
    87                 if(w.nodes.size() < 2)
    88                         return;
    89                 // show direction arrows, if draw.segment.relevant_directions_only is not set, the way is tagged with a direction key
    90                 // (even if the tag is negated as in oneway=false) or the way is selected
    91                 boolean showDirection = w.selected || ((!useRealWidth) && (showDirectionArrow
    92                 && (!showRelevantDirectionsOnly || w.hasDirectionKeys)));
    93 
    94                 Color color = untaggedColor;
    95                 int width = defaultSegmentWidth;
    96                 int realWidth = 0; //the real width of the element in meters
    97                 boolean dashed = false;
    98                 ElemStyle wayStyle = styles.get(w);
    99 
    100                 if(!isZoomOk(wayStyle))
    101                         return;
    102 
    103                 LineElemStyle l = null;
    104                 if(wayStyle!=null)
    105                 {
    106                         Color areacolor = untaggedColor;
    107                         boolean area = false;
    108                         if(wayStyle instanceof LineElemStyle)
    109                                 l = (LineElemStyle)wayStyle;
    110                         else if (wayStyle instanceof AreaElemStyle)
    111                         {
    112                                 areacolor = ((AreaElemStyle)wayStyle).color;
    113                                 color = areacolor;
    114                                 l = ((AreaElemStyle)wayStyle).line;
    115                                 area = true;
    116                         }
    117                         if(l != null)
    118                         {
    119                                 color = l.color;
    120                                 width = l.width;
    121                                 realWidth = l.realWidth;
    122                                 dashed = l.dashed;
    123                         }
    124                         if (area && fillAreas)
    125                                 drawWayAsArea(w, areacolor);
    126                 }
    127 
    128                 if (realWidth > 0 && useRealWidth && !showDirection)
    129                 {
    130                         int tmpWidth = (int) (100 /  (float) (circum / realWidth));
    131                         if (tmpWidth > width) width = tmpWidth;
    132                 }
    133                 if(w.selected)
    134                         color = selectedColor;
    135 
    136                 Node lastN;
    137                 if(l != null && l.overlays != null)
    138                 {
    139                         for(LineElemStyle s : l.overlays)
    140                         {
    141                                 if(!s.over)
    142                                 {
    143                                         lastN = null;
    144                                         for(Node n : w.nodes)
    145                                         {
    146                                                 if(lastN != null)
    147                                                 {
    148                                                         drawSeg(lastN, n, s.color != null  && !w.selected ? s.color : color,
    149                                                         false, s.getWidth(width), s.dashed);
    150                                                 }
    151                                                 lastN = n;
    152                                         }
    153                                 }
    154                         }
    155                 }
    156 
    157                 lastN = null;
    158                 for(Node n : w.nodes)
    159                 {
    160                         if(lastN != null)
    161                                 drawSeg(lastN, n, color, showDirection, width, dashed);
    162                         lastN = n;
    163                 }
    164 
    165                 if(l != null && l.overlays != null)
    166                 {
    167                         for(LineElemStyle s : l.overlays)
    168                         {
    169                                 if(s.over)
    170                                 {
    171                                         lastN = null;
    172                                         for(Node n : w.nodes)
    173                                         {
    174                                                 if(lastN != null)
    175                                                 {
    176                                                         drawSeg(lastN, n, s.color != null && !w.selected ? s.color : color,
    177                                                         false, s.getWidth(width), s.dashed);
    178                                                 }
    179                                                 lastN = n;
    180                                         }
    181                                 }
    182                         }
    183                 }
    184 
    185                 if(showOrderNumber)
    186                 {
    187                         int orderNumber = 0;
    188                         lastN = null;
    189                         for(Node n : w.nodes)
    190                         {
    191                                 if(lastN != null)
    192                                 {
    193                                         orderNumber++;
    194                                         drawOrderNumber(lastN, n, orderNumber);
    195                                 }
    196                                 lastN = n;
    197                         }
    198                 }
    199                 displaySegments();
    200         }
    201 
    202         public void visit(Relation e) {
    203                 // relations are not (yet?) drawn.
    204         }
    205 
    206         // This assumes that all segments are aligned in the same direction!
    207         protected void drawWayAsArea(Way w, Color color)
    208         {
    209                 Polygon polygon = new Polygon();
    210 
    211                 for (Node n : w.nodes)
    212                 {
    213                         Point p = nc.getPoint(n.eastNorth);
    214                         polygon.addPoint(p.x,p.y);
    215                 }
    216 
    217                 Color mycolor = w.selected ? selectedColor : color;
    218                 // set the opacity (alpha) level of the filled polygon
    219                 g.setColor(new Color( mycolor.getRed(), mycolor.getGreen(), mycolor.getBlue(), fillAlpha));
    220 
    221                 g.fillPolygon(polygon);
    222         }
    223 
    224         // NEW
    225         protected void drawNode(Node n, ImageIcon icon, boolean annotate) {
    226                 Point p = nc.getPoint(n.eastNorth);
    227                 if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth()) || (p.y > nc.getHeight())) return;
    228                 int w = icon.getIconWidth(), h=icon.getIconHeight();
    229                 icon.paintIcon ( Main.map.mapView, g, p.x-w/2, p.y-h/2 );
    230                 String name = getNodeName(n);
    231                 if (name!=null && annotate)
    232                 {
    233                         g.setColor(textColor);
    234                         Font defaultFont = g.getFont();
    235                         g.setFont (orderFont);
    236                         g.drawString (name, p.x+w/2+2, p.y+h/2+2);
    237                         g.setFont(defaultFont);
    238                 }
    239                 if (n.selected)
    240                 {
    241                         g.setColor (  selectedColor );
    242                         g.drawRect (p.x-w/2-2,p.y-w/2-2, w+4, h+4);
    243                 }
    244         }
    245 
    246         protected String getNodeName(Node n) {
    247                 String name = null;
    248                 if (n.keys != null) {
    249                         for (int i = 0; i < regionalNameOrder.length; i++) {
    250                                 name = n.keys.get(regionalNameOrder[i]);
    251                                 if (name != null) break;
    252                         }
    253                 }
    254                 return name;
    255         }
    256 
    257         private void drawSeg(Node n1, Node n2, Color col, boolean showDirection, int width, boolean dashed) {
    258                 if (col != currentColor || width != currentWidth || dashed != currentDashed) {
    259                         displaySegments(col, width, dashed);
    260                 }
    261                 Point p1 = nc.getPoint(n1.eastNorth);
    262                 Point p2 = nc.getPoint(n2.eastNorth);
    263 
    264                 if (!isSegmentVisible(p1, p2)) {
    265                         return;
    266                 }
    267                 currentPath.moveTo(p1.x, p1.y);
    268                 currentPath.lineTo(p2.x, p2.y);
    269 
    270                 if (showDirection) {
    271                         double t = Math.atan2(p2.y-p1.y, p2.x-p1.x) + Math.PI;
    272                         currentPath.lineTo((int)(p2.x + 10*Math.cos(t-PHI)), (int)(p2.y + 10*Math.sin(t-PHI)));
    273                         currentPath.moveTo((int)(p2.x + 10*Math.cos(t+PHI)), (int)(p2.y + 10*Math.sin(t+PHI)));
    274                         currentPath.lineTo(p2.x, p2.y);
    275                 }
    276         }
    277 
    278         protected void displaySegments() {
    279                 displaySegments(null, 0, false);
    280         }
    281 
    282         protected void displaySegments(Color newColor, int newWidth, boolean newDash) {
    283                 if (currentPath != null) {
    284                         Graphics2D g2d = (Graphics2D)g;
    285                         g2d.setColor(inactive ? inactiveColor : currentColor);
    286                         if (currentStroke == null) {
    287                                 if (currentDashed)
    288                                         g2d.setStroke(new BasicStroke(currentWidth,BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND,0,new float[] {9},0));
    289                                 else
    290                                         g2d.setStroke(new BasicStroke(currentWidth,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND));
    291                         }
    292                         g2d.draw(currentPath);
    293                         g2d.setStroke(new BasicStroke(1));
    294 
    295                         currentPath = new GeneralPath();
    296                         currentColor = newColor;
    297                         currentWidth = newWidth;
    298                         currentDashed = newDash;
    299                         currentStroke = null;
    300                 }
    301         }
    302 
    303         /**
    304         * Draw the node as small rectangle with the given color.
    305         *
    306         * @param n  The node to draw.
    307         * @param color The color of the node.
    308         */
    309         public void drawNode(Node n, Color color, int size, int radius, boolean fill) {
    310                 if (isZoomOk(null) && size > 1) {
    311                         Point p = nc.getPoint(n.eastNorth);
    312                         if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth())
    313                                         || (p.y > nc.getHeight()))
    314                                 return;
    315                         g.setColor(color);
    316                         if (fill) {
    317                                 g.fillRect(p.x - radius, p.y - radius, size, size);
    318                                 g.drawRect(p.x - radius, p.y - radius, size, size);
    319                         } else
    320                                 g.drawRect(p.x - radius, p.y - radius, size, size);
    321                 }
    322         }
    323 
    324         // NW 111106 Overridden from SimplePaintVisitor in josm-1.4-nw1
    325         // Shows areas before non-areas
    326         public void visitAll(DataSet data, Boolean virtual) {
    327                 getSettings(virtual);
    328                 untaggedColor = Main.pref.getColor(marktr("untagged"),Color.GRAY);
    329                 textColor = Main.pref.getColor (marktr("text"), Color.WHITE);
    330                 useRealWidth = Main.pref.getBoolean("mappaint.useRealWidth",false);
    331                 zoomLevelDisplay = Main.pref.getBoolean("mappaint.zoomLevelDisplay",false);
    332                 fillAreas = Main.pref.getBoolean("mappaint.fillareas", true);
    333                 fillAlpha = Math.min(255, Math.max(0, Integer.valueOf(Main.pref.getInteger("mappaint.fillalpha", 50))));
    334                 circum = Main.map.mapView.getScale()*100*Main.proj.scaleFactor()*40041455; // circumference of the earth in meter
    335                 styles = MapPaintStyles.getStyles();
    336                 orderFont = new Font(Main.pref.get("mappaint.font","Helvetica"), Font.PLAIN, Main.pref.getInteger("mappaint.fontsize", 8));
    337                 String currentLocale = Locale.getDefault().getLanguage();
    338                 regionalNameOrder = Main.pref.get("mappaint.nameOrder", "name:"+currentLocale+";name;int_name").split(";");
    339 
    340                 if (styles.hasAreas()) {
    341                         Collection<Way> noAreaWays = new LinkedList<Way>();
    342 
    343                         for (final OsmPrimitive osm : data.ways)
    344                                 if (!osm.incomplete && !osm.deleted && styles.isArea((Way)osm))
    345                                         osm.visit(this);
    346                                 else if (!osm.deleted && !osm.incomplete)
    347                                         noAreaWays.add((Way)osm);
    348 
    349                         for (final OsmPrimitive osm : noAreaWays)
    350                                 osm.visit(this);
    351                 }
    352                 else
    353                 {
    354                         for (final OsmPrimitive osm : data.ways)
    355                                 if (!osm.incomplete && !osm.deleted)
    356                                         osm.visit(this);
    357                 }
    358 
    359                 for (final OsmPrimitive osm : data.getSelected())
    360                         if (!osm.incomplete && !osm.deleted){
    361                                 osm.visit(this);
    362                         }
    363 
    364                 displaySegments();
    365 
    366                 for (final OsmPrimitive osm : data.nodes)
    367                         if (!osm.incomplete && !osm.deleted)
    368                                 osm.visit(this);
    369 
    370                 if (virtualNodeSize != 0)
    371                 {
    372                         currentColor = nodeColor;
    373                         for (final OsmPrimitive osm : data.ways)
    374                                 if (!osm.deleted)
    375                                         visitVirtual((Way)osm);
    376                         displaySegments(null);
    377                 }
    378         }
    379 
    380         /**
    381         * Draw a number of the order of the two consecutive nodes within the
    382         * parents way
    383         */
    384         protected void drawOrderNumber(Node n1, Node n2, int orderNumber) {
    385                 Point p1 = nc.getPoint(n1.eastNorth);
    386                 Point p2 = nc.getPoint(n2.eastNorth);
    387                 drawOrderNumber(p1, p2, orderNumber);
    388         }
     35    protected boolean useRealWidth;
     36    protected boolean zoomLevelDisplay;
     37    protected boolean fillAreas;
     38    protected int fillAlpha;
     39    protected Color untaggedColor;
     40    protected Color textColor;
     41    protected boolean currentDashed = false;
     42    protected int currentWidth = 0;
     43    protected Stroke currentStroke = null;
     44    protected Font orderFont;
     45    protected ElemStyles styles;
     46    protected double circum;
     47    protected String regionalNameOrder[];
     48
     49    protected boolean isZoomOk(ElemStyle e) {
     50        if (!zoomLevelDisplay) /* show everything if the user wishes so */
     51            return true;
     52
     53        if(e == null) /* the default for things that don't have a rule (show, if scale is smaller than 1500m) */
     54            return (circum < 1500);
     55
     56        // formula to calculate a map scale: natural size / map size = scale
     57        // example: 876000mm (876m as displayed) / 22mm (roughly estimated screen size of legend bar) = 39818
     58        //
     59        // so the exact "correcting value" below depends only on the screen size and resolution
     60        // XXX - do we need a Preference setting for this (if things vary widely)?
     61        return !(circum >= e.maxScale / 22 || circum < e.minScale / 22);
     62    }
     63
     64    /**
     65    * Draw a small rectangle.
     66    * White if selected (as always) or red otherwise.
     67    *
     68    * @param n The node to draw.
     69    */
     70    public void visit(Node n) {
     71        IconElemStyle nodeStyle = styles.get(n);
     72        if (nodeStyle != null && isZoomOk(nodeStyle))
     73            drawNode(n, nodeStyle.icon, nodeStyle.annotate);
     74        else if (n.selected)
     75            drawNode(n, selectedColor, selectedNodeSize, selectedNodeRadius, fillSelectedNode);
     76        else if (n.tagged)
     77            drawNode(n, nodeColor, taggedNodeSize, taggedNodeRadius, fillUnselectedNode);
     78        else
     79            drawNode(n, nodeColor, unselectedNodeSize, unselectedNodeRadius, fillUnselectedNode);
     80    }
     81
     82    /**
     83    * Draw a line for all segments, according to tags.
     84    * @param w The way to draw.
     85    */
     86    public void visit(Way w) {
     87        if(w.nodes.size() < 2)
     88            return;
     89        // show direction arrows, if draw.segment.relevant_directions_only is not set, the way is tagged with a direction key
     90        // (even if the tag is negated as in oneway=false) or the way is selected
     91        boolean showDirection = w.selected || ((!useRealWidth) && (showDirectionArrow
     92        && (!showRelevantDirectionsOnly || w.hasDirectionKeys)));
     93
     94        Color color = untaggedColor;
     95        int width = defaultSegmentWidth;
     96        int realWidth = 0; //the real width of the element in meters
     97        boolean dashed = false;
     98        ElemStyle wayStyle = styles.get(w);
     99
     100        if(!isZoomOk(wayStyle))
     101            return;
     102
     103        LineElemStyle l = null;
     104        if(wayStyle!=null)
     105        {
     106            Color areacolor = untaggedColor;
     107            boolean area = false;
     108            if(wayStyle instanceof LineElemStyle)
     109                l = (LineElemStyle)wayStyle;
     110            else if (wayStyle instanceof AreaElemStyle)
     111            {
     112                areacolor = ((AreaElemStyle)wayStyle).color;
     113                color = areacolor;
     114                l = ((AreaElemStyle)wayStyle).line;
     115                area = true;
     116            }
     117            if(l != null)
     118            {
     119                color = l.color;
     120                width = l.width;
     121                realWidth = l.realWidth;
     122                dashed = l.dashed;
     123            }
     124            if (area && fillAreas)
     125                drawWayAsArea(w, areacolor);
     126        }
     127
     128        if (realWidth > 0 && useRealWidth && !showDirection)
     129        {
     130            int tmpWidth = (int) (100 /  (float) (circum / realWidth));
     131            if (tmpWidth > width) width = tmpWidth;
     132        }
     133        if(w.selected)
     134            color = selectedColor;
     135
     136        Node lastN;
     137        if(l != null && l.overlays != null)
     138        {
     139            for(LineElemStyle s : l.overlays)
     140            {
     141                if(!s.over)
     142                {
     143                    lastN = null;
     144                    for(Node n : w.nodes)
     145                    {
     146                        if(lastN != null)
     147                        {
     148                            drawSeg(lastN, n, s.color != null  && !w.selected ? s.color : color,
     149                            false, s.getWidth(width), s.dashed);
     150                        }
     151                        lastN = n;
     152                    }
     153                }
     154            }
     155        }
     156
     157        lastN = null;
     158        for(Node n : w.nodes)
     159        {
     160            if(lastN != null)
     161                drawSeg(lastN, n, color, showDirection, width, dashed);
     162            lastN = n;
     163        }
     164
     165        if(l != null && l.overlays != null)
     166        {
     167            for(LineElemStyle s : l.overlays)
     168            {
     169                if(s.over)
     170                {
     171                    lastN = null;
     172                    for(Node n : w.nodes)
     173                    {
     174                        if(lastN != null)
     175                        {
     176                            drawSeg(lastN, n, s.color != null && !w.selected ? s.color : color,
     177                            false, s.getWidth(width), s.dashed);
     178                        }
     179                        lastN = n;
     180                    }
     181                }
     182            }
     183        }
     184
     185        if(showOrderNumber)
     186        {
     187            int orderNumber = 0;
     188            lastN = null;
     189            for(Node n : w.nodes)
     190            {
     191                if(lastN != null)
     192                {
     193                    orderNumber++;
     194                    drawOrderNumber(lastN, n, orderNumber);
     195                }
     196                lastN = n;
     197            }
     198        }
     199        displaySegments();
     200    }
     201
     202    public void visit(Relation e) {
     203        // relations are not (yet?) drawn.
     204    }
     205
     206    // This assumes that all segments are aligned in the same direction!
     207    protected void drawWayAsArea(Way w, Color color)
     208    {
     209        Polygon polygon = new Polygon();
     210
     211        for (Node n : w.nodes)
     212        {
     213            Point p = nc.getPoint(n.eastNorth);
     214            polygon.addPoint(p.x,p.y);
     215        }
     216
     217        Color mycolor = w.selected ? selectedColor : color;
     218        // set the opacity (alpha) level of the filled polygon
     219        g.setColor(new Color( mycolor.getRed(), mycolor.getGreen(), mycolor.getBlue(), fillAlpha));
     220
     221        g.fillPolygon(polygon);
     222    }
     223
     224    // NEW
     225    protected void drawNode(Node n, ImageIcon icon, boolean annotate) {
     226        Point p = nc.getPoint(n.eastNorth);
     227        if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth()) || (p.y > nc.getHeight())) return;
     228        int w = icon.getIconWidth(), h=icon.getIconHeight();
     229        icon.paintIcon ( Main.map.mapView, g, p.x-w/2, p.y-h/2 );
     230        String name = getNodeName(n);
     231        if (name!=null && annotate)
     232        {
     233            g.setColor(textColor);
     234            Font defaultFont = g.getFont();
     235            g.setFont (orderFont);
     236            g.drawString (name, p.x+w/2+2, p.y+h/2+2);
     237            g.setFont(defaultFont);
     238        }
     239        if (n.selected)
     240        {
     241            g.setColor (  selectedColor );
     242            g.drawRect (p.x-w/2-2,p.y-w/2-2, w+4, h+4);
     243        }
     244    }
     245
     246    protected String getNodeName(Node n) {
     247        String name = null;
     248        if (n.keys != null) {
     249            for (int i = 0; i < regionalNameOrder.length; i++) {
     250                name = n.keys.get(regionalNameOrder[i]);
     251                if (name != null) break;
     252            }
     253        }
     254        return name;
     255    }
     256
     257    private void drawSeg(Node n1, Node n2, Color col, boolean showDirection, int width, boolean dashed) {
     258        if (col != currentColor || width != currentWidth || dashed != currentDashed) {
     259            displaySegments(col, width, dashed);
     260        }
     261        Point p1 = nc.getPoint(n1.eastNorth);
     262        Point p2 = nc.getPoint(n2.eastNorth);
     263
     264        if (!isSegmentVisible(p1, p2)) {
     265            return;
     266        }
     267        currentPath.moveTo(p1.x, p1.y);
     268        currentPath.lineTo(p2.x, p2.y);
     269
     270        if (showDirection) {
     271            double t = Math.atan2(p2.y-p1.y, p2.x-p1.x) + Math.PI;
     272            currentPath.lineTo((int)(p2.x + 10*Math.cos(t-PHI)), (int)(p2.y + 10*Math.sin(t-PHI)));
     273            currentPath.moveTo((int)(p2.x + 10*Math.cos(t+PHI)), (int)(p2.y + 10*Math.sin(t+PHI)));
     274            currentPath.lineTo(p2.x, p2.y);
     275        }
     276    }
     277
     278    protected void displaySegments() {
     279        displaySegments(null, 0, false);
     280    }
     281
     282    protected void displaySegments(Color newColor, int newWidth, boolean newDash) {
     283        if (currentPath != null) {
     284            Graphics2D g2d = (Graphics2D)g;
     285            g2d.setColor(inactive ? inactiveColor : currentColor);
     286            if (currentStroke == null) {
     287                if (currentDashed)
     288                    g2d.setStroke(new BasicStroke(currentWidth,BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND,0,new float[] {9},0));
     289                else
     290                    g2d.setStroke(new BasicStroke(currentWidth,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND));
     291            }
     292            g2d.draw(currentPath);
     293            g2d.setStroke(new BasicStroke(1));
     294
     295            currentPath = new GeneralPath();
     296            currentColor = newColor;
     297            currentWidth = newWidth;
     298            currentDashed = newDash;
     299            currentStroke = null;
     300        }
     301    }
     302
     303    /**
     304    * Draw the node as small rectangle with the given color.
     305    *
     306    * @param n  The node to draw.
     307    * @param color The color of the node.
     308    */
     309    public void drawNode(Node n, Color color, int size, int radius, boolean fill) {
     310        if (isZoomOk(null) && size > 1) {
     311            Point p = nc.getPoint(n.eastNorth);
     312            if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth())
     313                    || (p.y > nc.getHeight()))
     314                return;
     315            g.setColor(color);
     316            if (fill) {
     317                g.fillRect(p.x - radius, p.y - radius, size, size);
     318                g.drawRect(p.x - radius, p.y - radius, size, size);
     319            } else
     320                g.drawRect(p.x - radius, p.y - radius, size, size);
     321        }
     322    }
     323
     324    // NW 111106 Overridden from SimplePaintVisitor in josm-1.4-nw1
     325    // Shows areas before non-areas
     326    public void visitAll(DataSet data, Boolean virtual) {
     327        getSettings(virtual);
     328        untaggedColor = Main.pref.getColor(marktr("untagged"),Color.GRAY);
     329        textColor = Main.pref.getColor (marktr("text"), Color.WHITE);
     330        useRealWidth = Main.pref.getBoolean("mappaint.useRealWidth",false);
     331        zoomLevelDisplay = Main.pref.getBoolean("mappaint.zoomLevelDisplay",false);
     332        fillAreas = Main.pref.getBoolean("mappaint.fillareas", true);
     333        fillAlpha = Math.min(255, Math.max(0, Integer.valueOf(Main.pref.getInteger("mappaint.fillalpha", 50))));
     334        circum = Main.map.mapView.getScale()*100*Main.proj.scaleFactor()*40041455; // circumference of the earth in meter
     335        styles = MapPaintStyles.getStyles();
     336        orderFont = new Font(Main.pref.get("mappaint.font","Helvetica"), Font.PLAIN, Main.pref.getInteger("mappaint.fontsize", 8));
     337        String currentLocale = Locale.getDefault().getLanguage();
     338        regionalNameOrder = Main.pref.get("mappaint.nameOrder", "name:"+currentLocale+";name;int_name").split(";");
     339
     340        if (styles.hasAreas()) {
     341            Collection<Way> noAreaWays = new LinkedList<Way>();
     342
     343            for (final OsmPrimitive osm : data.ways)
     344                if (!osm.incomplete && !osm.deleted && styles.isArea((Way)osm))
     345                    osm.visit(this);
     346                else if (!osm.deleted && !osm.incomplete)
     347                    noAreaWays.add((Way)osm);
     348
     349            for (final OsmPrimitive osm : noAreaWays)
     350                osm.visit(this);
     351        }
     352        else
     353        {
     354            for (final OsmPrimitive osm : data.ways)
     355                if (!osm.incomplete && !osm.deleted)
     356                    osm.visit(this);
     357        }
     358
     359        for (final OsmPrimitive osm : data.getSelected())
     360            if (!osm.incomplete && !osm.deleted){
     361                osm.visit(this);
     362            }
     363
     364        displaySegments();
     365
     366        for (final OsmPrimitive osm : data.nodes)
     367            if (!osm.incomplete && !osm.deleted)
     368                osm.visit(this);
     369
     370        if (virtualNodeSize != 0)
     371        {
     372            currentColor = nodeColor;
     373            for (final OsmPrimitive osm : data.ways)
     374                if (!osm.deleted)
     375                    visitVirtual((Way)osm);
     376            displaySegments(null);
     377        }
     378    }
     379
     380    /**
     381    * Draw a number of the order of the two consecutive nodes within the
     382    * parents way
     383    */
     384    protected void drawOrderNumber(Node n1, Node n2, int orderNumber) {
     385        Point p1 = nc.getPoint(n1.eastNorth);
     386        Point p2 = nc.getPoint(n2.eastNorth);
     387        drawOrderNumber(p1, p2, orderNumber);
     388    }
    389389}
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/MergeVisitor.java

    r627 r1169  
    1919 * A visitor that get a data set at construction time and merge every visited object
    2020 * into it.
    21  * 
     21 *
    2222 * @author imi
    2323 */
    2424public class MergeVisitor implements Visitor {
    2525
    26         /**
    27         * Map from primitives in the database to visited primitives. (Attention: The other way 
    28         * round than merged)
    29         */
    30         public Map<OsmPrimitive, OsmPrimitive> conflicts = new HashMap<OsmPrimitive, OsmPrimitive>();
    31 
    32         private final DataSet ds;
    33         private final DataSet mergeds;
    34 
    35         private final HashMap<Long, Node> nodeshash = new HashMap<Long, Node>();
    36         private final HashMap<Long, Way> wayshash = new HashMap<Long, Way>();
    37         private final HashMap<Long, Relation> relshash = new HashMap<Long, Relation>();
    38 
    39         /**
    40         * A list of all primitives that got replaced with other primitives.
    41         * Key is the primitives in the other's dataset and the value is the one that is now
    42         * in ds.nodes instead.
    43         */
    44         private final Map<OsmPrimitive, OsmPrimitive> merged
    45                 = new HashMap<OsmPrimitive, OsmPrimitive>();
    46 
    47         public MergeVisitor(DataSet ds, DataSet mergeds) {
    48                 this.ds = ds;
    49                 this.mergeds = mergeds;
    50 
    51                 for (Node n : ds.nodes) if (n.id != 0) nodeshash.put(n.id, n);
    52                 for (Way w : ds.ways) if (w.id != 0) wayshash.put(w.id, w);
    53                 for (Relation r : ds.relations) if (r.id != 0) relshash.put(r.id, r);
    54         }
    55 
    56         private <P extends OsmPrimitive> void genMerge(P other,
    57                         Collection<P> myprims, Collection<P> mergeprims,
    58                         HashMap<Long, P> primhash) {
    59                 // 1. Try to find an identical prim with the same id.
    60                 if (mergeAfterId(myprims, primhash, other))
    61                         return;
    62 
    63                 // 2. Try to find a prim we can merge with the prim from the other ds.
    64                 for (P my : myprims) {
    65                         // LinkedList.contains calls equal, and OsmPrimitive.equal
    66                         // compares just the id.
    67                         if (match(my, other) && !mergeprims.contains(my)) {
    68                                 merged.put(other, my);
    69                                 mergeCommon(my, other);
    70                                 return;
    71                         }
    72                 }
    73 
    74                 // 3. No idea how to merge that.  Simply add it unchanged.
    75                 myprims.add(other);
    76         }
    77 
    78         public void visit(Node other) {
    79                 genMerge(other, ds.nodes, mergeds.nodes, nodeshash);
    80         }
    81 
    82         public void visit(Way other) {
    83                 fixWay(other);
    84                 genMerge(other, ds.ways, mergeds.ways, wayshash);
    85         }
    86 
    87         public void visit(Relation other) {
    88                 fixRelation(other);
    89                 genMerge(other, ds.relations, mergeds.relations, relshash);
    90         }
    91 
    92         /**
    93         * Postprocess the dataset and fix all merged references to point to the actual
    94         * data.
    95         */
    96         public void fixReferences() {
    97                 for (Way w : ds.ways) fixWay(w);
    98                 for (Relation r : ds.relations) fixRelation(r);
    99                 for (OsmPrimitive osm : conflicts.values())
    100                         if (osm instanceof Way)
    101                                 fixWay((Way)osm);
    102                         else if (osm instanceof Relation)
    103                                 fixRelation((Relation) osm);
    104         }
    105 
    106         private void fixWay(Way w) {
    107             boolean replacedSomething = false;
    108             LinkedList<Node> newNodes = new LinkedList<Node>();
    109             for (Node n : w.nodes) {
    110                 Node otherN = (Node) merged.get(n);
    111                 newNodes.add(otherN == null ? n : otherN);
    112                 if (otherN != null)
    113                         replacedSomething = true;
    114             }
    115             if (replacedSomething) {
    116                 w.nodes.clear();
    117                 w.nodes.addAll(newNodes);
    118                 }
    119     }
    120 
    121         private void fixRelation(Relation r) {
    122             boolean replacedSomething = false;
    123             LinkedList<RelationMember> newMembers = new LinkedList<RelationMember>();
    124             for (RelationMember m : r.members) {
    125                 OsmPrimitive otherP = merged.get(m.member);
    126                         if (otherP == null) {
    127                                 newMembers.add(m);
    128                         } else {
    129                                 RelationMember mnew = new RelationMember(m);
    130                                 mnew.member = otherP;
    131                                 newMembers.add(mnew);
    132                         replacedSomething = true;
    133                         }
    134             }
    135             if (replacedSomething) {
    136                 r.members.clear();
    137                 r.members.addAll(newMembers);
    138                 }
    139         }
    140 
    141         private static <P extends OsmPrimitive> boolean match(P p1, P p2) {
    142                 if ((p1.id == 0 || p2.id == 0) && !p1.incomplete && !p2.incomplete) {
    143                         return realMatch(p1, p2);
    144                 }
    145                 return p1.id == p2.id;
    146         }
    147 
    148         /** @return true if the prims have pretty much the same data, i.e. the
    149         * same position, the same members, ...
    150         */
    151         // Java cannot dispatch on generics...
    152         private static boolean realMatch(OsmPrimitive p1, OsmPrimitive p2) {
    153                 if (p1 instanceof Node && p2 instanceof Node) {
    154                         return realMatch((Node) p1, (Node) p2);
    155                 } else if (p1 instanceof Way && p2 instanceof Way) {
    156                         return realMatch((Way) p1, (Way) p2);
    157                 } else if (p1 instanceof Relation && p2 instanceof Relation) {
    158                         return realMatch((Relation) p1, (Relation) p2);
    159                 } else {
    160                         throw new RuntimeException("arguments have unknown type");
    161                 }
    162         }
    163 
    164         private static boolean realMatch(Node n1, Node n2) {
    165                 return n1.coor.equalsEpsilon(n2.coor);
    166         }
    167 
    168         private static boolean realMatch(Way w1, Way w2) {
    169                 if (w1.nodes.size() != w2.nodes.size())
    170                         return false;
    171                 Iterator<Node> it = w1.nodes.iterator();
    172                 for (Node n : w2.nodes)
    173                         if (!match(n, it.next()))
    174                                 return false;
    175                 return true;
    176         }
    177 
    178         private static boolean realMatch(Relation w1, Relation w2) {
    179                 // FIXME this is not perfect yet...
    180                 if (w1.members.size() != w2.members.size())
    181                         return false;
    182                 for (RelationMember em : w1.members) {
    183                         if (!w2.members.contains(em)) {
    184                                 return false;
    185                         }
    186                 }
    187                 return true;
    188         }
    189 
    190         /**
    191         * Merge the common parts of an osm primitive.
    192         * @param my The object, the information gets merged into
    193         * @param other The object, the information gets merged from
    194         */
    195         private void mergeCommon(OsmPrimitive my, OsmPrimitive other) {
    196                 if (other.deleted)
    197                         my.delete(true);
    198                 if (my.id == 0 || !my.modified || other.modified) {
    199                         if (my.id == 0 && other.id != 0) {
    200                                 my.id = other.id;
    201                                 my.modified = other.modified; // match a new node
    202                         } else if (my.id != 0 && other.id != 0 && other.modified)
    203                                 my.modified = true;
    204                 }
    205                 if (other.keys == null)
    206                         return;
    207                 if (my.keySet().containsAll(other.keys.keySet()))
    208                         return;
    209                 if (my.keys == null)
    210                         my.keys = other.keys;
    211                 else
    212                         my.keys.putAll(other.keys);
    213                
    214                 my.modified = true;
    215         }
    216 
    217         /**
    218         * @return <code>true</code>, if no merge is needed or merge is performed already.
    219         */
    220         private <P extends OsmPrimitive> boolean mergeAfterId(
    221                         Collection<P> primitives, HashMap<Long, P> hash, P other) {
    222                 // Fast-path merging of identical objects
    223                 if (hash.containsKey(other.id)) {
    224                         P my = hash.get(other.id);
    225                         if (my.realEqual(other, true)) {
    226                                 merged.put(other, my);
    227                                 return true;
    228                         }
    229                 }
    230 
    231                 for (P my : primitives) {
    232                         if (my.realEqual(other, false)) {
    233                                 merged.put(other, my);
    234                                 return true; // no merge needed.
    235                         }
    236                         if (my.realEqual(other, true)) {
    237                                 Date myd = my.timestamp == null ? new Date(0) : my.getTimestamp();
    238                                 Date otherd = other.timestamp == null ? new Date(0) : other.getTimestamp();
    239 
    240                                 // they differ in modified/timestamp combination only. Auto-resolve it.
    241                                 merged.put(other, my);
    242                                 if (myd.before(otherd)) {
    243                                         my.modified = other.modified;
    244                                         my.timestamp = other.timestamp;
    245                                 }
    246                                 return true; // merge done.
    247                         }
    248                         if (my.id == other.id && my.id != 0) {
    249                                 Date myd = my.timestamp == null ? new Date(0) : my.getTimestamp();
    250                                 Date otherd = other.timestamp == null ? new Date(0) : other.getTimestamp();
    251 
    252                                 if (my.incomplete || other.incomplete) {
    253                                         if (my.incomplete) {
    254                                                 my.cloneFrom(other);
    255                                         }
    256                                 } else if (my.modified && other.modified) {
    257                                         conflicts.put(my, other);
    258                                 } else if (!my.modified && !other.modified) {
    259                                         if (myd.before(otherd)) {
    260                                                 my.cloneFrom(other);
    261                                         }
    262                                 } else if (other.modified) {
    263                                         if (myd.after(otherd)) {
    264                                                 conflicts.put(my, other);
    265                                         } else {
    266                                                 my.cloneFrom(other);
    267                                         }
    268                                 } else if (my.modified) {
    269                                         if (myd.before(otherd)) {
    270                                                 conflicts.put(my, other);
    271                                         }
    272                                 }
    273                                 merged.put(other, my);
    274                                 return true;
    275                         }
    276                 }
    277                 return false;
    278         }
     26    /**
     27    * Map from primitives in the database to visited primitives. (Attention: The other way
     28    * round than merged)
     29    */
     30    public Map<OsmPrimitive, OsmPrimitive> conflicts = new HashMap<OsmPrimitive, OsmPrimitive>();
     31
     32    private final DataSet ds;
     33    private final DataSet mergeds;
     34
     35    private final HashMap<Long, Node> nodeshash = new HashMap<Long, Node>();
     36    private final HashMap<Long, Way> wayshash = new HashMap<Long, Way>();
     37    private final HashMap<Long, Relation> relshash = new HashMap<Long, Relation>();
     38
     39    /**
     40    * A list of all primitives that got replaced with other primitives.
     41    * Key is the primitives in the other's dataset and the value is the one that is now
     42    * in ds.nodes instead.
     43    */
     44    private final Map<OsmPrimitive, OsmPrimitive> merged
     45        = new HashMap<OsmPrimitive, OsmPrimitive>();
     46
     47    public MergeVisitor(DataSet ds, DataSet mergeds) {
     48        this.ds = ds;
     49        this.mergeds = mergeds;
     50
     51        for (Node n : ds.nodes) if (n.id != 0) nodeshash.put(n.id, n);
     52        for (Way w : ds.ways) if (w.id != 0) wayshash.put(w.id, w);
     53        for (Relation r : ds.relations) if (r.id != 0) relshash.put(r.id, r);
     54    }
     55
     56    private <P extends OsmPrimitive> void genMerge(P other,
     57            Collection<P> myprims, Collection<P> mergeprims,
     58            HashMap<Long, P> primhash) {
     59        // 1. Try to find an identical prim with the same id.
     60        if (mergeAfterId(myprims, primhash, other))
     61            return;
     62
     63        // 2. Try to find a prim we can merge with the prim from the other ds.
     64        for (P my : myprims) {
     65            // LinkedList.contains calls equal, and OsmPrimitive.equal
     66            // compares just the id.
     67            if (match(my, other) && !mergeprims.contains(my)) {
     68                merged.put(other, my);
     69                mergeCommon(my, other);
     70                return;
     71            }
     72        }
     73
     74        // 3. No idea how to merge that.  Simply add it unchanged.
     75        myprims.add(other);
     76    }
     77
     78    public void visit(Node other) {
     79        genMerge(other, ds.nodes, mergeds.nodes, nodeshash);
     80    }
     81
     82    public void visit(Way other) {
     83        fixWay(other);
     84        genMerge(other, ds.ways, mergeds.ways, wayshash);
     85    }
     86
     87    public void visit(Relation other) {
     88        fixRelation(other);
     89        genMerge(other, ds.relations, mergeds.relations, relshash);
     90    }
     91
     92    /**
     93    * Postprocess the dataset and fix all merged references to point to the actual
     94    * data.
     95    */
     96    public void fixReferences() {
     97        for (Way w : ds.ways) fixWay(w);
     98        for (Relation r : ds.relations) fixRelation(r);
     99        for (OsmPrimitive osm : conflicts.values())
     100            if (osm instanceof Way)
     101                fixWay((Way)osm);
     102            else if (osm instanceof Relation)
     103                fixRelation((Relation) osm);
     104    }
     105
     106    private void fixWay(Way w) {
     107        boolean replacedSomething = false;
     108        LinkedList<Node> newNodes = new LinkedList<Node>();
     109        for (Node n : w.nodes) {
     110            Node otherN = (Node) merged.get(n);
     111            newNodes.add(otherN == null ? n : otherN);
     112            if (otherN != null)
     113                replacedSomething = true;
     114        }
     115        if (replacedSomething) {
     116            w.nodes.clear();
     117            w.nodes.addAll(newNodes);
     118        }
     119    }
     120
     121    private void fixRelation(Relation r) {
     122        boolean replacedSomething = false;
     123        LinkedList<RelationMember> newMembers = new LinkedList<RelationMember>();
     124        for (RelationMember m : r.members) {
     125            OsmPrimitive otherP = merged.get(m.member);
     126            if (otherP == null) {
     127                newMembers.add(m);
     128            } else {
     129                RelationMember mnew = new RelationMember(m);
     130                mnew.member = otherP;
     131                newMembers.add(mnew);
     132                replacedSomething = true;
     133            }
     134        }
     135        if (replacedSomething) {
     136            r.members.clear();
     137            r.members.addAll(newMembers);
     138        }
     139    }
     140
     141    private static <P extends OsmPrimitive> boolean match(P p1, P p2) {
     142        if ((p1.id == 0 || p2.id == 0) && !p1.incomplete && !p2.incomplete) {
     143            return realMatch(p1, p2);
     144        }
     145        return p1.id == p2.id;
     146    }
     147
     148    /** @return true if the prims have pretty much the same data, i.e. the
     149    * same position, the same members, ...
     150    */
     151    // Java cannot dispatch on generics...
     152    private static boolean realMatch(OsmPrimitive p1, OsmPrimitive p2) {
     153        if (p1 instanceof Node && p2 instanceof Node) {
     154            return realMatch((Node) p1, (Node) p2);
     155        } else if (p1 instanceof Way && p2 instanceof Way) {
     156            return realMatch((Way) p1, (Way) p2);
     157        } else if (p1 instanceof Relation && p2 instanceof Relation) {
     158            return realMatch((Relation) p1, (Relation) p2);
     159        } else {
     160            throw new RuntimeException("arguments have unknown type");
     161        }
     162    }
     163
     164    private static boolean realMatch(Node n1, Node n2) {
     165        return n1.coor.equalsEpsilon(n2.coor);
     166    }
     167
     168    private static boolean realMatch(Way w1, Way w2) {
     169        if (w1.nodes.size() != w2.nodes.size())
     170            return false;
     171        Iterator<Node> it = w1.nodes.iterator();
     172        for (Node n : w2.nodes)
     173            if (!match(n, it.next()))
     174                return false;
     175        return true;
     176    }
     177
     178    private static boolean realMatch(Relation w1, Relation w2) {
     179        // FIXME this is not perfect yet...
     180        if (w1.members.size() != w2.members.size())
     181            return false;
     182        for (RelationMember em : w1.members) {
     183            if (!w2.members.contains(em)) {
     184                return false;
     185            }
     186        }
     187        return true;
     188    }
     189
     190    /**
     191    * Merge the common parts of an osm primitive.
     192    * @param my The object, the information gets merged into
     193    * @param other The object, the information gets merged from
     194    */
     195    private void mergeCommon(OsmPrimitive my, OsmPrimitive other) {
     196        if (other.deleted)
     197            my.delete(true);
     198        if (my.id == 0 || !my.modified || other.modified) {
     199            if (my.id == 0 && other.id != 0) {
     200                my.id = other.id;
     201                my.modified = other.modified; // match a new node
     202            } else if (my.id != 0 && other.id != 0 && other.modified)
     203                my.modified = true;
     204        }
     205        if (other.keys == null)
     206            return;
     207        if (my.keySet().containsAll(other.keys.keySet()))
     208            return;
     209        if (my.keys == null)
     210            my.keys = other.keys;
     211        else
     212            my.keys.putAll(other.keys);
     213
     214        my.modified = true;
     215    }
     216
     217    /**
     218    * @return <code>true</code>, if no merge is needed or merge is performed already.
     219    */
     220    private <P extends OsmPrimitive> boolean mergeAfterId(
     221            Collection<P> primitives, HashMap<Long, P> hash, P other) {
     222        // Fast-path merging of identical objects
     223        if (hash.containsKey(other.id)) {
     224            P my = hash.get(other.id);
     225            if (my.realEqual(other, true)) {
     226                merged.put(other, my);
     227                return true;
     228            }
     229        }
     230
     231        for (P my : primitives) {
     232            if (my.realEqual(other, false)) {
     233                merged.put(other, my);
     234                return true; // no merge needed.
     235            }
     236            if (my.realEqual(other, true)) {
     237                Date myd = my.timestamp == null ? new Date(0) : my.getTimestamp();
     238                Date otherd = other.timestamp == null ? new Date(0) : other.getTimestamp();
     239
     240                // they differ in modified/timestamp combination only. Auto-resolve it.
     241                merged.put(other, my);
     242                if (myd.before(otherd)) {
     243                    my.modified = other.modified;
     244                    my.timestamp = other.timestamp;
     245                }
     246                return true; // merge done.
     247            }
     248            if (my.id == other.id && my.id != 0) {
     249                Date myd = my.timestamp == null ? new Date(0) : my.getTimestamp();
     250                Date otherd = other.timestamp == null ? new Date(0) : other.getTimestamp();
     251
     252                if (my.incomplete || other.incomplete) {
     253                    if (my.incomplete) {
     254                        my.cloneFrom(other);
     255                    }
     256                } else if (my.modified && other.modified) {
     257                    conflicts.put(my, other);
     258                } else if (!my.modified && !other.modified) {
     259                    if (myd.before(otherd)) {
     260                        my.cloneFrom(other);
     261                    }
     262                } else if (other.modified) {
     263                    if (myd.after(otherd)) {
     264                        conflicts.put(my, other);
     265                    } else {
     266                        my.cloneFrom(other);
     267                    }
     268                } else if (my.modified) {
     269                    if (myd.before(otherd)) {
     270                        conflicts.put(my, other);
     271                    }
     272                }
     273                merged.put(other, my);
     274                return true;
     275            }
     276        }
     277        return false;
     278    }
    279279}
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/NameVisitor.java

    r756 r1169  
    1717/**
    1818 * Able to create a name and an icon for each data element.
    19  * 
     19 *
    2020 * @author imi
    2121 */
    2222public class NameVisitor implements Visitor {
    2323
    24         /**
    25          * The name of the item class
    26          */
    27         public String className;
    28         public String classNamePlural;
    29         /**
    30          * The name of this item.
    31          */
    32         public String name;
    33         /**
    34          * The icon of this item.
    35          */
    36         public Icon icon;
    37        
    38         /**
    39          * If the node has a name-key or id-key, this is displayed. If not, (lat,lon)
    40          * is displayed.
    41          */
    42         public void visit(Node n) {
    43                 name = n.getName();
    44                 addId(n);
    45                 icon = ImageProvider.get("data", "node");
    46                 className = "node";
    47                 classNamePlural = trn("node", "nodes", 2);
    48         }
     24    /**
     25     * The name of the item class
     26     */
     27    public String className;
     28    public String classNamePlural;
     29    /**
     30     * The name of this item.
     31     */
     32    public String name;
     33    /**
     34     * The icon of this item.
     35     */
     36    public Icon icon;
    4937
    50         /**
    51          * If the way has a name-key or id-key, this is displayed. If not, (x nodes)
    52          * is displayed with x being the number of nodes in the way.
    53          */
    54         public void visit(Way w) {
    55                 name = w.getName();
    56                 addId(w);
    57                 icon = ImageProvider.get("data", "way");
    58                 className = "way";
    59                 classNamePlural = trn("way", "ways", 2);
    60         }
    61        
    62         /**
    63          */
    64         public void visit(Relation e) {
    65                 name = e.getName();
    66                 addId(e);
    67                 icon = ImageProvider.get("data", "relation");
    68                 className = "relation";
    69                 classNamePlural = trn("relation", "relations", 2);
    70         }
    71        
    72         public JLabel toLabel() {
    73                 return new JLabel(name, icon, JLabel.HORIZONTAL);
    74         }
     38    /**
     39     * If the node has a name-key or id-key, this is displayed. If not, (lat,lon)
     40     * is displayed.
     41     */
     42    public void visit(Node n) {
     43        name = n.getName();
     44        addId(n);
     45        icon = ImageProvider.get("data", "node");
     46        className = "node";
     47        classNamePlural = trn("node", "nodes", 2);
     48    }
     49
     50    /**
     51     * If the way has a name-key or id-key, this is displayed. If not, (x nodes)
     52     * is displayed with x being the number of nodes in the way.
     53     */
     54    public void visit(Way w) {
     55        name = w.getName();
     56        addId(w);
     57        icon = ImageProvider.get("data", "way");
     58        className = "way";
     59        classNamePlural = trn("way", "ways", 2);
     60    }
     61
     62    /**
     63     */
     64    public void visit(Relation e) {
     65        name = e.getName();
     66        addId(e);
     67        icon = ImageProvider.get("data", "relation");
     68        className = "relation";
     69        classNamePlural = trn("relation", "relations", 2);
     70    }
     71
     72    public JLabel toLabel() {
     73        return new JLabel(name, icon, JLabel.HORIZONTAL);
     74    }
    7575
    7676
    77         private void addId(OsmPrimitive osm) {
    78             if (Main.pref.getBoolean("osm-primitives.showid"))
    79                         name += tr(" [id: {0}]", osm.id);
     77    private void addId(OsmPrimitive osm) {
     78        if (Main.pref.getBoolean("osm-primitives.showid"))
     79            name += tr(" [id: {0}]", osm.id);
    8080    }
    8181}
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/SimplePaintVisitor.java

    r999 r1169  
    3232public class SimplePaintVisitor implements Visitor {
    3333
    34         public final static Color darkerblue = new Color(0,0,96);
    35         public final static Color darkblue = new Color(0,0,128);
    36         public final static Color darkgreen = new Color(0,128,0);
    37         public final static Color teal = new Color(0,128,128);
    38 
    39         /**
    40         * The environment to paint to.
    41         */
    42         protected Graphics g;
    43         /**
    44         * MapView to get screen coordinates.
    45         */
    46         protected NavigatableComponent nc;
    47 
    48         public boolean inactive;
    49 
    50         protected static final double PHI = Math.toRadians(20);
    51 
    52         /**
    53         * Preferences
    54         */
    55         protected Color inactiveColor;
    56         protected Color selectedColor;
    57         protected Color nodeColor;
    58         protected Color dfltWayColor;
    59         protected Color relationColor;
    60         protected Color untaggedWayColor;
    61         protected Color incompleteColor;
    62         protected Color backgroundColor;
    63         protected boolean showDirectionArrow;
    64         protected boolean showRelevantDirectionsOnly;
    65         protected boolean showOrderNumber;
    66         protected boolean fillSelectedNode;
    67         protected boolean fillUnselectedNode;
    68         protected int selectedNodeRadius;
    69         protected int unselectedNodeRadius;
    70         protected int selectedNodeSize;
    71         protected int unselectedNodeSize;
    72         protected int defaultSegmentWidth;
    73         protected int virtualNodeSize;
    74         protected int virtualNodeSpace;
    75         protected int segmentNumberSpace;
    76         protected int taggedNodeRadius;
    77         protected int taggedNodeSize;
    78 
    79         /**
    80         * Draw subsequent segments of same color as one Path
    81         */
    82         protected Color currentColor = null;
    83         protected GeneralPath currentPath = new GeneralPath();
    84 
    85         Rectangle bbox = new Rectangle();
    86 
    87         protected void getSettings(Boolean virtual) {
    88                 inactiveColor = Main.pref.getColor(marktr("inactive"), Color.DARK_GRAY);
    89                 selectedColor = Main.pref.getColor(marktr("selected"), Color.WHITE);
    90                 nodeColor = Main.pref.getColor(marktr("node"), Color.RED);
    91                 dfltWayColor = Main.pref.getColor(marktr("way"), darkblue);
    92                 relationColor = Main.pref.getColor(marktr("relation"), teal);
    93                 untaggedWayColor = Main.pref.getColor(marktr("untagged way"), darkgreen);
    94                 incompleteColor = Main.pref.getColor(marktr("incomplete way"), darkerblue);
    95                 backgroundColor = Main.pref.getColor(marktr("background"), Color.BLACK);
    96                 showDirectionArrow = Main.pref.getBoolean("draw.segment.direction");
    97                 showRelevantDirectionsOnly = Main.pref.getBoolean("draw.segment.relevant_directions_only");
    98                 showOrderNumber = Main.pref.getBoolean("draw.segment.order_number");
    99                 selectedNodeRadius = Main.pref.getInteger("mappaint.node.selected-size", 5) / 2;
    100                 selectedNodeSize = selectedNodeRadius * 2;
    101                 unselectedNodeRadius = Main.pref.getInteger("mappaint.node.unselected-size", 3) / 2;
    102                 unselectedNodeSize = unselectedNodeRadius * 2;
    103                 taggedNodeRadius = Main.pref.getInteger("mappaint.node.tagged-size", 5) / 2;
    104                 taggedNodeSize = taggedNodeRadius * 2;
    105                 defaultSegmentWidth = Main.pref.getInteger("mappaint.segment.default-width", 2);
    106                 fillSelectedNode = Main.pref.getBoolean("mappaint.node.fill-selected", true);
    107                 fillUnselectedNode = Main.pref.getBoolean("mappaint.node.fill-unselected", false);
    108                 virtualNodeSize = virtual ? Main.pref.getInteger("mappaint.node.virtual-size", 8) / 2 : 0;
    109                 virtualNodeSpace = Main.pref.getInteger("mappaint.node.virtual-space", 70);
    110                 segmentNumberSpace = Main.pref.getInteger("mappaint.segmentnumber.space", 40);
    111 
    112                 ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
    113                         Main.pref.getBoolean("mappaint.use-antialiasing", false) ?
    114                         RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF);
    115         }
    116 
    117         public void visitAll(DataSet data, Boolean virtual) {
    118                 getSettings(virtual);
    119                 // draw tagged ways first, then untagged ways. takes
    120                 // time to iterate through list twice, OTOH does not
    121                 // require changing the colour while painting...
    122                 for (final OsmPrimitive osm : data.relations)
    123                         if (!osm.deleted && !osm.selected)
    124                                 osm.visit(this);
    125 
    126                 for (final OsmPrimitive osm : data.ways)
    127                         if (!osm.deleted && !osm.selected && osm.tagged)
    128                                 osm.visit(this);
    129                 displaySegments();
    130 
    131                 for (final OsmPrimitive osm : data.ways)
    132                         if (!osm.deleted && !osm.selected && !osm.tagged)
    133                                 osm.visit(this);
    134                 displaySegments();
    135 
    136                 for (final OsmPrimitive osm : data.getSelected())
    137                         if (!osm.deleted)
    138                                 osm.visit(this);
    139                 displaySegments();
    140 
    141                 for (final OsmPrimitive osm : data.nodes)
    142                         if (!osm.deleted && !osm.selected)
    143                                 osm.visit(this);
    144                 if(virtualNodeSize != 0)
    145                 {
    146                         currentColor = nodeColor;
    147                         for (final OsmPrimitive osm : data.ways)
    148                                 if (!osm.deleted)
    149                                         visitVirtual((Way)osm);
    150                         displaySegments();
    151                 }
    152         }
    153 
    154         /**
    155         * Draw a small rectangle.
    156         * White if selected (as always) or red otherwise.
    157         *
    158         * @param n The node to draw.
    159         */
    160         public void visit(Node n) {
    161                 if (n.incomplete) return;
    162 
    163                 if (inactive)
    164                         drawNode(n, inactiveColor, unselectedNodeSize, unselectedNodeRadius, fillUnselectedNode);
    165                 else if (n.selected)
    166                         drawNode(n, selectedColor, selectedNodeSize, selectedNodeRadius, fillSelectedNode);
    167                 else if(n.tagged)
    168                         drawNode(n, nodeColor, taggedNodeSize, taggedNodeRadius, fillUnselectedNode);
    169                 else
    170                         drawNode(n, nodeColor, unselectedNodeSize, unselectedNodeRadius, fillUnselectedNode);
    171         }
    172 
    173         public static Boolean isLargeSegment(Point p1, Point p2, int space)
    174         {
    175                 int xd = p1.x-p2.x; if(xd < 0) xd = -xd;
    176                 int yd = p1.y-p2.y; if(yd < 0) yd = -yd;
    177                 return (xd+yd > space);
    178         }
    179 
    180         public void visitVirtual(Way w) {
    181                 Iterator<Node> it = w.nodes.iterator();
    182                 if (it.hasNext()) {
    183                         Point lastP = nc.getPoint(it.next().eastNorth);
    184                         while(it.hasNext())
    185                         {
    186                                 Point p = nc.getPoint(it.next().eastNorth);
    187                                 if(isSegmentVisible(lastP, p) && isLargeSegment(lastP, p, virtualNodeSpace))
    188                                 {
    189                                         int x = (p.x+lastP.x)/2;
    190                                         int y = (p.y+lastP.y)/2;
    191                                         currentPath.moveTo(x-virtualNodeSize, y);
    192                                         currentPath.lineTo(x+virtualNodeSize, y);
    193                                         currentPath.moveTo(x, y-virtualNodeSize);
    194                                         currentPath.lineTo(x, y+virtualNodeSize);
    195                                 }
    196                                 lastP = p;
    197                         }
    198                 }
    199         }
    200 
    201         /**
    202         * Draw a darkblue line for all segments.
    203         * @param w The way to draw.
    204         */
    205         public void visit(Way w) {
    206                 if (w.incomplete || w.nodes.size() < 2)
    207                         return;
    208 
    209                 // show direction arrows, if draw.segment.relevant_directions_only is not set, the way is tagged with a direction key
    210                 // (even if the tag is negated as in oneway=false) or the way is selected
    211 
    212                 boolean showThisDirectionArrow = w.selected
    213                 || (showDirectionArrow && (!showRelevantDirectionsOnly || w.hasDirectionKeys));
    214                 Color wayColor;
    215 
    216                 if (inactive) {
    217                         wayColor = inactiveColor;
    218                 } else if (!w.tagged) {
    219                         wayColor = untaggedWayColor;
    220                 } else {
    221                         wayColor = dfltWayColor;
    222                 }
    223 
    224                 Iterator<Node> it = w.nodes.iterator();
    225                 if (it.hasNext()) {
    226                         Point lastP = nc.getPoint(it.next().eastNorth);
    227                         for (int orderNumber = 1; it.hasNext(); orderNumber++) {
    228                                 Point p = nc.getPoint(it.next().eastNorth);
    229                                 drawSegment(lastP, p, w.selected && !inactive ? selectedColor : wayColor, showThisDirectionArrow);
    230                                 if (showOrderNumber)
    231                                         drawOrderNumber(lastP, p, orderNumber);
    232                                 lastP = p;
    233                         }
    234                 }
    235         }
    236 
    237         private Stroke relatedWayStroke = new BasicStroke(
    238                 4, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL);
    239         public void visit(Relation r) {
    240                 if (r.incomplete) return;
    241 
    242                 Color col;
    243                 if (inactive) {
    244                         col = inactiveColor;
    245                 } else if (r.selected) {
    246                         col = selectedColor;
    247                 } else {
    248                         col = relationColor;
    249                 }
    250                 g.setColor(col);
    251 
    252                 for (RelationMember m : r.members) {
    253                         if (m.member.incomplete || m.member.deleted) continue;
    254 
    255                         if (m.member instanceof Node) {
    256                                 Point p = nc.getPoint(((Node) m.member).eastNorth);
    257                                 if (p.x < 0 || p.y < 0
    258                                         || p.x > nc.getWidth() || p.y > nc.getHeight()) continue;
    259 
    260                                 g.drawOval(p.x-3, p.y-3, 6, 6);
    261                         } else if (m.member instanceof Way) {
    262                                 GeneralPath path = new GeneralPath();
    263 
    264                                 boolean first = true;
    265                                 for (Node n : ((Way) m.member).nodes) {
    266                                         if (n.incomplete || n.deleted) continue;
    267                                         Point p = nc.getPoint(n.eastNorth);
    268                                         if (first) {
    269                                                 path.moveTo(p.x, p.y);
    270                                                 first = false;
    271                                         } else {
    272                                                 path.lineTo(p.x, p.y);
    273                                         }
    274                                 }
    275 
    276                                 ((Graphics2D) g).draw(relatedWayStroke.createStrokedShape(path));
    277                         }
    278                 }
    279         }
    280 
    281         /**
    282         * Draw an number of the order of the two consecutive nodes within the
    283         * parents way
    284         */
    285         protected void drawOrderNumber(Point p1, Point p2, int orderNumber) {
    286                 if (isSegmentVisible(p1, p2) && isLargeSegment(p1, p2, segmentNumberSpace)) {
    287                         String on = Integer.toString(orderNumber);
    288                         int strlen = on.length();
    289                         int x = (p1.x+p2.x)/2 - 4*strlen;
    290                         int y = (p1.y+p2.y)/2 + 4;
    291 
    292                         if(virtualNodeSize != 0 && isLargeSegment(p1, p2, virtualNodeSpace))
    293                         {
    294                                 y = (p1.y+p2.y)/2 - virtualNodeSize - 3;
    295                         }
    296 
    297                         displaySegments(); // draw nodes on top!
    298                         Color c = g.getColor();
    299                         g.setColor(backgroundColor);
    300                         g.fillRect(x-1, y-12, 8*strlen+1, 14);
    301                         g.setColor(c);
    302                         g.drawString(on, x, y);
    303                 }
    304         }
    305 
    306         /**
    307         * Draw the node as small rectangle with the given color.
    308         *
    309         * @param n             The node to draw.
    310         * @param color The color of the node.
    311         */
    312         public void drawNode(Node n, Color color, int size, int radius, boolean fill) {
    313                 if (size > 1) {
    314                         Point p = nc.getPoint(n.eastNorth);
    315                         if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth())
    316                                         || (p.y > nc.getHeight()))
    317                                 return;
    318                         g.setColor(color);
    319                         if (fill) {
    320                                 g.fillRect(p.x - radius, p.y - radius, size, size);
    321                                 g.drawRect(p.x - radius, p.y - radius, size, size);
    322                         } else
    323                                 g.drawRect(p.x - radius, p.y - radius, size, size);
    324                 }
    325         }
    326 
    327         /**
    328         * Draw a line with the given color.
    329         */
    330         protected void drawSegment(Point p1, Point p2, Color col, boolean showDirection) {
    331                 if (col != currentColor) displaySegments(col);
    332 
    333                 if (isSegmentVisible(p1, p2)) {
    334                         currentPath.moveTo(p1.x, p1.y);
    335                         currentPath.lineTo(p2.x, p2.y);
    336 
    337                         if (showDirection) {
    338                                 double t = Math.atan2(p2.y-p1.y, p2.x-p1.x) + Math.PI;
    339                                 currentPath.lineTo((int)(p2.x + 10*Math.cos(t-PHI)), (int)(p2.y + 10*Math.sin(t-PHI)));
    340                                 currentPath.moveTo((int)(p2.x + 10*Math.cos(t+PHI)), (int)(p2.y + 10*Math.sin(t+PHI)));
    341                                 currentPath.lineTo(p2.x, p2.y);
    342                         }
    343                 }
    344         }
    345 
    346         protected boolean isSegmentVisible(Point p1, Point p2) {
    347                 if ((p1.x < 0) && (p2.x < 0)) return false;
    348                 if ((p1.y < 0) && (p2.y < 0)) return false;
    349                 if ((p1.x > nc.getWidth()) && (p2.x > nc.getWidth())) return false;
    350                 if ((p1.y > nc.getHeight()) && (p2.y > nc.getHeight())) return false;
    351                 return true;
    352         }
    353 
    354         public void setGraphics(Graphics g) {
    355                 this.g = g;
    356         }
    357 
    358         public void setNavigatableComponent(NavigatableComponent nc) {
    359                 this.nc = nc;
    360         }
    361 
    362         protected void displaySegments() {
    363                 displaySegments(null);
    364         }
    365         protected void displaySegments(Color newColor) {
    366                 if (currentPath != null) {
    367                         g.setColor(currentColor);
    368                         ((Graphics2D) g).draw(currentPath);
    369                         currentPath = new GeneralPath();
    370                         currentColor = newColor;
    371                 }
    372         }
     34    public final static Color darkerblue = new Color(0,0,96);
     35    public final static Color darkblue = new Color(0,0,128);
     36    public final static Color darkgreen = new Color(0,128,0);
     37    public final static Color teal = new Color(0,128,128);
     38
     39    /**
     40    * The environment to paint to.
     41    */
     42    protected Graphics g;
     43    /**
     44    * MapView to get screen coordinates.
     45    */
     46    protected NavigatableComponent nc;
     47
     48    public boolean inactive;
     49
     50    protected static final double PHI = Math.toRadians(20);
     51
     52    /**
     53    * Preferences
     54    */
     55    protected Color inactiveColor;
     56    protected Color selectedColor;
     57    protected Color nodeColor;
     58    protected Color dfltWayColor;
     59    protected Color relationColor;
     60    protected Color untaggedWayColor;
     61    protected Color incompleteColor;
     62    protected Color backgroundColor;
     63    protected boolean showDirectionArrow;
     64    protected boolean showRelevantDirectionsOnly;
     65    protected boolean showOrderNumber;
     66    protected boolean fillSelectedNode;
     67    protected boolean fillUnselectedNode;
     68    protected int selectedNodeRadius;
     69    protected int unselectedNodeRadius;
     70    protected int selectedNodeSize;
     71    protected int unselectedNodeSize;
     72    protected int defaultSegmentWidth;
     73    protected int virtualNodeSize;
     74    protected int virtualNodeSpace;
     75    protected int segmentNumberSpace;
     76    protected int taggedNodeRadius;
     77    protected int taggedNodeSize;
     78
     79    /**
     80    * Draw subsequent segments of same color as one Path
     81    */
     82    protected Color currentColor = null;
     83    protected GeneralPath currentPath = new GeneralPath();
     84
     85    Rectangle bbox = new Rectangle();
     86
     87    protected void getSettings(Boolean virtual) {
     88        inactiveColor = Main.pref.getColor(marktr("inactive"), Color.DARK_GRAY);
     89        selectedColor = Main.pref.getColor(marktr("selected"), Color.WHITE);
     90        nodeColor = Main.pref.getColor(marktr("node"), Color.RED);
     91        dfltWayColor = Main.pref.getColor(marktr("way"), darkblue);
     92        relationColor = Main.pref.getColor(marktr("relation"), teal);
     93        untaggedWayColor = Main.pref.getColor(marktr("untagged way"), darkgreen);
     94        incompleteColor = Main.pref.getColor(marktr("incomplete way"), darkerblue);
     95        backgroundColor = Main.pref.getColor(marktr("background"), Color.BLACK);
     96        showDirectionArrow = Main.pref.getBoolean("draw.segment.direction");
     97        showRelevantDirectionsOnly = Main.pref.getBoolean("draw.segment.relevant_directions_only");
     98        showOrderNumber = Main.pref.getBoolean("draw.segment.order_number");
     99        selectedNodeRadius = Main.pref.getInteger("mappaint.node.selected-size", 5) / 2;
     100        selectedNodeSize = selectedNodeRadius * 2;
     101        unselectedNodeRadius = Main.pref.getInteger("mappaint.node.unselected-size", 3) / 2;
     102        unselectedNodeSize = unselectedNodeRadius * 2;
     103        taggedNodeRadius = Main.pref.getInteger("mappaint.node.tagged-size", 5) / 2;
     104        taggedNodeSize = taggedNodeRadius * 2;
     105        defaultSegmentWidth = Main.pref.getInteger("mappaint.segment.default-width", 2);
     106        fillSelectedNode = Main.pref.getBoolean("mappaint.node.fill-selected", true);
     107        fillUnselectedNode = Main.pref.getBoolean("mappaint.node.fill-unselected", false);
     108        virtualNodeSize = virtual ? Main.pref.getInteger("mappaint.node.virtual-size", 8) / 2 : 0;
     109        virtualNodeSpace = Main.pref.getInteger("mappaint.node.virtual-space", 70);
     110        segmentNumberSpace = Main.pref.getInteger("mappaint.segmentnumber.space", 40);
     111
     112        ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
     113            Main.pref.getBoolean("mappaint.use-antialiasing", false) ?
     114            RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF);
     115    }
     116
     117    public void visitAll(DataSet data, Boolean virtual) {
     118        getSettings(virtual);
     119        // draw tagged ways first, then untagged ways. takes
     120        // time to iterate through list twice, OTOH does not
     121        // require changing the colour while painting...
     122        for (final OsmPrimitive osm : data.relations)
     123            if (!osm.deleted && !osm.selected)
     124                osm.visit(this);
     125
     126        for (final OsmPrimitive osm : data.ways)
     127            if (!osm.deleted && !osm.selected && osm.tagged)
     128                osm.visit(this);
     129        displaySegments();
     130
     131        for (final OsmPrimitive osm : data.ways)
     132            if (!osm.deleted && !osm.selected && !osm.tagged)
     133                osm.visit(this);
     134        displaySegments();
     135
     136        for (final OsmPrimitive osm : data.getSelected())
     137            if (!osm.deleted)
     138                osm.visit(this);
     139        displaySegments();
     140
     141        for (final OsmPrimitive osm : data.nodes)
     142            if (!osm.deleted && !osm.selected)
     143                osm.visit(this);
     144        if(virtualNodeSize != 0)
     145        {
     146            currentColor = nodeColor;
     147            for (final OsmPrimitive osm : data.ways)
     148                if (!osm.deleted)
     149                    visitVirtual((Way)osm);
     150            displaySegments();
     151        }
     152    }
     153
     154    /**
     155    * Draw a small rectangle.
     156    * White if selected (as always) or red otherwise.
     157    *
     158    * @param n The node to draw.
     159    */
     160    public void visit(Node n) {
     161        if (n.incomplete) return;
     162
     163        if (inactive)
     164            drawNode(n, inactiveColor, unselectedNodeSize, unselectedNodeRadius, fillUnselectedNode);
     165        else if (n.selected)
     166            drawNode(n, selectedColor, selectedNodeSize, selectedNodeRadius, fillSelectedNode);
     167        else if(n.tagged)
     168            drawNode(n, nodeColor, taggedNodeSize, taggedNodeRadius, fillUnselectedNode);
     169        else
     170            drawNode(n, nodeColor, unselectedNodeSize, unselectedNodeRadius, fillUnselectedNode);
     171    }
     172
     173    public static Boolean isLargeSegment(Point p1, Point p2, int space)
     174    {
     175        int xd = p1.x-p2.x; if(xd < 0) xd = -xd;
     176        int yd = p1.y-p2.y; if(yd < 0) yd = -yd;
     177        return (xd+yd > space);
     178    }
     179
     180    public void visitVirtual(Way w) {
     181        Iterator<Node> it = w.nodes.iterator();
     182        if (it.hasNext()) {
     183            Point lastP = nc.getPoint(it.next().eastNorth);
     184            while(it.hasNext())
     185            {
     186                Point p = nc.getPoint(it.next().eastNorth);
     187                if(isSegmentVisible(lastP, p) && isLargeSegment(lastP, p, virtualNodeSpace))
     188                {
     189                    int x = (p.x+lastP.x)/2;
     190                    int y = (p.y+lastP.y)/2;
     191                    currentPath.moveTo(x-virtualNodeSize, y);
     192                    currentPath.lineTo(x+virtualNodeSize, y);
     193                    currentPath.moveTo(x, y-virtualNodeSize);
     194                    currentPath.lineTo(x, y+virtualNodeSize);
     195                }
     196                lastP = p;
     197            }
     198        }
     199    }
     200
     201    /**
     202    * Draw a darkblue line for all segments.
     203    * @param w The way to draw.
     204    */
     205    public void visit(Way w) {
     206        if (w.incomplete || w.nodes.size() < 2)
     207            return;
     208
     209        // show direction arrows, if draw.segment.relevant_directions_only is not set, the way is tagged with a direction key
     210        // (even if the tag is negated as in oneway=false) or the way is selected
     211
     212        boolean showThisDirectionArrow = w.selected
     213        || (showDirectionArrow && (!showRelevantDirectionsOnly || w.hasDirectionKeys));
     214        Color wayColor;
     215
     216        if (inactive) {
     217            wayColor = inactiveColor;
     218        } else if (!w.tagged) {
     219            wayColor = untaggedWayColor;
     220        } else {
     221            wayColor = dfltWayColor;
     222        }
     223
     224        Iterator<Node> it = w.nodes.iterator();
     225        if (it.hasNext()) {
     226            Point lastP = nc.getPoint(it.next().eastNorth);
     227            for (int orderNumber = 1; it.hasNext(); orderNumber++) {
     228                Point p = nc.getPoint(it.next().eastNorth);
     229                drawSegment(lastP, p, w.selected && !inactive ? selectedColor : wayColor, showThisDirectionArrow);
     230                if (showOrderNumber)
     231                    drawOrderNumber(lastP, p, orderNumber);
     232                lastP = p;
     233            }
     234        }
     235    }
     236
     237    private Stroke relatedWayStroke = new BasicStroke(
     238        4, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL);
     239    public void visit(Relation r) {
     240        if (r.incomplete) return;
     241
     242        Color col;
     243        if (inactive) {
     244            col = inactiveColor;
     245        } else if (r.selected) {
     246            col = selectedColor;
     247        } else {
     248            col = relationColor;
     249        }
     250        g.setColor(col);
     251
     252        for (RelationMember m : r.members) {
     253            if (m.member.incomplete || m.member.deleted) continue;
     254
     255            if (m.member instanceof Node) {
     256                Point p = nc.getPoint(((Node) m.member).eastNorth);
     257                if (p.x < 0 || p.y < 0
     258                    || p.x > nc.getWidth() || p.y > nc.getHeight()) continue;
     259
     260                g.drawOval(p.x-3, p.y-3, 6, 6);
     261            } else if (m.member instanceof Way) {
     262                GeneralPath path = new GeneralPath();
     263
     264                boolean first = true;
     265                for (Node n : ((Way) m.member).nodes) {
     266                    if (n.incomplete || n.deleted) continue;
     267                    Point p = nc.getPoint(n.eastNorth);
     268                    if (first) {
     269                        path.moveTo(p.x, p.y);
     270                        first = false;
     271                    } else {
     272                        path.lineTo(p.x, p.y);
     273                    }
     274                }
     275
     276                ((Graphics2D) g).draw(relatedWayStroke.createStrokedShape(path));
     277            }
     278        }
     279    }
     280
     281    /**
     282    * Draw an number of the order of the two consecutive nodes within the
     283    * parents way
     284    */
     285    protected void drawOrderNumber(Point p1, Point p2, int orderNumber) {
     286        if (isSegmentVisible(p1, p2) && isLargeSegment(p1, p2, segmentNumberSpace)) {
     287            String on = Integer.toString(orderNumber);
     288            int strlen = on.length();
     289            int x = (p1.x+p2.x)/2 - 4*strlen;
     290            int y = (p1.y+p2.y)/2 + 4;
     291
     292            if(virtualNodeSize != 0 && isLargeSegment(p1, p2, virtualNodeSpace))
     293            {
     294                y = (p1.y+p2.y)/2 - virtualNodeSize - 3;
     295            }
     296
     297            displaySegments(); // draw nodes on top!
     298            Color c = g.getColor();
     299            g.setColor(backgroundColor);
     300            g.fillRect(x-1, y-12, 8*strlen+1, 14);
     301            g.setColor(c);
     302            g.drawString(on, x, y);
     303        }
     304    }
     305
     306    /**
     307    * Draw the node as small rectangle with the given color.
     308    *
     309    * @param n     The node to draw.
     310    * @param color The color of the node.
     311    */
     312    public void drawNode(Node n, Color color, int size, int radius, boolean fill) {
     313        if (size > 1) {
     314            Point p = nc.getPoint(n.eastNorth);
     315            if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth())
     316                    || (p.y > nc.getHeight()))
     317                return;
     318            g.setColor(color);
     319            if (fill) {
     320                g.fillRect(p.x - radius, p.y - radius, size, size);
     321                g.drawRect(p.x - radius, p.y - radius, size, size);
     322            } else
     323                g.drawRect(p.x - radius, p.y - radius, size, size);
     324        }
     325    }
     326
     327    /**
     328    * Draw a line with the given color.
     329    */
     330    protected void drawSegment(Point p1, Point p2, Color col, boolean showDirection) {
     331        if (col != currentColor) displaySegments(col);
     332
     333        if (isSegmentVisible(p1, p2)) {
     334            currentPath.moveTo(p1.x, p1.y);
     335            currentPath.lineTo(p2.x, p2.y);
     336
     337            if (showDirection) {
     338                double t = Math.atan2(p2.y-p1.y, p2.x-p1.x) + Math.PI;
     339                currentPath.lineTo((int)(p2.x + 10*Math.cos(t-PHI)), (int)(p2.y + 10*Math.sin(t-PHI)));
     340                currentPath.moveTo((int)(p2.x + 10*Math.cos(t+PHI)), (int)(p2.y + 10*Math.sin(t+PHI)));
     341                currentPath.lineTo(p2.x, p2.y);
     342            }
     343        }
     344    }
     345
     346    protected boolean isSegmentVisible(Point p1, Point p2) {
     347        if ((p1.x < 0) && (p2.x < 0)) return false;
     348        if ((p1.y < 0) && (p2.y < 0)) return false;
     349        if ((p1.x > nc.getWidth()) && (p2.x > nc.getWidth())) return false;
     350        if ((p1.y > nc.getHeight()) && (p2.y > nc.getHeight())) return false;
     351        return true;
     352    }
     353
     354    public void setGraphics(Graphics g) {
     355        this.g = g;
     356    }
     357
     358    public void setNavigatableComponent(NavigatableComponent nc) {
     359        this.nc = nc;
     360    }
     361
     362    protected void displaySegments() {
     363        displaySegments(null);
     364    }
     365    protected void displaySegments(Color newColor) {
     366        if (currentPath != null) {
     367            g.setColor(currentColor);
     368            ((Graphics2D) g).draw(currentPath);
     369            currentPath = new GeneralPath();
     370            currentColor = newColor;
     371        }
     372    }
    373373}
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/Visitor.java

    r627 r1169  
    99 * Implementation of the visitor scheme. Every OsmPrimitive can be visited by
    1010 * several different visitors.
    11  * 
     11 *
    1212 * @author imi
    1313 */
    1414public interface Visitor {
    15         void visit(Node n);
    16         void visit(Way w);
    17         void visit(Relation e);
     15    void visit(Node n);
     16    void visit(Way w);
     17    void visit(Relation e);
    1818}
  • trunk/src/org/openstreetmap/josm/data/projection/Epsg4326.java

    r1032 r1169  
    1212public class Epsg4326 implements Projection {
    1313
    14         public EastNorth latlon2eastNorth(LatLon p) {
    15                 return new EastNorth(p.lon(), p.lat());
    16         }
     14    public EastNorth latlon2eastNorth(LatLon p) {
     15        return new EastNorth(p.lon(), p.lat());
     16    }
    1717
    18         public LatLon eastNorth2latlon(EastNorth p) {
    19                 return new LatLon(p.north(), p.east());
    20         }
     18    public LatLon eastNorth2latlon(EastNorth p) {
     19        return new LatLon(p.north(), p.east());
     20    }
    2121
    22         @Override public String toString() {
    23                 return tr("EPSG:4326");
    24         }
     22    @Override public String toString() {
     23        return tr("EPSG:4326");
     24    }
    2525
    2626    public String getCacheDirectoryName() {
     
    2828    }
    2929
    30         public double scaleFactor() {
    31             return 1.0/360;
     30    public double scaleFactor() {
     31        return 1.0/360;
    3232    }
    3333
    34         @Override public boolean equals(Object o) {
    35                 return o instanceof Epsg4326;
    36         }
     34    @Override public boolean equals(Object o) {
     35        return o instanceof Epsg4326;
     36    }
    3737
    38         @Override public int hashCode() {
    39                 return Epsg4326.class.hashCode();
    40         }
     38    @Override public int hashCode() {
     39        return Epsg4326.class.hashCode();
     40    }
    4141}
  • trunk/src/org/openstreetmap/josm/data/projection/Lambert.java

    r865 r1169  
    1414
    1515public class Lambert implements Projection {
    16         /**
    17         * Lambert I, II, III, and IV projection exponents
    18         */
    19         public static final double n[] = { 0.7604059656, 0.7289686274, 0.6959127966, 0.6712679322 };
    20 
    21         /**
    22         * Lambert I, II, III, and IV projection constants
    23         */
    24         public static final double c[] = { 11603796.98, 11745793.39, 11947992.52, 12136281.99 };
    25 
    26         /**
    27         * Lambert I, II, III, and IV false east
    28         */
    29         public static final double Xs[] = { 600000.0, 600000.0, 600000.0, 234.358 };
    30 
    31         /**
    32         * Lambert I, II, III, and IV false north
    33         */
    34         public static final double Ys[] = { 5657616.674, 6199695.768, 6791905.085, 7239161.542 };
    35 
    36         /**
    37         * Lambert I, II, III, and IV longitudinal offset to Greenwich meridian
    38         */
    39         public static final double lg0 = 0.04079234433198; // 2deg20'14.025"
    40 
    41         /**
    42         * precision in iterative schema
    43         */
    44 
    45         public static final double epsilon = 1e-11;
    46 
    47         /**
    48         * France is divided in 4 Lambert projection zones (1,2,3 + 4th for Corsica)
    49         */
    50         public static final double cMaxLatZone1 = Math.toRadians(57 * 0.9);
    51 
    52         public static final double zoneLimits[] = { Math.toRadians(53.5 * 0.9), // between Zone 1 and Zone 2 (in grad *0.9)
    53                         Math.toRadians(50.5 * 0.9), // between Zone 2 and Zone 3
    54                         Math.toRadians(47.51963 * 0.9), // between Zone 3 and Zone 4
    55                         Math.toRadians(46.17821 * 0.9) };// lowest latitude of Zone 4
    56 
    57         public static final double cMinLonZones = Math.toRadians(-4.9074074074074059 * 0.9);
    58 
    59         public static final double cMaxLonZones = Math.toRadians(10.2 * 0.9);
    60 
    61         /**
    62         *  Because josm cannot work correctly if two zones are displayed, we allow some overlapping
    63         */
    64         public static final double cMaxOverlappingZones = Math.toRadians(1.5 * 0.9);
    65 
    66         public static int layoutZone = -1;
    67 
    68         private static int currentZone = 0;
    69 
    70         private static boolean dontDisplayErrors = false;
    71 
    72         /**
    73         * @param p  WGS84 lat/lon (ellipsoid GRS80) (in degree)
    74         * @return eastnorth projection in Lambert Zone (ellipsoid Clark)
    75         */
    76         public EastNorth latlon2eastNorth(LatLon p) {
    77                 // translate ellipsoid GRS80 (WGS83) => Clark
    78                 LatLon geo = GRS802Clark(p);
    79                 double lt = geo.lat(); // in radian
    80                 double lg = geo.lon();
    81 
    82                 // check if longitude and latitude are inside the french Lambert zones
    83                 currentZone = 0;
    84                 boolean outOfLambertZones = false;
    85                 if (lt >= zoneLimits[3] && lt <= cMaxLatZone1 && lg >= cMinLonZones && lg <= cMaxLonZones) {
    86                         // zone I
    87                         if (lt > zoneLimits[0])
    88                                 currentZone = 0;
    89                         // zone II
    90                         else if (lt > zoneLimits[1])
    91                                 currentZone = 1;
    92                         // zone III
    93                         else if (lt > zoneLimits[2])
    94                                 currentZone = 2;
    95                         // zone III or IV
    96                         else if (lt > zoneLimits[3])
    97                                 // Note: zone IV is dedicated to Corsica island and extends from 47.8 to
    98                                 // 45.9 degrees of latitude. There is an overlap with zone III that can be
    99                                 // solved only with longitude (covers Corsica if lon > 7.2 degree)
    100                                 if (lg < Math.toRadians(8 * 0.9))
    101                                         currentZone = 2;
    102                                 else
    103                                         currentZone = 3;
    104                 } else {
    105                         outOfLambertZones = true; // possible when MAX_LAT is used
    106                         if (p.lat() != 0 && Math.abs(p.lat()) != Projection.MAX_LAT
    107                                         && p.lon() != 0 && Math.abs(p.lon()) != Projection.MAX_LON
    108                                         && dontDisplayErrors == false) {
    109                                 JOptionPane.showMessageDialog(Main.parent,
    110                                                 tr("The projection \"{0}\" is designed for\n"
    111                                                 + "latitudes between 46.1° and 57° only.\n"
    112                                                 + "Use another projection system if you are not using\n"
    113                                                 + "a french WMS server.\n"
    114                                                 + "Do not upload any data after this message.", this.toString()));
    115                                 dontDisplayErrors = true;
    116                         }
    117                 }
    118                 if (!outOfLambertZones) {
    119                         if (layoutZone == -1) {
    120                                 layoutZone = currentZone;
    121                                 dontDisplayErrors = false;
    122                         } else if (layoutZone != currentZone) {
    123                                 if ((currentZone < layoutZone && Math.abs(zoneLimits[currentZone] - lt) > cMaxOverlappingZones)
    124                                                 || (currentZone > layoutZone && Math.abs(zoneLimits[layoutZone] - lt) > cMaxOverlappingZones)) {
    125                                         JOptionPane.showMessageDialog(Main.parent,
    126                                                                         tr("IMPORTANT : data positionned far away from\n"
    127                                                                                         + "the current Lambert zone limits.\n"
    128                                                                                         + "Do not upload any data after this message.\n"
    129                                                                                         + "Undo your last action, Save your work \n"
    130                                                                                         + "and Start a new layer on the new zone."));
    131                                         layoutZone = -1;
    132                                         dontDisplayErrors = true;
    133                                 } else {
    134                                         System.out.println("temporarily extend Lambert zone " + layoutZone + " projection at lat,lon:"
    135                                                         + lt + "," + lg);
    136                                 }
    137                         }
    138                 }
    139                 if (layoutZone == -1) {
    140                         return ConicProjection(lt, lg, Xs[currentZone], Ys[currentZone], c[currentZone], n[currentZone]);
    141                 } // else
    142                 return ConicProjection(lt, lg, Xs[layoutZone], Ys[layoutZone], c[layoutZone], n[layoutZone]);
    143         }
    144 
    145         public LatLon eastNorth2latlon(EastNorth p) {
    146                 LatLon geo;
    147                 if (layoutZone == -1)
    148                         // possible until the Lambert zone is determined by latlon2eastNorth() with a valid LatLon
    149                         geo = Geographic(p, Xs[currentZone], Ys[currentZone], c[currentZone], n[currentZone]);
    150                 else
    151                         geo = Geographic(p, Xs[layoutZone], Ys[layoutZone], c[layoutZone], n[layoutZone]);
    152                 // translate ellipsoid Clark => GRS80 (WGS83)
    153                 LatLon wgs = Clark2GRS80(geo);
    154                 return new LatLon(Math.toDegrees(wgs.lat()), Math.toDegrees(wgs.lon()));
    155         }
    156 
    157         @Override public String toString() {
    158                 return tr("Lambert Zone (France)");
    159         }
    160 
    161         public String getCacheDirectoryName() {
    162                 return "lambert";
    163         }
    164 
    165         public double scaleFactor() {
    166                 return 1.0 / 360;
    167         }
    168 
    169         @Override
    170         public boolean equals(Object o) {
    171                 return o instanceof Lambert;
    172         }
    173 
    174         @Override
    175         public int hashCode() {
    176                 return Lambert.class.hashCode();
    177         }
    178 
    179         /**
    180         * Initializes from geographic coordinates. Note that reference ellipsoid
    181         * used by Lambert is the Clark ellipsoid.
    182         *
    183         * @param lat latitude in grad
    184         * @param lon longitude in grad
    185         * @param Xs  false east (coordinate system origin) in meters
    186         * @param Ys  false north (coordinate system origin) in meters
    187         * @param c   projection constant
    188         * @param n   projection exponent
    189         * @return EastNorth projected coordinates in meter
    190         */
    191         private EastNorth ConicProjection(double lat, double lon, double Xs, double Ys, double c, double n) {
    192                 double eslt = Ellipsoid.clarke.e * Math.sin(lat);
    193                 double l = Math.log(Math.tan(Math.PI / 4.0 + (lat / 2.0))
    194                                 * Math.pow((1.0 - eslt) / (1.0 + eslt), Ellipsoid.clarke.e / 2.0));
    195                 double east = Xs + c * Math.exp(-n * l) * Math.sin(n * (lon - lg0));
    196                 double north = Ys - c * Math.exp(-n * l) * Math.cos(n * (lon - lg0));
    197                 return new EastNorth(east, north);
    198         }
    199 
    200         /**
    201         * Initializes from projected coordinates (conic projection). Note that
    202         * reference ellipsoid used by Lambert is Clark
    203         *
    204         * @param coord projected coordinates pair in meters
    205         * @param Xs    false east (coordinate system origin) in meters
    206         * @param Ys    false north (coordinate system origin) in meters
    207         * @param c     projection constant
    208         * @param n     projection exponent
    209         * @return LatLon in radian
    210         */
    211         private LatLon Geographic(EastNorth eastNorth, double Xs, double Ys, double c, double n) {
    212                 double dx = eastNorth.east() - Xs;
    213                 double dy = Ys - eastNorth.north();
    214                 double R = Math.sqrt(dx * dx + dy * dy);
    215                 double gamma = Math.atan(dx / dy);
    216                 double l = -1.0 / n * Math.log(Math.abs(R / c));
    217                 l = Math.exp(l);
    218                 double lon = lg0 + gamma / n;
    219                 double lat = 2.0 * Math.atan(l) - Math.PI / 2.0;
    220                 double delta = 1.0;
    221                 while (delta > epsilon) {
    222                         double eslt = Ellipsoid.clarke.e * Math.sin(lat);
    223                         double nlt = 2.0 * Math.atan(Math.pow((1.0 + eslt) / (1.0 - eslt), Ellipsoid.clarke.e / 2.0) * l) - Math.PI
    224                                         / 2.0;
    225                         delta = Math.abs(nlt - lat);
    226                         lat = nlt;
    227                 }
    228                 return new LatLon(lat, lon); // in radian
    229         }
    230 
    231         /**
    232         * Translate latitude/longitude in WGS84, (ellipsoid GRS80) to Lambert
    233         * geographic, (ellipsoid Clark)
    234         *
    235         * @param wgs
    236         * @return
    237         */
    238         private LatLon GRS802Clark(LatLon wgs) {
    239                 double lat = Math.toRadians(wgs.lat()); // degree to radian
    240                 double lon = Math.toRadians(wgs.lon());
    241                 // WGS84 geographic => WGS84 cartesian
    242                 double N = Ellipsoid.GRS80.a / (Math.sqrt(1.0 - Ellipsoid.GRS80.e2 * Math.sin(lat) * Math.sin(lat)));
    243                 double X = (N/* +height */) * Math.cos(lat) * Math.cos(lon);
    244                 double Y = (N/* +height */) * Math.cos(lat) * Math.sin(lon);
    245                 double Z = (N * (1.0 - Ellipsoid.GRS80.e2)/* + height */) * Math.sin(lat);
    246                 // WGS84 => Lambert ellipsoide similarity
    247                 X += 168.0;
    248                 Y += 60.0;
    249                 Z += -320.0;
    250                 // Lambert cartesian => Lambert geographic
    251                 return Geographic(X, Y, Z, Ellipsoid.clarke);
    252         }
    253 
    254         /**
    255         * @param lambert
    256         * @return
    257         */
    258         private LatLon Clark2GRS80(LatLon lambert) {
    259                 double lat = lambert.lat(); // in radian
    260                 double lon = lambert.lon();
    261                 // Lambert geographic => Lambert cartesian
    262                 double N = Ellipsoid.clarke.a / (Math.sqrt(1.0 - Ellipsoid.clarke.e2 * Math.sin(lat) * Math.sin(lat)));
    263                 double X = (N/* +height */) * Math.cos(lat) * Math.cos(lon);
    264                 double Y = (N/* +height */) * Math.cos(lat) * Math.sin(lon);
    265                 double Z = (N * (1.0 - Ellipsoid.clarke.e2)/* + height */) * Math.sin(lat);
    266                 // Lambert => WGS84 ellipsoide similarity
    267                 X += -168.0;
    268                 Y += -60.0;
    269                 Z += 320.0;
    270                 // WGS84 cartesian => WGS84 geographic
    271                 return Geographic(X, Y, Z, Ellipsoid.GRS80);
    272         }
    273 
    274         /**
    275         * initializes from cartesian coordinates
    276         *
    277         * @param X
    278         *            1st coordinate in meters
    279         * @param Y
    280         *            2nd coordinate in meters
    281         * @param Z
    282         *            3rd coordinate in meters
    283         * @param ell
    284         *            reference ellipsoid
    285         */
    286         private LatLon Geographic(double X, double Y, double Z, Ellipsoid ell) {
    287                 double norm = Math.sqrt(X * X + Y * Y);
    288                 double lg = 2.0 * Math.atan(Y / (X + norm));
    289                 double lt = Math.atan(Z / (norm * (1.0 - (ell.a * ell.e2 / Math.sqrt(X * X + Y * Y + Z * Z)))));
    290                 double delta = 1.0;
    291                 while (delta > epsilon) {
    292                         double s2 = Math.sin(lt);
    293                         s2 *= s2;
    294                         double l = Math.atan((Z / norm)
    295                                 / (1.0 - (ell.a * ell.e2 * Math.cos(lt) / (norm * Math.sqrt(1.0 - ell.e2 * s2)))));
    296                         delta = Math.abs(l - lt);
    297                         lt = l;
    298                 }
    299                 double s2 = Math.sin(lt);
    300                 s2 *= s2;
    301                 // h = norm / Math.cos(lt) - ell.a / Math.sqrt(1.0 - ell.e2 * s2);
    302                 return new LatLon(lt, lg);
    303         }
     16    /**
     17    * Lambert I, II, III, and IV projection exponents
     18    */
     19    public static final double n[] = { 0.7604059656, 0.7289686274, 0.6959127966, 0.6712679322 };
     20
     21    /**
     22    * Lambert I, II, III, and IV projection constants
     23    */
     24    public static final double c[] = { 11603796.98, 11745793.39, 11947992.52, 12136281.99 };
     25
     26    /**
     27    * Lambert I, II, III, and IV false east
     28    */
     29    public static final double Xs[] = { 600000.0, 600000.0, 600000.0, 234.358 };
     30
     31    /**
     32    * Lambert I, II, III, and IV false north
     33    */
     34    public static final double Ys[] = { 5657616.674, 6199695.768, 6791905.085, 7239161.542 };
     35
     36    /**
     37    * Lambert I, II, III, and IV longitudinal offset to Greenwich meridian
     38    */
     39    public static final double lg0 = 0.04079234433198; // 2deg20'14.025"
     40
     41    /**
     42    * precision in iterative schema
     43    */
     44
     45    public static final double epsilon = 1e-11;
     46
     47    /**
     48    * France is divided in 4 Lambert projection zones (1,2,3 + 4th for Corsica)
     49    */
     50    public static final double cMaxLatZone1 = Math.toRadians(57 * 0.9);
     51
     52    public static final double zoneLimits[] = { Math.toRadians(53.5 * 0.9), // between Zone 1 and Zone 2 (in grad *0.9)
     53            Math.toRadians(50.5 * 0.9), // between Zone 2 and Zone 3
     54            Math.toRadians(47.51963 * 0.9), // between Zone 3 and Zone 4
     55            Math.toRadians(46.17821 * 0.9) };// lowest latitude of Zone 4
     56
     57    public static final double cMinLonZones = Math.toRadians(-4.9074074074074059 * 0.9);
     58
     59    public static final double cMaxLonZones = Math.toRadians(10.2 * 0.9);
     60
     61    /**
     62    *  Because josm cannot work correctly if two zones are displayed, we allow some overlapping
     63    */
     64    public static final double cMaxOverlappingZones = Math.toRadians(1.5 * 0.9);
     65
     66    public static int layoutZone = -1;
     67
     68    private static int currentZone = 0;
     69
     70    private static boolean dontDisplayErrors = false;
     71
     72    /**
     73    * @param p  WGS84 lat/lon (ellipsoid GRS80) (in degree)
     74    * @return eastnorth projection in Lambert Zone (ellipsoid Clark)
     75    */
     76    public EastNorth latlon2eastNorth(LatLon p) {
     77        // translate ellipsoid GRS80 (WGS83) => Clark
     78        LatLon geo = GRS802Clark(p);
     79        double lt = geo.lat(); // in radian
     80        double lg = geo.lon();
     81
     82        // check if longitude and latitude are inside the french Lambert zones
     83        currentZone = 0;
     84        boolean outOfLambertZones = false;
     85        if (lt >= zoneLimits[3] && lt <= cMaxLatZone1 && lg >= cMinLonZones && lg <= cMaxLonZones) {
     86            // zone I
     87            if (lt > zoneLimits[0])
     88                currentZone = 0;
     89            // zone II
     90            else if (lt > zoneLimits[1])
     91                currentZone = 1;
     92            // zone III
     93            else if (lt > zoneLimits[2])
     94                currentZone = 2;
     95            // zone III or IV
     96            else if (lt > zoneLimits[3])
     97                // Note: zone IV is dedicated to Corsica island and extends from 47.8 to
     98                // 45.9 degrees of latitude. There is an overlap with zone III that can be
     99                // solved only with longitude (covers Corsica if lon > 7.2 degree)
     100                if (lg < Math.toRadians(8 * 0.9))
     101                    currentZone = 2;
     102                else
     103                    currentZone = 3;
     104        } else {
     105            outOfLambertZones = true; // possible when MAX_LAT is used
     106            if (p.lat() != 0 && Math.abs(p.lat()) != Projection.MAX_LAT
     107                    && p.lon() != 0 && Math.abs(p.lon()) != Projection.MAX_LON
     108                    && dontDisplayErrors == false) {
     109                JOptionPane.showMessageDialog(Main.parent,
     110                        tr("The projection \"{0}\" is designed for\n"
     111                        + "latitudes between 46.1° and 57° only.\n"
     112                        + "Use another projection system if you are not using\n"
     113                        + "a french WMS server.\n"
     114                        + "Do not upload any data after this message.", this.toString()));
     115                dontDisplayErrors = true;
     116            }
     117        }
     118        if (!outOfLambertZones) {
     119            if (layoutZone == -1) {
     120                layoutZone = currentZone;
     121                dontDisplayErrors = false;
     122            } else if (layoutZone != currentZone) {
     123                if ((currentZone < layoutZone && Math.abs(zoneLimits[currentZone] - lt) > cMaxOverlappingZones)
     124                        || (currentZone > layoutZone && Math.abs(zoneLimits[layoutZone] - lt) > cMaxOverlappingZones)) {
     125                    JOptionPane.showMessageDialog(Main.parent,
     126                                    tr("IMPORTANT : data positionned far away from\n"
     127                                            + "the current Lambert zone limits.\n"
     128                                            + "Do not upload any data after this message.\n"
     129                                            + "Undo your last action, Save your work \n"
     130                                            + "and Start a new layer on the new zone."));
     131                    layoutZone = -1;
     132                    dontDisplayErrors = true;
     133                } else {
     134                    System.out.println("temporarily extend Lambert zone " + layoutZone + " projection at lat,lon:"
     135                            + lt + "," + lg);
     136                }
     137            }
     138        }
     139        if (layoutZone == -1) {
     140            return ConicProjection(lt, lg, Xs[currentZone], Ys[currentZone], c[currentZone], n[currentZone]);
     141        } // else
     142        return ConicProjection(lt, lg, Xs[layoutZone], Ys[layoutZone], c[layoutZone], n[layoutZone]);
     143    }
     144
     145    public LatLon eastNorth2latlon(EastNorth p) {
     146        LatLon geo;
     147        if (layoutZone == -1)
     148            // possible until the Lambert zone is determined by latlon2eastNorth() with a valid LatLon
     149            geo = Geographic(p, Xs[currentZone], Ys[currentZone], c[currentZone], n[currentZone]);
     150        else
     151            geo = Geographic(p, Xs[layoutZone], Ys[layoutZone], c[layoutZone], n[layoutZone]);
     152        // translate ellipsoid Clark => GRS80 (WGS83)
     153        LatLon wgs = Clark2GRS80(geo);
     154        return new LatLon(Math.toDegrees(wgs.lat()), Math.toDegrees(wgs.lon()));
     155    }
     156
     157    @Override public String toString() {
     158        return tr("Lambert Zone (France)");
     159    }
     160
     161    public String getCacheDirectoryName() {
     162        return "lambert";
     163    }
     164
     165    public double scaleFactor() {
     166        return 1.0 / 360;
     167    }
     168
     169    @Override
     170    public boolean equals(Object o) {
     171        return o instanceof Lambert;
     172    }
     173
     174    @Override
     175    public int hashCode() {
     176        return Lambert.class.hashCode();
     177    }
     178
     179    /**
     180    * Initializes from geographic coordinates. Note that reference ellipsoid
     181    * used by Lambert is the Clark ellipsoid.
     182    *
     183    * @param lat latitude in grad
     184    * @param lon longitude in grad
     185    * @param Xs  false east (coordinate system origin) in meters
     186    * @param Ys  false north (coordinate system origin) in meters
     187    * @param c   projection constant
     188    * @param n   projection exponent
     189    * @return EastNorth projected coordinates in meter
     190    */
     191    private EastNorth ConicProjection(double lat, double lon, double Xs, double Ys, double c, double n) {
     192        double eslt = Ellipsoid.clarke.e * Math.sin(lat);
     193        double l = Math.log(Math.tan(Math.PI / 4.0 + (lat / 2.0))
     194                * Math.pow((1.0 - eslt) / (1.0 + eslt), Ellipsoid.clarke.e / 2.0));
     195        double east = Xs + c * Math.exp(-n * l) * Math.sin(n * (lon - lg0));
     196        double north = Ys - c * Math.exp(-n * l) * Math.cos(n * (lon - lg0));
     197        return new EastNorth(east, north);
     198    }
     199
     200    /**
     201    * Initializes from projected coordinates (conic projection). Note that
     202    * reference ellipsoid used by Lambert is Clark
     203    *
     204    * @param coord projected coordinates pair in meters
     205    * @param Xs    false east (coordinate system origin) in meters
     206    * @param Ys    false north (coordinate system origin) in meters
     207    * @param c     projection constant
     208    * @param n     projection exponent
     209    * @return LatLon in radian
     210    */
     211    private LatLon Geographic(EastNorth eastNorth, double Xs, double Ys, double c, double n) {
     212        double dx = eastNorth.east() - Xs;
     213        double dy = Ys - eastNorth.north();
     214        double R = Math.sqrt(dx * dx + dy * dy);
     215        double gamma = Math.atan(dx / dy);
     216        double l = -1.0 / n * Math.log(Math.abs(R / c));
     217        l = Math.exp(l);
     218        double lon = lg0 + gamma / n;
     219        double lat = 2.0 * Math.atan(l) - Math.PI / 2.0;
     220        double delta = 1.0;
     221        while (delta > epsilon) {
     222            double eslt = Ellipsoid.clarke.e * Math.sin(lat);
     223            double nlt = 2.0 * Math.atan(Math.pow((1.0 + eslt) / (1.0 - eslt), Ellipsoid.clarke.e / 2.0) * l) - Math.PI
     224                    / 2.0;
     225            delta = Math.abs(nlt - lat);
     226            lat = nlt;
     227        }
     228        return new LatLon(lat, lon); // in radian
     229    }
     230
     231    /**
     232    * Translate latitude/longitude in WGS84, (ellipsoid GRS80) to Lambert
     233    * geographic, (ellipsoid Clark)
     234    *
     235    * @param wgs
     236    * @return
     237    */
     238    private LatLon GRS802Clark(LatLon wgs) {
     239        double lat = Math.toRadians(wgs.lat()); // degree to radian
     240        double lon = Math.toRadians(wgs.lon());
     241        // WGS84 geographic => WGS84 cartesian
     242        double N = Ellipsoid.GRS80.a / (Math.sqrt(1.0 - Ellipsoid.GRS80.e2 * Math.sin(lat) * Math.sin(lat)));
     243        double X = (N/* +height */) * Math.cos(lat) * Math.cos(lon);
     244        double Y = (N/* +height */) * Math.cos(lat) * Math.sin(lon);
     245        double Z = (N * (1.0 - Ellipsoid.GRS80.e2)/* + height */) * Math.sin(lat);
     246        // WGS84 => Lambert ellipsoide similarity
     247        X += 168.0;
     248        Y += 60.0;
     249        Z += -320.0;
     250        // Lambert cartesian => Lambert geographic
     251        return Geographic(X, Y, Z, Ellipsoid.clarke);
     252    }
     253
     254    /**
     255    * @param lambert
     256    * @return
     257    */
     258    private LatLon Clark2GRS80(LatLon lambert) {
     259        double lat = lambert.lat(); // in radian
     260        double lon = lambert.lon();
     261        // Lambert geographic => Lambert cartesian
     262        double N = Ellipsoid.clarke.a / (Math.sqrt(1.0 - Ellipsoid.clarke.e2 * Math.sin(lat) * Math.sin(lat)));
     263        double X = (N/* +height */) * Math.cos(lat) * Math.cos(lon);
     264        double Y = (N/* +height */) * Math.cos(lat) * Math.sin(lon);
     265        double Z = (N * (1.0 - Ellipsoid.clarke.e2)/* + height */) * Math.sin(lat);
     266        // Lambert => WGS84 ellipsoide similarity
     267        X += -168.0;
     268        Y += -60.0;
     269        Z += 320.0;
     270        // WGS84 cartesian => WGS84 geographic
     271        return Geographic(X, Y, Z, Ellipsoid.GRS80);
     272    }
     273
     274    /**
     275    * initializes from cartesian coordinates
     276    *
     277    * @param X
     278    *            1st coordinate in meters
     279    * @param Y
     280    *            2nd coordinate in meters
     281    * @param Z
     282    *            3rd coordinate in meters
     283    * @param ell
     284    *            reference ellipsoid
     285    */
     286    private LatLon Geographic(double X, double Y, double Z, Ellipsoid ell) {
     287        double norm = Math.sqrt(X * X + Y * Y);
     288        double lg = 2.0 * Math.atan(Y / (X + norm));
     289        double lt = Math.atan(Z / (norm * (1.0 - (ell.a * ell.e2 / Math.sqrt(X * X + Y * Y + Z * Z)))));
     290        double delta = 1.0;
     291        while (delta > epsilon) {
     292            double s2 = Math.sin(lt);
     293            s2 *= s2;
     294            double l = Math.atan((Z / norm)
     295                / (1.0 - (ell.a * ell.e2 * Math.cos(lt) / (norm * Math.sqrt(1.0 - ell.e2 * s2)))));
     296            delta = Math.abs(l - lt);
     297            lt = l;
     298        }
     299        double s2 = Math.sin(lt);
     300        s2 *= s2;
     301        // h = norm / Math.cos(lt) - ell.a / Math.sqrt(1.0 - ell.e2 * s2);
     302        return new LatLon(lt, lg);
     303    }
    304304
    305305}
  • trunk/src/org/openstreetmap/josm/data/projection/Mercator.java

    r1032 r1169  
    1010 * Implement Mercator Projection code, coded after documentation
    1111 * from wikipedia.
    12  * 
    13  * The center of the mercator projection is always the 0 grad 
     12 *
     13 * The center of the mercator projection is always the 0 grad
    1414 * coordinate.
    15  * 
     15 *
    1616 * @author imi
    1717 */
    1818public class Mercator implements Projection {
    1919
    20         public EastNorth latlon2eastNorth(LatLon p) {
    21                 return new EastNorth(
    22                         p.lon()*Math.PI/180,
    23                         Math.log(Math.tan(Math.PI/4+p.lat()*Math.PI/360)));
    24         }
     20    public EastNorth latlon2eastNorth(LatLon p) {
     21        return new EastNorth(
     22            p.lon()*Math.PI/180,
     23            Math.log(Math.tan(Math.PI/4+p.lat()*Math.PI/360)));
     24    }
    2525
    26         public LatLon eastNorth2latlon(EastNorth p) {
    27                 return new LatLon(
    28                         Math.atan(Math.sinh(p.north()))*180/Math.PI,
    29                         p.east()*180/Math.PI);
    30         }
     26    public LatLon eastNorth2latlon(EastNorth p) {
     27        return new LatLon(
     28            Math.atan(Math.sinh(p.north()))*180/Math.PI,
     29            p.east()*180/Math.PI);
     30    }
    3131
    32         @Override public String toString() {
    33                 return tr("Mercator");
    34         }
     32    @Override public String toString() {
     33        return tr("Mercator");
     34    }
    3535
    3636    public String getCacheDirectoryName() {
     
    3838    }
    3939
    40         public double scaleFactor() {
    41             return 1/Math.PI/2;
     40    public double scaleFactor() {
     41        return 1/Math.PI/2;
    4242    }
    4343
    44         @Override public boolean equals(Object o) {
    45                 return o instanceof Mercator;
    46         }
     44    @Override public boolean equals(Object o) {
     45        return o instanceof Mercator;
     46    }
    4747
    48         @Override public int hashCode() {
    49                 return Mercator.class.hashCode();
    50         }
     48    @Override public int hashCode() {
     49        return Mercator.class.hashCode();
     50    }
    5151}
  • trunk/src/org/openstreetmap/josm/data/projection/Projection.java

    r656 r1169  
    66
    77/**
    8  * Classes implementing this are able to convert lat/lon values to 
     8 * Classes implementing this are able to convert lat/lon values to
    99 * planar screen coordinates.
    10  * 
     10 *
    1111 * @author imi
    1212 */
    1313public interface Projection {
    1414
    15         /**
    16          * Maximum latitude representable.
    17          */
    18         public static final double MAX_LAT = 85.05112877980659; // Mercator squares the world
    19        
    20         /**
    21          * Maximum longditude representable.
    22          */
    23         public static final double MAX_LON = 180;
     15    /**
     16     * Maximum latitude representable.
     17     */
     18    public static final double MAX_LAT = 85.05112877980659; // Mercator squares the world
    2419
    25         /**
    26          * Minimum difference in location to not be represented as the same position.
    27         */
    28         public static final double MAX_SERVER_PRECISION = 1e12;
     20    /**
     21     * Maximum longditude representable.
     22    */
     23    public static final double MAX_LON = 180;
    2924
    30         /**
    31          * List of all available projections.
    32          */
    33         public static Projection[] allProjections = new Projection[]{
    34                 new Epsg4326(),
    35                 new Mercator(),
    36                 new Lambert()
    37         };
    38        
    39         /**
    40          * Convert from lat/lon to northing/easting.
    41          *
    42          * @param p             The geo point to convert. x/y members of the point are filled.
    43          */
    44         EastNorth latlon2eastNorth(LatLon p);
    45        
    46         /**
    47          * Convert from norting/easting to lat/lon.
    48          *
    49          * @param p             The geo point to convert. lat/lon members of the point are filled.
    50          */
    51         LatLon eastNorth2latlon(EastNorth p);
     25    /**
     26     * Minimum difference in location to not be represented as the same position.
     27     */
     28    public static final double MAX_SERVER_PRECISION = 1e12;
    5229
    53         /**
    54          * Describe the projection converter in one or two words.
    55          */
    56         String toString();
    57    
     30    /**
     31     * List of all available projections.
     32     */
     33    public static Projection[] allProjections = new Projection[]{
     34        new Epsg4326(),
     35        new Mercator(),
     36        new Lambert()
     37    };
     38
     39    /**
     40     * Convert from lat/lon to northing/easting.
     41     *
     42     * @param p     The geo point to convert. x/y members of the point are filled.
     43     */
     44    EastNorth latlon2eastNorth(LatLon p);
     45
     46    /**
     47     * Convert from norting/easting to lat/lon.
     48     *
     49     * @param p     The geo point to convert. lat/lon members of the point are filled.
     50     */
     51    LatLon eastNorth2latlon(EastNorth p);
     52
     53    /**
     54     * Describe the projection converter in one or two words.
     55     */
     56    String toString();
     57
    5858    /**
    5959     * Get a filename compatible string (for the cache directory)
    6060     */
    6161    String getCacheDirectoryName();
    62    
     62
    6363    /**
    64      * The factor to multiply with an easting coordinate to get from "easting 
     64     * The factor to multiply with an easting coordinate to get from "easting
    6565     * units per pixel" to "meters per pixel"
    6666     */
  • trunk/src/org/openstreetmap/josm/gui/BookmarkList.java

    r627 r1169  
    2121public class BookmarkList extends JList {
    2222
    23         /**
    24         * Create a bookmark list as well as the Buttons add and remove.
    25         */
    26         public BookmarkList() {
    27                 setModel(new DefaultListModel());
    28                 load();
    29                 setVisibleRowCount(7);
    30         }
     23    /**
     24    * Create a bookmark list as well as the Buttons add and remove.
     25    */
     26    public BookmarkList() {
     27        setModel(new DefaultListModel());
     28        load();
     29        setVisibleRowCount(7);
     30    }
    3131
    32         /**
    33         * Loads the bookmarks from file.
    34         */
    35         public void load() {
    36                 DefaultListModel model = (DefaultListModel)getModel();
    37                 model.removeAllElements();
    38                 try {
    39                         for (Preferences.Bookmark b : Main.pref.loadBookmarks())
    40                                 model.addElement(b);
    41                 } catch (IOException e) {
    42                         e.printStackTrace();
    43                         JOptionPane.showMessageDialog(Main.parent, tr("Could not read bookmarks.")+"\n"+e.getMessage());
    44                 }
    45         }
     32    /**
     33    * Loads the bookmarks from file.
     34    */
     35    public void load() {
     36        DefaultListModel model = (DefaultListModel)getModel();
     37        model.removeAllElements();
     38        try {
     39            for (Preferences.Bookmark b : Main.pref.loadBookmarks())
     40                model.addElement(b);
     41        } catch (IOException e) {
     42            e.printStackTrace();
     43            JOptionPane.showMessageDialog(Main.parent, tr("Could not read bookmarks.")+"\n"+e.getMessage());
     44        }
     45    }
    4646
    47         /**
    48         * Save all bookmarks to the preferences file
    49         */
    50         public void save() {
    51                 try {
    52                         Collection<Preferences.Bookmark> bookmarks = new LinkedList<Preferences.Bookmark>();
    53                         for (Object o : ((DefaultListModel)getModel()).toArray())
    54                                 bookmarks.add((Preferences.Bookmark)o);
    55                         Main.pref.saveBookmarks(bookmarks);
    56                 } catch (IOException e) {
    57                         JOptionPane.showMessageDialog(Main.parent,tr("Could not write bookmark.")+"\n"+e.getMessage());
    58                 }
    59         }
     47    /**
     48    * Save all bookmarks to the preferences file
     49    */
     50    public void save() {
     51        try {
     52            Collection<Preferences.Bookmark> bookmarks = new LinkedList<Preferences.Bookmark>();
     53            for (Object o : ((DefaultListModel)getModel()).toArray())
     54                bookmarks.add((Preferences.Bookmark)o);
     55            Main.pref.saveBookmarks(bookmarks);
     56        } catch (IOException e) {
     57            JOptionPane.showMessageDialog(Main.parent,tr("Could not write bookmark.")+"\n"+e.getMessage());
     58        }
     59    }
    6060}
  • trunk/src/org/openstreetmap/josm/gui/ConflictResolver.java

    r627 r1169  
    4646 * three tables in the screen, one for each both sides and one resulting table. The user can
    4747 * move items from either one of the sides ("my" and "their") to the resulting table.
    48  * 
     48 *
    4949 * @author Imi
    5050 */
    5151public class ConflictResolver extends JPanel {
    5252
    53         public static enum Resolution {MY, THEIR}
    54 
    55         private final class ConflictTableModel implements TableModel {
    56                 private final Resolution resolution;
    57                 public ConflictTableModel(Resolution resolution) {
    58                         this.resolution = resolution;
    59                 }
    60 
    61                 public int getRowCount() {
    62                         return conflicts.size();
    63                 }
    64 
    65                 public Object getValueAt(int rowIndex, int columnIndex) {
    66                         ConflictItem ci = conflicts.get(rowIndex);
    67                         if (columnIndex == 0)
    68                                 return ci.key();
    69                         Resolution r = resolution == null ? ci.resolution : resolution;
    70                         if (r == null)
    71                                 return "<html><i>???</i></html>";
    72                         JLabel l = new JLabel(r == Resolution.MY ? ci.my : ci.their);
    73                         if (ci.resolution == resolution && resolution != null)
    74                                 l.setFont(l.getFont().deriveFont(Font.BOLD));
    75                         return l;
    76                 }
    77 
    78                 public String getColumnName(int columnIndex) {return columnIndex == 0 ? tr("Key") : tr("Value");}
    79                 public int getColumnCount() {return 2;}
    80                 public boolean isCellEditable(int row, int column) {return false;}
    81                 public Class<?> getColumnClass(int columnIndex) {return Object.class;}
    82 
    83                 public void addTableModelListener(TableModelListener l) {}
    84                 public void removeTableModelListener(TableModelListener l) {}
    85                 public void setValueAt(Object aValue, int rowIndex, int columnIndex) {}
    86         }
    87 
    88         private final class DblClickListener extends MouseAdapter {
    89                 private final Resolution resolution;
    90                 public DblClickListener(Resolution resolution) {
    91                         this.resolution = resolution;
    92                 }
    93                 @Override public void mouseClicked(MouseEvent e) {
    94                         if (e.getClickCount() >= 2) {
    95                                 int sel = ((JTable)e.getSource()).getSelectedRow();
    96                                 if (sel == -1)
    97                                         return;
    98                                 ConflictResolver.this.conflicts.get(sel).resolution = resolution;
    99                                 repaint();
    100                         }
    101                 }
    102         }
    103         private final class ResolveAction extends AbstractAction {
    104                 private final Resolution resolution;
    105                 public ResolveAction(String name, Resolution resolution) {
    106                         super(null, ImageProvider.get("dialogs", name));
    107                         this.resolution = resolution;
    108                 }
    109                 public void actionPerformed(ActionEvent e) {
    110                         int sel = myTable.getSelectedRow();
    111                         if (sel == -1)
    112                                 return;
    113                         conflicts.get(sel).resolution = resolution;
    114                         if (sel == myTable.getRowCount()-1)
    115                                 myTable.clearSelection();
    116                         else
    117                                 myTable.getSelectionModel().setSelectionInterval(sel+1, sel+1);
    118                         repaint();
    119                 }
    120         }
    121 
    122         public final List<ConflictItem> conflicts = new ArrayList<ConflictItem>();
    123 
    124         private final ConflictTableModel my = new ConflictTableModel(Resolution.MY);
    125         private final JTable myTable;
    126         private final ConflictTableModel their = new ConflictTableModel(Resolution.THEIR);
    127         private final JTable theirTable;
    128         private final ConflictTableModel resolve = new ConflictTableModel(null);
    129         private final JTable resolveTable;
    130 
    131        
    132         public ConflictResolver(Map<OsmPrimitive, OsmPrimitive> conflicts) {
    133                 super(new GridBagLayout());
    134                 Collection<ConflictItem> possibleConflicts = new ArrayList<ConflictItem>();
    135                 possibleConflicts.add(new DeleteConflict());
    136                 possibleConflicts.add(new PositionConflict());
    137                 TreeSet<String> allkeys = new TreeSet<String>();
    138                 for (Entry<OsmPrimitive, OsmPrimitive> e : conflicts.entrySet()) {
    139                         allkeys.addAll(e.getKey().keySet());
    140                         allkeys.addAll(e.getValue().keySet());
    141                 }
    142                 for (String s : allkeys)
    143                         possibleConflicts.add(new PropertyConflict(s));
    144                
    145                 for (Entry<OsmPrimitive, OsmPrimitive> e : conflicts.entrySet()) {
    146                         for (Iterator<ConflictItem> it = possibleConflicts.iterator(); it.hasNext();) {
    147                                 ConflictItem ci = it.next();
    148                                 if (ci.hasConflict(e.getKey(), e.getValue())) {
    149                                         ci.initialize(conflicts);
    150                                         this.conflicts.add(ci);
    151                                         it.remove();
    152                                 }
    153                         }
    154                 }
    155                
    156 
    157                 // have to initialize the JTables here and not in the declaration, because its constructor
    158                 // may access this.conflicts (indirectly)
    159                 myTable = new JTable(my);
    160                 theirTable = new JTable(their);
    161                 resolveTable = new JTable(resolve);
    162                
    163                 myTable.setPreferredScrollableViewportSize(new Dimension(250,70));
    164                 theirTable.setPreferredScrollableViewportSize(new Dimension(250,70));
    165                 resolveTable.setPreferredScrollableViewportSize(new Dimension(250,70));
    166 
    167                 TableCellRenderer renderer = new DefaultTableCellRenderer(){
    168                         final Font defFont = new JLabel().getFont();
    169                         @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    170                                 JLabel c = (JLabel)super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
    171                                 c.setIcon(null);
    172                                 c.setFont(defFont);
    173                                 if (value instanceof JLabel) {
    174                                         JLabel l = (JLabel)value;
    175                                         String text = l.getText();
    176                                         c.setText(text);
    177                                         c.setFont(l.getFont());
    178                                         if (text.startsWith("<html>") && l.getFont().isBold())
    179                                                 c.setText("<html>"+"<b>"+text.substring(6, text.length()-12));
    180                                 } else {
    181                                         String s = value.toString();
    182                                         int i = s.indexOf('|');
    183                                         if (i != -1) {
    184                                                 c.setIcon(ImageProvider.get("data", s.substring(0,i)));
    185                                                 c.setText(s.substring(i+1));
    186                                         }
    187                                 }
    188                                 return c;
    189                         }
    190                 };
    191                 myTable.setDefaultRenderer(Object.class, renderer);
    192                 theirTable.setDefaultRenderer(Object.class, renderer);
    193                 resolveTable.setDefaultRenderer(Object.class, renderer);
    194 
    195                 myTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    196                 theirTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    197                 resolveTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    198                 ListSelectionListener selListener = new ListSelectionListener(){
    199                         public void valueChanged(ListSelectionEvent e) {
    200                                 if (((ListSelectionModel)e.getSource()).isSelectionEmpty()) {
    201                                         myTable.clearSelection();
    202                                         theirTable.clearSelection();
    203                                         resolveTable.clearSelection();
    204                                 } else {
    205                                         int i = ((ListSelectionModel)e.getSource()).getMinSelectionIndex();
    206                                         myTable.scrollRectToVisible(myTable.getCellRect(i, 0, true));
    207                                         myTable.getSelectionModel().setSelectionInterval(i, i);
    208                                         theirTable.scrollRectToVisible(theirTable.getCellRect(i, 0, true));
    209                                         theirTable.getSelectionModel().setSelectionInterval(i, i);
    210                                         resolveTable.scrollRectToVisible(resolveTable.getCellRect(i, 0, true));
    211                                         resolveTable.getSelectionModel().setSelectionInterval(i, i);
    212                                 }
    213                         }
    214                 };
    215                 myTable.getSelectionModel().addListSelectionListener(selListener);
    216                 theirTable.getSelectionModel().addListSelectionListener(selListener);
    217                 resolveTable.getSelectionModel().addListSelectionListener(selListener);
    218                 myTable.getSelectionModel().setSelectionInterval(0,0);
    219 
    220                 myTable.addMouseListener(new DblClickListener(Resolution.MY));
    221                 theirTable.addMouseListener(new DblClickListener(Resolution.THEIR));
    222                 resolveTable.addMouseListener(new DblClickListener(null));
    223 
    224                 add(new JLabel(trn("{0} object has conflicts:","{0} objects have conflicts:",conflicts.size(),conflicts.size())), GBC.eol().insets(0,0,0,10));
    225 
    226                 JPanel p = new JPanel(new GridBagLayout());
    227                 p.add(new JLabel(tr("my version:")), GBC.eol());
    228                 p.add(new JScrollPane(myTable), GBC.eol().fill(GBC.BOTH));
    229                 p.add(new JButton(new ResolveAction("down", Resolution.MY)), GBC.eol().anchor(GBC.CENTER).insets(0,5,0,0));
    230                 add(p, GBC.std().insets(0,0,5,0));
    231 
    232                 p = new JPanel(new GridBagLayout());
    233                 p.add(new JLabel(tr("their version:")), GBC.eol());
    234                 p.add(new JScrollPane(theirTable), GBC.eol().fill(GBC.BOTH));
    235                 p.add(new JButton(new ResolveAction("down", Resolution.THEIR)), GBC.eol().anchor(GBC.CENTER).insets(0,5,0,0));
    236                 add(p, GBC.eop().insets(5,0,0,0));
    237 
    238                 add(new JButton(new ResolveAction("up", null)), GBC.eol().anchor(GBC.CENTER));
    239                 add(new JLabel(tr("resolved version:")), GBC.eol().insets(0,5,0,0));
    240                 add(new JScrollPane(resolveTable), GBC.eol().anchor(GBC.CENTER).fill(GBC.BOTH));
    241         }
     53    public static enum Resolution {MY, THEIR}
     54
     55    private final class ConflictTableModel implements TableModel {
     56        private final Resolution resolution;
     57        public ConflictTableModel(Resolution resolution) {
     58            this.resolution = resolution;
     59        }
     60
     61        public int getRowCount() {
     62            return conflicts.size();
     63        }
     64
     65        public Object getValueAt(int rowIndex, int columnIndex) {
     66            ConflictItem ci = conflicts.get(rowIndex);
     67            if (columnIndex == 0)
     68                return ci.key();
     69            Resolution r = resolution == null ? ci.resolution : resolution;
     70            if (r == null)
     71                return "<html><i>???</i></html>";
     72            JLabel l = new JLabel(r == Resolution.MY ? ci.my : ci.their);
     73            if (ci.resolution == resolution && resolution != null)
     74                l.setFont(l.getFont().deriveFont(Font.BOLD));
     75            return l;
     76        }
     77
     78        public String getColumnName(int columnIndex) {return columnIndex == 0 ? tr("Key") : tr("Value");}
     79        public int getColumnCount() {return 2;}
     80        public boolean isCellEditable(int row, int column) {return false;}
     81        public Class<?> getColumnClass(int columnIndex) {return Object.class;}
     82
     83        public void addTableModelListener(TableModelListener l) {}
     84        public void removeTableModelListener(TableModelListener l) {}
     85        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {}
     86    }
     87
     88    private final class DblClickListener extends MouseAdapter {
     89        private final Resolution resolution;
     90        public DblClickListener(Resolution resolution) {
     91            this.resolution = resolution;
     92        }
     93        @Override public void mouseClicked(MouseEvent e) {
     94            if (e.getClickCount() >= 2) {
     95                int sel = ((JTable)e.getSource()).getSelectedRow();
     96                if (sel == -1)
     97                    return;
     98                ConflictResolver.this.conflicts.get(sel).resolution = resolution;
     99                repaint();
     100            }
     101        }
     102    }
     103    private final class ResolveAction extends AbstractAction {
     104        private final Resolution resolution;
     105        public ResolveAction(String name, Resolution resolution) {
     106            super(null, ImageProvider.get("dialogs", name));
     107            this.resolution = resolution;
     108        }
     109        public void actionPerformed(ActionEvent e) {
     110            int sel = myTable.getSelectedRow();
     111            if (sel == -1)
     112                return;
     113            conflicts.get(sel).resolution = resolution;
     114            if (sel == myTable.getRowCount()-1)
     115                myTable.clearSelection();
     116            else
     117                myTable.getSelectionModel().setSelectionInterval(sel+1, sel+1);
     118            repaint();
     119        }
     120    }
     121
     122    public final List<ConflictItem> conflicts = new ArrayList<ConflictItem>();
     123
     124    private final ConflictTableModel my = new ConflictTableModel(Resolution.MY);
     125    private final JTable myTable;
     126    private final ConflictTableModel their = new ConflictTableModel(Resolution.THEIR);
     127    private final JTable theirTable;
     128    private final ConflictTableModel resolve = new ConflictTableModel(null);
     129    private final JTable resolveTable;
     130
     131
     132    public ConflictResolver(Map<OsmPrimitive, OsmPrimitive> conflicts) {
     133        super(new GridBagLayout());
     134        Collection<ConflictItem> possibleConflicts = new ArrayList<ConflictItem>();
     135        possibleConflicts.add(new DeleteConflict());
     136        possibleConflicts.add(new PositionConflict());
     137        TreeSet<String> allkeys = new TreeSet<String>();
     138        for (Entry<OsmPrimitive, OsmPrimitive> e : conflicts.entrySet()) {
     139            allkeys.addAll(e.getKey().keySet());
     140            allkeys.addAll(e.getValue().keySet());
     141        }
     142        for (String s : allkeys)
     143            possibleConflicts.add(new PropertyConflict(s));
     144
     145        for (Entry<OsmPrimitive, OsmPrimitive> e : conflicts.entrySet()) {
     146            for (Iterator<ConflictItem> it = possibleConflicts.iterator(); it.hasNext();) {
     147                ConflictItem ci = it.next();
     148                if (ci.hasConflict(e.getKey(), e.getValue())) {
     149                    ci.initialize(conflicts);
     150                    this.conflicts.add(ci);
     151                    it.remove();
     152                }
     153            }
     154        }
     155
     156
     157        // have to initialize the JTables here and not in the declaration, because its constructor
     158        // may access this.conflicts (indirectly)
     159        myTable = new JTable(my);
     160        theirTable = new JTable(their);
     161        resolveTable = new JTable(resolve);
     162
     163        myTable.setPreferredScrollableViewportSize(new Dimension(250,70));
     164        theirTable.setPreferredScrollableViewportSize(new Dimension(250,70));
     165        resolveTable.setPreferredScrollableViewportSize(new Dimension(250,70));
     166
     167        TableCellRenderer renderer = new DefaultTableCellRenderer(){
     168            final Font defFont = new JLabel().getFont();
     169            @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
     170                JLabel c = (JLabel)super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
     171                c.setIcon(null);
     172                c.setFont(defFont);
     173                if (value instanceof JLabel) {
     174                    JLabel l = (JLabel)value;
     175                    String text = l.getText();
     176                    c.setText(text);
     177                    c.setFont(l.getFont());
     178                    if (text.startsWith("<html>") && l.getFont().isBold())
     179                        c.setText("<html>"+"<b>"+text.substring(6, text.length()-12));
     180                } else {
     181                    String s = value.toString();
     182                    int i = s.indexOf('|');
     183                    if (i != -1) {
     184                        c.setIcon(ImageProvider.get("data", s.substring(0,i)));
     185                        c.setText(s.substring(i+1));
     186                    }
     187                }
     188                return c;
     189            }
     190        };
     191        myTable.setDefaultRenderer(Object.class, renderer);
     192        theirTable.setDefaultRenderer(Object.class, renderer);
     193        resolveTable.setDefaultRenderer(Object.class, renderer);
     194
     195        myTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
     196        theirTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
     197        resolveTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
     198        ListSelectionListener selListener = new ListSelectionListener(){
     199            public void valueChanged(ListSelectionEvent e) {
     200                if (((ListSelectionModel)e.getSource()).isSelectionEmpty()) {
     201                    myTable.clearSelection();
     202                    theirTable.clearSelection();
     203                    resolveTable.clearSelection();
     204                } else {
     205                    int i = ((ListSelectionModel)e.getSource()).getMinSelectionIndex();
     206                    myTable.scrollRectToVisible(myTable.getCellRect(i, 0, true));
     207                    myTable.getSelectionModel().setSelectionInterval(i, i);
     208                    theirTable.scrollRectToVisible(theirTable.getCellRect(i, 0, true));
     209                    theirTable.getSelectionModel().setSelectionInterval(i, i);
     210                    resolveTable.scrollRectToVisible(resolveTable.getCellRect(i, 0, true));
     211                    resolveTable.getSelectionModel().setSelectionInterval(i, i);
     212                }
     213            }
     214        };
     215        myTable.getSelectionModel().addListSelectionListener(selListener);
     216        theirTable.getSelectionModel().addListSelectionListener(selListener);
     217        resolveTable.getSelectionModel().addListSelectionListener(selListener);
     218        myTable.getSelectionModel().setSelectionInterval(0,0);
     219
     220        myTable.addMouseListener(new DblClickListener(Resolution.MY));
     221        theirTable.addMouseListener(new DblClickListener(Resolution.THEIR));
     222        resolveTable.addMouseListener(new DblClickListener(null));
     223
     224        add(new JLabel(trn("{0} object has conflicts:","{0} objects have conflicts:",conflicts.size(),conflicts.size())), GBC.eol().insets(0,0,0,10));
     225
     226        JPanel p = new JPanel(new GridBagLayout());
     227        p.add(new JLabel(tr("my version:")), GBC.eol());
     228        p.add(new JScrollPane(myTable), GBC.eol().fill(GBC.BOTH));
     229        p.add(new JButton(new ResolveAction("down", Resolution.MY)), GBC.eol().anchor(GBC.CENTER).insets(0,5,0,0));
     230        add(p, GBC.std().insets(0,0,5,0));
     231
     232        p = new JPanel(new GridBagLayout());
     233        p.add(new JLabel(tr("their version:")), GBC.eol());
     234        p.add(new JScrollPane(theirTable), GBC.eol().fill(GBC.BOTH));
     235        p.add(new JButton(new ResolveAction("down", Resolution.THEIR)), GBC.eol().anchor(GBC.CENTER).insets(0,5,0,0));
     236        add(p, GBC.eop().insets(5,0,0,0));
     237
     238        add(new JButton(new ResolveAction("up", null)), GBC.eol().anchor(GBC.CENTER));
     239        add(new JLabel(tr("resolved version:")), GBC.eol().insets(0,5,0,0));
     240        add(new JScrollPane(resolveTable), GBC.eol().anchor(GBC.CENTER).fill(GBC.BOTH));
     241    }
    242242}
  • trunk/src/org/openstreetmap/josm/gui/GettingStarted.java

    r1163 r1169  
    2525public class GettingStarted extends JPanel {
    2626
    27     static private String content = "";   
     27    static private String content = "";
    2828
    2929    public class LinkGeneral extends JEditorPane implements HyperlinkListener {
     
    7474                boolean included = false;
    7575                if (condition.equals("%3E")) {
    76                     if ((myVersion == 0 || myVersion > targetVersion) 
     76                    if ((myVersion == 0 || myVersion > targetVersion)
    7777                        /* && ! Main.pref.getBoolean("motd.gt."+targetVersion) */) {
    7878                        /* Main.pref.put("motd.gt."+targetVersion, true); */
     
    8080                    }
    8181                } else if (condition.equals("%3E%3D")) {
    82                     if ((myVersion == 0 || myVersion >= targetVersion) 
     82                    if ((myVersion == 0 || myVersion >= targetVersion)
    8383                        /* && ! Main.pref.getBoolean("motd.ge."+targetVersion) */) {
    8484                        /* Main.pref.put("motd.ge."+targetVersion, true); */
     
    114114                            content += wr.read(url).replace("<html>", "").replace("</html>", "").replace("<div id=\"searchable\">", "").replace("</div>", "");
    115115                        } catch (IOException ioe2) {
    116                         }           
    117                     }           
     116                        }
     117                    }
    118118                }
    119119            }
    120120            content += motdcontent.substring(start);
    121121            content = content.replace("<html>", "<html><style type=\"text/css\">\nbody { font-family: sans-serif; font-weight: bold; }\nh1 {text-align: center;}</style>");
    122             /* replace the wiki title */ 
    123             content = content.replace("JOSM, the Java OpenStreetMap editor", tr("JOSM, the Java OpenStreetMap editor")); 
     122            /* replace the wiki title */
     123            content = content.replace("JOSM, the Java OpenStreetMap editor", tr("JOSM, the Java OpenStreetMap editor"));
    124124        }
    125125
    126126    }
    127    
     127
    128128    public GettingStarted() {
    129129        super(new BorderLayout());
    130130        assignContent();
    131                                
     131
    132132        // panel.add(GBC.glue(0,1), GBC.eol());
    133133        //panel.setMinimumSize(new Dimension(400, 600));
  • trunk/src/org/openstreetmap/josm/gui/IconToggleButton.java

    r627 r1169  
    1818public class IconToggleButton extends JToggleButton implements PropertyChangeListener {
    1919
    20         public boolean groupbutton;
     20    public boolean groupbutton;
    2121
    22         /**
    23         * Construct the toggle button with the given action.
    24         */
    25         public IconToggleButton(Action action) {
    26                 super(action);
    27                 setText(null);
     22    /**
     23    * Construct the toggle button with the given action.
     24    */
     25    public IconToggleButton(Action action) {
     26        super(action);
     27        setText(null);
    2828
    29                 Object o = action.getValue(Action.SHORT_DESCRIPTION);
    30                 if (o != null)
    31                         setToolTipText(o.toString());
     29        Object o = action.getValue(Action.SHORT_DESCRIPTION);
     30        if (o != null)
     31            setToolTipText(o.toString());
    3232
    33                 action.addPropertyChangeListener(this);
    34                
    35                 addMouseListener(new MouseAdapter(){
    36                         @Override public void mousePressed(MouseEvent e) {
    37                                 groupbutton = e.getX() > getWidth()/2 && e.getY() > getHeight()/2;
     33        action.addPropertyChangeListener(this);
     34
     35        addMouseListener(new MouseAdapter(){
     36            @Override public void mousePressed(MouseEvent e) {
     37                groupbutton = e.getX() > getWidth()/2 && e.getY() > getHeight()/2;
    3838            }
    39                 });
    40         }
     39        });
     40    }
    4141
    42         public void propertyChange(PropertyChangeEvent evt) {
    43                 if (evt.getPropertyName().equals("active")) {
    44                         setSelected((Boolean)evt.getNewValue());
    45                         requestFocusInWindow();
    46                 }
    47         }
     42    public void propertyChange(PropertyChangeEvent evt) {
     43        if (evt.getPropertyName().equals("active")) {
     44            setSelected((Boolean)evt.getNewValue());
     45            requestFocusInWindow();
     46        }
     47    }
    4848}
  • trunk/src/org/openstreetmap/josm/gui/JMultilineLabel.java

    r729 r1169  
    11// License: GPL. For details, see LICENSE file.
    22
    3 // This class was taken from 
     3// This class was taken from
    44// http://forum.java.sun.com/thread.jspa?threadID=459705&messageID=2104021
    55// - Removed hardcoded margin
     
    2222
    2323public class JMultilineLabel extends JComponent {
    24         private String text;
    25         private int maxWidth = Integer.MAX_VALUE;
    26         private boolean justify;
    27         private final FontRenderContext frc = new FontRenderContext(null, false, false);
     24    private String text;
     25    private int maxWidth = Integer.MAX_VALUE;
     26    private boolean justify;
     27    private final FontRenderContext frc = new FontRenderContext(null, false, false);
    2828
    29         public JMultilineLabel(String description) {
    30                 super();
    31                 setText(description);
    32         }
     29    public JMultilineLabel(String description) {
     30        super();
     31        setText(description);
     32    }
    3333
    34         private void morph() {
    35                 revalidate();
    36                 repaint();
    37         }
     34    private void morph() {
     35        revalidate();
     36        repaint();
     37    }
    3838
    39         public String getText() {
    40                 return text;
    41         }
     39    public String getText() {
     40        return text;
     41    }
    4242
    43         public void setText(String text) {
    44                 String old = this.text;
    45                 this.text = text;
    46                 firePropertyChange("text", old, this.text);
    47                 if ((old == null) ? text!=null : !old.equals(text))
    48                         morph();
    49         }
     43    public void setText(String text) {
     44        String old = this.text;
     45        this.text = text;
     46        firePropertyChange("text", old, this.text);
     47        if ((old == null) ? text!=null : !old.equals(text))
     48            morph();
     49    }
    5050
    51         public int getMaxWidth() {
    52                 return maxWidth;
    53         }
     51    public int getMaxWidth() {
     52        return maxWidth;
     53    }
    5454
    55         public void setMaxWidth(int maxWidth) {
    56                 if (maxWidth <= 0)
    57                         throw new IllegalArgumentException();
    58                 int old = this.maxWidth;
    59                 this.maxWidth = maxWidth;
    60                 firePropertyChange("maxWidth", old, this.maxWidth);
    61                 if (old !=      this.maxWidth)
    62                         morph();
    63         }
     55    public void setMaxWidth(int maxWidth) {
     56        if (maxWidth <= 0)
     57            throw new IllegalArgumentException();
     58        int old = this.maxWidth;
     59        this.maxWidth = maxWidth;
     60        firePropertyChange("maxWidth", old, this.maxWidth);
     61        if (old !=  this.maxWidth)
     62            morph();
     63    }
    6464
    65         public boolean isJustified() {
    66                 return justify;
    67         }
     65    public boolean isJustified() {
     66        return justify;
     67    }
    6868
    69         public void setJustified(boolean justify) {
    70                 boolean old = this.justify;
    71                 this.justify = justify;
    72                 firePropertyChange("justified", old, this.justify);
    73                 if (old != this.justify)
    74                         repaint();
    75         }
     69    public void setJustified(boolean justify) {
     70        boolean old = this.justify;
     71        this.justify = justify;
     72        firePropertyChange("justified", old, this.justify);
     73        if (old != this.justify)
     74            repaint();
     75    }
    7676
    77         public Dimension getPreferredSize() {
    78                 return paintOrGetSize(null, getMaxWidth());
    79         }
     77    public Dimension getPreferredSize() {
     78        return paintOrGetSize(null, getMaxWidth());
     79    }
    8080
    81         public Dimension getMinimumSize() {
    82                 return getPreferredSize();
    83         }
     81    public Dimension getMinimumSize() {
     82        return getPreferredSize();
     83    }
    8484
    85         protected void paintComponent(Graphics g) {
    86                 super.paintComponent(g);
    87                 paintOrGetSize((Graphics2D)g, getWidth());
    88         }
     85    protected void paintComponent(Graphics g) {
     86        super.paintComponent(g);
     87        paintOrGetSize((Graphics2D)g, getWidth());
     88    }
    8989
    90         private Dimension paintOrGetSize(Graphics2D g, int width) {
    91                 Insets insets = getInsets();
    92                 width -= insets.left + insets.right;
    93                 float w = insets.left + insets.right;
    94                 float x = insets.left, y=insets.top;
    95                 if (width > 0 && text != null && text.length() > 0) {
    96                         AttributedString as = new AttributedString(getText());
    97                         as.addAttribute(TextAttribute.FONT, getFont());
    98                         AttributedCharacterIterator aci = as.getIterator();
    99                         LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc);
    100                         float max = 0;
    101                         while (lbm.getPosition() < aci.getEndIndex()) {
    102                                 TextLayout textLayout = lbm.nextLayout(width);
    103                                 if (g != null && isJustified() && textLayout.getVisibleAdvance() > 0.80 * width)
    104                                         textLayout = textLayout.getJustifiedLayout(width);
    105                                 if (g != null)
    106                                         textLayout.draw(g, x, y + textLayout.getAscent());
    107                                 y += textLayout.getDescent() + textLayout.getLeading() + textLayout.getAscent();
    108                                 max = Math.max(max, textLayout.getVisibleAdvance());
    109                         }
    110                         w += max;
    111                 }
    112                 return new Dimension((int)Math.ceil(w), (int)Math.ceil(y) + insets.bottom);
    113         }
     90    private Dimension paintOrGetSize(Graphics2D g, int width) {
     91        Insets insets = getInsets();
     92        width -= insets.left + insets.right;
     93        float w = insets.left + insets.right;
     94        float x = insets.left, y=insets.top;
     95        if (width > 0 && text != null && text.length() > 0) {
     96            AttributedString as = new AttributedString(getText());
     97            as.addAttribute(TextAttribute.FONT, getFont());
     98            AttributedCharacterIterator aci = as.getIterator();
     99            LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc);
     100            float max = 0;
     101            while (lbm.getPosition() < aci.getEndIndex()) {
     102                TextLayout textLayout = lbm.nextLayout(width);
     103                if (g != null && isJustified() && textLayout.getVisibleAdvance() > 0.80 * width)
     104                    textLayout = textLayout.getJustifiedLayout(width);
     105                if (g != null)
     106                    textLayout.draw(g, x, y + textLayout.getAscent());
     107                y += textLayout.getDescent() + textLayout.getLeading() + textLayout.getAscent();
     108                max = Math.max(max, textLayout.getVisibleAdvance());
     109            }
     110            w += max;
     111        }
     112        return new Dimension((int)Math.ceil(w), (int)Math.ceil(y) + insets.bottom);
     113    }
    114114}
  • trunk/src/org/openstreetmap/josm/gui/MainApplet.java

    r1146 r1169  
    3333public class MainApplet extends JApplet {
    3434
    35         public static final class UploadPreferencesAction extends JosmAction {
    36                 public UploadPreferencesAction() {
    37                         super(tr("Upload Preferences"), "upload-preferences", tr("Upload the current preferences to the server"),
    38                         Shortcut.registerShortcut("applet:uploadprefs", tr("Upload Preferences"), KeyEvent.VK_U, Shortcut.GROUP_HOTKEY), true);
     35    public static final class UploadPreferencesAction extends JosmAction {
     36        public UploadPreferencesAction() {
     37            super(tr("Upload Preferences"), "upload-preferences", tr("Upload the current preferences to the server"),
     38            Shortcut.registerShortcut("applet:uploadprefs", tr("Upload Preferences"), KeyEvent.VK_U, Shortcut.GROUP_HOTKEY), true);
    3939        }
    40             public void actionPerformed(ActionEvent e) {
    41                 ((ServerSidePreferences)Main.pref).upload();
    42             }
     40        public void actionPerformed(ActionEvent e) {
     41            ((ServerSidePreferences)Main.pref).upload();
     42        }
    4343    }
    4444
    4545    private final class MainCaller extends Main {
    46                 private MainCaller() {
    47                         setContentPane(contentPane);
    48                         setJMenuBar(menu);
    49                         setBounds(bounds);
    50                 }
    51         }
     46        private MainCaller() {
     47            setContentPane(contentPane);
     48            setJMenuBar(menu);
     49            setBounds(bounds);
     50        }
     51    }
    5252
    53         private final static String[][] paramInfo = {
    54                 {"username", tr("string"), tr("Name of the user.")},
    55                 {"password", tr("string"), tr("OSM Password.")},
    56                 {"geometry", tr("string"), tr("Resize the applet to the given geometry (format: WIDTHxHEIGHT)")},
    57                 {"download", tr("string;string;..."), tr("Download each. Can be x1,y1,x2,y2 an url containing lat=y&lon=x&zoom=z or a filename")},
    58                 {"downloadgps", tr("string;string;..."), tr("Download each as raw gps. Can be x1,y1,x2,y2 an url containing lat=y&lon=x&zoom=z or a filename")},
    59                 {"selection", tr("string;string;..."), tr("Add each to the initial selection. Can be a google-like search string or an url which returns osm-xml")},
    60                 {"reset-preferences", tr("any"),tr("If specified, reset the configuration instead of reading it.")}
    61         };
     53    private final static String[][] paramInfo = {
     54        {"username", tr("string"), tr("Name of the user.")},
     55        {"password", tr("string"), tr("OSM Password.")},
     56        {"geometry", tr("string"), tr("Resize the applet to the given geometry (format: WIDTHxHEIGHT)")},
     57        {"download", tr("string;string;..."), tr("Download each. Can be x1,y1,x2,y2 an url containing lat=y&lon=x&zoom=z or a filename")},
     58        {"downloadgps", tr("string;string;..."), tr("Download each as raw gps. Can be x1,y1,x2,y2 an url containing lat=y&lon=x&zoom=z or a filename")},
     59        {"selection", tr("string;string;..."), tr("Add each to the initial selection. Can be a google-like search string or an url which returns osm-xml")},
     60        {"reset-preferences", tr("any"),tr("If specified, reset the configuration instead of reading it.")}
     61    };
    6262
    63         private Map<String, Collection<String>> args = new HashMap<String, Collection<String>>();
     63    private Map<String, Collection<String>> args = new HashMap<String, Collection<String>>();
    6464
    65         @Override public String[][] getParameterInfo() {
    66                 return paramInfo;
    67         }
     65    @Override public String[][] getParameterInfo() {
     66        return paramInfo;
     67    }
    6868
    69         @Override public void init() {
    70                 for (String[] s : paramInfo) {
    71                         Collection<String> p = readParameter(s[0], args.get(s[0]));
    72                         if (p != null)
    73                                 args.put(s[0], p);
    74                 }
    75                 if (!args.containsKey("geometry") && getParameter("width") != null && getParameter("height") != null) {
    76                         args.put("geometry", Arrays.asList(new String[]{getParameter("width")+"x"+getParameter("height")}));
    77                 }
    78         }
     69    @Override public void init() {
     70        for (String[] s : paramInfo) {
     71            Collection<String> p = readParameter(s[0], args.get(s[0]));
     72            if (p != null)
     73                args.put(s[0], p);
     74        }
     75        if (!args.containsKey("geometry") && getParameter("width") != null && getParameter("height") != null) {
     76            args.put("geometry", Arrays.asList(new String[]{getParameter("width")+"x"+getParameter("height")}));
     77        }
     78    }
    7979
    80         @Override public void start() {
    81                 String username = args.containsKey("username") ? args.get("username").iterator().next() : null;
    82                 String password = args.containsKey("password") ? args.get("password").iterator().next() : null;
    83                 if (username == null || password == null) {
    84                         JPanel p = new JPanel(new GridBagLayout());
    85                         p.add(new JLabel(tr("Username")), GBC.std().insets(0,0,20,0));
    86                         JTextField user = new JTextField(username == null ? "" : username);
    87                         p.add(user, GBC.eol().fill(GBC.HORIZONTAL));
    88                         p.add(new JLabel(tr("Password")), GBC.std().insets(0,0,20,0));
    89                         JPasswordField pass = new JPasswordField(password == null ? "" : password);
    90                         p.add(pass, GBC.eol().fill(GBC.HORIZONTAL));
    91                         JOptionPane.showMessageDialog(null, p);
    92                         username = user.getText();
    93                         password = new String(pass.getPassword());
    94                         args.put("password", Arrays.asList(new String[]{password}));
    95                 }
     80    @Override public void start() {
     81        String username = args.containsKey("username") ? args.get("username").iterator().next() : null;
     82        String password = args.containsKey("password") ? args.get("password").iterator().next() : null;
     83        if (username == null || password == null) {
     84            JPanel p = new JPanel(new GridBagLayout());
     85            p.add(new JLabel(tr("Username")), GBC.std().insets(0,0,20,0));
     86            JTextField user = new JTextField(username == null ? "" : username);
     87            p.add(user, GBC.eol().fill(GBC.HORIZONTAL));
     88            p.add(new JLabel(tr("Password")), GBC.std().insets(0,0,20,0));
     89            JPasswordField pass = new JPasswordField(password == null ? "" : password);
     90            p.add(pass, GBC.eol().fill(GBC.HORIZONTAL));
     91            JOptionPane.showMessageDialog(null, p);
     92            username = user.getText();
     93            password = new String(pass.getPassword());
     94            args.put("password", Arrays.asList(new String[]{password}));
     95        }
    9696
    97                 Main.applet = true;
    98                 Main.pref = new ServerSidePreferences(getCodeBase());
    99                 ((ServerSidePreferences)Main.pref).download(username, password);
     97        Main.applet = true;
     98        Main.pref = new ServerSidePreferences(getCodeBase());
     99        ((ServerSidePreferences)Main.pref).download(username, password);
    100100
    101                 Main.preConstructorInit(args);
    102                 Main.parent = this;
    103                 new MainCaller().postConstructorProcessCmdLine(args);
     101        Main.preConstructorInit(args);
     102        Main.parent = this;
     103        new MainCaller().postConstructorProcessCmdLine(args);
    104104
    105                 MainMenu m = Main.main.menu; // shortcut
     105        MainMenu m = Main.main.menu; // shortcut
    106106
    107                 // remove offending stuff from JOSM (that would break the SecurityManager)
    108                 m.remove(m.fileMenu);
    109                 m.editMenu.add(new UploadPreferencesAction());
    110                 m.openFile.setEnabled(false);
    111                 m.exit.setEnabled(false);
    112                 m.save.setEnabled(false);
    113                 m.saveAs.setEnabled(false);
    114                 m.gpxExport.setEnabled(false);
    115         }
     107        // remove offending stuff from JOSM (that would break the SecurityManager)
     108        m.remove(m.fileMenu);
     109        m.editMenu.add(new UploadPreferencesAction());
     110        m.openFile.setEnabled(false);
     111        m.exit.setEnabled(false);
     112        m.save.setEnabled(false);
     113        m.saveAs.setEnabled(false);
     114        m.gpxExport.setEnabled(false);
     115    }
    116116
    117         private Collection<String> readParameter(String s, Collection<String> v) {
    118                 String param = getParameter(s);
    119                 if (param != null) {
    120                         if (v == null)
    121                                 v = new LinkedList<String>();
    122                         v.addAll(Arrays.asList(param.split(";")));
    123                 }
    124                 return v;
    125         }
     117    private Collection<String> readParameter(String s, Collection<String> v) {
     118        String param = getParameter(s);
     119        if (param != null) {
     120            if (v == null)
     121                v = new LinkedList<String>();
     122            v.addAll(Arrays.asList(param.split(";")));
     123        }
     124        return v;
     125    }
    126126
    127         public static void main(String[] args) {
    128                 final JFrame frame = new JFrame("Java OpenStreetMap Applet");
    129                 MainApplet applet = new MainApplet();
    130                 applet.setStub(new AppletStub() {
    131                         public void appletResize(int w, int h) {
    132                                 frame.setSize(w, h);
    133                         }
     127    public static void main(String[] args) {
     128        final JFrame frame = new JFrame("Java OpenStreetMap Applet");
     129        MainApplet applet = new MainApplet();
     130        applet.setStub(new AppletStub() {
     131            public void appletResize(int w, int h) {
     132                frame.setSize(w, h);
     133            }
    134134
    135                         public AppletContext getAppletContext() {
    136                                 return null;
    137                         }
     135            public AppletContext getAppletContext() {
     136                return null;
     137            }
    138138
    139                         public URL getCodeBase() {
    140                                 try {
    141                                         return new File(".").toURI().toURL();
    142                                 } catch (Exception e) {
    143                                         e.printStackTrace();
    144                                         return null;
    145                                 }
    146                         }
     139            public URL getCodeBase() {
     140                try {
     141                    return new File(".").toURI().toURL();
     142                } catch (Exception e) {
     143                    e.printStackTrace();
     144                    return null;
     145                }
     146            }
    147147
    148                         public URL getDocumentBase() {
    149                                 return getCodeBase();
    150                         }
     148            public URL getDocumentBase() {
     149                return getCodeBase();
     150            }
    151151
    152                         public String getParameter(String k) {
    153                                 return null;
    154                         }
     152            public String getParameter(String k) {
     153                return null;
     154            }
    155155
    156                         public boolean isActive() {
    157                                 return true;
    158                         }
    159                 });
    160                 applet.init();
    161                 applet.start();
    162                 frame.setContentPane(applet);
    163                 frame.setVisible(true);
    164         }
     156            public boolean isActive() {
     157                return true;
     158            }
     159        });
     160        applet.init();
     161        applet.start();
     162        frame.setContentPane(applet);
     163        frame.setVisible(true);
     164    }
    165165}
  • trunk/src/org/openstreetmap/josm/gui/MainApplication.java

    r1082 r1169  
    3737 */
    3838public class MainApplication extends Main {
    39         /**
    40         * Allow subclassing (see JOSM.java)
    41         */
    42         public MainApplication() {}
    43 
    44         /**
    45         * Construct an main frame, ready sized and operating. Does not
    46         * display the frame.
    47         */
    48         public MainApplication(JFrame mainFrame) {
    49                 super();
    50                 mainFrame.setContentPane(contentPane);
    51                 mainFrame.setJMenuBar(menu);
    52                 mainFrame.setBounds(bounds);
    53                 mainFrame.setIconImage(ImageProvider.get("logo.png").getImage());
    54                 mainFrame.addWindowListener(new WindowAdapter(){
    55                         @Override public void windowClosing(final WindowEvent arg0) {
    56                                 if (Main.breakBecauseUnsavedChanges())
    57                                         return;
    58                                 System.exit(0);
    59                         }
    60                 });
    61                 mainFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
    62         }
    63 
    64         /**
    65         * Main application Startup
    66         */
    67         public static void main(final String[] argArray) {
    68                 /////////////////////////////////////////////////////////////////////////
    69                 //                        TO ALL TRANSLATORS
    70                 /////////////////////////////////////////////////////////////////////////
    71                 // Do not translate the early strings below until the locale is set up.
    72                 // (By the eager loaded plugins)
    73                 //
    74                 // These strings cannot be translated. That's life. Really. Sorry.
    75                 //
    76                 //                                                                 Imi.
    77                 /////////////////////////////////////////////////////////////////////////
    78 
    79                 Thread.setDefaultUncaughtExceptionHandler(new BugReportExceptionHandler());
    80 
    81                 // initialize the plaform hook, and
    82                 Main.determinePlatformHook();
    83                 // call the really early hook before we anything else
    84                 Main.platform.preStartupHook();
    85 
    86                 // construct argument table
    87                 List<String> argList = Arrays.asList(argArray);
    88                 final Map<String, Collection<String>> args = new HashMap<String, Collection<String>>();
    89                 for (String arg : argArray) {
    90                         if (!arg.startsWith("--"))
    91                                 arg = "--download="+arg;
    92                         int i = arg.indexOf('=');
    93                         String key = i == -1 ? arg.substring(2) : arg.substring(2,i);
    94                         String value = i == -1 ? "" : arg.substring(i+1);
    95                         Collection<String> v = args.get(key);
    96                         if (v == null)
    97                                 v = new LinkedList<String>();
    98                         v.add(value);
    99                         args.put(key, v);
    100                 }
    101 
    102                 if (argList.contains("--help") || argList.contains("-?") || argList.contains("-h")) {
    103                         // TODO: put in a platformHook for system that have no console by default
    104                         System.out.println(tr("Java OpenStreetMap Editor")+"\n\n"+
    105                                         tr("usage")+":\n"+
    106                                         "\tjava -jar josm.jar <option> <option> <option>...\n\n"+
    107                                         tr("options")+":\n"+
    108                                         "\t--help|-?|-h                              "+tr("Show this help")+"\n"+
    109                                         "\t--geometry=widthxheight(+|-)x(+|-)y       "+tr("Standard unix geometry argument")+"\n"+
    110                                         "\t[--download=]minlat,minlon,maxlat,maxlon  "+tr("Download the bounding box")+"\n"+
    111                                         "\t[--download=]<url>                        "+tr("Download the location at the url (with lat=x&lon=y&zoom=z)")+"\n"+
    112                                         "\t[--download=]<filename>                   "+tr("Open file (as raw gps, if .gpx)")+"\n"+
    113                                         "\t--downloadgps=minlat,minlon,maxlat,maxlon "+tr("Download the bounding box as raw gps")+"\n"+
    114                                         "\t--selection=<searchstring>                "+tr("Select with the given search")+"\n"+
    115                                         "\t--no-fullscreen                           "+tr("Don't launch in fullscreen mode")+"\n"+
    116                                         "\t--reset-preferences                       "+tr("Reset the preferences to default")+"\n\n"+
    117                                         "\t--language=<language>                     "+tr("Set the language.")+"\n\n"+
    118                                         tr("examples")+":\n"+
    119                                         "\tjava -jar josm.jar track1.gpx track2.gpx london.osm\n"+
    120                                         "\tjava -jar josm.jar http://www.openstreetmap.org/index.html?lat=43.2&lon=11.1&zoom=13\n"+
    121                                         "\tjava -jar josm.jar london.osm --selection=http://www.ostertag.name/osm/OSM_errors_node-duplicate.xml\n"+
    122                                         "\tjava -jar josm.jar 43.2,11.1,43.4,11.4\n\n"+
    123 
    124                                         tr("Parameters are read in the order they are specified, so make sure you load\n"+
    125                                         "some data before --selection")+"\n\n"+
    126                                         tr("Instead of --download=<bbox> you may specify osm://<bbox>\n"));
    127                         System.exit(0);
    128                 }
    129 
    130                 // get the preferences.
    131                 final File prefDir = new File(Main.pref.getPreferencesDir());
    132                 // check if preferences directory has moved (TODO: Update code. Remove this after some time)
    133                 File oldPrefDir = new File(System.getProperty("user.home"), ".josm");
    134                 if (!prefDir.isDirectory() && oldPrefDir.isDirectory()) {
    135                         if (oldPrefDir.renameTo(prefDir)) {
    136                                 // do not translate this
    137                                 JOptionPane.showMessageDialog(null, "The preference directory has been moved to "+prefDir);
    138                         } else {
    139                                 JOptionPane.showMessageDialog(null, "The preference directory location has changed. Please move "+oldPrefDir+" to "+prefDir);
    140                         }
    141                 }
    142 
    143                 if (prefDir.exists() && !prefDir.isDirectory()) {
    144                         JOptionPane.showMessageDialog(null, "Cannot open preferences directory: "+Main.pref.getPreferencesDir());
    145                         return;
    146                 }
    147                 if (!prefDir.exists())
    148                         prefDir.mkdirs();
    149 
    150                 if (!new File(Main.pref.getPreferencesDir()+"preferences").exists()) {
    151                         Main.pref.resetToDefault();
    152                 }
    153 
    154                 try {
    155                         if (args.containsKey("reset-preferences")) {
    156                                 Main.pref.resetToDefault();
    157                         } else {
    158                                 Main.pref.load();
    159                         }
    160                 } catch (final IOException e1) {
    161                         e1.printStackTrace();
    162                         String backup = Main.pref.getPreferencesDir() + "preferences.bak";
    163                         JOptionPane.showMessageDialog(null, "Preferences file had errors.  Making backup of old one to " + backup);
    164                         new File(Main.pref.getPreferencesDir() + "preferences").renameTo(new File(backup));
    165                         Main.pref.save();
    166                 }
     39    /**
     40    * Allow subclassing (see JOSM.java)
     41    */
     42    public MainApplication() {}
     43
     44    /**
     45    * Construct an main frame, ready sized and operating. Does not
     46    * display the frame.
     47    */
     48    public MainApplication(JFrame mainFrame) {
     49        super();
     50        mainFrame.setContentPane(contentPane);
     51        mainFrame.setJMenuBar(menu);
     52        mainFrame.setBounds(bounds);
     53        mainFrame.setIconImage(ImageProvider.get("logo.png").getImage());
     54        mainFrame.addWindowListener(new WindowAdapter(){
     55            @Override public void windowClosing(final WindowEvent arg0) {
     56                if (Main.breakBecauseUnsavedChanges())
     57                    return;
     58                System.exit(0);
     59            }
     60        });
     61        mainFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
     62    }
     63
     64    /**
     65    * Main application Startup
     66    */
     67    public static void main(final String[] argArray) {
     68        /////////////////////////////////////////////////////////////////////////
     69        //                        TO ALL TRANSLATORS
     70        /////////////////////////////////////////////////////////////////////////
     71        // Do not translate the early strings below until the locale is set up.
     72        // (By the eager loaded plugins)
     73        //
     74        // These strings cannot be translated. That's life. Really. Sorry.
     75        //
     76        //                                                                 Imi.
     77        /////////////////////////////////////////////////////////////////////////
     78
     79        Thread.setDefaultUncaughtExceptionHandler(new BugReportExceptionHandler());
     80
     81        // initialize the plaform hook, and
     82        Main.determinePlatformHook();
     83        // call the really early hook before we anything else
     84        Main.platform.preStartupHook();
     85
     86        // construct argument table
     87        List<String> argList = Arrays.asList(argArray);
     88        final Map<String, Collection<String>> args = new HashMap<String, Collection<String>>();
     89        for (String arg : argArray) {
     90            if (!arg.startsWith("--"))
     91                arg = "--download="+arg;
     92            int i = arg.indexOf('=');
     93            String key = i == -1 ? arg.substring(2) : arg.substring(2,i);
     94            String value = i == -1 ? "" : arg.substring(i+1);
     95            Collection<String> v = args.get(key);
     96            if (v == null)
     97                v = new LinkedList<String>();
     98            v.add(value);
     99            args.put(key, v);
     100        }
     101
     102        if (argList.contains("--help") || argList.contains("-?") || argList.contains("-h")) {
     103            // TODO: put in a platformHook for system that have no console by default
     104            System.out.println(tr("Java OpenStreetMap Editor")+"\n\n"+
     105                    tr("usage")+":\n"+
     106                    "\tjava -jar josm.jar <option> <option> <option>...\n\n"+
     107                    tr("options")+":\n"+
     108                    "\t--help|-?|-h                              "+tr("Show this help")+"\n"+
     109                    "\t--geometry=widthxheight(+|-)x(+|-)y       "+tr("Standard unix geometry argument")+"\n"+
     110                    "\t[--download=]minlat,minlon,maxlat,maxlon  "+tr("Download the bounding box")+"\n"+
     111                    "\t[--download=]<url>                        "+tr("Download the location at the url (with lat=x&lon=y&zoom=z)")+"\n"+
     112                    "\t[--download=]<filename>                   "+tr("Open file (as raw gps, if .gpx)")+"\n"+
     113                    "\t--downloadgps=minlat,minlon,maxlat,maxlon "+tr("Download the bounding box as raw gps")+"\n"+
     114                    "\t--selection=<searchstring>                "+tr("Select with the given search")+"\n"+
     115                    "\t--no-fullscreen                           "+tr("Don't launch in fullscreen mode")+"\n"+
     116                    "\t--reset-preferences                       "+tr("Reset the preferences to default")+"\n\n"+
     117                    "\t--language=<language>                     "+tr("Set the language.")+"\n\n"+
     118                    tr("examples")+":\n"+
     119                    "\tjava -jar josm.jar track1.gpx track2.gpx london.osm\n"+
     120                    "\tjava -jar josm.jar http://www.openstreetmap.org/index.html?lat=43.2&lon=11.1&zoom=13\n"+
     121                    "\tjava -jar josm.jar london.osm --selection=http://www.ostertag.name/osm/OSM_errors_node-duplicate.xml\n"+
     122                    "\tjava -jar josm.jar 43.2,11.1,43.4,11.4\n\n"+
     123
     124                    tr("Parameters are read in the order they are specified, so make sure you load\n"+
     125                    "some data before --selection")+"\n\n"+
     126                    tr("Instead of --download=<bbox> you may specify osm://<bbox>\n"));
     127            System.exit(0);
     128        }
     129
     130        // get the preferences.
     131        final File prefDir = new File(Main.pref.getPreferencesDir());
     132        // check if preferences directory has moved (TODO: Update code. Remove this after some time)
     133        File oldPrefDir = new File(System.getProperty("user.home"), ".josm");
     134        if (!prefDir.isDirectory() && oldPrefDir.isDirectory()) {
     135            if (oldPrefDir.renameTo(prefDir)) {
     136                // do not translate this
     137                JOptionPane.showMessageDialog(null, "The preference directory has been moved to "+prefDir);
     138            } else {
     139                JOptionPane.showMessageDialog(null, "The preference directory location has changed. Please move "+oldPrefDir+" to "+prefDir);
     140            }
     141        }
     142
     143        if (prefDir.exists() && !prefDir.isDirectory()) {
     144            JOptionPane.showMessageDialog(null, "Cannot open preferences directory: "+Main.pref.getPreferencesDir());
     145            return;
     146        }
     147        if (!prefDir.exists())
     148            prefDir.mkdirs();
     149
     150        if (!new File(Main.pref.getPreferencesDir()+"preferences").exists()) {
     151            Main.pref.resetToDefault();
     152        }
     153
     154        try {
     155            if (args.containsKey("reset-preferences")) {
     156                Main.pref.resetToDefault();
     157            } else {
     158                Main.pref.load();
     159            }
     160        } catch (final IOException e1) {
     161            e1.printStackTrace();
     162            String backup = Main.pref.getPreferencesDir() + "preferences.bak";
     163            JOptionPane.showMessageDialog(null, "Preferences file had errors.  Making backup of old one to " + backup);
     164            new File(Main.pref.getPreferencesDir() + "preferences").renameTo(new File(backup));
     165            Main.pref.save();
     166        }
    167167
    168168        // TODO remove this in early 2009 - just here to weed out color setting we don't use any more
    169169        Main.pref.put("downloaded Area", null);
    170170
    171                 String localeName = null; //The locale to use
    172        
    173                 //Check if passed as parameter
    174                 if(args.containsKey("language")) 
    175                     localeName = (String)(args.get("language").toArray()[0]);
    176                
    177                 if (localeName == null) {
    178                         localeName = Main.pref.get("language", null);
    179                 }
    180 
    181                 if (localeName != null) {
    182                         Locale l;
    183                         int i = localeName.indexOf('_');
    184                         if (i > 0) {
    185                                 l = new Locale(localeName.substring(0, i), localeName.substring(i + 1));
    186                         } else {
    187                                 l = new Locale(localeName);
    188                         }
    189                         Locale.setDefault(l);
    190                 }
     171        String localeName = null; //The locale to use
     172
     173        //Check if passed as parameter
     174        if(args.containsKey("language"))
     175            localeName = (String)(args.get("language").toArray()[0]);
     176
     177        if (localeName == null) {
     178            localeName = Main.pref.get("language", null);
     179        }
     180
     181        if (localeName != null) {
     182            Locale l;
     183            int i = localeName.indexOf('_');
     184            if (i > 0) {
     185                l = new Locale(localeName.substring(0, i), localeName.substring(i + 1));
     186            } else {
     187                l = new Locale(localeName);
     188            }
     189            Locale.setDefault(l);
     190        }
    191191        try {
    192192            i18n = I18nFactory.getI18n(MainApplication.class);
     
    194194            System.out.println("Unable to find translation for the locale: " + Locale.getDefault().getDisplayName() + " reverting to English.");
    195195        }
    196                
    197                 SplashScreen splash = new SplashScreen(Main.pref.getBoolean("draw.splashscreen", true));
    198 
    199                 splash.setStatus(tr("Activating updated plugins"));
    200                 if (!PluginDownloader.moveUpdatedPlugins()) {
    201                         JOptionPane.showMessageDialog(null,
    202                                 tr("Activating the updated plugins failed. Check if JOSM has the permission to overwrite the existing ones."),
    203                                 tr("Plugins"), JOptionPane.ERROR_MESSAGE);
    204                 }
    205 
    206                 // load the early plugins
    207                 splash.setStatus(tr("Loading early plugins"));
    208                 Main.loadPlugins(true);
    209 
    210                 splash.setStatus(tr("Setting defaults"));
    211                 preConstructorInit(args);
    212                 splash.setStatus(tr("Creating main GUI"));
    213                 JFrame mainFrame = new JFrame(tr("Java OpenStreetMap - Editor"));
    214                 Main.parent = mainFrame;
    215                 final Main main = new MainApplication(mainFrame);
    216                 splash.setStatus(tr("Loading plugins"));
    217                 Main.loadPlugins(false);
    218                 toolbar.refreshToolbarControl();
    219 
    220                 mainFrame.setVisible(true);
    221                 splash.closeSplash();
    222 
    223                 if (!args.containsKey("no-fullscreen") && !args.containsKey("geometry") && Toolkit.getDefaultToolkit().isFrameStateSupported(JFrame.MAXIMIZED_BOTH))
    224                         mainFrame.setExtendedState(JFrame.MAXIMIZED_BOTH);
    225 
    226                 EventQueue.invokeLater(new Runnable(){
    227                         public void run() {
    228                                 main.postConstructorProcessCmdLine(args);
    229                         }
    230                 });
    231         }
     196
     197        SplashScreen splash = new SplashScreen(Main.pref.getBoolean("draw.splashscreen", true));
     198
     199        splash.setStatus(tr("Activating updated plugins"));
     200        if (!PluginDownloader.moveUpdatedPlugins()) {
     201            JOptionPane.showMessageDialog(null,
     202                    tr("Activating the updated plugins failed. Check if JOSM has the permission to overwrite the existing ones."),
     203                    tr("Plugins"), JOptionPane.ERROR_MESSAGE);
     204        }
     205
     206        // load the early plugins
     207        splash.setStatus(tr("Loading early plugins"));
     208        Main.loadPlugins(true);
     209
     210        splash.setStatus(tr("Setting defaults"));
     211        preConstructorInit(args);
     212        splash.setStatus(tr("Creating main GUI"));
     213        JFrame mainFrame = new JFrame(tr("Java OpenStreetMap - Editor"));
     214        Main.parent = mainFrame;
     215        final Main main = new MainApplication(mainFrame);
     216        splash.setStatus(tr("Loading plugins"));
     217        Main.loadPlugins(false);
     218        toolbar.refreshToolbarControl();
     219
     220        mainFrame.setVisible(true);
     221        splash.closeSplash();
     222
     223        if (!args.containsKey("no-fullscreen") && !args.containsKey("geometry") && Toolkit.getDefaultToolkit().isFrameStateSupported(JFrame.MAXIMIZED_BOTH))
     224            mainFrame.setExtendedState(JFrame.MAXIMIZED_BOTH);
     225
     226        EventQueue.invokeLater(new Runnable(){
     227            public void run() {
     228                main.postConstructorProcessCmdLine(args);
     229            }
     230        });
     231    }
    232232
    233233}
  • trunk/src/org/openstreetmap/josm/gui/MainMenu.java

    r1161 r1169  
    6868 * This is the JOSM main menu bar. It is overwritten to initialize itself and provide all menu
    6969 * entries as member variables (sort of collect them).
    70  * 
     70 *
    7171 * It also provides possibilities to attach new menu entries (used by plugins).
    72  * 
     72 *
    7373 * @author Immanuel.Scholz
    7474 */
     
    140140    /**
    141141     * Add a JosmAction to a menu.
    142      * 
     142     *
    143143     * This method handles all the shortcut handling. It also makes sure that actions that are
    144144     * handled by the OS are not duplicated on the menu.
     
    156156    /**
    157157     * Add a menu to the main menu.
    158      * 
     158     *
    159159     * This method handles all the shortcut handling.
    160160     */
  • trunk/src/org/openstreetmap/josm/gui/MapFrame.java

    r1153 r1169  
    3535 * One Map frame with one dataset behind. This is the container gui class whose
    3636 * display can be set to the different views.
    37  * 
     37 *
    3838 * @author imi
    3939 */
    4040public class MapFrame extends JPanel implements Destroyable {
    4141
    42         /**
    43         * The current mode, this frame operates.
    44         */
    45         public MapMode mapMode;
    46         /**
    47         * The view control displayed.
    48         */
    49         public MapView mapView;
    50         /**
    51         * The toolbar with the action icons. To add new toggle dialog actions, use addToggleDialog
    52         * instead of adding directly to this list. To add a new mode use addMapMode.
    53         */
    54         public JToolBar toolBarActions = new JToolBar(JToolBar.VERTICAL);
    55         public JToolBar toolBarToggle = new JToolBar(JToolBar.VERTICAL);
    56         /**
    57         * The status line below the map
    58         */
    59         public MapStatus statusLine;
    60 
    61         public ConflictDialog conflictDialog;
    62         /**
    63         * The dialog that shows all relations and lets the user edit them.
    64         */
    65         public RelationListDialog relationListDialog;
    66         /**
    67         * The panel list of all toggle dialog icons. To add new toggle dialog actions, use addToggleDialog
    68         * instead of adding directly to this list.
    69         */
    70         public JPanel toggleDialogs = new JPanel();
    71 
    72         public final ButtonGroup toolGroup = new ButtonGroup();
    73 
    74         public MapFrame() {
    75                 setSize(400,400);
    76                 setLayout(new BorderLayout());
    77 
    78                 add(mapView = new MapView(), BorderLayout.CENTER);
    79 
    80                 // show menu entry
    81                 Main.main.menu.viewMenu.setVisible(true);
    82 
    83                 // toolbar
    84                 toolBarActions.setFloatable(false);
    85                 addMapMode(new IconToggleButton(new ZoomAction(this)));
    86                 addMapMode(new IconToggleButton(new SelectAction(this)));
    87                 addMapMode(new IconToggleButton(new DrawAction(this)));
    88                 addMapMode(new IconToggleButton(new DeleteAction(this)));
    89                 addMapMode(new IconToggleButton(new ExtrudeAction(this)));
    90 
    91                 toolGroup.setSelected(((AbstractButton)toolBarActions.getComponent(0)).getModel(), true);
    92 
    93                 add(toggleDialogs, BorderLayout.EAST);
    94                 toggleDialogs.setLayout(new BoxLayout(toggleDialogs, BoxLayout.Y_AXIS));
    95 
    96                 toolBarToggle.setFloatable(false);
    97                 addToggleDialog(new LayerListDialog(this));
    98                 addToggleDialog(new PropertiesDialog(this));
    99                 addToggleDialog(new HistoryDialog());
    100                 addToggleDialog(new SelectionListDialog());
    101                 addToggleDialog(new UserListDialog());
    102                 addToggleDialog(conflictDialog = new ConflictDialog());
    103                 addToggleDialog(new CommandStackDialog(this));
    104                 addToggleDialog(relationListDialog = new RelationListDialog());
    105 
    106                 // status line below the map
    107                 statusLine = new MapStatus(this);
    108         }
    109 
    110         /**
    111         * Called as some kind of destructor when the last layer has been removed.
    112         * Delegates the call to all Destroyables within this component (e.g. MapModes)
    113         */
    114         public void destroy() {
    115                 for (int i = 0; i < toolBarActions.getComponentCount(); ++i)
    116                         if (toolBarActions.getComponent(i) instanceof Destroyable)
    117                                 ((Destroyable)toolBarActions).destroy();
    118                 for (int i = 0; i < toolBarToggle.getComponentCount(); ++i)
    119                         if (toolBarToggle.getComponent(i) instanceof Destroyable)
    120                                 ((Destroyable)toolBarToggle).destroy();
    121                
    122                 // remove menu entries
    123                 Main.main.menu.viewMenu.setVisible(false);
    124     }
    125 
    126         public Action getDefaultButtonAction() {
    127                 return ((AbstractButton)toolBarActions.getComponent(0)).getAction();
    128         }
    129 
    130         /**
    131         * Open all ToggleDialogs that have their preferences property set. Close all others.
    132         */
    133         public void setVisibleDialogs() {
    134                 for (Component c : toggleDialogs.getComponents()) {
    135                         if (c instanceof ToggleDialog) {
    136                                 boolean sel = Main.pref.getBoolean(((ToggleDialog)c).prefName+".visible");
    137                                 ((ToggleDialog)c).action.button.setSelected(sel);
    138                                 c.setVisible(sel);
    139                         }
    140                 }
    141         }
    142 
    143         /**
    144         * Call this to add new toggle dialogs to the left button-list
    145         * @param dlg The toggle dialog. It must not be in the list already.
    146         */
    147         public void addToggleDialog(ToggleDialog dlg) {
    148                 IconToggleButton button = new IconToggleButton(dlg.action);
    149                 dlg.action.button = button;
    150                 dlg.parent = toggleDialogs;
    151                 toolBarToggle.add(button);
    152                 toggleDialogs.add(dlg);
    153         }
    154 
    155         public void addMapMode(IconToggleButton b) {
    156                 toolBarActions.add(b);
    157                 toolGroup.add((AbstractButton)b);
    158         }
    159 
    160         /**
    161         * Fires an property changed event "visible".
    162         */
    163         @Override public void setVisible(boolean aFlag) {
    164                 boolean old = isVisible();
    165                 super.setVisible(aFlag);
    166                 if (old != aFlag)
    167                         firePropertyChange("visible", old, aFlag);
    168         }
    169 
    170 
    171 
    172         /**
    173         * Change the operating map mode for the view. Will call unregister on the
    174         * old MapMode and register on the new one.
    175         * @param mapMode       The new mode to set.
    176         */
    177         public void selectMapMode(MapMode mapMode) {
    178                 if (mapMode == this.mapMode)
    179                         return;
    180                 if (this.mapMode != null)
    181                         this.mapMode.exitMode();
    182                 this.mapMode = mapMode;
    183                 mapMode.enterMode();
    184         }
    185 
    186         /**
    187         * Fill the given panel by adding all necessary components to the different
    188         * locations.
    189          *
    190         * @param panel The container to fill. Must have an BorderLayout.
    191         */
    192         public void fillPanel(Container panel) {
    193                 panel.add(this, BorderLayout.CENTER);
    194                 JToolBar jb = new JToolBar(JToolBar.VERTICAL);
    195                 jb.setFloatable(false);
    196                 jb.add(toolBarActions);
    197                 jb.addSeparator();
    198                 jb.add(toolBarToggle);
    199                 panel.add(jb, BorderLayout.WEST);
    200                 if (statusLine != null)
    201                         panel.add(statusLine, BorderLayout.SOUTH);
    202         }
     42    /**
     43    * The current mode, this frame operates.
     44    */
     45    public MapMode mapMode;
     46    /**
     47    * The view control displayed.
     48    */
     49    public MapView mapView;
     50    /**
     51    * The toolbar with the action icons. To add new toggle dialog actions, use addToggleDialog
     52    * instead of adding directly to this list. To add a new mode use addMapMode.
     53    */
     54    public JToolBar toolBarActions = new JToolBar(JToolBar.VERTICAL);
     55    public JToolBar toolBarToggle = new JToolBar(JToolBar.VERTICAL);
     56    /**
     57    * The status line below the map
     58    */
     59    public MapStatus statusLine;
     60
     61    public ConflictDialog conflictDialog;
     62    /**
     63    * The dialog that shows all relations and lets the user edit them.
     64    */
     65    public RelationListDialog relationListDialog;
     66    /**
     67    * The panel list of all toggle dialog icons. To add new toggle dialog actions, use addToggleDialog
     68    * instead of adding directly to this list.
     69    */
     70    public JPanel toggleDialogs = new JPanel();
     71
     72    public final ButtonGroup toolGroup = new ButtonGroup();
     73
     74    public MapFrame() {
     75        setSize(400,400);
     76        setLayout(new BorderLayout());
     77
     78        add(mapView = new MapView(), BorderLayout.CENTER);
     79
     80        // show menu entry
     81        Main.main.menu.viewMenu.setVisible(true);
     82
     83        // toolbar
     84        toolBarActions.setFloatable(false);
     85        addMapMode(new IconToggleButton(new ZoomAction(this)));
     86        addMapMode(new IconToggleButton(new SelectAction(this)));
     87        addMapMode(new IconToggleButton(new DrawAction(this)));
     88        addMapMode(new IconToggleButton(new DeleteAction(this)));
     89        addMapMode(new IconToggleButton(new ExtrudeAction(this)));
     90
     91        toolGroup.setSelected(((AbstractButton)toolBarActions.getComponent(0)).getModel(), true);
     92
     93        add(toggleDialogs, BorderLayout.EAST);
     94        toggleDialogs.setLayout(new BoxLayout(toggleDialogs, BoxLayout.Y_AXIS));
     95
     96        toolBarToggle.setFloatable(false);
     97        addToggleDialog(new LayerListDialog(this));
     98        addToggleDialog(new PropertiesDialog(this));
     99        addToggleDialog(new HistoryDialog());
     100        addToggleDialog(new SelectionListDialog());
     101        addToggleDialog(new UserListDialog());
     102        addToggleDialog(conflictDialog = new ConflictDialog());
     103        addToggleDialog(new CommandStackDialog(this));
     104        addToggleDialog(relationListDialog = new RelationListDialog());
     105
     106        // status line below the map
     107        statusLine = new MapStatus(this);
     108    }
     109
     110    /**
     111    * Called as some kind of destructor when the last layer has been removed.
     112    * Delegates the call to all Destroyables within this component (e.g. MapModes)
     113    */
     114    public void destroy() {
     115        for (int i = 0; i < toolBarActions.getComponentCount(); ++i)
     116            if (toolBarActions.getComponent(i) instanceof Destroyable)
     117                ((Destroyable)toolBarActions).destroy();
     118        for (int i = 0; i < toolBarToggle.getComponentCount(); ++i)
     119            if (toolBarToggle.getComponent(i) instanceof Destroyable)
     120                ((Destroyable)toolBarToggle).destroy();
     121
     122        // remove menu entries
     123        Main.main.menu.viewMenu.setVisible(false);
     124    }
     125
     126    public Action getDefaultButtonAction() {
     127        return ((AbstractButton)toolBarActions.getComponent(0)).getAction();
     128    }
     129
     130    /**
     131    * Open all ToggleDialogs that have their preferences property set. Close all others.
     132    */
     133    public void setVisibleDialogs() {
     134        for (Component c : toggleDialogs.getComponents()) {
     135            if (c instanceof ToggleDialog) {
     136                boolean sel = Main.pref.getBoolean(((ToggleDialog)c).prefName+".visible");
     137                ((ToggleDialog)c).action.button.setSelected(sel);
     138                c.setVisible(sel);
     139            }
     140        }
     141    }
     142
     143    /**
     144    * Call this to add new toggle dialogs to the left button-list
     145    * @param dlg The toggle dialog. It must not be in the list already.
     146    */
     147    public void addToggleDialog(ToggleDialog dlg) {
     148        IconToggleButton button = new IconToggleButton(dlg.action);
     149        dlg.action.button = button;
     150        dlg.parent = toggleDialogs;
     151        toolBarToggle.add(button);
     152        toggleDialogs.add(dlg);
     153    }
     154
     155    public void addMapMode(IconToggleButton b) {
     156        toolBarActions.add(b);
     157        toolGroup.add((AbstractButton)b);
     158    }
     159
     160    /**
     161    * Fires an property changed event "visible".
     162    */
     163    @Override public void setVisible(boolean aFlag) {
     164        boolean old = isVisible();
     165        super.setVisible(aFlag);
     166        if (old != aFlag)
     167            firePropertyChange("visible", old, aFlag);
     168    }
     169
     170
     171
     172    /**
     173    * Change the operating map mode for the view. Will call unregister on the
     174    * old MapMode and register on the new one.
     175    * @param mapMode   The new mode to set.
     176    */
     177    public void selectMapMode(MapMode mapMode) {
     178        if (mapMode == this.mapMode)
     179            return;
     180        if (this.mapMode != null)
     181            this.mapMode.exitMode();
     182        this.mapMode = mapMode;
     183        mapMode.enterMode();
     184    }
     185
     186    /**
     187    * Fill the given panel by adding all necessary components to the different
     188    * locations.
     189     *
     190    * @param panel The container to fill. Must have an BorderLayout.
     191    */
     192    public void fillPanel(Container panel) {
     193        panel.add(this, BorderLayout.CENTER);
     194        JToolBar jb = new JToolBar(JToolBar.VERTICAL);
     195        jb.setFloatable(false);
     196        jb.add(toolBarActions);
     197        jb.addSeparator();
     198        jb.add(toolBarToggle);
     199        panel.add(jb, BorderLayout.WEST);
     200        if (statusLine != null)
     201            panel.add(statusLine, BorderLayout.SOUTH);
     202    }
    203203}
  • trunk/src/org/openstreetmap/josm/gui/MapMover.java

    r1084 r1169  
    2828public class MapMover extends MouseAdapter implements MouseMotionListener, MouseWheelListener {
    2929
    30         private final class ZoomerAction extends AbstractAction {
    31                 private final String action;
    32                 public ZoomerAction(String action) {
    33                         this.action = action;
     30    private final class ZoomerAction extends AbstractAction {
     31        private final String action;
     32        public ZoomerAction(String action) {
     33            this.action = action;
    3434        }
    35             public void actionPerformed(ActionEvent e) {
    36                 if (action.equals(".") || action.equals(",")) {
    37                         Point mouse = nc.getMousePosition();
    38                         if (mouse == null)
    39                                 mouse = new Point((int)nc.getBounds().getCenterX(), (int)nc.getBounds().getCenterY());
    40                         MouseWheelEvent we = new MouseWheelEvent(nc, e.getID(), e.getWhen(), e.getModifiers(), mouse.x, mouse.y, 0, false, MouseWheelEvent.WHEEL_UNIT_SCROLL, 1, action.equals(",") ? -1 : 1);
    41                         mouseWheelMoved(we);
    42                 } else {
    43                         EastNorth center = nc.getCenter();
    44                         EastNorth newcenter = nc.getEastNorth(nc.getWidth()/2+nc.getWidth()/5, nc.getHeight()/2+nc.getHeight()/5);
    45                         if (action.equals("left"))
    46                                 nc.zoomTo(new EastNorth(2*center.east()-newcenter.east(), center.north()), nc.getScale());
    47                         else if (action.equals("right"))
    48                                 nc.zoomTo(new EastNorth(newcenter.east(), center.north()), nc.getScale());
    49                         else if (action.equals("up"))
    50                                 nc.zoomTo(new EastNorth(center.east(), 2*center.north()-newcenter.north()), nc.getScale());
    51                         else if (action.equals("down"))
    52                                 nc.zoomTo(new EastNorth(center.east(), newcenter.north()), nc.getScale());
    53                 }
    54             }
    55     }
    56 
    57         /**
    58         * The point in the map that was the under the mouse point
    59         * when moving around started.
    60         */
    61         private EastNorth mousePosMove;
    62         /**
    63         * The map to move around.
    64         */
    65         private final NavigatableComponent nc;
    66         /**
    67         * The old cursor when we changed it to movement cursor.
    68         */
    69         private Cursor oldCursor;
    70 
    71         private boolean movementInPlace = false;
    72 
    73         /**
    74         * Create a new MapMover
    75         */
    76         public MapMover(NavigatableComponent navComp, JPanel contentPane) {
    77                 this.nc = navComp;
    78                 nc.addMouseListener(this);
    79                 nc.addMouseMotionListener(this);
    80                 nc.addMouseWheelListener(this);
    81 
    82                 if (contentPane != null) {
    83                         contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
    84                                 Shortcut.registerShortcut("system:movefocusright", tr("Map: {0}", tr("Move right")), KeyEvent.VK_RIGHT, Shortcut.GROUP_HOTKEY).getKeyStroke(),
    85                                 "MapMover.Zoomer.right");
    86                         contentPane.getActionMap().put("MapMover.Zoomer.right", new ZoomerAction("right"));
    87 
    88                         contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
    89                                 Shortcut.registerShortcut("system:movefocusleft", tr("Map: {0}", tr("Move left")), KeyEvent.VK_LEFT, Shortcut.GROUP_HOTKEY).getKeyStroke(),
    90                                 "MapMover.Zoomer.left");
    91                         contentPane.getActionMap().put("MapMover.Zoomer.left", new ZoomerAction("left"));
    92 
    93                         contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
    94                                 Shortcut.registerShortcut("system:movefocusup", tr("Map: {0}", tr("Move up")), KeyEvent.VK_UP, Shortcut.GROUP_HOTKEY).getKeyStroke(),
    95                                 "MapMover.Zoomer.up");
    96                         contentPane.getActionMap().put("MapMover.Zoomer.up", new ZoomerAction("up"));
    97 
    98                         contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
    99                                 Shortcut.registerShortcut("system:movefocusdown", tr("Map: {0}", tr("Move down")), KeyEvent.VK_DOWN, Shortcut.GROUP_HOTKEY).getKeyStroke(),
    100                                 "MapMover.Zoomer.down");
    101                         contentPane.getActionMap().put("MapMover.Zoomer.down", new ZoomerAction("down"));
    102 
    103                         contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
    104                                 Shortcut.registerShortcut("view:zoominalternate", tr("Map: {0}", tr("Zoom in")), KeyEvent.VK_COMMA, Shortcut.GROUP_HOTKEY).getKeyStroke(),
    105                                 "MapMover.Zoomer.in");
    106                         contentPane.getActionMap().put("MapMover.Zoomer.in", new ZoomerAction(","));
    107 
    108                         contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
    109                                 Shortcut.registerShortcut("view:zoomoutalternate", tr("Map: {0}", tr("Zoom out")), KeyEvent.VK_PERIOD, Shortcut.GROUP_HOTKEY).getKeyStroke(),
    110                                 "MapMover.Zoomer.out");
    111                         contentPane.getActionMap().put("MapMover.Zoomer.out", new ZoomerAction("."));
    112                 }
    113         }
    114 
    115         /**
    116         * If the right (and only the right) mouse button is pressed, move the map
    117         */
    118         public void mouseDragged(MouseEvent e) {
    119                 int offMask = MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON2_DOWN_MASK;
    120                 if ((e.getModifiersEx() & (MouseEvent.BUTTON3_DOWN_MASK | offMask)) == MouseEvent.BUTTON3_DOWN_MASK) {
    121                         if (mousePosMove == null)
    122                                 startMovement(e);
    123                         EastNorth center = nc.getCenter();
    124                         EastNorth mouseCenter = nc.getEastNorth(e.getX(), e.getY());
    125                         EastNorth p = new EastNorth(
    126                                         mousePosMove.east() + center.east() - mouseCenter.east(),
    127                                         mousePosMove.north() + center.north() - mouseCenter.north());
    128                         nc.zoomTo(p, nc.getScale());
    129                 } else
    130                         endMovement();
    131         }
    132 
    133         /**
    134         * Start the movement, if it was the 3rd button (right button).
    135         */
    136         @Override public void mousePressed(MouseEvent e) {
    137                 int offMask = MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON2_DOWN_MASK;
    138                 if (e.getButton() == MouseEvent.BUTTON3 && (e.getModifiersEx() & offMask) == 0)
    139                         startMovement(e);
    140         }
    141 
    142         /**
    143         * Change the cursor back to it's pre-move cursor.
    144         */
    145         @Override public void mouseReleased(MouseEvent e) {
    146                 if (e.getButton() == MouseEvent.BUTTON3)
    147                         endMovement();
    148         }
    149 
    150         /**
    151         * Start movement by setting a new cursor and remember the current mouse
    152         * position.
    153         * @param e The mouse event that leat to the movement from.
    154         */
    155         private void startMovement(MouseEvent e) {
    156                 if (movementInPlace)
    157                         return;
    158                 movementInPlace = true;
    159                 mousePosMove = nc.getEastNorth(e.getX(), e.getY());
    160                 oldCursor = nc.getCursor();
    161                 nc.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
    162         }
    163 
    164         /**
    165         * End the movement. Setting back the cursor and clear the movement variables
    166         */
    167         private void endMovement() {
    168                 if (!movementInPlace)
    169                         return;
    170                 movementInPlace = false;
    171                 if (oldCursor != null)
    172                         nc.setCursor(oldCursor);
    173                 else
    174                         nc.setCursor(Cursor.getDefaultCursor());
    175                 mousePosMove = null;
    176                 oldCursor = null;
    177         }
    178 
    179         /**
    180         * Zoom the map by 1/5th of current zoom per wheel-delta.
    181         * @param e The wheel event.
    182         */
    183         public void mouseWheelMoved(MouseWheelEvent e) {
    184                 int w = nc.getWidth();
    185                 int h = nc.getHeight();
    186 
    187                 double zoom = Math.max(0.1, 1 + e.getWheelRotation()/5.0);
    188                 double zoomfactor = (zoom-1)/2+1;
    189 
    190                 double newHalfWidth = w*zoomfactor - w/2;
    191                 double newHalfHeight = h*zoomfactor - h/2;
    192                 double centerx = e.getX() - (e.getX()-w/2)*newHalfWidth*2/w;
    193                 double centery = e.getY() - (e.getY()-h/2)*newHalfHeight*2/h;
    194                 EastNorth newCenter = nc.getEastNorth((int)centerx, (int)centery);
    195 
    196                 nc.zoomTo(newCenter, nc.getScale()*zoom);
    197         }
    198 
    199         /**
    200         * Does nothing. Only to satisfy MouseMotionListener
    201         */
    202         public void mouseMoved(MouseEvent e) {}
     35        public void actionPerformed(ActionEvent e) {
     36            if (action.equals(".") || action.equals(",")) {
     37                Point mouse = nc.getMousePosition();
     38                if (mouse == null)
     39                    mouse = new Point((int)nc.getBounds().getCenterX(), (int)nc.getBounds().getCenterY());
     40                MouseWheelEvent we = new MouseWheelEvent(nc, e.getID(), e.getWhen(), e.getModifiers(), mouse.x, mouse.y, 0, false, MouseWheelEvent.WHEEL_UNIT_SCROLL, 1, action.equals(",") ? -1 : 1);
     41                mouseWheelMoved(we);
     42            } else {
     43                EastNorth center = nc.getCenter();
     44                EastNorth newcenter = nc.getEastNorth(nc.getWidth()/2+nc.getWidth()/5, nc.getHeight()/2+nc.getHeight()/5);
     45                if (action.equals("left"))
     46                    nc.zoomTo(new EastNorth(2*center.east()-newcenter.east(), center.north()), nc.getScale());
     47                else if (action.equals("right"))
     48                    nc.zoomTo(new EastNorth(newcenter.east(), center.north()), nc.getScale());
     49                else if (action.equals("up"))
     50                    nc.zoomTo(new EastNorth(center.east(), 2*center.north()-newcenter.north()), nc.getScale());
     51                else if (action.equals("down"))
     52                    nc.zoomTo(new EastNorth(center.east(), newcenter.north()), nc.getScale());
     53            }
     54        }
     55    }
     56
     57    /**
     58    * The point in the map that was the under the mouse point
     59    * when moving around started.
     60    */
     61    private EastNorth mousePosMove;
     62    /**
     63    * The map to move around.
     64    */
     65    private final NavigatableComponent nc;
     66    /**
     67    * The old cursor when we changed it to movement cursor.
     68    */
     69    private Cursor oldCursor;
     70
     71    private boolean movementInPlace = false;
     72
     73    /**
     74    * Create a new MapMover
     75    */
     76    public MapMover(NavigatableComponent navComp, JPanel contentPane) {
     77        this.nc = navComp;
     78        nc.addMouseListener(this);
     79        nc.addMouseMotionListener(this);
     80        nc.addMouseWheelListener(this);
     81
     82        if (contentPane != null) {
     83            contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
     84                Shortcut.registerShortcut("system:movefocusright", tr("Map: {0}", tr("Move right")), KeyEvent.VK_RIGHT, Shortcut.GROUP_HOTKEY).getKeyStroke(),
     85                "MapMover.Zoomer.right");
     86            contentPane.getActionMap().put("MapMover.Zoomer.right", new ZoomerAction("right"));
     87
     88            contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
     89                Shortcut.registerShortcut("system:movefocusleft", tr("Map: {0}", tr("Move left")), KeyEvent.VK_LEFT, Shortcut.GROUP_HOTKEY).getKeyStroke(),
     90                "MapMover.Zoomer.left");
     91            contentPane.getActionMap().put("MapMover.Zoomer.left", new ZoomerAction("left"));
     92
     93            contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
     94                Shortcut.registerShortcut("system:movefocusup", tr("Map: {0}", tr("Move up")), KeyEvent.VK_UP, Shortcut.GROUP_HOTKEY).getKeyStroke(),
     95                "MapMover.Zoomer.up");
     96            contentPane.getActionMap().put("MapMover.Zoomer.up", new ZoomerAction("up"));
     97
     98            contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
     99                Shortcut.registerShortcut("system:movefocusdown", tr("Map: {0}", tr("Move down")), KeyEvent.VK_DOWN, Shortcut.GROUP_HOTKEY).getKeyStroke(),
     100                "MapMover.Zoomer.down");
     101            contentPane.getActionMap().put("MapMover.Zoomer.down", new ZoomerAction("down"));
     102
     103            contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
     104                Shortcut.registerShortcut("view:zoominalternate", tr("Map: {0}", tr("Zoom in")), KeyEvent.VK_COMMA, Shortcut.GROUP_HOTKEY).getKeyStroke(),
     105                "MapMover.Zoomer.in");
     106            contentPane.getActionMap().put("MapMover.Zoomer.in", new ZoomerAction(","));
     107
     108            contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
     109                Shortcut.registerShortcut("view:zoomoutalternate", tr("Map: {0}", tr("Zoom out")), KeyEvent.VK_PERIOD, Shortcut.GROUP_HOTKEY).getKeyStroke(),
     110                "MapMover.Zoomer.out");
     111            contentPane.getActionMap().put("MapMover.Zoomer.out", new ZoomerAction("."));
     112        }
     113    }
     114
     115    /**
     116    * If the right (and only the right) mouse button is pressed, move the map
     117    */
     118    public void mouseDragged(MouseEvent e) {
     119        int offMask = MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON2_DOWN_MASK;
     120        if ((e.getModifiersEx() & (MouseEvent.BUTTON3_DOWN_MASK | offMask)) == MouseEvent.BUTTON3_DOWN_MASK) {
     121            if (mousePosMove == null)
     122                startMovement(e);
     123            EastNorth center = nc.getCenter();
     124            EastNorth mouseCenter = nc.getEastNorth(e.getX(), e.getY());
     125            EastNorth p = new EastNorth(
     126                    mousePosMove.east() + center.east() - mouseCenter.east(),
     127                    mousePosMove.north() + center.north() - mouseCenter.north());
     128            nc.zoomTo(p, nc.getScale());
     129        } else
     130            endMovement();
     131    }
     132
     133    /**
     134    * Start the movement, if it was the 3rd button (right button).
     135    */
     136    @Override public void mousePressed(MouseEvent e) {
     137        int offMask = MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON2_DOWN_MASK;
     138        if (e.getButton() == MouseEvent.BUTTON3 && (e.getModifiersEx() & offMask) == 0)
     139            startMovement(e);
     140    }
     141
     142    /**
     143    * Change the cursor back to it's pre-move cursor.
     144    */
     145    @Override public void mouseReleased(MouseEvent e) {
     146        if (e.getButton() == MouseEvent.BUTTON3)
     147            endMovement();
     148    }
     149
     150    /**
     151    * Start movement by setting a new cursor and remember the current mouse
     152    * position.
     153    * @param e The mouse event that leat to the movement from.
     154    */
     155    private void startMovement(MouseEvent e) {
     156        if (movementInPlace)
     157            return;
     158        movementInPlace = true;
     159        mousePosMove = nc.getEastNorth(e.getX(), e.getY());
     160        oldCursor = nc.getCursor();
     161        nc.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
     162    }
     163
     164    /**
     165    * End the movement. Setting back the cursor and clear the movement variables
     166    */
     167    private void endMovement() {
     168        if (!movementInPlace)
     169            return;
     170        movementInPlace = false;
     171        if (oldCursor != null)
     172            nc.setCursor(oldCursor);
     173        else
     174            nc.setCursor(Cursor.getDefaultCursor());
     175        mousePosMove = null;
     176        oldCursor = null;
     177    }
     178
     179    /**
     180    * Zoom the map by 1/5th of current zoom per wheel-delta.
     181    * @param e The wheel event.
     182    */
     183    public void mouseWheelMoved(MouseWheelEvent e) {
     184        int w = nc.getWidth();
     185        int h = nc.getHeight();
     186
     187        double zoom = Math.max(0.1, 1 + e.getWheelRotation()/5.0);
     188        double zoomfactor = (zoom-1)/2+1;
     189
     190        double newHalfWidth = w*zoomfactor - w/2;
     191        double newHalfHeight = h*zoomfactor - h/2;
     192        double centerx = e.getX() - (e.getX()-w/2)*newHalfWidth*2/w;
     193        double centery = e.getY() - (e.getY()-h/2)*newHalfHeight*2/h;
     194        EastNorth newCenter = nc.getEastNorth((int)centerx, (int)centery);
     195
     196        nc.zoomTo(newCenter, nc.getScale()*zoom);
     197    }
     198
     199    /**
     200    * Does nothing. Only to satisfy MouseMotionListener
     201    */
     202    public void mouseMoved(MouseEvent e) {}
    203203}
  • trunk/src/org/openstreetmap/josm/gui/MapScaler.java

    r999 r1169  
    1818public class MapScaler extends JComponent implements Helpful {
    1919
    20         private final NavigatableComponent mv;
    21         public MapScaler(NavigatableComponent mv, Projection proj) {
    22                 this.mv = mv;
    23                 setSize(100,30);
    24                 setOpaque(false);
     20    private final NavigatableComponent mv;
     21    public MapScaler(NavigatableComponent mv, Projection proj) {
     22        this.mv = mv;
     23        setSize(100,30);
     24        setOpaque(false);
    2525    }
    2626
    27         @Override public void paint(Graphics g) {
    28                 LatLon ll1 = mv.getLatLon(0,0);
    29                 LatLon ll2 = mv.getLatLon(100,0);
    30                 double dist = ll1.greatCircleDistance(ll2);
    31                 String text = dist > 1000 ? (Math.round(dist/100)/10.0)+" km" : Math.round(dist*10)/10+" m";
    32                 Rectangle2D bound = g.getFontMetrics().getStringBounds(text, g);
    33                 g.setColor(Main.pref.getColor(marktr("scale"), Color.white));
    34                 g.drawLine(0, 5, 99, 5);
    35                 g.drawLine(0, 0, 0, 10);
    36                 g.drawLine(99, 0, 99, 10);
    37                 g.drawLine(49, 0, 49, 10);
    38                 g.drawLine(24, 3, 24, 7);
    39                 g.drawLine(74, 3, 74, 7);
    40                 g.drawString(text, (int)(50-bound.getWidth()/2), 23);
     27    @Override public void paint(Graphics g) {
     28        LatLon ll1 = mv.getLatLon(0,0);
     29        LatLon ll2 = mv.getLatLon(100,0);
     30        double dist = ll1.greatCircleDistance(ll2);
     31        String text = dist > 1000 ? (Math.round(dist/100)/10.0)+" km" : Math.round(dist*10)/10+" m";
     32        Rectangle2D bound = g.getFontMetrics().getStringBounds(text, g);
     33        g.setColor(Main.pref.getColor(marktr("scale"), Color.white));
     34        g.drawLine(0, 5, 99, 5);
     35        g.drawLine(0, 0, 0, 10);
     36        g.drawLine(99, 0, 99, 10);
     37        g.drawLine(49, 0, 49, 10);
     38        g.drawLine(24, 3, 24, 7);
     39        g.drawLine(74, 3, 74, 7);
     40        g.drawString(text, (int)(50-bound.getWidth()/2), 23);
    4141    }
    4242
    43         public String helpTopic() {
    44             return "MapView/Scaler";
     43    public String helpTopic() {
     44        return "MapView/Scaler";
    4545    }
    4646}
  • trunk/src/org/openstreetmap/josm/gui/MapSlider.java

    r627 r1169  
    1515
    1616class MapSlider extends JSlider implements PropertyChangeListener, ChangeListener, Helpful {
    17        
     17
    1818    private final MapView mv;
    19         boolean clicked = false;
    20        
    21         public MapSlider(MapView mv) {
    22                 super(0, 20);
    23                 setOpaque(false);
    24                 this.mv = mv;
    25                 addMouseListener(new MouseAdapter(){
    26                         @Override public void mousePressed(MouseEvent e) {
    27                                 clicked = true;
    28                         }
    29                         @Override public void mouseReleased(MouseEvent e) {
    30                                 clicked = false;
    31                         }
    32                 });
    33                 mv.addPropertyChangeListener("scale", this);
    34                 addChangeListener(this);
    35         }
    36        
    37         public void propertyChange(PropertyChangeEvent evt) {
    38                 if (!getModel().getValueIsAdjusting())
    39                         setValue(this.mv.zoom());
    40         }
    41        
    42         public void stateChanged(ChangeEvent e) {
    43                 if (!clicked)
    44                         return;
    45                 EastNorth pos = MapView.world;
    46                 for (int zoom = 0; zoom < getValue(); ++zoom)
    47                         pos = new EastNorth(pos.east()/2, pos.north()/2);
    48                 if (this.mv.getWidth() < this.mv.getHeight())
    49                         this.mv.zoomTo(this.mv.center, pos.east()*2/(this.mv.getWidth()-20));
    50                 else
    51                         this.mv.zoomTo(this.mv.center, pos.north()*2/(this.mv.getHeight()-20));
    52         }
     19    boolean clicked = false;
    5320
    54         public String helpTopic() {
    55             return "MapView/Slider";
     21    public MapSlider(MapView mv) {
     22        super(0, 20);
     23        setOpaque(false);
     24        this.mv = mv;
     25        addMouseListener(new MouseAdapter(){
     26            @Override public void mousePressed(MouseEvent e) {
     27                clicked = true;
     28            }
     29            @Override public void mouseReleased(MouseEvent e) {
     30                clicked = false;
     31            }
     32        });
     33        mv.addPropertyChangeListener("scale", this);
     34        addChangeListener(this);
     35    }
     36
     37    public void propertyChange(PropertyChangeEvent evt) {
     38        if (!getModel().getValueIsAdjusting())
     39            setValue(this.mv.zoom());
     40    }
     41
     42    public void stateChanged(ChangeEvent e) {
     43        if (!clicked)
     44            return;
     45        EastNorth pos = MapView.world;
     46        for (int zoom = 0; zoom < getValue(); ++zoom)
     47            pos = new EastNorth(pos.east()/2, pos.north()/2);
     48        if (this.mv.getWidth() < this.mv.getHeight())
     49            this.mv.zoomTo(this.mv.center, pos.east()*2/(this.mv.getWidth()-20));
     50        else
     51            this.mv.zoomTo(this.mv.center, pos.north()*2/(this.mv.getHeight()-20));
     52    }
     53
     54    public String helpTopic() {
     55        return "MapView/Slider";
    5656    }
    5757}
  • trunk/src/org/openstreetmap/josm/gui/MapStatus.java

    r1108 r1169  
    5757public class MapStatus extends JPanel implements Helpful {
    5858
    59         /**
    60         * The MapView this status belongs to.
    61         */
    62         final MapView mv;
    63        
    64         /**
    65         * A small user interface component that consists of an image label and
    66         * a fixed text content to the right of the image.
    67         */
    68         class ImageLabel extends JPanel {
    69                 private JLabel tf; 
    70                 private int chars;
    71                 public ImageLabel(String img, String tooltip, int chars) {
    72                         super();
    73                         setLayout(new GridBagLayout());
    74                         setBackground(Color.decode("#b8cfe5"));
    75                         add(new JLabel(ImageProvider.get("statusline/"+img+".png")), GBC.std().anchor(GBC.WEST).insets(0,1,1,0));
    76                         add(tf = new JLabel(), GBC.std().fill(GBC.BOTH).anchor(GBC.WEST).insets(2,1,1,0));
    77                         setToolTipText(tooltip);
    78                         this.chars = chars;
    79                 }
    80                 public void setText(String t) {
    81                         tf.setText(t);
    82                 }
    83                 @Override public Dimension getPreferredSize() {
    84                         return new Dimension(25 + chars*tf.getFontMetrics(tf.getFont()).charWidth('0'), super.getPreferredSize().height);
    85                 }
    86                 @Override public Dimension getMinimumSize() {
    87                         return new Dimension(25 + chars*tf.getFontMetrics(tf.getFont()).charWidth('0'), super.getMinimumSize().height); 
    88                 }
    89         }
    90 
    91         LatLon.CoordinateFormat mCord;
     59    /**
     60    * The MapView this status belongs to.
     61    */
     62    final MapView mv;
     63
     64    /**
     65    * A small user interface component that consists of an image label and
     66    * a fixed text content to the right of the image.
     67    */
     68    class ImageLabel extends JPanel {
     69        private JLabel tf;
     70        private int chars;
     71        public ImageLabel(String img, String tooltip, int chars) {
     72            super();
     73            setLayout(new GridBagLayout());
     74            setBackground(Color.decode("#b8cfe5"));
     75            add(new JLabel(ImageProvider.get("statusline/"+img+".png")), GBC.std().anchor(GBC.WEST).insets(0,1,1,0));
     76            add(tf = new JLabel(), GBC.std().fill(GBC.BOTH).anchor(GBC.WEST).insets(2,1,1,0));
     77            setToolTipText(tooltip);
     78            this.chars = chars;
     79        }
     80        public void setText(String t) {
     81            tf.setText(t);
     82        }
     83        @Override public Dimension getPreferredSize() {
     84            return new Dimension(25 + chars*tf.getFontMetrics(tf.getFont()).charWidth('0'), super.getPreferredSize().height);
     85        }
     86        @Override public Dimension getMinimumSize() {
     87            return new Dimension(25 + chars*tf.getFontMetrics(tf.getFont()).charWidth('0'), super.getMinimumSize().height);
     88        }
     89    }
     90
     91    LatLon.CoordinateFormat mCord;
    9292
    9393    ImageLabel lonText = new ImageLabel("lon", tr("The geographic longitude at the mouse pointer."), 11);
     
    9999    ImageLabel distText = new ImageLabel("dist", tr("The length of the new way segment being drawn."), 8);
    100100
    101         /**
    102         * The collector class that waits for notification and then update
    103         * the display objects.
    104         *
    105         * @author imi
    106         */
    107         private final class Collector implements Runnable {
    108                 /**
    109                 * The last object displayed in status line.
    110                 */
    111                 Collection<OsmPrimitive> osmStatus;
    112                 /**
    113                 * The old modifiers that was pressed the last time this collector ran.
    114                 */
    115                 private int oldModifiers;
    116                 /**
    117                 * The popup displayed to show additional information
    118                 */
    119                 private Popup popup;
    120 
    121                 private MapFrame parent;
    122 
    123                 public Collector(MapFrame parent) {
    124                         this.parent = parent;
    125                 }
    126 
    127                 /**
    128                 * Execution function for the Collector.
    129                 */
    130                 public void run() {
    131                         for (;;) {
    132                                 MouseState ms = new MouseState();
    133                                 synchronized (this) {
    134                                         try {wait();} catch (InterruptedException e) {}
    135                                         ms.modifiers = mouseState.modifiers;
    136                                         ms.mousePos = mouseState.mousePos;
    137                                 }
    138                                 if (parent != Main.map)
    139                                         return; // exit, if new parent.
    140                                 if ((ms.modifiers & MouseEvent.CTRL_DOWN_MASK) != 0 || ms.mousePos == null)
    141                                         continue; // freeze display when holding down ctrl
    142 
    143                                 if (mv.center == null)
    144                                         continue;
    145 
    146                                 // This try/catch is a hack to stop the flooding bug reports about this.
    147                                 // The exception needed to handle with in the first place, means that this
    148                                 // access to the data need to be restarted, if the main thread modifies
    149                                 // the data.
    150                                 try {
    151                                         OsmPrimitive osmNearest = null;
    152                                         // Set the text label in the bottom status bar
    153                                         osmNearest = mv.getNearest(ms.mousePos);
    154                                         if (osmNearest != null) {
    155                                                 NameVisitor visitor = new NameVisitor();
    156                                                 osmNearest.visit(visitor);
    157                                                 nameText.setText(visitor.name);
    158                                         } else
    159                                                 nameText.setText(tr("(no object)"));
    160 
    161                                         // Popup Information
    162                                         if ((ms.modifiers & MouseEvent.BUTTON2_DOWN_MASK) != 0 ) {
    163                                                 Collection<OsmPrimitive> osms = mv.getAllNearest(ms.mousePos);
    164 
    165                                                 if (osms == null)
    166                                                         continue;
    167                                                 if (osms != null && osms.equals(osmStatus) && ms.modifiers == oldModifiers)
    168                                                         continue;
    169 
    170                                                 if (popup != null) {
    171                                                         try {
    172                                     EventQueue.invokeAndWait(new Runnable() {
    173                                         public void run() {
    174                                                 popup.hide();
    175                                         }
    176                                     });
     101    /**
     102    * The collector class that waits for notification and then update
     103    * the display objects.
     104    *
     105    * @author imi
     106    */
     107    private final class Collector implements Runnable {
     108        /**
     109        * The last object displayed in status line.
     110        */
     111        Collection<OsmPrimitive> osmStatus;
     112        /**
     113        * The old modifiers that was pressed the last time this collector ran.
     114        */
     115        private int oldModifiers;
     116        /**
     117        * The popup displayed to show additional information
     118        */
     119        private Popup popup;
     120
     121        private MapFrame parent;
     122
     123        public Collector(MapFrame parent) {
     124            this.parent = parent;
     125        }
     126
     127        /**
     128        * Execution function for the Collector.
     129        */
     130        public void run() {
     131            for (;;) {
     132                MouseState ms = new MouseState();
     133                synchronized (this) {
     134                    try {wait();} catch (InterruptedException e) {}
     135                    ms.modifiers = mouseState.modifiers;
     136                    ms.mousePos = mouseState.mousePos;
     137                }
     138                if (parent != Main.map)
     139                    return; // exit, if new parent.
     140                if ((ms.modifiers & MouseEvent.CTRL_DOWN_MASK) != 0 || ms.mousePos == null)
     141                    continue; // freeze display when holding down ctrl
     142
     143                if (mv.center == null)
     144                    continue;
     145
     146                // This try/catch is a hack to stop the flooding bug reports about this.
     147                // The exception needed to handle with in the first place, means that this
     148                // access to the data need to be restarted, if the main thread modifies
     149                // the data.
     150                try {
     151                    OsmPrimitive osmNearest = null;
     152                    // Set the text label in the bottom status bar
     153                    osmNearest = mv.getNearest(ms.mousePos);
     154                    if (osmNearest != null) {
     155                        NameVisitor visitor = new NameVisitor();
     156                        osmNearest.visit(visitor);
     157                        nameText.setText(visitor.name);
     158                    } else
     159                        nameText.setText(tr("(no object)"));
     160
     161                    // Popup Information
     162                    if ((ms.modifiers & MouseEvent.BUTTON2_DOWN_MASK) != 0 ) {
     163                        Collection<OsmPrimitive> osms = mv.getAllNearest(ms.mousePos);
     164
     165                        if (osms == null)
     166                            continue;
     167                        if (osms != null && osms.equals(osmStatus) && ms.modifiers == oldModifiers)
     168                            continue;
     169
     170                        if (popup != null) {
     171                            try {
     172                                EventQueue.invokeAndWait(new Runnable() {
     173                                    public void run() {
     174                                        popup.hide();
     175                                    }
     176                                });
    177177                            } catch (InterruptedException e) {
    178178                            } catch (InvocationTargetException e) {
    179                                 throw new RuntimeException(e);
     179                                throw new RuntimeException(e);
    180180                            }
    181                                                 }
    182 
    183                                                 JPanel c = new JPanel(new GridBagLayout());
    184                                                 for (final OsmPrimitive osm : osms) {
    185                                                         NameVisitor visitor = new NameVisitor();
    186                                                         osm.visit(visitor);
    187                                                         final StringBuilder text = new StringBuilder();
    188                                                         if (osm.id == 0 || osm.modified)
    189                                                                 visitor.name = "<i><b>"+visitor.name+"*</b></i>";
    190                                                         text.append(visitor.name);
    191                                                         if (osm.id != 0)
    192                                                                 text.append("<br>id="+osm.id);
    193                                                         for (Entry<String, String> e : osm.entrySet())
    194                                                                 text.append("<br>"+e.getKey()+"="+e.getValue());
    195                                                         final JLabel l = new JLabel("<html>"+text.toString()+"</html>", visitor.icon, JLabel.HORIZONTAL);
    196                                                         l.setFont(l.getFont().deriveFont(Font.PLAIN));
    197                                                         l.setVerticalTextPosition(JLabel.TOP);
    198                                                         l.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
    199                                                         l.addMouseListener(new MouseAdapter(){
    200                                                                 @Override public void mouseEntered(MouseEvent e) {
    201                                                                         l.setText("<html><u color='blue'>"+text.toString()+"</u></html>");
    202                                                                 }
    203                                                                 @Override public void mouseExited(MouseEvent e) {
    204                                                                         l.setText("<html>"+text.toString()+"</html>");
    205                                                                 }
    206                                                                 @Override public void mouseClicked(MouseEvent e) {
    207                                                                         Main.ds.setSelected(osm);
    208                                                                         mv.repaint();
    209                                                                 }
    210                                                         });
    211                                                         c.add(l, GBC.eol());
    212                                                 }
    213 
    214                                                 Point p = mv.getLocationOnScreen();
    215                                                 popup = PopupFactory.getSharedInstance().getPopup(mv, c, p.x+ms.mousePos.x+16, p.y+ms.mousePos.y+16);
    216                                                 final Popup staticPopup = popup;
    217                                                 EventQueue.invokeLater(new Runnable(){
    218                                                         public void run() {
    219                                                                 staticPopup.show();
     181                        }
     182
     183                        JPanel c = new JPanel(new GridBagLayout());
     184                        for (final OsmPrimitive osm : osms) {
     185                            NameVisitor visitor = new NameVisitor();
     186                            osm.visit(visitor);
     187                            final StringBuilder text = new StringBuilder();
     188                            if (osm.id == 0 || osm.modified)
     189                                visitor.name = "<i><b>"+visitor.name+"*</b></i>";
     190                            text.append(visitor.name);
     191                            if (osm.id != 0)
     192                                text.append("<br>id="+osm.id);
     193                            for (Entry<String, String> e : osm.entrySet())
     194                                text.append("<br>"+e.getKey()+"="+e.getValue());
     195                            final JLabel l = new JLabel("<html>"+text.toString()+"</html>", visitor.icon, JLabel.HORIZONTAL);
     196                            l.setFont(l.getFont().deriveFont(Font.PLAIN));
     197                            l.setVerticalTextPosition(JLabel.TOP);
     198                            l.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
     199                            l.addMouseListener(new MouseAdapter(){
     200                                @Override public void mouseEntered(MouseEvent e) {
     201                                    l.setText("<html><u color='blue'>"+text.toString()+"</u></html>");
     202                                }
     203                                @Override public void mouseExited(MouseEvent e) {
     204                                    l.setText("<html>"+text.toString()+"</html>");
     205                                }
     206                                @Override public void mouseClicked(MouseEvent e) {
     207                                    Main.ds.setSelected(osm);
     208                                    mv.repaint();
     209                                }
     210                            });
     211                            c.add(l, GBC.eol());
     212                        }
     213
     214                        Point p = mv.getLocationOnScreen();
     215                        popup = PopupFactory.getSharedInstance().getPopup(mv, c, p.x+ms.mousePos.x+16, p.y+ms.mousePos.y+16);
     216                        final Popup staticPopup = popup;
     217                        EventQueue.invokeLater(new Runnable(){
     218                            public void run() {
     219                                staticPopup.show();
    220220                            }
    221                                                 });
    222                                         } else if (popup != null) {
    223                                                 final Popup staticPopup = popup;
    224                                                 popup = null;
    225                                                 EventQueue.invokeLater(new Runnable(){
    226                                                         public void run() {
    227                                                                 staticPopup.hide();
     221                        });
     222                    } else if (popup != null) {
     223                        final Popup staticPopup = popup;
     224                        popup = null;
     225                        EventQueue.invokeLater(new Runnable(){
     226                            public void run() {
     227                                staticPopup.hide();
    228228                            }
    229                                                 });
    230                                         }
    231                                 } catch (ConcurrentModificationException x) {
    232                                 } catch (NullPointerException x) {
    233                                 }
    234                         }
    235                 }
    236         }
    237 
    238         /**
    239         * Everything, the collector is interested of. Access must be synchronized.
    240         * @author imi
    241         */
    242         class MouseState {
    243                 Point mousePos;
    244                 int modifiers;
    245         }
    246         /**
    247         * The last sent mouse movement event.
    248         */
    249         MouseState mouseState = new MouseState();
    250 
    251         /**
    252         * Construct a new MapStatus and attach it to the map view.
    253         * @param mapFrame The MapFrame the status line is part of.
    254         */
    255         public MapStatus(final MapFrame mapFrame) {
    256                 this.mv = mapFrame.mapView;
    257                
     229                        });
     230                    }
     231                } catch (ConcurrentModificationException x) {
     232                } catch (NullPointerException x) {
     233                }
     234            }
     235        }
     236    }
     237
     238    /**
     239    * Everything, the collector is interested of. Access must be synchronized.
     240    * @author imi
     241    */
     242    class MouseState {
     243        Point mousePos;
     244        int modifiers;
     245    }
     246    /**
     247    * The last sent mouse movement event.
     248    */
     249    MouseState mouseState = new MouseState();
     250
     251    /**
     252    * Construct a new MapStatus and attach it to the map view.
     253    * @param mapFrame The MapFrame the status line is part of.
     254    */
     255    public MapStatus(final MapFrame mapFrame) {
     256        this.mv = mapFrame.mapView;
     257
    258258        try {
    259259            mCord = LatLon.CoordinateFormat.valueOf(Main.pref.get("coordinates"));
     
    261261            mCord =LatLon.CoordinateFormat.DECIMAL_DEGREES;
    262262        }
    263                 // Listen for mouse movements and set the position text field
    264                 mv.addMouseMotionListener(new MouseMotionListener(){
    265                         public void mouseDragged(MouseEvent e) {
    266                                 mouseMoved(e);
    267                         }
    268                         public void mouseMoved(MouseEvent e) {
    269                                 if (mv.center == null)
    270                                         return;
    271                                 // Do not update the view if ctrl is pressed.
    272                                 if ((e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) == 0) {
    273                                         LatLon p = mv.getLatLon(e.getX(),e.getY());
    274                                         latText.setText(p.latToString(mCord));
    275                                         lonText.setText(p.lonToString(mCord));
    276                                 }
    277                         }
    278                 });
    279 
    280                 setLayout(new GridBagLayout());
    281                 setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
     263        // Listen for mouse movements and set the position text field
     264        mv.addMouseMotionListener(new MouseMotionListener(){
     265            public void mouseDragged(MouseEvent e) {
     266                mouseMoved(e);
     267            }
     268            public void mouseMoved(MouseEvent e) {
     269                if (mv.center == null)
     270                    return;
     271                // Do not update the view if ctrl is pressed.
     272                if ((e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) == 0) {
     273                    LatLon p = mv.getLatLon(e.getX(),e.getY());
     274                    latText.setText(p.latToString(mCord));
     275                    lonText.setText(p.lonToString(mCord));
     276                }
     277            }
     278        });
     279
     280        setLayout(new GridBagLayout());
     281        setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    282282
    283283        add(latText, GBC.std());
     
    287287        add(distText, GBC.std().insets(3,0,0,0));
    288288
    289                 helpText.setEditable(false);
    290                 add(nameText, GBC.std().insets(3,0,0,0));
    291                 add(helpText, GBC.eol().insets(3,0,0,0).fill(GBC.HORIZONTAL));
    292                
    293                 // The background thread
    294                 final Collector collector = new Collector(mapFrame);
    295                 new Thread(collector).start();
    296 
    297                 // Listen to keyboard/mouse events for pressing/releasing alt key and
    298                 // inform the collector.
    299                 try {
    300                         Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener(){
    301                                 public void eventDispatched(AWTEvent event) {
    302                                         synchronized (collector) {
    303                                                 mouseState.modifiers = ((InputEvent)event).getModifiersEx();
    304                                                 if (event instanceof MouseEvent)
    305                                                         mouseState.mousePos = ((MouseEvent)event).getPoint();
    306                                                 collector.notify();
    307                                         }
    308                                 }
    309                         }, AWTEvent.KEY_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
    310                 } catch (SecurityException ex) {
    311                         mapFrame.mapView.addMouseMotionListener(new MouseMotionListener() {
    312                                 public void mouseMoved(MouseEvent e) {
    313                                         synchronized (collector) {
    314                                                 mouseState.modifiers = e.getModifiersEx();
    315                                                 mouseState.mousePos = e.getPoint();
    316                                                 collector.notify();
    317                                         }
    318                                 }
    319 
    320                                 public void mouseDragged(MouseEvent e) {
    321                                         mouseMoved(e);
    322                                 }
    323                         });
    324 
    325                         mapFrame.mapView.addKeyListener(new KeyAdapter() {
    326                                 @Override public void keyPressed(KeyEvent e) {
    327                                         synchronized (collector) {
    328                                                 mouseState.modifiers = e.getModifiersEx();
    329                                                 collector.notify();
    330                                         }
    331                                 }
    332 
    333                                 @Override public void keyReleased(KeyEvent e) {
    334                                         keyPressed(e);
    335                                 }
    336                         });
    337                 }
    338         }
    339 
    340         public String helpTopic() {
    341                 return "Statusline";
    342         }
    343        
    344         public void setHelpText(String t) {
    345                 helpText.setText(t);
    346                 helpText.setToolTipText(t);
    347         }
    348         public void setAngle(double a) {
    349                 angleText.setText(a < 0 ? "--" : Math.round(a*10)/10.0 + " °");
    350         }
    351         public void setHeading(double h) {
    352                 headingText.setText(h < 0 ? "--" : Math.round(h*10)/10.0 + " °");
    353         }
    354         public void setDist(double dist) {
    355                 String text = dist > 1000 ? (Math.round(dist/100)/10.0)+" km" : Math.round(dist*10)/10.0 +" m";
    356                 distText.setText(dist < 0 ? "--" : text);
    357         }
    358        
     289        helpText.setEditable(false);
     290        add(nameText, GBC.std().insets(3,0,0,0));
     291        add(helpText, GBC.eol().insets(3,0,0,0).fill(GBC.HORIZONTAL));
     292
     293        // The background thread
     294        final Collector collector = new Collector(mapFrame);
     295        new Thread(collector).start();
     296
     297        // Listen to keyboard/mouse events for pressing/releasing alt key and
     298        // inform the collector.
     299        try {
     300            Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener(){
     301                public void eventDispatched(AWTEvent event) {
     302                    synchronized (collector) {
     303                        mouseState.modifiers = ((InputEvent)event).getModifiersEx();
     304                        if (event instanceof MouseEvent)
     305                            mouseState.mousePos = ((MouseEvent)event).getPoint();
     306                        collector.notify();
     307                    }
     308                }
     309            }, AWTEvent.KEY_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
     310        } catch (SecurityException ex) {
     311            mapFrame.mapView.addMouseMotionListener(new MouseMotionListener() {
     312                public void mouseMoved(MouseEvent e) {
     313                    synchronized (collector) {
     314                        mouseState.modifiers = e.getModifiersEx();
     315                        mouseState.mousePos = e.getPoint();
     316                        collector.notify();
     317                    }
     318                }
     319
     320                public void mouseDragged(MouseEvent e) {
     321                    mouseMoved(e);
     322                }
     323            });
     324
     325            mapFrame.mapView.addKeyListener(new KeyAdapter() {
     326                @Override public void keyPressed(KeyEvent e) {
     327                    synchronized (collector) {
     328                        mouseState.modifiers = e.getModifiersEx();
     329                        collector.notify();
     330                    }
     331                }
     332
     333                @Override public void keyReleased(KeyEvent e) {
     334                    keyPressed(e);
     335                }
     336            });
     337        }
     338    }
     339
     340    public String helpTopic() {
     341        return "Statusline";
     342    }
     343
     344    public void setHelpText(String t) {
     345        helpText.setText(t);
     346        helpText.setToolTipText(t);
     347    }
     348    public void setAngle(double a) {
     349        angleText.setText(a < 0 ? "--" : Math.round(a*10)/10.0 + " °");
     350    }
     351    public void setHeading(double h) {
     352        headingText.setText(h < 0 ? "--" : Math.round(h*10)/10.0 + " °");
     353    }
     354    public void setDist(double dist) {
     355        String text = dist > 1000 ? (Math.round(dist/100)/10.0)+" km" : Math.round(dist*10)/10.0 +" m";
     356        distText.setText(dist < 0 ? "--" : text);
     357    }
     358
    359359}
  • trunk/src/org/openstreetmap/josm/gui/MapView.java

    r1084 r1169  
    5656public class MapView extends NavigatableComponent {
    5757
    58         /**
    59         * Interface to notify listeners of the change of the active layer.
    60         * @author imi
    61         * @deprecated Use Layer.LayerChangeListener instead
    62         */
    63         @Deprecated public interface LayerChangeListener {
    64                 void activeLayerChange(Layer oldLayer, Layer newLayer);
    65                 void layerAdded(Layer newLayer);
    66                 void layerRemoved(Layer oldLayer);
    67         }
    68 
    69         /**
    70         * A list of all layers currently loaded.
    71         */
    72         private ArrayList<Layer> layers = new ArrayList<Layer>();
    73         /**
    74         * The play head marker: there is only one of these so it isn't in any specific layer
    75         */
    76         public PlayHeadMarker playHeadMarker = null;
    77         /**
    78         * Direct link to the edit layer (if any) in the layers list.
    79         */
    80         public OsmDataLayer editLayer;
    81         /**
    82         * The layer from the layers list that is currently active.
    83         */
    84         private Layer activeLayer;
    85 
    86         /**
    87         * The last event performed by mouse.
    88         */
    89         public MouseEvent lastMEvent;
    90 
    91         private LinkedList<MapViewPaintable> temporaryLayers = new LinkedList<MapViewPaintable>();
    92 
    93         private BufferedImage offscreenBuffer;
    94 
    95         /**
    96         * The listener of the active layer changes.
    97         * @deprecated Use Layer.listener instead.
    98         */
    99         @Deprecated private Collection<LayerChangeListener> listeners = new LinkedList<LayerChangeListener>();
    100 
    101         public MapView() {
    102                 addComponentListener(new ComponentAdapter(){
    103                         @Override public void componentResized(ComponentEvent e) {
    104                                 removeComponentListener(this);
    105 
    106                                 if (!zoomToEditLayerBoundingBox())
    107                                         new AutoScaleAction("data").actionPerformed(null);
    108 
    109                                 new MapMover(MapView.this, Main.contentPane);
    110                                 JosmAction mv;
    111                                 mv = new MoveAction(MoveAction.Direction.UP);
    112                                 if (mv.getShortcut() != null) {
    113                                         Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(mv.getShortcut().getKeyStroke(), "UP");
    114                                         Main.contentPane.getActionMap().put("UP", mv);
    115                                 }
    116                                 mv = new MoveAction(MoveAction.Direction.DOWN);
    117                                 if (mv.getShortcut() != null) {
    118                                         Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(mv.getShortcut().getKeyStroke(), "DOWN");
    119                                         Main.contentPane.getActionMap().put("DOWN", mv);
    120                                 }
    121                                 mv = new MoveAction(MoveAction.Direction.LEFT);
    122                                 if (mv.getShortcut() != null) {
    123                                         Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(mv.getShortcut().getKeyStroke(), "LEFT");
    124                                         Main.contentPane.getActionMap().put("LEFT", mv);
    125                                 }
    126                                 mv = new MoveAction(MoveAction.Direction.RIGHT);
    127                                 if (mv.getShortcut() != null) {
    128                                         Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(mv.getShortcut().getKeyStroke(), "RIGHT");
    129                                         Main.contentPane.getActionMap().put("RIGHT", mv);
    130                                 }
    131 
    132                                 MapSlider zoomSlider = new MapSlider(MapView.this);
    133                                 add(zoomSlider);
    134                                 zoomSlider.setBounds(3, 0, 114, 30);
    135 
    136                                 MapScaler scaler = new MapScaler(MapView.this, Main.proj);
    137                                 add(scaler);
    138                                 scaler.setLocation(10,30);
    139                         }
    140                 });
    141 
    142                 // listend to selection changes to redraw the map
    143                 DataSet.selListeners.add(new SelectionChangedListener(){
    144                         public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
    145                                 repaint();
    146                         }
    147                 });
    148 
    149                 //store the last mouse action
    150                 this.addMouseMotionListener(new MouseMotionListener() {
    151                         public void mouseDragged(MouseEvent e) {
    152                                 mouseMoved(e);
    153                         }
    154                         public void mouseMoved(MouseEvent e) {
    155                                 lastMEvent = e;
    156                         }
    157                 });
    158         }
    159 
    160         /**
    161         * Add a layer to the current MapView. The layer will be added at topmost
    162         * position.
    163         */
    164         public void addLayer(Layer layer) {
    165                 if (layer instanceof OsmDataLayer) {
    166                         editLayer = (OsmDataLayer)layer;
    167                         Main.ds = editLayer.data;
    168                         editLayer.listenerModified.add(new ModifiedChangedListener(){
    169                                 public void modifiedChanged(boolean value, OsmDataLayer source) {
    170                                         JOptionPane.getFrameForComponent(Main.parent).setTitle((value?"*":"")+tr("Java OpenStreetMap - Editor"));
    171                                 }
    172                         });
    173                 }
    174                 if (layer instanceof MarkerLayer && playHeadMarker == null)
    175                         playHeadMarker = PlayHeadMarker.create();
    176                 int pos = layers.size();
    177                 while(pos > 0 && layers.get(pos-1).background)
    178                         --pos;
    179                 layers.add(pos, layer);
    180 
    181                 // TODO: Deprecated
    182                 for (LayerChangeListener l : listeners)
    183                         l.layerAdded(layer);
    184                 for (Layer.LayerChangeListener l : Layer.listeners)
    185                         l.layerAdded(layer);
    186                 if (layer instanceof OsmDataLayer || activeLayer == null) {
    187                         // autoselect the new layer
    188                         Layer old = activeLayer;
    189                         setActiveLayer(layer);
    190                         for (Layer.LayerChangeListener l : Layer.listeners)
    191                                 l.activeLayerChange(old, layer);
    192                 }
    193                 repaint();
    194         }
    195 
    196         @Override
    197         protected DataSet getData()
    198         {
    199                 if(activeLayer != null && activeLayer instanceof OsmDataLayer)
    200                         return ((OsmDataLayer)activeLayer).data;
    201                 return new DataSet();
    202         }
    203 
    204         public Boolean isDrawableLayer()
    205         {
    206                 return activeLayer != null && activeLayer instanceof OsmDataLayer;
    207         }
    208 
    209         /**
    210         * Remove the layer from the mapview. If the layer was in the list before,
    211         * an LayerChange event is fired.
    212         */
    213         public void removeLayer(Layer layer) {
    214                 if (layers.remove(layer)) {
    215                         // TODO: Deprecated
    216                         for (LayerChangeListener l : listeners)
    217                                 l.layerRemoved(layer);
    218                         for (Layer.LayerChangeListener l : Layer.listeners)
    219                                 l.layerRemoved(layer);
    220                 }
    221                 if (layer == editLayer) {
    222                         editLayer = null;
    223                         Main.ds.setSelected();
    224                 }
    225                 layer.destroy();
    226         }
    227 
    228         private Boolean virtualnodes = false;
    229         public void enableVirtualNodes(Boolean state)
    230         {
    231                 if(virtualnodes != state)
    232                 {
    233                         virtualnodes = state;
    234                         repaint();
    235                 }
    236         }
    237         public Boolean useVirtualNodes()
    238         {
    239                 return virtualnodes;
    240         }
    241 
    242         /**
    243         * Moves the layer to the given new position. No event is fired.
    244         * @param layer         The layer to move
    245         * @param pos           The new position of the layer
    246         */
    247         public void moveLayer(Layer layer, int pos) {
    248                 int curLayerPos = layers.indexOf(layer);
    249                 if (curLayerPos == -1)
    250                         throw new IllegalArgumentException(tr("layer not in list."));
    251                 if (pos == curLayerPos)
    252                         return; // already in place.
    253                 layers.remove(curLayerPos);
    254                 if (pos >= layers.size())
    255                         layers.add(layer);
    256                 else
    257                         layers.add(pos, layer);
    258         }
    259 
    260         /**
    261         * Draw the component.
    262         */
    263         @Override public void paint(Graphics g) {
    264                 if (center == null)
    265                         return; // no data loaded yet.
    266 
    267                 // re-create offscreen-buffer if we've been resized, otherwise
    268                 // just re-use it.
    269                 if (null == offscreenBuffer || offscreenBuffer.getWidth() != getWidth()
    270                         || offscreenBuffer.getHeight() != getHeight())
    271                         offscreenBuffer = new BufferedImage(getWidth(), getHeight(),
    272                                 BufferedImage.TYPE_INT_ARGB);
    273 
    274                 Graphics2D tempG = offscreenBuffer.createGraphics();
    275                 tempG.setColor(Main.pref.getColor("background", Color.BLACK));
    276                 tempG.fillRect(0, 0, getWidth(), getHeight());
    277 
    278                 for (int i = layers.size()-1; i >= 0; --i) {
    279                         Layer l = layers.get(i);
    280                         if (l.visible/* && l != getActiveLayer()*/)
    281                                 l.paint(tempG, this);
    282                 }
    283 
    284                 /*if (getActiveLayer() != null && getActiveLayer().visible)
    285                         getActiveLayer().paint(tempG, this);*/
    286 
    287                 for (MapViewPaintable mvp : temporaryLayers) {
    288                         mvp.paint(tempG, this);
    289                 }
    290 
    291                 // draw world borders
    292                 tempG.setColor(Color.WHITE);
    293                 Bounds b = new Bounds();
    294                 Point min = getPoint(getProjection().latlon2eastNorth(b.min));
    295                 Point max = getPoint(getProjection().latlon2eastNorth(b.max));
    296                 int x1 = Math.min(min.x, max.x);
    297                 int y1 = Math.min(min.y, max.y);
    298                 int x2 = Math.max(min.x, max.x);
    299                 int y2 = Math.max(min.y, max.y);
    300                 if (x1 > 0 || y1 > 0 || x2 < getWidth() || y2 < getHeight())
    301                         tempG.drawRect(x1, y1, x2-x1+1, y2-y1+1);
    302 
    303                 if (playHeadMarker != null)
    304                         playHeadMarker.paint(tempG, this);
    305 
    306                 g.drawImage(offscreenBuffer, 0, 0, null);
    307                 super.paint(g);
    308         }
    309 
    310         /**
    311         * Set the new dimension to the projection class. Also adjust the components
    312         * scale, if in autoScale mode.
    313         */
    314         public void recalculateCenterScale(BoundingXYVisitor box) {
    315                 // -20 to leave some border
    316                 int w = getWidth()-20;
    317                 if (w < 20)
    318                         w = 20;
    319                 int h = getHeight()-20;
    320                 if (h < 20)
    321                         h = 20;
    322 
    323                 EastNorth oldCenter = center;
    324                 double oldScale = this.scale;
    325 
    326                 if (box == null || box.min == null || box.max == null || box.min.equals(box.max)) {
    327                         // no bounds means whole world
    328                         center = getProjection().latlon2eastNorth(new LatLon(0,0));
    329                         EastNorth world = getProjection().latlon2eastNorth(new LatLon(Projection.MAX_LAT,Projection.MAX_LON));
    330                         double scaleX = world.east()*2/w;
    331                         double scaleY = world.north()*2/h;
    332                         scale = Math.max(scaleX, scaleY); // minimum scale to see all of the screen
    333                 } else {
    334                         center = new EastNorth(box.min.east()/2+box.max.east()/2, box.min.north()/2+box.max.north()/2);
    335                         double scaleX = (box.max.east()-box.min.east())/w;
    336                         double scaleY = (box.max.north()-box.min.north())/h;
    337                         scale = Math.max(scaleX, scaleY); // minimum scale to see all of the screen
    338                 }
    339 
    340                 if (!center.equals(oldCenter))
    341                         firePropertyChange("center", oldCenter, center);
    342                 if (oldScale != scale)
    343                         firePropertyChange("scale", oldScale, scale);
    344                 repaint();
    345         }
    346 
    347         /**
    348         * Add a listener for changes of active layer.
    349         * @param listener The listener that get added.
    350         * @deprecated Use Layer.listener.add instead.
    351         */
    352         @Deprecated public void addLayerChangeListener(LayerChangeListener listener) {
    353                 if (listener != null)
    354                         listeners.add(listener);
    355         }
    356 
    357         /**
    358         * Remove the listener.
    359         * @param listener The listener that get removed from the list.
    360         * @deprecated Use Layer.listener.remove instead
    361         */
    362         @Deprecated public void removeLayerChangeListener(LayerChangeListener listener) {
    363                 listeners.remove(listener);
    364         }
    365 
    366         /**
    367         * @return An unmodificable list of all layers
    368         */
    369         public Collection<Layer> getAllLayers() {
    370                 return Collections.unmodifiableCollection(layers);
    371         }
    372 
    373         /**
    374         * Set the active selection to the given value and raise an layerchange event.
    375         */
    376         public void setActiveLayer(Layer layer) {
    377                 if (!layers.contains(layer))
    378                         throw new IllegalArgumentException("Layer must be in layerlist");
    379                 if (layer instanceof OsmDataLayer) {
    380                         editLayer = (OsmDataLayer)layer;
    381                         Main.ds = editLayer.data;
    382                 }
    383                 else
    384                         Main.ds.setSelected();
    385                 DataSet.fireSelectionChanged(Main.ds.getSelected());
    386                 Layer old = activeLayer;
    387                 activeLayer = layer;
    388                 if (old != layer) {
    389                         // TODO: Deprecated
    390                         for (LayerChangeListener l : listeners)
    391                                 l.activeLayerChange(old, layer);
    392                         for (Layer.LayerChangeListener l : Layer.listeners)
    393                                 l.activeLayerChange(old, layer);
    394                 }
    395                 repaint();
    396         }
    397 
    398         /**
    399         * @return The current active layer
    400         */
    401         public Layer getActiveLayer() {
    402                 return activeLayer;
    403         }
    404 
    405         /**
    406         * In addition to the base class funcitonality, this keep trak of the autoscale
    407         * feature.
    408         */
    409         @Override public void zoomTo(EastNorth newCenter, double scale) {
    410                 EastNorth oldCenter = center;
    411                 double oldScale = this.scale;
    412                 super.zoomTo(newCenter, scale);
    413                 if ((oldCenter == null && center != null) || !oldCenter.equals(center))
    414                         firePropertyChange("center", oldCenter, center);
    415                 if (oldScale != scale)
    416                         firePropertyChange("scale", oldScale, scale);
    417         }
    418 
    419         /**
    420         * Tries to zoom to the download boundingbox[es] of the current edit layer
    421         * (aka {@link OsmDataLayer}). If the edit layer has multiple download bounding
    422         * boxes it zooms to a large virtual bounding box containing all smaller ones.
    423         * This implementation can be used for resolving ticket #1461.
    424         *
    425         * @return <code>true</code> if a zoom operation has been performed
    426         * @author Jan Peter Stotz
    427         */
    428         public boolean zoomToEditLayerBoundingBox() {
    429                 // workaround for #1461 (zoom to download bounding box instead of all data)
    430                 // In case we already have an existing data layer ...
    431                 Collection<DataSource> dataSources = Main.main.editLayer().data.dataSources;
    432                 // ... with bounding box[es] of data loaded from OSM or a file...
    433                 BoundingXYVisitor bbox = new BoundingXYVisitor();
    434                 for (DataSource ds : dataSources) {
    435                         if (ds.bounds != null) {
    436                                 bbox.visit(Main.proj.latlon2eastNorth(ds.bounds.max));
    437                                 bbox.visit(Main.proj.latlon2eastNorth(ds.bounds.min));
    438                         }
    439                         if (bbox.max != null && bbox.min != null && !bbox.max.equals(bbox.min)) {
    440                                 // ... we zoom to it's bounding box
    441                                 recalculateCenterScale(bbox);
    442                                 return true;
    443                         }
    444                 }
    445                 return false;
    446         }
    447 
    448         public boolean addTemporaryLayer(MapViewPaintable mvp) {
    449                 if (temporaryLayers.contains(mvp)) return false;
    450                 return temporaryLayers.add(mvp);
    451         }
    452 
    453         public boolean removeTemporaryLayer(MapViewPaintable mvp) {
    454                 return temporaryLayers.remove(mvp);
    455         }
     58    /**
     59    * Interface to notify listeners of the change of the active layer.
     60    * @author imi
     61    * @deprecated Use Layer.LayerChangeListener instead
     62    */
     63    @Deprecated public interface LayerChangeListener {
     64        void activeLayerChange(Layer oldLayer, Layer newLayer);
     65        void layerAdded(Layer newLayer);
     66        void layerRemoved(Layer oldLayer);
     67    }
     68
     69    /**
     70    * A list of all layers currently loaded.
     71    */
     72    private ArrayList<Layer> layers = new ArrayList<Layer>();
     73    /**
     74    * The play head marker: there is only one of these so it isn't in any specific layer
     75    */
     76    public PlayHeadMarker playHeadMarker = null;
     77    /**
     78    * Direct link to the edit layer (if any) in the layers list.
     79    */
     80    public OsmDataLayer editLayer;
     81    /**
     82    * The layer from the layers list that is currently active.
     83    */
     84    private Layer activeLayer;
     85
     86    /**
     87    * The last event performed by mouse.
     88    */
     89    public MouseEvent lastMEvent;
     90
     91    private LinkedList<MapViewPaintable> temporaryLayers = new LinkedList<MapViewPaintable>();
     92
     93    private BufferedImage offscreenBuffer;
     94
     95    /**
     96    * The listener of the active layer changes.
     97    * @deprecated Use Layer.listener instead.
     98    */
     99    @Deprecated private Collection<LayerChangeListener> listeners = new LinkedList<LayerChangeListener>();
     100
     101    public MapView() {
     102        addComponentListener(new ComponentAdapter(){
     103            @Override public void componentResized(ComponentEvent e) {
     104                removeComponentListener(this);
     105
     106                if (!zoomToEditLayerBoundingBox())
     107                    new AutoScaleAction("data").actionPerformed(null);
     108
     109                new MapMover(MapView.this, Main.contentPane);
     110                JosmAction mv;
     111                mv = new MoveAction(MoveAction.Direction.UP);
     112                if (mv.getShortcut() != null) {
     113                    Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(mv.getShortcut().getKeyStroke(), "UP");
     114                    Main.contentPane.getActionMap().put("UP", mv);
     115                }
     116                mv = new MoveAction(MoveAction.Direction.DOWN);
     117                if (mv.getShortcut() != null) {
     118                    Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(mv.getShortcut().getKeyStroke(), "DOWN");
     119                    Main.contentPane.getActionMap().put("DOWN", mv);
     120                }
     121                mv = new MoveAction(MoveAction.Direction.LEFT);
     122                if (mv.getShortcut() != null) {
     123                    Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(mv.getShortcut().getKeyStroke(), "LEFT");
     124                    Main.contentPane.getActionMap().put("LEFT", mv);
     125                }
     126                mv = new MoveAction(MoveAction.Direction.RIGHT);
     127                if (mv.getShortcut() != null) {
     128                    Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(mv.getShortcut().getKeyStroke(), "RIGHT");
     129                    Main.contentPane.getActionMap().put("RIGHT", mv);
     130                }
     131
     132                MapSlider zoomSlider = new MapSlider(MapView.this);
     133                add(zoomSlider);
     134                zoomSlider.setBounds(3, 0, 114, 30);
     135
     136                MapScaler scaler = new MapScaler(MapView.this, Main.proj);
     137                add(scaler);
     138                scaler.setLocation(10,30);
     139            }
     140        });
     141
     142        // listend to selection changes to redraw the map
     143        DataSet.selListeners.add(new SelectionChangedListener(){
     144            public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
     145                repaint();
     146            }
     147        });
     148
     149        //store the last mouse action
     150        this.addMouseMotionListener(new MouseMotionListener() {
     151            public void mouseDragged(MouseEvent e) {
     152                mouseMoved(e);
     153            }
     154            public void mouseMoved(MouseEvent e) {
     155                lastMEvent = e;
     156            }
     157        });
     158    }
     159
     160    /**
     161    * Add a layer to the current MapView. The layer will be added at topmost
     162    * position.
     163    */
     164    public void addLayer(Layer layer) {
     165        if (layer instanceof OsmDataLayer) {
     166            editLayer = (OsmDataLayer)layer;
     167            Main.ds = editLayer.data;
     168            editLayer.listenerModified.add(new ModifiedChangedListener(){
     169                public void modifiedChanged(boolean value, OsmDataLayer source) {
     170                    JOptionPane.getFrameForComponent(Main.parent).setTitle((value?"*":"")+tr("Java OpenStreetMap - Editor"));
     171                }
     172            });
     173        }
     174        if (layer instanceof MarkerLayer && playHeadMarker == null)
     175            playHeadMarker = PlayHeadMarker.create();
     176        int pos = layers.size();
     177        while(pos > 0 && layers.get(pos-1).background)
     178            --pos;
     179        layers.add(pos, layer);
     180
     181        // TODO: Deprecated
     182        for (LayerChangeListener l : listeners)
     183            l.layerAdded(layer);
     184        for (Layer.LayerChangeListener l : Layer.listeners)
     185            l.layerAdded(layer);
     186        if (layer instanceof OsmDataLayer || activeLayer == null) {
     187            // autoselect the new layer
     188            Layer old = activeLayer;
     189            setActiveLayer(layer);
     190            for (Layer.LayerChangeListener l : Layer.listeners)
     191                l.activeLayerChange(old, layer);
     192        }
     193        repaint();
     194    }
     195
     196    @Override
     197    protected DataSet getData()
     198    {
     199        if(activeLayer != null && activeLayer instanceof OsmDataLayer)
     200            return ((OsmDataLayer)activeLayer).data;
     201        return new DataSet();
     202    }
     203
     204    public Boolean isDrawableLayer()
     205    {
     206        return activeLayer != null && activeLayer instanceof OsmDataLayer;
     207    }
     208
     209    /**
     210    * Remove the layer from the mapview. If the layer was in the list before,
     211    * an LayerChange event is fired.
     212    */
     213    public void removeLayer(Layer layer) {
     214        if (layers.remove(layer)) {
     215            // TODO: Deprecated
     216            for (LayerChangeListener l : listeners)
     217                l.layerRemoved(layer);
     218            for (Layer.LayerChangeListener l : Layer.listeners)
     219                l.layerRemoved(layer);
     220        }
     221        if (layer == editLayer) {
     222            editLayer = null;
     223            Main.ds.setSelected();
     224        }
     225        layer.destroy();
     226    }
     227
     228    private Boolean virtualnodes = false;
     229    public void enableVirtualNodes(Boolean state)
     230    {
     231        if(virtualnodes != state)
     232        {
     233            virtualnodes = state;
     234            repaint();
     235        }
     236    }
     237    public Boolean useVirtualNodes()
     238    {
     239        return virtualnodes;
     240    }
     241
     242    /**
     243    * Moves the layer to the given new position. No event is fired.
     244    * @param layer     The layer to move
     245    * @param pos       The new position of the layer
     246    */
     247    public void moveLayer(Layer layer, int pos) {
     248        int curLayerPos = layers.indexOf(layer);
     249        if (curLayerPos == -1)
     250            throw new IllegalArgumentException(tr("layer not in list."));
     251        if (pos == curLayerPos)
     252            return; // already in place.
     253        layers.remove(curLayerPos);
     254        if (pos >= layers.size())
     255            layers.add(layer);
     256        else
     257            layers.add(pos, layer);
     258    }
     259
     260    /**
     261    * Draw the component.
     262    */
     263    @Override public void paint(Graphics g) {
     264        if (center == null)
     265            return; // no data loaded yet.
     266
     267        // re-create offscreen-buffer if we've been resized, otherwise
     268        // just re-use it.
     269        if (null == offscreenBuffer || offscreenBuffer.getWidth() != getWidth()
     270                || offscreenBuffer.getHeight() != getHeight())
     271            offscreenBuffer = new BufferedImage(getWidth(), getHeight(),
     272                    BufferedImage.TYPE_INT_ARGB);
     273
     274        Graphics2D tempG = offscreenBuffer.createGraphics();
     275        tempG.setColor(Main.pref.getColor("background", Color.BLACK));
     276        tempG.fillRect(0, 0, getWidth(), getHeight());
     277
     278        for (int i = layers.size()-1; i >= 0; --i) {
     279            Layer l = layers.get(i);
     280            if (l.visible/* && l != getActiveLayer()*/)
     281                l.paint(tempG, this);
     282        }
     283
     284        /*if (getActiveLayer() != null && getActiveLayer().visible)
     285            getActiveLayer().paint(tempG, this);*/
     286
     287        for (MapViewPaintable mvp : temporaryLayers) {
     288            mvp.paint(tempG, this);
     289        }
     290
     291        // draw world borders
     292        tempG.setColor(Color.WHITE);
     293        Bounds b = new Bounds();
     294        Point min = getPoint(getProjection().latlon2eastNorth(b.min));
     295        Point max = getPoint(getProjection().latlon2eastNorth(b.max));
     296        int x1 = Math.min(min.x, max.x);
     297        int y1 = Math.min(min.y, max.y);
     298        int x2 = Math.max(min.x, max.x);
     299        int y2 = Math.max(min.y, max.y);
     300        if (x1 > 0 || y1 > 0 || x2 < getWidth() || y2 < getHeight())
     301            tempG.drawRect(x1, y1, x2-x1+1, y2-y1+1);
     302
     303        if (playHeadMarker != null)
     304            playHeadMarker.paint(tempG, this);
     305
     306        g.drawImage(offscreenBuffer, 0, 0, null);
     307        super.paint(g);
     308    }
     309
     310    /**
     311    * Set the new dimension to the projection class. Also adjust the components
     312    * scale, if in autoScale mode.
     313    */
     314    public void recalculateCenterScale(BoundingXYVisitor box) {
     315        // -20 to leave some border
     316        int w = getWidth()-20;
     317        if (w < 20)
     318            w = 20;
     319        int h = getHeight()-20;
     320        if (h < 20)
     321            h = 20;
     322
     323        EastNorth oldCenter = center;
     324        double oldScale = this.scale;
     325
     326        if (box == null || box.min == null || box.max == null || box.min.equals(box.max)) {
     327            // no bounds means whole world
     328            center = getProjection().latlon2eastNorth(new LatLon(0,0));
     329            EastNorth world = getProjection().latlon2eastNorth(new LatLon(Projection.MAX_LAT,Projection.MAX_LON));
     330            double scaleX = world.east()*2/w;
     331            double scaleY = world.north()*2/h;
     332            scale = Math.max(scaleX, scaleY); // minimum scale to see all of the screen
     333        } else {
     334            center = new EastNorth(box.min.east()/2+box.max.east()/2, box.min.north()/2+box.max.north()/2);
     335            double scaleX = (box.max.east()-box.min.east())/w;
     336            double scaleY = (box.max.north()-box.min.north())/h;
     337            scale = Math.max(scaleX, scaleY); // minimum scale to see all of the screen
     338        }
     339
     340        if (!center.equals(oldCenter))
     341            firePropertyChange("center", oldCenter, center);
     342        if (oldScale != scale)
     343            firePropertyChange("scale", oldScale, scale);
     344        repaint();
     345    }
     346
     347    /**
     348    * Add a listener for changes of active layer.
     349    * @param listener The listener that get added.
     350    * @deprecated Use Layer.listener.add instead.
     351    */
     352    @Deprecated public void addLayerChangeListener(LayerChangeListener listener) {
     353        if (listener != null)
     354            listeners.add(listener);
     355    }
     356
     357    /**
     358    * Remove the listener.
     359    * @param listener The listener that get removed from the list.
     360    * @deprecated Use Layer.listener.remove instead
     361    */
     362    @Deprecated public void removeLayerChangeListener(LayerChangeListener listener) {
     363        listeners.remove(listener);
     364    }
     365
     366    /**
     367    * @return An unmodificable list of all layers
     368    */
     369    public Collection<Layer> getAllLayers() {
     370        return Collections.unmodifiableCollection(layers);
     371    }
     372
     373    /**
     374    * Set the active selection to the given value and raise an layerchange event.
     375    */
     376    public void setActiveLayer(Layer layer) {
     377        if (!layers.contains(layer))
     378            throw new IllegalArgumentException("Layer must be in layerlist");
     379        if (layer instanceof OsmDataLayer) {
     380            editLayer = (OsmDataLayer)layer;
     381            Main.ds = editLayer.data;
     382        }
     383        else
     384            Main.ds.setSelected();
     385        DataSet.fireSelectionChanged(Main.ds.getSelected());
     386        Layer old = activeLayer;
     387        activeLayer = layer;
     388        if (old != layer) {
     389            // TODO: Deprecated
     390            for (LayerChangeListener l : listeners)
     391                l.activeLayerChange(old, layer);
     392            for (Layer.LayerChangeListener l : Layer.listeners)
     393                l.activeLayerChange(old, layer);
     394        }
     395        repaint();
     396    }
     397
     398    /**
     399    * @return The current active layer
     400    */
     401    public Layer getActiveLayer() {
     402        return activeLayer;
     403    }
     404
     405    /**
     406    * In addition to the base class funcitonality, this keep trak of the autoscale
     407    * feature.
     408    */
     409    @Override public void zoomTo(EastNorth newCenter, double scale) {
     410        EastNorth oldCenter = center;
     411        double oldScale = this.scale;
     412        super.zoomTo(newCenter, scale);
     413        if ((oldCenter == null && center != null) || !oldCenter.equals(center))
     414            firePropertyChange("center", oldCenter, center);
     415        if (oldScale != scale)
     416            firePropertyChange("scale", oldScale, scale);
     417    }
     418
     419    /**
     420    * Tries to zoom to the download boundingbox[es] of the current edit layer
     421    * (aka {@link OsmDataLayer}). If the edit layer has multiple download bounding
     422    * boxes it zooms to a large virtual bounding box containing all smaller ones.
     423    * This implementation can be used for resolving ticket #1461.
     424    *
     425    * @return <code>true</code> if a zoom operation has been performed
     426    * @author Jan Peter Stotz
     427    */
     428    public boolean zoomToEditLayerBoundingBox() {
     429        // workaround for #1461 (zoom to download bounding box instead of all data)
     430        // In case we already have an existing data layer ...
     431        Collection<DataSource> dataSources = Main.main.editLayer().data.dataSources;
     432        // ... with bounding box[es] of data loaded from OSM or a file...
     433        BoundingXYVisitor bbox = new BoundingXYVisitor();
     434        for (DataSource ds : dataSources) {
     435            if (ds.bounds != null) {
     436                bbox.visit(Main.proj.latlon2eastNorth(ds.bounds.max));
     437                bbox.visit(Main.proj.latlon2eastNorth(ds.bounds.min));
     438            }
     439            if (bbox.max != null && bbox.min != null && !bbox.max.equals(bbox.min)) {
     440                // ... we zoom to it's bounding box
     441                recalculateCenterScale(bbox);
     442                return true;
     443            }
     444        }
     445        return false;
     446    }
     447
     448    public boolean addTemporaryLayer(MapViewPaintable mvp) {
     449        if (temporaryLayers.contains(mvp)) return false;
     450        return temporaryLayers.add(mvp);
     451    }
     452
     453    public boolean removeTemporaryLayer(MapViewPaintable mvp) {
     454        return temporaryLayers.remove(mvp);
     455    }
    456456}
  • trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java

    r860 r1169  
    3333public class NavigatableComponent extends JComponent implements Helpful {
    3434
    35         public static final EastNorth world = Main.proj.latlon2eastNorth(new LatLon(Projection.MAX_LAT, Projection.MAX_LON));
    36         public static final int snapDistance = sqr(Main.pref.getInteger("node.snap-distance", 10));
    37 
    38         private static int sqr(int a) { return a*a;}
    39         /**
    40         * The scale factor in x or y-units per pixel. This means, if scale = 10,
    41         * every physical pixel on screen are 10 x or 10 y units in the
    42         * northing/easting space of the projection.
    43         */
    44         protected double scale;
    45         /**
    46         * Center n/e coordinate of the desired screen center.
    47         */
    48         protected EastNorth center;
    49 
    50         public NavigatableComponent() {
    51                 setLayout(null);
    52         }
    53 
    54         protected DataSet getData()
    55         {
    56                 return Main.ds;
    57         }
    58 
    59         /**
    60         * Return the OSM-conform zoom factor (0 for whole world, 1 for half, 2 for quarter...)
    61         */
    62         public int zoom() {
    63                 double sizex = scale * getWidth();
    64                 double sizey = scale * getHeight();
    65                 for (int zoom = 0; zoom <= 32; zoom++, sizex *= 2, sizey *= 2)
    66                         if (sizex > world.east() || sizey > world.north())
    67                                 return zoom;
    68                 return 32;
    69         }
    70 
    71         /**
    72         * Return the current scale value.
    73         * @return The scale value currently used in display
    74         */
    75         public double getScale() {
    76                 return scale;
    77         }
    78 
    79         /**
    80         * @return Returns the center point. A copy is returned, so users cannot
    81          *              change the center by accessing the return value. Use zoomTo instead.
    82         */
    83         public EastNorth getCenter() {
    84                 return center;
    85         }
    86 
    87         /**
    88         * @param x X-Pixelposition to get coordinate from
    89         * @param y Y-Pixelposition to get coordinate from
    90         *
    91         * @return Geographic coordinates from a specific pixel coordination
    92          *              on the screen.
    93         */
    94         public EastNorth getEastNorth(int x, int y) {
    95                 return new EastNorth(
    96                                 center.east() + (x - getWidth()/2.0)*scale,
    97                                 center.north() - (y - getHeight()/2.0)*scale);
    98         }
    99 
    100         /**
    101         * @param x X-Pixelposition to get coordinate from
    102         * @param y Y-Pixelposition to get coordinate from
    103         *
    104         * @return Geographic unprojected coordinates from a specific pixel coordination
    105          *              on the screen.
    106         */
    107         public LatLon getLatLon(int x, int y) {
    108 
    109                 return getProjection().eastNorth2latlon(getEastNorth(x, y));
    110         }
    111 
    112         /**
    113         * Return the point on the screen where this Coordinate would be.
    114         * @param p The point, where this geopoint would be drawn.
    115         * @return The point on screen where "point" would be drawn, relative
    116          *              to the own top/left.
    117         */
    118         public Point getPoint(EastNorth p) {
    119                 if(null == p)
    120                         return new Point();
    121                 double x = (p.east()-center.east())/scale + getWidth()/2;
    122                 double y = (center.north()-p.north())/scale + getHeight()/2;
    123                 return new Point((int)x,(int)y);
    124         }
    125 
    126         /**
    127         * Zoom to the given coordinate.
    128         * @param newCenter The center x-value (easting) to zoom to.
    129         * @param scale The scale to use.
    130         */
    131         public void zoomTo(EastNorth newCenter, double scale) {
    132                 center = newCenter;
    133                 getProjection().eastNorth2latlon(center);
    134                 this.scale = scale;
    135                 repaint();
    136         }
    137 
    138         /**
    139         * Return the nearest point to the screen point given.
    140         * If a node within 10 pixel is found, the nearest node is returned.
    141         */
    142         public final Node getNearestNode(Point p) {
    143                 double minDistanceSq = Double.MAX_VALUE;
    144                 Node minPrimitive = null;
    145                 for (Node n : getData().nodes) {
    146                         if (n.deleted || n.incomplete)
    147                                 continue;
    148                         Point sp = getPoint(n.eastNorth);
    149                         double dist = p.distanceSq(sp);
    150                         if (minDistanceSq > dist && dist < snapDistance) {
    151                                 minDistanceSq = p.distanceSq(sp);
    152                                 minPrimitive = n;
    153                         }
    154                         // prefer already selected node when multiple nodes on one point
    155                         else if(minDistanceSq == dist && n.selected && !minPrimitive.selected)
    156                         {
    157                                 minPrimitive = n;
    158                         }
    159                 }
    160                 return minPrimitive;
    161         }
    162 
    163         /**
    164         * @return all way segments within 10px of p, sorted by their
    165         * perpendicular distance.
    166          *
    167         * @param p the point for which to search the nearest segment.
    168         */
    169         public final List<WaySegment> getNearestWaySegments(Point p) {
    170                 TreeMap<Double, List<WaySegment>> nearest = new TreeMap<Double, List<WaySegment>>();
    171                 for (Way w : getData().ways) {
    172                         if (w.deleted || w.incomplete) continue;
    173                         Node lastN = null;
    174                         int i = -2;
    175                         for (Node n : w.nodes) {
    176                                 i++;
    177                                 if (n.deleted || n.incomplete) continue;
    178                                 if (lastN == null) {
    179                                         lastN = n;
    180                                         continue;
    181                                 }
    182 
    183                                 Point A = getPoint(lastN.eastNorth);
    184                                 Point B = getPoint(n.eastNorth);
    185                                 double c = A.distanceSq(B);
    186                                 double a = p.distanceSq(B);
    187                                 double b = p.distanceSq(A);
    188                                 double perDist = a-(a-b+c)*(a-b+c)/4/c; // perpendicular distance squared
    189                                 if (perDist < snapDistance && a < c+snapDistance && b < c+snapDistance) {
    190                                         if(w.selected) // prefer selected ways a little bit
    191                                                 perDist -= 0.00001;
    192                                         List<WaySegment> l;
    193                                         if (nearest.containsKey(perDist)) {
    194                                                 l = nearest.get(perDist);
    195                                         } else {
    196                                                 l = new LinkedList<WaySegment>();
    197                                                 nearest.put(perDist, l);
    198                                         }
    199                                         l.add(new WaySegment(w, i));
    200                                 }
    201 
    202                                 lastN = n;
    203                         }
    204                 }
    205                 ArrayList<WaySegment> nearestList = new ArrayList<WaySegment>();
    206                 for (List<WaySegment> wss : nearest.values()) {
    207                         nearestList.addAll(wss);
    208                 }
    209                 return nearestList;
    210         }
    211 
    212         /**
    213         * @return the nearest way segment to the screen point given that is not 
    214         * in ignore.
    215          *
    216         * @param p the point for which to search the nearest segment.
    217         * @param ignore a collection of segments which are not to be returned.
    218         * May be null.
    219         */
    220         public final WaySegment getNearestWaySegment(Point p, Collection<WaySegment> ignore) {
    221                 List<WaySegment> nearest = getNearestWaySegments(p);
    222                 if (ignore != null) nearest.removeAll(ignore);
    223                 return nearest.isEmpty() ? null : nearest.get(0);
    224         }
    225 
    226         /**
    227         * @return the nearest way segment to the screen point given.
    228         */
    229         public final WaySegment getNearestWaySegment(Point p) {
    230                 return getNearestWaySegment(p, null);
    231         }
    232        
    233         /**
    234         * @return the nearest way to the screen point given.
    235         */
    236         public final Way getNearestWay(Point p) {
    237                 WaySegment nearestWaySeg = getNearestWaySegment(p);
    238                 return nearestWaySeg == null ? null : nearestWaySeg.way;
    239         }
    240 
    241         /**
    242         * Return the object, that is nearest to the given screen point.
    243         *
    244         * First, a node will be searched. If a node within 10 pixel is found, the
    245         * nearest node is returned.
    246         *
    247         * If no node is found, search for near ways.
    248         *
    249         * If nothing is found, return <code>null</code>.
    250         *
    251         * @param p The point on screen.
    252         * @return  The primitive that is nearest to the point p.
    253         */
    254         public OsmPrimitive getNearest(Point p) {
    255                 OsmPrimitive osm = getNearestNode(p);
    256                 if (osm == null)
    257                 {
    258                         osm = getNearestWay(p);
    259                 }
    260                 return osm;
    261         }
    262 
    263         /**
    264         * Returns a singleton of the nearest object, or else an empty collection.
    265         */
    266         public Collection<OsmPrimitive> getNearestCollection(Point p) {
    267                 OsmPrimitive osm = getNearest(p);
    268                 if (osm == null) 
    269                         return Collections.emptySet();
    270                 return Collections.singleton(osm);
    271         }
    272 
    273         /**
    274         * @return A list of all objects that are nearest to
    275         * the mouse.  Does a simple sequential scan on all the data.
    276         *
    277         * @return A collection of all items or <code>null</code>
    278          *              if no item under or near the point. The returned
    279          *              list is never empty.
    280         */
    281         public Collection<OsmPrimitive> getAllNearest(Point p) {
    282                 Collection<OsmPrimitive> nearest = new HashSet<OsmPrimitive>();
    283                         for (Way w : getData().ways) {
    284                         if (w.deleted || w.incomplete) continue;
    285                         Node lastN = null;
    286                         for (Node n : w.nodes) {
    287                                 if (n.deleted || n.incomplete) continue;
    288                                 if (lastN == null) {
    289                                         lastN = n;
    290                                         continue;
    291                                 }
    292                                 Point A = getPoint(lastN.eastNorth);
    293                                 Point B = getPoint(n.eastNorth);
    294                                 double c = A.distanceSq(B);
    295                                 double a = p.distanceSq(B);
    296                                 double b = p.distanceSq(A);
    297                                 double perDist = a-(a-b+c)*(a-b+c)/4/c; // perpendicular distance squared
    298                                 if (perDist < snapDistance && a < c+snapDistance && b < c+snapDistance) {
    299                                         nearest.add(w);
    300                                                 break;
    301                                         }
    302                                 lastN = n;
    303                                 }
    304                         }
    305                 for (Node n : getData().nodes) {
    306                         if (!n.deleted && !n.incomplete
    307                                         && getPoint(n.eastNorth).distanceSq(p) < snapDistance) {
    308                                 nearest.add(n);
    309                         }
    310                 }
    311                 return nearest.isEmpty() ? null : nearest;
    312         }
    313 
    314         /**
    315         * @return A list of all nodes that are nearest to
    316         * the mouse.  Does a simple sequential scan on all the data.
    317         *
    318         * @return A collection of all nodes or <code>null</code>
    319          *              if no node under or near the point. The returned
    320          *              list is never empty.
    321         */
    322         public Collection<Node> getNearestNodes(Point p) {
    323                 Collection<Node> nearest = new HashSet<Node>();
    324                 for (Node n : getData().nodes) {
    325                         if (!n.deleted && !n.incomplete
    326                                         && getPoint(n.eastNorth).distanceSq(p) < snapDistance) {
    327                                 nearest.add(n);
    328                         }
    329                 }
    330                 return nearest.isEmpty() ? null : nearest;
    331         }
    332 
    333         /**
    334         * @return the nearest nodes to the screen point given that is not 
    335         * in ignore.
    336          *
    337         * @param p the point for which to search the nearest segment.
    338         * @param ignore a collection of nodes which are not to be returned.
    339         * May be null.
    340         */
    341         public final Collection<Node> getNearestNodes(Point p, Collection<Node> ignore) {
    342                 Collection<Node> nearest = getNearestNodes(p);
     35    public static final EastNorth world = Main.proj.latlon2eastNorth(new LatLon(Projection.MAX_LAT, Projection.MAX_LON));
     36    public static final int snapDistance = sqr(Main.pref.getInteger("node.snap-distance", 10));
     37
     38    private static int sqr(int a) { return a*a;}
     39    /**
     40    * The scale factor in x or y-units per pixel. This means, if scale = 10,
     41    * every physical pixel on screen are 10 x or 10 y units in the
     42    * northing/easting space of the projection.
     43    */
     44    protected double scale;
     45    /**
     46    * Center n/e coordinate of the desired screen center.
     47    */
     48    protected EastNorth center;
     49
     50    public NavigatableComponent() {
     51        setLayout(null);
     52    }
     53
     54    protected DataSet getData()
     55    {
     56        return Main.ds;
     57    }
     58
     59    /**
     60    * Return the OSM-conform zoom factor (0 for whole world, 1 for half, 2 for quarter...)
     61    */
     62    public int zoom() {
     63        double sizex = scale * getWidth();
     64        double sizey = scale * getHeight();
     65        for (int zoom = 0; zoom <= 32; zoom++, sizex *= 2, sizey *= 2)
     66            if (sizex > world.east() || sizey > world.north())
     67                return zoom;
     68        return 32;
     69    }
     70
     71    /**
     72    * Return the current scale value.
     73    * @return The scale value currently used in display
     74    */
     75    public double getScale() {
     76        return scale;
     77    }
     78
     79    /**
     80    * @return Returns the center point. A copy is returned, so users cannot
     81     *      change the center by accessing the return value. Use zoomTo instead.
     82    */
     83    public EastNorth getCenter() {
     84        return center;
     85    }
     86
     87    /**
     88    * @param x X-Pixelposition to get coordinate from
     89    * @param y Y-Pixelposition to get coordinate from
     90    *
     91    * @return Geographic coordinates from a specific pixel coordination
     92     *      on the screen.
     93    */
     94    public EastNorth getEastNorth(int x, int y) {
     95        return new EastNorth(
     96                center.east() + (x - getWidth()/2.0)*scale,
     97                center.north() - (y - getHeight()/2.0)*scale);
     98    }
     99
     100    /**
     101    * @param x X-Pixelposition to get coordinate from
     102    * @param y Y-Pixelposition to get coordinate from
     103    *
     104    * @return Geographic unprojected coordinates from a specific pixel coordination
     105     *      on the screen.
     106    */
     107    public LatLon getLatLon(int x, int y) {
     108
     109        return getProjection().eastNorth2latlon(getEastNorth(x, y));
     110    }
     111
     112    /**
     113    * Return the point on the screen where this Coordinate would be.
     114    * @param p The point, where this geopoint would be drawn.
     115    * @return The point on screen where "point" would be drawn, relative
     116     *      to the own top/left.
     117    */
     118    public Point getPoint(EastNorth p) {
     119        if(null == p)
     120            return new Point();
     121        double x = (p.east()-center.east())/scale + getWidth()/2;
     122        double y = (center.north()-p.north())/scale + getHeight()/2;
     123        return new Point((int)x,(int)y);
     124    }
     125
     126    /**
     127    * Zoom to the given coordinate.
     128    * @param newCenter The center x-value (easting) to zoom to.
     129    * @param scale The scale to use.
     130    */
     131    public void zoomTo(EastNorth newCenter, double scale) {
     132        center = newCenter;
     133        getProjection().eastNorth2latlon(center);
     134        this.scale = scale;
     135        repaint();
     136    }
     137
     138    /**
     139    * Return the nearest point to the screen point given.
     140    * If a node within 10 pixel is found, the nearest node is returned.
     141    */
     142    public final Node getNearestNode(Point p) {
     143        double minDistanceSq = Double.MAX_VALUE;
     144        Node minPrimitive = null;
     145        for (Node n : getData().nodes) {
     146            if (n.deleted || n.incomplete)
     147                continue;
     148            Point sp = getPoint(n.eastNorth);
     149            double dist = p.distanceSq(sp);
     150            if (minDistanceSq > dist && dist < snapDistance) {
     151                minDistanceSq = p.distanceSq(sp);
     152                minPrimitive = n;
     153            }
     154            // prefer already selected node when multiple nodes on one point
     155            else if(minDistanceSq == dist && n.selected && !minPrimitive.selected)
     156            {
     157                minPrimitive = n;
     158            }
     159        }
     160        return minPrimitive;
     161    }
     162
     163    /**
     164    * @return all way segments within 10px of p, sorted by their
     165    * perpendicular distance.
     166     *
     167    * @param p the point for which to search the nearest segment.
     168    */
     169    public final List<WaySegment> getNearestWaySegments(Point p) {
     170        TreeMap<Double, List<WaySegment>> nearest = new TreeMap<Double, List<WaySegment>>();
     171        for (Way w : getData().ways) {
     172            if (w.deleted || w.incomplete) continue;
     173            Node lastN = null;
     174            int i = -2;
     175            for (Node n : w.nodes) {
     176                i++;
     177                if (n.deleted || n.incomplete) continue;
     178                if (lastN == null) {
     179                    lastN = n;
     180                    continue;
     181                }
     182
     183                Point A = getPoint(lastN.eastNorth);
     184                Point B = getPoint(n.eastNorth);
     185                double c = A.distanceSq(B);
     186                double a = p.distanceSq(B);
     187                double b = p.distanceSq(A);
     188                double perDist = a-(a-b+c)*(a-b+c)/4/c; // perpendicular distance squared
     189                if (perDist < snapDistance && a < c+snapDistance && b < c+snapDistance) {
     190                    if(w.selected) // prefer selected ways a little bit
     191                        perDist -= 0.00001;
     192                    List<WaySegment> l;
     193                    if (nearest.containsKey(perDist)) {
     194                        l = nearest.get(perDist);
     195                    } else {
     196                        l = new LinkedList<WaySegment>();
     197                        nearest.put(perDist, l);
     198                    }
     199                    l.add(new WaySegment(w, i));
     200                }
     201
     202                lastN = n;
     203            }
     204        }
     205        ArrayList<WaySegment> nearestList = new ArrayList<WaySegment>();
     206        for (List<WaySegment> wss : nearest.values()) {
     207            nearestList.addAll(wss);
     208        }
     209        return nearestList;
     210    }
     211
     212    /**
     213    * @return the nearest way segment to the screen point given that is not
     214    * in ignore.
     215     *
     216    * @param p the point for which to search the nearest segment.
     217    * @param ignore a collection of segments which are not to be returned.
     218    * May be null.
     219    */
     220    public final WaySegment getNearestWaySegment(Point p, Collection<WaySegment> ignore) {
     221        List<WaySegment> nearest = getNearestWaySegments(p);
     222        if (ignore != null) nearest.removeAll(ignore);
     223        return nearest.isEmpty() ? null : nearest.get(0);
     224    }
     225
     226    /**
     227    * @return the nearest way segment to the screen point given.
     228    */
     229    public final WaySegment getNearestWaySegment(Point p) {
     230        return getNearestWaySegment(p, null);
     231    }
     232
     233    /**
     234    * @return the nearest way to the screen point given.
     235    */
     236    public final Way getNearestWay(Point p) {
     237        WaySegment nearestWaySeg = getNearestWaySegment(p);
     238        return nearestWaySeg == null ? null : nearestWaySeg.way;
     239    }
     240
     241    /**
     242    * Return the object, that is nearest to the given screen point.
     243    *
     244    * First, a node will be searched. If a node within 10 pixel is found, the
     245    * nearest node is returned.
     246    *
     247    * If no node is found, search for near ways.
     248    *
     249    * If nothing is found, return <code>null</code>.
     250    *
     251    * @param p The point on screen.
     252    * @return  The primitive that is nearest to the point p.
     253    */
     254    public OsmPrimitive getNearest(Point p) {
     255        OsmPrimitive osm = getNearestNode(p);
     256        if (osm == null)
     257        {
     258            osm = getNearestWay(p);
     259        }
     260        return osm;
     261    }
     262
     263    /**
     264    * Returns a singleton of the nearest object, or else an empty collection.
     265    */
     266    public Collection<OsmPrimitive> getNearestCollection(Point p) {
     267        OsmPrimitive osm = getNearest(p);
     268        if (osm == null)
     269            return Collections.emptySet();
     270        return Collections.singleton(osm);
     271    }
     272
     273    /**
     274    * @return A list of all objects that are nearest to
     275    * the mouse.  Does a simple sequential scan on all the data.
     276    *
     277    * @return A collection of all items or <code>null</code>
     278     *      if no item under or near the point. The returned
     279     *      list is never empty.
     280    */
     281    public Collection<OsmPrimitive> getAllNearest(Point p) {
     282        Collection<OsmPrimitive> nearest = new HashSet<OsmPrimitive>();
     283            for (Way w : getData().ways) {
     284            if (w.deleted || w.incomplete) continue;
     285            Node lastN = null;
     286            for (Node n : w.nodes) {
     287                if (n.deleted || n.incomplete) continue;
     288                if (lastN == null) {
     289                    lastN = n;
     290                    continue;
     291                }
     292                Point A = getPoint(lastN.eastNorth);
     293                Point B = getPoint(n.eastNorth);
     294                double c = A.distanceSq(B);
     295                double a = p.distanceSq(B);
     296                double b = p.distanceSq(A);
     297                double perDist = a-(a-b+c)*(a-b+c)/4/c; // perpendicular distance squared
     298                if (perDist < snapDistance && a < c+snapDistance && b < c+snapDistance) {
     299                    nearest.add(w);
     300                        break;
     301                    }
     302                lastN = n;
     303                }
     304            }
     305        for (Node n : getData().nodes) {
     306            if (!n.deleted && !n.incomplete
     307                    && getPoint(n.eastNorth).distanceSq(p) < snapDistance) {
     308                nearest.add(n);
     309            }
     310        }
     311        return nearest.isEmpty() ? null : nearest;
     312    }
     313
     314    /**
     315    * @return A list of all nodes that are nearest to
     316    * the mouse.  Does a simple sequential scan on all the data.
     317    *
     318    * @return A collection of all nodes or <code>null</code>
     319     *      if no node under or near the point. The returned
     320     *      list is never empty.
     321    */
     322    public Collection<Node> getNearestNodes(Point p) {
     323        Collection<Node> nearest = new HashSet<Node>();
     324        for (Node n : getData().nodes) {
     325            if (!n.deleted && !n.incomplete
     326                    && getPoint(n.eastNorth).distanceSq(p) < snapDistance) {
     327                nearest.add(n);
     328            }
     329        }
     330        return nearest.isEmpty() ? null : nearest;
     331    }
     332
     333    /**
     334    * @return the nearest nodes to the screen point given that is not
     335    * in ignore.
     336     *
     337    * @param p the point for which to search the nearest segment.
     338    * @param ignore a collection of nodes which are not to be returned.
     339    * May be null.
     340    */
     341    public final Collection<Node> getNearestNodes(Point p, Collection<Node> ignore) {
     342        Collection<Node> nearest = getNearestNodes(p);
    343343                if (nearest == null) return null;
    344                 if (ignore != null) nearest.removeAll(ignore);
    345                 return nearest.isEmpty() ? null : nearest;
    346         }
    347 
    348         /**
    349         * @return The projection to be used in calculating stuff.
    350         */
    351         protected Projection getProjection() {
    352                 return Main.proj;
    353         }
    354 
    355         public String helpTopic() {
    356             String n = getClass().getName();
    357             return n.substring(n.lastIndexOf('.')+1);
     344        if (ignore != null) nearest.removeAll(ignore);
     345        return nearest.isEmpty() ? null : nearest;
     346    }
     347
     348    /**
     349    * @return The projection to be used in calculating stuff.
     350    */
     351    protected Projection getProjection() {
     352        return Main.proj;
     353    }
     354
     355    public String helpTopic() {
     356        String n = getClass().getName();
     357        return n.substring(n.lastIndexOf('.')+1);
    358358    }
    359359}
  • trunk/src/org/openstreetmap/josm/gui/OsmPrimitivRenderer.java

    r627 r1169  
    1717/**
    1818 * Renderer that renders the objects from an OsmPrimitive as data.
    19  * 
     19 *
    2020 * Can be used in lists and tables.
    21  * 
     21 *
    2222 * @author imi
    2323 * @author Frederik Ramm <frederik@remote.org>
     
    2525public class OsmPrimitivRenderer implements ListCellRenderer, TableCellRenderer {
    2626
    27         /**
    28         * NameVisitor provides proper names and icons for OsmPrimitives
    29         */
    30         private NameVisitor visitor = new NameVisitor();
     27    /**
     28    * NameVisitor provides proper names and icons for OsmPrimitives
     29    */
     30    private NameVisitor visitor = new NameVisitor();
    3131
    32         /**
    33          * Default list cell renderer - delegate for ListCellRenderer operation
    34          */
    35         private DefaultListCellRenderer defaultListCellRenderer = new DefaultListCellRenderer();
    36        
    37         /**
    38          * Default table cell renderer - delegate for TableCellRenderer operation
    39          */
    40         private DefaultTableCellRenderer defaultTableCellRenderer = new DefaultTableCellRenderer();
     32    /**
     33     * Default list cell renderer - delegate for ListCellRenderer operation
     34     */
     35    private DefaultListCellRenderer defaultListCellRenderer = new DefaultListCellRenderer();
    4136
    42         /**
    43          * Adapter method supporting the ListCellRenderer interface.
    44          */
    45         public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
    46                 Component def = defaultListCellRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
    47                 return renderer(def, (OsmPrimitive) value);
    48         }
     37    /**
     38     * Default table cell renderer - delegate for TableCellRenderer operation
     39     */
     40    private DefaultTableCellRenderer defaultTableCellRenderer = new DefaultTableCellRenderer();
    4941
    50         /**
    51          * Adapter method supporting the TableCellRenderer interface.
    52          */
    53         public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    54                 Component def = defaultTableCellRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
    55                 return renderer(def, (OsmPrimitive) value);
    56         }
    57        
    58         /**
    59          * Internal method that stuffs information into the rendering component
    60          * provided that it's a kind of JLabel.
    61          * @param def the rendering component
    62          * @param value the OsmPrimtive to render
    63          * @return the modified rendering component
    64          */
    65         private Component renderer(Component def, OsmPrimitive value) {
    66                 if (def != null && value != null && def instanceof JLabel) {
    67                         (value).visit(visitor);
    68                         ((JLabel)def).setText(visitor.name);
    69                         ((JLabel)def).setIcon(visitor.icon);
    70                 }
    71                 return def;
    72         }
    73        
     42    /**
     43     * Adapter method supporting the ListCellRenderer interface.
     44     */
     45    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
     46        Component def = defaultListCellRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
     47        return renderer(def, (OsmPrimitive) value);
     48    }
     49
     50    /**
     51     * Adapter method supporting the TableCellRenderer interface.
     52     */
     53    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
     54        Component def = defaultTableCellRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
     55        return renderer(def, (OsmPrimitive) value);
     56    }
     57
     58    /**
     59     * Internal method that stuffs information into the rendering component
     60     * provided that it's a kind of JLabel.
     61     * @param def the rendering component
     62     * @param value the OsmPrimtive to render
     63     * @return the modified rendering component
     64     */
     65    private Component renderer(Component def, OsmPrimitive value) {
     66        if (def != null && value != null && def instanceof JLabel) {
     67            (value).visit(visitor);
     68            ((JLabel)def).setText(visitor.name);
     69            ((JLabel)def).setIcon(visitor.icon);
     70        }
     71        return def;
     72    }
     73
    7474}
  • trunk/src/org/openstreetmap/josm/gui/PleaseWaitDialog.java

    r1073 r1169  
    2020public class PleaseWaitDialog extends JDialog {
    2121
    22         private final JProgressBar progressBar = new JProgressBar();
     22    private final JProgressBar progressBar = new JProgressBar();
    2323
    24         public final JLabel currentAction = new JLabel(I18n.tr("Contacting the OSM server..."));
    25         public final BoundedRangeModel progress = progressBar.getModel();
    26         public final JButton cancel = new JButton(I18n.tr("Cancel"));
     24    public final JLabel currentAction = new JLabel(I18n.tr("Contacting the OSM server..."));
     25    public final BoundedRangeModel progress = progressBar.getModel();
     26    public final JButton cancel = new JButton(I18n.tr("Cancel"));
    2727
    28         public PleaseWaitDialog(Component parent) {
    29                 super(JOptionPane.getFrameForComponent(parent), true);
    30                 setLayout(new GridBagLayout());
    31                 JPanel pane = new JPanel(new GridBagLayout());
    32                 pane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
    33                 pane.add(currentAction, GBC.eol().fill(GBC.HORIZONTAL));
    34                 pane.add(progressBar, GBC.eop().fill(GBC.HORIZONTAL));
    35                 pane.add(cancel, GBC.eol().anchor(GBC.CENTER));
    36                 setContentPane(pane);
    37                 setSize(Main.pref.getInteger("progressdialog.size",400),100);
    38                 setLocationRelativeTo(Main.parent);
    39         }
     28    public PleaseWaitDialog(Component parent) {
     29        super(JOptionPane.getFrameForComponent(parent), true);
     30        setLayout(new GridBagLayout());
     31        JPanel pane = new JPanel(new GridBagLayout());
     32        pane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
     33        pane.add(currentAction, GBC.eol().fill(GBC.HORIZONTAL));
     34        pane.add(progressBar, GBC.eop().fill(GBC.HORIZONTAL));
     35        pane.add(cancel, GBC.eol().anchor(GBC.CENTER));
     36        setContentPane(pane);
     37        setSize(Main.pref.getInteger("progressdialog.size",400),100);
     38        setLocationRelativeTo(Main.parent);
     39    }
    4040}
  • trunk/src/org/openstreetmap/josm/gui/PleaseWaitRunnable.java

    r627 r1169  
    2626public abstract class PleaseWaitRunnable implements Runnable {
    2727
    28         public String errorMessage;
     28    public String errorMessage;
    2929
    30         private boolean closeDialogCalled = false;
    31         private boolean cancelled = false;
     30    private boolean closeDialogCalled = false;
     31    private boolean cancelled = false;
    3232
    33         private final String title;
     33    private final String title;
    3434
    35         /**
    36         * Create the runnable object with a given message for the user.
    37         */
    38         public PleaseWaitRunnable(String title) {
    39                 this.title = title;
    40                 Main.pleaseWaitDlg.cancel.addActionListener(new ActionListener(){
    41                         public void actionPerformed(ActionEvent e) {
    42                                 if (!cancelled) {
    43                                         cancelled = true;
    44                                         cancel();
    45                                 }
    46                         }
    47                 });
    48                 Main.pleaseWaitDlg.addWindowListener(new WindowAdapter(){
    49                         @Override public void windowClosing(WindowEvent e) {
    50                                 if (!closeDialogCalled) {
    51                                         if (!cancelled) {
    52                                                 cancelled = true;
    53                                                 cancel();
    54                                         }
    55                                         closeDialog();
    56                                 }
    57                         }
    58                 });
    59         }
     35    /**
     36    * Create the runnable object with a given message for the user.
     37    */
     38    public PleaseWaitRunnable(String title) {
     39        this.title = title;
     40        Main.pleaseWaitDlg.cancel.addActionListener(new ActionListener(){
     41            public void actionPerformed(ActionEvent e) {
     42                if (!cancelled) {
     43                    cancelled = true;
     44                    cancel();
     45                }
     46            }
     47        });
     48        Main.pleaseWaitDlg.addWindowListener(new WindowAdapter(){
     49            @Override public void windowClosing(WindowEvent e) {
     50                if (!closeDialogCalled) {
     51                    if (!cancelled) {
     52                        cancelled = true;
     53                        cancel();
     54                    }
     55                    closeDialog();
     56                }
     57            }
     58        });
     59    }
    6060
    61         public final void run() {
    62                 try {
    63                         if (cancelled)
    64                                 return; // since realRun isn't executed, do not call to finish
     61    public final void run() {
     62        try {
     63            if (cancelled)
     64                return; // since realRun isn't executed, do not call to finish
    6565
    66                         // reset dialog state
    67                         Main.pleaseWaitDlg.setTitle(title);
    68                         errorMessage = null;
    69                         closeDialogCalled = false;
     66            // reset dialog state
     67            Main.pleaseWaitDlg.setTitle(title);
     68            errorMessage = null;
     69            closeDialogCalled = false;
    7070
    71                         // show the dialog
    72                         synchronized (this) {
    73                     EventQueue.invokeLater(new Runnable() {
    74                         public void run() {
    75                                 synchronized (PleaseWaitRunnable.this) {
    76                                         PleaseWaitRunnable.this.notifyAll();
    77                                 }
    78                                 Main.pleaseWaitDlg.setVisible(true);
    79                         }
    80                     });
    81                     try {wait();} catch (InterruptedException e) {}
    82                         }
     71            // show the dialog
     72            synchronized (this) {
     73                EventQueue.invokeLater(new Runnable() {
     74                    public void run() {
     75                        synchronized (PleaseWaitRunnable.this) {
     76                            PleaseWaitRunnable.this.notifyAll();
     77                        }
     78                        Main.pleaseWaitDlg.setVisible(true);
     79                    }
     80                });
     81                try {wait();} catch (InterruptedException e) {}
     82            }
    8383
    84                         realRun();
    85                 } catch (SAXException x) {
    86                         x.printStackTrace();
    87                         errorMessage = tr("Error while parsing")+": "+x.getMessage();
    88                 } catch (FileNotFoundException x) {
    89                         x.printStackTrace();
    90                         errorMessage = tr("File not found")+": "+x.getMessage();
    91                 } catch (IOException x) {
    92                         x.printStackTrace();
    93                         errorMessage = x.getMessage();
    94                 } finally {
    95                         closeDialog();
    96                 }
    97         }
     84            realRun();
     85        } catch (SAXException x) {
     86            x.printStackTrace();
     87            errorMessage = tr("Error while parsing")+": "+x.getMessage();
     88        } catch (FileNotFoundException x) {
     89            x.printStackTrace();
     90            errorMessage = tr("File not found")+": "+x.getMessage();
     91        } catch (IOException x) {
     92            x.printStackTrace();
     93            errorMessage = x.getMessage();
     94        } finally {
     95            closeDialog();
     96        }
     97    }
    9898
    99         /**
    100         * User pressed cancel button.
    101         */
    102         protected abstract void cancel();
     99    /**
     100    * User pressed cancel button.
     101    */
     102    protected abstract void cancel();
    103103
    104         /**
    105         * Called in the worker thread to do the actual work. When any of the
    106         * exception is thrown, a message box will be displayed and closeDialog
    107         * is called. finish() is called in any case.
    108         */
    109         protected abstract void realRun() throws SAXException, IOException;
     104    /**
     105    * Called in the worker thread to do the actual work. When any of the
     106    * exception is thrown, a message box will be displayed and closeDialog
     107    * is called. finish() is called in any case.
     108    */
     109    protected abstract void realRun() throws SAXException, IOException;
    110110
    111         /**
    112         * Finish up the data work. Is guaranteed to be called if realRun is called.
    113         * Finish is called in the gui thread just after the dialog disappeared.
    114         */
    115         protected abstract void finish();
     111    /**
     112    * Finish up the data work. Is guaranteed to be called if realRun is called.
     113    * Finish is called in the gui thread just after the dialog disappeared.
     114    */
     115    protected abstract void finish();
    116116
    117         /**
    118         * Close the dialog. Usually called from worker thread.
    119         */
    120         public void closeDialog() {
    121                 if (closeDialogCalled)
    122                         return;
    123                 closeDialogCalled  = true;
    124                 try {
    125                         Runnable runnable = new Runnable(){
    126                                 public void run() {
    127                                         try {
    128                                                 finish();
    129                                         } finally {
    130                                                 Main.pleaseWaitDlg.setVisible(false);
    131                                                 Main.pleaseWaitDlg.dispose();
    132                                         }
    133                                         if (errorMessage != null)
    134                                                 JOptionPane.showMessageDialog(Main.parent, errorMessage);
    135                                 }
    136                         };
     117    /**
     118    * Close the dialog. Usually called from worker thread.
     119    */
     120    public void closeDialog() {
     121        if (closeDialogCalled)
     122            return;
     123        closeDialogCalled  = true;
     124        try {
     125            Runnable runnable = new Runnable(){
     126                public void run() {
     127                    try {
     128                        finish();
     129                    } finally {
     130                        Main.pleaseWaitDlg.setVisible(false);
     131                        Main.pleaseWaitDlg.dispose();
     132                    }
     133                    if (errorMessage != null)
     134                        JOptionPane.showMessageDialog(Main.parent, errorMessage);
     135                }
     136            };
    137137
    138                         // make sure, this is called in the dispatcher thread ASAP
    139                         if (EventQueue.isDispatchThread())
    140                                 runnable.run();
    141                         else
    142                                 EventQueue.invokeAndWait(runnable);
     138            // make sure, this is called in the dispatcher thread ASAP
     139            if (EventQueue.isDispatchThread())
     140                runnable.run();
     141            else
     142                EventQueue.invokeAndWait(runnable);
    143143
    144                 } catch (InterruptedException e) {
    145                 } catch (InvocationTargetException e) {
    146                         throw new RuntimeException(e);
    147                 }
    148         }
     144        } catch (InterruptedException e) {
     145        } catch (InvocationTargetException e) {
     146            throw new RuntimeException(e);
     147        }
     148    }
    149149}
  • trunk/src/org/openstreetmap/josm/gui/QuadStateCheckBox.java

    r747 r1169  
    2323public class QuadStateCheckBox extends JCheckBox {
    2424
    25         public enum State { NOT_SELECTED, SELECTED, UNSET, PARTIAL }
     25    public enum State { NOT_SELECTED, SELECTED, UNSET, PARTIAL }
    2626
    27         private final QuadStateDecorator model;
    28         private State[] allowed;
     27    private final QuadStateDecorator model;
     28    private State[] allowed;
    2929
    30         public QuadStateCheckBox(String text, Icon icon, State initial, State[] allowed) {
    31                 super(text, icon);
    32                 this.allowed = allowed;
    33                 // Add a listener for when the mouse is pressed
    34                 super.addMouseListener(new MouseAdapter() {
    35                         @Override public void mousePressed(MouseEvent e) {
    36                                 grabFocus();
    37                                 model.nextState();
    38                         }
    39                 });
    40                 // Reset the keyboard action map
    41                 ActionMap map = new ActionMapUIResource();
    42                 map.put("pressed", new AbstractAction() {
    43                         public void actionPerformed(ActionEvent e) {
    44                                 grabFocus();
    45                                 model.nextState();
    46                         }
    47                 });
    48                 map.put("released", null);
    49                 SwingUtilities.replaceUIActionMap(this, map);
    50                 // set the model to the adapted model
    51                 model = new QuadStateDecorator(getModel());
    52                 setModel(model);
    53                 setState(initial);
    54         }
    55         public QuadStateCheckBox(String text, State initial, State[] allowed) {
    56                 this(text, null, initial, allowed);
    57         }
     30    public QuadStateCheckBox(String text, Icon icon, State initial, State[] allowed) {
     31        super(text, icon);
     32        this.allowed = allowed;
     33        // Add a listener for when the mouse is pressed
     34        super.addMouseListener(new MouseAdapter() {
     35            @Override public void mousePressed(MouseEvent e) {
     36                grabFocus();
     37                model.nextState();
     38            }
     39        });
     40        // Reset the keyboard action map
     41        ActionMap map = new ActionMapUIResource();
     42        map.put("pressed", new AbstractAction() {
     43            public void actionPerformed(ActionEvent e) {
     44                grabFocus();
     45                model.nextState();
     46            }
     47        });
     48        map.put("released", null);
     49        SwingUtilities.replaceUIActionMap(this, map);
     50        // set the model to the adapted model
     51        model = new QuadStateDecorator(getModel());
     52        setModel(model);
     53        setState(initial);
     54    }
     55    public QuadStateCheckBox(String text, State initial, State[] allowed) {
     56        this(text, null, initial, allowed);
     57    }
    5858
    59         /** Do not let anyone add mouse listeners */
    60         @Override public void addMouseListener(MouseListener l) { }
    61         /**
    62         * Set the new state.
    63         */
    64         public void setState(State state) { model.setState(state); }
    65         /** Return the current state, which is determined by the
    66         * selection status of the model. */
    67         public State getState() { return model.getState(); }
    68         @Override public void setSelected(boolean b) {
    69                 if (b) {
    70                         setState(State.SELECTED);
    71                 } else {
    72                         setState(State.NOT_SELECTED);
    73                 }
    74         }
     59    /** Do not let anyone add mouse listeners */
     60    @Override public void addMouseListener(MouseListener l) { }
     61    /**
     62    * Set the new state.
     63    */
     64    public void setState(State state) { model.setState(state); }
     65    /** Return the current state, which is determined by the
     66    * selection status of the model. */
     67    public State getState() { return model.getState(); }
     68    @Override public void setSelected(boolean b) {
     69        if (b) {
     70            setState(State.SELECTED);
     71        } else {
     72            setState(State.NOT_SELECTED);
     73        }
     74    }
    7575
    76         private class QuadStateDecorator implements ButtonModel {
    77                 private final ButtonModel other;
    78                 private QuadStateDecorator(ButtonModel other) {
    79                         this.other = other;
    80                 }
    81                 private void setState(State state) {
    82                         if (state == State.NOT_SELECTED) {
    83                                 other.setArmed(false);
    84                                 other.setPressed(false);
    85                                 other.setSelected(false);
    86                                 setToolTipText(tr("false: the property is explicitly switched off"));
    87                         } else if (state == State.SELECTED) {
    88                                 other.setArmed(false);
    89                                 other.setPressed(false);
    90                                 other.setSelected(true);
    91                                 setToolTipText(tr("true: the property is explicitly switched on"));
    92                         } else if (state == State.PARTIAL) {
    93                                 other.setArmed(true);
    94                                 other.setPressed(true);
    95                                 other.setSelected(true);
    96                                 setToolTipText(tr("partial: different selected objects have different values, do not change"));
    97                         } else {
    98                                 other.setArmed(true);
    99                                 other.setPressed(true);
    100                                 other.setSelected(false);
    101                                 setToolTipText(tr("unset: do not set this property on the selected objects"));
    102                         }
    103                 }
    104                 /**
    105                 * The current state is embedded in the selection / armed
    106                 * state of the model.
    107                  *
    108                 * We return the SELECTED state when the checkbox is selected
    109                 * but not armed, PARTIAL state when the checkbox is
    110                 * selected and armed (grey) and NOT_SELECTED when the
    111                 * checkbox is deselected.
    112                 */
    113                 private State getState() {
    114                         if (isSelected() && !isArmed()) {
    115                                 // normal black tick
    116                                 return State.SELECTED;
    117                         } else if (isSelected() && isArmed()) {
    118                                 // don't care grey tick
    119                                 return State.PARTIAL;
    120                         } else if (!isSelected() && !isArmed()) {
    121                                 return State.NOT_SELECTED;
    122                         } else {
    123                                 return State.UNSET;
    124                         }
    125                 }
    126                 /** Rotate to the next allowed state.*/
    127                 private void nextState() {
    128                         State current = getState();
    129                         for (int i = 0; i < allowed.length; i++) {
    130                                 if (allowed[i] == current) {
    131                                         setState((i == allowed.length-1) ? allowed[0] : allowed[i+1]);
    132                                         break;
    133                                 }
    134                         }
    135                 }
    136                 /** Filter: No one may change the armed/selected/pressed status except us. */
    137                 public void setArmed(boolean b) { }
    138                 public void setSelected(boolean b) { }
    139                 public void setPressed(boolean b) { }
    140                 /** We disable focusing on the component when it is not
    141                 * enabled. */
    142                 public void setEnabled(boolean b) {
    143                         setFocusable(b);
    144                         other.setEnabled(b);
    145                 }
    146                 /** All these methods simply delegate to the "other" model
    147                 * that is being decorated. */
    148                 public boolean isArmed() { return other.isArmed(); }
    149                 public boolean isSelected() { return other.isSelected(); }
    150                 public boolean isEnabled() { return other.isEnabled(); }
    151                 public boolean isPressed() { return other.isPressed(); }
    152                 public boolean isRollover() { return other.isRollover(); }
    153                 public void setRollover(boolean b) { other.setRollover(b); }
    154                 public void setMnemonic(int key) { other.setMnemonic(key); }
    155                 public int getMnemonic() { return other.getMnemonic(); }
    156                 public void setActionCommand(String s) {
    157                         other.setActionCommand(s);
    158                 }
    159                 public String getActionCommand() {
    160                         return other.getActionCommand();
    161                 }
    162                 public void setGroup(ButtonGroup group) {
    163                         other.setGroup(group);
    164                 }
    165                 public void addActionListener(ActionListener l) {
    166                         other.addActionListener(l);
    167                 }
    168                 public void removeActionListener(ActionListener l) {
    169                         other.removeActionListener(l);
    170                 }
    171                 public void addItemListener(ItemListener l) {
    172                         other.addItemListener(l);
    173                 }
    174                 public void removeItemListener(ItemListener l) {
    175                         other.removeItemListener(l);
    176                 }
    177                 public void addChangeListener(ChangeListener l) {
    178                         other.addChangeListener(l);
    179                 }
    180                 public void removeChangeListener(ChangeListener l) {
    181                         other.removeChangeListener(l);
    182                 }
    183                 public Object[] getSelectedObjects() {
    184                         return other.getSelectedObjects();
    185                 }
    186         }
     76    private class QuadStateDecorator implements ButtonModel {
     77        private final ButtonModel other;
     78        private QuadStateDecorator(ButtonModel other) {
     79            this.other = other;
     80        }
     81        private void setState(State state) {
     82            if (state == State.NOT_SELECTED) {
     83                other.setArmed(false);
     84                other.setPressed(false);
     85                other.setSelected(false);
     86                setToolTipText(tr("false: the property is explicitly switched off"));
     87            } else if (state == State.SELECTED) {
     88                other.setArmed(false);
     89                other.setPressed(false);
     90                other.setSelected(true);
     91                setToolTipText(tr("true: the property is explicitly switched on"));
     92            } else if (state == State.PARTIAL) {
     93                other.setArmed(true);
     94                other.setPressed(true);
     95                other.setSelected(true);
     96                setToolTipText(tr("partial: different selected objects have different values, do not change"));
     97            } else {
     98                other.setArmed(true);
     99                other.setPressed(true);
     100                other.setSelected(false);
     101                setToolTipText(tr("unset: do not set this property on the selected objects"));
     102            }
     103        }
     104        /**
     105        * The current state is embedded in the selection / armed
     106        * state of the model.
     107         *
     108        * We return the SELECTED state when the checkbox is selected
     109        * but not armed, PARTIAL state when the checkbox is
     110        * selected and armed (grey) and NOT_SELECTED when the
     111        * checkbox is deselected.
     112        */
     113        private State getState() {
     114            if (isSelected() && !isArmed()) {
     115                // normal black tick
     116                return State.SELECTED;
     117            } else if (isSelected() && isArmed()) {
     118                // don't care grey tick
     119                return State.PARTIAL;
     120            } else if (!isSelected() && !isArmed()) {
     121                return State.NOT_SELECTED;
     122            } else {
     123                return State.UNSET;
     124            }
     125        }
     126        /** Rotate to the next allowed state.*/
     127        private void nextState() {
     128            State current = getState();
     129            for (int i = 0; i < allowed.length; i++) {
     130                if (allowed[i] == current) {
     131                    setState((i == allowed.length-1) ? allowed[0] : allowed[i+1]);
     132                    break;
     133                }
     134            }
     135        }
     136        /** Filter: No one may change the armed/selected/pressed status except us. */
     137        public void setArmed(boolean b) { }
     138        public void setSelected(boolean b) { }
     139        public void setPressed(boolean b) { }
     140        /** We disable focusing on the component when it is not
     141        * enabled. */
     142        public void setEnabled(boolean b) {
     143            setFocusable(b);
     144            other.setEnabled(b);
     145        }
     146        /** All these methods simply delegate to the "other" model
     147        * that is being decorated. */
     148        public boolean isArmed() { return other.isArmed(); }
     149        public boolean isSelected() { return other.isSelected(); }
     150        public boolean isEnabled() { return other.isEnabled(); }
     151        public boolean isPressed() { return other.isPressed(); }
     152        public boolean isRollover() { return other.isRollover(); }
     153        public void setRollover(boolean b) { other.setRollover(b); }
     154        public void setMnemonic(int key) { other.setMnemonic(key); }
     155        public int getMnemonic() { return other.getMnemonic(); }
     156        public void setActionCommand(String s) {
     157            other.setActionCommand(s);
     158        }
     159        public String getActionCommand() {
     160            return other.getActionCommand();
     161        }
     162        public void setGroup(ButtonGroup group) {
     163            other.setGroup(group);
     164        }
     165        public void addActionListener(ActionListener l) {
     166            other.addActionListener(l);
     167        }
     168        public void removeActionListener(ActionListener l) {
     169            other.removeActionListener(l);
     170        }
     171        public void addItemListener(ItemListener l) {
     172            other.addItemListener(l);
     173        }
     174        public void removeItemListener(ItemListener l) {
     175            other.removeItemListener(l);
     176        }
     177        public void addChangeListener(ChangeListener l) {
     178            other.addChangeListener(l);
     179        }
     180        public void removeChangeListener(ChangeListener l) {
     181            other.removeChangeListener(l);
     182        }
     183        public Object[] getSelectedObjects() {
     184            return other.getSelectedObjects();
     185        }
     186    }
    187187}
    188188
  • trunk/src/org/openstreetmap/josm/gui/SelectionManager.java

    r1003 r1169  
    2323 * Manages the selection of a rectangle. Listening to left and right mouse button
    2424 * presses and to mouse motions and draw the rectangle accordingly.
    25  * 
     25 *
    2626 * Left mouse button selects a rectangle from the press until release. Pressing
    2727 * right mouse button while left is still pressed enable the rectangle to move
     
    2929 * at constructor, except if the right is still pressed, which just remove the
    3030 * selection rectangle and does nothing.
    31  * 
    32  * The point where the left mouse button was pressed and the current mouse 
     31 *
     32 * The point where the left mouse button was pressed and the current mouse
    3333 * position are two opposite corners of the selection rectangle.
    34  * 
    35  * It is possible to specify an aspect ratio (width per height) which the 
     34 *
     35 * It is possible to specify an aspect ratio (width per height) which the
    3636 * selection rectangle always must have. In this case, the selection rectangle
    3737 * will be the largest window with this aspect ratio, where the position the left
    38  * mouse button was pressed and the corner of the current mouse position are at 
     38 * mouse button was pressed and the corner of the current mouse position are at
    3939 * opposite sites (the mouse position corner is the corner nearest to the mouse
    40  * cursor). 
    41  * 
    42  * When the left mouse button was released, an ActionEvent is send to the 
     40 * cursor).
     41 *
     42 * When the left mouse button was released, an ActionEvent is send to the
    4343 * ActionListener given at constructor. The source of this event is this manager.
    44  * 
     44 *
    4545 * @author imi
    4646 */
    4747public class SelectionManager implements MouseListener, MouseMotionListener, PropertyChangeListener {
    4848
    49         /**
    50         * This is the interface that an user of SelectionManager has to implement
    51         * to get informed when a selection closes.
    52         * @author imi
    53         */
    54         public interface SelectionEnded {
    55                 /**
    56                 * Called, when the left mouse button was released.
    57                 * @param r The rectangle that is currently the selection.
    58                 * @param alt Whether the alt key was pressed
    59                 * @param shift Whether the shift key was pressed
    60                 * @param ctrl Whether the ctrl key was pressed 
    61                 * @see InputEvent#getModifiersEx()
    62                 */
    63                 public void selectionEnded(Rectangle r, boolean alt, boolean shift, boolean ctrl);
    64                 /**
    65                 * Called to register the selection manager for "active" property.
    66                 * @param listener The listener to register
    67                 */
    68                 public void addPropertyChangeListener(PropertyChangeListener listener);
    69                 /**
    70                 * Called to remove the selection manager from the listener list 
    71                 * for "active" property.
    72                 * @param listener The listener to register
    73                 */
    74                 public void removePropertyChangeListener(PropertyChangeListener listener);
    75         }
    76         /**
    77         * The listener that receives the events after left mouse button is released.
    78         */
    79         private final SelectionEnded selectionEndedListener;
    80         /**
    81         * Position of the map when the mouse button was pressed.
    82         * If this is not <code>null</code>, a rectangle is drawn on screen. 
    83         */
    84         private Point mousePosStart;
    85         /**
    86         * Position of the map when the selection rectangle was last drawn.
    87         */
    88         private Point mousePos;
    89         /**
    90         * The Component, the selection rectangle is drawn onto.
    91         */
    92         private final NavigatableComponent nc;
    93         /**
    94         * Whether the selection rectangle must obtain the aspect ratio of the 
    95         * drawComponent.
    96         */
    97         private boolean aspectRatio;
    98 
    99         /**
    100         * Create a new SelectionManager.
    101         *
    102         * @param selectionEndedListener The action listener that receives the event when
    103          *              the left button is released.
    104         * @param aspectRatio If true, the selection window must obtain the aspect
    105          *              ratio of the drawComponent.
    106         * @param navComp The component, the rectangle is drawn onto.
    107         */
    108         public SelectionManager(SelectionEnded selectionEndedListener, boolean aspectRatio, NavigatableComponent navComp) {
    109                 this.selectionEndedListener = selectionEndedListener;
    110                 this.aspectRatio = aspectRatio;
    111                 this.nc = navComp;
    112         }
    113        
    114         /**
    115         * Register itself at the given event source.
    116         * @param eventSource The emitter of the mouse events.
    117         */
    118         public void register(NavigatableComponent eventSource) {
    119                 eventSource.addMouseListener(this);
    120                 eventSource.addMouseMotionListener(this);
    121                 selectionEndedListener.addPropertyChangeListener(this);
     49    /**
     50    * This is the interface that an user of SelectionManager has to implement
     51    * to get informed when a selection closes.
     52    * @author imi
     53    */
     54    public interface SelectionEnded {
     55        /**
     56        * Called, when the left mouse button was released.
     57        * @param r The rectangle that is currently the selection.
     58        * @param alt Whether the alt key was pressed
     59        * @param shift Whether the shift key was pressed
     60        * @param ctrl Whether the ctrl key was pressed
     61        * @see InputEvent#getModifiersEx()
     62        */
     63        public void selectionEnded(Rectangle r, boolean alt, boolean shift, boolean ctrl);
     64        /**
     65        * Called to register the selection manager for "active" property.
     66        * @param listener The listener to register
     67        */
     68        public void addPropertyChangeListener(PropertyChangeListener listener);
     69        /**
     70        * Called to remove the selection manager from the listener list
     71        * for "active" property.
     72        * @param listener The listener to register
     73        */
     74        public void removePropertyChangeListener(PropertyChangeListener listener);
     75    }
     76    /**
     77    * The listener that receives the events after left mouse button is released.
     78    */
     79    private final SelectionEnded selectionEndedListener;
     80    /**
     81    * Position of the map when the mouse button was pressed.
     82    * If this is not <code>null</code>, a rectangle is drawn on screen.
     83    */
     84    private Point mousePosStart;
     85    /**
     86    * Position of the map when the selection rectangle was last drawn.
     87    */
     88    private Point mousePos;
     89    /**
     90    * The Component, the selection rectangle is drawn onto.
     91    */
     92    private final NavigatableComponent nc;
     93    /**
     94    * Whether the selection rectangle must obtain the aspect ratio of the
     95    * drawComponent.
     96    */
     97    private boolean aspectRatio;
     98
     99    /**
     100    * Create a new SelectionManager.
     101    *
     102    * @param selectionEndedListener The action listener that receives the event when
     103     *      the left button is released.
     104    * @param aspectRatio If true, the selection window must obtain the aspect
     105     *      ratio of the drawComponent.
     106    * @param navComp The component, the rectangle is drawn onto.
     107    */
     108    public SelectionManager(SelectionEnded selectionEndedListener, boolean aspectRatio, NavigatableComponent navComp) {
     109        this.selectionEndedListener = selectionEndedListener;
     110        this.aspectRatio = aspectRatio;
     111        this.nc = navComp;
     112    }
     113
     114    /**
     115    * Register itself at the given event source.
     116    * @param eventSource The emitter of the mouse events.
     117    */
     118    public void register(NavigatableComponent eventSource) {
     119        eventSource.addMouseListener(this);
     120        eventSource.addMouseMotionListener(this);
     121        selectionEndedListener.addPropertyChangeListener(this);
    122122        eventSource.addPropertyChangeListener("scale", new PropertyChangeListener(){
    123                         public void propertyChange(PropertyChangeEvent evt) {
    124                                 if (mousePosStart != null) {
    125                                         paintRect();
    126                                         mousePos = mousePosStart = null;
    127                                 }
     123            public void propertyChange(PropertyChangeEvent evt) {
     124                if (mousePosStart != null) {
     125                    paintRect();
     126                    mousePos = mousePosStart = null;
     127                }
    128128            }
    129129        });
    130         }
    131         /**
    132         * Unregister itself from the given event source. If a selection rectangle is
    133         * shown, hide it first.
    134         *
    135         * @param eventSource The emitter of the mouse events.
    136         */
    137         public void unregister(Component eventSource) {
    138                 eventSource.removeMouseListener(this);
    139                 eventSource.removeMouseMotionListener(this);
    140                 selectionEndedListener.removePropertyChangeListener(this);
    141         }
    142 
    143         /**
    144         * If the correct button, from the "drawing rectangle" mode
    145         */
    146         public void mousePressed(MouseEvent e) {
    147                 if (e.getButton() == MouseEvent.BUTTON1)
    148                         mousePosStart = mousePos = e.getPoint();
    149         }
    150 
    151         /**
    152         * If the correct button is hold, draw the rectangle.
    153         */
    154         public void mouseDragged(MouseEvent e) {
    155                 int buttonPressed = e.getModifiersEx() & (MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON3_DOWN_MASK); 
    156 
    157                
    158                 if (buttonPressed != 0) {
    159                         if (mousePosStart == null)
    160                                 mousePosStart = mousePos = e.getPoint();
    161                         paintRect();
    162                 }
    163                
    164                 if (buttonPressed == MouseEvent.BUTTON1_DOWN_MASK) {
    165                         mousePos = e.getPoint();
    166                         paintRect();
    167                 } else if (buttonPressed == (MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON3_DOWN_MASK)) {
    168                         mousePosStart.x += e.getX()-mousePos.x;
    169                         mousePosStart.y += e.getY()-mousePos.y;
    170                         mousePos = e.getPoint();
    171                         paintRect();
    172                 }
    173         }
    174 
    175         /**
    176         * Check the state of the keys and buttons and set the selection accordingly.
    177         */
    178         public void mouseReleased(MouseEvent e) {
    179                 if (e.getButton() != MouseEvent.BUTTON1)
    180                         return;
    181                 if (mousePos == null || mousePosStart == null)
    182                         return; // injected release from outside
    183                        
    184                 // disable the selection rect
    185                 paintRect();
    186                 Rectangle r = getSelectionRectangle();
    187                 mousePosStart = null;
    188                 mousePos = null;
    189 
    190                 boolean shift = (e.getModifiersEx() & MouseEvent.SHIFT_DOWN_MASK) != 0;
    191                 boolean alt = (e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) != 0;
    192                 boolean ctrl = (e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) != 0;
    193                 if ((e.getModifiersEx() & MouseEvent.BUTTON3_DOWN_MASK) == 0)
    194                         selectionEndedListener.selectionEnded(r, alt, shift, ctrl);
    195         }
    196 
    197 
    198         /**
    199         * Draw a selection rectangle on screen. If already a rectangle is drawn,
    200         * it is removed instead.
    201         */
    202         private void paintRect() {
    203                 if (mousePos == null || mousePosStart == null || mousePos == mousePosStart)
    204                         return;
    205                 Graphics g = nc.getGraphics();
    206                 g.setColor(Color.BLACK);
    207                 g.setXORMode(Color.WHITE);
    208 
    209                 Rectangle r = getSelectionRectangle();
    210                 g.drawRect(r.x,r.y,r.width,r.height);
    211         }
    212 
    213         /**
    214         * Calculate and return the current selection rectangle
    215         * @return A rectangle that spans from mousePos to mouseStartPos
    216         */
    217         private Rectangle getSelectionRectangle() {
    218                 int x = mousePosStart.x;
    219                 int y = mousePosStart.y;
    220                 int w = mousePos.x - mousePosStart.x;
    221                 int h = mousePos.y - mousePosStart.y;
    222                 if (w < 0) {
    223                         x += w;
    224                         w = -w;
    225                 }
    226                 if (h < 0) {
    227                         y += h;
    228                         h = -h;
    229                 }
    230                
    231                 if (aspectRatio) {
    232                         /* Keep the aspect ratio by growing the rectangle; the
    233                         * rectangle is always under the cursor. */
    234                         double aspectRatio = (double)nc.getWidth()/nc.getHeight();
    235                         if ((double)w/h < aspectRatio) {
    236                                 int neww = (int)(h*aspectRatio);
    237                                 if (mousePos.x < mousePosStart.x)
    238                                         x += w - neww;
    239                                 w = neww;
    240                         } else {
    241                                 int newh = (int)(w/aspectRatio);
    242                                 if (mousePos.y < mousePosStart.y)
    243                                         y += h - newh;
    244                                 h = newh;
    245                         }
    246                 }
    247                
    248                 return new Rectangle(x,y,w,h);
    249         }
    250 
    251         /**
    252         * If the action goes inactive, remove the selection rectangle from screen
    253         */
    254         public void propertyChange(PropertyChangeEvent evt) {
    255                 if (evt.getPropertyName().equals("active") && !(Boolean)evt.getNewValue() && mousePosStart != null) {
    256                         paintRect();
    257                         mousePosStart = null;
    258                         mousePos = null;
    259                 }
    260         }
    261 
    262         /**
    263         * Return a list of all objects in the rectangle, respecting the different
    264         * modifier.
    265         * @param alt Whether the alt key was pressed, which means select all objects
    266          *              that are touched, instead those which are completly covered.
    267         */
    268         public Collection<OsmPrimitive> getObjectsInRectangle(Rectangle r, boolean alt) {
    269                 Collection<OsmPrimitive> selection = new LinkedList<OsmPrimitive>();
    270 
    271                 // whether user only clicked, not dragged.
    272                 boolean clicked = r.width <= 2 && r.height <= 2;
    273                 Point center = new Point(r.x+r.width/2, r.y+r.height/2);
    274 
    275                 if (clicked) {
    276                         OsmPrimitive osm = nc.getNearest(center);
    277                         if (osm != null)
    278                                 selection.add(osm);
    279                 } else {
    280                         // nodes
    281                         for (Node n : nc.getData().nodes) {
    282                                 if (!n.deleted && !n.incomplete && r.contains(nc.getPoint(n.eastNorth)))
    283                                         selection.add(n);
    284                         }
    285                        
    286                         // ways
    287                         for (Way w : nc.getData().ways) {
    288                                 if (w.deleted || w.nodes.isEmpty() || w.incomplete)
    289                                                 continue;
    290                                 if (alt) {
    291                                         for (Node n : w.nodes) {
    292                                                 if (!n.incomplete && r.contains(nc.getPoint(n.eastNorth))) {
    293                                                         selection.add(w);
    294                                                         break;
    295                                                 }
    296                                         }
    297                                 } else {
    298                                         boolean allIn = true;
    299                                         for (Node n : w.nodes) {
    300                                                 if (!n.incomplete && !r.contains(nc.getPoint(n.eastNorth))) {
    301                                                         allIn = false;
    302                                                         break;
    303                                                 }
    304                                         }
    305                                         if (allIn) selection.add(w);
    306                                 }
    307                         }
    308                 }
    309                 return selection;
    310         }
    311        
    312         public void mouseClicked(MouseEvent e) {}
    313         public void mouseEntered(MouseEvent e) {}
    314         public void mouseExited(MouseEvent e) {}
    315         public void mouseMoved(MouseEvent e) {}
     130    }
     131    /**
     132    * Unregister itself from the given event source. If a selection rectangle is
     133    * shown, hide it first.
     134    *
     135    * @param eventSource The emitter of the mouse events.
     136    */
     137    public void unregister(Component eventSource) {
     138        eventSource.removeMouseListener(this);
     139        eventSource.removeMouseMotionListener(this);
     140        selectionEndedListener.removePropertyChangeListener(this);
     141    }
     142
     143    /**
     144    * If the correct button, from the "drawing rectangle" mode
     145    */
     146    public void mousePressed(MouseEvent e) {
     147        if (e.getButton() == MouseEvent.BUTTON1)
     148            mousePosStart = mousePos = e.getPoint();
     149    }
     150
     151    /**
     152    * If the correct button is hold, draw the rectangle.
     153    */
     154    public void mouseDragged(MouseEvent e) {
     155        int buttonPressed = e.getModifiersEx() & (MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON3_DOWN_MASK);
     156
     157
     158        if (buttonPressed != 0) {
     159            if (mousePosStart == null)
     160                mousePosStart = mousePos = e.getPoint();
     161            paintRect();
     162        }
     163
     164        if (buttonPressed == MouseEvent.BUTTON1_DOWN_MASK) {
     165            mousePos = e.getPoint();
     166            paintRect();
     167        } else if (buttonPressed == (MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON3_DOWN_MASK)) {
     168            mousePosStart.x += e.getX()-mousePos.x;
     169            mousePosStart.y += e.getY()-mousePos.y;
     170            mousePos = e.getPoint();
     171            paintRect();
     172        }
     173    }
     174
     175    /**
     176    * Check the state of the keys and buttons and set the selection accordingly.
     177    */
     178    public void mouseReleased(MouseEvent e) {
     179        if (e.getButton() != MouseEvent.BUTTON1)
     180            return;
     181        if (mousePos == null || mousePosStart == null)
     182            return; // injected release from outside
     183
     184        // disable the selection rect
     185        paintRect();
     186        Rectangle r = getSelectionRectangle();
     187        mousePosStart = null;
     188        mousePos = null;
     189
     190        boolean shift = (e.getModifiersEx() & MouseEvent.SHIFT_DOWN_MASK) != 0;
     191        boolean alt = (e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) != 0;
     192        boolean ctrl = (e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) != 0;
     193        if ((e.getModifiersEx() & MouseEvent.BUTTON3_DOWN_MASK) == 0)
     194            selectionEndedListener.selectionEnded(r, alt, shift, ctrl);
     195    }
     196
     197
     198    /**
     199    * Draw a selection rectangle on screen. If already a rectangle is drawn,
     200    * it is removed instead.
     201    */
     202    private void paintRect() {
     203        if (mousePos == null || mousePosStart == null || mousePos == mousePosStart)
     204            return;
     205        Graphics g = nc.getGraphics();
     206        g.setColor(Color.BLACK);
     207        g.setXORMode(Color.WHITE);
     208
     209        Rectangle r = getSelectionRectangle();
     210        g.drawRect(r.x,r.y,r.width,r.height);
     211    }
     212
     213    /**
     214    * Calculate and return the current selection rectangle
     215    * @return A rectangle that spans from mousePos to mouseStartPos
     216    */
     217    private Rectangle getSelectionRectangle() {
     218        int x = mousePosStart.x;
     219        int y = mousePosStart.y;
     220        int w = mousePos.x - mousePosStart.x;
     221        int h = mousePos.y - mousePosStart.y;
     222        if (w < 0) {
     223            x += w;
     224            w = -w;
     225        }
     226        if (h < 0) {
     227            y += h;
     228            h = -h;
     229        }
     230
     231        if (aspectRatio) {
     232            /* Keep the aspect ratio by growing the rectangle; the
     233            * rectangle is always under the cursor. */
     234            double aspectRatio = (double)nc.getWidth()/nc.getHeight();
     235            if ((double)w/h < aspectRatio) {
     236                int neww = (int)(h*aspectRatio);
     237                if (mousePos.x < mousePosStart.x)
     238                    x += w - neww;
     239                w = neww;
     240            } else {
     241                int newh = (int)(w/aspectRatio);
     242                if (mousePos.y < mousePosStart.y)
     243                    y += h - newh;
     244                h = newh;
     245            }
     246        }
     247
     248        return new Rectangle(x,y,w,h);
     249    }
     250
     251    /**
     252    * If the action goes inactive, remove the selection rectangle from screen
     253    */
     254    public void propertyChange(PropertyChangeEvent evt) {
     255        if (evt.getPropertyName().equals("active") && !(Boolean)evt.getNewValue() && mousePosStart != null) {
     256            paintRect();
     257            mousePosStart = null;
     258            mousePos = null;
     259        }
     260    }
     261
     262    /**
     263    * Return a list of all objects in the rectangle, respecting the different
     264    * modifier.
     265    * @param alt Whether the alt key was pressed, which means select all objects
     266     *      that are touched, instead those which are completly covered.
     267    */
     268    public Collection<OsmPrimitive> getObjectsInRectangle(Rectangle r, boolean alt) {
     269        Collection<OsmPrimitive> selection = new LinkedList<OsmPrimitive>();
     270
     271        // whether user only clicked, not dragged.
     272        boolean clicked = r.width <= 2 && r.height <= 2;
     273        Point center = new Point(r.x+r.width/2, r.y+r.height/2);
     274
     275        if (clicked) {
     276            OsmPrimitive osm = nc.getNearest(center);
     277            if (osm != null)
     278                selection.add(osm);
     279        } else {
     280            // nodes
     281            for (Node n : nc.getData().nodes) {
     282                if (!n.deleted && !n.incomplete && r.contains(nc.getPoint(n.eastNorth)))
     283                    selection.add(n);
     284            }
     285
     286            // ways
     287            for (Way w : nc.getData().ways) {
     288                if (w.deleted || w.nodes.isEmpty() || w.incomplete)
     289                        continue;
     290                if (alt) {
     291                    for (Node n : w.nodes) {
     292                        if (!n.incomplete && r.contains(nc.getPoint(n.eastNorth))) {
     293                            selection.add(w);
     294                            break;
     295                        }
     296                    }
     297                } else {
     298                    boolean allIn = true;
     299                    for (Node n : w.nodes) {
     300                        if (!n.incomplete && !r.contains(nc.getPoint(n.eastNorth))) {
     301                            allIn = false;
     302                            break;
     303                        }
     304                    }
     305                    if (allIn) selection.add(w);
     306                }
     307            }
     308        }
     309        return selection;
     310    }
     311
     312    public void mouseClicked(MouseEvent e) {}
     313    public void mouseEntered(MouseEvent e) {}
     314    public void mouseExited(MouseEvent e) {}
     315    public void mouseMoved(MouseEvent e) {}
    316316}
  • trunk/src/org/openstreetmap/josm/gui/SideButton.java

    r1103 r1169  
    1212
    1313public class SideButton extends JButton {
    14         public SideButton(Action action)
    15         {
    16                 super(action);
    17                 doStyle();
    18                 setText(null);
    19         }
    20         public SideButton(String imagename, String property, String tooltip, ActionListener actionListener)
    21         {
    22                 super(ImageProvider.get("dialogs", imagename));
    23                 doStyle();
    24                 setActionCommand(imagename);
    25                 addActionListener(actionListener);
    26                 setToolTipText(tooltip);
    27         }
    28         @Deprecated
    29         public SideButton(String name, String imagename, String property, String tooltip, int mnemonic, ActionListener actionListener)
    30         {
    31                 super(tr(name), ImageProvider.get("dialogs", imagename));
    32                 setMnemonic(mnemonic);
    33                 setup(name, property, tooltip, actionListener);
    34         }
    35         public SideButton(String name, String imagename, String property, String tooltip, Shortcut shortcut, ActionListener actionListener)
    36         {
    37                 super(tr(name), ImageProvider.get("dialogs", imagename));
    38                 if(shortcut != null)
     14    public SideButton(Action action)
     15    {
     16        super(action);
     17        doStyle();
     18        setText(null);
     19    }
     20    public SideButton(String imagename, String property, String tooltip, ActionListener actionListener)
     21    {
     22        super(ImageProvider.get("dialogs", imagename));
     23        doStyle();
     24        setActionCommand(imagename);
     25        addActionListener(actionListener);
     26        setToolTipText(tooltip);
     27    }
     28    @Deprecated
     29    public SideButton(String name, String imagename, String property, String tooltip, int mnemonic, ActionListener actionListener)
     30    {
     31        super(tr(name), ImageProvider.get("dialogs", imagename));
     32        setMnemonic(mnemonic);
     33        setup(name, property, tooltip, actionListener);
     34    }
     35    public SideButton(String name, String imagename, String property, String tooltip, Shortcut shortcut, ActionListener actionListener)
     36    {
     37        super(tr(name), ImageProvider.get("dialogs", imagename));
     38        if(shortcut != null)
    3939                {
    40                         shortcut.setMnemonic(this);
     40            shortcut.setMnemonic(this);
    4141                        if(tooltip != null)
    42                                 tooltip = Main.platform.makeTooltip(tooltip, shortcut);
     42                tooltip = Main.platform.makeTooltip(tooltip, shortcut);
    4343                }
    44                 setup(name, property, tooltip, actionListener);
    45         }
    46         public SideButton(String name, String imagename, String property, String tooltip, ActionListener actionListener)
    47         {
    48                 super(tr(name), ImageProvider.get("dialogs", imagename));
    49                 setup(name, property, tooltip, actionListener);
    50         }
    51         private void setup(String name, String property, String tooltip, ActionListener actionListener)
    52         {
    53                 doStyle();
    54                 setActionCommand(name);
    55                 addActionListener(actionListener);
    56                 setToolTipText(tooltip);
    57                 putClientProperty("help", "Dialog/"+property+"/"+name);
    58         }
    59         private void doStyle()
    60         {
    61                 setMargin(new Insets(1,1,1,1));
    62                 setIconTextGap(2);
    63         }
     44        setup(name, property, tooltip, actionListener);
     45    }
     46    public SideButton(String name, String imagename, String property, String tooltip, ActionListener actionListener)
     47    {
     48        super(tr(name), ImageProvider.get("dialogs", imagename));
     49        setup(name, property, tooltip, actionListener);
     50    }
     51    private void setup(String name, String property, String tooltip, ActionListener actionListener)
     52    {
     53        doStyle();
     54        setActionCommand(name);
     55        addActionListener(actionListener);
     56        setToolTipText(tooltip);
     57        putClientProperty("help", "Dialog/"+property+"/"+name);
     58    }
     59    private void doStyle()
     60    {
     61        setMargin(new Insets(1,1,1,1));
     62        setIconTextGap(2);
     63    }
    6464}
  • trunk/src/org/openstreetmap/josm/gui/SplashScreen.java

    r1138 r1169  
    3030/**
    3131 * Show a splash screen so the user knows what is happening during startup.
    32  * 
    33  * @author cbrill 
     32 *
     33 * @author cbrill
    3434 */
    3535public class SplashScreen extends JWindow {
    3636
    37         private JLabel status;
    38         private boolean visible;
     37    private JLabel status;
     38    private boolean visible;
    3939
    40         private Runnable closerRunner;
     40    private Runnable closerRunner;
    4141
    42         public SplashScreen(boolean visible) {
    43                 super();
    44                 this.visible=visible;
     42    public SplashScreen(boolean visible) {
     43        super();
     44        this.visible=visible;
    4545
    46                 if (!visible)
    47                         return;
     46        if (!visible)
     47            return;
    4848
    49                 // Add a nice border to the main splash screen
    50                 JPanel contentPane = (JPanel)this.getContentPane();
    51                 Border margin = new EtchedBorder(1, Color.white, Color.gray);
    52                 contentPane.setBorder(margin);
     49        // Add a nice border to the main splash screen
     50        JPanel contentPane = (JPanel)this.getContentPane();
     51        Border margin = new EtchedBorder(1, Color.white, Color.gray);
     52        contentPane.setBorder(margin);
    5353
    54                 // Add a margin from the border to the content
    55                 JPanel innerContentPane = new JPanel();
    56                 innerContentPane.setBorder(new EmptyBorder(10, 10, 2, 10));
    57                 contentPane.add(innerContentPane);
    58                 innerContentPane.setLayout(new GridBagLayout());
     54        // Add a margin from the border to the content
     55        JPanel innerContentPane = new JPanel();
     56        innerContentPane.setBorder(new EmptyBorder(10, 10, 2, 10));
     57        contentPane.add(innerContentPane);
     58        innerContentPane.setLayout(new GridBagLayout());
    5959
    60                 // Add the logo
    61                 JLabel logo = new JLabel(ImageProvider.get("logo.png"));
    62                 GridBagConstraints gbc = new GridBagConstraints();
    63                 gbc.gridheight = 2;
    64                 innerContentPane.add(logo, gbc);
     60        // Add the logo
     61        JLabel logo = new JLabel(ImageProvider.get("logo.png"));
     62        GridBagConstraints gbc = new GridBagConstraints();
     63        gbc.gridheight = 2;
     64        innerContentPane.add(logo, gbc);
    6565
    66                 // Add the name of this application
    67                 JLabel caption = new JLabel(tr("JOSM - Java OpenStreetMap Editor"));
    68                 caption.setFont(new Font("Helvetica", Font.BOLD, 20));
    69                 gbc.gridheight = 1;
    70                 gbc.gridx = 1;
    71                 gbc.insets = new Insets(30, 0, 0, 0);
    72                 innerContentPane.add(caption, gbc);
     66        // Add the name of this application
     67        JLabel caption = new JLabel(tr("JOSM - Java OpenStreetMap Editor"));
     68        caption.setFont(new Font("Helvetica", Font.BOLD, 20));
     69        gbc.gridheight = 1;
     70        gbc.gridx = 1;
     71        gbc.insets = new Insets(30, 0, 0, 0);
     72        innerContentPane.add(caption, gbc);
    7373
    74                 // Add the version number
    75                 JLabel version = new JLabel(tr("Version {0}", AboutAction.getVersionString()));
    76                 gbc.gridy = 1;
    77                 gbc.insets = new Insets(0, 0, 0, 0);
    78                 innerContentPane.add(version, gbc);
     74        // Add the version number
     75        JLabel version = new JLabel(tr("Version {0}", AboutAction.getVersionString()));
     76        gbc.gridy = 1;
     77        gbc.insets = new Insets(0, 0, 0, 0);
     78        innerContentPane.add(version, gbc);
    7979
    80                 // Add a separator to the status text
    81                 JSeparator separator = new JSeparator(JSeparator.HORIZONTAL);
    82                 gbc.gridx = 0;
    83                 gbc.gridy = 2;
    84                 gbc.gridwidth = 2;
    85                 gbc.fill = GridBagConstraints.HORIZONTAL;
    86                 gbc.insets = new Insets(15, 0, 5, 0);
    87                 innerContentPane.add(separator, gbc);
     80        // Add a separator to the status text
     81        JSeparator separator = new JSeparator(JSeparator.HORIZONTAL);
     82        gbc.gridx = 0;
     83        gbc.gridy = 2;
     84        gbc.gridwidth = 2;
     85        gbc.fill = GridBagConstraints.HORIZONTAL;
     86        gbc.insets = new Insets(15, 0, 5, 0);
     87        innerContentPane.add(separator, gbc);
    8888
    89                 // Add a status message
    90                 status = new JLabel();
    91                 gbc.gridy = 3;
    92                 gbc.insets = new Insets(0, 0, 0, 0);
    93                 innerContentPane.add(status, gbc);
    94                 setStatus(tr("Initializing"));
     89        // Add a status message
     90        status = new JLabel();
     91        gbc.gridy = 3;
     92        gbc.insets = new Insets(0, 0, 0, 0);
     93        innerContentPane.add(status, gbc);
     94        setStatus(tr("Initializing"));
    9595
    96                 pack();
     96        pack();
    9797
    98                 // Center the splash screen
    99                 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    100                 Dimension labelSize = contentPane.getPreferredSize();
    101                 setLocation(screenSize.width / 2 - (labelSize.width / 2),
    102                         screenSize.height / 2 - (labelSize.height / 2));
     98        // Center the splash screen
     99        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
     100        Dimension labelSize = contentPane.getPreferredSize();
     101        setLocation(screenSize.width / 2 - (labelSize.width / 2),
     102                screenSize.height / 2 - (labelSize.height / 2));
    103103
    104                 // Method to close the splash screen when being clicked or when closeSplash is called
    105                 closerRunner = new Runnable() {
    106                         public void run() {
    107                                 setVisible(false);
    108                                 dispose();
    109                         }
    110                 };
     104        // Method to close the splash screen when being clicked or when closeSplash is called
     105        closerRunner = new Runnable() {
     106            public void run() {
     107                setVisible(false);
     108                dispose();
     109            }
     110        };
    111111
    112                 // Add ability to hide splash screen by clicking it
    113                 addMouseListener(new MouseAdapter() {
    114                         public void mousePressed(MouseEvent event) {
    115                                 try {
    116                                         closerRunner.run();
    117                                 } catch (Exception e) {
    118                                         e.printStackTrace();
    119                                         // can catch InvocationTargetException
    120                                         // can catch InterruptedException
    121                                 }
    122                         }
    123                 });
    124                
     112        // Add ability to hide splash screen by clicking it
     113        addMouseListener(new MouseAdapter() {
     114            public void mousePressed(MouseEvent event) {
     115                try {
     116                    closerRunner.run();
     117                } catch (Exception e) {
     118                    e.printStackTrace();
     119                    // can catch InvocationTargetException
     120                    // can catch InterruptedException
     121                }
     122            }
     123        });
     124
    125125        // Hide splashscreen when other window is created
    126                 Toolkit.getDefaultToolkit().addAWTEventListener(awtListener, AWTEvent.WINDOW_EVENT_MASK);
    127                
    128                 setVisible(true);
    129         }
    130        
    131         private AWTEventListener awtListener = new AWTEventListener() {
    132                 public void eventDispatched(AWTEvent event) {
    133                         if (event.getSource() != SplashScreen.this) {
    134                                 closeSplash();
    135                         }
    136                 }               
    137         };
     126        Toolkit.getDefaultToolkit().addAWTEventListener(awtListener, AWTEvent.WINDOW_EVENT_MASK);
    138127
    139         /**
    140          * This method sets the status message. It should be called prior to
    141          * actually doing the action.
    142          *
    143          * @param message
    144          *            the message to be displayed
    145          */
    146         public void setStatus(String message) {
    147                 if (!visible)
    148                         return;
    149                 status.setText(message + " ...");
    150         }
     128        setVisible(true);
     129    }
    151130
    152         /**
    153          * Closes the splashscreen. Call once you are done starting.
    154          */
    155         public void closeSplash() {
    156                 if (!visible)
    157                         return;
    158                 Toolkit.getDefaultToolkit().removeAWTEventListener(awtListener);
    159                 try {
    160                         SwingUtilities.invokeLater(closerRunner);
    161                 } catch (Exception e) {
    162                         e.printStackTrace();
    163                         // can catch InvocationTargetException
    164                         // can catch InterruptedException
    165                 }
    166         }
     131    private AWTEventListener awtListener = new AWTEventListener() {
     132        public void eventDispatched(AWTEvent event) {
     133            if (event.getSource() != SplashScreen.this) {
     134                closeSplash();
     135            }
     136        }
     137    };
     138
     139    /**
     140     * This method sets the status message. It should be called prior to
     141     * actually doing the action.
     142     *
     143     * @param message
     144     *            the message to be displayed
     145     */
     146    public void setStatus(String message) {
     147        if (!visible)
     148            return;
     149        status.setText(message + " ...");
     150    }
     151
     152    /**
     153     * Closes the splashscreen. Call once you are done starting.
     154     */
     155    public void closeSplash() {
     156        if (!visible)
     157            return;
     158        Toolkit.getDefaultToolkit().removeAWTEventListener(awtListener);
     159        try {
     160            SwingUtilities.invokeLater(closerRunner);
     161        } catch (Exception e) {
     162            e.printStackTrace();
     163            // can catch InvocationTargetException
     164            // can catch InterruptedException
     165        }
     166    }
    167167
    168168}
  • trunk/src/org/openstreetmap/josm/gui/dialogs/CommandStackDialog.java

    r1084 r1169  
    2424public class CommandStackDialog extends ToggleDialog implements CommandQueueListener {
    2525
    26         private DefaultTreeModel treeModel = new DefaultTreeModel(new DefaultMutableTreeNode());
     26    private DefaultTreeModel treeModel = new DefaultTreeModel(new DefaultMutableTreeNode());
    2727    private JTree tree = new JTree(treeModel);
    2828
    29         public CommandStackDialog(final MapFrame mapFrame) {
    30                 super(tr("Command Stack"), "commandstack", tr("Open a list of all commands (undo buffer)."),
    31                 Shortcut.registerShortcut("subwindow:commandstack", tr("Toggle: {0}", tr("Command Stack")), KeyEvent.VK_O, Shortcut.GROUP_LAYER), 100);
    32                 Main.main.undoRedo.listenerCommands.add(this);
     29    public CommandStackDialog(final MapFrame mapFrame) {
     30        super(tr("Command Stack"), "commandstack", tr("Open a list of all commands (undo buffer)."),
     31        Shortcut.registerShortcut("subwindow:commandstack", tr("Toggle: {0}", tr("Command Stack")), KeyEvent.VK_O, Shortcut.GROUP_LAYER), 100);
     32        Main.main.undoRedo.listenerCommands.add(this);
    3333
    34                 tree.setRootVisible(false);
    35                 tree.setShowsRootHandles(true);
    36                 tree.expandRow(0);
    37                 tree.setCellRenderer(new DefaultTreeCellRenderer(){
    38                         @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
    39                                 super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
    40                                 DefaultMutableTreeNode v = (DefaultMutableTreeNode)value;
    41                                 if (v.getUserObject() instanceof JLabel) {
    42                                         JLabel l = (JLabel)v.getUserObject();
    43                                         setIcon(l.getIcon());
    44                                         setText(l.getText());
    45                                 }
    46                                 return this;
    47                         }
    48                 });
    49                 tree.setVisibleRowCount(8);
    50                 add(new JScrollPane(tree), BorderLayout.CENTER);
    51         }
     34        tree.setRootVisible(false);
     35        tree.setShowsRootHandles(true);
     36        tree.expandRow(0);
     37        tree.setCellRenderer(new DefaultTreeCellRenderer(){
     38            @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
     39                super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
     40                DefaultMutableTreeNode v = (DefaultMutableTreeNode)value;
     41                if (v.getUserObject() instanceof JLabel) {
     42                    JLabel l = (JLabel)v.getUserObject();
     43                    setIcon(l.getIcon());
     44                    setText(l.getText());
     45                }
     46                return this;
     47            }
     48        });
     49        tree.setVisibleRowCount(8);
     50        add(new JScrollPane(tree), BorderLayout.CENTER);
     51    }
    5252
    53         @Override public void setVisible(boolean v) {
    54                 if (v)
    55                         buildList();
    56                 else if (tree != null)
    57                         treeModel.setRoot(new DefaultMutableTreeNode());
    58                 super.setVisible(v);
    59         }
     53    @Override public void setVisible(boolean v) {
     54        if (v)
     55            buildList();
     56        else if (tree != null)
     57            treeModel.setRoot(new DefaultMutableTreeNode());
     58        super.setVisible(v);
     59    }
    6060
    61         private void buildList() {
    62                 if (Main.map == null || Main.map.mapView == null || Main.map.mapView.editLayer == null)
    63                         return;
    64                 Collection<Command> commands = Main.main.undoRedo.commands;
    65                 DefaultMutableTreeNode root = new DefaultMutableTreeNode();
    66                 for (Command c : commands)
    67                         root.add(c.description());
    68                 treeModel.setRoot(root);
    69                 tree.scrollRowToVisible(treeModel.getChildCount(root)-1);
    70         }
     61    private void buildList() {
     62        if (Main.map == null || Main.map.mapView == null || Main.map.mapView.editLayer == null)
     63            return;
     64        Collection<Command> commands = Main.main.undoRedo.commands;
     65        DefaultMutableTreeNode root = new DefaultMutableTreeNode();
     66        for (Command c : commands)
     67            root.add(c.description());
     68        treeModel.setRoot(root);
     69        tree.scrollRowToVisible(treeModel.getChildCount(root)-1);
     70    }
    7171
    72         public void commandChanged(int queueSize, int redoSize) {
    73                 if (!isVisible())
    74                         return;
     72    public void commandChanged(int queueSize, int redoSize) {
     73        if (!isVisible())
     74            return;
    7575        treeModel.setRoot(new DefaultMutableTreeNode());
    76                 buildList();
     76        buildList();
    7777    }
    7878}
  • trunk/src/org/openstreetmap/josm/gui/dialogs/ConflictDialog.java

    r1117 r1169  
    4747public final class ConflictDialog extends ToggleDialog {
    4848
    49         public final Map<OsmPrimitive, OsmPrimitive> conflicts = new HashMap<OsmPrimitive, OsmPrimitive>();
    50         private final DefaultListModel model = new DefaultListModel();
    51         private final JList displaylist = new JList(model);
     49    public final Map<OsmPrimitive, OsmPrimitive> conflicts = new HashMap<OsmPrimitive, OsmPrimitive>();
     50    private final DefaultListModel model = new DefaultListModel();
     51    private final JList displaylist = new JList(model);
    5252
    53         public ConflictDialog() {
    54                 super(tr("Conflict"), "conflict", tr("Merging conflicts."),
    55                 Shortcut.registerShortcut("subwindow:conflict", tr("Toggle: {0}", tr("Conflict")), KeyEvent.VK_C, Shortcut.GROUP_LAYER), 100);
    56                 displaylist.setCellRenderer(new OsmPrimitivRenderer());
    57                 displaylist.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
    58                 displaylist.addMouseListener(new MouseAdapter(){
    59                         @Override public void mouseClicked(MouseEvent e) {
    60                                 if (e.getClickCount() >= 2)
    61                                         resolve();
    62                         }
    63                 });
    64                 add(new JScrollPane(displaylist), BorderLayout.CENTER);
     53    public ConflictDialog() {
     54        super(tr("Conflict"), "conflict", tr("Merging conflicts."),
     55        Shortcut.registerShortcut("subwindow:conflict", tr("Toggle: {0}", tr("Conflict")), KeyEvent.VK_C, Shortcut.GROUP_LAYER), 100);
     56        displaylist.setCellRenderer(new OsmPrimitivRenderer());
     57        displaylist.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
     58        displaylist.addMouseListener(new MouseAdapter(){
     59            @Override public void mouseClicked(MouseEvent e) {
     60                if (e.getClickCount() >= 2)
     61                    resolve();
     62            }
     63        });
     64        add(new JScrollPane(displaylist), BorderLayout.CENTER);
    6565
    66                 JPanel buttonPanel = new JPanel(new GridLayout(1,2));
    67                 buttonPanel.add(new SideButton(marktr("Resolve"), "conflict", "Conflict",
    68                 tr("Open a merge dialog of all selected items in the list above."), new ActionListener(){
    69                         public void actionPerformed(ActionEvent e) {
    70                                 resolve();
    71                         }
    72                 }));
     66        JPanel buttonPanel = new JPanel(new GridLayout(1,2));
     67        buttonPanel.add(new SideButton(marktr("Resolve"), "conflict", "Conflict",
     68        tr("Open a merge dialog of all selected items in the list above."), new ActionListener(){
     69            public void actionPerformed(ActionEvent e) {
     70                resolve();
     71            }
     72        }));
    7373
    74                 buttonPanel.add(new SideButton(marktr("Select"), "select", "Conflict",
    75                 tr("Set the selected elements on the map to the selected items in the list above."), new ActionListener(){
    76                         public void actionPerformed(ActionEvent e) {
    77                                 Collection<OsmPrimitive> sel = new LinkedList<OsmPrimitive>();
    78                                 for (Object o : displaylist.getSelectedValues())
    79                                         sel.add((OsmPrimitive)o);
    80                                 Main.ds.setSelected(sel);
    81                         }
    82                 }));
    83                 add(buttonPanel, BorderLayout.SOUTH);
     74        buttonPanel.add(new SideButton(marktr("Select"), "select", "Conflict",
     75        tr("Set the selected elements on the map to the selected items in the list above."), new ActionListener(){
     76            public void actionPerformed(ActionEvent e) {
     77                Collection<OsmPrimitive> sel = new LinkedList<OsmPrimitive>();
     78                for (Object o : displaylist.getSelectedValues())
     79                    sel.add((OsmPrimitive)o);
     80                Main.ds.setSelected(sel);
     81            }
     82        }));
     83        add(buttonPanel, BorderLayout.SOUTH);
    8484
    85                 DataSet.selListeners.add(new SelectionChangedListener(){
    86                         public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
    87                                 displaylist.clearSelection();
    88                                 for (OsmPrimitive osm : newSelection) {
    89                                         if (conflicts.containsKey(osm)) {
    90                                                 int pos = model.indexOf(osm);
    91                                                 displaylist.addSelectionInterval(pos, pos);
    92                                         }
    93                                 }
    94                         }
    95                 });
    96                 displaylist.getSelectionModel().addListSelectionListener(new ListSelectionListener(){
    97                         public void valueChanged(ListSelectionEvent e) {
    98                                 Main.map.mapView.repaint();
    99                         }
    100                 });
    101         }
     85        DataSet.selListeners.add(new SelectionChangedListener(){
     86            public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
     87                displaylist.clearSelection();
     88                for (OsmPrimitive osm : newSelection) {
     89                    if (conflicts.containsKey(osm)) {
     90                        int pos = model.indexOf(osm);
     91                        displaylist.addSelectionInterval(pos, pos);
     92                    }
     93                }
     94            }
     95        });
     96        displaylist.getSelectionModel().addListSelectionListener(new ListSelectionListener(){
     97            public void valueChanged(ListSelectionEvent e) {
     98                Main.map.mapView.repaint();
     99            }
     100        });
     101    }
    102102
    103         private final void resolve() {
    104                 if (displaylist.getSelectedIndex() == -1) {
    105                         JOptionPane.showMessageDialog(Main.parent,tr("Please select something from the conflict list."));
    106                         return;
    107                 }
    108                 Map<OsmPrimitive, OsmPrimitive> sel = new HashMap<OsmPrimitive, OsmPrimitive>();
    109                 for (int i : displaylist.getSelectedIndices()) {
    110                         OsmPrimitive s = (OsmPrimitive)model.get(i);
    111                         sel.put(s, conflicts.get(s));
    112                 }
    113                 ConflictResolver resolver = new ConflictResolver(sel);
    114                 int answer = JOptionPane.showConfirmDialog(Main.parent, resolver, tr("Resolve Conflicts"), JOptionPane.OK_CANCEL_OPTION);
    115                 if (answer != JOptionPane.OK_OPTION)
    116                         return;
    117                 Main.main.undoRedo.add(new ConflictResolveCommand(resolver.conflicts, sel));
    118                 Main.map.mapView.repaint();
    119         }
     103    private final void resolve() {
     104        if (displaylist.getSelectedIndex() == -1) {
     105            JOptionPane.showMessageDialog(Main.parent,tr("Please select something from the conflict list."));
     106            return;
     107        }
     108        Map<OsmPrimitive, OsmPrimitive> sel = new HashMap<OsmPrimitive, OsmPrimitive>();
     109        for (int i : displaylist.getSelectedIndices()) {
     110            OsmPrimitive s = (OsmPrimitive)model.get(i);
     111            sel.put(s, conflicts.get(s));
     112        }
     113        ConflictResolver resolver = new ConflictResolver(sel);
     114        int answer = JOptionPane.showConfirmDialog(Main.parent, resolver, tr("Resolve Conflicts"), JOptionPane.OK_CANCEL_OPTION);
     115        if (answer != JOptionPane.OK_OPTION)
     116            return;
     117        Main.main.undoRedo.add(new ConflictResolveCommand(resolver.conflicts, sel));
     118        Main.map.mapView.repaint();
     119    }
    120120
    121         public final void rebuildList() {
    122                 model.removeAllElements();
    123                 for (OsmPrimitive osm : this.conflicts.keySet())
    124                         if (osm instanceof Node)
    125                                 model.addElement(osm);
    126                 for (OsmPrimitive osm : this.conflicts.keySet())
    127                         if (osm instanceof Way)
    128                                 model.addElement(osm);
     121    public final void rebuildList() {
     122        model.removeAllElements();
     123        for (OsmPrimitive osm : this.conflicts.keySet())
     124            if (osm instanceof Node)
     125                model.addElement(osm);
     126        for (OsmPrimitive osm : this.conflicts.keySet())
     127            if (osm instanceof Way)
     128                model.addElement(osm);
    129129        for (OsmPrimitive osm : this.conflicts.keySet())
    130130            if (osm instanceof Relation)
     
    132132    }
    133133
    134         public final void add(Map<OsmPrimitive, OsmPrimitive> conflicts) {
    135                 this.conflicts.putAll(conflicts);
    136                 rebuildList();
    137         }
     134    public final void add(Map<OsmPrimitive, OsmPrimitive> conflicts) {
     135        this.conflicts.putAll(conflicts);
     136        rebuildList();
     137    }
    138138
    139         /**
    140         * Paint all conflicts that can be expressed on the main window.
    141         */
    142         public void paintConflicts(final Graphics g, final NavigatableComponent nc) {
    143                 Color preferencesColor = Main.pref.getColor("conflict", Color.gray);
    144                 if (preferencesColor.equals(Color.BLACK))
    145                         return;
    146                 g.setColor(preferencesColor);
    147                 Visitor conflictPainter = new Visitor(){
    148                         public void visit(Node n) {
    149                                 Point p = nc.getPoint(n.eastNorth);
    150                                 g.drawRect(p.x-1, p.y-1, 2, 2);
    151                         }
    152                         public void visit(Node n1, Node n2) {
    153                                 Point p1 = nc.getPoint(n1.eastNorth);
    154                                 Point p2 = nc.getPoint(n2.eastNorth);
    155                                 g.drawLine(p1.x, p1.y, p2.x, p2.y);
    156                         }
    157                         public void visit(Way w) {
    158                                 Node lastN = null;
    159                                 for (Node n : w.nodes) {
    160                                         if (lastN == null) {
    161                                                 lastN = n;
    162                                                 continue;
    163                                         }
    164                                         visit(lastN, n);
    165                                         lastN = n;
    166                                 }
    167                         }
    168                         public void visit(Relation e) {
    169                                 for (RelationMember em : e.members)
    170                                         em.member.visit(this);
    171                         }
    172                 };
    173                 for (Object o : displaylist.getSelectedValues())
    174                         conflicts.get(o).visit(conflictPainter);
    175         }
     139    /**
     140    * Paint all conflicts that can be expressed on the main window.
     141    */
     142    public void paintConflicts(final Graphics g, final NavigatableComponent nc) {
     143        Color preferencesColor = Main.pref.getColor("conflict", Color.gray);
     144        if (preferencesColor.equals(Color.BLACK))
     145            return;
     146        g.setColor(preferencesColor);
     147        Visitor conflictPainter = new Visitor(){
     148            public void visit(Node n) {
     149                Point p = nc.getPoint(n.eastNorth);
     150                g.drawRect(p.x-1, p.y-1, 2, 2);
     151            }
     152            public void visit(Node n1, Node n2) {
     153                Point p1 = nc.getPoint(n1.eastNorth);
     154                Point p2 = nc.getPoint(n2.eastNorth);
     155                g.drawLine(p1.x, p1.y, p2.x, p2.y);
     156            }
     157            public void visit(Way w) {
     158                Node lastN = null;
     159                for (Node n : w.nodes) {
     160                    if (lastN == null) {
     161                        lastN = n;
     162                        continue;
     163                    }
     164                    visit(lastN, n);
     165                    lastN = n;
     166                }
     167            }
     168            public void visit(Relation e) {
     169                for (RelationMember em : e.members)
     170                    em.member.visit(this);
     171            }
     172        };
     173        for (Object o : displaylist.getSelectedValues())
     174            conflicts.get(o).visit(conflictPainter);
     175    }
    176176}
  • trunk/src/org/openstreetmap/josm/gui/dialogs/HistoryDialog.java

    r1084 r1169  
    5454public class HistoryDialog extends ToggleDialog implements SelectionChangedListener {
    5555
    56         public static final Date unifyDate(Date d) {
    57                 Calendar c = Calendar.getInstance();
    58                 c.setTime(d);
    59                 c.set(Calendar.MINUTE, 0);
    60                 c.set(Calendar.SECOND, 0);
    61                 return c.getTime();
    62         }
     56    public static final Date unifyDate(Date d) {
     57        Calendar c = Calendar.getInstance();
     58        c.setTime(d);
     59        c.set(Calendar.MINUTE, 0);
     60        c.set(Calendar.SECOND, 0);
     61        return c.getTime();
     62    }
    6363
    64         private static class HistoryItem implements Comparable<HistoryItem> {
    65                 OsmPrimitive osm;
    66                 boolean visible;
     64    private static class HistoryItem implements Comparable<HistoryItem> {
     65        OsmPrimitive osm;
     66        boolean visible;
    6767
    68                 public int compareTo(HistoryItem o) {
    69                         return unifyDate(osm.getTimestamp()).compareTo(unifyDate(o.osm.getTimestamp()));
    70                 }
    71         }
     68        public int compareTo(HistoryItem o) {
     69            return unifyDate(osm.getTimestamp()).compareTo(unifyDate(o.osm.getTimestamp()));
     70        }
     71    }
    7272
    73         private final DefaultTableModel data = new DefaultTableModel(){
    74                 @Override public boolean isCellEditable(int row, int column) {
    75                         return false;
    76                 }
    77         };
     73    private final DefaultTableModel data = new DefaultTableModel(){
     74        @Override public boolean isCellEditable(int row, int column) {
     75            return false;
     76        }
     77    };
    7878
    79         /**
    80         * Main table. 3 columns:
    81         * Object | Date | visible (icon, no text)
    82         */
    83         private JTable history = new JTable(data);
    84         private JScrollPane historyPane = new JScrollPane(history);
     79    /**
     80    * Main table. 3 columns:
     81    * Object | Date | visible (icon, no text)
     82    */
     83    private JTable history = new JTable(data);
     84    private JScrollPane historyPane = new JScrollPane(history);
    8585
    86         private Map<OsmPrimitive, List<HistoryItem>> cache = new HashMap<OsmPrimitive, List<HistoryItem>>();
    87         private JLabel notLoaded = new JLabel("<html><i>"+tr("Click Reload to refresh list")+"</i></html>");
     86    private Map<OsmPrimitive, List<HistoryItem>> cache = new HashMap<OsmPrimitive, List<HistoryItem>>();
     87    private JLabel notLoaded = new JLabel("<html><i>"+tr("Click Reload to refresh list")+"</i></html>");
    8888
    89         public HistoryDialog() {
    90                 super(tr("History"), "history", tr("Display the history of all selected items."),
    91                 Shortcut.registerShortcut("subwindow:history", tr("Toggle: {0}", tr("History")), KeyEvent.VK_H,
    92                 Shortcut.GROUP_LAYER, Shortcut.SHIFT_DEFAULT), 150);
    93                 historyPane.setVisible(false);
    94                 notLoaded.setVisible(true);
    95                 notLoaded.setHorizontalAlignment(JLabel.CENTER);
     89    public HistoryDialog() {
     90        super(tr("History"), "history", tr("Display the history of all selected items."),
     91        Shortcut.registerShortcut("subwindow:history", tr("Toggle: {0}", tr("History")), KeyEvent.VK_H,
     92        Shortcut.GROUP_LAYER, Shortcut.SHIFT_DEFAULT), 150);
     93        historyPane.setVisible(false);
     94        notLoaded.setVisible(true);
     95        notLoaded.setHorizontalAlignment(JLabel.CENTER);
    9696
    97                 history.setDefaultRenderer(Object.class, new DefaultTableCellRenderer(){
    98                         @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    99                                 return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
    100                         }
    101                 });
    102                 data.setColumnIdentifiers(new Object[]{tr("Object"),tr("Date"),""});
    103                 history.getColumnModel().getColumn(0).setPreferredWidth(200);
    104                 history.getColumnModel().getColumn(1).setPreferredWidth(200);
    105                 history.getColumnModel().getColumn(2).setPreferredWidth(20);
    106                 final TableCellRenderer oldRenderer = history.getTableHeader().getDefaultRenderer();
    107                 history.getTableHeader().setDefaultRenderer(new DefaultTableCellRenderer(){
    108                         @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    109                                 JComponent c = (JComponent)oldRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
    110                                 if (!value.equals(""))
    111                                         return c;
    112                                 JLabel l = new JLabel(ImageProvider.get("misc","showhide"));
    113                                 l.setForeground(c.getForeground());
    114                                 l.setBackground(c.getBackground());
    115                                 l.setFont(c.getFont());
    116                                 l.setBorder(c.getBorder());
    117                                 l.setOpaque(true);
    118                                 return l;
    119                         }
    120                 });
     97        history.setDefaultRenderer(Object.class, new DefaultTableCellRenderer(){
     98            @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
     99                return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
     100            }
     101        });
     102        data.setColumnIdentifiers(new Object[]{tr("Object"),tr("Date"),""});
     103        history.getColumnModel().getColumn(0).setPreferredWidth(200);
     104        history.getColumnModel().getColumn(1).setPreferredWidth(200);
     105        history.getColumnModel().getColumn(2).setPreferredWidth(20);
     106        final TableCellRenderer oldRenderer = history.getTableHeader().getDefaultRenderer();
     107        history.getTableHeader().setDefaultRenderer(new DefaultTableCellRenderer(){
     108            @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
     109                JComponent c = (JComponent)oldRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
     110                if (!value.equals(""))
     111                    return c;
     112                JLabel l = new JLabel(ImageProvider.get("misc","showhide"));
     113                l.setForeground(c.getForeground());
     114                l.setBackground(c.getBackground());
     115                l.setFont(c.getFont());
     116                l.setBorder(c.getBorder());
     117                l.setOpaque(true);
     118                return l;
     119            }
     120        });
    121121
    122                 JPanel centerPanel = new JPanel(new GridBagLayout());
    123                 centerPanel.add(notLoaded, GBC.eol().fill(GBC.BOTH));
    124                 centerPanel.add(historyPane, GBC.eol().fill(GBC.BOTH));
    125                 add(centerPanel, BorderLayout.CENTER);
     122        JPanel centerPanel = new JPanel(new GridBagLayout());
     123        centerPanel.add(notLoaded, GBC.eol().fill(GBC.BOTH));
     124        centerPanel.add(historyPane, GBC.eol().fill(GBC.BOTH));
     125        add(centerPanel, BorderLayout.CENTER);
    126126
    127                 JPanel buttons = new JPanel(new GridLayout(1,2));
    128                 buttons.add(new SideButton(marktr("Reload"), "refresh", "History", tr("Reload all currently selected objects and refresh the list."),
    129                 new ActionListener(){
    130                         public void actionPerformed(ActionEvent e) {
    131                                 reload();
    132                         }
    133                 }));
    134                 buttons.add(new SideButton(marktr("Revert"), "revert", "History",
    135                 tr("Revert the state of all currently selected objects to the version selected in the history list."), new ActionListener(){
    136                         public void actionPerformed(ActionEvent e) {
    137                                 JOptionPane.showMessageDialog(Main.parent, tr("Not implemented yet."));
    138                         }
    139                 }));
    140                 add(buttons, BorderLayout.SOUTH);
     127        JPanel buttons = new JPanel(new GridLayout(1,2));
     128        buttons.add(new SideButton(marktr("Reload"), "refresh", "History", tr("Reload all currently selected objects and refresh the list."),
     129        new ActionListener(){
     130            public void actionPerformed(ActionEvent e) {
     131                reload();
     132            }
     133        }));
     134        buttons.add(new SideButton(marktr("Revert"), "revert", "History",
     135        tr("Revert the state of all currently selected objects to the version selected in the history list."), new ActionListener(){
     136            public void actionPerformed(ActionEvent e) {
     137                JOptionPane.showMessageDialog(Main.parent, tr("Not implemented yet."));
     138            }
     139        }));
     140        add(buttons, BorderLayout.SOUTH);
    141141
    142                 DataSet.selListeners.add(this);
    143         }
     142        DataSet.selListeners.add(this);
     143    }
    144144
    145145
    146         @Override public void setVisible(boolean b) {
    147                 super.setVisible(b);
    148                 if (b)
    149                         update();
    150         }
     146    @Override public void setVisible(boolean b) {
     147        super.setVisible(b);
     148        if (b)
     149            update();
     150    }
    151151
    152152
    153         public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
    154                 if (isVisible())
    155                         update();
    156         }
     153    public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
     154        if (isVisible())
     155            update();
     156    }
    157157
    158         /**
    159         * Identify all new objects in the selection and if any, hide the list.
    160         * Else, update the list with the selected items shown.
    161         */
    162         private void update() {
    163                 Collection<OsmPrimitive> sel = Main.ds.getSelected();
    164                 if (!cache.keySet().containsAll(sel)) {
    165                         historyPane.setVisible(false);
    166                         notLoaded.setVisible(true);
    167                 } else {
    168                         SortedSet<HistoryItem> orderedHistory = new TreeSet<HistoryItem>();
    169                         for (OsmPrimitive osm : sel)
    170                                 orderedHistory.addAll(cache.get(osm));
    171                         data.setRowCount(0);
    172                         for (HistoryItem i : orderedHistory)
    173                                 data.addRow(new Object[]{i.osm, i.osm.timestamp, i.visible});
    174                         historyPane.setVisible(true);
    175                         notLoaded.setVisible(false);
    176                 }
    177         }
     158    /**
     159    * Identify all new objects in the selection and if any, hide the list.
     160    * Else, update the list with the selected items shown.
     161    */
     162    private void update() {
     163        Collection<OsmPrimitive> sel = Main.ds.getSelected();
     164        if (!cache.keySet().containsAll(sel)) {
     165            historyPane.setVisible(false);
     166            notLoaded.setVisible(true);
     167        } else {
     168            SortedSet<HistoryItem> orderedHistory = new TreeSet<HistoryItem>();
     169            for (OsmPrimitive osm : sel)
     170                orderedHistory.addAll(cache.get(osm));
     171            data.setRowCount(0);
     172            for (HistoryItem i : orderedHistory)
     173                data.addRow(new Object[]{i.osm, i.osm.timestamp, i.visible});
     174            historyPane.setVisible(true);
     175            notLoaded.setVisible(false);
     176        }
     177    }
    178178
    179         void reload() {
    180                 JOptionPane.showMessageDialog(Main.parent, tr("Not implemented yet."));
    181         }
     179    void reload() {
     180        JOptionPane.showMessageDialog(Main.parent, tr("Not implemented yet."));
     181    }
    182182}
  • trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java

    r1084 r1169  
    5050public class LayerListDialog extends ToggleDialog implements LayerChangeListener {
    5151
    52         /**
    53         * The last layerlist created. Used to update the list in the Show/Hide and Delete actions.
    54         * TODO: Replace with Listener-Pattern.
    55         */
    56         static JList instance;
    57         private JScrollPane listScrollPane;
    58 
    59         public final static class DeleteLayerAction extends AbstractAction {
    60 
    61                 private final Layer layer;
    62 
    63                 public DeleteLayerAction(Layer layer) {
    64                         super(tr("Delete"), ImageProvider.get("dialogs", "delete"));
    65                         putValue(SHORT_DESCRIPTION, tr("Delete the selected layer."));
    66                         putValue("help", "Action/LayerDelete");
    67                         this.layer = layer;
    68                 }
    69 
    70                 public void actionPerformed(ActionEvent e) {
    71                         int sel = instance.getSelectedIndex();
    72                         Layer l = layer != null ? layer : (Layer)instance.getSelectedValue();
    73                         if(l == null)
    74                                 return;
    75                         if (l instanceof OsmDataLayer)
    76                         {
    77                                 if (((OsmDataLayer)l).isModified())
    78                                 {
    79                                         if(JOptionPane.showConfirmDialog(instance, tr("There are unsaved changes. Delete the layer anwyay?"),
    80                                         tr("Unsaved Changes"), JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION)
    81                                                 return;
    82                                 }
    83                                 else if(!DontShowAgainInfo.show("delete_layer", tr("Do you really want to delete the whole layer?"), false))
    84                                         return;
    85                         }
    86                         Main.main.removeLayer(l);
    87                         if (sel >= instance.getModel().getSize())
    88                                 sel = instance.getModel().getSize()-1;
    89                         if (instance.getSelectedValue() == null)
    90                                 instance.setSelectedIndex(sel);
    91                         if (Main.map != null)
    92                                 Main.map.mapView.setActiveLayer((Layer)instance.getSelectedValue());
    93                 }
    94         }
    95 
    96         public final static class ShowHideLayerAction extends AbstractAction {
    97                 private final Layer layer;
    98 
    99                 public ShowHideLayerAction(Layer layer) {
    100                         super(tr("Show/Hide"), ImageProvider.get("dialogs", "showhide"));
    101                         putValue(SHORT_DESCRIPTION, tr("Toggle visible state of the selected layer."));
    102                         putValue("help", "Action/LayerShowHide");
    103                         this.layer = layer;
    104                 }
    105 
    106                 public void actionPerformed(ActionEvent e) {
    107                         Layer l = layer == null ? (Layer)instance.getSelectedValue() : layer;
    108                         if(l == null)
    109                                 return;
    110                         l.visible = !l.visible;
    111                         Main.map.mapView.repaint();
    112                         instance.repaint();
    113                 }
    114         }
    115 
    116         public final static class ShowHideMarkerText extends AbstractAction {
    117                 private final Layer layer;
    118 
    119                 public ShowHideMarkerText(Layer layer) {
    120                         super(tr("Show/Hide Text/Icons"), ImageProvider.get("dialogs", "showhide"));
    121                         putValue(SHORT_DESCRIPTION, tr("Toggle visible state of the marker text and icons."));
    122                         putValue("help", "Action/ShowHideTextIcons");
    123                         this.layer = layer;
    124                 }
    125 
    126                 public void actionPerformed(ActionEvent e) {
    127                         Layer l = layer == null ? (Layer)instance.getSelectedValue() : layer;
    128                         String current = Main.pref.get("marker.show "+l.name,"show");
    129                         Main.pref.put("marker.show "+l.name, current.equalsIgnoreCase("show") ? "hide" : "show");
    130                         Main.map.mapView.repaint();
    131                         instance.repaint();
    132                 }
    133         }
    134 
    135         /**
    136         * The data model for the list component.
    137         */
    138         DefaultListModel model = new DefaultListModel();
    139         /**
    140         * The merge action. This is only called, if the current selection and its
    141         * item below are editable datasets and the merge button is clicked.
    142         */
    143         private final SideButton mergeButton;
    144         /**
    145         * Button for moving layer up.
    146         */
    147         private final SideButton upButton;
    148         /**
    149         * Button for moving layer down.
    150         */
    151         private final SideButton downButton;
    152         /**
    153         * Button for delete layer.
    154         */
    155         private Action deleteAction = new DeleteLayerAction(null);
    156 
    157         /**
    158         * Create an layerlist and attach it to the given mapView.
    159         */
    160         public LayerListDialog(MapFrame mapFrame) {
    161                 super(tr("Layers"), "layerlist", tr("Open a list of all loaded layers."),
    162                 Shortcut.registerShortcut("subwindow:layers", tr("Toggle: {0}", tr("Layers")), KeyEvent.VK_L, Shortcut.GROUP_LAYER), 100);
    163                 instance = new JList(model);
    164                 listScrollPane = new JScrollPane(instance);
    165                 add(listScrollPane, BorderLayout.CENTER);
    166                 instance.setBackground(UIManager.getColor("Button.background"));
    167                 instance.setCellRenderer(new DefaultListCellRenderer(){
    168                         @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
    169                                 Layer layer = (Layer)value;
    170                                 JLabel label = (JLabel)super.getListCellRendererComponent(list,
    171                                                 layer.name, index, isSelected, cellHasFocus);
    172                                 Icon icon = layer.getIcon();
    173                                 if (!layer.visible)
    174                                         icon = ImageProvider.overlay(icon, "overlay/invisible", OverlayPosition.SOUTHEAST);
    175                                 label.setIcon(icon);
    176                                 label.setToolTipText(layer.getToolTipText());
    177                                 return label;
    178                         }
    179                 });
    180 
    181                 final MapView mapView = mapFrame.mapView;
    182 
    183                 Collection<Layer> data = mapView.getAllLayers();
    184                 for (Layer l : data)
    185                         model.addElement(l);
    186 
    187                 instance.setSelectedValue(mapView.getActiveLayer(), true);
    188                 instance.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    189                 instance.addListSelectionListener(new ListSelectionListener(){
    190                         public void valueChanged(ListSelectionEvent e) {
    191                                 if (instance.getModel().getSize() == 0)
    192                                         return;
    193                                 if (instance.getSelectedIndex() == -1)
    194                                         instance.setSelectedIndex(e.getFirstIndex());
    195                                 mapView.setActiveLayer((Layer)instance.getSelectedValue());
    196                         }
    197                 });
    198                 Layer.listeners.add(this);
    199 
    200                 instance.addMouseListener(new MouseAdapter(){
    201                         private void openPopup(MouseEvent e) {
    202                                 Point p = listScrollPane.getMousePosition();
    203                                 if (p == null)
    204                                         return; // user is faster than swing with mouse movement
    205                                 int index = instance.locationToIndex(e.getPoint());
    206                                 Layer layer = (Layer)instance.getModel().getElementAt(index);
    207                                 LayerListPopup menu = new LayerListPopup(instance, layer);
    208                                 menu.show(listScrollPane, p.x, p.y-3);
    209                         }
    210                         @Override public void mousePressed(MouseEvent e) {
    211                                 if (e.isPopupTrigger())
    212                                         openPopup(e);
    213                         }
    214                         @Override public void mouseReleased(MouseEvent e) {
    215                                 if (e.isPopupTrigger())
    216                                         openPopup(e);
    217                         }
    218                         @Override public void mouseClicked(MouseEvent e) {
    219                                 if (e.getClickCount() == 2) {
    220                                         int index = instance.locationToIndex(e.getPoint());
    221                                         Layer layer = (Layer)instance.getModel().getElementAt(index);
    222                                         String current = Main.pref.get("marker.show "+layer.name,"show");
    223                                         Main.pref.put("marker.show "+layer.name, current.equalsIgnoreCase("show") ? "hide" : "show");
    224                                         layer.visible = !layer.visible;
    225                                         Main.map.mapView.repaint();
    226                                         instance.repaint();
    227                                 }
    228                         }
    229                 });
    230 
    231 
    232                 // Buttons
    233                 JPanel buttonPanel = new JPanel(new GridLayout(1, 5));
    234 
    235                 ActionListener upDown = new ActionListener(){
    236                         public void actionPerformed(ActionEvent e) {
    237                                 Layer l = (Layer)instance.getSelectedValue();
    238                                 int sel = instance.getSelectedIndex();
    239                                 int selDest = e.getActionCommand().equals("up") ? sel-1 : sel+1;
    240                                 mapView.moveLayer(l, selDest);
    241                                 model.set(sel, model.get(selDest));
    242                                 model.set(selDest, l);
    243                                 instance.setSelectedIndex(selDest);
    244                                 updateButtonEnabled();
    245                                 mapView.repaint();
    246                         }
    247                 };
    248 
    249                 upButton = new SideButton("up", "LayerList", tr("Move the selected layer one row up."), upDown);
    250                 buttonPanel.add(upButton);
    251 
    252                 downButton = new SideButton("down", "LayerList", tr("Move the selected layer one row down."), upDown);
    253                 buttonPanel.add(downButton);
    254 
    255                 buttonPanel.add(new SideButton(new ShowHideLayerAction(null)));
    256                 buttonPanel.add(new SideButton(deleteAction));
    257 
    258                 mergeButton = new SideButton("Merge", "mergedown", "LayerList", tr("Merge the layer directly below into the selected layer."),
    259                 new ActionListener(){
    260                         public void actionPerformed(ActionEvent e) {
    261                                 Layer lTo = (Layer)instance.getSelectedValue();
    262                                 Layer lFrom = (Layer)model.get(instance.getSelectedIndex()+1);
    263                                 lTo.mergeFrom(lFrom);
    264                                 mapView.removeLayer(lFrom);
    265                                 updateButtonEnabled();
    266                                 mapView.repaint();
    267                         }
    268                 });
    269                 mergeButton.setText(null);
    270                 buttonPanel.add(mergeButton);
    271 
    272                 add(buttonPanel, BorderLayout.SOUTH);
    273 
    274                 updateButtonEnabled();
    275         }
    276 
    277         /**
    278         * Updates the state of the Buttons.
    279         */
    280         void updateButtonEnabled() {
    281                 int sel = instance.getSelectedIndex();
    282                 Layer l = (Layer)instance.getSelectedValue();
    283                 boolean enable = model.getSize() > 1;
    284                 enable = enable && sel < model.getSize()-1;
    285                 enable = enable && ((Layer)model.get(sel+1)).isMergable(l);
    286                 mergeButton.setEnabled(enable);
    287                 upButton.setEnabled(sel > 0);
    288                 downButton.setEnabled(sel >= 0 && sel < model.getSize()-1);
    289                 deleteAction.setEnabled(!model.isEmpty());
    290         }
    291 
    292         /**
    293         * Add the new layer to the list.
    294         */
    295         public void layerAdded(Layer newLayer) {
    296                 model.add(model.size(), newLayer);
    297                 updateButtonEnabled();
    298         }
    299 
    300         public void layerRemoved(Layer oldLayer) {
    301                 model.removeElement(oldLayer);
    302                 if (model.isEmpty()) {
    303                         Layer.listeners.remove(this);
    304                         return;
    305                 }
    306                 if (instance.getSelectedIndex() == -1)
    307                         instance.setSelectedIndex(0);
    308                 updateButtonEnabled();
    309         }
    310 
    311         /**
    312         * If the newLayer is not the actual selection, select it.
    313         */
    314         public void activeLayerChange(Layer oldLayer, Layer newLayer) {
    315                 if (newLayer != instance.getSelectedValue())
    316                         instance.setSelectedValue(newLayer, true);
    317                 updateButtonEnabled();
    318         }
     52    /**
     53    * The last layerlist created. Used to update the list in the Show/Hide and Delete actions.
     54    * TODO: Replace with Listener-Pattern.
     55    */
     56    static JList instance;
     57    private JScrollPane listScrollPane;
     58
     59    public final static class DeleteLayerAction extends AbstractAction {
     60
     61        private final Layer layer;
     62
     63        public DeleteLayerAction(Layer layer) {
     64            super(tr("Delete"), ImageProvider.get("dialogs", "delete"));
     65            putValue(SHORT_DESCRIPTION, tr("Delete the selected layer."));
     66            putValue("help", "Action/LayerDelete");
     67            this.layer = layer;
     68        }
     69
     70        public void actionPerformed(ActionEvent e) {
     71            int sel = instance.getSelectedIndex();
     72            Layer l = layer != null ? layer : (Layer)instance.getSelectedValue();
     73            if(l == null)
     74                return;
     75            if (l instanceof OsmDataLayer)
     76            {
     77                if (((OsmDataLayer)l).isModified())
     78                {
     79                    if(JOptionPane.showConfirmDialog(instance, tr("There are unsaved changes. Delete the layer anwyay?"),
     80                    tr("Unsaved Changes"), JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION)
     81                        return;
     82                }
     83                else if(!DontShowAgainInfo.show("delete_layer", tr("Do you really want to delete the whole layer?"), false))
     84                    return;
     85            }
     86            Main.main.removeLayer(l);
     87            if (sel >= instance.getModel().getSize())
     88                sel = instance.getModel().getSize()-1;
     89            if (instance.getSelectedValue() == null)
     90                instance.setSelectedIndex(sel);
     91            if (Main.map != null)
     92                Main.map.mapView.setActiveLayer((Layer)instance.getSelectedValue());
     93        }
     94    }
     95
     96    public final static class ShowHideLayerAction extends AbstractAction {
     97        private final Layer layer;
     98
     99        public ShowHideLayerAction(Layer layer) {
     100            super(tr("Show/Hide"), ImageProvider.get("dialogs", "showhide"));
     101            putValue(SHORT_DESCRIPTION, tr("Toggle visible state of the selected layer."));
     102            putValue("help", "Action/LayerShowHide");
     103            this.layer = layer;
     104        }
     105
     106        public void actionPerformed(ActionEvent e) {
     107            Layer l = layer == null ? (Layer)instance.getSelectedValue() : layer;
     108            if(l == null)
     109                return;
     110            l.visible = !l.visible;
     111            Main.map.mapView.repaint();
     112            instance.repaint();
     113        }
     114    }
     115
     116    public final static class ShowHideMarkerText extends AbstractAction {
     117        private final Layer layer;
     118
     119        public ShowHideMarkerText(Layer layer) {
     120            super(tr("Show/Hide Text/Icons"), ImageProvider.get("dialogs", "showhide"));
     121            putValue(SHORT_DESCRIPTION, tr("Toggle visible state of the marker text and icons."));
     122            putValue("help", "Action/ShowHideTextIcons");
     123            this.layer = layer;
     124        }
     125
     126        public void actionPerformed(ActionEvent e) {
     127            Layer l = layer == null ? (Layer)instance.getSelectedValue() : layer;
     128            String current = Main.pref.get("marker.show "+l.name,"show");
     129            Main.pref.put("marker.show "+l.name, current.equalsIgnoreCase("show") ? "hide" : "show");
     130            Main.map.mapView.repaint();
     131            instance.repaint();
     132        }
     133    }
     134
     135    /**
     136    * The data model for the list component.
     137    */
     138    DefaultListModel model = new DefaultListModel();
     139    /**
     140    * The merge action. This is only called, if the current selection and its
     141    * item below are editable datasets and the merge button is clicked.
     142    */
     143    private final SideButton mergeButton;
     144    /**
     145    * Button for moving layer up.
     146    */
     147    private final SideButton upButton;
     148    /**
     149    * Button for moving layer down.
     150    */
     151    private final SideButton downButton;
     152    /**
     153    * Button for delete layer.
     154    */
     155    private Action deleteAction = new DeleteLayerAction(null);
     156
     157    /**
     158    * Create an layerlist and attach it to the given mapView.
     159    */
     160    public LayerListDialog(MapFrame mapFrame) {
     161        super(tr("Layers"), "layerlist", tr("Open a list of all loaded layers."),
     162        Shortcut.registerShortcut("subwindow:layers", tr("Toggle: {0}", tr("Layers")), KeyEvent.VK_L, Shortcut.GROUP_LAYER), 100);
     163        instance = new JList(model);
     164        listScrollPane = new JScrollPane(instance);
     165        add(listScrollPane, BorderLayout.CENTER);
     166        instance.setBackground(UIManager.getColor("Button.background"));
     167        instance.setCellRenderer(new DefaultListCellRenderer(){
     168            @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
     169                Layer layer = (Layer)value;
     170                JLabel label = (JLabel)super.getListCellRendererComponent(list,
     171                        layer.name, index, isSelected, cellHasFocus);
     172                Icon icon = layer.getIcon();
     173                if (!layer.visible)
     174                    icon = ImageProvider.overlay(icon, "overlay/invisible", OverlayPosition.SOUTHEAST);
     175                label.setIcon(icon);
     176                label.setToolTipText(layer.getToolTipText());
     177                return label;
     178            }
     179        });
     180
     181        final MapView mapView = mapFrame.mapView;
     182
     183        Collection<Layer> data = mapView.getAllLayers();
     184        for (Layer l : data)
     185            model.addElement(l);
     186
     187        instance.setSelectedValue(mapView.getActiveLayer(), true);
     188        instance.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
     189        instance.addListSelectionListener(new ListSelectionListener(){
     190            public void valueChanged(ListSelectionEvent e) {
     191                if (instance.getModel().getSize() == 0)
     192                    return;
     193                if (instance.getSelectedIndex() == -1)
     194                    instance.setSelectedIndex(e.getFirstIndex());
     195                mapView.setActiveLayer((Layer)instance.getSelectedValue());
     196            }
     197        });
     198        Layer.listeners.add(this);
     199
     200        instance.addMouseListener(new MouseAdapter(){
     201            private void openPopup(MouseEvent e) {
     202                Point p = listScrollPane.getMousePosition();
     203                if (p == null)
     204                    return; // user is faster than swing with mouse movement
     205                int index = instance.locationToIndex(e.getPoint());
     206                Layer layer = (Layer)instance.getModel().getElementAt(index);
     207                LayerListPopup menu = new LayerListPopup(instance, layer);
     208                menu.show(listScrollPane, p.x, p.y-3);
     209            }
     210            @Override public void mousePressed(MouseEvent e) {
     211                if (e.isPopupTrigger())
     212                    openPopup(e);
     213            }
     214            @Override public void mouseReleased(MouseEvent e) {
     215                if (e.isPopupTrigger())
     216                    openPopup(e);
     217            }
     218            @Override public void mouseClicked(MouseEvent e) {
     219                if (e.getClickCount() == 2) {
     220                    int index = instance.locationToIndex(e.getPoint());
     221                    Layer layer = (Layer)instance.getModel().getElementAt(index);
     222                    String current = Main.pref.get("marker.show "+layer.name,"show");
     223                    Main.pref.put("marker.show "+layer.name, current.equalsIgnoreCase("show") ? "hide" : "show");
     224                    layer.visible = !layer.visible;
     225                    Main.map.mapView.repaint();
     226                    instance.repaint();
     227                }
     228            }
     229        });
     230
     231
     232        // Buttons
     233        JPanel buttonPanel = new JPanel(new GridLayout(1, 5));
     234
     235        ActionListener upDown = new ActionListener(){
     236            public void actionPerformed(ActionEvent e) {
     237                Layer l = (Layer)instance.getSelectedValue();
     238                int sel = instance.getSelectedIndex();
     239                int selDest = e.getActionCommand().equals("up") ? sel-1 : sel+1;
     240                mapView.moveLayer(l, selDest);
     241                model.set(sel, model.get(selDest));
     242                model.set(selDest, l);
     243                instance.setSelectedIndex(selDest);
     244                updateButtonEnabled();
     245                mapView.repaint();
     246            }
     247        };
     248
     249        upButton = new SideButton("up", "LayerList", tr("Move the selected layer one row up."), upDown);
     250        buttonPanel.add(upButton);
     251
     252        downButton = new SideButton("down", "LayerList", tr("Move the selected layer one row down."), upDown);
     253        buttonPanel.add(downButton);
     254
     255        buttonPanel.add(new SideButton(new ShowHideLayerAction(null)));
     256        buttonPanel.add(new SideButton(deleteAction));
     257
     258        mergeButton = new SideButton("Merge", "mergedown", "LayerList", tr("Merge the layer directly below into the selected layer."),
     259        new ActionListener(){
     260            public void actionPerformed(ActionEvent e) {
     261                Layer lTo = (Layer)instance.getSelectedValue();
     262                Layer lFrom = (Layer)model.get(instance.getSelectedIndex()+1);
     263                lTo.mergeFrom(lFrom);
     264                mapView.removeLayer(lFrom);
     265            &nbs