Changes in / [20:30] in josm


Ignore:
Files:
28 added
12 deleted
45 edited

Legend:

Unmodified
Added
Removed
  • /.classpath

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

    r20 r30  
    1313import java.util.regex.Pattern;
    1414
    15 import javax.swing.AbstractAction;
    1615import javax.swing.JEditorPane;
    1716import javax.swing.JLabel;
     
    2423import javax.swing.event.HyperlinkListener;
    2524
     25import org.openstreetmap.josm.Main;
    2626import org.openstreetmap.josm.gui.GBC;
    2727import org.openstreetmap.josm.gui.ImageProvider;
    28 import org.openstreetmap.josm.gui.Main;
    2928
    3029/**
     
    3635 * @author imi
    3736 */
    38 public class AboutAction extends AbstractAction {
     37public class AboutAction extends JosmAction {
    3938       
    4039        public AboutAction() {
    41                 super("About", ImageProvider.get("about"));
    42                 putValue(MNEMONIC_KEY, KeyEvent.VK_A);
    43                 putValue(SHORT_DESCRIPTION, "Display the about screen.");
     40                super("About", "about", "Display the about screen.", KeyEvent.VK_A, null);
    4441        }
    4542       
  • /src/org/openstreetmap/josm/actions/AutoScaleAction.java

    r20 r30  
    44import java.awt.event.KeyEvent;
    55
    6 import javax.swing.AbstractAction;
    7 import javax.swing.JComponent;
    8 import javax.swing.KeyStroke;
    9 
    10 import org.openstreetmap.josm.gui.ImageProvider;
    116import org.openstreetmap.josm.gui.MapFrame;
    127import org.openstreetmap.josm.gui.MapView;
     
    1611 * @author imi
    1712 */
    18 public class AutoScaleAction extends AbstractAction {
     13public class AutoScaleAction extends JosmAction {
    1914        /**
    2015         * The mapView this action operates on.
     
    2318       
    2419        public AutoScaleAction(MapFrame mapFrame) {
    25                 super("Auto Scale", ImageProvider.get("autoscale"));
     20                super("Auto Scale", "autoscale", "Zoom the view to show the whole layer. Disabled if the view is moved.",
     21                                KeyEvent.VK_A, null);
    2622                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);
    3323        }
    3424
  • /src/org/openstreetmap/josm/actions/ExitAction.java

    r20 r30  
    33import java.awt.event.ActionEvent;
    44import java.awt.event.KeyEvent;
    5 
    6 import javax.swing.AbstractAction;
    7 
    8 import org.openstreetmap.josm.gui.ImageProvider;
    95
    106/**
     
    139 * @author imi
    1410 */
    15 public class ExitAction extends AbstractAction {
     11public class ExitAction extends JosmAction {
    1612
    1713        /**
     
    1915         */
    2016        public ExitAction() {
    21                 super("Exit", ImageProvider.get("exit"));
    22                 putValue(MNEMONIC_KEY, KeyEvent.VK_X);
    23                 putValue(SHORT_DESCRIPTION, "Exit the application.");
     17                super("Exit", "exit", "Exit the application.", KeyEvent.VK_X, null);
    2418        }
    2519       
  • /src/org/openstreetmap/josm/actions/OpenOsmServerAction.java

    r20 r30  
    55import java.awt.event.ActionEvent;
    66import java.awt.event.ActionListener;
     7import java.awt.event.InputEvent;
    78import java.awt.event.KeyEvent;
     9import java.io.IOException;
    810
    9 import javax.swing.AbstractAction;
    1011import javax.swing.DefaultListModel;
    1112import javax.swing.JButton;
     
    1617import javax.swing.JScrollPane;
    1718import javax.swing.JTextField;
     19import javax.swing.KeyStroke;
    1820import javax.swing.event.ListSelectionEvent;
    1921import javax.swing.event.ListSelectionListener;
    2022
     23import org.jdom.JDOMException;
     24import org.openstreetmap.josm.Main;
    2125import org.openstreetmap.josm.data.GeoPoint;
    2226import org.openstreetmap.josm.data.osm.DataSet;
    2327import org.openstreetmap.josm.gui.BookmarkList;
    2428import org.openstreetmap.josm.gui.GBC;
    25 import org.openstreetmap.josm.gui.ImageProvider;
    26 import org.openstreetmap.josm.gui.Main;
    2729import org.openstreetmap.josm.gui.MapFrame;
    2830import org.openstreetmap.josm.gui.MapView;
    2931import org.openstreetmap.josm.gui.BookmarkList.Bookmark;
    3032import org.openstreetmap.josm.gui.layer.Layer;
    31 import org.openstreetmap.josm.gui.layer.LayerFactory;
    32 import org.openstreetmap.josm.io.OsmReader;
    33 import org.openstreetmap.josm.io.DataReader.ConnectionException;
    34 import org.openstreetmap.josm.io.DataReader.ParseException;
     33import org.openstreetmap.josm.gui.layer.OsmDataLayer;
     34import org.openstreetmap.josm.gui.layer.RawGpsDataLayer;
     35import org.openstreetmap.josm.io.OsmServerReader;
    3536
    3637/**
     
    4243 * @author imi
    4344 */
    44 public class OpenOsmServerAction extends AbstractAction {
     45public class OpenOsmServerAction extends JosmAction {
    4546
    46         private JTextField[] latlon = new JTextField[]{
     47        JTextField[] latlon = new JTextField[]{
    4748                        new JTextField(9),
    4849                        new JTextField(9),
    4950                        new JTextField(9),
    5051                        new JTextField(9)};
    51         private JCheckBox rawGps = new JCheckBox("Open as raw gps data", false);
     52        JCheckBox rawGps = new JCheckBox("Open as raw gps data", false);
    5253
    5354        public OpenOsmServerAction() {
    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.");
     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));
    5757        }
    5858
     
    8282                        for (JTextField f : latlon)
    8383                                f.setCaretPosition(0);
    84                         rawGps.setSelected(!mv.getActiveLayer().isEditable());
     84                        rawGps.setSelected(mv.getActiveLayer() instanceof RawGpsDataLayer);
    8585                }
    8686
     
    144144                        return;
    145145                }
    146                 OsmReader osmReader = new OsmReader(Main.pref.osmDataServer,
    147                                 rawGps.isSelected(), b.latlon[0], b.latlon[1], b.latlon[2], b.latlon[3]);
     146                OsmServerReader osmReader = new OsmServerReader(Main.pref.osmDataServer,
     147                                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 
    155149                        String name = latlon[0].getText()+" "+latlon[1].getText()+" x "+
    156150                                        latlon[2].getText()+" "+latlon[3].getText();
    157151                       
    158                         Layer layer = LayerFactory.create(dataSet, name, rawGps.isSelected());
     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                        }
    159164
    160165                        if (Main.main.getMapFrame() == null)
     
    162167                        else
    163168                                Main.main.getMapFrame().mapView.addLayer(layer);
    164                 } catch (ParseException x) {
     169                } catch (JDOMException x) {
    165170                        x.printStackTrace();
    166171                        JOptionPane.showMessageDialog(Main.main, x.getMessage());
    167                 } catch (ConnectionException x) {
     172                } catch (IOException x) {
    168173                        x.printStackTrace();
    169174                        JOptionPane.showMessageDialog(Main.main, x.getMessage());
     
    178183         *              checkbox.
    179184         */
    180         private Bookmark readBookmark() {
     185        Bookmark readBookmark() {
    181186                try {
    182187                        Bookmark b = new Bookmark();
  • /src/org/openstreetmap/josm/actions/PreferencesAction.java

    r20 r30  
    44import java.awt.event.KeyEvent;
    55
    6 import javax.swing.AbstractAction;
    7 
    8 import org.openstreetmap.josm.gui.ImageProvider;
    96import org.openstreetmap.josm.gui.PreferenceDialog;
    107
     
    1411 * @author imi
    1512 */
    16 public class PreferencesAction extends AbstractAction {
     13public class PreferencesAction extends JosmAction {
    1714
    1815        /**
     
    2017         */
    2118        public PreferencesAction() {
    22                 super("Preferences", ImageProvider.get("preference"));
    23                 putValue(MNEMONIC_KEY, KeyEvent.VK_P);
    24                 putValue(SHORT_DESCRIPTION, "Open a preferences page for global settings.");
     19                super("Preferences", "preference", "Open a preferences page for global settings.",
     20                                KeyEvent.VK_P, null);
    2521        }
    2622
  • /src/org/openstreetmap/josm/actions/mapmode/AddLineSegmentAction.java

    r20 r30  
    44import java.awt.Graphics;
    55import java.awt.Point;
     6import java.awt.event.ActionEvent;
    67import java.awt.event.KeyEvent;
    78import java.awt.event.MouseEvent;
    89import java.awt.event.MouseListener;
    910
    10 import javax.swing.JOptionPane;
    11 
    12 import org.openstreetmap.josm.data.osm.DataSet;
     11import org.openstreetmap.josm.Main;
     12import org.openstreetmap.josm.command.AddCommand;
    1313import org.openstreetmap.josm.data.osm.LineSegment;
    1414import org.openstreetmap.josm.data.osm.Node;
    1515import org.openstreetmap.josm.data.osm.OsmPrimitive;
    16 import org.openstreetmap.josm.data.osm.Track;
    17 import org.openstreetmap.josm.gui.Main;
    1816import org.openstreetmap.josm.gui.MapFrame;
    1917
     
    2220 * starting node and dragging to the ending node.
    2321 *
    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  *
    3022 * No line segment can be created if there is already a line segment containing
    31  * both nodes in the same order.
     23 * both nodes.
    3224 *
    3325 * @author imi
     
    5446         */
    5547        public AddLineSegmentAction(MapFrame mapFrame) {
    56                 super("Add Line Segment", "addlinesegment", "Add a line segment between two nodes.", KeyEvent.VK_L, mapFrame);
     48                super("Add Line Segment", "addlinesegment", "Add a line segment between two nodes.", KeyEvent.VK_G, mapFrame);
    5749        }
    5850
     
    7062                mv.removeMouseMotionListener(this);
    7163                drawHint(false);
     64        }
     65
     66       
     67        @Override
     68        public void actionPerformed(ActionEvent e) {
     69                super.actionPerformed(e);
     70                makeLineSegment();
    7271        }
    7372
     
    108107
    109108        /**
     109         * If left button was released, try to create the line segment.
     110         */
     111        @Override
     112        public void mouseReleased(MouseEvent e) {
     113                if (e.getButton() == MouseEvent.BUTTON1) {
     114                        makeLineSegment();
     115                        first = null; // release line segment drawing
     116                }
     117        }
     118
     119        /**
    110120         * Create the line segment if first and second are different and there is
    111121         * not already a line segment.
    112122         */
    113         @Override
    114         public void mouseReleased(MouseEvent e) {
    115                 if (e.getButton() != MouseEvent.BUTTON1)
    116                         return;
    117 
     123        private void makeLineSegment() {
    118124                if (first == null || second == null) {
    119125                        first = null;
     
    126132                Node start = first;
    127133                Node end = second;
    128                 first = null;
     134                first = second;
    129135                second = null;
    130136               
    131137                if (start != end) {
    132                         DataSet ds = mv.getActiveDataSet();
    133 
    134138                        // try to find a line segment
    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                                         }
     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.
    141142
    142143                        LineSegment ls = new LineSegment(start, end);
    143                         boolean foundTrack = false;
     144                        mv.editLayer().add(new AddCommand(Main.main.ds, ls));
     145                }
    144146
    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);
    164                 }
    165                
    166147                mv.repaint();
    167148        }
     
    186167                hintDrawn = !hintDrawn;
    187168        }
    188 
    189         @Override
    190         protected boolean isEditMode() {
    191                 return true;
    192         }
    193169}
  • /src/org/openstreetmap/josm/actions/mapmode/AddNodeAction.java

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

    r20 r30  
    22
    33import java.awt.Rectangle;
     4import java.awt.event.ActionEvent;
    45import java.awt.event.KeyEvent;
    56import java.util.Collection;
     7import java.util.Iterator;
    68import java.util.LinkedList;
    79
    8 import org.openstreetmap.josm.data.osm.DataSet;
     10import org.openstreetmap.josm.Main;
     11import org.openstreetmap.josm.command.AddCommand;
    912import org.openstreetmap.josm.data.osm.LineSegment;
    1013import org.openstreetmap.josm.data.osm.OsmPrimitive;
     
    5962        }
    6063
     64       
     65        @Override
     66        public void actionPerformed(ActionEvent e) {
     67                makeTrack();
     68                super.actionPerformed(e);
     69        }
     70
    6171        /**
    6272         * If Shift is pressed, only add the selected line segments to the selection.
     
    7686                        return; // not allowed together
    7787
    78                 DataSet ds = mv.getActiveDataSet();
    79                
    8088                if (!ctrl && !shift)
    81                         ds.clearSelection(); // new selection will replace the old.
     89                        Main.main.ds.clearSelection(); // new selection will replace the old.
    8290
    8391                Collection<OsmPrimitive> selectionList = selectionManager.getObjectsInRectangle(r,alt);
    8492                for (OsmPrimitive osm : selectionList)
    85                         osm.setSelected(!ctrl, ds);
     93                        osm.setSelected(!ctrl);
    8694
    8795                mv.repaint(); // from now on, the map has to be repainted.
     
    9098                        return; // no new track yet.
    9199               
    92                 Collection<OsmPrimitive> selection = ds.getSelected();
     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();
    93108                if (selection.isEmpty())
    94109                        return;
     
    98113                for (OsmPrimitive osm : selection) {
    99114                        if (osm instanceof Track)
    100                                 lineSegments.addAll(((Track)osm).segments());
     115                                lineSegments.addAll(((Track)osm).segments);
    101116                        else if (osm instanceof LineSegment)
    102117                                lineSegments.add((LineSegment)osm);
    103118                }
     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               
    104149                Track t = new Track();
    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;
     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();
    114155        }
    115156}
  • /src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java

    r20 r30  
    11package org.openstreetmap.josm.actions.mapmode;
    22
     3import java.awt.event.ActionEvent;
    34import java.awt.event.KeyEvent;
    45import java.awt.event.MouseEvent;
    56import java.util.ArrayList;
    6 import java.util.HashMap;
     7import java.util.Collection;
     8import java.util.HashSet;
     9import java.util.Iterator;
    710import java.util.LinkedList;
    8 import java.util.Map;
    911
    1012import javax.swing.JOptionPane;
    1113
     14import org.openstreetmap.josm.Main;
     15import org.openstreetmap.josm.command.CombineAndDeleteCommand;
     16import org.openstreetmap.josm.command.DeleteCommand;
    1217import org.openstreetmap.josm.data.osm.DataSet;
    13 import org.openstreetmap.josm.data.osm.Key;
    1418import org.openstreetmap.josm.data.osm.LineSegment;
    1519import org.openstreetmap.josm.data.osm.Node;
    1620import org.openstreetmap.josm.data.osm.OsmPrimitive;
    1721import org.openstreetmap.josm.data.osm.Track;
    18 import org.openstreetmap.josm.gui.Main;
    1922import org.openstreetmap.josm.gui.MapFrame;
    2023
     
    3235 * tries to combine the referencing objects as follows:
    3336 *
    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.
     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.
    4440 *
    4541 * Combining is only possible, if both objects that should be combined have no
     
    5551 *
    5652 * If the user enters the mapmode and any object is selected, all selected
    57  * objects get deleted. Combining applies to the selected objects.
     53 * objects that can be deleted will. Combining applies to the selected objects.
    5854 *
    5955 * @author imi
     
    6662         */
    6763        public DeleteAction(MapFrame mapFrame) {
    68                 super("Delete", "delete", "Delete nodes, streets or areas.", KeyEvent.VK_DELETE, mapFrame);
     64                super("Delete", "delete", "Delete nodes, streets or areas.", KeyEvent.VK_D, mapFrame);
    6965        }
    7066
     
    8177        }
    8278
     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
    83105        /**
    84106         * If user clicked with the left button, delete the nearest object.
     
    94116                        return;
    95117
    96                 DataSet ds = mv.getActiveDataSet();
    97 
    98118                if ((e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) != 0)
    99                         deleteWithReferences(sel, ds);
     119                        deleteWithReferences(sel);
    100120                else
    101                         delete(sel, ds);
     121                        delete(sel, true);
    102122
    103123                mv.repaint();
     
    126146         * TODO If you delete x, then a,B,C and x gets deleted. A now consist of b only.
    127147         * If you delete a or b, then A, a, b and z gets deleted.
    128          *
     148         * 
    129149         * @param osm The object to delete.
    130150         */
    131         private void deleteWithReferences(OsmPrimitive osm, DataSet ds) {
    132                 // collect all tracks, areas and pending line segments that should be deleted
     151        private void deleteWithReferences(OsmPrimitive osm) {
     152                // collect all tracks, areas and line segments that should be deleted
    133153                ArrayList<Track> tracksToDelete = new ArrayList<Track>();
    134154                ArrayList<LineSegment> lineSegmentsToDelete = new ArrayList<LineSegment>();
     
    136156                if (osm instanceof Node) {
    137157                        // delete any track and line segment the node is in.
    138                         for (Track t : ds.tracks())
    139                                 for (LineSegment ls : t.segments())
    140                                         if (ls.getStart() == osm || ls.getEnd() == osm)
     158                        for (Track t : Main.main.ds.tracks)
     159                                for (LineSegment ls : t.segments)
     160                                        if (ls.start == osm || ls.end == osm)
    141161                                                tracksToDelete.add(t);
    142                         for (LineSegment ls : ds.pendingLineSegments())
    143                                 if (ls.getStart() == osm || ls.getEnd() == osm)
     162                        for (LineSegment ls : Main.main.ds.lineSegments)
     163                                if (ls.start == osm || ls.end == osm)
    144164                                        lineSegmentsToDelete.add(ls);
    145165                               
     
    147167                        LineSegment lineSegment = (LineSegment)osm;
    148168                        lineSegmentsToDelete.add(lineSegment);
    149                         for (Track t : ds.tracks())
    150                                 for (LineSegment ls : t.segments())
     169                        for (Track t : Main.main.ds.tracks)
     170                                for (LineSegment ls : t.segments)
    151171                                        if (lineSegment == ls)
    152172                                                tracksToDelete.add(t);
     
    157177                ArrayList<Node> checkUnreferencing = new ArrayList<Node>();
    158178                for (Track t : tracksToDelete) {
    159                         for (LineSegment ls : t.segments()) {
    160                                 checkUnreferencing.add(ls.getStart());
    161                                 checkUnreferencing.add(ls.getEnd());
     179                        for (LineSegment ls : t.segments) {
     180                                checkUnreferencing.add(ls.start);
     181                                checkUnreferencing.add(ls.end);
    162182                        }
    163183                }
    164184                for (LineSegment ls : 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 
     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);
    175192                // removing all unreferenced nodes
    176                 for (Node n : checkUnreferencing) {
    177                         if (!isReferenced(n, ds))
    178                                 ds.nodes.remove(n);
    179                 }
     193                for (Node n : checkUnreferencing)
     194                        if (!isReferenced(n))
     195                                deleteData.add(n);
    180196                // now, all references are killed. Delete the node (if it was a node)
    181197                if (osm instanceof Node)
    182                         ds.nodes.remove(osm);
     198                        deleteData.add(osm);
     199
     200                mv.editLayer().add(new DeleteCommand(Main.main.ds, deleteData));
    183201        }
    184202
     
    189207         *
    190208         * @param osm The object to delete.
    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                 }
     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;
    219219        }
    220220
     
    225225         * @return Whether the node is used by a track or area.
    226226         */
    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)
     227        private boolean isReferenced(Node n) {
     228                for (LineSegment ls : Main.main.ds.lineSegments)
     229                        if (ls.start == n || ls.end == n)
    234230                                return true;
    235231                // TODO areas
     
    243239         *
    244240         * @param n The node that is going to be deleted.
    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.";
     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;
     274                        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                }
    320284
    321285                // 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)
    365                         first = second;
    366                 else if (second != null && first != null)
    367                         first.putAll(second);
    368                 return first;
    369         }
    370 
    371         @Override
    372         protected boolean isEditMode() {
     286                mv.editLayer().add(new CombineAndDeleteCommand(ds, first, second));
    373287                return true;
    374288        }
  • /src/org/openstreetmap/josm/actions/mapmode/MapMode.java

    r20 r30  
    66import java.awt.event.MouseMotionListener;
    77
    8 import javax.swing.AbstractAction;
    9 import javax.swing.JComponent;
    10 import javax.swing.KeyStroke;
    11 
    12 import org.openstreetmap.josm.gui.ImageProvider;
     8import org.openstreetmap.josm.actions.JosmAction;
    139import org.openstreetmap.josm.gui.MapFrame;
    1410import org.openstreetmap.josm.gui.MapView;
    15 import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
    16 import org.openstreetmap.josm.gui.layer.Layer;
    1711
    1812/**
     
    2418 * control.
    2519 */
    26 abstract public class MapMode extends AbstractAction implements MouseListener, MouseMotionListener {
     20abstract public class MapMode extends JosmAction implements MouseListener, MouseMotionListener {
    2721
    2822        /**
     
    4236         */
    4337        public MapMode(String name, String iconName, String tooltip, int mnemonic, MapFrame mapFrame) {
    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);
     38                super(name, "mapmode/"+iconName, tooltip, mnemonic, null);
    5039                this.mapFrame = mapFrame;
    5140                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                 });
    5941        }
    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();
    6642
    6743        /**
     
    8763                mapFrame.selectMapMode(this);
    8864        }
    89        
     65
    9066        /**
    9167         * Does nothing. Only to subclass.
  • /src/org/openstreetmap/josm/actions/mapmode/MoveAction.java

    r20 r30  
    66import java.awt.event.MouseEvent;
    77import java.util.Collection;
    8 import java.util.HashSet;
    98
    10 import org.openstreetmap.josm.data.osm.DataSet;
    11 import org.openstreetmap.josm.data.osm.Node;
     9import org.openstreetmap.josm.Main;
     10import org.openstreetmap.josm.command.MoveCommand;
     11import org.openstreetmap.josm.data.GeoPoint;
    1212import org.openstreetmap.josm.data.osm.OsmPrimitive;
    1313import org.openstreetmap.josm.gui.MapFrame;
     
    7575                }
    7676
    77                 int dx = e.getX() - mousePos.x;
    78                 int dy = e.getY() - mousePos.y;
     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;
    7981                if (dx == 0 && dy == 0)
    8082                        return;
    8183
    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                 }
     84                Collection<OsmPrimitive> selection = Main.main.ds.getSelected();
     85                mv.editLayer().add(new MoveCommand(selection, dx, dy));
     86               
    9487                mv.repaint();
    95                
    9688                mousePos = e.getPoint();
    9789        }
     
    111103                        return;
    112104
    113                 DataSet ds = mv.getActiveDataSet();
    114 
    115                 if (ds.getSelected().size() == 0) {
     105                if (Main.main.ds.getSelected().size() == 0) {
    116106                        OsmPrimitive osm = mv.getNearest(e.getPoint(), (e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) != 0);
    117107                        if (osm != null)
    118                                 osm.setSelected(true, ds);
     108                                osm.setSelected(true);
    119109                        singleOsmPrimitive = osm;
    120110                        mv.repaint();
     
    134124                mv.setCursor(oldCursor);
    135125                if (singleOsmPrimitive != null) {
    136                         singleOsmPrimitive.setSelected(false, mv.getActiveDataSet());
     126                        singleOsmPrimitive.setSelected(false);
    137127                        mv.repaint();
    138128                }
    139129        }
    140 
    141         @Override
    142         protected boolean isEditMode() {
    143                 return true;
    144         }
    145130}
  • /src/org/openstreetmap/josm/actions/mapmode/SelectionAction.java

    r20 r30  
    55import java.util.Collection;
    66
    7 import org.openstreetmap.josm.data.osm.DataSet;
     7import org.openstreetmap.josm.Main;
    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 
    9189                if (!ctrl && !shift)
    92                         ds.clearSelection(); // new selection will replace the old.
     90                        Main.main.ds.clearSelection(); // new selection will replace the old.
    9391
    9492                Collection<OsmPrimitive> selectionList = selectionManager.getObjectsInRectangle(r,alt);
    9593                for (OsmPrimitive osm : selectionList)
    96                         osm.setSelected(!ctrl, ds);
     94                        osm.setSelected(!ctrl);
    9795                mv.repaint();
    9896        }
    99 
    100         @Override
    101         protected boolean isEditMode() {
    102                 return false;
    103         }
    10497}
  • /src/org/openstreetmap/josm/actions/mapmode/ZoomAction.java

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

    r20 r30  
    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        }
    4775}
  • /src/org/openstreetmap/josm/data/Preferences.java

    r20 r30  
    134134                        mergeNodes = root.getChild("mergeNodes") != null;
    135135                        drawRawGpsLines = root.getChild("drawRawGpsLines") != null;
     136                        forceRawGpsLines = root.getChild("forceRawGpsLines") != null;
    136137                } catch (Exception e) {
    137138                        if (e instanceof PreferencesException)
     
    156157                if (drawRawGpsLines)
    157158                        children.add(new Element("drawRawGpsLines"));
     159                if (forceRawGpsLines)
     160                        children.add(new Element("forceRawGpsLines"));
    158161                Element osmServer = new Element("osm-server");
    159162                osmServer.getChildren().add(new Element("url").setText(osmDataServer));
     
    177180        }
    178181
    179        
    180182        // projection change listener stuff
    181183       
     
    184186         */
    185187        private Collection<PropertyChangeListener> listener = new LinkedList<PropertyChangeListener>();
     188
    186189        /**
    187190         * Add a listener of projection changes to the list of listeners.
  • /src/org/openstreetmap/josm/data/SelectionTracker.java

    r20 r30  
    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 private SelectionEventState state = SelectionEventState.WAITING;
     66        transient SelectionEventState state = SelectionEventState.WAITING;
    6767
    6868        /**
    6969         * A list of listeners to selection changed events.
    7070         */
    71         transient private Collection<SelectionChangedListener> listeners = new LinkedList<SelectionChangedListener>();
     71        transient Collection<SelectionChangedListener> listeners = new LinkedList<SelectionChangedListener>();
    7272
    7373       
  • /src/org/openstreetmap/josm/data/osm/DataSet.java

    r20 r30  
    22
    33import java.util.Collection;
    4 import java.util.Collections;
    54import java.util.HashMap;
    65import java.util.HashSet;
    7 import java.util.Iterator;
    86import java.util.LinkedList;
    97import java.util.Map;
    10 import java.util.Set;
    118
    129import org.openstreetmap.josm.data.Bounds;
     
    1411
    1512/**
    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.
     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.
    1916 *
    20  * Note, that DataSet is not an osm-primitive, so it has no key association but a few
    21  * members to store some information.
     17 * Note, that DataSet is not an osm-primitive and so has no key association
     18 * but a few members to store some information.
    2219 *
    2320 * @author imi
    2421 */
    25 public class DataSet extends SelectionTracker implements Cloneable {
     22public class DataSet extends SelectionTracker {
    2623
    2724        /**
     
    3330
    3431        /**
    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>();
     32         * All line segments goes here, even when they are in a track.
     33         */
     34        public Collection<LineSegment> lineSegments = new LinkedList<LineSegment>();
    3935
    4036        /**
     
    4541         * track list.
    4642         */
    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         }
     43        public Collection<Track> tracks = new LinkedList<Track>();
    10344
    10445        /**
     
    170111        public void clearSelection() {
    171112                clearSelection(nodes);
     113                clearSelection(lineSegments);
    172114                clearSelection(tracks);
    173                 for (Track t : tracks)
    174                         clearSelection(t.segments());
    175115        }
    176116
     
    182122        public Collection<OsmPrimitive> getSelected() {
    183123                Collection<OsmPrimitive> sel = getSelected(nodes);
    184                 sel.addAll(getSelected(pendingLineSegments));
     124                sel.addAll(getSelected(lineSegments));
    185125                sel.addAll(getSelected(tracks));
    186                 for (Track t : tracks)
    187                         sel.addAll(getSelected(t.segments()));
    188126                return sel;
    189127        }
     
    193131         * The objects imported are not cloned, so from now on, these data belong
    194132         * to both datasets. So use mergeFrom only if you are about to abandon the
    195          * other dataset or this dataset.
    196          *
     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         *
    197142         * @param ds    The DataSet to merge into this one.
    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                                         }
     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;
    216200                                }
    217201                        }
    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());
     202                        if (!found)
     203                                trackToAdd.add(otherTrack);
     204                }
     205                tracks.addAll(trackToAdd);
    245206        }
    246207
     
    253214                        return;
    254215                for (OsmPrimitive osm : list) {
    255                         osm.setSelected(false, this);
     216                        osm.setSelected(false);
    256217                        if (osm.keys != null)
    257218                                clearSelection(osm.keys.keySet());
     
    275236                return sel;
    276237        }
    277 
    278 
    279         @Override
    280         public DataSet clone() {
    281                 try {return (DataSet)super.clone();} catch (CloneNotSupportedException e) {}
    282                 return null;
    283         }
    284238}
  • /src/org/openstreetmap/josm/data/osm/Key.java

    r20 r30  
    11package org.openstreetmap.josm.data.osm;
    22
    3 import java.util.Collection;
    43import java.util.HashMap;
    5 import java.util.LinkedList;
    64import java.util.Map;
    75
     
    2422         * All keys are stored here.
    2523         */
    26         private static Map<String, Key> allKeys = new HashMap<String, Key>();
     24        public static final Map<String, Key> allKeys = new HashMap<String, Key>();
    2725       
    2826        /**
     
    4947        }
    5048       
    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 
    5949        @Override
    6050        public void visit(Visitor visitor) {
    6151                visitor.visit(this);
    6252        }
     53
     54        @Override
     55        public String toString() {
     56                return name;
     57        }
    6358}
  • /src/org/openstreetmap/josm/data/osm/LineSegment.java

    r20 r30  
    11package org.openstreetmap.josm.data.osm;
    2 
    3 import java.util.Collection;
    4 import java.util.Collections;
    5 import java.util.LinkedList;
    62
    73import org.openstreetmap.josm.data.osm.visitor.Visitor;
     
    1814         * The starting node of the line segment
    1915         */
    20         Node start;
     16        public Node start;
    2117       
    2218        /**
    2319         * The ending node of the line segment
    2420         */
    25         Node end;
    26 
    27         /**
    28          * The tracks, this line segment is part of.
    29          */
    30         transient Collection<Track> parent = new LinkedList<Track>();
     21        public Node end;
    3122
    3223        /**
     
    3829                this.start = start;
    3930                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;
    8531        }
    8632
  • /src/org/openstreetmap/josm/data/osm/Node.java

    r20 r30  
    11package org.openstreetmap.josm.data.osm;
    2 
    3 import java.util.Collection;
    4 import java.util.Collections;
    5 import java.util.LinkedList;
    62
    73import org.openstreetmap.josm.data.GeoPoint;
     
    2117        public GeoPoint coor;
    2218
    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 
    6219        @Override
    6320        public void visit(Visitor visitor) {
  • /src/org/openstreetmap/josm/data/osm/OsmPrimitive.java

    r20 r30  
    11package org.openstreetmap.josm.data.osm;
    22
    3 import java.util.Collection;
    43import java.util.Map;
    54
     5import org.openstreetmap.josm.Main;
    66import org.openstreetmap.josm.data.osm.visitor.Visitor;
    77
     
    1919         */
    2020        public Map<Key, String> keys;
    21        
     21
    2222        /**
    23          * If set to true, this object has been modified in the current session.
     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.
    2426         */
    25         transient public boolean modified = false;
    26        
     27        public long id = 0;
     28
    2729        /**
    2830         * If set to true, this object is currently selected.
    2931         */
    3032        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();
    3833
    3934        /**
     
    7166         * changed later, if the value actualy changed.
    7267         * @param selected Whether the primitive should be selected or not.
    73          * @param ds The dataSet, this primitive is in.
    7468         */
    75         public void setSelected(boolean selected, DataSet ds) {
     69        public void setSelected(boolean selected) {
    7670                if (selected != this.selected)
    77                         ds.fireSelectionChanged();
     71                        Main.main.ds.fireSelectionChanged();
    7872                this.selected = selected;
    7973        }
     
    8579                return selected;
    8680        }
     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        }
    87104}
  • /src/org/openstreetmap/josm/data/osm/Track.java

    r20 r30  
    22
    33import java.util.ArrayList;
    4 import java.util.Collection;
    5 import java.util.Collections;
    64import java.util.List;
    75
     
    1816         * All track segments in this track
    1917         */
    20         private final List<LineSegment> segments = new ArrayList<LineSegment>();
     18        public final List<LineSegment> segments = new ArrayList<LineSegment>();
    2119
    2220       
     
    2624        public void add(LineSegment ls) {
    2725                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();
    8926        }
    9027
     
    10138                if (segments.isEmpty())
    10239                        return null;
    103                 return segments.get(segments.size()-1).getEnd();
     40                return segments.get(segments.size()-1).end;
    10441        }
    10542       
     
    12663                if (segments.isEmpty())
    12764                        return null;
    128                 return segments.get(0).getStart();
     65                return segments.get(0).start;
    12966        }
    13067       
  • /src/org/openstreetmap/josm/data/osm/visitor/SelectionComponentVisitor.java

    r20 r30  
    1919 * @author imi
    2020 */
    21 public class SelectionComponentVisitor extends Visitor {
     21public class SelectionComponentVisitor implements Visitor {
    2222
    2323        /**
     
    3434         * A key icon and the name of the key.
    3535         */
    36         @Override
    3736        public void visit(Key k) {
    3837                name = k.name;
     
    4544         * "(x1,y1) -> (x2,y2)" is displayed with the nodes coordinates.
    4645         */
    47         @Override
    4846        public void visit(LineSegment ls) {
    4947                String name = getName(ls.keys);
    5048                if (name == null)
    51                         name = "("+ls.getStart().coor.lat+","+ls.getStart().coor.lon+") -> ("+ls.getEnd().coor.lat+","+ls.getEnd().coor.lon+")";
     49                        name = "("+ls.start.coor.lat+","+ls.start.coor.lon+") -> ("+ls.end.coor.lat+","+ls.end.coor.lon+")";
    5250                       
    5351                this.name = name;
     
    5957         * is displayed.
    6058         */
    61         @Override
    6259        public void visit(Node n) {
    6360                String name = getName(n.keys);
     
    7370         * is displayed with x beeing the number of nodes in the track.
    7471         */
    75         @Override
    7672        public void visit(Track t) {
    7773                String name = getName(t.keys);
    7874                if (name == null) {
    7975                        Set<Node> nodes = new HashSet<Node>();
    80                         for (LineSegment ls : t.segments()) {
    81                                 nodes.add(ls.getStart());
    82                                 nodes.add(ls.getEnd());
     76                        for (LineSegment ls : t.segments) {
     77                                nodes.add(ls.start);
     78                                nodes.add(ls.end);
    8379                        }
    8480                        name = "("+nodes.size()+" nodes)";
  • /src/org/openstreetmap/josm/data/osm/visitor/Visitor.java

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

    r20 r30  
    88import javax.swing.event.ChangeListener;
    99
     10import org.openstreetmap.josm.data.Bounds;
    1011import org.openstreetmap.josm.data.GeoPoint;
    11 import org.openstreetmap.josm.data.osm.DataSet;
    1212
    1313/**
     
    7171
    7272        /**
    73          * Initialize itself with the given dataSet.
     73         * Initialize itself with the given bounding rectangle (regarding lat/lon).
    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)
    9183         */
    92         public void init(DataSet dataSet) {}
     84        public void init(Bounds b) {}
    9385       
    9486        /**
  • /src/org/openstreetmap/josm/data/projection/UTM.java

    r20 r30  
    1515import javax.swing.SpinnerNumberModel;
    1616
     17import org.openstreetmap.josm.Main;
    1718import org.openstreetmap.josm.data.Bounds;
    1819import org.openstreetmap.josm.data.GeoPoint;
    19 import org.openstreetmap.josm.data.osm.DataSet;
    2020import org.openstreetmap.josm.gui.GBC;
    21 import org.openstreetmap.josm.gui.Main;
    2221
    2322/**
     
    8079        };
    8180
    82         private enum Hemisphere {north, south};
     81        private enum Hemisphere {north, south}
    8382
    8483        /**
     
    102101         * Spinner with all possible zones for the configuration panel
    103102         */
    104         private JSpinner zoneSpinner;
     103        JSpinner zoneSpinner;
    105104        /**
    106105         * Hemisphere combo for the configuration panel
    107106         */
    108         private JComboBox hemisphereCombo;
     107        JComboBox hemisphereCombo;
    109108
    110109       
     
    187186         * @author imi
    188187         */
    189         private class ZoneData {
     188        private static class ZoneData {
    190189                int zone = 0;
    191190                Hemisphere hemisphere = Hemisphere.north;
     
    193192        /**
    194193         * Try to autodetect the zone and hemisphere from the dataset.
    195          * @param dataSet The dataset to extrakt zone information from.
    196194         * @return The zone data extrakted from the dataset.
    197195         */
    198         private ZoneData autoDetect(DataSet dataSet) {
     196        ZoneData autoDetect(Bounds b) {
    199197                ZoneData zd = new ZoneData();
    200                
    201                 Bounds b = dataSet.getBoundsLatLon();
    202198                if (b == null)
    203199                        return zd;
     
    234230         */
    235231        @Override
    236         public void init(DataSet dataSet) {
     232        public void init(Bounds b) {
    237233                if (zone == 0) {
    238                         ZoneData zd = autoDetect(dataSet);
     234                        ZoneData zd = autoDetect(b);
    239235                        zone = zd.zone;
    240236                        hemisphere = zd.hemisphere;
     
    274270                        public void actionPerformed(ActionEvent e) {
    275271                                if (Main.main.getMapFrame() != null) {
    276                                         DataSet ds = Main.main.getMapFrame().mapView.getActiveDataSet();
    277                                         ZoneData zd = autoDetect(ds);
     272                                        ZoneData zd = autoDetect(Main.main.ds.getBoundsLatLon());
    278273                                        if (zd.zone == 0)
    279274                                                JOptionPane.showMessageDialog(Main.main, "Autodetection failed. Maybe the data set contain too few information.");
  • /src/org/openstreetmap/josm/gui/BookmarkList.java

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

    r20 r30  
    2525                // Tooltip
    2626                String toolTipText = "";
    27                 Object o = action.getValue(Action.LONG_DESCRIPTION);
     27                Object o = action.getValue(Action.SHORT_DESCRIPTION);
    2828                if (o != null)
    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                 }
     29                        toolTipText = o.toString();
    3930                setToolTipText(toolTipText);
    4031               
  • /src/org/openstreetmap/josm/gui/ImageProvider.java

    r20 r30  
    1313import javax.swing.ImageIcon;
    1414
     15import org.openstreetmap.josm.Main;
     16
    1517/**
    1618 * Helperclass to support the application with images.
     
    2325         * @author imi
    2426         */
    25         public enum OverlayPosition {NORTHWEST, NORTHEAST, SOUTHWEST, SOUTHEAST};
     27        public enum OverlayPosition {NORTHWEST, NORTHEAST, SOUTHWEST, SOUTHEAST}
    2628       
    2729        /**
  • /src/org/openstreetmap/josm/gui/MapFrame.java

    r20 r30  
    44import java.awt.Component;
    55import java.awt.Container;
    6 import java.awt.event.WindowAdapter;
    7 import java.awt.event.WindowEvent;
    86import java.beans.PropertyChangeEvent;
    97import java.beans.PropertyChangeListener;
    108
    119import javax.swing.AbstractButton;
     10import javax.swing.BoxLayout;
    1211import javax.swing.ButtonGroup;
    1312import javax.swing.JPanel;
     
    1918import org.openstreetmap.josm.actions.mapmode.AddNodeAction;
    2019import org.openstreetmap.josm.actions.mapmode.AddTrackAction;
    21 import org.openstreetmap.josm.actions.mapmode.CombineAction;
    2220import org.openstreetmap.josm.actions.mapmode.DeleteAction;
    2321import org.openstreetmap.josm.actions.mapmode.MapMode;
     
    5452         */
    5553        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;
    5666
    5767        /**
     
    7686                toolBarActions.add(new IconToggleButton(this, new AddLineSegmentAction(this)));
    7787                toolBarActions.add(new IconToggleButton(this, new AddTrackAction(this)));
    78                 toolBarActions.add(new IconToggleButton(this, new CombineAction(this)));
    7988                toolBarActions.add(new IconToggleButton(this, new DeleteAction(this)));
    8089
     
    99108                });
    100109
    101                 // layer list
    102                 toolBarActions.add(new IconToggleButton(this, new LayerList(this)));
     110                JPanel toggleDialogs = new JPanel();
     111                add(toggleDialogs, BorderLayout.EAST);
     112
     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);
    103120               
    104                 // properties
    105                 toolBarActions.add(new IconToggleButton(this, new PropertiesDialog(this)));
    106 
    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);
    117121
    118122                // status line below the map
  • /src/org/openstreetmap/josm/gui/MapStatus.java

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

    r20 r30  
    1717import javax.swing.event.ChangeListener;
    1818
     19import org.openstreetmap.josm.Main;
    1920import org.openstreetmap.josm.data.Bounds;
    2021import org.openstreetmap.josm.data.GeoPoint;
     
    2627import org.openstreetmap.josm.data.projection.Projection;
    2728import org.openstreetmap.josm.gui.layer.Layer;
     29import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    2830
    2931/**
    3032 * This is a component used in the MapFrame for browsing the map. It use is to
    3133 * 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        /**
    7579         * The layer from the layers list that is currently active.
    7680         */
     
    8690         */
    8791        public MapView(Layer layer) {
    88                 if (layer.getDataSet() == null)
    89                         throw new IllegalArgumentException("Initial layer must have a dataset.");
    90 
    9192                addComponentListener(new ComponentAdapter(){
    9293                        @Override
     
    102103                addLayer(layer);
    103104                Main.pref.addPropertyChangeListener(this);
    104 
    105                 // init screen
    106                 recalculateCenterScale();
    107105        }
    108106
     
    112110         */
    113111        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
    114132                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                 }
    127133
    128134                for (LayerChangeListener l : listeners)
    129135                        l.layerAdded(layer);
    130136
     137                // autoselect the new layer
    131138                setActiveLayer(layer);
    132139        }
    133        
     140
    134141        /**
    135142         * Remove the layer from the mapview. If the layer was in the list before,
     
    140147                        for (LayerChangeListener l : listeners)
    141148                                l.layerRemoved(layer);
     149                if (layer == editLayer)
     150                        editLayer = null;
    142151        }
    143152
     
    232241                OsmPrimitive minPrimitive = null;
    233242
    234                 // calculate the object based on the current active dataset.
    235                 DataSet ds = getActiveDataSet();
    236                
    237243                // nodes
    238                 for (Node n : ds.nodes) {
     244                for (Node n : Main.main.ds.nodes) {
    239245                        Point sp = getScreenPoint(n.coor);
    240246                        double dist = p.distanceSq(sp);
     
    248254               
    249255                // pending line segments
    250                 for (LineSegment ls : ds.pendingLineSegments()) {
    251                         Point A = getScreenPoint(ls.getStart().coor);
    252                         Point B = getScreenPoint(ls.getEnd().coor);
     256                for (LineSegment ls : Main.main.ds.lineSegments) {
     257                        Point A = getScreenPoint(ls.start.coor);
     258                        Point B = getScreenPoint(ls.end.coor);
    253259                        double c = A.distanceSq(B);
    254260                        double a = p.distanceSq(B);
     
    263269                // tracks & line segments
    264270                minDistanceSq = Double.MAX_VALUE;
    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);
     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);
    269275                                double c = A.distanceSq(B);
    270276                                double a = p.distanceSq(B);
     
    320326                for (int i = layers.size()-1; i >= 0; --i) {
    321327                        Layer l = layers.get(i);
    322                         if (l.isVisible())
     328                        if (l.visible)
    323329                                l.paint(g, this);
    324330                }
     
    332338                // reset all datasets.
    333339                Projection p = Main.pref.getProjection();
    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                 }
     340                for (Node n : Main.main.ds.nodes)
     341                        p.latlon2xy(n.coor);
    340342                recalculateCenterScale();
    341343        }
     
    375377
    376378       
    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 
    394379        /**
    395380         * Change to the new projection. Recalculate the dataset and zoom, if autoZoom
     
    425410                                h = 20;
    426411                       
    427                         Bounds bounds = getActiveDataSet().getBoundsXY();
    428                        
     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
    429423                        boolean oldAutoScale = autoScale;
    430424                        GeoPoint oldCenter = center;
     
    479473        /**
    480474         * 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.
    481476         */
    482477        public void setActiveLayer(Layer layer) {
     
    485480                Layer old = activeLayer;
    486481                activeLayer = layer;
     482                if (layer instanceof OsmDataLayer)
     483                        Main.main.ds = ((OsmDataLayer)layer).data;
    487484                if (old != layer) {
    488                         if (old != null && old.getDataSet() != null)
    489                                 old.getDataSet().clearSelection();
    490485                        for (LayerChangeListener l : listeners)
    491486                                l.activeLayerChange(old, layer);
     
    500495                return activeLayer;
    501496        }
     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        }
    502507}
  • /src/org/openstreetmap/josm/gui/PreferenceDialog.java

    r20 r30  
    2828import javax.swing.UIManager.LookAndFeelInfo;
    2929
     30import org.openstreetmap.josm.Main;
    3031import org.openstreetmap.josm.data.Preferences;
    3132import org.openstreetmap.josm.data.Preferences.PreferencesException;
     
    9091         * Indicate, that the application has to be restarted for the settings to take effect.
    9192         */
    92         private boolean requiresRestart = false;
     93        boolean requiresRestart = false;
    9394        /**
    9495         * ComboBox with all look and feels.
    9596         */
    96         private JComboBox lafCombo = new JComboBox(UIManager.getInstalledLookAndFeels());
     97        JComboBox lafCombo = new JComboBox(UIManager.getInstalledLookAndFeels());
    9798        /**
    9899         * Combobox with all projections available
    99100         */
    100         private JComboBox projectionCombo = new JComboBox(Preferences.allProjections.clone());
     101        JComboBox projectionCombo = new JComboBox(Preferences.allProjections.clone());
    101102        /**
    102103         * The main tab panel.
     
    107108         * Editfield for the Base url to the REST API from OSM.
    108109         */
    109         private JTextField osmDataServer = new JTextField(20);
     110        JTextField osmDataServer = new JTextField(20);
    110111        /**
    111112         * Editfield for the username to the OSM account.
    112113         */
    113         private JTextField osmDataUsername = new JTextField(20);
     114        JTextField osmDataUsername = new JTextField(20);
    114115        /**
    115116         * Passwordfield for the userpassword of the REST API.
    116117         */
    117         private JPasswordField osmDataPassword = new JPasswordField(20);
     118        JPasswordField osmDataPassword = new JPasswordField(20);
    118119        /**
    119120         * The checkbox stating whether nodes should be merged together.
    120121         */
    121         private JCheckBox drawRawGpsLines = new JCheckBox("Draw lines between raw gps points.");
     122        JCheckBox drawRawGpsLines = new JCheckBox("Draw lines between raw gps points.");
    122123        /**
    123124         * The checkbox stating whether raw gps lines should be forced.
    124125         */
    125         private JCheckBox forceRawGpsLines = new JCheckBox("Force lines if no line segments imported.");
     126        JCheckBox forceRawGpsLines = new JCheckBox("Force lines if no line segments imported.");
    126127        /**
    127128         * The checkbox stating whether nodes should be merged together.
    128129         */
    129         private JCheckBox mergeNodes = new JCheckBox("Merge nodes with equal latitude/longitude.");
     130        JCheckBox mergeNodes = new JCheckBox("Merge nodes with equal latitude/longitude.");
    130131
    131132        /**
  • /src/org/openstreetmap/josm/gui/SelectionManager.java

    r20 r30  
    1515import java.util.LinkedList;
    1616
    17 import org.openstreetmap.josm.data.osm.DataSet;
     17import org.openstreetmap.josm.Main;
    1818import org.openstreetmap.josm.data.osm.LineSegment;
    1919import org.openstreetmap.josm.data.osm.Node;
     
    272272                } else {
    273273                        // nodes
    274                         DataSet ds = mv.getActiveDataSet();
    275                         for (Node n : ds.nodes) {
     274                        for (Node n : Main.main.ds.nodes) {
    276275                                if (r.contains(mv.getScreenPoint(n.coor)))
    277276                                        selection.add(n);
     
    279278                       
    280279                        // pending line segments
    281                         for (LineSegment ls : ds.pendingLineSegments())
     280                        for (LineSegment ls : Main.main.ds.lineSegments)
    282281                                if (rectangleContainLineSegment(r, alt, ls))
    283282                                        selection.add(ls);
    284283
    285284                        // tracks
    286                         for (Track t : ds.tracks()) {
    287                                 boolean wholeTrackSelected = !t.segments().isEmpty();
    288                                 for (LineSegment ls : t.segments())
     285                        for (Track t : Main.main.ds.tracks) {
     286                                boolean wholeTrackSelected = !t.segments.isEmpty();
     287                                for (LineSegment ls : t.segments)
    289288                                        if (rectangleContainLineSegment(r, alt, ls))
    290289                                                selection.add(ls);
     
    311310        private boolean rectangleContainLineSegment(Rectangle r, boolean alt, LineSegment ls) {
    312311                if (alt) {
    313                         Point p1 = mv.getScreenPoint(ls.getStart().coor);
    314                         Point p2 = mv.getScreenPoint(ls.getEnd().coor);
     312                        Point p1 = mv.getScreenPoint(ls.start.coor);
     313                        Point p2 = mv.getScreenPoint(ls.end.coor);
    315314                        if (r.intersectsLine(p1.x, p1.y, p2.x, p2.y))
    316315                                return true;
    317316                } else {
    318                         if (r.contains(mv.getScreenPoint(ls.getStart().coor))
    319                                         && r.contains(mv.getScreenPoint(ls.getEnd().coor)))
     317                        if (r.contains(mv.getScreenPoint(ls.start.coor))
     318                                        && r.contains(mv.getScreenPoint(ls.end.coor)))
    320319                                return true;
    321320                }
  • /src/org/openstreetmap/josm/gui/dialogs/LayerList.java

    r20 r30  
    2323import javax.swing.event.ListSelectionListener;
    2424
     25import org.openstreetmap.josm.Main;
    2526import org.openstreetmap.josm.data.osm.DataSet;
    2627import org.openstreetmap.josm.gui.ImageProvider;
    27 import 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         private DefaultListModel model = new DefaultListModel();
     44        DefaultListModel model = new DefaultListModel();
    4545        /**
    4646         * The list component holding all layers.
    4747         */
    48         private JList layers = new JList(model);
     48        JList layers = new JList(model);
    4949        /**
    5050         * The invisible icon blended over invisible layers.
    5151         */
    52         private static final Icon invisible = ImageProvider.get("layer", "invisible");
     52        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(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));
     76                super("Layers", "List of all layers", "layerlist", KeyEvent.VK_L, "Open a list of all loaded layers.");
     77                setPreferredSize(new Dimension(320,100));
    7978                add(new JScrollPane(layers), BorderLayout.CENTER);
    8079                layers.setBackground(UIManager.getColor("Button.background"));
     
    8483                                Layer layer = (Layer)value;
    8584                                JLabel label = (JLabel)super.getListCellRendererComponent(list,
    86                                                 layer.getName(), index, isSelected, cellHasFocus);
     85                                                layer.name, index, isSelected, cellHasFocus);
    8786                                Icon icon = layer.getIcon();
    88                                 if (!layer.isVisible())
     87                                if (!layer.visible)
    8988                                        icon = ImageProvider.overlay(icon, invisible, ImageProvider.OverlayPosition.SOUTHEAST);
    9089                                label.setIcon(icon);
    91                                
    92                                 DataSet ds = layer.getDataSet();
    93                                 if (ds != null) {
    94                                         label.setToolTipText(ds.nodes.size()+" nodes, "+
    95                                                         ds.tracks().size()+" tracks");
    96                                 }
     90                                label.setToolTipText(layer.getToolTipText());
    9791                                return label;
    9892                        }
     
    10094
    10195                final MapView mapView = mapFrame.mapView;
    102                
     96
    10397                Collection<Layer> data = mapView.getAllLayers();
    10498                for (Layer l : data)
     
    115109                });
    116110                mapView.addLayerChangeListener(this);
    117                
     111
    118112                // Buttons
    119113                JPanel buttonPanel = new JPanel(new GridLayout(1, 5));
     
    148142                        public void actionPerformed(ActionEvent e) {
    149143                                Layer l = (Layer)layers.getSelectedValue();
    150                                 l.setVisible(!l.isVisible());
     144                                l.visible = !l.visible;
    151145                                mapView.repaint();
    152146                                layers.repaint();
     
    160154                                if (model.size() == 1) {
    161155                                        Main.main.setMapFrame(null, null);
     156                                        Main.main.ds = new DataSet();
    162157                                } else {
    163158                                        int sel = layers.getSelectedIndex();
     
    173168                mergeButton.setToolTipText("Merge the selected layer into the layer directly below.");
    174169                mergeButton.addActionListener(new ActionListener(){
    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                         });             
     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                });             
    185178                buttonPanel.add(mergeButton);
    186179
     
    193186         * Updates the state of the Buttons.
    194187         */
    195         private void updateButtonEnabled() {
     188        void updateButtonEnabled() {
    196189                int sel = layers.getSelectedIndex();
    197190                Layer l = (Layer)layers.getSelectedValue();
    198191                boolean enable = model.getSize() > 1;
    199192                enable = enable && sel < model.getSize()-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();
     193                enable = enable && l.isMergable((Layer)model.get(sel+1));
    203194                mergeButton.setEnabled(enable);
    204195                upButton.setEnabled(sel > 0);
  • /src/org/openstreetmap/josm/gui/dialogs/PropertiesDialog.java

    r20 r30  
    11package org.openstreetmap.josm.gui.dialogs;
    22
     3import java.awt.BorderLayout;
     4import java.awt.Component;
     5import java.awt.Dimension;
     6import java.awt.Font;
     7import java.awt.GridLayout;
     8import java.awt.event.ActionEvent;
     9import java.awt.event.ActionListener;
    310import java.awt.event.KeyEvent;
    4 
    5 import javax.swing.BorderFactory;
    6 import javax.swing.Box;
     11import java.awt.event.MouseAdapter;
     12import java.awt.event.MouseEvent;
     13import java.awt.event.WindowEvent;
     14import java.awt.event.WindowFocusListener;
     15import java.util.Collection;
     16import java.util.HashMap;
     17import java.util.Iterator;
     18import java.util.TreeMap;
     19import java.util.TreeSet;
     20import java.util.Vector;
     21import java.util.Map.Entry;
     22
     23import javax.swing.JButton;
     24import javax.swing.JComboBox;
     25import javax.swing.JDialog;
    726import javax.swing.JLabel;
    8 import javax.swing.border.Border;
    9 
    10 import org.openstreetmap.josm.gui.Main;
     27import javax.swing.JOptionPane;
     28import javax.swing.JPanel;
     29import javax.swing.JScrollPane;
     30import javax.swing.JTable;
     31import javax.swing.JTextField;
     32import javax.swing.ListSelectionModel;
     33import javax.swing.table.DefaultTableCellRenderer;
     34import javax.swing.table.DefaultTableModel;
     35
     36import org.openstreetmap.josm.Main;
     37import org.openstreetmap.josm.command.ChangeKeyValueCommand;
     38import org.openstreetmap.josm.data.SelectionChangedListener;
     39import org.openstreetmap.josm.data.osm.Key;
     40import org.openstreetmap.josm.data.osm.OsmPrimitive;
     41import org.openstreetmap.josm.gui.ImageProvider;
    1142import org.openstreetmap.josm.gui.MapFrame;
     43import org.openstreetmap.josm.gui.MapView;
    1244
    1345/**
    14  * Open a Property dialog for the current visible map. When saving to own josm-
    15  * data format, the properties are saved along.
     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.
    1659 *
    1760 * @author imi
    1861 */
    19 public class PropertiesDialog extends ToggleDialog {
    20 
     62public class PropertiesDialog extends ToggleDialog implements SelectionChangedListener {
     63
     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       
    21209        /**
    22210         * Create a new PropertiesDialog
    23211         */
    24212        public PropertiesDialog(MapFrame mapFrame) {
    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);
    27 
    28                 final Border panelBorder = BorderFactory.createEmptyBorder(5,0,0,0);
    29                 Box panel = Box.createVerticalBox();
     213                super("Properties", "Properties Dialog", "properties", KeyEvent.VK_P, "Property for selected objects.");
     214                mv = mapFrame.mapView;
     215
     216                setPreferredSize(new Dimension(320,150));
    30217               
    31                 JLabel todo = new JLabel("Nothing implemented yet.");
    32                 todo.setBorder(panelBorder);
    33                 panel.add(todo);
     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);
    34244               
    35                 panel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
    36                 setContentPane(panel);
    37                 pack();
    38                 setResizable(false);
     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                }
    39321        }
    40322}
  • /src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java

    r20 r30  
    33import java.awt.BorderLayout;
    44import java.awt.Component;
     5import java.awt.Dimension;
    56import java.awt.event.ActionEvent;
    67import java.awt.event.ActionListener;
     
    1617import javax.swing.ListSelectionModel;
    1718
     19import org.openstreetmap.josm.Main;
    1820import org.openstreetmap.josm.data.SelectionChangedListener;
    19 import org.openstreetmap.josm.data.osm.DataSet;
    2021import org.openstreetmap.josm.data.osm.OsmPrimitive;
    2122import org.openstreetmap.josm.data.osm.visitor.SelectionComponentVisitor;
    2223import org.openstreetmap.josm.gui.ImageProvider;
    23 import org.openstreetmap.josm.gui.Main;
    2424import org.openstreetmap.josm.gui.MapFrame;
    25 import org.openstreetmap.josm.gui.MapView;
    26 import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
    27 import org.openstreetmap.josm.gui.layer.Layer;
    2825
    2926/**
     
    3431 * @author imi
    3532 */
    36 public class SelectionListDialog extends ToggleDialog implements SelectionChangedListener, LayerChangeListener {
     33public class SelectionListDialog extends ToggleDialog implements SelectionChangedListener {
    3734
    3835        /**
     
    4441         */
    4542        private JList displaylist = new JList(list);
    46         /**
    47          * The dataset, all selections are part of.
    48          */
    49         private final MapView mapView;
    5043       
    5144        /**
     
    5447         */
    5548        public SelectionListDialog(MapFrame mapFrame) {
    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);
     49                super("Current Selection", "Selection List", "selectionlist", KeyEvent.VK_E, "Open a selection list window.");
     50                setPreferredSize(new Dimension(320,150));
    6051                displaylist.setCellRenderer(new DefaultListCellRenderer(){
    6152                        private SelectionComponentVisitor visitor = new SelectionComponentVisitor();
     
    7364                displaylist.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
    7465
    75                 getContentPane().add(new JScrollPane(displaylist), BorderLayout.CENTER);
     66                add(new JScrollPane(displaylist), BorderLayout.CENTER);
    7667
    7768                JButton button = new JButton("Select", ImageProvider.get("mapmode", "selection"));
     
    8273                        }
    8374                });
    84                 getContentPane().add(button, BorderLayout.SOUTH);
     75                add(button, BorderLayout.SOUTH);
    8576
    86                 selectionChanged(mapView.getActiveDataSet().getSelected());
     77                selectionChanged(Main.main.ds.getSelected());
    8778        }
    8879
     
    9081        public void setVisible(boolean b) {
    9182                if (b) {
    92                         mapView.addLayerChangeListener(this);
    93                         mapView.getActiveDataSet().addSelectionChangedListener(this);
    94                         selectionChanged(mapView.getActiveDataSet().getSelected());
     83                        Main.main.ds.addSelectionChangedListener(this);
     84                        selectionChanged(Main.main.ds.getSelected());
    9585                } else {
    96                         mapView.removeLayerChangeListener(this);
    97                         mapView.getActiveDataSet().removeSelectionChangedListener(this);
     86                        Main.main.ds.removeSelectionChangedListener(this);
    9887                }
    9988                super.setVisible(b);
     
    118107         */
    119108        public void updateMap() {
    120                 DataSet ds = mapView.getActiveDataSet();
    121                 ds.clearSelection();
     109                Main.main.ds.clearSelection();
    122110                for (int i = 0; i < list.getSize(); ++i)
    123111                        if (displaylist.isSelectedIndex(i))
    124                                 ((OsmPrimitive)list.get(i)).setSelected(true, ds);
     112                                ((OsmPrimitive)list.get(i)).setSelected(true);
    125113                Main.main.getMapFrame().repaint();
    126114        }
    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) {}
    145115}
  • /src/org/openstreetmap/josm/gui/dialogs/ToggleDialog.java

    r20 r30  
    11package org.openstreetmap.josm.gui.dialogs;
    22
     3import java.awt.BorderLayout;
    34import java.awt.event.ActionEvent;
    4 import java.beans.PropertyChangeEvent;
    5 import java.beans.PropertyChangeListener;
    65import java.util.HashMap;
    76import java.util.Map;
     
    98import javax.swing.AbstractButton;
    109import javax.swing.Action;
    11 import javax.swing.JComponent;
    12 import javax.swing.JDialog;
    13 import javax.swing.KeyStroke;
     10import javax.swing.BorderFactory;
     11import javax.swing.JLabel;
     12import javax.swing.JPanel;
    1413
    1514import org.openstreetmap.josm.gui.ImageProvider;
    16 import org.openstreetmap.josm.gui.Main;
    17 import org.openstreetmap.josm.gui.MapFrame;
    1815
    1916/**
     
    2320 * @author imi
    2421 */
    25 public class ToggleDialog extends JDialog implements Action {
     22public class ToggleDialog extends JPanel implements Action {
    2623
    2724        /**
     
    2926         * @param title The title of the dialog.
    3027         */
    31         public ToggleDialog(MapFrame mapFrame, String title, String name, String iconName, int mnemonic, String tooltip) {
    32                 super(Main.main, title, false);
     28        public ToggleDialog(String title, String name, String iconName, int mnemonic, String tooltip) {
    3329                putValue(SMALL_ICON, ImageProvider.get("dialogs", iconName));
    3430                putValue(NAME, name);
    3531                putValue(MNEMONIC_KEY, mnemonic);
    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                 });
     32                putValue(SHORT_DESCRIPTION, tooltip);
     33               
     34                setLayout(new BorderLayout());
     35                add(new JLabel(title), BorderLayout.NORTH);
     36                setVisible(false);
     37                setBorder(BorderFactory.createEtchedBorder());
    4738        }
    4839
  • /src/org/openstreetmap/josm/gui/layer/Layer.java

    r20 r30  
    55import javax.swing.Icon;
    66
    7 import org.openstreetmap.josm.data.osm.DataSet;
     7import org.openstreetmap.josm.data.Bounds;
     8import org.openstreetmap.josm.data.projection.Projection;
    89import org.openstreetmap.josm.gui.MapView;
    910
     
    2324 * @author imi
    2425 */
    25 public interface Layer {
     26abstract public class Layer {
    2627
    2728        /**
    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.
     29         * The visibility state of the layer.
    3330         */
    34         void paint(Graphics g, MapView mv);
     31        public boolean visible = true;
     32        /**
     33         * The name of this layer.
     34         */
     35        public final String name;
    3536
     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);
    3649        /**
    3750         * Return a representative small image for this layer. The image must not
    3851         * be larger than 64 pixel in any dimension.
    3952         */
    40         Icon getIcon();
     53        abstract public Icon getIcon();
    4154
    4255        /**
    43          * Provide a human readable name (may be in html format).
     56         * @return A small tooltip hint about some statistics for this layer.
    4457         */
    45         String getName();
     58        abstract public String getToolTipText();
     59
     60        /**
     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.
     66         */
     67        abstract public void mergeFrom(Layer from);
    4668       
    4769        /**
    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.
     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.
    5172         */
    52         DataSet getDataSet();
     73        abstract public boolean isMergable(Layer other);
    5374       
    5475        /**
    55          * @return <code>true</code>, if the map data can be edited.
     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.
    5679         */
    57         boolean isEditable();
     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();
    5888
    5989        /**
    60          * @return <code>true</code>, if the layer is visible
     90         * Initialize the internal dataset with the given projection.
    6191         */
    62         boolean isVisible();
    63        
    64         /**
    65          * Set the visibility state of the layer.
    66          */
    67         void setVisible(boolean visible);
     92        abstract public void init(Projection projection);
    6893}
  • /src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java

    r20 r30  
    11package org.openstreetmap.josm.gui.layer;
     2
     3import java.awt.Graphics;
     4import java.io.FileWriter;
     5import java.io.StringWriter;
     6import java.util.LinkedList;
    27
    38import javax.swing.Icon;
    49
     10import org.openstreetmap.josm.Main;
     11import org.openstreetmap.josm.command.Command;
     12import org.openstreetmap.josm.data.Bounds;
    513import org.openstreetmap.josm.data.osm.DataSet;
     14import org.openstreetmap.josm.data.osm.LineSegment;
     15import org.openstreetmap.josm.data.osm.Node;
     16import org.openstreetmap.josm.data.osm.Track;
     17import org.openstreetmap.josm.data.osm.visitor.BoundingVisitor;
     18import org.openstreetmap.josm.data.osm.visitor.CsvVisitor;
     19import org.openstreetmap.josm.data.osm.visitor.SimplePaintVisitor;
     20import org.openstreetmap.josm.data.projection.Projection;
    621import org.openstreetmap.josm.gui.ImageProvider;
    7 import org.openstreetmap.josm.gui.engine.SimpleEngine;
     22import org.openstreetmap.josm.gui.MapView;
    823
    924/**
    10  * A layer holding data imported from the osm server.
    11  *
     25 * A layer holding data from a specific dataset.
    1226 * The data can be fully edited.
    1327 *
    1428 * @author imi
    1529 */
    16 public class OsmDataLayer extends DataLayer {
     30public class OsmDataLayer extends Layer {
    1731
    1832        private static Icon icon;
    19        
     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
    2045        /**
    2146         * Construct a OsmDataLayer.
    2247         */
    23         protected OsmDataLayer(DataSet dataSet, String name) {
    24                 super(dataSet, new SimpleEngine(), name);
     48        public OsmDataLayer(DataSet data, String name) {
     49                super(name);
     50                this.data = data;
    2551        }
    2652
     
    2955         *              updated by a background thread to not disturb the running programm.
    3056         */
     57        @Override
    3158        public Icon getIcon() {
    3259                if (icon == null)
     
    3562        }
    3663
    37         public boolean isEditable() {
    38                 return true;
     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                }
    39180        }
    40181}
  • /src/org/openstreetmap/josm/gui/layer/RawGpsDataLayer.java

    r20 r30  
    11package org.openstreetmap.josm.gui.layer;
     2
     3import java.awt.Color;
     4import java.awt.Graphics;
     5import java.awt.Point;
     6import java.beans.PropertyChangeEvent;
     7import java.beans.PropertyChangeListener;
     8import java.util.Collection;
    29
    310import javax.swing.Icon;
    411
    5 import org.openstreetmap.josm.data.osm.DataSet;
     12import org.openstreetmap.josm.Main;
     13import org.openstreetmap.josm.data.Bounds;
     14import org.openstreetmap.josm.data.GeoPoint;
     15import org.openstreetmap.josm.data.projection.Projection;
    616import org.openstreetmap.josm.gui.ImageProvider;
    7 import org.openstreetmap.josm.gui.engine.RawGpsEngine;
     17import org.openstreetmap.josm.gui.MapView;
    818
    919/**
     
    1323 * @author imi
    1424 */
    15 public class RawGpsDataLayer extends DataLayer {
     25public class RawGpsDataLayer extends Layer {
    1626
    1727        private static Icon icon;
    1828
    19         protected RawGpsDataLayer(DataSet dataSet, String name) {
    20                 super(dataSet, new RawGpsEngine(), name);
     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                });
    2148        }
    2249
     
    2451         * Return a static icon.
    2552         */
     53        @Override
    2654        public Icon getIcon() {
    2755                if (icon == null)
     
    3058        }
    3159
    32         public boolean isEditable() {
    33                 return false;
     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);
    34144        }
    35145}
  • /src/org/openstreetmap/josm/io/GpxReader.java

    r20 r30  
    99import org.jdom.Namespace;
    1010import org.jdom.input.SAXBuilder;
     11import org.openstreetmap.josm.Main;
    1112import org.openstreetmap.josm.data.GeoPoint;
    1213import org.openstreetmap.josm.data.osm.DataSet;
     
    1617import org.openstreetmap.josm.data.osm.OsmPrimitive;
    1718import org.openstreetmap.josm.data.osm.Track;
    18 import org.openstreetmap.josm.gui.Main;
    1919
    2020/**
     
    2525 * @author imi
    2626 */
    27 public class GpxReader implements DataReader {
     27public class GpxReader {
    2828
    2929        /**
    3030         * The GPX namespace used.
    3131         */
    32         private static Namespace GPX = Namespace.getNamespace("http://www.topografix.com/GPX/1/0");
     32        public static final 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");
     36        private static final Namespace OSM = Namespace.getNamespace("osm", "http://www.openstreetmap.org");
    3737
    3838        /**
     
    4040         */
    4141        public Reader source;
    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        
     42
    4943        /**
    5044         * Construct a parser from a specific data source.
    5145         * @param source The data source, as example a FileReader to read from a file.
    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) {
     46         */
     47        public GpxReader(Reader source) {
    5748                this.source = source;
    58                 this.rawGps = rawGps;
    5949        }
    6050       
     
    6252         * Read the input stream and return a DataSet from the stream.
    6353         */
    64         public DataSet parse() throws ParseException, ConnectionException {
     54        public DataSet parse() throws JDOMException, IOException {
    6555                try {
    6656                        final SAXBuilder builder = new SAXBuilder();
    6757                        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                        
    7358                        return parseDataSet(root);
    7459                } catch (NullPointerException npe) {
    75                         throw new ParseException("NullPointerException. Probably a tag name mismatch.", npe);
     60                        throw new JDOMException("NullPointerException. Probably a tag name mismatch.", npe);
    7661                } catch (ClassCastException 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);
     62                        throw new JDOMException("ClassCastException. Probably a tag does not contain the correct type.", cce);
    8263                }
    8364        }
     
    9475                        Float.parseFloat(e.getAttributeValue("lat")),
    9576                        Float.parseFloat(e.getAttributeValue("lon")));
    96                
    97                 if (rawGps)
    98                         return data;
    9977               
    10078                for (Object o : e.getChildren()) {
     
    137115        private void parseTrack(Element e, DataSet ds) {
    138116                Track track = new Track();
     117                boolean realLineSegment = false; // is this track just a fake?
     118
    139119                for (Object o : e.getChildren()) {
    140120                        Element child = (Element)o;
     
    149129                                        else {
    150130                                                LineSegment lineSegment = new LineSegment(start, node);
    151                                                 if (!rawGps)
    152                                                         parseKeyValueExtensions(lineSegment, ((Element)w).getChild("extensions", GPX));
     131                                                parseKeyValueExtensions(lineSegment, child.getChild("extensions", GPX));
    153132                                                track.add(lineSegment);
    154133                                                start = null;
    155134                                        }
    156135                                }
    157                         }
    158                        
    159                         if (rawGps)
    160                                 continue;
    161                        
    162                         if (child.getName().equals("extensions"))
     136                        } else if (child.getName().equals("extensions")) {
    163137                                parseKeyValueExtensions(track, child);
    164                         else if (child.getName().equals("link"))
     138                                if (child.getChild("segment", OSM) != null)
     139                                        realLineSegment = true;
     140                        } else if (child.getName().equals("link"))
    165141                                parseKeyValueLink(track, child);
    166142                        else
    167143                                parseKeyValueTag(track, child);
    168144                }
    169                 ds.addTrack(track);
     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                }
    170151        }
    171152       
     
    183164         * @return Either the parameter node or the old node found in the dataset.
    184165         */
    185         private Node addNode (DataSet data, Node node) {
    186                 if (Main.pref.mergeNodes || rawGps)
     166        private Node addNode(DataSet data, Node node) {
     167                if (Main.pref.mergeNodes)
    187168                        for (Node n : data.nodes)
    188169                                if (node.coor.equalsLatLon(n.coor))
     
    203184        private void parseKeyValueExtensions(OsmPrimitive osm, Element e) {
    204185                if (e != null) {
    205                         if (osm.keys == null)
    206                                 osm.keys = new HashMap<Key, String>();
    207186                        for (Object o : e.getChildren("property", OSM)) {
     187                                if (osm.keys == null)
     188                                        osm.keys = new HashMap<Key, String>();
    208189                                Element child = (Element)o;
    209                                 Key key = Key.get(child.getAttributeValue("name"));
    210                                 osm.keys.put(key, child.getAttributeValue("value"));
     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                                }
    211198                        }
    212199                }
  • /src/org/openstreetmap/josm/io/GpxWriter.java

    r20 r30  
    1414import org.jdom.output.Format;
    1515import org.jdom.output.XMLOutputter;
    16 import org.openstreetmap.josm.data.osm.DataSet;
     16import org.openstreetmap.josm.Main;
    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;
    5349       
    5450        /**
     
    5753         *
    5854         * @param out The Writer to store the result data in.
    59          * @param ds The dataset to store.
    60          */
    61         public GpxWriter(Writer out, DataSet ds) {
    62                 this.ds = ds;
     55         */
     56        public GpxWriter(Writer out) {
    6357                this.out = out;
    6458        }
     
    8680                Element e = new Element("gpx", GPX);
    8781                e.setAttribute("version", "1.0");
    88                 e.setAttribute("creator", "JOSM Beta");
     82                e.setAttribute("creator", "JOSM Beta2");
    8983                // for getting all unreferenced waypoints in the wpt-list
    90                 LinkedList<Node> nodes = new LinkedList<Node>(ds.nodes);
     84                LinkedList<Node> nodes = new LinkedList<Node>(Main.main.ds.nodes);
    9185
    9286                // tracks
    93                 for (Track t : ds.tracks()) {
     87                for (Track t : Main.main.ds.tracks) {
    9488                        Element tElem = new Element("trk", GPX);
    9589                        if (t.keys != null) {
     
    10599                        }
    106100                        // line segments
    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);
     101                        for (LineSegment ls : t.segments) {
     102                                tElem.getChildren().add(parseLineSegment(ls));
     103                                nodes.remove(ls.start);
     104                                nodes.remove(ls.end);
    116105                        }
     106
    117107                        e.getChildren().add(tElem);
    118108                }
    119109               
     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
    120122                // waypoints (missing nodes)
    121123                for (Node n : nodes)
     
    123125
    124126                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;
    125141        }
    126142
     
    219235                if (keys.isEmpty())
    220236                        return;
    221                 Element extensions = e.getChild("extensions");
     237                Element extensions = e.getChild("extensions", GPX);
    222238                if (extensions == null)
    223239                        e.getChildren().add(extensions = new Element("extensions", GPX));
  • /src/org/openstreetmap/josm/io/OsmReader.java

    r20 r30  
    11package org.openstreetmap.josm.io;
    22
    3 import java.awt.Font;
    4 import java.awt.GridBagLayout;
    53import java.io.IOException;
    6 import java.io.InputStreamReader;
    74import java.io.Reader;
    8 import java.net.Authenticator;
    9 import java.net.HttpURLConnection;
    10 import java.net.PasswordAuthentication;
    11 import java.net.URL;
    12 
    13 import javax.swing.JLabel;
    14 import javax.swing.JOptionPane;
    15 import javax.swing.JPanel;
    16 import javax.swing.JPasswordField;
    17 import javax.swing.JTextField;
    18 
     5import java.util.Collection;
     6import java.util.HashMap;
     7import java.util.StringTokenizer;
     8
     9import org.jdom.Element;
     10import org.jdom.JDOMException;
     11import org.jdom.input.SAXBuilder;
     12import org.openstreetmap.josm.Main;
     13import org.openstreetmap.josm.data.GeoPoint;
    1914import org.openstreetmap.josm.data.osm.DataSet;
    20 import org.openstreetmap.josm.gui.GBC;
    21 import org.openstreetmap.josm.gui.Main;
     15import org.openstreetmap.josm.data.osm.Key;
     16import org.openstreetmap.josm.data.osm.LineSegment;
     17import org.openstreetmap.josm.data.osm.Node;
     18import org.openstreetmap.josm.data.osm.OsmPrimitive;
     19import org.openstreetmap.josm.data.osm.Track;
    2220
    2321/**
    24  * This DataReader read directly from the REST API of the osm server.
     22 * Reads an osm xml stream and construct a DataSet out of it.
    2523 *
    2624 * @author imi
    2725 */
    28 public class OsmReader implements DataReader {
    29 
    30         /**
    31          * The url string of the desired map data.
    32          */
    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;
    46 
    47         /**
    48          * Construct the reader and store the information for attaching
    49          */
    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=";
     26public class OsmReader {
     27
     28        /**
     29         * The data source from this reader.
     30         */
     31        public Reader source;
     32
     33        /**
     34         * Construct a parser from a specific data source.
     35         * @param source The data source, as example a FileReader to read from a file.
     36         */
     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                }
     56        }
     57
     58
     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.");
    5888               
    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;
     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), "");
    85101                                }
    86                                 passwordtried = true;
    87                                 return new PasswordAuthentication(username, password.toCharArray());
    88                         }
    89                 });
    90         }
    91 
    92 
    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);
     102                        }
     103                }
     104        }
     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;
    109188                                }
    110189                        }
    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);
    120                 }
     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;
    121223        }
    122224}
Note: See TracChangeset for help on using the changeset viewer.