Add a continuous selection From: <> Select all continuous segments --- images/mapmode/selection/continuous.png | Bin .../josm/actions/mapmode/SelectionAction.java | 121 ++++++++++++++++++++--- 2 files changed, 106 insertions(+), 15 deletions(-) diff --git a/images/mapmode/selection/continuous.png b/images/mapmode/selection/continuous.png new file mode 100644 index 0000000..6c05cb7 Binary files /dev/null and b/images/mapmode/selection/continuous.png differ diff --git a/src/org/openstreetmap/josm/actions/mapmode/SelectionAction.java b/src/org/openstreetmap/josm/actions/mapmode/SelectionAction.java index 62d747b..3ad577d 100644 --- a/src/org/openstreetmap/josm/actions/mapmode/SelectionAction.java +++ b/src/org/openstreetmap/josm/actions/mapmode/SelectionAction.java @@ -63,7 +63,7 @@ import org.openstreetmap.josm.tools.ImageProvider; */ public class SelectionAction extends MapMode implements SelectionEnded { - enum Mode {select, straight} + enum Mode {select, straight, continuous} private final Mode mode; public static class Group extends GroupAction { @@ -72,6 +72,7 @@ public class SelectionAction extends MapMode implements SelectionEnded { putValue("help", "Action/Selection"); actions.add(new SelectionAction(mf, tr("Selection"), Mode.select, tr("Select objects by dragging or clicking."))); actions.add(new SelectionAction(mf, tr("Straight line"), Mode.straight, tr("Select objects in a straight line."))); + actions.add(new SelectionAction(mf, tr("Continuous segments"), Mode.continuous, tr("Select continuous segments."))); setCurrent(0); } } @@ -85,10 +86,10 @@ public class SelectionAction extends MapMode implements SelectionEnded { private Node straightStart = null; private Node lastEnd = null; private Collection oldSelection = null; - + //TODO: Implement reverse references into data objects and remove this private final Map> reverseSegmentMap = new HashMap>(); - + /** * Create a new SelectionAction in the given frame. * @param mapFrame The frame this action belongs to @@ -104,13 +105,19 @@ public class SelectionAction extends MapMode implements SelectionEnded { super.enterMode(); if (mode == Mode.select) selectionManager.register(Main.map.mapView); - else { + else if (mode == Mode.straight) { Main.map.mapView.addMouseMotionListener(this); Main.map.mapView.addMouseListener(this); for (Segment s : Main.ds.segments) { addBackReference(s.from, s); addBackReference(s.to, s); } + } else if (mode == Mode.continuous) { + Main.map.mapView.addMouseListener(this); + for (Segment s : Main.ds.segments) { + addBackReference(s.from, s); + addBackReference(s.to, s); + } } } @@ -127,10 +134,12 @@ public class SelectionAction extends MapMode implements SelectionEnded { super.exitMode(); if (mode == Mode.select) selectionManager.unregister(Main.map.mapView); - else { + else if (mode == Mode.straight) { Main.map.mapView.removeMouseMotionListener(this); Main.map.mapView.removeMouseListener(this); reverseSegmentMap.clear(); + } else if (mode == Mode.continuous) { + Main.map.mapView.removeMouseListener(this); } } @@ -169,25 +178,60 @@ public class SelectionAction extends MapMode implements SelectionEnded { straightStart = lastEnd; if (straightStart != null && lastEnd != null && straightStart != lastEnd && old != lastEnd) { Collection path = new HashSet(); - Collection sel = new HashSet(); path.add(straightStart); calculateShortestPath(path, straightStart, lastEnd); - if ((e.getModifiers() & MouseEvent.CTRL_MASK) != 0) { - sel.addAll(oldSelection); - sel.removeAll(path); - } else if ((e.getModifiers() & MouseEvent.SHIFT_MASK) != 0) { - sel = path; - sel.addAll(oldSelection); - } else - sel = path; - Main.ds.setSelected(sel); + updateSelection(e, path); } } + /** + * Update the selection. + * + * Handles the modifier key. + * + * @param e + * @param path the path to use for updating. + */ + private void updateSelection(MouseEvent e, Collection path) { + Collection sel = new HashSet(); + if ((e.getModifiers() & MouseEvent.CTRL_MASK) != 0) { + sel.addAll(oldSelection); + sel.removeAll(path); + } else if ((e.getModifiers() & MouseEvent.SHIFT_MASK) != 0) { + sel = path; + sel.addAll(oldSelection); + } else + sel = path; + Main.ds.setSelected(sel); + } + + /** + * Continuous selection. + * + * Does a continuous selection. + * + * @param e + */ + private void continuousSelection(MouseEvent e) { + // Retrieve the initial segment + Segment initialSegment = Main.map.mapView.getNearestSegment(e.getPoint()); + if (initialSegment != null) { + // Initialise the path + Collection path = new HashSet(); + path.add(initialSegment); + // Fill the path with continuous segments + calculateContinuousPath(path, initialSegment); + // Update the selection with the path + updateSelection(e, path); + } + } + @Override public void mousePressed(MouseEvent e) { straightStart = Main.map.mapView.getNearestNode(e.getPoint()); lastEnd = null; oldSelection = Main.ds.getSelected(); + + if (mode == Mode.continuous) continuousSelection(e); } @Override public void mouseReleased(MouseEvent e) { @@ -234,4 +278,51 @@ public class SelectionAction extends MapMode implements SelectionEnded { } return null; } + + /** + * Get the continuous path. + * + * @param path Path to fill in + * @param initial initial segment + */ + private void calculateContinuousPath(Collection path, Segment initial) { + Segment current = null; + Segment next = initial; + Collection c = null; + // Reverse order + while ((current = next) != null && (c = reverseSegmentMap.get(current.from)) != null && c.size() == 2) { + for (Segment s : c) { + if (s != current) { + // s is the other segment connected to current node + if (s != initial && s.to == current.from) { + // s is the preceding segment + path.add(s); + next = s; + } else + // s and next are connected to the same node, but in opposite direction. + // Stop here. + next = null; + } + } + } + + next = initial; + // Correct order + while ((current = next) != null && (c = reverseSegmentMap.get(current.to)) != null && c.size() == 2) { + for (Segment s : c) { + if (s != current) { + // s is the other segment connected to current node + if (s != initial && s.from == current.to) { + // s is the preceding segment + path.add(s); + next = s; + } else + // s and next are connected to the same node, but in opposite direction. + // Stop here. + next = null; + } + } + } + + } }