Changes in / [30:20] in josm


Ignore:
Files:
15 added
22 deleted
45 edited

Legend:

Unmodified
Added
Removed
  • /.classpath

    r30 r20  
    22<classpath>
    33        <classpathentry kind="src" path="src"/>
    4         <classpathentry including="images/" kind="src" path=""/>
    54        <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
    65        <classpathentry sourcepath="/home/imi/src/jdom-1.0/src" kind="lib" path="lib/jdom.jar"/>
  • /src/org/openstreetmap/josm/actions/AboutAction.java

    r30 r20  
    1313import java.util.regex.Pattern;
    1414
     15import javax.swing.AbstractAction;
    1516import javax.swing.JEditorPane;
    1617import javax.swing.JLabel;
     
    2324import javax.swing.event.HyperlinkListener;
    2425
    25 import org.openstreetmap.josm.Main;
    2626import org.openstreetmap.josm.gui.GBC;
    2727import org.openstreetmap.josm.gui.ImageProvider;
     28import org.openstreetmap.josm.gui.Main;
    2829
    2930/**
     
    3536 * @author imi
    3637 */
    37 public class AboutAction extends JosmAction {
     38public class AboutAction extends AbstractAction {
    3839       
    3940        public AboutAction() {
    40                 super("About", "about", "Display the about screen.", KeyEvent.VK_A, null);
     41                super("About", ImageProvider.get("about"));
     42                putValue(MNEMONIC_KEY, KeyEvent.VK_A);
     43                putValue(SHORT_DESCRIPTION, "Display the about screen.");
    4144        }
    4245       
  • /src/org/openstreetmap/josm/actions/AutoScaleAction.java

    r30 r20  
    44import java.awt.event.KeyEvent;
    55
     6import javax.swing.AbstractAction;
     7import javax.swing.JComponent;
     8import javax.swing.KeyStroke;
     9
     10import org.openstreetmap.josm.gui.ImageProvider;
    611import org.openstreetmap.josm.gui.MapFrame;
    712import org.openstreetmap.josm.gui.MapView;
     
    1116 * @author imi
    1217 */
    13 public class AutoScaleAction extends JosmAction {
     18public class AutoScaleAction extends AbstractAction {
    1419        /**
    1520         * The mapView this action operates on.
     
    1823       
    1924        public AutoScaleAction(MapFrame mapFrame) {
    20                 super("Auto Scale", "autoscale", "Zoom the view to show the whole layer. Disabled if the view is moved.",
    21                                 KeyEvent.VK_A, null);
     25                super("Auto Scale", ImageProvider.get("autoscale"));
    2226                mapView = mapFrame.mapView;
     27                putValue(MNEMONIC_KEY, KeyEvent.VK_A);
     28                putValue(SHORT_DESCRIPTION, "Zoom the view to show the whole layer. Disabled if the view is moved.");
     29                KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_A, 0);
     30                putValue(ACCELERATOR_KEY, ks);
     31                mapFrame.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ks, this);
     32                mapFrame.getActionMap().put(this, this);
    2333        }
    2434
  • /src/org/openstreetmap/josm/actions/ExitAction.java

    r30 r20  
    33import java.awt.event.ActionEvent;
    44import java.awt.event.KeyEvent;
     5
     6import javax.swing.AbstractAction;
     7
     8import org.openstreetmap.josm.gui.ImageProvider;
    59
    610/**
     
    913 * @author imi
    1014 */
    11 public class ExitAction extends JosmAction {
     15public class ExitAction extends AbstractAction {
    1216
    1317        /**
     
    1519         */
    1620        public ExitAction() {
    17                 super("Exit", "exit", "Exit the application.", KeyEvent.VK_X, null);
     21                super("Exit", ImageProvider.get("exit"));
     22                putValue(MNEMONIC_KEY, KeyEvent.VK_X);
     23                putValue(SHORT_DESCRIPTION, "Exit the application.");
    1824        }
    1925       
  • /src/org/openstreetmap/josm/actions/OpenOsmServerAction.java

    r30 r20  
    55import java.awt.event.ActionEvent;
    66import java.awt.event.ActionListener;
    7 import java.awt.event.InputEvent;
    87import java.awt.event.KeyEvent;
    9 import java.io.IOException;
    108
     9import javax.swing.AbstractAction;
    1110import javax.swing.DefaultListModel;
    1211import javax.swing.JButton;
     
    1716import javax.swing.JScrollPane;
    1817import javax.swing.JTextField;
    19 import javax.swing.KeyStroke;
    2018import javax.swing.event.ListSelectionEvent;
    2119import javax.swing.event.ListSelectionListener;
    2220
    23 import org.jdom.JDOMException;
    24 import org.openstreetmap.josm.Main;
    2521import org.openstreetmap.josm.data.GeoPoint;
    2622import org.openstreetmap.josm.data.osm.DataSet;
    2723import org.openstreetmap.josm.gui.BookmarkList;
    2824import org.openstreetmap.josm.gui.GBC;
     25import org.openstreetmap.josm.gui.ImageProvider;
     26import org.openstreetmap.josm.gui.Main;
    2927import org.openstreetmap.josm.gui.MapFrame;
    3028import org.openstreetmap.josm.gui.MapView;
    3129import org.openstreetmap.josm.gui.BookmarkList.Bookmark;
    3230import org.openstreetmap.josm.gui.layer.Layer;
    33 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    34 import org.openstreetmap.josm.gui.layer.RawGpsDataLayer;
    35 import org.openstreetmap.josm.io.OsmServerReader;
     31import org.openstreetmap.josm.gui.layer.LayerFactory;
     32import org.openstreetmap.josm.io.OsmReader;
     33import org.openstreetmap.josm.io.DataReader.ConnectionException;
     34import org.openstreetmap.josm.io.DataReader.ParseException;
    3635
    3736/**
     
    4342 * @author imi
    4443 */
    45 public class OpenOsmServerAction extends JosmAction {
     44public class OpenOsmServerAction extends AbstractAction {
    4645
    47         JTextField[] latlon = new JTextField[]{
     46        private JTextField[] latlon = new JTextField[]{
    4847                        new JTextField(9),
    4948                        new JTextField(9),
    5049                        new JTextField(9),
    5150                        new JTextField(9)};
    52         JCheckBox rawGps = new JCheckBox("Open as raw gps data", false);
     51        private JCheckBox rawGps = new JCheckBox("Open as raw gps data", false);
    5352
    5453        public OpenOsmServerAction() {
    55                 super("Connect to OSM", "connectosm", "Open a connection to the OSM server.", KeyEvent.VK_C,
    56                                 KeyStroke.getAWTKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK));
     54                super("Connect to OSM", ImageProvider.get("connectosm"));
     55                putValue(MNEMONIC_KEY, KeyEvent.VK_C);
     56                putValue(SHORT_DESCRIPTION, "Open a connection to the OSM server.");
    5757        }
    5858
     
    8282                        for (JTextField f : latlon)
    8383                                f.setCaretPosition(0);
    84                         rawGps.setSelected(mv.getActiveLayer() instanceof RawGpsDataLayer);
     84                        rawGps.setSelected(!mv.getActiveLayer().isEditable());
    8585                }
    8686
     
    144144                        return;
    145145                }
    146                 OsmServerReader osmReader = new OsmServerReader(Main.pref.osmDataServer,
    147                                 b.latlon[0], b.latlon[1], b.latlon[2], b.latlon[3]);
     146                OsmReader osmReader = new OsmReader(Main.pref.osmDataServer,
     147                                rawGps.isSelected(), b.latlon[0], b.latlon[1], b.latlon[2], b.latlon[3]);
    148148                try {
     149                        DataSet dataSet = osmReader.parse();
     150                        if (dataSet == null)
     151                                return; // user cancelled download
     152                        if (dataSet.nodes.isEmpty())
     153                                JOptionPane.showMessageDialog(Main.main, "No data imported.");
     154
    149155                        String name = latlon[0].getText()+" "+latlon[1].getText()+" x "+
    150156                                        latlon[2].getText()+" "+latlon[3].getText();
    151157                       
    152                         Layer layer;
    153                         if (rawGps.isSelected()) {
    154                                 layer = new RawGpsDataLayer(osmReader.parseRawGps(), name);
    155                         } else {
    156                                 DataSet dataSet = osmReader.parseOsm();
    157                                 if (dataSet == null)
    158                                         return; // user cancelled download
    159                                 if (dataSet.nodes.isEmpty())
    160                                         JOptionPane.showMessageDialog(Main.main, "No data imported.");
    161                                
    162                                 layer = new OsmDataLayer(dataSet, name);
    163                         }
     158                        Layer layer = LayerFactory.create(dataSet, name, rawGps.isSelected());
    164159
    165160                        if (Main.main.getMapFrame() == null)
     
    167162                        else
    168163                                Main.main.getMapFrame().mapView.addLayer(layer);
    169                 } catch (JDOMException x) {
     164                } catch (ParseException x) {
    170165                        x.printStackTrace();
    171166                        JOptionPane.showMessageDialog(Main.main, x.getMessage());
    172                 } catch (IOException x) {
     167                } catch (ConnectionException x) {
    173168                        x.printStackTrace();
    174169                        JOptionPane.showMessageDialog(Main.main, x.getMessage());
     
    183178         *              checkbox.
    184179         */
    185         Bookmark readBookmark() {
     180        private Bookmark readBookmark() {
    186181                try {
    187182                        Bookmark b = new Bookmark();
  • /src/org/openstreetmap/josm/actions/PreferencesAction.java

    r30 r20  
    44import java.awt.event.KeyEvent;
    55
     6import javax.swing.AbstractAction;
     7
     8import org.openstreetmap.josm.gui.ImageProvider;
    69import org.openstreetmap.josm.gui.PreferenceDialog;
    710
     
    1114 * @author imi
    1215 */
    13 public class PreferencesAction extends JosmAction {
     16public class PreferencesAction extends AbstractAction {
    1417
    1518        /**
     
    1720         */
    1821        public PreferencesAction() {
    19                 super("Preferences", "preference", "Open a preferences page for global settings.",
    20                                 KeyEvent.VK_P, null);
     22                super("Preferences", ImageProvider.get("preference"));
     23                putValue(MNEMONIC_KEY, KeyEvent.VK_P);
     24                putValue(SHORT_DESCRIPTION, "Open a preferences page for global settings.");
    2125        }
    2226
  • /src/org/openstreetmap/josm/actions/mapmode/AddLineSegmentAction.java

    r30 r20  
    44import java.awt.Graphics;
    55import java.awt.Point;
    6 import java.awt.event.ActionEvent;
    76import java.awt.event.KeyEvent;
    87import java.awt.event.MouseEvent;
    98import java.awt.event.MouseListener;
    109
    11 import org.openstreetmap.josm.Main;
    12 import org.openstreetmap.josm.command.AddCommand;
     10import javax.swing.JOptionPane;
     11
     12import org.openstreetmap.josm.data.osm.DataSet;
    1313import org.openstreetmap.josm.data.osm.LineSegment;
    1414import org.openstreetmap.josm.data.osm.Node;
    1515import org.openstreetmap.josm.data.osm.OsmPrimitive;
     16import org.openstreetmap.josm.data.osm.Track;
     17import org.openstreetmap.josm.gui.Main;
    1618import org.openstreetmap.josm.gui.MapFrame;
    1719
     
    2022 * starting node and dragging to the ending node.
    2123 *
     24 * If the Alt key was pressed when releasing the mouse, this action tries to
     25 * add the line segment to a track. The new line segment gets added to all tracks
     26 * of the first node that end in the first node. If no tracks are found, the
     27 * line segment gets added to all tracks in the second node that start with
     28 * the second node.
     29 *
    2230 * No line segment can be created if there is already a line segment containing
    23  * both nodes.
     31 * both nodes in the same order.
    2432 *
    2533 * @author imi
     
    4654         */
    4755        public AddLineSegmentAction(MapFrame mapFrame) {
    48                 super("Add Line Segment", "addlinesegment", "Add a line segment between two nodes.", KeyEvent.VK_G, mapFrame);
     56                super("Add Line Segment", "addlinesegment", "Add a line segment between two nodes.", KeyEvent.VK_L, mapFrame);
    4957        }
    5058
     
    6270                mv.removeMouseMotionListener(this);
    6371                drawHint(false);
    64         }
    65 
    66        
    67         @Override
    68         public void actionPerformed(ActionEvent e) {
    69                 super.actionPerformed(e);
    70                 makeLineSegment();
    7172        }
    7273
     
    107108
    108109        /**
    109          * If left button was released, try to create the line segment.
     110         * Create the line segment if first and second are different and there is
     111         * not already a line segment.
    110112         */
    111113        @Override
    112114        public void mouseReleased(MouseEvent e) {
    113                 if (e.getButton() == MouseEvent.BUTTON1) {
    114                         makeLineSegment();
    115                         first = null; // release line segment drawing
    116                 }
    117         }
     115                if (e.getButton() != MouseEvent.BUTTON1)
     116                        return;
    118117
    119         /**
    120          * Create the line segment if first and second are different and there is
    121          * not already a line segment.
    122          */
    123         private void makeLineSegment() {
    124118                if (first == null || second == null) {
    125119                        first = null;
     
    132126                Node start = first;
    133127                Node end = second;
    134                 first = second;
     128                first = null;
    135129                second = null;
    136130               
    137131                if (start != end) {
     132                        DataSet ds = mv.getActiveDataSet();
     133
    138134                        // try to find a line segment
    139                         for (LineSegment ls : Main.main.ds.lineSegments)
    140                                 if ((start == ls.start && end == ls.end) || (end == ls.start && start == ls.end))
    141                                         return; // already a line segment here - be happy, do nothing.
     135                        for (Track t : ds.tracks())
     136                                for (LineSegment ls : t.segments())
     137                                        if (start == ls.getStart() && end == ls.getEnd()) {
     138                                                JOptionPane.showMessageDialog(Main.main, "There is already an line segment with the same direction between the selected nodes.");
     139                                                return;
     140                                        }
    142141
    143142                        LineSegment ls = new LineSegment(start, end);
    144                         mv.editLayer().add(new AddCommand(Main.main.ds, ls));
     143                        boolean foundTrack = false;
     144
     145                        if (((e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) != 0)) {
     146                                // find a track for the new line segment
     147                                for (Track t : ds.tracks()) {
     148                                        if (t.getEndingNode() == start) {
     149                                                t.add(ls);
     150                                                foundTrack = true;
     151                                        }
     152                                }
     153                                if (!foundTrack) {
     154                                        for (Track t : ds.tracks()) {
     155                                                if (t.getStartingNode() == end) {
     156                                                        t.addStart(ls);
     157                                                        foundTrack = true;
     158                                                }
     159                                        }
     160                                }
     161                        }
     162                        if (!foundTrack)
     163                                ds.addPendingLineSegment(ls);
    145164                }
    146 
     165               
    147166                mv.repaint();
    148167        }
     
    167186                hintDrawn = !hintDrawn;
    168187        }
     188
     189        @Override
     190        protected boolean isEditMode() {
     191                return true;
     192        }
    169193}
  • /src/org/openstreetmap/josm/actions/mapmode/AddNodeAction.java

    r30 r20  
    44import java.awt.event.MouseEvent;
    55
    6 import org.openstreetmap.josm.Main;
    7 import org.openstreetmap.josm.command.AddCommand;
    86import org.openstreetmap.josm.data.osm.Node;
    97import org.openstreetmap.josm.gui.MapFrame;
     
    5048                        Node node = new Node();
    5149                        node.coor = mv.getPoint(e.getX(), e.getY(), true);
    52                         mv.editLayer().add(new AddCommand(Main.main.ds, node));
     50                        mv.getActiveDataSet().nodes.add(node);
    5351                        mv.repaint();
    5452                }
    5553        }
     54
     55        @Override
     56        protected boolean isEditMode() {
     57                return true;
     58        }
    5659}
  • /src/org/openstreetmap/josm/actions/mapmode/AddTrackAction.java

    r30 r20  
    22
    33import java.awt.Rectangle;
    4 import java.awt.event.ActionEvent;
    54import java.awt.event.KeyEvent;
    65import java.util.Collection;
    7 import java.util.Iterator;
    86import java.util.LinkedList;
    97
    10 import org.openstreetmap.josm.Main;
    11 import org.openstreetmap.josm.command.AddCommand;
     8import org.openstreetmap.josm.data.osm.DataSet;
    129import org.openstreetmap.josm.data.osm.LineSegment;
    1310import org.openstreetmap.josm.data.osm.OsmPrimitive;
     
    6259        }
    6360
    64        
    65         @Override
    66         public void actionPerformed(ActionEvent e) {
    67                 makeTrack();
    68                 super.actionPerformed(e);
    69         }
    70 
    7161        /**
    7262         * If Shift is pressed, only add the selected line segments to the selection.
     
    8676                        return; // not allowed together
    8777
     78                DataSet ds = mv.getActiveDataSet();
     79               
    8880                if (!ctrl && !shift)
    89                         Main.main.ds.clearSelection(); // new selection will replace the old.
     81                        ds.clearSelection(); // new selection will replace the old.
    9082
    9183                Collection<OsmPrimitive> selectionList = selectionManager.getObjectsInRectangle(r,alt);
    9284                for (OsmPrimitive osm : selectionList)
    93                         osm.setSelected(!ctrl);
     85                        osm.setSelected(!ctrl, ds);
    9486
    9587                mv.repaint(); // from now on, the map has to be repainted.
     
    9890                        return; // no new track yet.
    9991               
    100                 makeTrack();
    101         }
    102 
    103         /**
    104          * Just make a track of all selected items.
    105          */
    106         private void makeTrack() {
    107                 Collection<OsmPrimitive> selection = Main.main.ds.getSelected();
     92                Collection<OsmPrimitive> selection = ds.getSelected();
    10893                if (selection.isEmpty())
    10994                        return;
     
    11398                for (OsmPrimitive osm : selection) {
    11499                        if (osm instanceof Track)
    115                                 lineSegments.addAll(((Track)osm).segments);
     100                                lineSegments.addAll(((Track)osm).segments());
    116101                        else if (osm instanceof LineSegment)
    117102                                lineSegments.add((LineSegment)osm);
    118103                }
    119                
    120                 // sort the line segments in best possible order. This is done by:
    121                 // 0  if no elements in list, quit
    122                 // 1  taking the first ls as pivot, remove it from list
    123                 // 2  searching for a connection at start or end of pivot
    124                 // 3  if found, attach it, remove it from list, goto 2
    125                 // 4  if not found, save the pivot-string and goto 0
    126                 LinkedList<LineSegment> sortedLineSegments = new LinkedList<LineSegment>();
    127                 while (!lineSegments.isEmpty()) {
    128                         LinkedList<LineSegment> pivotList = new LinkedList<LineSegment>();
    129                         pivotList.add(lineSegments.getFirst());
    130                         lineSegments.removeFirst();
    131                         for (boolean found = true; found;) {
    132                                 found = false;
    133                                 for (Iterator<LineSegment> it = lineSegments.iterator(); it.hasNext();) {
    134                                         LineSegment ls = it.next();
    135                                         if (ls.start == pivotList.getLast().end) {
    136                                                 pivotList.addLast(ls);
    137                                                 it.remove();
    138                                                 found = true;
    139                                         } else if (ls.end == pivotList.getFirst().start) {
    140                                                 pivotList.addFirst(ls);
    141                                                 it.remove();
    142                                                 found = true;
    143                                         }
    144                                 }
    145                         }
    146                         sortedLineSegments.addAll(pivotList);
    147                 }
    148                
    149104                Track t = new Track();
    150                 for (LineSegment ls : sortedLineSegments)
    151                         t.add(ls);
    152                 mv.editLayer().add(new AddCommand(Main.main.ds, t));
    153                 Main.main.ds.clearSelection();
    154                 mv.repaint();
     105                for (LineSegment ls : lineSegments)
     106                        ds.assignPendingLineSegment(ls, t, true);
     107                ds.addTrack(t);
     108                ds.clearSelection();
     109        }
     110
     111        @Override
     112        protected boolean isEditMode() {
     113                return true;
    155114        }
    156115}
  • /src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java

    r30 r20  
    11package org.openstreetmap.josm.actions.mapmode;
    22
    3 import java.awt.event.ActionEvent;
    43import java.awt.event.KeyEvent;
    54import java.awt.event.MouseEvent;
    65import java.util.ArrayList;
    7 import java.util.Collection;
    8 import java.util.HashSet;
    9 import java.util.Iterator;
     6import java.util.HashMap;
    107import java.util.LinkedList;
     8import java.util.Map;
    119
    1210import javax.swing.JOptionPane;
    1311
    14 import org.openstreetmap.josm.Main;
    15 import org.openstreetmap.josm.command.CombineAndDeleteCommand;
    16 import org.openstreetmap.josm.command.DeleteCommand;
    1712import org.openstreetmap.josm.data.osm.DataSet;
     13import org.openstreetmap.josm.data.osm.Key;
    1814import org.openstreetmap.josm.data.osm.LineSegment;
    1915import org.openstreetmap.josm.data.osm.Node;
    2016import org.openstreetmap.josm.data.osm.OsmPrimitive;
    2117import org.openstreetmap.josm.data.osm.Track;
     18import org.openstreetmap.josm.gui.Main;
    2219import org.openstreetmap.josm.gui.MapFrame;
    2320
     
    3532 * tries to combine the referencing objects as follows:
    3633 *
    37  * If a node is part of exactly two line segments, the two line segments are
    38  * combined into one. The first line segment spans now to the end of the
    39  * second and the second line segment gets deleted.
     34 * If a node is part of exactly two line segments from a track, the two line
     35 * segments are combined into one. The first line segment spans now to the end
     36 * of the second and the second line segment gets deleted. This is checked for
     37 * every track.
     38 *
     39 * If a node is the end of the ending line segment of one track and the start of
     40 * exactly one other tracks start segment, the tracks are combined into one track,
     41 * deleting the second track and keeping the first one. The ending line segment
     42 * of the fist track is combined with the starting line segment of the second
     43 * track.
    4044 *
    4145 * Combining is only possible, if both objects that should be combined have no
     
    5155 *
    5256 * If the user enters the mapmode and any object is selected, all selected
    53  * objects that can be deleted will. Combining applies to the selected objects.
     57 * objects get deleted. Combining applies to the selected objects.
    5458 *
    5559 * @author imi
     
    6266         */
    6367        public DeleteAction(MapFrame mapFrame) {
    64                 super("Delete", "delete", "Delete nodes, streets or areas.", KeyEvent.VK_D, mapFrame);
     68                super("Delete", "delete", "Delete nodes, streets or areas.", KeyEvent.VK_DELETE, mapFrame);
    6569        }
    6670
     
    7781        }
    7882
    79        
    80         @Override
    81         public void actionPerformed(ActionEvent e) {
    82                 super.actionPerformed(e);
    83                 boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
    84                 Collection<OsmPrimitive> selection = Main.main.ds.getSelected();
    85                
    86                 int selSize = 0;
    87                 // loop as long as the selection size changes
    88                 while(selSize != selection.size()) {
    89                         selSize = selection.size();
    90 
    91                         for (Iterator<OsmPrimitive> it = selection.iterator(); it.hasNext();) {
    92                                 OsmPrimitive osm = it.next();
    93                                 if (ctrl) {
    94                                         deleteWithReferences(osm);
    95                                         it.remove();
    96                                 } else {
    97                                         if (delete(osm, false))
    98                                                 it.remove();
    99                                 }
    100                         }
    101                 }
    102                 mv.repaint();
    103         }
    104 
    10583        /**
    10684         * If user clicked with the left button, delete the nearest object.
     
    11694                        return;
    11795
     96                DataSet ds = mv.getActiveDataSet();
     97
    11898                if ((e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) != 0)
    119                         deleteWithReferences(sel);
     99                        deleteWithReferences(sel, ds);
    120100                else
    121                         delete(sel, true);
     101                        delete(sel, ds);
    122102
    123103                mv.repaint();
     
    146126         * TODO If you delete x, then a,B,C and x gets deleted. A now consist of b only.
    147127         * If you delete a or b, then A, a, b and z gets deleted.
    148          * 
     128         *
    149129         * @param osm The object to delete.
    150130         */
    151         private void deleteWithReferences(OsmPrimitive osm) {
    152                 // collect all tracks, areas and line segments that should be deleted
     131        private void deleteWithReferences(OsmPrimitive osm, DataSet ds) {
     132                // collect all tracks, areas and pending line segments that should be deleted
    153133                ArrayList<Track> tracksToDelete = new ArrayList<Track>();
    154134                ArrayList<LineSegment> lineSegmentsToDelete = new ArrayList<LineSegment>();
     
    156136                if (osm instanceof Node) {
    157137                        // delete any track and line segment the node is in.
    158                         for (Track t : Main.main.ds.tracks)
    159                                 for (LineSegment ls : t.segments)
    160                                         if (ls.start == osm || ls.end == osm)
     138                        for (Track t : ds.tracks())
     139                                for (LineSegment ls : t.segments())
     140                                        if (ls.getStart() == osm || ls.getEnd() == osm)
    161141                                                tracksToDelete.add(t);
    162                         for (LineSegment ls : Main.main.ds.lineSegments)
    163                                 if (ls.start == osm || ls.end == osm)
     142                        for (LineSegment ls : ds.pendingLineSegments())
     143                                if (ls.getStart() == osm || ls.getEnd() == osm)
    164144                                        lineSegmentsToDelete.add(ls);
    165145                               
     
    167147                        LineSegment lineSegment = (LineSegment)osm;
    168148                        lineSegmentsToDelete.add(lineSegment);
    169                         for (Track t : Main.main.ds.tracks)
    170                                 for (LineSegment ls : t.segments)
     149                        for (Track t : ds.tracks())
     150                                for (LineSegment ls : t.segments())
    171151                                        if (lineSegment == ls)
    172152                                                tracksToDelete.add(t);
     
    177157                ArrayList<Node> checkUnreferencing = new ArrayList<Node>();
    178158                for (Track t : tracksToDelete) {
    179                         for (LineSegment ls : t.segments) {
    180                                 checkUnreferencing.add(ls.start);
    181                                 checkUnreferencing.add(ls.end);
     159                        for (LineSegment ls : t.segments()) {
     160                                checkUnreferencing.add(ls.getStart());
     161                                checkUnreferencing.add(ls.getEnd());
    182162                        }
    183163                }
    184164                for (LineSegment ls : lineSegmentsToDelete) {
    185                         checkUnreferencing.add(ls.start);
    186                         checkUnreferencing.add(ls.end);
    187                 }
    188 
    189                 Collection<OsmPrimitive> deleteData = new LinkedList<OsmPrimitive>();
    190                 deleteData.addAll(tracksToDelete);
    191                 deleteData.addAll(lineSegmentsToDelete);
     165                        checkUnreferencing.add(ls.getStart());
     166                        checkUnreferencing.add(ls.getEnd());
     167                }
     168               
     169                // delete tracks and areas
     170                for (Track t : tracksToDelete)
     171                        ds.removeTrack(t);
     172                for (LineSegment ls : lineSegmentsToDelete)
     173                        ds.destroyPendingLineSegment(ls);
     174
    192175                // removing all unreferenced nodes
    193                 for (Node n : checkUnreferencing)
    194                         if (!isReferenced(n))
    195                                 deleteData.add(n);
     176                for (Node n : checkUnreferencing) {
     177                        if (!isReferenced(n, ds))
     178                                ds.nodes.remove(n);
     179                }
    196180                // now, all references are killed. Delete the node (if it was a node)
    197181                if (osm instanceof Node)
    198                         deleteData.add(osm);
    199 
    200                 mv.editLayer().add(new DeleteCommand(Main.main.ds, deleteData));
     182                        ds.nodes.remove(osm);
    201183        }
    202184
     
    207189         *
    208190         * @param osm The object to delete.
    209          * @param msgBox Whether a message box for errors should be shown
    210          * @return <code>true</code> if the object could be deleted
    211          */
    212         private boolean delete(OsmPrimitive osm, boolean msgBox) {
    213                 if (osm instanceof Node && isReferenced((Node)osm))
    214                         return combineAndDelete((Node)osm, msgBox);
    215                 Collection<OsmPrimitive> c = new LinkedList<OsmPrimitive>();
    216                 c.add(osm);
    217                 mv.editLayer().add(new DeleteCommand(Main.main.ds, c));
    218                 return true;
     191         */
     192        private void delete(OsmPrimitive osm, DataSet ds) {
     193                if (osm instanceof Node) {
     194                        Node n = (Node)osm;
     195                        if (isReferenced(n, ds)) {
     196                                String combined = combine(n, ds);
     197                                if (combined != null) {
     198                                        JOptionPane.showMessageDialog(Main.main, combined);
     199                                        return;
     200                                }
     201                        }
     202                        // now, the node isn't referenced anymore, so delete it.
     203                        ds.nodes.remove(n);
     204                } else if (osm instanceof LineSegment) {
     205                        LinkedList<Track> tracksToDelete = new LinkedList<Track>();
     206                        for (Track t : ds.tracks()) {
     207                                t.remove((LineSegment)osm);
     208                                if (t.segments().isEmpty())
     209                                        tracksToDelete.add(t);
     210                        }
     211                        for (Track t : tracksToDelete)
     212                                ds.removeTrack(t);
     213                        ds.destroyPendingLineSegment((LineSegment)osm);
     214                } else if (osm instanceof Track) {
     215                        ds.removeTrack((Track)osm);
     216                        for (LineSegment ls : ((Track)osm).segments())
     217                                ds.addPendingLineSegment(ls);
     218                }
    219219        }
    220220
     
    225225         * @return Whether the node is used by a track or area.
    226226         */
    227         private boolean isReferenced(Node n) {
    228                 for (LineSegment ls : Main.main.ds.lineSegments)
    229                         if (ls.start == n || ls.end == n)
     227        private boolean isReferenced(Node n, DataSet ds) {
     228                for (Track t : ds.tracks())
     229                        for (LineSegment ls : t.segments())
     230                                if (ls.getStart() == n || ls.getEnd() == n)
     231                                        return true;
     232                for (LineSegment ls : ds.pendingLineSegments())
     233                        if (ls.getStart() == n || ls.getEnd() == n)
    230234                                return true;
    231235                // TODO areas
     
    239243         *
    240244         * @param n The node that is going to be deleted.
    241          * @param msgBox Whether a message box should be displayed in case of problems
    242          * @return <code>true</code> if combining suceded.
    243          */
    244         private boolean combineAndDelete(Node n, boolean msgBox) {
    245                 DataSet ds = Main.main.ds;
    246                 Collection<LineSegment> lineSegmentsUsed = new HashSet<LineSegment>();
    247                 for (LineSegment ls : ds.lineSegments)
    248                         if (ls.start == n || ls.end == n)
    249                                 lineSegmentsUsed.add(ls);
    250 
    251                 if (lineSegmentsUsed.isEmpty())
    252                         // should not be called
    253                         throw new IllegalStateException();
    254                
    255                 if (lineSegmentsUsed.size() == 1) {
    256                         if (msgBox)
    257                                 JOptionPane.showMessageDialog(Main.main, "Node used by a line segment. Delete this first.");
    258                         return false;
    259                 }
    260                        
    261                 if (lineSegmentsUsed.size() > 2) {
    262                         if (msgBox)
    263                                 JOptionPane.showMessageDialog(Main.main, "Node used by more than two line segments. Delete them first.");
    264                         return false;
    265                 }
    266                
    267                 Iterator<LineSegment> it = lineSegmentsUsed.iterator();
    268                 LineSegment first = it.next();
    269                 LineSegment second = it.next();
    270                
    271                 // wrong direction?
    272                 if (first.start == second.end) {
    273                         LineSegment t = first;
     245         * @return <code>null</code> if combining suceded or an error string if there
     246         *              are problems combining the node.
     247         */
     248        private String combine(Node n, DataSet ds) {
     249                // first, check for pending line segments
     250                for (LineSegment ls : ds.pendingLineSegments())
     251                        if (n == ls.getStart() || n == ls.getEnd())
     252                                return "Node used by a line segment which is not part of any track. Remove this first.";
     253               
     254                // These line segments must be combined within the track combining
     255                ArrayList<LineSegment> pendingLineSegmentsForTrack = new ArrayList<LineSegment>();
     256
     257                // try to combine line segments
     258               
     259                // These line segments are combinable. The inner arraylist has always
     260                // two elements. The keys maps to the track, the line segments are in.
     261                HashMap<ArrayList<LineSegment>, Track> lineSegments = new HashMap<ArrayList<LineSegment>, Track>();
     262               
     263                for (Track t : ds.tracks()) {
     264                        ArrayList<LineSegment> current = new ArrayList<LineSegment>();
     265                        for (LineSegment ls : t.segments())
     266                                if (ls.getStart() == n || ls.getEnd() == n)
     267                                        current.add(ls);
     268                        if (!current.isEmpty()) {
     269                                if (current.size() > 2)
     270                                        return "Node used by more than two line segments.";
     271                                if (current.size() == 1 &&
     272                                                (current.get(0) == t.getStartingSegment() || current.get(0) == t.getEndingSegment()))
     273                                        pendingLineSegmentsForTrack.add(current.get(0));
     274                                else if (current.get(0).getEnd() != current.get(1).getStart() &&
     275                                                current.get(1).getEnd() != current.get(0).getStart())
     276                                        return "Node used by line segments that points together.";
     277                                else if (!current.get(0).keyPropertiesMergable(current.get(1)))
     278                                        return "Node used by line segments with different properties.";
     279                                else
     280                                        lineSegments.put(current, t);
     281                        }
     282                }
     283               
     284                // try to combine tracks
     285                ArrayList<Track> tracks = new ArrayList<Track>();
     286                for (Track t : ds.tracks())
     287                        if (t.getStartingNode() == n || t.getEndingNode() == n)
     288                                tracks.add(t);
     289                if (!tracks.isEmpty()) {
     290                        if (tracks.size() > 2)
     291                                return "Node used by more than two tracks.";
     292                        if (tracks.size() == 1)
     293                                return "Node used by a track.";
     294                        Track t1 = tracks.get(0);
     295                        Track t2 = tracks.get(1);
     296                        if (t1.getStartingNode() != t2.getEndingNode() &&
     297                                        t2.getStartingNode() != t1.getEndingNode()) {
     298                                if (t1.getStartingNode() == t2.getStartingNode() ||
     299                                                t1.getEndingNode() == t2.getEndingNode())
     300                                        return "Node used by tracks that point together.";
     301                                return "Node used by tracks that cannot be combined.";
     302                        }
     303                        if (!t1.keyPropertiesMergable(t2))
     304                                return "Node used by tracks with different properties.";
     305                }
     306               
     307                // try to match the pending line segments
     308                if (pendingLineSegmentsForTrack.size() == 2) {
     309                        LineSegment l1 = pendingLineSegmentsForTrack.get(0);
     310                        LineSegment l2 = pendingLineSegmentsForTrack.get(1);
     311                        if (l1.getStart() == l2.getStart() || l1.getEnd() == l2.getEnd())
     312                                return "Node used by line segments that points together.";
     313                        if (l1.getStart() == l2.getEnd() || l2.getStart() == l1.getEnd())
     314                                pendingLineSegmentsForTrack.clear(); // resolved.
     315                }
     316               
     317                // still pending line segments?
     318                if (!pendingLineSegmentsForTrack.isEmpty())
     319                        return "Node used by tracks that cannot be combined.";
     320
     321                // Ok, we can combine. Do it.
     322                // line segments
     323                for (ArrayList<LineSegment> list : lineSegments.keySet()) {
     324                        LineSegment first = list.get(0);
     325                        LineSegment second = list.get(1);
     326                        if (first.getStart() == second.getEnd()) {
     327                                first = second;
     328                                second = list.get(0);
     329                        }
     330                        first.setEnd(second.getEnd());
     331                        first.keys = mergeKeys(first.keys, second.keys);
     332                        lineSegments.get(list).remove(second);
     333                }
     334               
     335                // tracks
     336                if (!tracks.isEmpty()) {
     337                        Track first = tracks.get(0);
     338                        Track second = tracks.get(1);
     339                        if (first.getStartingNode() == second.getEndingNode()) {
     340                                first = second;
     341                                second = tracks.get(0);
     342                        }
     343                        // concatenate the line segments.
     344                        LineSegment lastOfFirst = first.getEndingSegment();
     345                        LineSegment firstOfSecond = second.getStartingSegment();
     346                        lastOfFirst.setEnd(firstOfSecond.getEnd());
     347                        lastOfFirst.keys = mergeKeys(lastOfFirst.keys, firstOfSecond.keys);
     348                        second.remove(firstOfSecond);
     349                        // move the remaining line segments to first track.
     350                        first.addAll(second.segments());
     351                        ds.removeTrack(second);
     352                }
     353               
     354                return null;
     355        }
     356
     357        /**
     358         * Merges the second parameter into the first and return the merged map.
     359         * @param first The first map that will hold keys.
     360         * @param second The map to merge with the first.
     361         * @return The merged key map.
     362         */
     363        private Map<Key, String> mergeKeys(Map<Key, String> first, Map<Key, String> second) {
     364                if (first == null)
    274365                        first = second;
    275                         second = t;
    276                 }
    277                
    278                 // combinable?
    279                 if (first.end != second.start || !first.end.keyPropertiesMergable(second.start)) {
    280                         if (msgBox)
    281                                 JOptionPane.showMessageDialog(Main.main, "Node used by line segments that cannot be combined.");
    282                         return false;
    283                 }
    284 
    285                 // Ok, we can combine. Do it.
    286                 mv.editLayer().add(new CombineAndDeleteCommand(ds, first, second));
     366                else if (second != null && first != null)
     367                        first.putAll(second);
     368                return first;
     369        }
     370
     371        @Override
     372        protected boolean isEditMode() {
    287373                return true;
    288374        }
  • /src/org/openstreetmap/josm/actions/mapmode/MapMode.java

    r30 r20  
    66import java.awt.event.MouseMotionListener;
    77
    8 import org.openstreetmap.josm.actions.JosmAction;
     8import javax.swing.AbstractAction;
     9import javax.swing.JComponent;
     10import javax.swing.KeyStroke;
     11
     12import org.openstreetmap.josm.gui.ImageProvider;
    913import org.openstreetmap.josm.gui.MapFrame;
    1014import org.openstreetmap.josm.gui.MapView;
     15import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
     16import org.openstreetmap.josm.gui.layer.Layer;
    1117
    1218/**
     
    1824 * control.
    1925 */
    20 abstract public class MapMode extends JosmAction implements MouseListener, MouseMotionListener {
     26abstract public class MapMode extends AbstractAction implements MouseListener, MouseMotionListener {
    2127
    2228        /**
     
    3642         */
    3743        public MapMode(String name, String iconName, String tooltip, int mnemonic, MapFrame mapFrame) {
    38                 super(name, "mapmode/"+iconName, tooltip, mnemonic, null);
     44                super(name, ImageProvider.get("mapmode", iconName));
     45                putValue(MNEMONIC_KEY, mnemonic);
     46                putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(mnemonic,0));
     47                putValue(LONG_DESCRIPTION, tooltip);
     48                mapFrame.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(mnemonic,0), this);
     49                mapFrame.getActionMap().put(this, this);
    3950                this.mapFrame = mapFrame;
    4051                mv = mapFrame.mapView;
     52                mv.addLayerChangeListener(new LayerChangeListener(){
     53                        public void activeLayerChange(Layer oldLayer, Layer newLayer) {
     54                                setEnabled(!isEditMode() || newLayer.isEditable());
     55                        }
     56                        public void layerAdded(Layer newLayer) {}
     57                        public void layerRemoved(Layer oldLayer) {}
     58                });
    4159        }
     60
     61        /**
     62         * Subclasses should return whether they want to edit the map data or
     63         * whether they are read-only.
     64         */
     65        abstract protected boolean isEditMode();
    4266
    4367        /**
     
    6387                mapFrame.selectMapMode(this);
    6488        }
    65 
     89       
    6690        /**
    6791         * Does nothing. Only to subclass.
  • /src/org/openstreetmap/josm/actions/mapmode/MoveAction.java

    r30 r20  
    66import java.awt.event.MouseEvent;
    77import java.util.Collection;
     8import java.util.HashSet;
    89
    9 import org.openstreetmap.josm.Main;
    10 import org.openstreetmap.josm.command.MoveCommand;
    11 import org.openstreetmap.josm.data.GeoPoint;
     10import org.openstreetmap.josm.data.osm.DataSet;
     11import org.openstreetmap.josm.data.osm.Node;
    1212import org.openstreetmap.josm.data.osm.OsmPrimitive;
    1313import org.openstreetmap.josm.gui.MapFrame;
     
    7575                }
    7676
    77                 GeoPoint mouseGeo = mv.getPoint(e.getX(), e.getY(), false);
    78                 GeoPoint mouseStartGeo = mv.getPoint(mousePos.x, mousePos.y, false);
    79                 double dx = mouseGeo.x - mouseStartGeo.x;
    80                 double dy = mouseGeo.y - mouseStartGeo.y;
     77                int dx = e.getX() - mousePos.x;
     78                int dy = e.getY() - mousePos.y;
    8179                if (dx == 0 && dy == 0)
    8280                        return;
    8381
    84                 Collection<OsmPrimitive> selection = Main.main.ds.getSelected();
    85                 mv.editLayer().add(new MoveCommand(selection, dx, dy));
     82                Collection<OsmPrimitive> selection = mv.getActiveDataSet().getSelected();
     83                // creating a list of all nodes that should be moved.
     84                Collection<Node> movingNodes = new HashSet<Node>();
     85                for (OsmPrimitive osm : selection)
     86                        movingNodes.addAll(osm.getAllNodes());
     87
     88                for (Node n : movingNodes) {
     89                        Point pos = mv.getScreenPoint(n.coor);
     90                        pos.x += dx;
     91                        pos.y += dy;
     92                        n.coor = mv.getPoint(pos.x, pos.y, true);
     93                }
     94                mv.repaint();
    8695               
    87                 mv.repaint();
    8896                mousePos = e.getPoint();
    8997        }
     
    103111                        return;
    104112
    105                 if (Main.main.ds.getSelected().size() == 0) {
     113                DataSet ds = mv.getActiveDataSet();
     114
     115                if (ds.getSelected().size() == 0) {
    106116                        OsmPrimitive osm = mv.getNearest(e.getPoint(), (e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) != 0);
    107117                        if (osm != null)
    108                                 osm.setSelected(true);
     118                                osm.setSelected(true, ds);
    109119                        singleOsmPrimitive = osm;
    110120                        mv.repaint();
     
    124134                mv.setCursor(oldCursor);
    125135                if (singleOsmPrimitive != null) {
    126                         singleOsmPrimitive.setSelected(false);
     136                        singleOsmPrimitive.setSelected(false, mv.getActiveDataSet());
    127137                        mv.repaint();
    128138                }
    129139        }
     140
     141        @Override
     142        protected boolean isEditMode() {
     143                return true;
     144        }
    130145}
  • /src/org/openstreetmap/josm/actions/mapmode/SelectionAction.java

    r30 r20  
    55import java.util.Collection;
    66
    7 import org.openstreetmap.josm.Main;
     7import org.openstreetmap.josm.data.osm.DataSet;
    88import org.openstreetmap.josm.data.osm.OsmPrimitive;
    99import org.openstreetmap.josm.gui.MapFrame;
     
    8787                        return; // not allowed together
    8888
     89                DataSet ds = mv.getActiveDataSet();
     90
    8991                if (!ctrl && !shift)
    90                         Main.main.ds.clearSelection(); // new selection will replace the old.
     92                        ds.clearSelection(); // new selection will replace the old.
    9193
    9294                Collection<OsmPrimitive> selectionList = selectionManager.getObjectsInRectangle(r,alt);
    9395                for (OsmPrimitive osm : selectionList)
    94                         osm.setSelected(!ctrl);
     96                        osm.setSelected(!ctrl, ds);
    9597                mv.repaint();
    9698        }
     99
     100        @Override
     101        protected boolean isEditMode() {
     102                return false;
     103        }
    97104}
  • /src/org/openstreetmap/josm/actions/mapmode/ZoomAction.java

    r30 r20  
    6868                selectionManager.unregister(mv);
    6969        }
     70
     71        @Override
     72        protected boolean isEditMode() {
     73                return false;
     74        }
    7075}
  • /src/org/openstreetmap/josm/data/Bounds.java

    r30 r20  
    4545                this.max = max;
    4646        }
    47        
    48         /**
    49          * @return The bounding rectangle that covers <code>this</code> and
    50          *              the <code>other</code> bounds, regarding the x/y values.
    51          */
    52         public Bounds mergeXY(Bounds other) {
    53                 GeoPoint nmin = new GeoPoint();
    54                 nmin.x = Math.min(min.x, other.min.x);
    55                 nmin.y = Math.min(min.y, other.min.y);
    56                 GeoPoint nmax = new GeoPoint();
    57                 nmax.x = Math.max(max.x, other.max.x);
    58                 nmax.y = Math.max(max.y, other.max.y);
    59                 return new Bounds(nmin, nmax);
    60         }
    61        
    62         /**
    63          * @return The bounding rectangle that covers <code>this</code> and
    64          *              the <code>other</code> bounds, regarding the lat/lon values.
    65          */
    66         public Bounds mergeLatLon(Bounds other) {
    67                 GeoPoint nmin = new GeoPoint(
    68                                 Math.min(min.lat, other.min.lat),
    69                                 Math.min(min.lon, other.min.lon));
    70                 GeoPoint nmax = new GeoPoint(
    71                                 Math.max(max.lat, other.max.lat),
    72                                 Math.max(max.lon, other.max.lon));
    73                 return new Bounds(nmin, nmax);
    74         }
    7547}
  • /src/org/openstreetmap/josm/data/Preferences.java

    r30 r20  
    134134                        mergeNodes = root.getChild("mergeNodes") != null;
    135135                        drawRawGpsLines = root.getChild("drawRawGpsLines") != null;
    136                         forceRawGpsLines = root.getChild("forceRawGpsLines") != null;
    137136                } catch (Exception e) {
    138137                        if (e instanceof PreferencesException)
     
    157156                if (drawRawGpsLines)
    158157                        children.add(new Element("drawRawGpsLines"));
    159                 if (forceRawGpsLines)
    160                         children.add(new Element("forceRawGpsLines"));
    161158                Element osmServer = new Element("osm-server");
    162159                osmServer.getChildren().add(new Element("url").setText(osmDataServer));
     
    180177        }
    181178
     179       
    182180        // projection change listener stuff
    183181       
     
    186184         */
    187185        private Collection<PropertyChangeListener> listener = new LinkedList<PropertyChangeListener>();
    188 
    189186        /**
    190187         * Add a listener of projection changes to the list of listeners.
  • /src/org/openstreetmap/josm/data/SelectionTracker.java

    r30 r20  
    5959         * @author imi
    6060         */
    61         private enum SelectionEventState {WAITING, COLLECTING, PURGING}
     61        private enum SelectionEventState {WAITING, COLLECTING, PURGING};
    6262
    6363        /**
    6464         * The state, regarding to the selection changing that we are in.
    6565         */
    66         transient SelectionEventState state = SelectionEventState.WAITING;
     66        transient private SelectionEventState state = SelectionEventState.WAITING;
    6767
    6868        /**
    6969         * A list of listeners to selection changed events.
    7070         */
    71         transient Collection<SelectionChangedListener> listeners = new LinkedList<SelectionChangedListener>();
     71        transient private Collection<SelectionChangedListener> listeners = new LinkedList<SelectionChangedListener>();
    7272
    7373       
  • /src/org/openstreetmap/josm/data/osm/DataSet.java

    r30 r20  
    22
    33import java.util.Collection;
     4import java.util.Collections;
    45import java.util.HashMap;
    56import java.util.HashSet;
     7import java.util.Iterator;
    68import java.util.LinkedList;
    79import java.util.Map;
     10import java.util.Set;
    811
    912import org.openstreetmap.josm.data.Bounds;
     
    1114
    1215/**
    13  * DataSet is the data behind the application. It can consist of only a few
    14  * points up to the whole osm database. DataSet's can be merged together,
    15  * saved, (up/down/disk)loaded etc.
     16 * DataSet is the data behind one window in the application. It can consist of only a few
     17 * points up to the whole osm database. DataSet's can be merged together, split up into
     18 * several different ones, saved, (up/down/disk)loaded etc.
    1619 *
    17  * Note, that DataSet is not an osm-primitive and so has no key association
    18  * but a few members to store some information.
     20 * Note, that DataSet is not an osm-primitive, so it has no key association but a few
     21 * members to store some information.
    1922 *
    2023 * @author imi
    2124 */
    22 public class DataSet extends SelectionTracker {
     25public class DataSet extends SelectionTracker implements Cloneable {
    2326
    2427        /**
     
    3033
    3134        /**
    32          * All line segments goes here, even when they are in a track.
    33          */
    34         public Collection<LineSegment> lineSegments = new LinkedList<LineSegment>();
     35         * All pending line segments goes here. Pending line segments are those, that
     36         * are in this list but are in no track.
     37         */
     38        private Collection<LineSegment> pendingLineSegments = new LinkedList<LineSegment>();
    3539
    3640        /**
     
    4145         * track list.
    4246         */
    43         public Collection<Track> tracks = new LinkedList<Track>();
     47        private Collection<Track> tracks = new LinkedList<Track>();
     48
     49        /**
     50         * Add the track to the tracklist.
     51         */
     52        public void addTrack(Track t) {
     53                tracks.add(t);
     54        }
     55        /**
     56         * Remove the track from the tracklist.
     57         */
     58        public void removeTrack(Track t) {
     59                t.destroy();
     60                tracks.remove(t);
     61        }
     62        /**
     63         * Return a read-only collection of all tracks
     64         */
     65        public Collection<Track> tracks() {
     66                return Collections.unmodifiableCollection(tracks);
     67        }
     68
     69        /**
     70         * Add a newly created line segment to the pending lines list.
     71         */
     72        public void addPendingLineSegment(LineSegment ls) {
     73                pendingLineSegments.add(ls);
     74        }
     75        /**
     76         * Remove a line segment from the pending lines list, because it has been
     77         * assigned to the track.
     78         * @param ls The line segment from the pending list
     79         * @param t The track, that will hold the line segment
     80         * @param end <code>true</code> to attach on the end. <code>false</code>
     81         *              to attach on the beginning.
     82         */
     83        public void assignPendingLineSegment(LineSegment ls, Track t, boolean end) {
     84                pendingLineSegments.remove(ls);
     85                if (end)
     86                        t.add(ls);
     87                else
     88                        t.addStart(ls);
     89        }
     90        /**
     91         * Delete the pending line segment without moving it anywhere.
     92         */
     93        public void destroyPendingLineSegment(LineSegment ls) {
     94                pendingLineSegments.remove(ls);
     95                ls.destroy();
     96        }
     97        /**
     98         * Return an read-only iterator over all pending line segments.
     99         */
     100        public Collection<LineSegment> pendingLineSegments() {
     101                return Collections.unmodifiableCollection(pendingLineSegments);
     102        }
    44103
    45104        /**
     
    111170        public void clearSelection() {
    112171                clearSelection(nodes);
    113                 clearSelection(lineSegments);
    114172                clearSelection(tracks);
     173                for (Track t : tracks)
     174                        clearSelection(t.segments());
    115175        }
    116176
     
    122182        public Collection<OsmPrimitive> getSelected() {
    123183                Collection<OsmPrimitive> sel = getSelected(nodes);
    124                 sel.addAll(getSelected(lineSegments));
     184                sel.addAll(getSelected(pendingLineSegments));
    125185                sel.addAll(getSelected(tracks));
     186                for (Track t : tracks)
     187                        sel.addAll(getSelected(t.segments()));
    126188                return sel;
    127189        }
     
    131193         * The objects imported are not cloned, so from now on, these data belong
    132194         * to both datasets. So use mergeFrom only if you are about to abandon the
    133          * other dataset.
    134          *
    135          * Elements are tried to merged.
    136          * Nodes are merged first, if their lat/lon are equal.
    137          * Line segments are merged, if they have the same nodes.
    138          * Tracks are merged, if they consist of the same line segments.
    139          *
    140          * TODO Additional to that, every two objects with the same id are merged.
    141          *
     195         * other dataset or this dataset.
     196         *
    142197         * @param ds    The DataSet to merge into this one.
    143          */
    144         public void mergeFrom(DataSet ds) {
    145                 // merge nodes
    146                
    147                 Map<Node, Node> nodeMap = new HashMap<Node, Node>();
    148 
    149                 // find mergable
    150                 for (Node otherNode : ds.nodes)
    151                         for (Node myNode : nodes)
    152                                 if (otherNode.coor.equalsLatLon(myNode.coor))
    153                                         nodeMap.put(otherNode, myNode);
    154                 // add
    155                 for (Node n : ds.nodes)
    156                         if (!nodeMap.containsKey(n))
    157                                 nodes.add(n);
    158                 // reassign
    159                 for (LineSegment ls : ds.lineSegments) {
    160                         Node n = nodeMap.get(ls.start);
    161                         if (n != null)
    162                                 ls.start = n;
    163                         n = nodeMap.get(ls.end);
    164                         if (n != null)
    165                                 ls.end = n;
    166                 }
    167 
    168 
    169                 // merge line segments
    170 
    171                 Map<LineSegment, LineSegment> lsMap = new HashMap<LineSegment, LineSegment>();
    172                 // find mergable
    173                 for (LineSegment otherLS : ds.lineSegments)
    174                         for (LineSegment myLS : lineSegments)
    175                                 if (otherLS.start == myLS.start && otherLS.end == myLS.end)
    176                                         lsMap.put(otherLS, myLS);
    177                 // add ls
    178                 for (LineSegment ls : ds.lineSegments)
    179                         if (!lsMap.containsKey(ls))
    180                                 lineSegments.add(ls);
    181                 // reassign
    182                 for (Track t : ds.tracks) {
    183                         for (int i = 0; i < t.segments.size(); ++i) {
    184                                 LineSegment newLS = lsMap.get(t.segments.get(i));
    185                                 if (newLS != null)
    186                                         t.segments.set(i, newLS);
    187                         }
    188                 }
    189 
    190 
    191                 // merge tracks
    192                
    193                 LinkedList<Track> trackToAdd = new LinkedList<Track>();
    194                 for (Track otherTrack : ds.tracks) {
    195                         boolean found = false;
    196                         for (Track myTrack : tracks) {
    197                                 if (myTrack.segments.equals(otherTrack.segments)) {
    198                                         found = true;
    199                                         break;
     198         * @param mergeEqualNodes If <code>true</code>, nodes with the same lat/lon
     199         *              are merged together.
     200         */
     201        public void mergeFrom(DataSet ds, boolean mergeEqualNodes) {
     202                System.out.println(nodes.size()+" "+pendingLineSegments.size()+" "+tracks.size());
     203                if (mergeEqualNodes) {
     204                        Map<Node, Node> mergeMap = new HashMap<Node, Node>();
     205                        Set<Node> nodesToAdd = new HashSet<Node>();
     206                        for (Node n : nodes) {
     207                                for (Iterator<Node> it = ds.nodes.iterator(); it.hasNext();) {
     208                                        Node dsn = it.next();
     209                                        if (n.coor.equalsLatLon(dsn.coor)) {
     210                                                mergeMap.put(dsn, n);
     211                                                n.mergeFrom(dsn);
     212                                                it.remove();
     213                                        } else {
     214                                                nodesToAdd.add(dsn);
     215                                        }
    200216                                }
    201217                        }
    202                         if (!found)
    203                                 trackToAdd.add(otherTrack);
    204                 }
    205                 tracks.addAll(trackToAdd);
     218                        nodes.addAll(nodesToAdd);
     219                        for (Track t : ds.tracks) {
     220                                for (LineSegment ls : t.segments()) {
     221                                        Node n = mergeMap.get(ls.getStart());
     222                                        if (n != null)
     223                                                ls.start = n;
     224                                        n = mergeMap.get(ls.getEnd());
     225                                        if (n != null)
     226                                                ls.end = n;
     227                                }
     228                        }
     229                        tracks.addAll(ds.tracks);
     230                        for (LineSegment ls : ds.pendingLineSegments) {
     231                                Node n = mergeMap.get(ls.getStart());
     232                                if (n != null)
     233                                        ls.start = n;
     234                                n = mergeMap.get(ls.getEnd());
     235                                if (n != null)
     236                                        ls.end = n;
     237                        }
     238                        pendingLineSegments.addAll(ds.pendingLineSegments);
     239                } else {
     240                        nodes.addAll(ds.nodes);
     241                        tracks.addAll(ds.tracks);
     242                        pendingLineSegments.addAll(ds.pendingLineSegments);
     243                }
     244                System.out.println(nodes.size()+" "+pendingLineSegments.size()+" "+tracks.size());
    206245        }
    207246
     
    214253                        return;
    215254                for (OsmPrimitive osm : list) {
    216                         osm.setSelected(false);
     255                        osm.setSelected(false, this);
    217256                        if (osm.keys != null)
    218257                                clearSelection(osm.keys.keySet());
     
    236275                return sel;
    237276        }
     277
     278
     279        @Override
     280        public DataSet clone() {
     281                try {return (DataSet)super.clone();} catch (CloneNotSupportedException e) {}
     282                return null;
     283        }
    238284}
  • /src/org/openstreetmap/josm/data/osm/Key.java

    r30 r20  
    11package org.openstreetmap.josm.data.osm;
    22
     3import java.util.Collection;
    34import java.util.HashMap;
     5import java.util.LinkedList;
    46import java.util.Map;
    57
     
    2224         * All keys are stored here.
    2325         */
    24         public static final Map<String, Key> allKeys = new HashMap<String, Key>();
     26        private static Map<String, Key> allKeys = new HashMap<String, Key>();
    2527       
    2628        /**
     
    4749        }
    4850       
     51        /**
     52         * Return an empty list, since keys cannot have nodes.
     53         */
     54        @Override
     55        public Collection<Node> getAllNodes() {
     56                return new LinkedList<Node>();
     57        }
     58
    4959        @Override
    5060        public void visit(Visitor visitor) {
    5161                visitor.visit(this);
    5262        }
    53 
    54         @Override
    55         public String toString() {
    56                 return name;
    57         }
    5863}
  • /src/org/openstreetmap/josm/data/osm/LineSegment.java

    r30 r20  
    11package org.openstreetmap.josm.data.osm;
     2
     3import java.util.Collection;
     4import java.util.Collections;
     5import java.util.LinkedList;
    26
    37import org.openstreetmap.josm.data.osm.visitor.Visitor;
     
    1418         * The starting node of the line segment
    1519         */
    16         public Node start;
     20        Node start;
    1721       
    1822        /**
    1923         * The ending node of the line segment
    2024         */
    21         public Node end;
     25        Node end;
     26
     27        /**
     28         * The tracks, this line segment is part of.
     29         */
     30        transient Collection<Track> parent = new LinkedList<Track>();
    2231
    2332        /**
     
    2938                this.start = start;
    3039                this.end = end;
     40                start.parentSegment.add(this);
     41                end.parentSegment.add(this);
     42        }
     43
     44        /**
     45         * Return all parent tracks this line segment is part of. The list is readonly.
     46         */
     47        public Collection<Track> getParents() {
     48                return Collections.unmodifiableCollection(parent);
     49        }
     50
     51        public void setStart(Node start) {
     52                this.start.parentSegment.remove(this);
     53                this.start = start;
     54                start.parentSegment.add(this);
     55        }
     56        public Node getStart() {
     57                return start;
     58        }
     59        public void setEnd(Node end) {
     60                this.end.parentSegment.remove(this);
     61                this.end = end;
     62                end.parentSegment.add(this);
     63        }
     64        public Node getEnd() {
     65                return end;
     66        }
     67
     68        /**
     69         * The LineSegment is going to be destroyed. Unlink all back references.
     70         */
     71        void destroy() {
     72                start.parentSegment.remove(this);
     73                end.parentSegment.remove(this);
     74        }
     75
     76        /**
     77         * Return start and end in a list.
     78         */
     79        @Override
     80        public Collection<Node> getAllNodes() {
     81                LinkedList<Node> nodes = new LinkedList<Node>();
     82                nodes.add(getStart());
     83                nodes.add(getEnd());
     84                return nodes;
    3185        }
    3286
  • /src/org/openstreetmap/josm/data/osm/Node.java

    r30 r20  
    11package org.openstreetmap.josm.data.osm;
     2
     3import java.util.Collection;
     4import java.util.Collections;
     5import java.util.LinkedList;
    26
    37import org.openstreetmap.josm.data.GeoPoint;
     
    1721        public GeoPoint coor;
    1822
     23        /**
     24         * The list of line segments, this node is part of.
     25         */
     26        transient Collection<LineSegment> parentSegment = new LinkedList<LineSegment>();
     27
     28        /**
     29         * Returns a read-only list of all segments this node is in.
     30         * @return A list of all segments. Readonly.
     31         */
     32        public Collection<LineSegment> getParentSegments() {
     33                return Collections.unmodifiableCollection(parentSegment);
     34        }
     35
     36        /**
     37         * Merge the node given at parameter with this node.
     38         * All parents of the parameter-node become parents of this node.
     39         *
     40         * The argument node is not changed.
     41         *
     42         * @param node Merge the node to this.
     43         */
     44        public void mergeFrom(Node node) {
     45                parentSegment.addAll(node.parentSegment);
     46                if (keys == null)
     47                        keys = node.keys;
     48                else if (node.keys != null)
     49                        keys.putAll(node.keys);
     50        }
     51       
     52        /**
     53         * Return a list only this added.
     54         */
     55        @Override
     56        public Collection<Node> getAllNodes() {
     57                LinkedList<Node> nodes = new LinkedList<Node>();
     58                nodes.add(this);
     59                return nodes;
     60        }
     61
    1962        @Override
    2063        public void visit(Visitor visitor) {
  • /src/org/openstreetmap/josm/data/osm/OsmPrimitive.java

    r30 r20  
    11package org.openstreetmap.josm.data.osm;
    22
     3import java.util.Collection;
    34import java.util.Map;
    45
    5 import org.openstreetmap.josm.Main;
    66import org.openstreetmap.josm.data.osm.visitor.Visitor;
    77
     
    1919         */
    2020        public Map<Key, String> keys;
    21 
     21       
    2222        /**
    23          * Unique identifier in OSM. This is used to reidentify objects in the server.
    24          * An id of 0 means an unknown id. The object has not been uploaded yet to
    25          * know what id it will get.
     23         * If set to true, this object has been modified in the current session.
    2624         */
    27         public long id = 0;
    28 
     25        transient public boolean modified = false;
     26       
    2927        /**
    3028         * If set to true, this object is currently selected.
    3129         */
    3230        transient private boolean selected = false;
     31
     32        /**
     33         * Return a list of all nodes, this osmPrimitive consists of. Does return
     34         * an empty list, if it is an primitive that cannot have nodes (e.g. Key)
     35         * TODO replace with visitor
     36         */
     37        abstract public Collection<Node> getAllNodes();
    3338
    3439        /**
     
    6671         * changed later, if the value actualy changed.
    6772         * @param selected Whether the primitive should be selected or not.
     73         * @param ds The dataSet, this primitive is in.
    6874         */
    69         public void setSelected(boolean selected) {
     75        public void setSelected(boolean selected, DataSet ds) {
    7076                if (selected != this.selected)
    71                         Main.main.ds.fireSelectionChanged();
     77                        ds.fireSelectionChanged();
    7278                this.selected = selected;
    7379        }
     
    7985                return selected;
    8086        }
    81 
    82 
    83         /**
    84          * Equal, if the id is equal. If both ids are 0, use the super classes equal
    85          * instead.
    86          */
    87         @Override
    88         public boolean equals(Object obj) {
    89                 if (!(obj instanceof OsmPrimitive))
    90                         return false;
    91                 OsmPrimitive osm = (OsmPrimitive)obj;
    92                 if (id == 0 && osm.id == 0)
    93                         return super.equals(obj);
    94                 return id == osm.id;
    95         }
    96 
    97         /**
    98          * Return the id as hashcode or supers hashcode if 0.
    99          */
    100         @Override
    101         public int hashCode() {
    102                 return id == 0 ? super.hashCode() : (int)id;
    103         }
    10487}
  • /src/org/openstreetmap/josm/data/osm/Track.java

    r30 r20  
    22
    33import java.util.ArrayList;
     4import java.util.Collection;
     5import java.util.Collections;
    46import java.util.List;
    57
     
    1618         * All track segments in this track
    1719         */
    18         public final List<LineSegment> segments = new ArrayList<LineSegment>();
     20        private final List<LineSegment> segments = new ArrayList<LineSegment>();
    1921
    2022       
     
    2426        public void add(LineSegment ls) {
    2527                segments.add(ls);
     28                ls.parent.add(this);
     29        }
     30
     31        /**
     32         * Add the line segment at first position to the track. First position means,
     33         * the line segment's start becomes the starting node.
     34         * @param ls The line segment to add at starting position.
     35         * @see #getStartingNode()
     36         */
     37        public void addStart(LineSegment ls) {
     38                segments.add(ls);
     39                ls.parent.add(this);
     40        }
     41
     42        /**
     43         * Add all LineSegment's to the list of segments.
     44         * @param lineSegments The line segments to add.
     45         */
     46        public void addAll(Collection<? extends LineSegment> lineSegments) {
     47                segments.addAll(lineSegments);
     48                for (LineSegment ls : lineSegments)
     49                        ls.parent.add(this);
     50        }
     51       
     52        /**
     53         * Remove the line segment from the track.
     54         */
     55        public void remove(LineSegment ls) {
     56                if (segments.remove(ls))
     57                        if (!ls.parent.remove(this))
     58                                throw new IllegalStateException("Parent violation detected.");
     59        }
     60
     61        /**
     62         * Return an read-only collection. Do not alter the object returned.
     63         * @return The read-only Collection of all segments.
     64         */
     65        public Collection<LineSegment> segments() {
     66                return Collections.unmodifiableCollection(segments);
     67        }
     68
     69        /**
     70         * Return a merge of getAllNodes - calls to the line segments.
     71         */
     72        @Override
     73        public Collection<Node> getAllNodes() {
     74                ArrayList<Node> nodes = new ArrayList<Node>();
     75                for (LineSegment ls : segments)
     76                        nodes.addAll(ls.getAllNodes());
     77                return nodes;
     78        }
     79        /**
     80         * The track is going to be destroyed. Unlink all back references.
     81         */
     82        void destroy() {
     83                for (LineSegment ls : segments) {
     84                        ls.parent.remove(this);
     85                        if (ls.parent.isEmpty())
     86                                ls.destroy();
     87                }
     88                segments.clear();
    2689        }
    2790
     
    38101                if (segments.isEmpty())
    39102                        return null;
    40                 return segments.get(segments.size()-1).end;
     103                return segments.get(segments.size()-1).getEnd();
    41104        }
    42105       
     
    63126                if (segments.isEmpty())
    64127                        return null;
    65                 return segments.get(0).start;
     128                return segments.get(0).getStart();
    66129        }
    67130       
  • /src/org/openstreetmap/josm/data/osm/visitor/SelectionComponentVisitor.java

    r30 r20  
    1919 * @author imi
    2020 */
    21 public class SelectionComponentVisitor implements Visitor {
     21public class SelectionComponentVisitor extends Visitor {
    2222
    2323        /**
     
    3434         * A key icon and the name of the key.
    3535         */
     36        @Override
    3637        public void visit(Key k) {
    3738                name = k.name;
     
    4445         * "(x1,y1) -> (x2,y2)" is displayed with the nodes coordinates.
    4546         */
     47        @Override
    4648        public void visit(LineSegment ls) {
    4749                String name = getName(ls.keys);
    4850                if (name == null)
    49                         name = "("+ls.start.coor.lat+","+ls.start.coor.lon+") -> ("+ls.end.coor.lat+","+ls.end.coor.lon+")";
     51                        name = "("+ls.getStart().coor.lat+","+ls.getStart().coor.lon+") -> ("+ls.getEnd().coor.lat+","+ls.getEnd().coor.lon+")";
    5052                       
    5153                this.name = name;
     
    5759         * is displayed.
    5860         */
     61        @Override
    5962        public void visit(Node n) {
    6063                String name = getName(n.keys);
     
    7073         * is displayed with x beeing the number of nodes in the track.
    7174         */
     75        @Override
    7276        public void visit(Track t) {
    7377                String name = getName(t.keys);
    7478                if (name == null) {
    7579                        Set<Node> nodes = new HashSet<Node>();
    76                         for (LineSegment ls : t.segments) {
    77                                 nodes.add(ls.start);
    78                                 nodes.add(ls.end);
     80                        for (LineSegment ls : t.segments()) {
     81                                nodes.add(ls.getStart());
     82                                nodes.add(ls.getEnd());
    7983                        }
    8084                        name = "("+nodes.size()+" nodes)";
  • /src/org/openstreetmap/josm/data/osm/visitor/Visitor.java

    r30 r20  
    1212 * @author imi
    1313 */
    14 public interface Visitor {
    15         void visit(Node n);
    16         void visit(LineSegment ls);
    17         void visit(Track t);
    18         void visit(Key k);
     14abstract public class Visitor {
     15        public void visit(Node n) {}
     16        public void visit(LineSegment ls) {}
     17        public void visit(Track t) {}
     18        public void visit(Key k) {}
    1919}
  • /src/org/openstreetmap/josm/data/projection/Projection.java

    r30 r20  
    88import javax.swing.event.ChangeListener;
    99
    10 import org.openstreetmap.josm.data.Bounds;
    1110import org.openstreetmap.josm.data.GeoPoint;
     11import org.openstreetmap.josm.data.osm.DataSet;
    1212
    1313/**
     
    7171
    7272        /**
    73          * Initialize itself with the given bounding rectangle (regarding lat/lon).
     73         * Initialize itself with the given dataSet.
    7474         *
    7575         * This function should initialize own parameters needed to do the
     
    8181         * This implementation does nothing. It is provided only for subclasses
    8282         * to initialize their data members.
     83         *
     84         * @param dataSet
     85         *            The dataset, which will be displayed on screen. Later, all
     86         *            projections should be relative to the given dataset. Any
     87         *            reverse projections (xy2latlon) can be assumed to be in near
     88         *            distance to nodes of this dataset (that means, it is ok, if
     89         *            there is a conversion error, if the requested x/y to xy2latlon
     90         *            is far away from any coordinate in the dataset)
    8391         */
    84         public void init(Bounds b) {}
     92        public void init(DataSet dataSet) {}
    8593       
    8694        /**
  • /src/org/openstreetmap/josm/data/projection/UTM.java

    r30 r20  
    1515import javax.swing.SpinnerNumberModel;
    1616
    17 import org.openstreetmap.josm.Main;
    1817import org.openstreetmap.josm.data.Bounds;
    1918import org.openstreetmap.josm.data.GeoPoint;
     19import org.openstreetmap.josm.data.osm.DataSet;
    2020import org.openstreetmap.josm.gui.GBC;
     21import org.openstreetmap.josm.gui.Main;
    2122
    2223/**
     
    7980        };
    8081
    81         private enum Hemisphere {north, south}
     82        private enum Hemisphere {north, south};
    8283
    8384        /**
     
    101102         * Spinner with all possible zones for the configuration panel
    102103         */
    103         JSpinner zoneSpinner;
     104        private JSpinner zoneSpinner;
    104105        /**
    105106         * Hemisphere combo for the configuration panel
    106107         */
    107         JComboBox hemisphereCombo;
     108        private JComboBox hemisphereCombo;
    108109
    109110       
     
    186187         * @author imi
    187188         */
    188         private static class ZoneData {
     189        private class ZoneData {
    189190                int zone = 0;
    190191                Hemisphere hemisphere = Hemisphere.north;
     
    192193        /**
    193194         * Try to autodetect the zone and hemisphere from the dataset.
     195         * @param dataSet The dataset to extrakt zone information from.
    194196         * @return The zone data extrakted from the dataset.
    195197         */
    196         ZoneData autoDetect(Bounds b) {
     198        private ZoneData autoDetect(DataSet dataSet) {
    197199                ZoneData zd = new ZoneData();
     200               
     201                Bounds b = dataSet.getBoundsLatLon();
    198202                if (b == null)
    199203                        return zd;
     
    230234         */
    231235        @Override
    232         public void init(Bounds b) {
     236        public void init(DataSet dataSet) {
    233237                if (zone == 0) {
    234                         ZoneData zd = autoDetect(b);
     238                        ZoneData zd = autoDetect(dataSet);
    235239                        zone = zd.zone;
    236240                        hemisphere = zd.hemisphere;
     
    270274                        public void actionPerformed(ActionEvent e) {
    271275                                if (Main.main.getMapFrame() != null) {
    272                                         ZoneData zd = autoDetect(Main.main.ds.getBoundsLatLon());
     276                                        DataSet ds = Main.main.getMapFrame().mapView.getActiveDataSet();
     277                                        ZoneData zd = autoDetect(ds);
    273278                                        if (zd.zone == 0)
    274279                                                JOptionPane.showMessageDialog(Main.main, "Autodetection failed. Maybe the data set contain too few information.");
  • /src/org/openstreetmap/josm/gui/BookmarkList.java

    r30 r20  
    1616import javax.swing.JOptionPane;
    1717
    18 import org.openstreetmap.josm.Main;
    1918import org.openstreetmap.josm.data.Preferences;
    2019
  • /src/org/openstreetmap/josm/gui/IconToggleButton.java

    r30 r20  
    2525                // Tooltip
    2626                String toolTipText = "";
    27                 Object o = action.getValue(Action.SHORT_DESCRIPTION);
     27                Object o = action.getValue(Action.LONG_DESCRIPTION);
    2828                if (o != null)
    29                         toolTipText = o.toString();
     29                        toolTipText += o.toString();
     30                o = action.getValue(Action.ACCELERATOR_KEY);
     31                if (o != null) {
     32                        String ksName = o.toString();
     33                        if (ksName.startsWith("pressed "))
     34                                ksName = ksName.substring("pressed ".length());
     35                        else if (ksName.startsWith("released "))
     36                                ksName = ksName.substring("released ".length());
     37                        toolTipText += " Shortcut: "+ksName;
     38                }
    3039                setToolTipText(toolTipText);
    3140               
  • /src/org/openstreetmap/josm/gui/ImageProvider.java

    r30 r20  
    1313import javax.swing.ImageIcon;
    1414
    15 import org.openstreetmap.josm.Main;
    16 
    1715/**
    1816 * Helperclass to support the application with images.
     
    2523         * @author imi
    2624         */
    27         public enum OverlayPosition {NORTHWEST, NORTHEAST, SOUTHWEST, SOUTHEAST}
     25        public enum OverlayPosition {NORTHWEST, NORTHEAST, SOUTHWEST, SOUTHEAST};
    2826       
    2927        /**
  • /src/org/openstreetmap/josm/gui/MapFrame.java

    r30 r20  
    44import java.awt.Component;
    55import java.awt.Container;
     6import java.awt.event.WindowAdapter;
     7import java.awt.event.WindowEvent;
    68import java.beans.PropertyChangeEvent;
    79import java.beans.PropertyChangeListener;
    810
    911import javax.swing.AbstractButton;
    10 import javax.swing.BoxLayout;
    1112import javax.swing.ButtonGroup;
    1213import javax.swing.JPanel;
     
    1819import org.openstreetmap.josm.actions.mapmode.AddNodeAction;
    1920import org.openstreetmap.josm.actions.mapmode.AddTrackAction;
     21import org.openstreetmap.josm.actions.mapmode.CombineAction;
    2022import org.openstreetmap.josm.actions.mapmode.DeleteAction;
    2123import org.openstreetmap.josm.actions.mapmode.MapMode;
     
    5254         */
    5355        public MapStatus statusLine;
    54         /**
    55          * The action to open the layer list
    56          */
    57         private LayerList layerList;
    58         /**
    59          * Action to open the properties panel for the selected objects
    60          */
    61         private PropertiesDialog propertiesDialog;
    62         /**
    63          * Action to open a list of all selected objects
    64          */
    65         private SelectionListDialog selectionListDialog;
    6656
    6757        /**
     
    8676                toolBarActions.add(new IconToggleButton(this, new AddLineSegmentAction(this)));
    8777                toolBarActions.add(new IconToggleButton(this, new AddTrackAction(this)));
     78                toolBarActions.add(new IconToggleButton(this, new CombineAction(this)));
    8879                toolBarActions.add(new IconToggleButton(this, new DeleteAction(this)));
    8980
     
    10899                });
    109100
    110                 JPanel toggleDialogs = new JPanel();
    111                 add(toggleDialogs, BorderLayout.EAST);
     101                // layer list
     102                toolBarActions.add(new IconToggleButton(this, new LayerList(this)));
     103               
     104                // properties
     105                toolBarActions.add(new IconToggleButton(this, new PropertiesDialog(this)));
    112106
    113                 toggleDialogs.setLayout(new BoxLayout(toggleDialogs, BoxLayout.Y_AXIS));
    114                 toolBarActions.add(new IconToggleButton(this, layerList = new LayerList(this)));
    115                 toggleDialogs.add(layerList);
    116                 toolBarActions.add(new IconToggleButton(this, propertiesDialog = new PropertiesDialog(this)));
    117                 toggleDialogs.add(propertiesDialog);
    118                 toolBarActions.add(new IconToggleButton(this, selectionListDialog = new SelectionListDialog(this)));
    119                 toggleDialogs.add(selectionListDialog);
    120                
     107                // selection dialog
     108                SelectionListDialog selectionList = new SelectionListDialog(this);
     109                final IconToggleButton buttonSelection = new IconToggleButton(this, selectionList);
     110                selectionList.addWindowListener(new WindowAdapter(){
     111                        @Override
     112                        public void windowClosing(WindowEvent e) {
     113                                buttonSelection.setSelected(false);
     114                        }
     115                });
     116                toolBarActions.add(buttonSelection);
    121117
    122118                // status line below the map
  • /src/org/openstreetmap/josm/gui/MapStatus.java

    r30 r20  
    4747         * The position of the mouse cursor.
    4848         */
    49         JTextField positionText = new JTextField("-000.00000000000000 -000.00000000000000".length());
     49        private JTextField positionText = new JTextField("-000.00000000000000 -000.00000000000000".length());
    5050        /**
    5151         * The field holding the name of the object under the mouse.
    5252         */
    53         JTextField nameText = new JTextField(30);
     53        private JTextField nameText = new JTextField(30);
    5454
    5555        /**
     
    147147         * The last sent mouse movement event.
    148148         */
    149         MouseState mouseState = new MouseState();
     149        private MouseState mouseState = new MouseState();
    150150       
    151151        /**
  • /src/org/openstreetmap/josm/gui/MapView.java

    r30 r20  
    1717import javax.swing.event.ChangeListener;
    1818
    19 import org.openstreetmap.josm.Main;
    2019import org.openstreetmap.josm.data.Bounds;
    2120import org.openstreetmap.josm.data.GeoPoint;
     
    2726import org.openstreetmap.josm.data.projection.Projection;
    2827import org.openstreetmap.josm.gui.layer.Layer;
    29 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    3028
    3129/**
    3230 * This is a component used in the MapFrame for browsing the map. It use is to
    3331 * provide the MapMode's enough capabilities to operate.
     32 *
     33 * MapView holds the map data, organize it, convert it, provide access to it.
    3434 *
    3535 * MapView hold meta-data about the data set currently displayed, as scale level,
     
    7373        private ArrayList<Layer> layers = new ArrayList<Layer>();
    7474        /**
    75          * Direct link to the edit layer (if any) in the layers list.
    76          */
    77         private OsmDataLayer editLayer;
    78         /**
    7975         * The layer from the layers list that is currently active.
    8076         */
     
    9086         */
    9187        public MapView(Layer layer) {
     88                if (layer.getDataSet() == null)
     89                        throw new IllegalArgumentException("Initial layer must have a dataset.");
     90
    9291                addComponentListener(new ComponentAdapter(){
    9392                        @Override
     
    103102                addLayer(layer);
    104103                Main.pref.addPropertyChangeListener(this);
     104
     105                // init screen
     106                recalculateCenterScale();
    105107        }
    106108
     
    110112         */
    111113        public void addLayer(Layer layer) {
    112                 // initialize the projection if it is the first layer
    113                 if (layers.isEmpty())
    114                         Main.pref.getProjection().init(layer.getBoundsLatLon());
    115 
    116                 // reinitialize layer's data
    117                 layer.init(Main.pref.getProjection());
    118 
    119                 if (layer instanceof OsmDataLayer) {
    120                         if (editLayer != null) {
    121                                 // merge the layer into the existing one
    122                                 if (!editLayer.isMergable(layer))
    123                                         throw new IllegalArgumentException("Cannot merge argument");
    124                                 editLayer.mergeFrom(layer);
    125                                 repaint();
    126                                 return;
    127                         }
    128                         editLayer = (OsmDataLayer)layer;
    129                 }
    130 
    131                 // add as a new layer
    132114                layers.add(0,layer);
     115
     116                DataSet ds = layer.getDataSet();
     117
     118                if (ds != null) {
     119                        // initialize the projection if it was the first layer
     120                        if (layers.size() == 1)
     121                                Main.pref.getProjection().init(ds);
     122                       
     123                        // initialize the dataset in the new layer
     124                        for (Node n : ds.nodes)
     125                                Main.pref.getProjection().latlon2xy(n.coor);
     126                }
    133127
    134128                for (LayerChangeListener l : listeners)
    135129                        l.layerAdded(layer);
    136130
    137                 // autoselect the new layer
    138131                setActiveLayer(layer);
    139132        }
    140 
     133       
    141134        /**
    142135         * Remove the layer from the mapview. If the layer was in the list before,
     
    147140                        for (LayerChangeListener l : listeners)
    148141                                l.layerRemoved(layer);
    149                 if (layer == editLayer)
    150                         editLayer = null;
    151142        }
    152143
     
    241232                OsmPrimitive minPrimitive = null;
    242233
     234                // calculate the object based on the current active dataset.
     235                DataSet ds = getActiveDataSet();
     236               
    243237                // nodes
    244                 for (Node n : Main.main.ds.nodes) {
     238                for (Node n : ds.nodes) {
    245239                        Point sp = getScreenPoint(n.coor);
    246240                        double dist = p.distanceSq(sp);
     
    254248               
    255249                // pending line segments
    256                 for (LineSegment ls : Main.main.ds.lineSegments) {
    257                         Point A = getScreenPoint(ls.start.coor);
    258                         Point B = getScreenPoint(ls.end.coor);
     250                for (LineSegment ls : ds.pendingLineSegments()) {
     251                        Point A = getScreenPoint(ls.getStart().coor);
     252                        Point B = getScreenPoint(ls.getEnd().coor);
    259253                        double c = A.distanceSq(B);
    260254                        double a = p.distanceSq(B);
     
    269263                // tracks & line segments
    270264                minDistanceSq = Double.MAX_VALUE;
    271                 for (Track t : Main.main.ds.tracks) {
    272                         for (LineSegment ls : t.segments) {
    273                                 Point A = getScreenPoint(ls.start.coor);
    274                                 Point B = getScreenPoint(ls.end.coor);
     265                for (Track t : ds.tracks()) {
     266                        for (LineSegment ls : t.segments()) {
     267                                Point A = getScreenPoint(ls.getStart().coor);
     268                                Point B = getScreenPoint(ls.getEnd().coor);
    275269                                double c = A.distanceSq(B);
    276270                                double a = p.distanceSq(B);
     
    326320                for (int i = layers.size()-1; i >= 0; --i) {
    327321                        Layer l = layers.get(i);
    328                         if (l.visible)
     322                        if (l.isVisible())
    329323                                l.paint(g, this);
    330324                }
     
    338332                // reset all datasets.
    339333                Projection p = Main.pref.getProjection();
    340                 for (Node n : Main.main.ds.nodes)
    341                         p.latlon2xy(n.coor);
     334                for (Layer l : layers) {
     335                        DataSet ds = l.getDataSet();
     336                        if (ds != null)
     337                                for (Node n : ds.nodes)
     338                                        p.latlon2xy(n.coor);
     339                }
    342340                recalculateCenterScale();
    343341        }
     
    377375
    378376       
     377        /**
     378         * Return the dataSet for the current selected layer. If the active layer
     379         * does not have a dataset, return the DataSet from the next layer a.s.o.
     380         * 
     381         * @return The DataSet of the current active layer.
     382         */
     383        public DataSet getActiveDataSet() {
     384                if (activeLayer.getDataSet() != null)
     385                        return activeLayer.getDataSet();
     386                for (Layer l : layers) {
     387                        DataSet ds = l.getDataSet();
     388                        if (ds != null)
     389                                return ds;
     390                }
     391                throw new IllegalStateException("No dataset found.");
     392        }
     393
    379394        /**
    380395         * Change to the new projection. Recalculate the dataset and zoom, if autoZoom
     
    410425                                h = 20;
    411426                       
    412                         Bounds bounds = null;
    413                         for (Layer l : layers) {
    414                                 if (bounds == null)
    415                                         bounds = l.getBoundsXY();
    416                                 else {
    417                                         Bounds lb = l.getBoundsXY();
    418                                         if (lb != null)
    419                                                 bounds = bounds.mergeXY(lb);
    420                                 }
    421                         }
    422 
     427                        Bounds bounds = getActiveDataSet().getBoundsXY();
     428                       
    423429                        boolean oldAutoScale = autoScale;
    424430                        GeoPoint oldCenter = center;
     
    473479        /**
    474480         * Set the active selection to the given value and raise an layerchange event.
    475          * Also, swap the active dataset in Main.main if it is a datalayer.
    476481         */
    477482        public void setActiveLayer(Layer layer) {
     
    480485                Layer old = activeLayer;
    481486                activeLayer = layer;
    482                 if (layer instanceof OsmDataLayer)
    483                         Main.main.ds = ((OsmDataLayer)layer).data;
    484487                if (old != layer) {
     488                        if (old != null && old.getDataSet() != null)
     489                                old.getDataSet().clearSelection();
    485490                        for (LayerChangeListener l : listeners)
    486491                                l.activeLayerChange(old, layer);
     
    495500                return activeLayer;
    496501        }
    497 
    498         /**
    499          * @return The current edit layer. If no edit layer exist, one is created.
    500          *              So editLayer does never return <code>null</code>.
    501          */
    502         public OsmDataLayer editLayer() {
    503                 if (editLayer == null)
    504                         addLayer(new OsmDataLayer(new DataSet(), "unnamed"));
    505                 return editLayer;
    506         }
    507502}
  • /src/org/openstreetmap/josm/gui/PreferenceDialog.java

    r30 r20  
    2828import javax.swing.UIManager.LookAndFeelInfo;
    2929
    30 import org.openstreetmap.josm.Main;
    3130import org.openstreetmap.josm.data.Preferences;
    3231import org.openstreetmap.josm.data.Preferences.PreferencesException;
     
    9190         * Indicate, that the application has to be restarted for the settings to take effect.
    9291         */
    93         boolean requiresRestart = false;
     92        private boolean requiresRestart = false;
    9493        /**
    9594         * ComboBox with all look and feels.
    9695         */
    97         JComboBox lafCombo = new JComboBox(UIManager.getInstalledLookAndFeels());
     96        private JComboBox lafCombo = new JComboBox(UIManager.getInstalledLookAndFeels());
    9897        /**
    9998         * Combobox with all projections available
    10099         */
    101         JComboBox projectionCombo = new JComboBox(Preferences.allProjections.clone());
     100        private JComboBox projectionCombo = new JComboBox(Preferences.allProjections.clone());
    102101        /**
    103102         * The main tab panel.
     
    108107         * Editfield for the Base url to the REST API from OSM.
    109108         */
    110         JTextField osmDataServer = new JTextField(20);
     109        private JTextField osmDataServer = new JTextField(20);
    111110        /**
    112111         * Editfield for the username to the OSM account.
    113112         */
    114         JTextField osmDataUsername = new JTextField(20);
     113        private JTextField osmDataUsername = new JTextField(20);
    115114        /**
    116115         * Passwordfield for the userpassword of the REST API.
    117116         */
    118         JPasswordField osmDataPassword = new JPasswordField(20);
     117        private JPasswordField osmDataPassword = new JPasswordField(20);
    119118        /**
    120119         * The checkbox stating whether nodes should be merged together.
    121120         */
    122         JCheckBox drawRawGpsLines = new JCheckBox("Draw lines between raw gps points.");
     121        private JCheckBox drawRawGpsLines = new JCheckBox("Draw lines between raw gps points.");
    123122        /**
    124123         * The checkbox stating whether raw gps lines should be forced.
    125124         */
    126         JCheckBox forceRawGpsLines = new JCheckBox("Force lines if no line segments imported.");
     125        private JCheckBox forceRawGpsLines = new JCheckBox("Force lines if no line segments imported.");
    127126        /**
    128127         * The checkbox stating whether nodes should be merged together.
    129128         */
    130         JCheckBox mergeNodes = new JCheckBox("Merge nodes with equal latitude/longitude.");
     129        private JCheckBox mergeNodes = new JCheckBox("Merge nodes with equal latitude/longitude.");
    131130
    132131        /**
  • /src/org/openstreetmap/josm/gui/SelectionManager.java

    r30 r20  
    1515import java.util.LinkedList;
    1616
    17 import org.openstreetmap.josm.Main;
     17import org.openstreetmap.josm.data.osm.DataSet;
    1818import org.openstreetmap.josm.data.osm.LineSegment;
    1919import org.openstreetmap.josm.data.osm.Node;
     
    272272                } else {
    273273                        // nodes
    274                         for (Node n : Main.main.ds.nodes) {
     274                        DataSet ds = mv.getActiveDataSet();
     275                        for (Node n : ds.nodes) {
    275276                                if (r.contains(mv.getScreenPoint(n.coor)))
    276277                                        selection.add(n);
     
    278279                       
    279280                        // pending line segments
    280                         for (LineSegment ls : Main.main.ds.lineSegments)
     281                        for (LineSegment ls : ds.pendingLineSegments())
    281282                                if (rectangleContainLineSegment(r, alt, ls))
    282283                                        selection.add(ls);
    283284
    284285                        // tracks
    285                         for (Track t : Main.main.ds.tracks) {
    286                                 boolean wholeTrackSelected = !t.segments.isEmpty();
    287                                 for (LineSegment ls : t.segments)
     286                        for (Track t : ds.tracks()) {
     287                                boolean wholeTrackSelected = !t.segments().isEmpty();
     288                                for (LineSegment ls : t.segments())
    288289                                        if (rectangleContainLineSegment(r, alt, ls))
    289290                                                selection.add(ls);
     
    310311        private boolean rectangleContainLineSegment(Rectangle r, boolean alt, LineSegment ls) {
    311312                if (alt) {
    312                         Point p1 = mv.getScreenPoint(ls.start.coor);
    313                         Point p2 = mv.getScreenPoint(ls.end.coor);
     313                        Point p1 = mv.getScreenPoint(ls.getStart().coor);
     314                        Point p2 = mv.getScreenPoint(ls.getEnd().coor);
    314315                        if (r.intersectsLine(p1.x, p1.y, p2.x, p2.y))
    315316                                return true;
    316317                } else {
    317                         if (r.contains(mv.getScreenPoint(ls.start.coor))
    318                                         && r.contains(mv.getScreenPoint(ls.end.coor)))
     318                        if (r.contains(mv.getScreenPoint(ls.getStart().coor))
     319                                        && r.contains(mv.getScreenPoint(ls.getEnd().coor)))
    319320                                return true;
    320321                }
  • /src/org/openstreetmap/josm/gui/dialogs/LayerList.java

    r30 r20  
    2323import javax.swing.event.ListSelectionListener;
    2424
    25 import org.openstreetmap.josm.Main;
    2625import org.openstreetmap.josm.data.osm.DataSet;
    2726import org.openstreetmap.josm.gui.ImageProvider;
     27import org.openstreetmap.josm.gui.Main;
    2828import org.openstreetmap.josm.gui.MapFrame;
    2929import org.openstreetmap.josm.gui.MapView;
     
    4242         * The data model for the list component.
    4343         */
    44         DefaultListModel model = new DefaultListModel();
     44        private DefaultListModel model = new DefaultListModel();
    4545        /**
    4646         * The list component holding all layers.
    4747         */
    48         JList layers = new JList(model);
     48        private JList layers = new JList(model);
    4949        /**
    5050         * The invisible icon blended over invisible layers.
    5151         */
    52         static final Icon invisible = ImageProvider.get("layer", "invisible");
     52        private static final Icon invisible = ImageProvider.get("layer", "invisible");
    5353
    5454        /**
     
    6969         */
    7070        private JButton deleteButton = new JButton(ImageProvider.get("dialogs", "delete"));
    71 
     71       
    7272        /**
    7373         * Create an layerlist and attach it to the given mapView.
    7474         */
    7575        public LayerList(MapFrame mapFrame) {
    76                 super("Layers", "List of all layers", "layerlist", KeyEvent.VK_L, "Open a list of all loaded layers.");
    77                 setPreferredSize(new Dimension(320,100));
     76                super(mapFrame, "Layers", "List of all layers", "layerlist", KeyEvent.VK_L, "Open a list of all loaded layers.");
     77                setSize(250,256);
     78                setMinimumSize(new Dimension(70,70));
    7879                add(new JScrollPane(layers), BorderLayout.CENTER);
    7980                layers.setBackground(UIManager.getColor("Button.background"));
     
    8384                                Layer layer = (Layer)value;
    8485                                JLabel label = (JLabel)super.getListCellRendererComponent(list,
    85                                                 layer.name, index, isSelected, cellHasFocus);
     86                                                layer.getName(), index, isSelected, cellHasFocus);
    8687                                Icon icon = layer.getIcon();
    87                                 if (!layer.visible)
     88                                if (!layer.isVisible())
    8889                                        icon = ImageProvider.overlay(icon, invisible, ImageProvider.OverlayPosition.SOUTHEAST);
    8990                                label.setIcon(icon);
    90                                 label.setToolTipText(layer.getToolTipText());
     91                               
     92                                DataSet ds = layer.getDataSet();
     93                                if (ds != null) {
     94                                        label.setToolTipText(ds.nodes.size()+" nodes, "+
     95                                                        ds.tracks().size()+" tracks");
     96                                }
    9197                                return label;
    9298                        }
     
    94100
    95101                final MapView mapView = mapFrame.mapView;
    96 
     102               
    97103                Collection<Layer> data = mapView.getAllLayers();
    98104                for (Layer l : data)
     
    109115                });
    110116                mapView.addLayerChangeListener(this);
    111 
     117               
    112118                // Buttons
    113119                JPanel buttonPanel = new JPanel(new GridLayout(1, 5));
     
    142148                        public void actionPerformed(ActionEvent e) {
    143149                                Layer l = (Layer)layers.getSelectedValue();
    144                                 l.visible = !l.visible;
     150                                l.setVisible(!l.isVisible());
    145151                                mapView.repaint();
    146152                                layers.repaint();
     
    154160                                if (model.size() == 1) {
    155161                                        Main.main.setMapFrame(null, null);
    156                                         Main.main.ds = new DataSet();
    157162                                } else {
    158163                                        int sel = layers.getSelectedIndex();
     
    168173                mergeButton.setToolTipText("Merge the selected layer into the layer directly below.");
    169174                mergeButton.addActionListener(new ActionListener(){
    170                         public void actionPerformed(ActionEvent e) {
    171                                 Layer lFrom = (Layer)layers.getSelectedValue();
    172                                 Layer lTo = (Layer)model.get(layers.getSelectedIndex()+1);
    173                                 lTo.mergeFrom(lFrom);
    174                                 layers.setSelectedValue(lTo, true);
    175                                 mapView.removeLayer(lFrom);
    176                         }
    177                 });             
     175                                public void actionPerformed(ActionEvent e) {
     176                                        Layer lFrom = (Layer)layers.getSelectedValue();
     177                                        DataSet dsFrom = lFrom.getDataSet();
     178                                        Layer lTo = (Layer)model.get(layers.getSelectedIndex()+1);
     179                                        DataSet dsTo = lTo.getDataSet();
     180                                        dsTo.mergeFrom(dsFrom, Main.pref.mergeNodes);
     181                                        layers.setSelectedValue(lTo, true);
     182                                        mapView.removeLayer(lFrom);
     183                                }
     184                        });             
    178185                buttonPanel.add(mergeButton);
    179186
     
    186193         * Updates the state of the Buttons.
    187194         */
    188         void updateButtonEnabled() {
     195        private void updateButtonEnabled() {
    189196                int sel = layers.getSelectedIndex();
    190197                Layer l = (Layer)layers.getSelectedValue();
    191198                boolean enable = model.getSize() > 1;
    192199                enable = enable && sel < model.getSize()-1;
    193                 enable = enable && l.isMergable((Layer)model.get(sel+1));
     200                enable = enable && l.getDataSet() != null;
     201                enable = enable && ((Layer)model.get(sel+1)).getDataSet() != null;
     202                enable = enable && l.isEditable() == ((Layer)model.get(sel+1)).isEditable();
    194203                mergeButton.setEnabled(enable);
    195204                upButton.setEnabled(sel > 0);
  • /src/org/openstreetmap/josm/gui/dialogs/PropertiesDialog.java

    r30 r20  
    11package org.openstreetmap.josm.gui.dialogs;
    22
    3 import java.awt.BorderLayout;
    4 import java.awt.Component;
    5 import java.awt.Dimension;
    6 import java.awt.Font;
    7 import java.awt.GridLayout;
    8 import java.awt.event.ActionEvent;
    9 import java.awt.event.ActionListener;
    103import java.awt.event.KeyEvent;
    11 import java.awt.event.MouseAdapter;
    12 import java.awt.event.MouseEvent;
    13 import java.awt.event.WindowEvent;
    14 import java.awt.event.WindowFocusListener;
    15 import java.util.Collection;
    16 import java.util.HashMap;
    17 import java.util.Iterator;
    18 import java.util.TreeMap;
    19 import java.util.TreeSet;
    20 import java.util.Vector;
    21 import java.util.Map.Entry;
    224
    23 import javax.swing.JButton;
    24 import javax.swing.JComboBox;
    25 import javax.swing.JDialog;
     5import javax.swing.BorderFactory;
     6import javax.swing.Box;
    267import javax.swing.JLabel;
    27 import javax.swing.JOptionPane;
    28 import javax.swing.JPanel;
    29 import javax.swing.JScrollPane;
    30 import javax.swing.JTable;
    31 import javax.swing.JTextField;
    32 import javax.swing.ListSelectionModel;
    33 import javax.swing.table.DefaultTableCellRenderer;
    34 import javax.swing.table.DefaultTableModel;
     8import javax.swing.border.Border;
    359
    36 import org.openstreetmap.josm.Main;
    37 import org.openstreetmap.josm.command.ChangeKeyValueCommand;
    38 import org.openstreetmap.josm.data.SelectionChangedListener;
    39 import org.openstreetmap.josm.data.osm.Key;
    40 import org.openstreetmap.josm.data.osm.OsmPrimitive;
    41 import org.openstreetmap.josm.gui.ImageProvider;
     10import org.openstreetmap.josm.gui.Main;
    4211import org.openstreetmap.josm.gui.MapFrame;
    43 import org.openstreetmap.josm.gui.MapView;
    4412
    4513/**
    46  * This dialog displays the properties of the current selected primitives.
    47  *
    48  * If no object is selected, the dialog list is empty.
    49  * If only one is selected, all properties of this object are selected.
    50  * If more than one object are selected, the sum of all properties are displayed. If the
    51  * different objects share the same property, the shared value is displayed. If they have
    52  * different values, all of them are put in a combo box and the string "&lt;different&gt;"
    53  * is displayed in italic.
    54  *
    55  * Below the list, the user can click on an add, modify and delete property button to
    56  * edit the table selection value.
    57  *
    58  * The command is applied to all selected entries.
     14 * Open a Property dialog for the current visible map. When saving to own josm-
     15 * data format, the properties are saved along.
    5916 *
    6017 * @author imi
    6118 */
    62 public class PropertiesDialog extends ToggleDialog implements SelectionChangedListener {
     19public class PropertiesDialog extends ToggleDialog {
    6320
    64         /**
    65          * Watches for double clicks and start editing or new property, depending on the
    66          * location, the click was.
    67          * @author imi
    68          */
    69         public class DblClickWatch extends MouseAdapter {
    70                 @Override
    71                 public void mouseClicked(MouseEvent e) {
    72                         if (e.getClickCount() < 2)
    73                                 return;
    74                         if (e.getSource() instanceof JScrollPane)
    75                                 add();
    76                         else {
    77                                 int row = propertyTable.rowAtPoint(e.getPoint());
    78                                 edit(row);
    79                         }
    80                 }
    81         }
    82        
    83         /**
    84          * Edit the value in the table row
    85          * @param row   The row of the table, from which the value is edited.
    86          */
    87         void edit(int row) {
    88                 String key = data.getValueAt(row, 0).toString();
    89                 Collection<OsmPrimitive> sel = Main.main.ds.getSelected();
    90                 String msg = "<html>This will change "+sel.size()+" object"+(sel.size()==1?"":"s")+".<br><br>"+
    91                 "Please select a new value for '"+key+"'.<br>(Empty string deletes the key.)";
    92                 final JComboBox combo = (JComboBox)data.getValueAt(row, 1);
    93                 JPanel p = new JPanel(new BorderLayout());
    94                 p.add(new JLabel(msg+"</html>"), BorderLayout.NORTH);
    95                 p.add(combo, BorderLayout.CENTER);
    96 
    97                 final JOptionPane optionPane = new JOptionPane(p, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
    98                 final JDialog dlg = optionPane.createDialog(PropertiesDialog.this, "Change values?");
    99                 dlg.addWindowFocusListener(new WindowFocusListener(){
    100                         public void windowGainedFocus(WindowEvent e) {
    101                                 combo.requestFocusInWindow();
    102                         }
    103                         public void windowLostFocus(WindowEvent e) {
    104                         }
    105                 });
    106                 combo.getEditor().addActionListener(new ActionListener(){
    107                         public void actionPerformed(ActionEvent e) {
    108                                 optionPane.setValue(JOptionPane.OK_OPTION);
    109                                 dlg.setVisible(false);
    110                         }
    111                 });
    112                 String oldComboEntry = combo.getEditor().getItem().toString();
    113                 dlg.setVisible(true);
    114 
    115                 Object answer = optionPane.getValue();
    116                 if (answer == null || answer == JOptionPane.UNINITIALIZED_VALUE ||
    117                                 (answer instanceof Integer && (Integer)answer != JOptionPane.OK_OPTION)) {
    118                         combo.getEditor().setItem(oldComboEntry);
    119                         return;
    120                 }
    121 
    122                 String value = combo.getEditor().getItem().toString();
    123                 if (value.equals("<different>"))
    124                         return;
    125                 if (value.equals(""))
    126                         value = null; // delete the key
    127                 mv.editLayer().add(new ChangeKeyValueCommand(sel, Key.get(key), value));
    128 
    129                 if (value == null)
    130                         selectionChanged(sel); // update whole table
    131                 else
    132                         PropertiesDialog.this.repaint(); // repaint is enough
    133         }
    134        
    135         /**
    136          * Open the add selection dialog and add a new key/value to the table (and to the
    137          * dataset, of course).
    138          */
    139         void add() {
    140                 Collection<OsmPrimitive> sel = Main.main.ds.getSelected();
    141                
    142                 JPanel p = new JPanel(new BorderLayout());
    143                 p.add(new JLabel("<html>This will change "+sel.size()+" object"+(sel.size()==1?"":"s")+".<br><br>"+
    144                 "Please select a key"), BorderLayout.NORTH);
    145                 Vector<String> allKeys = new Vector<String>(Key.allKeys.keySet());
    146                 for (Iterator<String> it = allKeys.iterator(); it.hasNext();) {
    147                         String s = it.next();
    148                         for (int i = 0; i < data.getRowCount(); ++i) {
    149                                 if (s.equals(data.getValueAt(i, 0))) {
    150                                         it.remove();
    151                                         break;
    152                                 }
    153                         }
    154                 }
    155                 JComboBox keys = new JComboBox(allKeys);
    156                 keys.setEditable(true);
    157                 p.add(keys, BorderLayout.CENTER);
    158                
    159                 JPanel p2 = new JPanel(new BorderLayout());
    160                 p.add(p2, BorderLayout.SOUTH);
    161                 p2.add(new JLabel("Please select a value"), BorderLayout.NORTH);
    162                 JTextField values = new JTextField();
    163                 p2.add(values, BorderLayout.CENTER);
    164                 int answer = JOptionPane.showConfirmDialog(PropertiesDialog.this, p,
    165                                 "Change values?", JOptionPane.OK_CANCEL_OPTION);
    166                 if (answer != JOptionPane.OK_OPTION)
    167                         return;
    168                 String key = keys.getEditor().getItem().toString();
    169                 String value = values.getText();
    170                 if (value.equals(""))
    171                         return;
    172                 mv.editLayer().add(new ChangeKeyValueCommand(sel, Key.get(key), value));
    173                 selectionChanged(sel); // update table
    174         }
    175 
    176         /**
    177          * Delete the keys from the given row.
    178          * @param row   The row, which key gets deleted from the dataset.
    179          */
    180         private void delete(int row) {
    181                 String key = data.getValueAt(row, 0).toString();
    182                 Collection<OsmPrimitive> sel = Main.main.ds.getSelected();
    183                 mv.editLayer().add(new ChangeKeyValueCommand(sel, Key.get(key), null));
    184                 selectionChanged(sel); // update table
    185         }
    186        
    187         /**
    188          * The property data.
    189          */
    190         private final DefaultTableModel data = new DefaultTableModel(){
    191                 @Override
    192                 public boolean isCellEditable(int row, int column) {
    193                         return false;
    194                 }
    195                 @Override
    196                 public Class<?> getColumnClass(int columnIndex) {
    197                         return columnIndex == 1 ? JComboBox.class : String.class;
    198                 }
    199         };
    200         /**
    201          * The properties list.
    202          */
    203         private final JTable propertyTable = new JTable(data);
    204         /**
    205          * The map view this dialog operates on.
    206          */
    207         private final MapView mv;
    208        
    20921        /**
    21022         * Create a new PropertiesDialog
    21123         */
    21224        public PropertiesDialog(MapFrame mapFrame) {
    213                 super("Properties", "Properties Dialog", "properties", KeyEvent.VK_P, "Property for selected objects.");
    214                 mv = mapFrame.mapView;
     25                super(mapFrame, "Properties of "+Main.main.getNameOfLoadedMapFrame(), "Properties Dialog", "properties", KeyEvent.VK_P, "Property page for this map.");
     26                putValue(MNEMONIC_KEY, KeyEvent.VK_P);
    21527
    216                 setPreferredSize(new Dimension(320,150));
     28                final Border panelBorder = BorderFactory.createEmptyBorder(5,0,0,0);
     29                Box panel = Box.createVerticalBox();
    21730               
    218                 data.setColumnIdentifiers(new String[]{"Key", "Value"});
    219                 propertyTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    220                 propertyTable.setDefaultRenderer(JComboBox.class, new DefaultTableCellRenderer(){
    221                         @Override
    222                         public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    223                                 Component c = super.getTableCellRendererComponent(table, value, isSelected, false, row, column);
    224                                 if (c instanceof JLabel) {
    225                                         String str = ((JComboBox)value).getEditor().getItem().toString();
    226                                         ((JLabel)c).setText(str);
    227                                         if (str.equals("<different>"))
    228                                                 c.setFont(c.getFont().deriveFont(Font.ITALIC));
    229                                 }
    230                                 return c;
    231                         }
    232                 });
    233                 propertyTable.setDefaultRenderer(String.class, new DefaultTableCellRenderer(){
    234                         @Override
    235                         public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    236                                 return super.getTableCellRendererComponent(table, value, isSelected, false, row, column);
    237                         }
    238                 });
    239                 propertyTable.addMouseListener(new DblClickWatch());
    240 
    241                 JScrollPane scrollPane = new JScrollPane(propertyTable);
    242                 scrollPane.addMouseListener(new DblClickWatch());
    243                 add(scrollPane, BorderLayout.CENTER);
     31                JLabel todo = new JLabel("Nothing implemented yet.");
     32                todo.setBorder(panelBorder);
     33                panel.add(todo);
    24434               
    245                 JPanel buttonPanel = new JPanel(new GridLayout(1,3));
    246                 ActionListener buttonAction = new ActionListener(){
    247                         public void actionPerformed(ActionEvent e) {
    248                                 int sel = propertyTable.getSelectedRow();
    249                                 if (e.getActionCommand().equals("Add"))
    250                                         add();
    251                                 else if (e.getActionCommand().equals("Edit")) {
    252                                         if (sel == -1)
    253                                                 JOptionPane.showMessageDialog(PropertiesDialog.this, "Please select the row to edit.");
    254                                         else
    255                                                 edit(sel);
    256                                 } else if (e.getActionCommand().equals("Delete")) {
    257                                         if (sel == -1)
    258                                                 JOptionPane.showMessageDialog(PropertiesDialog.this, "Please select the row to delete.");
    259                                         else
    260                                                 delete(sel);
    261                                 }
    262                         }
    263                 };
    264                 buttonPanel.add(createButton("Add", "Add a new key/value pair to all objects", KeyEvent.VK_A, buttonAction));
    265                 buttonPanel.add(createButton("Edit", "Edit the value of the selected key for all objects", KeyEvent.VK_E, buttonAction));
    266                 buttonPanel.add(createButton("Delete", "Delete the selected key in all objects", KeyEvent.VK_D, buttonAction));
    267                 add(buttonPanel, BorderLayout.SOUTH);
    268         }
    269        
    270         private JButton createButton(String name, String tooltip, int mnemonic, ActionListener actionListener) {
    271                 JButton b = new JButton(name, ImageProvider.get("dialogs", name.toLowerCase()));
    272                 b.setActionCommand(name);
    273                 b.addActionListener(actionListener);
    274                 b.setToolTipText(tooltip);
    275                 b.setMnemonic(mnemonic);
    276                 return b;
    277         }
    278 
    279         @Override
    280         public void setVisible(boolean b) {
    281                 if (b) {
    282                         Main.main.ds.addSelectionChangedListener(this);
    283                         selectionChanged(Main.main.ds.getSelected());
    284                 } else {
    285                         Main.main.ds.removeSelectionChangedListener(this);
    286                 }
    287                 super.setVisible(b);
    288         }
    289 
    290         public void selectionChanged(Collection<OsmPrimitive> newSelection) {
    291                 if (propertyTable.getCellEditor() != null)
    292                         propertyTable.getCellEditor().cancelCellEditing();
    293                 data.setRowCount(0);
    294                 TreeMap<String, Collection<String>> props = new TreeMap<String, Collection<String>>();
    295                 HashMap<String, Integer> valueCounts = new HashMap<String, Integer>();
    296                 for (OsmPrimitive osm : newSelection) {
    297                         if (osm.keys != null) {
    298                                 for (Entry<Key, String> e : osm.keys.entrySet()) {
    299                                         Collection<String> value = props.get(e.getKey().name);
    300                                         if (value == null) {
    301                                                 value = new TreeSet<String>();
    302                                                 props.put(e.getKey().name, value);
    303                                         }
    304                                         value.add(e.getValue());
    305                                        
    306                                         Integer count = valueCounts.get(e.getValue());
    307                                         if (count == null)
    308                                                 count = 0;
    309                                         valueCounts.put(e.getValue(), count+1);
    310                                 }
    311                         }
    312                 }
    313                 int selCount = newSelection.size();
    314                 for (Entry<String, Collection<String>> e : props.entrySet()) {
    315                         JComboBox value = new JComboBox(e.getValue().toArray());
    316                         value.setEditable(true);
    317                         if (e.getValue().size() > 1 || valueCounts.get(e.getValue().iterator().next()) != selCount)
    318                                 value.getEditor().setItem("<different>");
    319                         data.addRow(new Object[]{e.getKey(), value});
    320                 }
     35                panel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
     36                setContentPane(panel);
     37                pack();
     38                setResizable(false);
    32139        }
    32240}
  • /src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java

    r30 r20  
    33import java.awt.BorderLayout;
    44import java.awt.Component;
    5 import java.awt.Dimension;
    65import java.awt.event.ActionEvent;
    76import java.awt.event.ActionListener;
     
    1716import javax.swing.ListSelectionModel;
    1817
    19 import org.openstreetmap.josm.Main;
    2018import org.openstreetmap.josm.data.SelectionChangedListener;
     19import org.openstreetmap.josm.data.osm.DataSet;
    2120import org.openstreetmap.josm.data.osm.OsmPrimitive;
    2221import org.openstreetmap.josm.data.osm.visitor.SelectionComponentVisitor;
    2322import org.openstreetmap.josm.gui.ImageProvider;
     23import org.openstreetmap.josm.gui.Main;
    2424import org.openstreetmap.josm.gui.MapFrame;
     25import org.openstreetmap.josm.gui.MapView;
     26import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
     27import org.openstreetmap.josm.gui.layer.Layer;
    2528
    2629/**
     
    3134 * @author imi
    3235 */
    33 public class SelectionListDialog extends ToggleDialog implements SelectionChangedListener {
     36public class SelectionListDialog extends ToggleDialog implements SelectionChangedListener, LayerChangeListener {
    3437
    3538        /**
     
    4144         */
    4245        private JList displaylist = new JList(list);
     46        /**
     47         * The dataset, all selections are part of.
     48         */
     49        private final MapView mapView;
    4350       
    4451        /**
     
    4754         */
    4855        public SelectionListDialog(MapFrame mapFrame) {
    49                 super("Current Selection", "Selection List", "selectionlist", KeyEvent.VK_E, "Open a selection list window.");
    50                 setPreferredSize(new Dimension(320,150));
     56                super(mapFrame, "Current Selection", "Selection List", "selectionlist", KeyEvent.VK_E, "Open a selection list window.");
     57                this.mapView = mapFrame.mapView;
     58                setLayout(new BorderLayout());
     59                setSize(300,400);
    5160                displaylist.setCellRenderer(new DefaultListCellRenderer(){
    5261                        private SelectionComponentVisitor visitor = new SelectionComponentVisitor();
     
    6473                displaylist.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
    6574
    66                 add(new JScrollPane(displaylist), BorderLayout.CENTER);
     75                getContentPane().add(new JScrollPane(displaylist), BorderLayout.CENTER);
    6776
    6877                JButton button = new JButton("Select", ImageProvider.get("mapmode", "selection"));
     
    7382                        }
    7483                });
    75                 add(button, BorderLayout.SOUTH);
     84                getContentPane().add(button, BorderLayout.SOUTH);
    7685
    77                 selectionChanged(Main.main.ds.getSelected());
     86                selectionChanged(mapView.getActiveDataSet().getSelected());
    7887        }
    7988
     
    8190        public void setVisible(boolean b) {
    8291                if (b) {
    83                         Main.main.ds.addSelectionChangedListener(this);
    84                         selectionChanged(Main.main.ds.getSelected());
     92                        mapView.addLayerChangeListener(this);
     93                        mapView.getActiveDataSet().addSelectionChangedListener(this);
     94                        selectionChanged(mapView.getActiveDataSet().getSelected());
    8595                } else {
    86                         Main.main.ds.removeSelectionChangedListener(this);
     96                        mapView.removeLayerChangeListener(this);
     97                        mapView.getActiveDataSet().removeSelectionChangedListener(this);
    8798                }
    8899                super.setVisible(b);
     
    107118         */
    108119        public void updateMap() {
    109                 Main.main.ds.clearSelection();
     120                DataSet ds = mapView.getActiveDataSet();
     121                ds.clearSelection();
    110122                for (int i = 0; i < list.getSize(); ++i)
    111123                        if (displaylist.isSelectedIndex(i))
    112                                 ((OsmPrimitive)list.get(i)).setSelected(true);
     124                                ((OsmPrimitive)list.get(i)).setSelected(true, ds);
    113125                Main.main.getMapFrame().repaint();
    114126        }
     127
     128        public void activeLayerChange(Layer oldLayer, Layer newLayer) {
     129                DataSet ds = oldLayer.getDataSet();
     130                if (ds != null)
     131                        ds.removeSelectionChangedListener(this);
     132                ds = newLayer.getDataSet();
     133                if (ds != null)
     134                        ds.addSelectionChangedListener(this);
     135        }
     136
     137        /**
     138         * Does nothing. Only to satisfy LayerChangeListener
     139         */
     140        public void layerAdded(Layer newLayer) {}
     141        /**
     142         * Does nothing. Only to satisfy LayerChangeListener
     143         */
     144        public void layerRemoved(Layer oldLayer) {}
    115145}
  • /src/org/openstreetmap/josm/gui/dialogs/ToggleDialog.java

    r30 r20  
    11package org.openstreetmap.josm.gui.dialogs;
    22
    3 import java.awt.BorderLayout;
    43import java.awt.event.ActionEvent;
     4import java.beans.PropertyChangeEvent;
     5import java.beans.PropertyChangeListener;
    56import java.util.HashMap;
    67import java.util.Map;
     
    89import javax.swing.AbstractButton;
    910import javax.swing.Action;
    10 import javax.swing.BorderFactory;
    11 import javax.swing.JLabel;
    12 import javax.swing.JPanel;
     11import javax.swing.JComponent;
     12import javax.swing.JDialog;
     13import javax.swing.KeyStroke;
    1314
    1415import org.openstreetmap.josm.gui.ImageProvider;
     16import org.openstreetmap.josm.gui.Main;
     17import org.openstreetmap.josm.gui.MapFrame;
    1518
    1619/**
     
    2023 * @author imi
    2124 */
    22 public class ToggleDialog extends JPanel implements Action {
     25public class ToggleDialog extends JDialog implements Action {
    2326
    2427        /**
     
    2629         * @param title The title of the dialog.
    2730         */
    28         public ToggleDialog(String title, String name, String iconName, int mnemonic, String tooltip) {
     31        public ToggleDialog(MapFrame mapFrame, String title, String name, String iconName, int mnemonic, String tooltip) {
     32                super(Main.main, title, false);
    2933                putValue(SMALL_ICON, ImageProvider.get("dialogs", iconName));
    3034                putValue(NAME, name);
    3135                putValue(MNEMONIC_KEY, mnemonic);
    32                 putValue(SHORT_DESCRIPTION, tooltip);
    33                
    34                 setLayout(new BorderLayout());
    35                 add(new JLabel(title), BorderLayout.NORTH);
    36                 setVisible(false);
    37                 setBorder(BorderFactory.createEtchedBorder());
     36                KeyStroke ks = KeyStroke.getKeyStroke(mnemonic,0);
     37                putValue(ACCELERATOR_KEY, ks);
     38                mapFrame.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ks, this);
     39                mapFrame.getActionMap().put(this, this);
     40                putValue(LONG_DESCRIPTION, tooltip);
     41                mapFrame.addPropertyChangeListener("visible", new PropertyChangeListener(){
     42                        public void propertyChange(PropertyChangeEvent evt) {
     43                                if (evt.getNewValue() == Boolean.FALSE)
     44                                        setVisible(false);
     45                        }
     46                });
    3847        }
    3948
  • /src/org/openstreetmap/josm/gui/layer/Layer.java

    r30 r20  
    55import javax.swing.Icon;
    66
    7 import org.openstreetmap.josm.data.Bounds;
    8 import org.openstreetmap.josm.data.projection.Projection;
     7import org.openstreetmap.josm.data.osm.DataSet;
    98import org.openstreetmap.josm.gui.MapView;
    109
     
    2423 * @author imi
    2524 */
    26 abstract public class Layer {
     25public interface Layer {
    2726
    2827        /**
    29          * The visibility state of the layer.
     28         * Draw the layer on the given Graphics. The state of the graphics object
     29         * can be changed (drawing color..)
     30         *
     31         * @param g The graphics to draw the layer on.
     32         * @param mv The MapView with information about the screen layout.
    3033         */
    31         public boolean visible = true;
    32         /**
    33          * The name of this layer.
    34          */
    35         public final String name;
     34        void paint(Graphics g, MapView mv);
    3635
    37         /**
    38          * Create the layer and fill in the necessary components.
    39          */
    40         public Layer(String name) {
    41                 this.name = name;
    42         }
    43 
    44         /**
    45          * Paint the dataset using the engine set.
    46          * @param mv The object that can translate GeoPoints to screen coordinates.
    47          */
    48         abstract public void paint(Graphics g, MapView mv);
    4936        /**
    5037         * Return a representative small image for this layer. The image must not
    5138         * be larger than 64 pixel in any dimension.
    5239         */
    53         abstract public Icon getIcon();
     40        Icon getIcon();
    5441
    5542        /**
    56          * @return A small tooltip hint about some statistics for this layer.
     43         * Provide a human readable name (may be in html format).
    5744         */
    58         abstract public String getToolTipText();
     45        String getName();
     46       
     47        /**
     48         * If the layer has a dataset it can provide, return it here.
     49         * @return The dataset for this layer or <code>null</code> if no dataset
     50         *              is available.
     51         */
     52        DataSet getDataSet();
     53       
     54        /**
     55         * @return <code>true</code>, if the map data can be edited.
     56         */
     57        boolean isEditable();
    5958
    6059        /**
    61          * Merges the given layer into this layer. Throws if the layer types are
    62          * incompatible.
    63          * @param from The layer that get merged into this one. After the merge,
    64          *              the other layer is not usable anymore and passing to one others
    65          *              mergeFrom should be one of the last things to do with a layer.
     60         * @return <code>true</code>, if the layer is visible
    6661         */
    67         abstract public void mergeFrom(Layer from);
     62        boolean isVisible();
    6863       
    6964        /**
    70          * @param other The other layer that is tested to be mergable with this.
    71          * @return Whether the other layer can be merged into this layer.
     65         * Set the visibility state of the layer.
    7266         */
    73         abstract public boolean isMergable(Layer other);
    74        
    75         /**
    76          * @return The bounding rectangle this layer occupies on screen when looking
    77          *              at lat/lon values or <code>null</code>, if infinite area or unknown
    78          *              area is occupied.
    79          */
    80         abstract public Bounds getBoundsLatLon();
    81        
    82         /**
    83          * @return The bounding rectangle this layer occupies on screen when looking
    84          *              at x/y values or <code>null</code>, if infinite area or unknown
    85          *              area is occupied.
    86          */
    87         abstract public Bounds getBoundsXY();
    88 
    89         /**
    90          * Initialize the internal dataset with the given projection.
    91          */
    92         abstract public void init(Projection projection);
     67        void setVisible(boolean visible);
    9368}
  • /src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java

    r30 r20  
    11package org.openstreetmap.josm.gui.layer;
    2 
    3 import java.awt.Graphics;
    4 import java.io.FileWriter;
    5 import java.io.StringWriter;
    6 import java.util.LinkedList;
    72
    83import javax.swing.Icon;
    94
    10 import org.openstreetmap.josm.Main;
    11 import org.openstreetmap.josm.command.Command;
    12 import org.openstreetmap.josm.data.Bounds;
    135import org.openstreetmap.josm.data.osm.DataSet;
    14 import org.openstreetmap.josm.data.osm.LineSegment;
    15 import org.openstreetmap.josm.data.osm.Node;
    16 import org.openstreetmap.josm.data.osm.Track;
    17 import org.openstreetmap.josm.data.osm.visitor.BoundingVisitor;
    18 import org.openstreetmap.josm.data.osm.visitor.CsvVisitor;
    19 import org.openstreetmap.josm.data.osm.visitor.SimplePaintVisitor;
    20 import org.openstreetmap.josm.data.projection.Projection;
    216import org.openstreetmap.josm.gui.ImageProvider;
    22 import org.openstreetmap.josm.gui.MapView;
     7import org.openstreetmap.josm.gui.engine.SimpleEngine;
    238
    249/**
    25  * A layer holding data from a specific dataset.
     10 * A layer holding data imported from the osm server.
     11 *
    2612 * The data can be fully edited.
    2713 *
    2814 * @author imi
    2915 */
    30 public class OsmDataLayer extends Layer {
     16public class OsmDataLayer extends DataLayer {
    3117
    3218        private static Icon icon;
    33 
    34         /**
    35          * The data behind this layer.
    36          */
    37         public final DataSet data;
    38 
    39         /**
    40          * All commands that were made on the dataset.
    41          */
    42         private LinkedList<Command> commands = new LinkedList<Command>();
    43         private LinkedList<String> debugDsBefore = new LinkedList<String>();
    44 
     19       
    4520        /**
    4621         * Construct a OsmDataLayer.
    4722         */
    48         public OsmDataLayer(DataSet data, String name) {
    49                 super(name);
    50                 this.data = data;
     23        protected OsmDataLayer(DataSet dataSet, String name) {
     24                super(dataSet, new SimpleEngine(), name);
    5125        }
    5226
     
    5529         *              updated by a background thread to not disturb the running programm.
    5630         */
    57         @Override
    5831        public Icon getIcon() {
    5932                if (icon == null)
     
    6235        }
    6336
    64         /**
    65          * Draw all primitives in this layer but do not draw modified ones (they
    66          * are drawn by the edit layer).
    67          * Draw nodes last to overlap the line segments they belong to.
    68          */
    69         @Override
    70         public void paint(Graphics g, MapView mv) {
    71                 SimplePaintVisitor visitor = new SimplePaintVisitor(g, mv, null);
    72 
    73                 for (Track t : data.tracks)
    74                         visitor.visit(t);
    75                 for (LineSegment ls : data.lineSegments)
    76                         visitor.visit(ls);
    77                 for (Node n : data.nodes)
    78                         visitor.visit(n);
    79         }
    80 
    81         @Override
    82         public String getToolTipText() {
    83                 return data.nodes.size()+" nodes, "+data.tracks.size()+" streets.";
    84         }
    85 
    86         @Override
    87         public void mergeFrom(Layer from) {
    88                 data.mergeFrom(((OsmDataLayer)from).data);
    89         }
    90 
    91         @Override
    92         public boolean isMergable(Layer other) {
    93                 return other instanceof OsmDataLayer;
    94         }
    95 
    96         @Override
    97         public Bounds getBoundsLatLon() {
    98                 BoundingVisitor b = new BoundingVisitor(BoundingVisitor.Type.LATLON);
    99                 for (Node n : data.nodes)
    100                         b.visit(n);
    101                 return b.bounds;
    102         }
    103 
    104         @Override
    105         public Bounds getBoundsXY() {
    106                 BoundingVisitor b = new BoundingVisitor(BoundingVisitor.Type.XY);
    107                 for (Node n : data.nodes)
    108                         b.visit(n);
    109                 return b.bounds;
    110         }
    111 
    112         @Override
    113         public void init(Projection projection) {
    114                 for (Node n : data.nodes)
    115                         projection.latlon2xy(n.coor);
    116         }
    117 
    118         /**
    119          * Execute the command and add it to the intern command queue. Also mark all
    120          * primitives in the command as modified.
    121          */
    122         public void add(Command c) {
    123                 StringWriter sw = new StringWriter();
    124                 CsvVisitor v = new CsvVisitor(sw);
    125                 for (Node n : Main.main.ds.nodes) {
    126                         v.visit(n);
    127                         sw.append('\n');
    128                 }
    129                 for (LineSegment ls : Main.main.ds.lineSegments) {
    130                         v.visit(ls);
    131                         sw.append('\n');
    132                 }
    133                 for (Track t : Main.main.ds.tracks) {
    134                         v.visit(t);
    135                         sw.append('\n');
    136                 }
    137                 debugDsBefore.add(sw.getBuffer().toString());
    138                
    139                 c.executeCommand();
    140                 commands.add(c);
    141         }
    142 
    143         /**
    144          * Undoes the last added command.
    145          */
    146         public void undo() {
    147                 if (commands.isEmpty())
    148                         return;
    149                 Command c = commands.removeLast();
    150                 c.undoCommand();
    151                
    152                 //DEBUG
    153                 StringWriter sw = new StringWriter();
    154                 CsvVisitor v = new CsvVisitor(sw);
    155                 for (Node n : Main.main.ds.nodes) {
    156                         v.visit(n);
    157                         sw.append('\n');
    158                 }
    159                 for (LineSegment ls : Main.main.ds.lineSegments) {
    160                         v.visit(ls);
    161                         sw.append('\n');
    162                 }
    163                 for (Track t : Main.main.ds.tracks) {
    164                         v.visit(t);
    165                         sw.append('\n');
    166                 }
    167                 String s = Main.main.getMapFrame().mapView.editLayer().debugDsBefore.removeLast();
    168                 if (!s.equals(sw.getBuffer().toString())) {
    169                         try {
    170                                 FileWriter fw = new FileWriter("/home/imi/richtig");
    171                                 fw.append(sw.getBuffer().toString());
    172                                 fw.close();
    173                                 fw = new FileWriter("/home/imi/falsch");
    174                                 fw.append(s);
    175                                 fw.close();
    176                         } catch (Exception x) {
    177                                 x.printStackTrace();
    178                         }
    179                 }
     37        public boolean isEditable() {
     38                return true;
    18039        }
    18140}
  • /src/org/openstreetmap/josm/gui/layer/RawGpsDataLayer.java

    r30 r20  
    11package org.openstreetmap.josm.gui.layer;
    2 
    3 import java.awt.Color;
    4 import java.awt.Graphics;
    5 import java.awt.Point;
    6 import java.beans.PropertyChangeEvent;
    7 import java.beans.PropertyChangeListener;
    8 import java.util.Collection;
    92
    103import javax.swing.Icon;
    114
    12 import org.openstreetmap.josm.Main;
    13 import org.openstreetmap.josm.data.Bounds;
    14 import org.openstreetmap.josm.data.GeoPoint;
    15 import org.openstreetmap.josm.data.projection.Projection;
     5import org.openstreetmap.josm.data.osm.DataSet;
    166import org.openstreetmap.josm.gui.ImageProvider;
    17 import org.openstreetmap.josm.gui.MapView;
     7import org.openstreetmap.josm.gui.engine.RawGpsEngine;
    188
    199/**
     
    2313 * @author imi
    2414 */
    25 public class RawGpsDataLayer extends Layer {
     15public class RawGpsDataLayer extends DataLayer {
    2616
    2717        private static Icon icon;
    2818
    29         /**
    30          * A list of tracks which containing a list of points.
    31          */
    32         private final Collection<Collection<GeoPoint>> data;
    33 
    34         public RawGpsDataLayer(Collection<Collection<GeoPoint>> data, String name) {
    35                 super(name);
    36                 this.data = data;
    37                 Main.pref.addPropertyChangeListener(new PropertyChangeListener(){
    38                         public void propertyChange(PropertyChangeEvent evt) {
    39                                 if (Main.main.getMapFrame() == null) {
    40                                         Main.pref.removePropertyChangeListener(this);
    41                                         return;
    42                                 }
    43                                 if (evt.getPropertyName().equals("drawRawGpsLines") ||
    44                                                 evt.getPropertyName().equals("drawRawGpsLines"))
    45                                         Main.main.getMapFrame().repaint();
    46                         }
    47                 });
     19        protected RawGpsDataLayer(DataSet dataSet, String name) {
     20                super(dataSet, new RawGpsEngine(), name);
    4821        }
    4922
     
    5124         * Return a static icon.
    5225         */
    53         @Override
    5426        public Icon getIcon() {
    5527                if (icon == null)
     
    5830        }
    5931
    60         @Override
    61         public void paint(Graphics g, MapView mv) {
    62                 g.setColor(Color.GRAY);
    63                 Point old = null;
    64                 for (Collection<GeoPoint> c : data) {
    65                         if (!Main.pref.isForceRawGpsLines())
    66                                 old = null;
    67                         for (GeoPoint p : c) {
    68                                 Point screen = mv.getScreenPoint(p);
    69                                 if (Main.pref.isDrawRawGpsLines() && old != null) {
    70                                         g.drawLine(old.x, old.y, screen.x, screen.y);
    71                                 } else {
    72                                         g.drawRect(screen.x, screen.y, 0, 0);
    73                                         old = screen;
    74                                 }
    75                         }
    76                 }
    77         }
    78 
    79         @Override
    80         public String getToolTipText() {
    81                 return data.size()+" tracks.";
    82         }
    83 
    84         @Override
    85         public void mergeFrom(Layer from) {
    86                 RawGpsDataLayer layer = (RawGpsDataLayer)from;
    87                 data.addAll(layer.data);
    88         }
    89 
    90         @Override
    91         public boolean isMergable(Layer other) {
    92                 return other instanceof RawGpsDataLayer;
    93         }
    94 
    95         @Override
    96         public Bounds getBoundsLatLon() {
    97                 GeoPoint min = null;
    98                 GeoPoint max = null;
    99                 for (Collection<GeoPoint> c : data) {
    100                         for (GeoPoint p : c) {
    101                                 if (min == null) {
    102                                         min = p.clone();
    103                                         max = p.clone();
    104                                 } else {
    105                                         min.lat = Math.min(min.lat, p.lat);
    106                                         min.lon = Math.min(min.lon, p.lon);
    107                                         max.lat = Math.max(max.lat, p.lat);
    108                                         max.lon = Math.max(max.lon, p.lon);
    109                                 }
    110                         }
    111                 }
    112                 if (min == null)
    113                         return null;
    114                 return new Bounds(min, max);
    115         }
    116 
    117         @Override
    118         public Bounds getBoundsXY() {
    119                 GeoPoint min = null;
    120                 GeoPoint max = null;
    121                 for (Collection<GeoPoint> c : data) {
    122                         for (GeoPoint p : c) {
    123                                 if (min == null) {
    124                                         min = p.clone();
    125                                         max = p.clone();
    126                                 } else {
    127                                         min.x = Math.min(min.x, p.x);
    128                                         min.y = Math.min(min.y, p.y);
    129                                         max.x = Math.max(max.x, p.x);
    130                                         max.y = Math.max(max.y, p.y);
    131                                 }
    132                         }
    133                 }
    134                 if (min == null)
    135                         return null;
    136                 return new Bounds(min, max);
    137         }
    138 
    139         @Override
    140         public void init(Projection projection) {
    141                 for (Collection<GeoPoint> c : data)
    142                         for (GeoPoint p : c)
    143                                 projection.latlon2xy(p);
     32        public boolean isEditable() {
     33                return false;
    14434        }
    14535}
  • /src/org/openstreetmap/josm/io/GpxReader.java

    r30 r20  
    99import org.jdom.Namespace;
    1010import org.jdom.input.SAXBuilder;
    11 import org.openstreetmap.josm.Main;
    1211import org.openstreetmap.josm.data.GeoPoint;
    1312import org.openstreetmap.josm.data.osm.DataSet;
     
    1716import org.openstreetmap.josm.data.osm.OsmPrimitive;
    1817import org.openstreetmap.josm.data.osm.Track;
     18import org.openstreetmap.josm.gui.Main;
    1919
    2020/**
     
    2525 * @author imi
    2626 */
    27 public class GpxReader {
     27public class GpxReader implements DataReader {
    2828
    2929        /**
    3030         * The GPX namespace used.
    3131         */
    32         public static final Namespace GPX = Namespace.getNamespace("http://www.topografix.com/GPX/1/0");
     32        private static Namespace GPX = Namespace.getNamespace("http://www.topografix.com/GPX/1/0");
    3333        /**
    3434         * The OSM namespace used (for extensions).
    3535         */
    36         private static final Namespace OSM = Namespace.getNamespace("osm", "http://www.openstreetmap.org");
     36        private static final Namespace OSM = Namespace.getNamespace("osm");
    3737
    3838        /**
     
    4040         */
    4141        public Reader source;
    42 
     42        /**
     43         * If <code>true</code>, only nodes and tracks are imported (but no key/value
     44         * pairs). That is to support background gps information as an hint for
     45         * real OSM data.
     46         */
     47        private final boolean rawGps;
     48       
    4349        /**
    4450         * Construct a parser from a specific data source.
    4551         * @param source The data source, as example a FileReader to read from a file.
    46          */
    47         public GpxReader(Reader source) {
     52         * @param rawGps Whether the gpx file describes raw gps data. Only very few
     53         *              information (only nodes and line segments) imported for raw gps to
     54         *              save memory.
     55         */
     56        public GpxReader(Reader source, boolean rawGps) {
    4857                this.source = source;
     58                this.rawGps = rawGps;
    4959        }
    5060       
     
    5262         * Read the input stream and return a DataSet from the stream.
    5363         */
    54         public DataSet parse() throws JDOMException, IOException {
     64        public DataSet parse() throws ParseException, ConnectionException {
    5565                try {
    5666                        final SAXBuilder builder = new SAXBuilder();
    5767                        Element root = builder.build(source).getRootElement();
     68                       
     69                        // HACK, since the osm server seem to not provide a namespace.
     70                        if (root.getNamespacePrefix().equals(""))
     71                                GPX = null;
     72                       
    5873                        return parseDataSet(root);
    5974                } catch (NullPointerException npe) {
    60                         throw new JDOMException("NullPointerException. Probably a tag name mismatch.", npe);
     75                        throw new ParseException("NullPointerException. Probably a tag name mismatch.", npe);
    6176                } catch (ClassCastException cce) {
    62                         throw new JDOMException("ClassCastException. Probably a tag does not contain the correct type.", cce);
     77                        throw new ParseException("ClassCastException. Probably a tag does not contain the correct type.", cce);
     78                } catch (JDOMException e) {
     79                        throw new ParseException("The data could not be parsed. Reason: "+e.getMessage(), e);
     80                } catch (IOException e) {
     81                        throw new ConnectionException("The data could not be retrieved. Reason: "+e.getMessage(), e);
    6382                }
    6483        }
     
    7594                        Float.parseFloat(e.getAttributeValue("lat")),
    7695                        Float.parseFloat(e.getAttributeValue("lon")));
     96               
     97                if (rawGps)
     98                        return data;
    7799               
    78100                for (Object o : e.getChildren()) {
     
    115137        private void parseTrack(Element e, DataSet ds) {
    116138                Track track = new Track();
    117                 boolean realLineSegment = false; // is this track just a fake?
    118 
    119139                for (Object o : e.getChildren()) {
    120140                        Element child = (Element)o;
     
    129149                                        else {
    130150                                                LineSegment lineSegment = new LineSegment(start, node);
    131                                                 parseKeyValueExtensions(lineSegment, child.getChild("extensions", GPX));
     151                                                if (!rawGps)
     152                                                        parseKeyValueExtensions(lineSegment, ((Element)w).getChild("extensions", GPX));
    132153                                                track.add(lineSegment);
    133154                                                start = null;
    134155                                        }
    135156                                }
    136                         } else if (child.getName().equals("extensions")) {
     157                        }
     158                       
     159                        if (rawGps)
     160                                continue;
     161                       
     162                        if (child.getName().equals("extensions"))
    137163                                parseKeyValueExtensions(track, child);
    138                                 if (child.getChild("segment", OSM) != null)
    139                                         realLineSegment = true;
    140                         } else if (child.getName().equals("link"))
     164                        else if (child.getName().equals("link"))
    141165                                parseKeyValueLink(track, child);
    142166                        else
    143167                                parseKeyValueTag(track, child);
    144168                }
    145                 if (realLineSegment && track.segments.size() == 1)
    146                         ds.lineSegments.add(track.segments.get(0));
    147                 else {
    148                         ds.tracks.add(track);
    149                         ds.lineSegments.addAll(track.segments);
    150                 }
     169                ds.addTrack(track);
    151170        }
    152171       
     
    164183         * @return Either the parameter node or the old node found in the dataset.
    165184         */
    166         private Node addNode(DataSet data, Node node) {
    167                 if (Main.pref.mergeNodes)
     185        private Node addNode (DataSet data, Node node) {
     186                if (Main.pref.mergeNodes || rawGps)
    168187                        for (Node n : data.nodes)
    169188                                if (node.coor.equalsLatLon(n.coor))
     
    184203        private void parseKeyValueExtensions(OsmPrimitive osm, Element e) {
    185204                if (e != null) {
     205                        if (osm.keys == null)
     206                                osm.keys = new HashMap<Key, String>();
    186207                        for (Object o : e.getChildren("property", OSM)) {
    187                                 if (osm.keys == null)
    188                                         osm.keys = new HashMap<Key, String>();
    189208                                Element child = (Element)o;
    190                                 String keyname = child.getAttributeValue("key");
    191                                 if (keyname != null) {
    192                                         Key key = Key.get(keyname);
    193                                         String value = child.getAttributeValue("value");
    194                                         if (value == null)
    195                                                 value = "";
    196                                         osm.keys.put(key, value);
    197                                 }
     209                                Key key = Key.get(child.getAttributeValue("name"));
     210                                osm.keys.put(key, child.getAttributeValue("value"));
    198211                        }
    199212                }
  • /src/org/openstreetmap/josm/io/GpxWriter.java

    r30 r20  
    1414import org.jdom.output.Format;
    1515import org.jdom.output.XMLOutputter;
    16 import org.openstreetmap.josm.Main;
     16import org.openstreetmap.josm.data.osm.DataSet;
    1717import org.openstreetmap.josm.data.osm.Key;
    1818import org.openstreetmap.josm.data.osm.LineSegment;
     
    4747         */
    4848        private Writer out;
     49        /**
     50         * The DataSet this outputter operates on.
     51         */
     52        private final DataSet ds;
    4953       
    5054        /**
     
    5357         *
    5458         * @param out The Writer to store the result data in.
    55          */
    56         public GpxWriter(Writer out) {
     59         * @param ds The dataset to store.
     60         */
     61        public GpxWriter(Writer out, DataSet ds) {
     62                this.ds = ds;
    5763                this.out = out;
    5864        }
     
    8086                Element e = new Element("gpx", GPX);
    8187                e.setAttribute("version", "1.0");
    82                 e.setAttribute("creator", "JOSM Beta2");
     88                e.setAttribute("creator", "JOSM Beta");
    8389                // for getting all unreferenced waypoints in the wpt-list
    84                 LinkedList<Node> nodes = new LinkedList<Node>(Main.main.ds.nodes);
     90                LinkedList<Node> nodes = new LinkedList<Node>(ds.nodes);
    8591
    8692                // tracks
    87                 for (Track t : Main.main.ds.tracks) {
     93                for (Track t : ds.tracks()) {
    8894                        Element tElem = new Element("trk", GPX);
    8995                        if (t.keys != null) {
     
    99105                        }
    100106                        // line segments
    101                         for (LineSegment ls : t.segments) {
    102                                 tElem.getChildren().add(parseLineSegment(ls));
    103                                 nodes.remove(ls.start);
    104                                 nodes.remove(ls.end);
     107                        for (LineSegment ls : t.segments()) {
     108                                Element lsElem = new Element("trkseg", GPX);
     109                                if (ls.keys != null)
     110                                addPropertyExtensions(lsElem, ls.keys);
     111                                lsElem.getChildren().add(parseWaypoint(ls.getStart(), "trkpt"));
     112                                lsElem.getChildren().add(parseWaypoint(ls.getEnd(), "trkpt"));
     113                                nodes.remove(ls.getStart());
     114                                nodes.remove(ls.getEnd());
     115                                tElem.getChildren().add(lsElem);
    105116                        }
    106 
    107117                        e.getChildren().add(tElem);
    108118                }
    109119               
    110                 // encode pending line segments as tracks
    111                 for (LineSegment ls : Main.main.ds.lineSegments) {
    112                         Element t = new Element("trk", GPX);
    113                         t.getChildren().add(parseLineSegment(ls));
    114                         nodes.remove(ls.start);
    115                         nodes.remove(ls.end);
    116                         Element ext = new Element("extensions", GPX);
    117                         ext.getChildren().add(new Element("segment", OSM));
    118                         t.getChildren().add(ext);
    119                         e.getChildren().add(t);
    120                 }
    121 
    122120                // waypoints (missing nodes)
    123121                for (Node n : nodes)
     
    125123
    126124                return e;
    127         }
    128 
    129 
    130         /**
    131          * Parse a line segment and store it into a JDOM-Element. Return that element.
    132          */
    133         @SuppressWarnings("unchecked")
    134         private Element parseLineSegment(LineSegment ls) {
    135                 Element lsElem = new Element("trkseg", GPX);
    136                 if (ls.keys != null)
    137                 addPropertyExtensions(lsElem, ls.keys);
    138                 lsElem.getChildren().add(parseWaypoint(ls.start, "trkpt"));
    139                 lsElem.getChildren().add(parseWaypoint(ls.end, "trkpt"));
    140                 return lsElem;
    141125        }
    142126
     
    235219                if (keys.isEmpty())
    236220                        return;
    237                 Element extensions = e.getChild("extensions", GPX);
     221                Element extensions = e.getChild("extensions");
    238222                if (extensions == null)
    239223                        e.getChildren().add(extensions = new Element("extensions", GPX));
  • /src/org/openstreetmap/josm/io/OsmReader.java

    r30 r20  
    11package org.openstreetmap.josm.io;
    22
     3import java.awt.Font;
     4import java.awt.GridBagLayout;
    35import java.io.IOException;
     6import java.io.InputStreamReader;
    47import java.io.Reader;
    5 import java.util.Collection;
    6 import java.util.HashMap;
    7 import java.util.StringTokenizer;
     8import java.net.Authenticator;
     9import java.net.HttpURLConnection;
     10import java.net.PasswordAuthentication;
     11import java.net.URL;
    812
    9 import org.jdom.Element;
    10 import org.jdom.JDOMException;
    11 import org.jdom.input.SAXBuilder;
    12 import org.openstreetmap.josm.Main;
    13 import org.openstreetmap.josm.data.GeoPoint;
     13import javax.swing.JLabel;
     14import javax.swing.JOptionPane;
     15import javax.swing.JPanel;
     16import javax.swing.JPasswordField;
     17import javax.swing.JTextField;
     18
    1419import org.openstreetmap.josm.data.osm.DataSet;
    15 import org.openstreetmap.josm.data.osm.Key;
    16 import org.openstreetmap.josm.data.osm.LineSegment;
    17 import org.openstreetmap.josm.data.osm.Node;
    18 import org.openstreetmap.josm.data.osm.OsmPrimitive;
    19 import org.openstreetmap.josm.data.osm.Track;
     20import org.openstreetmap.josm.gui.GBC;
     21import org.openstreetmap.josm.gui.Main;
    2022
    2123/**
    22  * Reads an osm xml stream and construct a DataSet out of it.
     24 * This DataReader read directly from the REST API of the osm server.
    2325 *
    2426 * @author imi
    2527 */
    26 public class OsmReader {
     28public class OsmReader implements DataReader {
    2729
    2830        /**
    29          * The data source from this reader.
     31         * The url string of the desired map data.
    3032         */
    31         public Reader source;
     33        private String urlStr;
     34        /**
     35         * Whether importing the raw trackpoints or the regular osm map information
     36         */
     37        private boolean rawGps;
     38        /**
     39         * Whether the user cancelled the password dialog
     40         */
     41        private boolean cancelled = false;
     42        /**
     43         * Set to true, when the autenticator tried the password once.
     44         */
     45        private boolean passwordtried = false;
    3246
    3347        /**
    34          * Construct a parser from a specific data source.
    35          * @param source The data source, as example a FileReader to read from a file.
     48         * Construct the reader and store the information for attaching
    3649         */
    37         public OsmReader(Reader source) {
    38                 this.source = source;
    39         }
    40         static int i;
    41         /**
    42          * Read the input stream and return a DataSet from the stream.
    43          */
    44         public DataSet parse() throws JDOMException, IOException {
    45                 try {
    46                         final SAXBuilder builder = new SAXBuilder();
    47                         Element root = builder.build(source).getRootElement();
    48                         return parseDataSet(root);
    49                 } catch (NumberFormatException nfe) {
    50                         throw new JDOMException("NumberFormatException. Probably a tag is missing.", nfe);
    51                 } catch (NullPointerException npe) {
    52                         throw new JDOMException("NullPointerException. Probably a tag name mismatch.", npe);
    53                 } catch (ClassCastException cce) {
    54                         throw new JDOMException("ClassCastException. Probably a tag does not contain the correct type.", cce);
    55                 }
     50        public OsmReader(String server, boolean rawGps,
     51                        double lat1, double lon1, double lat2, double lon2) {
     52                this.rawGps = rawGps;
     53                urlStr = server.endsWith("/") ? server : server+"/";
     54                urlStr += rawGps?"trackpoints" : "map";
     55                urlStr += "?bbox="+lon1+","+lat1+","+lon2+","+lat2;
     56                if (rawGps)
     57                        urlStr += "&page=";
     58               
     59                HttpURLConnection.setFollowRedirects(true);
     60                Authenticator.setDefault(new Authenticator(){
     61                        @Override
     62                        protected PasswordAuthentication getPasswordAuthentication() {
     63                                String username = Main.pref.osmDataUsername;
     64                                String password = Main.pref.osmDataPassword;
     65                                if (passwordtried || "".equals(username) || password == null || "".equals(password)) {
     66                                        JPanel p = new JPanel(new GridBagLayout());
     67                                        p.add(new JLabel("Username"), GBC.std().insets(0,0,10,0));
     68                                        JTextField usernameField = new JTextField("".equals(username) ? "" : username, 20);
     69                                        p.add(usernameField, GBC.eol());
     70                                        p.add(new JLabel("Password"), GBC.std().insets(0,0,10,0));
     71                                        JPasswordField passwordField = new JPasswordField(password == null ? "" : password, 20);
     72                                        p.add(passwordField, GBC.eol());
     73                                        JLabel warning = new JLabel("Warning: The password is transferred unencrypted.");
     74                                        warning.setFont(warning.getFont().deriveFont(Font.ITALIC));
     75                                        p.add(warning, GBC.eol());
     76                                        int choice = JOptionPane.showConfirmDialog(Main.main, p, "Enter Password", JOptionPane.OK_CANCEL_OPTION);
     77                                        if (choice == JOptionPane.CANCEL_OPTION) {
     78                                                cancelled = true;
     79                                                return null;
     80                                        }
     81                                        username = usernameField.getText();
     82                                        password = String.valueOf(passwordField.getPassword());
     83                                        if ("".equals(username))
     84                                                return null;
     85                                }
     86                                passwordtried = true;
     87                                return new PasswordAuthentication(username, password.toCharArray());
     88                        }
     89                });
    5690        }
    5791
    5892
    59         /**
    60          * Read one node.
    61          * @param e     The element to parse
    62          * @return              The Waypoint read from the element
    63          * @throws JDOMException In case of a parsing error.
    64          */
    65         private Node parseNode(Element e) throws JDOMException {
    66                 Node data = new Node();
    67                 data.coor = new GeoPoint(
    68                         Float.parseFloat(e.getAttributeValue("lat")),
    69                         Float.parseFloat(e.getAttributeValue("lon")));
    70                 if (Double.isNaN(data.coor.lat) ||
    71                                 data.coor.lat < -90 || data.coor.lat > 90 ||
    72                                 data.coor.lon < -180 || data.coor.lon > 180)
    73                         throw new JDOMException("Illegal lat or lon value: "+data.coor.lat+"/"+data.coor.lon);
    74                 parseCommon(data, e);
    75                 return data;
    76         }
    77 
    78         /**
    79          * Parse the common part (properties and uid) of the element.
    80          * @param data  To store the data in.
    81          * @param e             The element to extract the common information.
    82          * @throws JDOMException In case of a parsing error
    83          */
    84         private void parseCommon(OsmPrimitive data, Element e) throws JDOMException {
    85                 data.id = Long.parseLong(e.getAttributeValue("uid"));
    86                 if (data.id == 0)
    87                         throw new JDOMException("Object has illegal or no id.");
    88                
    89                 String propStr = e.getAttributeValue("tags");
    90                 if (propStr != null && !propStr.equals("")) {
    91                         data.keys = new HashMap<Key, String>();
    92                         StringTokenizer st = new StringTokenizer(propStr, ";");
    93                         while (st.hasMoreTokens()) {
    94                                 StringTokenizer t = new StringTokenizer(st.nextToken(), "=");
    95                                 if (t.countTokens() > 1)
    96                                         data.keys.put(Key.get(t.nextToken()), t.nextToken());
    97                                 else {
    98                                         String token = t.nextToken();
    99                                         if (!" ".equals(token))
    100                                                 data.keys.put(Key.get(token), "");
     93        public DataSet parse() throws ParseException, ConnectionException {
     94                Reader in;
     95                try {
     96                        if (rawGps) {
     97                                DataSet ds = new DataSet();
     98                                for (int i = 0;;++i) {
     99                                        URL url = new URL(urlStr+i);
     100                                        HttpURLConnection con = (HttpURLConnection)url.openConnection();
     101                                        con.setConnectTimeout(20000);
     102                                        if (con.getResponseCode() == 401 && cancelled)
     103                                                return null;
     104                                        in = new InputStreamReader(con.getInputStream());
     105                                        DataSet currentData = new GpxReader(in, true).parse();
     106                                        if (currentData.nodes.isEmpty())
     107                                                return ds;
     108                                        ds.mergeFrom(currentData, true);
    101109                                }
    102110                        }
     111                        URL url = new URL(urlStr);
     112                        HttpURLConnection con = (HttpURLConnection)url.openConnection();
     113                        con.setConnectTimeout(20000);
     114                        if (con.getResponseCode() == 401 && cancelled)
     115                                return null;
     116                        in = new InputStreamReader(con.getInputStream());
     117                        return new GpxReader(in, false).parse();
     118                } catch (IOException e) {
     119                        throw new ConnectionException("Failed to open server connection\n"+e.getMessage(), e);
    103120                }
    104121        }
    105 
    106         /**
    107          * Read a data set from the element.
    108          * @param e     The element to parse
    109          * @return              The DataSet read from the element
    110          * @throws JDOMException In case of a parsing error.
    111          */
    112         private DataSet parseDataSet(Element e) throws JDOMException {
    113                 DataSet data = new DataSet();
    114                 for (Object o : e.getChildren()) {
    115                         Element child = (Element)o;
    116                         if (child.getName().equals("node"))
    117                                 addNode(data, parseNode(child));
    118                         else if (child.getName().equals("segment")) {
    119                                 LineSegment ls = parseLineSegment(child, data);
    120                                 if (data.lineSegments.contains(ls))
    121                                         throw new JDOMException("Double segment definition "+ls.id);
    122                                 for (Track t : data.tracks)
    123                                         if (t.segments.contains(ls))
    124                                                 throw new JDOMException("Double segment definition "+ls.id);
    125                                 data.lineSegments.add(ls);
    126                         } else if (child.getName().equals("track")) {
    127                                 Track track = parseTrack(child, data);
    128                                 if (data.tracks.contains(track))
    129                                         throw new JDOMException("Double track definition "+track.id);
    130                                 data.tracks.add(track);
    131                         }
    132                 }
    133 
    134                 return data;
    135         }
    136 
    137         /**
    138          * Parse and return an line segment. The node information of the "from" and
    139          * "to" attributes must already be in the dataset.
    140          * @param e             The line segment element to parse.
    141          * @param data  The dataset to obtain the node information from.
    142          * @return The parsed line segment.
    143          * @throws JDOMException In case of parsing errors.
    144          */
    145         private LineSegment parseLineSegment(Element e, DataSet data) throws JDOMException {
    146                 long startId = Long.parseLong(e.getAttributeValue("from"));
    147                 long endId = Long.parseLong(e.getAttributeValue("to"));
    148                
    149                 Node start = null, end = null;
    150                 for (Node n : data.nodes) {
    151                         if (n.id == startId)
    152                                 start = n;
    153                         if (n.id == endId)
    154                                 end = n;
    155                 }
    156                 if (start == null || end == null)
    157                         throw new JDOMException("The 'from' or 'to' object has not been transfered before.");
    158                 LineSegment ls = new LineSegment(start, end);
    159                 parseCommon(ls, e);
    160                 return ls;
    161         }
    162 
    163         /**
    164          * Parse and read a track from the element.
    165          *
    166          * @param e             The element that contain the track.
    167          * @param data  The DataSet to get segment information from.
    168          * @return              The parsed track.
    169          * @throws JDOMException In case of a parsing error.
    170          */
    171         private Track parseTrack(Element e, DataSet data) throws JDOMException {
    172                 Track track = new Track();
    173                 parseCommon(track, e);
    174                 for (Object o : e.getChildren("segment")) {
    175                         Element child = (Element)o;
    176                         long id = Long.parseLong(child.getAttributeValue("uid"));
    177                         LineSegment ls = findLineSegment(data.lineSegments, id);
    178                         if (ls != null) {
    179                                 track.segments.add(ls);
    180                                 data.lineSegments.remove(ls);
    181                                 continue;
    182                         }
    183                         for (Track t : data.tracks) {
    184                                 ls = findLineSegment(t.segments, id);
    185                                 if (ls != null) {
    186                                         track.segments.add(ls);
    187                                         break;
    188                                 }
    189                         }
    190                 }
    191                 return track;
    192         }
    193        
    194         /**
    195          * Search for a segment in a collection by comparing the id.
    196          */
    197         private LineSegment findLineSegment(Collection<LineSegment> segments, long id) {
    198                 for (LineSegment ls : segments)
    199                         if (ls.id == id)
    200                                 return ls;
    201                 return null;
    202         }
    203        
    204         /**
    205          * Adds the node to allNodes if it is not already listed. Does respect the
    206          * preference setting "mergeNodes". Return the node in the list that correspond
    207          * to the node in the list (either the new added or the old found).
    208          *
    209          * If reading raw gps data, mergeNodes are always on (To save memory. You
    210          * can't edit raw gps nodes anyway.)
    211          *
    212          * @param data The DataSet to add the node to.
    213          * @param node The node that should be added.
    214          * @return Either the parameter node or the old node found in the dataset.
    215          */
    216         private Node addNode(DataSet data, Node node) {
    217                 if (Main.pref.mergeNodes)
    218                         for (Node n : data.nodes)
    219                                 if (node.coor.equalsLatLon(n.coor))
    220                                         return n;
    221                 data.nodes.add(node);
    222                 return node;
    223         }
    224122}
Note: See TracChangeset for help on using the changeset viewer.