Ticket #2411: patch_v2_not_cleaned_up.patch

File patch_v2_not_cleaned_up.patch, 74.9 KB (added by xeen, 15 years ago)
  • src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java

     
    55
    66import java.awt.AWTEvent;
    77import java.awt.Cursor;
    8 import java.awt.EventQueue;
    98import java.awt.Toolkit;
    109import java.awt.event.AWTEventListener;
    1110import java.awt.event.ActionEvent;
     
    1312import java.awt.event.KeyEvent;
    1413import java.awt.event.MouseEvent;
    1514import java.util.Collections;
     15import java.util.HashSet;
     16import java.util.Set;
    1617
    1718import org.openstreetmap.josm.Main;
    1819import org.openstreetmap.josm.command.Command;
    1920import org.openstreetmap.josm.command.DeleteCommand;
     21import org.openstreetmap.josm.data.osm.DataSet;
    2022import org.openstreetmap.josm.data.osm.Node;
    2123import org.openstreetmap.josm.data.osm.OsmPrimitive;
    2224import org.openstreetmap.josm.data.osm.Relation;
     
    4446 *
    4547 * @author imi
    4648 */
    47 
    48 /**
    49  * This class contains stubs for highlighting affected primitives when affected.
    50  * However, way segments can be deleted as well, but cannot be highlighted
    51  * alone. If the highlight feature for this delete action is to be implemented
    52  * properly, highlighting way segments must be possible first. --xeen, 2009-09-02
    53  */
    5449public class DeleteAction extends MapMode implements AWTEventListener {
    5550    // Cache previous mouse event (needed when only the modifier keys are
    5651    // pressed but the mouse isn't moved)
    5752    private MouseEvent oldEvent = null;
    5853
     54    /**
     55     * elements that have been highlighted in the previous iteration. Used
     56     * to remove the highlight from them again as otherwise the whole data
     57     * set would have to be checked.
     58     */
     59    private Set<OsmPrimitive> oldHighlights = new HashSet<OsmPrimitive>();
     60
     61    private boolean drawTargetHighlight;
     62
    5963    private enum DeleteMode {
    6064        none("delete"),
    6165        segment("delete_segment"),
     
    100104        if (!isEnabled())
    101105            return;
    102106
     107        drawTargetHighlight = Main.pref.getBoolean("draw.target-highlight", true);
     108
    103109        Main.map.mapView.addMouseListener(this);
    104110        Main.map.mapView.addMouseMotionListener(this);
    105111        // This is required to update the cursors when ctrl/shift/alt is pressed
     
    119125        } catch (SecurityException ex) {
    120126            System.out.println(ex);
    121127        }
     128        removeHighlighting();
    122129    }
    123130
    124131    @Override public void actionPerformed(ActionEvent e) {
     
    156163     */
    157164    @Override public void mouseMoved(MouseEvent e) {
    158165        oldEvent = e;
    159         updateCursor(e, e.getModifiers());
     166        giveUserFeedback(e);
    160167    }
    161168
    162169    /**
     170     * removes any highlighting that may have been set beforehand.
     171     */
     172    private void removeHighlighting() {
     173        for(OsmPrimitive prim : oldHighlights) {
     174            prim.setHighlighted(false);
     175        }
     176        oldHighlights = new HashSet<OsmPrimitive>();
     177        DataSet ds = getCurrentDataSet();
     178        if(ds != null) {
     179            ds.clearHighlightedWaySegments();
     180        }
     181    }
     182
     183    /**
     184     * handles everything related to highlighting primitives and way
     185     * segments for the given pointer position (via MouseEvent) and
     186     * modifiers.
     187     * @param e
     188     * @param modifiers
     189     */
     190    private void addHighlighting(MouseEvent e, int modifiers) {
     191        if(!drawTargetHighlight)
     192            return;
     193        removeHighlighting();
     194
     195        Command delCmd = buildDeleteCommands(e, modifiers, true);
     196        if(delCmd == null) {
     197            Main.map.mapView.repaint();
     198            return;
     199        }
     200
     201        DeleteParameters parameters = getDeleteParameters(e, modifiers);
     202
     203        if(parameters.mode == DeleteMode.segment) {
     204            // deleting segments is the only action not working on OsmPrimitives
     205            // so we have to handle them separately.
     206            DataSet ds = getCurrentDataSet();
     207            if(ds != null) {
     208                ds.setHighlightedWaySegments(Collections.singleton(parameters.nearestSegment));
     209            }
     210        } else {
     211            // all other cases delete OsmPrimitives directly, so we can
     212            // safely do the following
     213            for(OsmPrimitive osm : delCmd.getParticipatingPrimitives()) {
     214                osm.setHighlighted(true);
     215                oldHighlights.add(osm);
     216            }
     217        }
     218        Main.map.mapView.repaint();
     219    }
     220
     221    /**
    163222     * This function handles all work related to updating the cursor and
    164      * highlights. For now, only the cursor is enabled because highlighting
    165      * requires WaySegment to be highlightable.
     223     * highlights
    166224     *
    167      * Normally the mouse event also contains the modifiers. However, when the
    168      * mouse is not moved and only modifier keys are pressed, no mouse event
    169      * occurs. We can use AWTEvent to catch those but still lack a proper
    170      * mouseevent. Instead we copy the previous event and only update the
    171      * modifiers.
    172      *
    173225     * @param MouseEvent
    174226     * @param int modifiers
    175227     */
     
    182234        DeleteParameters parameters = getDeleteParameters(e, modifiers);
    183235        Main.map.mapView.setNewCursor(parameters.mode.cursor(), this);
    184236    }
     237    /**
     238     * Gives the user feedback for the action he/she is about to do. Currently
     239     * calls the cursor and target highlighting routines. Allows for modifiers
     240     * not taken from the given mouse event.
     241     *
     242     * Normally the mouse event also contains the modifiers. However, when the
     243     * mouse is not moved and only modifier keys are pressed, no mouse event
     244     * occurs. We can use AWTEvent to catch those but still lack a proper
     245     * mouseevent. Instead we copy the previous event and only update the
     246     * modifiers.
     247     */
     248    private void giveUserFeedback(MouseEvent e, int modifiers) {
     249        updateCursor(e, modifiers);
     250        addHighlighting(e, modifiers);
     251    }
    185252
    186253    /**
     254     * Gives the user feedback for the action he/she is about to do. Currently
     255     * calls the cursor and target highlighting routines. Extracts modifiers
     256     * from mouse event.
     257     */
     258    private void giveUserFeedback(MouseEvent e) {
     259        giveUserFeedback(e, e.getModifiers());
     260    }
     261
     262    /**
    187263     * If user clicked with the left button, delete the nearest object.
    188264     * position.
    189265     */
     
    203279        }
    204280
    205281        getCurrentDataSet().setSelected();
     282        giveUserFeedback(e);
    206283        Main.map.mapView.repaint();
    207284    }
    208285
     
    241318    }
    242319
    243320    private DeleteParameters getDeleteParameters(MouseEvent e, int modifiers) {
    244         // Note: CTRL is the only modifier that is checked in MouseMove, don't
    245         // forget updating it there
    246         boolean ctrl = (modifiers & ActionEvent.CTRL_MASK) != 0;
    247         boolean shift = (modifiers & ActionEvent.SHIFT_MASK) != 0;
    248         boolean alt = (modifiers & (ActionEvent.ALT_MASK|InputEvent.ALT_GRAPH_MASK)) != 0;
     321        updateKeyModifiers(modifiers);
    249322
    250323        DeleteParameters result = new DeleteParameters();
    251324
     
    287360        case node:
    288361            return DeleteCommand.delete(getEditLayer(),Collections.singleton(parameters.nearestNode), false, silent);
    289362        case node_with_references:
    290             return DeleteCommand.deleteWithReferences(getEditLayer(),Collections.singleton(parameters.nearestNode));
     363            return DeleteCommand.deleteWithReferences(getEditLayer(),Collections.singleton(parameters.nearestNode), silent);
    291364        case segment:
    292365            return DeleteCommand.deleteWaySegment(getEditLayer(), parameters.nearestSegment);
    293366        case way:
     
    295368        case way_with_nodes:
    296369            return DeleteCommand.delete(getEditLayer(), Collections.singleton(parameters.nearestSegment.way), true, silent);
    297370        case way_with_references:
    298             return DeleteCommand.deleteWithReferences(getEditLayer(),Collections.singleton(parameters.nearestSegment.way),true);
     371            return DeleteCommand.deleteWithReferences(getEditLayer(), Collections.singleton(parameters.nearestSegment.way), true);
    299372        default:
    300373            return null;
    301374        }
     
    305378     * This is required to update the cursors when ctrl/shift/alt is pressed
    306379     */
    307380    public void eventDispatched(AWTEvent e) {
     381        if(e == null)
     382            return;
    308383        // We don't have a mouse event, so we pass the old mouse event but the
    309384        // new modifiers.
    310         updateCursor(oldEvent, ((InputEvent)e).getModifiers());
     385        giveUserFeedback(oldEvent, ((InputEvent) e).getModifiers());
    311386    }
    312387}
  • src/org/openstreetmap/josm/actions/mapmode/MapMode.java

     
    33
    44import java.awt.Cursor;
    55import java.awt.event.ActionEvent;
     6import java.awt.event.InputEvent;
    67import java.awt.event.MouseEvent;
    78import java.awt.event.MouseListener;
    89import java.awt.event.MouseMotionListener;
     
    2425 */
    2526abstract public class MapMode extends JosmAction implements MouseListener, MouseMotionListener {
    2627    protected final Cursor cursor;
     28    protected boolean ctrl;
     29    protected boolean alt;
     30    protected boolean shift;
    2731
    2832    /**
    2933     * Constructor for mapmodes without an menu
     
    7680        return true;
    7781    }
    7882
     83    protected void updateKeyModifiers(InputEvent e) {
     84        updateKeyModifiers(e.getModifiers());
     85    }
     86
     87    protected void updateKeyModifiers(MouseEvent e) {
     88        updateKeyModifiers(e.getModifiers());
     89    }
     90
     91    protected void updateKeyModifiers(int modifiers) {
     92        ctrl = (modifiers & ActionEvent.CTRL_MASK) != 0;
     93        alt = (modifiers & (ActionEvent.ALT_MASK|InputEvent.ALT_GRAPH_MASK)) != 0;
     94        shift = (modifiers & ActionEvent.SHIFT_MASK) != 0;
     95    }
     96
    7997    public void mouseReleased(MouseEvent e) {}
    8098    public void mouseExited(MouseEvent e) {}
    8199    public void mousePressed(MouseEvent e) {}
  • src/org/openstreetmap/josm/actions/mapmode/PlayHeadDragMode.java

     
    55
    66import java.awt.Cursor;
    77import java.awt.Point;
    8 import java.awt.event.ActionEvent;
    98import java.awt.event.MouseEvent;
    109
    1110import org.openstreetmap.josm.Main;
     
    2726
    2827    public PlayHeadDragMode(PlayHeadMarker m) {
    2928        super(tr("Drag play head"), "playheaddrag", tr("Drag play head"), null,
    30         Main.map, Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
     29                Main.map, Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
    3130        playHeadMarker = m;
    3231    }
    3332
     
    6766        mouseStart = null;
    6867        if (ev.getButton() != MouseEvent.BUTTON1 || p == null || ! dragging)
    6968            return;
    70         boolean shift = (ev.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
     69
     70        updateKeyModifiers(ev);
     71
    7172        EastNorth en = Main.map.mapView.getEastNorth(ev.getX(), ev.getY());
    7273        if (! shift) {
    7374            playHeadMarker.reposition(en);
  • src/org/openstreetmap/josm/actions/mapmode/DrawAction.java

     
    88import java.awt.BasicStroke;
    99import java.awt.Color;
    1010import java.awt.Cursor;
    11 import java.awt.EventQueue;
    1211import java.awt.Graphics2D;
    1312import java.awt.Point;
    1413import java.awt.Toolkit;
    1514import java.awt.event.AWTEventListener;
    16 import java.awt.event.ActionEvent;
    1715import java.awt.event.InputEvent;
    1816import java.awt.event.KeyEvent;
    1917import java.awt.event.MouseEvent;
     
    6563    private Node lastUsedNode = null;
    6664    private double PHI=Math.toRadians(90);
    6765
    68     private boolean ctrl;
    69     private boolean alt;
    70     private boolean shift;
    7166    private Node mouseOnExistingNode;
    7267    private Set<Way> mouseOnExistingWays = new HashSet<Way>();
    7368    private Set<OsmPrimitive> oldHighlights = new HashSet<OsmPrimitive>();
     
    512507
    513508        getCurrentDataSet().setSelected(newSelection);
    514509
    515         // "viewport following" mode for tracing long features 
    516         // from aerial imagery or GPS tracks. 
     510        // "viewport following" mode for tracing long features
     511        // from aerial imagery or GPS tracks.
    517512        if (n != null && Main.map.mapView.viewportFollowing) {
    518513            Main.map.mapView.smoothScrollTo(n.getEastNorth());
    519514        };
     
    601596        redrawIfRequired();
    602597    }
    603598
    604     private void updateKeyModifiers(InputEvent e) {
    605         ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
    606         alt = (e.getModifiers() & (ActionEvent.ALT_MASK|InputEvent.ALT_GRAPH_MASK)) != 0;
    607         shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
    608     }
    609 
    610     private void updateKeyModifiers(MouseEvent e) {
    611         ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
    612         alt = (e.getModifiers() & (ActionEvent.ALT_MASK|InputEvent.ALT_GRAPH_MASK)) != 0;
    613         shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
    614     }
    615 
    616599    /**
    617600     * This method prepares data required for painting the "helper line" from
    618601     * the last used position to the mouse cursor. It duplicates some code from
  • src/org/openstreetmap/josm/actions/mapmode/ParallelWayAction.java

     
    1313import java.awt.Stroke;
    1414import java.awt.Toolkit;
    1515import java.awt.event.AWTEventListener;
    16 import java.awt.event.ActionEvent;
    1716import java.awt.event.InputEvent;
    1817import java.awt.event.KeyEvent;
    1918import java.awt.event.MouseEvent;
     
    108107
    109108    private final MapView mv;
    110109
    111     private boolean ctrl;
    112     private boolean alt;
    113     private boolean shift;
    114 
    115110    // Mouse tracking state
    116111    private Point mousePressedPos;
    117112    private boolean mouseIsDown;
     
    232227
    233228    private boolean updateModifiersState(InputEvent e) {
    234229        boolean oldAlt = alt, oldShift = shift, oldCtrl = ctrl;
    235         alt = (e.getModifiers() & (ActionEvent.ALT_MASK | InputEvent.ALT_GRAPH_MASK)) != 0;
    236         ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
    237         shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
     230        updateKeyModifiers(e);
    238231        boolean changed = (oldAlt != alt || oldShift != shift || oldCtrl != ctrl);
    239232        return changed;
    240233    }
     
    393386            // event can come quite late
    394387            if (!isModifiersValidForDragMode())
    395388                return;
    396             if (!initParallelWays(mousePressedPos, copyTags)) {
     389            if (!initParallelWays(mousePressedPos, copyTags))
    397390                return;
    398             }
    399391            setMode(Mode.dragging);
    400392        }
    401393
     
    408400        double d = enp.distance(nearestPointOnRefLine);
    409401        double realD = mv.getProjection().eastNorth2latlon(enp).greatCircleDistance(mv.getProjection().eastNorth2latlon(nearestPointOnRefLine));
    410402        double snappedRealD = realD;
    411        
     403
    412404        // TODO: abuse of isToTheRightSideOfLine function.
    413405        boolean toTheRight = Geometry.isToTheRightSideOfLine(referenceSegment.getFirstNode(),
    414406                referenceSegment.getFirstNode(), referenceSegment.getSecondNode(), new Node(enp));
     
    430422            d = -d;
    431423        }
    432424        pWays.changeOffset(d);
    433        
     425
    434426        Main.map.statusLine.setDist(Math.abs(snappedRealD));
    435427        Main.map.statusLine.repaint();
    436428        mv.repaint();
  • src/org/openstreetmap/josm/actions/mapmode/SelectAction.java

     
    55import static org.openstreetmap.josm.tools.I18n.tr;
    66import static org.openstreetmap.josm.tools.I18n.trn;
    77
     8import java.awt.AWTEvent;
    89import java.awt.Cursor;
    910import java.awt.Point;
    1011import java.awt.Rectangle;
     12import java.awt.Toolkit;
     13import java.awt.event.AWTEventListener;
    1114import java.awt.event.ActionEvent;
    1215import java.awt.event.InputEvent;
    1316import java.awt.event.KeyEvent;
     
    1518import java.awt.geom.Point2D;
    1619import java.util.Collection;
    1720import java.util.Collections;
     21import java.util.HashSet;
    1822import java.util.Iterator;
    1923import java.util.LinkedList;
     24import java.util.Set;
    2025
    2126import javax.swing.JOptionPane;
    2227
     
    5964 *
    6065 * @author imi
    6166 */
    62 public class SelectAction extends MapMode implements SelectionEnded {
     67public class SelectAction extends MapMode implements AWTEventListener, SelectionEnded {
     68    // "select" means the selection rectangle and "move" means either dragging
     69    // or select if no mouse movement occurs (i.e. just clicking)
    6370    enum Mode { move, rotate, scale, select }
    64    
     71
     72    // contains all possible cases the cursor can be in the SelectAction except the
     73    // the move pointer (latter is a system one and not an image)
     74    private enum SelectActionCursor {
     75        rect("normal", "selection"),
     76        rect_add("normal", "select_add"),
     77        rect_rm("normal", "select_remove"),
     78        way("normal", "select_way"),
     79        way_add("normal", "select_way_add"),
     80        way_rm("normal", "select_way_remove"),
     81        node("normal", "select_node"),
     82        node_add("normal", "select_node_add"),
     83        node_rm("normal", "select_node_remove"),
     84        virtual_node("normal", "addnode"),
     85        scale("scale", null),
     86        rotate("rotate", null);
     87
     88        private final Cursor c;
     89        private SelectActionCursor(String main, String sub) {
     90            c = ImageProvider.getCursor(main, sub);
     91        }
     92        public Cursor cursor() {
     93            return c;
     94        }
     95    }
     96
     97    // Cache previous mouse event (needed when only the modifier keys are
     98    // pressed but the mouse isn't moved)
     99    private MouseEvent oldEvent = null;
     100
    65101    private Mode mode = null;
    66102    private SelectionManager selectionManager;
    67103    private boolean cancelDrawMode = false;
     104    private boolean drawTargetHighlight;
    68105    private boolean didMouseDrag = false;
    69106    /**
    70107     * The component this SelectAction is associated with.
     
    95132    private boolean initialMoveThresholdExceeded = false;
    96133
    97134    /**
     135     * elements that have been highlighted in the previous iteration. Used
     136     * to remove the highlight from them again as otherwise the whole data
     137     * set would have to be checked.
     138     */
     139    private Set<OsmPrimitive> oldHighlights = new HashSet<OsmPrimitive>();
     140
     141    /**
    98142     * Create a new SelectAction
    99143     * @param mapFrame The MapFrame this action belongs to.
    100144     */
     
    108152        selectionManager = new SelectionManager(this, false, mv);
    109153        initialMoveDelay = Main.pref.getInteger("edit.initial-move-delay", 200);
    110154        initialMoveThreshold = Main.pref.getInteger("edit.initial-move-threshold", 5);
     155        drawTargetHighlight = Main.pref.getBoolean("draw.target-highlight", true);
     156        // This is required to update the cursors when ctrl/shift/alt is pressed
     157        try {
     158            Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.KEY_EVENT_MASK);
     159        } catch (SecurityException ex) {
     160            System.out.println(ex);
     161        }
    111162    }
    112163
    113164    @Override
     
    126177        mv.removeMouseListener(this);
    127178        mv.removeMouseMotionListener(this);
    128179        mv.setVirtualNodesEnabled(false);
     180        removeHighlighting();
    129181    }
    130182
    131183    /**
     184     * works out which cursor should be displayed for most of SelectAction's
     185     * features. The only exception is the "move" cursor when actually dragging
     186     * primitives.
     187     * @param nearbyStuff  primitives near the cursor
     188     * @return the cursor that should be displayed
     189     */
     190    private Cursor getCursor(Collection<OsmPrimitive> nearbyStuff) {
     191        String c = "rect";
     192        switch(mode) {
     193        case move:
     194            if(virtualNode != null) {
     195                c = "virtual_node";
     196                break;
     197            }
     198
     199            // nearbyStuff cannot be empty as otherwise we would be in
     200            // Move.select and not Move.move
     201            OsmPrimitive osm = nearbyStuff.iterator().next();
     202
     203            c = (osm instanceof Node) ? "node" : c;
     204            c = (osm instanceof Way) ? "way" : c;
     205
     206            if(shift) {
     207                c += "_add";
     208            } else if(ctrl) {
     209                c += osm.isSelected() ? "_rm" : "_add";
     210            }
     211            break;
     212        case rotate:
     213            c = "rotate";
     214            break;
     215        case scale:
     216            c = "scale";
     217            break;
     218        case select:
     219            c = "rect" + (shift ? "_add" : (ctrl ? "_rm" : ""));
     220            break;
     221        }
     222        return SelectActionCursor.valueOf(c).cursor();
     223    }
     224
     225    /**
     226     * Removes all existing highlights.
     227     * @return true if a repaint is required
     228     */
     229    private boolean removeHighlighting() {
     230        boolean needsRepaint = false;
     231        DataSet ds = getCurrentDataSet();
     232        if(ds != null && !ds.getHighlightedVirtualNodes().isEmpty()) {
     233            needsRepaint = true;
     234            ds.clearHighlightedVirtualNodes();
     235        }
     236        if(oldHighlights.isEmpty())
     237            return needsRepaint;
     238
     239        for(OsmPrimitive prim : oldHighlights) {
     240            prim.setHighlighted(false);
     241        }
     242        oldHighlights = new HashSet<OsmPrimitive>();
     243        return true;
     244    }
     245
     246    /**
     247     * handles adding highlights and updating the cursor for the given mouse event.
     248     * @param MouseEvent which should be used as base for the feedback
     249     * @return true if repaint is required
     250     */
     251    private boolean giveUserFeedback(MouseEvent e) {
     252        return giveUserFeedback(e, e.getModifiers());
     253    }
     254
     255    /**
     256     * handles adding highlights and updating the cursor for the given mouse event.
     257     * @param MouseEvent which should be used as base for the feedback
     258     * @param define custom keyboard modifiers if the ones from MouseEvent are outdated or similar
     259     * @return true if repaint is required
     260     */
     261    private boolean giveUserFeedback(MouseEvent e, int modifiers) {
     262        boolean needsRepaints = false;
     263
     264        Collection<OsmPrimitive> c = MapView.asColl(
     265                mv.getNearestNodeOrWay(e.getPoint(), OsmPrimitive.isSelectablePredicate, true));
     266
     267        updateKeyModifiers(modifiers);
     268        determineMapMode(!c.isEmpty());
     269
     270        if(drawTargetHighlight) {
     271            needsRepaints = removeHighlighting();
     272        }
     273
     274        virtualWays.clear();
     275        virtualNode = null;
     276        if(mode == Mode.move && setupVirtual(e)) {
     277            DataSet ds = getCurrentDataSet();
     278            if (ds != null) {
     279                ds.setHighlightedVirtualNodes(virtualWays);
     280            }
     281            mv.setNewCursor(SelectActionCursor.virtual_node.cursor(), this);
     282            // don't highlight anything else if a virtual node will be
     283            return true;
     284        }
     285
     286        mv.setNewCursor(getCursor(c), this);
     287
     288        // return early if there can't be any highlights
     289        if(!drawTargetHighlight || mode != Mode.move || c.isEmpty())
     290            return needsRepaints;
     291
     292        oldHighlights = (Set<OsmPrimitive>) c;
     293        for(OsmPrimitive x : c) {
     294            // only highlight primitives that will change the selection
     295            // when clicked. I.e. don't highlight selected elements unless
     296            // we are in toggle mode.
     297            if(ctrl || !x.isSelected()) {
     298                x.setHighlighted(true);
     299            }
     300        }
     301        return true;
     302    }
     303
     304    /**
     305     * This is called whenever the keyboard modifier status changes
     306     */
     307    public void eventDispatched(AWTEvent e) {
     308        if(e == null)
     309            return;
     310        // We don't have a mouse event, so we pass the old mouse event but the
     311        // new modifiers.
     312        giveUserFeedback(oldEvent, ((InputEvent) e).getModifiers());
     313    }
     314
     315    /**
    132316     * If the left mouse button is pressed, move all currently selected
    133317     * objects (if one of them is under the mouse) or the current one under the
    134318     * mouse (which will become selected).
     
    210394                return;
    211395
    212396            Command c = !Main.main.undoRedo.commands.isEmpty()
    213                     ? Main.main.undoRedo.commands.getLast() : null;
     397            ? Main.main.undoRedo.commands.getLast() : null;
    214398            if (c instanceof SequenceCommand) {
    215399                c = ((SequenceCommand) c).getLastCommand();
    216400            }
     
    263447    @Override
    264448    public void mouseMoved(MouseEvent e) {
    265449        // Mac OSX simulates with  ctrl + mouse 1  the second mouse button hence no dragging events get fired.
    266         //
    267450        if ((Main.platform instanceof PlatformHookOsx) && (mode == Mode.rotate || mode == Mode.scale)) {
    268451            mouseDragged(e);
     452            return;
    269453        }
     454        oldEvent = e;
     455        if(giveUserFeedback(e)) {
     456            mv.repaint();
     457        }
    270458    }
     459
     460    @Override
     461    public void mouseExited(MouseEvent e) {
     462        if(removeHighlighting()) {
     463            mv.repaint();
     464        }
     465    }
     466
    271467    private Node virtualNode = null;
    272468    private Collection<WaySegment> virtualWays = new LinkedList<WaySegment>();
    273469
     
    338534
    339535            Point p = e.getPoint();
    340536            boolean waitForMouseUp = Main.pref.getBoolean("mappaint.select.waits-for-mouse-up", false);
    341             boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
    342             boolean alt = ((e.getModifiers() & (ActionEvent.ALT_MASK | InputEvent.ALT_GRAPH_MASK)) != 0 || Main.pref.getBoolean("selectaction.cycles.multiple.matches", false));
     537            updateKeyModifiers(e);
     538            alt = alt || Main.pref.getBoolean("selectaction.cycles.multiple.matches", false);
    343539
    344540            if (!alt) {
    345541                cycleList = MapView.asColl(osm);
     
    388584    }
    389585
    390586    /**
     587     * sets the mapmode according to key modifiers and if there are any
     588     * selectables nearby. Everything has to be pre-determined for this
     589     * function; its main purpose is to centralize what the modifiers do.
     590     * @param nearSelectables
     591     */
     592    private void determineMapMode(boolean hasSelectionNearby) {
     593        if (shift && ctrl) {
     594            mode = Mode.rotate;
     595        } else if (alt && ctrl) {
     596            mode = Mode.scale;
     597        } else if (hasSelectionNearby) {
     598            mode = Mode.move;
     599        } else {
     600            mode = Mode.select;
     601        }
     602    }
     603
     604    /**
    391605     * Look, whether any object is selected. If not, select the nearest node.
    392606     * If there are no nodes in the dataset, do nothing.
    393607     *
     
    399613    @Override
    400614    public void mousePressed(MouseEvent e) {
    401615        // return early
    402         if (!mv.isActiveLayerVisible() || !(Boolean) this.getValue("active") || e.getButton() != MouseEvent.BUTTON1) {
     616        if (!mv.isActiveLayerVisible() || !(Boolean) this.getValue("active") || e.getButton() != MouseEvent.BUTTON1)
    403617            return;
    404         }
    405618
    406619        // request focus in order to enable the expected keyboard shortcuts
    407620        mv.requestFocus();
    408621
    409         boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
    410         boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
    411         boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
     622        // update which modifiers are pressed (shift, alt, ctrl)
     623        updateKeyModifiers(e);
    412624
    413625        // We don't want to change to draw tool if the user tries to (de)select
    414626        // stuff but accidentally clicks in an empty area when selection is empty
     
    421633        Collection<OsmPrimitive> c = MapView.asColl(
    422634                mv.getNearestNodeOrWay(e.getPoint(), OsmPrimitive.isSelectablePredicate, true));
    423635
    424         if (shift && ctrl) {
    425             mode = Mode.rotate;
    426 
     636        determineMapMode(!c.isEmpty());
     637        switch(mode) {
     638        case rotate:
     639        case scale:
    427640            if (getCurrentDataSet().getSelected().isEmpty()) {
    428641                getCurrentDataSet().setSelected(c);
    429642            }
     
    431644            // Mode.select redraws when selectPrims is called
    432645            // Mode.move   redraws when mouseDragged is called
    433646            // Mode.rotate redraws here
    434             mv.setNewCursor(ImageProvider.getCursor("rotate", null), this);
    435             mv.repaint();
    436         } else if (alt && ctrl) {
    437             mode = Mode.scale;
    438 
    439             if (getCurrentDataSet().getSelected().isEmpty()) {
    440                 getCurrentDataSet().setSelected(c);
    441             }
    442 
    443             // Mode.select redraws when selectPrims is called
    444             // Mode.move   redraws when mouseDragged is called
    445647            // Mode.scale redraws here
    446             mv.setNewCursor(ImageProvider.getCursor("scale", null), this);
    447             mv.repaint();
    448         } else if (!c.isEmpty()) {
    449             mode = Mode.move;
    450 
     648            break;
     649        case move:
    451650            if (!cancelDrawMode && c.iterator().next() instanceof Way) {
    452651                setupVirtual(e);
    453652            }
    454653
    455654            selectPrims(cycleSetup(c, e), e, false, false);
    456         } else {
    457             mode = Mode.select;
    458 
     655            break;
     656        case select:
     657        default:
    459658            selectionManager.register(mv);
    460659            selectionManager.mousePressed(e);
     660            break;
    461661        }
    462 
     662        // this doesn't require repainting since the mouse was only pressed
     663        // but not moved, therefore the highlighted elements will still be
     664        // the same
     665        giveUserFeedback(e);
     666        mv.repaint();
    463667        updateStatusLine();
    464668    }
    465669
    466670    @Override
    467671    public void mouseReleased(MouseEvent e) {
    468         if (!mv.isActiveLayerVisible()) {
     672        if (!mv.isActiveLayerVisible())
    469673            return;
    470         }
    471674
    472675        startingDraggingPos = null;
    473676
    474         mv.setNewCursor(cursor, this);
    475677        if (mode == Mode.select) {
    476678            selectionManager.unregister(mv);
    477679
     
    488690                virtualWays.clear();
    489691                virtualNode = null;
    490692
    491                 // do nothing if the click was to short to be recognized as a drag,
     693                // do nothing if the click was to short too be recognized as a drag,
    492694                // but the release position is farther than 10px away from the press position
    493695                if (lastMousePos.distanceSq(e.getPoint()) < 100) {
    494696                    selectPrims(cyclePrims(cycleList, e), e, true, false);
     
    499701                        // We need to do it like this as otherwise drawAction will see a double
    500702                        // click and switch back to SelectMode
    501703                        Main.worker.execute(new Runnable() {
    502 
    503704                            public void run() {
    504705                                Main.map.selectDrawTool(true);
    505706                            }
     
    538739            }
    539740        }
    540741
    541         // I don't see why we need this.
    542         //updateStatusLine();
    543742        mode = null;
     743        giveUserFeedback(e);
    544744        updateStatusLine();
    545745    }
    546746
    547747    public void selectionEnded(Rectangle r, MouseEvent e) {
    548         boolean alt = (e.getModifiersEx() & (MouseEvent.ALT_DOWN_MASK | MouseEvent.ALT_GRAPH_DOWN_MASK)) != 0;
     748        updateKeyModifiers(e);
    549749        selectPrims(selectionManager.getObjectsInRectangle(r, alt), e, true, true);
    550750    }
    551751
     
    553753     * Modifies current selection state and returns the next element in a
    554754     * selection cycle given by <code>prims</code>.
    555755     * @param prims the primitives that form the selection cycle
    556      * @param shift whether shift is pressed
    557      * @param ctrl whether ctrl is pressed
     756     * @param mouse event
    558757     * @return the next element of cycle list <code>prims</code>.
    559758     */
    560759    private Collection<OsmPrimitive> cyclePrims(Collection<OsmPrimitive> prims, MouseEvent e) {
    561760        OsmPrimitive nxt = null;
    562761
    563762        if (prims.size() > 1) {
    564             boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
    565             boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
     763            updateKeyModifiers(e);
    566764
    567765            DataSet ds = getCurrentDataSet();
    568766            OsmPrimitive first = prims.iterator().next(), foundInDS = null;
     
    629827    }
    630828
    631829    private void selectPrims(Collection<OsmPrimitive> prims, MouseEvent e, boolean released, boolean area) {
    632         boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
    633         boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
     830        updateKeyModifiers(e);
    634831        DataSet ds = getCurrentDataSet();
    635832
    636833        // not allowed together: do not change dataset selection, return early
    637         if ((shift && ctrl) || (ctrl && !released) || (!virtualWays.isEmpty())) {
     834        if ((shift && ctrl) || (ctrl && !released) || (!virtualWays.isEmpty()))
    638835            return;
    639         }
    640836
    641837        if (!released) {
    642838            // Don't replace the selection if the user clicked on a
     
    665861
    666862    @Override
    667863    public String getModeHelpText() {
    668         if (mode == Mode.select) {
     864        if (mode == Mode.select)
    669865            return tr("Release the mouse button to select the objects in the rectangle.");
    670         } else if (mode == Mode.move) {
     866        else if (mode == Mode.move)
    671867            return tr("Release the mouse button to stop moving. Ctrl to merge with nearest node.");
    672         } else if (mode == Mode.rotate) {
     868        else if (mode == Mode.rotate)
    673869            return tr("Release the mouse button to stop rotating.");
    674         } else if (mode == Mode.scale) {
     870        else if (mode == Mode.scale)
    675871            return tr("Release the mouse button to stop scaling.");
    676         } else {
     872        else
    677873            return tr("Move objects by dragging; Shift to add to selection (Ctrl to toggle); Shift-Ctrl to rotate selected; Alt-Ctrl to scale selected; or change selection");
    678         }
    679874    }
    680875
    681876    @Override
  • src/org/openstreetmap/josm/actions/mapmode/ExtrudeAction.java

     
    184184        if (e.getButton() != MouseEvent.BUTTON1)
    185185            return;
    186186
     187        updateKeyModifiers(e);
     188
    187189        selectedSegment = Main.map.mapView.getNearestWaySegment(e.getPoint(), OsmPrimitive.isSelectablePredicate);
    188190
    189191        if (selectedSegment == null) {
     
    191193        } else {
    192194            // Otherwise switch to another mode
    193195
    194             if ((e.getModifiers() & ActionEvent.CTRL_MASK) != 0) {
     196            if (ctrl) {
    195197                mode = Mode.translate;
    196             } else if ((e.getModifiers() & (ActionEvent.ALT_MASK|InputEvent.ALT_GRAPH_MASK)) != 0) {
     198            } else if (alt) {
    197199                mode = Mode.create_new;
    198200                // create a new segment and then select and extrude the new segment
    199201                getCurrentDataSet().setSelected(selectedSegment.way);
     
    201203            } else {
    202204                mode = Mode.extrude;
    203205                getCurrentDataSet().setSelected(selectedSegment.way);
    204                 alwaysCreateNodes = ((e.getModifiers() & ActionEvent.SHIFT_MASK) != 0);
     206                alwaysCreateNodes = shift;
    205207            }
    206208
    207209            // remember initial positions for segment nodes.
  • src/org/openstreetmap/josm/gui/OsmPrimitivRenderer.java

     
    6666     */
    6767    private Component renderer(Component def, OsmPrimitive value) {
    6868        if (def != null && value != null && def instanceof JLabel) {
     69            System.out.println();
     70            System.out.println(value);
     71            System.out.println(getComponentText(value));
    6972            ((JLabel)def).setText(getComponentText(value));
    7073            ((JLabel)def).setIcon(ImageProvider.get(value.getDisplayType()));
    7174            ((JLabel)def).setToolTipText(getComponentToolTipText(value));
  • src/org/openstreetmap/josm/gui/DefaultNameFormatter.java

     
    5656        }
    5757        return instance;
    5858    }
    59    
     59
    6060    /**
    6161     * Registers a format hook. Adds the hook at the first position of the format hooks.
    6262     * (for plugins)
     
    165165            if (name == null) {
    166166                name = node.isNew() ? tr("node") : ""+ node.getId();
    167167            }
    168             name += " (" + node.getCoor().latToString(CoordinateFormat.getDefaultFormat()) + ", " + node.getCoor().lonToString(CoordinateFormat.getDefaultFormat()) + ")";
     168            name += " \u200E(" + node.getCoor().latToString(CoordinateFormat.getDefaultFormat()) + ", " + node.getCoor().lonToString(CoordinateFormat.getDefaultFormat()) + ")";
    169169        }
    170170        name = decorateNameWithId(name, node);
    171171
     
    252252            name += (name.length() > 0) ? " ("+nodes+")" : nodes;
    253253        }
    254254        name = decorateNameWithId(name, way);
    255        
     255
    256256        for (NameFormatterHook hook: formatHooks) {
    257257            String hookResult = hook.checkFormat(way, name);
    258             if (hookResult != null) {
     258            if (hookResult != null)
    259259                return hookResult;
    260             }
    261260        }
    262261
    263262        return name;
     
    310309
    311310        for (NameFormatterHook hook: formatHooks) {
    312311            String hookResult = hook.checkFormat(relation, name);
    313             if (hookResult != null) {
     312            if (hookResult != null)
    314313                return hookResult;
    315             }
    316314        }
    317315
    318316        return name;
     
    407405        if (admin_level != null) {
    408406            name += "["+admin_level+"]";
    409407        }
    410        
     408
    411409        for (NameFormatterHook hook: formatHooks) {
    412410            String hookResult = hook.checkRelationTypeName(relation, name);
    413             if (hookResult != null) {
     411            if (hookResult != null)
    414412                return hookResult;
    415             }
    416413        }
    417414
    418415        return name;
  • src/org/openstreetmap/josm/gui/layer/GpxLayer.java

     
    2929import java.util.Comparator;
    3030import java.util.LinkedList;
    3131import java.util.List;
     32import java.util.concurrent.Callable;
     33import java.util.concurrent.ExecutionException;
    3234import java.util.concurrent.Future;
    3335
    3436import javax.swing.AbstractAction;
     
    466468                                }
    467469                                if (oldWp != null && trkPnt.time > oldWp.time) {
    468470                                    double vel = c.greatCircleDistance(oldWp.getCoor())
    469                                             / (trkPnt.time - oldWp.time);
     471                                    / (trkPnt.time - oldWp.time);
    470472                                    if(vel > maxval) {
    471473                                        maxval = vel;
    472474                                    }
     
    657659                    // skip points that are on the same screenposition
    658660                    if (old != null
    659661                            && (oldA == null || screen.x < oldA.x - delta || screen.x > oldA.x + delta
    660                             || screen.y < oldA.y - delta || screen.y > oldA.y + delta)) {
     662                                    || screen.y < oldA.y - delta || screen.y > oldA.y + delta)) {
    661663                        g.setColor(trkPnt.customColoring);
    662664                        double t = Math.atan2(screen.y - old.y, screen.x - old.x) + Math.PI;
    663665                        g.drawLine(screen.x, screen.y, (int) (screen.x + 10 * Math.cos(t - PHI)),
     
    687689                    // skip points that are on the same screenposition
    688690                    if (old != null
    689691                            && (oldA == null || screen.x < oldA.x - delta || screen.x > oldA.x + delta
    690                             || screen.y < oldA.y - delta || screen.y > oldA.y + delta)) {
     692                                    || screen.y < oldA.y - delta || screen.y > oldA.y + delta)) {
    691693                        g.setColor(trkPnt.customColoring);
    692694                        g.drawLine(screen.x, screen.y, screen.x + dir[trkPnt.dir][0], screen.y
    693695                                + dir[trkPnt.dir][1]);
     
    857859
    858860            msg.add(new JLabel(tr("Download near:")), GBC.eol());
    859861            JList downloadNear = new JList(new String[] { tr("track only"), tr("waypoints only"), tr("track and waypoints") });
    860             int NEAR_TRACK=0;
    861             int NEAR_WAYPOINTS=1;
    862             int NEAR_BOTH=2;
     862            final int NEAR_TRACK=0;
     863            final int NEAR_WAYPOINTS=1;
     864            final int NEAR_BOTH=2;
    863865
    864866            downloadNear.setSelectedIndex(Main.pref.getInteger(PREF_DOWNLOAD_ALONG_TRACK_NEAR, 0));
    865867            msg.add(downloadNear, GBC.eol());
     
    870872                    tr("Download from OSM along this track"),
    871873                    JOptionPane.OK_CANCEL_OPTION,
    872874                    JOptionPane.QUESTION_MESSAGE
    873                     );
     875            );
    874876            switch(ret) {
    875877            case JOptionPane.CANCEL_OPTION:
    876878            case JOptionPane.CLOSED_OPTION:
     
    881883
    882884            Main.pref.putInteger(PREF_DOWNLOAD_ALONG_TRACK_DISTANCE, buffer.getSelectedIndex());
    883885            Main.pref.putInteger(PREF_DOWNLOAD_ALONG_TRACK_AREA, maxRect.getSelectedIndex());
    884             int near = downloadNear.getSelectedIndex();
     886            final int near = downloadNear.getSelectedIndex();
    885887            Main.pref.putInteger(PREF_DOWNLOAD_ALONG_TRACK_NEAR, near);
    886888
    887889            /*
     
    890892             */
    891893            double latsum = 0;
    892894            int latcnt = 0;
     895            // one "tick" takes about 1 ms to compute later on, so use this to guess if a
     896            // please wait dialog should be shown.
     897            int ticks = 0;
    893898
    894899            if (near == NEAR_TRACK || near == NEAR_BOTH) {
    895900                for (GpxTrack trk : data.tracks) {
    896901                    for (GpxTrackSegment segment : trk.getSegments()) {
    897902                        for (WayPoint p : segment.getWayPoints()) {
     903                            ticks++;
    898904                            latsum += p.getCoor().lat();
    899905                            latcnt++;
    900906                        }
     
    912918            double avglat = latsum / latcnt;
    913919            double scale = Math.cos(Math.toRadians(avglat));
    914920
     921
     922
     923            Integer i = buffer.getSelectedIndex();
     924            final int buffer_dist = dist[i < 0 ? 0 : i];
     925            i = maxRect.getSelectedIndex();
     926            double max_area = area[i < 0 ? 0 : i] / 10000.0 / scale;
     927            final double buffer_y = buffer_dist / 100000.0;
     928            final double buffer_x = buffer_y / scale;
     929
    915930            /*
    916931             * Compute buffer zone extents and maximum bounding box size. Note that the maximum we
    917932             * ever offer is a bbox area of 0.002, while the API theoretically supports 0.25, but as
    918933             * soon as you touch any built-up area, that kind of bounding box will download forever
    919934             * and then stop because it has more than 50k nodes.
    920935             */
    921             Integer i = buffer.getSelectedIndex();
    922             int buffer_dist = dist[i < 0 ? 0 : i];
    923             double buffer_y = buffer_dist / 100000.0;
    924             double buffer_x = buffer_y / scale;
    925             i = maxRect.getSelectedIndex();
    926             double max_area = area[i < 0 ? 0 : i] / 10000.0 / scale;
    927             Area a = new Area();
    928             Rectangle2D r = new Rectangle2D.Double();
     936            Callable<Area> calc =  new Callable<Area>() {
     937                public Area call() {
     938                    try {
     939                        Thread.sleep(2000);
     940                    } catch (InterruptedException e) {
     941                        // TODO Auto-generated catch block
     942                        e.printStackTrace();
     943                    }
     944                    Area a = new Area();
     945                    Rectangle2D r = new Rectangle2D.Double();
    929946
    930             /*
    931              * Collect the combined area of all gpx points plus buffer zones around them. We ignore
    932              * points that lie closer to the previous point than the given buffer size because
    933              * otherwise this operation takes ages.
    934              */
    935             LatLon previous = null;
    936             if (near == NEAR_TRACK || near == NEAR_BOTH) {
    937                 for (GpxTrack trk : data.tracks) {
    938                     for (GpxTrackSegment segment : trk.getSegments()) {
    939                         for (WayPoint p : segment.getWayPoints()) {
     947                    /*
     948                     * Collect the combined area of all gpx points plus buffer zones around them. We ignore
     949                     * points that lie closer to the previous point than the given buffer size because
     950                     * otherwise this operation takes ages.
     951                     */
     952                    LatLon previous = null;
     953                    if (near == NEAR_TRACK || near == NEAR_BOTH) {
     954                        for (GpxTrack trk : data.tracks) {
     955                            for (GpxTrackSegment segment : trk.getSegments()) {
     956                                for (WayPoint p : segment.getWayPoints()) {
     957                                    LatLon c = p.getCoor();
     958                                    if (previous == null || c.greatCircleDistance(previous) > buffer_dist) {
     959                                        // we add a buffer around the point.
     960                                        r.setRect(c.lon() - buffer_x, c.lat() - buffer_y, 2 * buffer_x, 2 * buffer_y);
     961                                        a.add(new Area(r));
     962                                        previous = c;
     963                                    }
     964                                }
     965                            }
     966                        }
     967                    }
     968                    if (near == NEAR_WAYPOINTS || near == NEAR_BOTH) {
     969                        for (WayPoint p : data.waypoints) {
    940970                            LatLon c = p.getCoor();
    941971                            if (previous == null || c.greatCircleDistance(previous) > buffer_dist) {
    942972                                // we add a buffer around the point.
     
    946976                            }
    947977                        }
    948978                    }
     979                    return a;
    949980                }
     981            };
     982
     983            Area a;
     984            final PleaseWaitProgressMonitor monitor1 = new PleaseWaitProgressMonitor(tr("Calculating download areas"));
     985            try {
     986                monitor1.beginTask("I have no idea", ticks);
     987                a = Main.worker.submit(calc).get();
     988            } catch (InterruptedException e1) {
     989                e1.printStackTrace();
     990                return;
     991            } catch (ExecutionException e1) {
     992                e1.printStackTrace();
     993                return;
     994            } finally {
     995                //monitor1.close();
    950996            }
    951             if (near == NEAR_WAYPOINTS || near == NEAR_BOTH) {
    952                 for (WayPoint p : data.waypoints) {
    953                     LatLon c = p.getCoor();
    954                     if (previous == null || c.greatCircleDistance(previous) > buffer_dist) {
    955                         // we add a buffer around the point.
    956                         r.setRect(c.lon() - buffer_x, c.lat() - buffer_y, 2 * buffer_x, 2 * buffer_y);
    957                         a.add(new Area(r));
    958                         previous = c;
    959                     }
    960                 }
    961             }
    962997
    963998            /*
    964999             * Area "a" now contains the hull that we would like to download data for. however we
     
    9931028                        tr("Download from OSM along this track"),
    9941029                        JOptionPane.OK_CANCEL_OPTION,
    9951030                        JOptionPane.PLAIN_MESSAGE
    996                         );
     1031                );
    9971032                switch(ret) {
    9981033                case JOptionPane.CANCEL_OPTION:
    9991034                case JOptionPane.CLOSED_OPTION:
     
    10021037                    // continue
    10031038                }
    10041039            }
    1005             final PleaseWaitProgressMonitor monitor = new PleaseWaitProgressMonitor(tr("Download data"));
    1006             final Future<?> future = new DownloadOsmTaskList().download(false, toDownload, monitor);
     1040            final PleaseWaitProgressMonitor monitor2 = new PleaseWaitProgressMonitor(tr("Download data"));
     1041            final Future<?> future = new DownloadOsmTaskList().download(false, toDownload, monitor2);
    10071042            Main.worker.submit(
    10081043                    new Runnable() {
    10091044                        @Override
     
    10141049                                e.printStackTrace();
    10151050                                return;
    10161051                            }
    1017                             monitor.close();
     1052                            monitor2.close();
    10181053                        }
    10191054                    }
    1020                     );
     1055            );
    10211056        }
    10221057    }
    10231058
     
    11001135                    tr("No GPX track available in layer to associate audio with."),
    11011136                    tr("Error"),
    11021137                    JOptionPane.ERROR_MESSAGE
    1103                     );
     1138            );
    11041139            return;
    11051140        }
    11061141
     
    11591194            double duration = AudioUtil.getCalibratedDuration(wavFile);
    11601195            double startTime = lastModified - duration;
    11611196            startTime = firstStartTime + (startTime - firstStartTime)
    1162                     / Main.pref.getDouble("audio.calibration", "1.0" /* default, ratio */);
     1197            / Main.pref.getDouble("audio.calibration", "1.0" /* default, ratio */);
    11631198            WayPoint w1 = null;
    11641199            WayPoint w2 = null;
    11651200
     
    14811516            String msg = tr("<html>The data in the GPX layer ''{0}'' has been downloaded from the server.<br>"
    14821517                    + "Because its way points do not include a timestamp we cannot correlate them with audio data.</html>",
    14831518                    layer.getName()
    1484                     );
     1519            );
    14851520            HelpAwareOptionPane.showOptionDialog(
    14861521                    Main.parent,
    14871522                    msg,
    14881523                    tr("Import not possible"),
    14891524                    JOptionPane.WARNING_MESSAGE,
    14901525                    ht("/Action/ImportAudio#CantImportIntoGpxLayerFromServer")
    1491                     );
     1526            );
    14921527        }
    14931528
    14941529        @Override
     
    15471582                MarkerLayer ml = new MarkerLayer(new GpxData(), tr("Audio markers from {0}", getName()) + names,
    15481583                        getAssociatedFile(), GpxLayer.this);
    15491584                double firstStartTime = sel[0].lastModified() / 1000.0 /* ms -> seconds */
    1550                         - AudioUtil.getCalibratedDuration(sel[0]);
     1585                - AudioUtil.getCalibratedDuration(sel[0]);
    15511586
    15521587                Markers m = new Markers();
    15531588                for (int i = 0; i < sel.length; i++) {
     
    15711606            String msg = tr("<html>The data in the GPX layer ''{0}'' has been downloaded from the server.<br>"
    15721607                    + "Because its way points do not include a timestamp we cannot correlate them with images.</html>",
    15731608                    layer.getName()
    1574                     );
     1609            );
    15751610            HelpAwareOptionPane.showOptionDialog(
    15761611                    Main.parent,
    15771612                    msg,
    15781613                    tr("Import not possible"),
    15791614                    JOptionPane.WARNING_MESSAGE,
    15801615                    ht("/Action/ImportImages#CantImportIntoGpxLayerFromServer")
    1581                     );
     1616            );
    15821617        }
    15831618
    15841619        private void addRecursiveFiles(LinkedList<File> files, File[] sel) {
  • src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java

     
    1818import java.util.Collection;
    1919import java.util.Collections;
    2020import java.util.Comparator;
    21 import java.util.HashMap;
    2221import java.util.HashSet;
    2322import java.util.LinkedList;
    2423import java.util.List;
     
    5857import org.openstreetmap.josm.data.osm.event.DataChangedEvent;
    5958import org.openstreetmap.josm.data.osm.event.DataSetListener;
    6059import org.openstreetmap.josm.data.osm.event.DatasetEventManager;
    61 import org.openstreetmap.josm.data.osm.event.DatasetEventManager.FireMode;
    6260import org.openstreetmap.josm.data.osm.event.NodeMovedEvent;
    6361import org.openstreetmap.josm.data.osm.event.PrimitivesAddedEvent;
    6462import org.openstreetmap.josm.data.osm.event.PrimitivesRemovedEvent;
     
    6664import org.openstreetmap.josm.data.osm.event.SelectionEventManager;
    6765import org.openstreetmap.josm.data.osm.event.TagsChangedEvent;
    6866import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent;
     67import org.openstreetmap.josm.data.osm.event.DatasetEventManager.FireMode;
    6968import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
    7069import org.openstreetmap.josm.gui.DefaultNameFormatter;
    7170import org.openstreetmap.josm.gui.MapView;
    72 import org.openstreetmap.josm.gui.MapView.EditLayerChangeListener;
    7371import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
    7472import org.openstreetmap.josm.gui.SideButton;
     73import org.openstreetmap.josm.gui.MapView.EditLayerChangeListener;
    7574import org.openstreetmap.josm.gui.dialogs.relation.DownloadRelationMemberTask;
    7675import org.openstreetmap.josm.gui.dialogs.relation.RelationEditor;
    7776import org.openstreetmap.josm.gui.layer.OsmDataLayer;
     
    622621            double dist = -1;
    623622            if(this.selection.size() == 1) {
    624623                OsmPrimitive o = this.selection.get(0);
    625                 if(o instanceof Way)
    626                    dist = ((Way)o).getLength();
     624                if(o instanceof Way) {
     625                    dist = ((Way)o).getLength();
     626                }
    627627            }
    628628            Main.map.statusLine.setDist(dist);
    629629        }
  • src/org/openstreetmap/josm/data/osm/WaySegment.java

     
    2929        return way.getNode(lowerIndex + 1);
    3030    }
    3131
     32    /**
     33     * returns this way segment as complete way.
     34     * @return
     35     */
     36    public Way toWay() {
     37        Way w = new Way();
     38        w.addNode(getFirstNode());
     39        w.addNode(getSecondNode());
     40        return w;
     41    }
     42
    3243    @Override public boolean equals(Object o) {
    3344        return o != null && o instanceof WaySegment
    3445            && ((WaySegment) o).way == way
  • src/org/openstreetmap/josm/data/osm/DataSet.java

     
    114114    private Map<PrimitiveId, OsmPrimitive> primitivesMap = allPrimitives.foreignKey(new IdHash());
    115115    private CopyOnWriteArrayList<DataSetListener> listeners = new CopyOnWriteArrayList<DataSetListener>();
    116116
     117    // provide means to highlight map elements that are not osm primitives
     118    private Collection<WaySegment> highlightedVirtualNodes = new LinkedList<WaySegment>();
     119    private Collection<WaySegment> highlightedWaySegments = new LinkedList<WaySegment>();
     120
    117121    // Number of open calls to beginUpdate
    118122    private int updateCount;
    119123    // Events that occurred while dataset was locked but should be fired after write lock is released
     
    430434    }
    431435
    432436    /**
     437     * returns an unmodifiable collection of *WaySegments* whose virtual
     438     * nodes should be highlighted. WaySegements are used to avoid having
     439     * to create a VirtualNode class that wouldn't have much purpose otherwise.
     440     *
     441     * @return unmodifiable collection of WaySegements
     442     */
     443    public Collection<WaySegment> getHighlightedVirtualNodes() {
     444        return Collections.unmodifiableCollection(highlightedVirtualNodes);
     445    }
     446
     447    /**
     448     * returns an unmodifiable collection of WaySegments that should be
     449     * highlighted.
     450     *
     451     * @return unmodifiable collection of WaySegements
     452     */
     453    public Collection<WaySegment> getHighlightedWaySegments() {
     454        return Collections.unmodifiableCollection(highlightedWaySegments);
     455    }
     456
     457    /**
    433458     * Replies an unmodifiable collection of primitives currently selected
    434459     * in this dataset. May be empty, but not null.
    435460     *
     
    507532    }
    508533
    509534    /**
     535     * set what virtual nodes should be highlighted. Requires a Collection of
     536     * *WaySegements* to avoid a VirtualNode class that wouldn't have much use
     537     * otherwise.
     538     * @param Collection of waySegments
     539     */
     540    public void setHighlightedVirtualNodes(Collection<WaySegment> waySegments) {
     541        if(highlightedVirtualNodes.isEmpty() && waySegments.isEmpty())
     542            return;
     543
     544        highlightedVirtualNodes = waySegments;
     545        // can't use fireHighlightingChanged because it requires an OsmPrimitive
     546        highlightUpdateCount++;
     547    }
     548
     549    /**
     550     * set what virtual ways should be highlighted.
     551     * @param Collection of waySegments
     552     */
     553    public void setHighlightedWaySegments(Collection<WaySegment> waySegments) {
     554        if(highlightedWaySegments.isEmpty() && waySegments.isEmpty())
     555            return;
     556
     557        highlightedWaySegments = waySegments;
     558        // can't use fireHighlightingChanged because it requires an OsmPrimitive
     559        highlightUpdateCount++;
     560    }
     561
     562    /**
    510563     * Sets the current selection to the primitives in <code>selection</code>.
    511564     * Notifies all {@see SelectionChangedListener} if <code>fireSelectionChangeEvent</code> is true.
    512565     *
     
    592645    }
    593646
    594647    /**
     648     * clear all highlights of virtual nodes
     649     */
     650    public void clearHighlightedVirtualNodes() {
     651        setHighlightedVirtualNodes(new ArrayList<WaySegment>());
     652    }
     653
     654    /**
     655     * clear all highlights of way segments
     656     */
     657    public void clearHighlightedWaySegments() {
     658        setHighlightedWaySegments(new ArrayList<WaySegment>());
     659    }
     660
     661    /**
    595662     * Remove the selection from every value in the collection.
    596663     * @param list The collection to remove the selection from.
    597664     */
  • src/org/openstreetmap/josm/data/osm/visitor/paint/MapPainter.java

     
    2020import java.awt.geom.GeneralPath;
    2121import java.awt.geom.Rectangle2D;
    2222import java.awt.image.BufferedImage;
     23import java.util.ArrayList;
    2324import java.util.Arrays;
    2425import java.util.Collection;
    2526import java.util.Iterator;
     
    3435import org.openstreetmap.josm.data.osm.Relation;
    3536import org.openstreetmap.josm.data.osm.RelationMember;
    3637import org.openstreetmap.josm.data.osm.Way;
     38import org.openstreetmap.josm.data.osm.WaySegment;
    3739import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon;
    3840import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.PolyData;
    3941import org.openstreetmap.josm.gui.NavigatableComponent;
     
    4143import org.openstreetmap.josm.gui.mappaint.BoxTextElemStyle.HorizontalTextAlignment;
    4244import org.openstreetmap.josm.gui.mappaint.BoxTextElemStyle.VerticalTextAlignment;
    4345import org.openstreetmap.josm.gui.mappaint.NodeElemStyle;
     46import org.openstreetmap.josm.gui.mappaint.TextElement;
    4447import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.Symbol;
    45 import org.openstreetmap.josm.gui.mappaint.TextElement;
    4648import org.openstreetmap.josm.tools.ImageProvider;
    4749import org.openstreetmap.josm.tools.Pair;
    4850
     
    5254    private final NavigatableComponent nc;
    5355    private final boolean inactive;
    5456    private final MapPaintSettings settings;
     57    private final Collection<WaySegment> highlightWaySegments;
    5558
    5659    private final boolean useStrokes;
    5760    private final boolean showNames;
     
    6366    private final Color selectedColor;
    6467    private final Color relationSelectedColor;
    6568    private final Color nodeColor;
     69    private final Color highlightColor;
    6670    private final Color backgroundColor;
    6771
    6872    private final Font orderFont;
     
    8084
    8185    public MapPainter(MapPaintSettings settings, Graphics2D g,
    8286            boolean inactive, NavigatableComponent nc, boolean virtual,
    83             double circum, boolean leftHandTraffic){
     87            double circum, boolean leftHandTraffic,
     88            Collection<WaySegment> highlightWaySegments){
    8489        this.settings = settings;
    8590        this.g = g;
    8691        this.inactive = inactive;
    8792        this.nc = nc;
     93        this.highlightWaySegments = highlightWaySegments;
    8894        this.useStrokes = settings.getUseStrokesDistance() > circum;
    8995        this.showNames = settings.getShowNamesDistance() > circum;
    9096        this.showIcons = settings.getShowIconsDistance() > circum;
     
    95101        this.selectedColor = PaintColors.SELECTED.get();
    96102        this.relationSelectedColor = PaintColors.RELATIONSELECTED.get();
    97103        this.nodeColor = PaintColors.NODE.get();
     104        this.highlightColor = PaintColors.HIGHLIGHT.get();
    98105        this.backgroundColor = PaintColors.getBackgroundColor();
    99106
    100107        this.orderFont = new Font(Main.pref.get("mappaint.font", "Helvetica"), Font.PLAIN, Main.pref.getInteger("mappaint.fontsize", 8));
     
    130137        boolean initialMoveToNeeded = true;
    131138        List<Node> wayNodes = way.getNodes();
    132139        if (wayNodes.size() < 2) return;
    133        
    134         Iterator<Point> it = new OffsetIterator(way.getNodes(), offset);
     140
     141        Collection<Integer> segmentsToHighlight = new ArrayList<Integer>();
     142        // only highlight the segment if the way itself is not highlighted
     143        if(!way.isHighlighted()) {
     144            for(WaySegment ws : highlightWaySegments) {
     145                if(ws.way != way || ws.lowerIndex < offset) {
     146                    continue;
     147                }
     148                segmentsToHighlight.add(ws.lowerIndex+1);
     149            }
     150        }
     151        GeneralPath highlightSegs = segmentsToHighlight.isEmpty() ? null : new GeneralPath();
     152
     153        Iterator<Point> it = new OffsetIterator(wayNodes, offset);
    135154        while (it.hasNext()) {
    136155            Point p = it.next();
    137156            if (lastPoint != null) {
     
    153172                        path.moveTo(p1.x, p1.y);
    154173                    }
    155174                    p2 = clip.getP2();
    156                     path.lineTo(p2.x, p2.y);
     175                    if(segmentsToHighlight.contains(offset)) {
     176                        path.moveTo(p2.x, p2.y);
     177                        // it is assumed that highlighted segments are not
     178                        // next to each other.
     179                        highlightSegs.moveTo(p1.x, p1.y);
     180                        highlightSegs.lineTo(p2.x, p2.y);
     181                    } else {
     182                        path.lineTo(p2.x, p2.y);
     183                    }
    157184
    158185                    /* draw arrow */
    159186                    if (showHeadArrowOnly ? !it.hasNext() : showOrientation) {
     
    207234                }
    208235            }
    209236            lastPoint = p;
     237            // have the offset variable point to the current segment
     238            offset++;
    210239        }
    211         displaySegments(path, orientationArrows, onewayArrows, onewayArrowsCasing, color, line, dashes, dashedColor);
     240        displaySegments(path, orientationArrows, onewayArrows, onewayArrowsCasing, highlightSegs, color, line, dashes, dashedColor);
    212241    }
    213242
    214243    /**
     
    220249     * perfect way, but it is should not throw an exception.
    221250     */
    222251    public class OffsetIterator implements Iterator<Point> {
    223        
     252
    224253        private List<Node> nodes;
    225254        private int offset;
    226255        private int idx;
    227        
     256
    228257        private Point prev = null;
    229258        /* 'prev0' is a point that has distance 'offset' from 'prev' and the
    230259         * line from 'prev' to 'prev0' is perpendicular to the way segment from
     
    237266            this.offset = offset;
    238267            idx = 0;
    239268        }
    240        
     269
    241270        @Override
    242271        public boolean hasNext() {
    243272            return idx < nodes.size();
     
    246275        @Override
    247276        public Point next() {
    248277            if (offset == 0) return nc.getPoint(nodes.get(idx++));
    249            
     278
    250279            Point current = nc.getPoint(nodes.get(idx));
    251            
     280
    252281            if (idx == nodes.size() - 1) {
    253282                ++idx;
    254283                return new Point(x_prev0 + current.x - prev.x, y_prev0 + current.y - prev.y);
     
    276305            } else {
    277306                int dx_prev = current.x - prev.x;
    278307                int dy_prev = current.y - prev.y;
    279                
     308
    280309                // determine intersection of the lines parallel to the two
    281310                // segments
    282311                int det = dx_next*dy_prev - dx_prev*dy_next;
    283                
     312
    284313                if (det == 0) {
    285314                    ++idx;
    286315                    prev = current;
     
    306335            throw new UnsupportedOperationException();
    307336        }
    308337    }
    309    
    310     private void displaySegments(GeneralPath path, GeneralPath orientationArrows, GeneralPath onewayArrows, GeneralPath onewayArrowsCasing,
    311             Color color, BasicStroke line, BasicStroke dashes, Color dashedColor) {
     338
     339    private void displaySegments(GeneralPath path, GeneralPath orientationArrows, GeneralPath onewayArrows,
     340            GeneralPath onewayArrowsCasing, GeneralPath highlightedSegments, Color color, BasicStroke line,
     341            BasicStroke dashes, Color dashedColor) {
    312342        g.setColor(inactive ? inactiveColor : color);
    313343        if (useStrokes) {
    314344            g.setStroke(line);
    315345        }
    316346        g.draw(path);
    317347
     348        if(highlightedSegments != null) {
     349            g.setColor(highlightColor);
     350            g.draw(highlightedSegments);
     351        }
     352
    318353        if(!inactive && useStrokes && dashes != null) {
    319354            g.setColor(dashedColor);
    320355            g.setStroke(dashes);
    321356            g.draw(path);
     357            if(highlightedSegments != null) {
     358                g.draw(highlightedSegments);
     359            }
    322360        }
    323361
    324362        if (orientationArrows != null) {
     
    9971035                pVia, vx, vx2, vy, vy2, iconAngle, r.isSelected());
    9981036    }
    9991037
    1000     public void drawVirtualNodes(Collection<Way> ways) {
    1001 
    1002         if (virtualNodeSize != 0) {
    1003             GeneralPath path = new GeneralPath();
    1004             for (Way osm: ways){
    1005                 if (osm.isUsable() && !osm.isDisabled()) {
    1006                     visitVirtual(path, osm);
    1007                 }
     1038    public void drawVirtualNodes(Collection<Way> ways, Collection<WaySegment> highlightVirtualNodes) {
     1039        if (virtualNodeSize == 0)
     1040            return;
     1041        // print normal virtual nodes
     1042        GeneralPath path = new GeneralPath();
     1043        for (Way osm: ways){
     1044            if (osm.isUsable() && !osm.isDisabled()) {
     1045                visitVirtual(path, osm);
    10081046            }
    1009             g.setColor(nodeColor);
    1010             g.draw(path);
    10111047        }
     1048        g.setColor(nodeColor);
     1049        g.draw(path);
     1050        // print highlighted virtual nodes. Since only the color changes, simply
     1051        // drawing them over the existing ones works fine (at least in their current
     1052        // simple style)
     1053        path = new GeneralPath();
     1054        for (WaySegment wseg: highlightVirtualNodes){
     1055            if (wseg.way.isUsable() && !wseg.way.isDisabled()) {
     1056                visitVirtual(path, wseg.toWay());
     1057            }
     1058        }
     1059        g.setColor(highlightColor);
     1060        g.draw(path);
    10121061    }
    10131062
    10141063    public void visitVirtual(GeneralPath path, Way w) {
  • src/org/openstreetmap/josm/data/osm/visitor/paint/WireframeMapRenderer.java

     
    2424import org.openstreetmap.josm.data.osm.Relation;
    2525import org.openstreetmap.josm.data.osm.RelationMember;
    2626import org.openstreetmap.josm.data.osm.Way;
     27import org.openstreetmap.josm.data.osm.WaySegment;
    2728import org.openstreetmap.josm.data.osm.visitor.Visitor;
    2829import org.openstreetmap.josm.gui.NavigatableComponent;
    2930
     
    127128    }
    128129
    129130    DataSet ds;
     131
    130132    public void render(DataSet data, boolean virtual, Bounds bounds) {
    131133        BBox bbox = new BBox(bounds);
    132134        this.ds = data;
     
    167169                osm.visit(this);
    168170            }
    169171        }
    170         drawVirtualNodes(data.searchWays(bbox));
     172        drawVirtualNodes(data.searchWays(bbox), data.getHighlightedVirtualNodes());
     173
     174        // draw highlighted way segments over the already drawn ways. Otherwise each
     175        // way would have to be checked if it contains a way segment to highlight when
     176        // in most of the cases there won't be more than one segment. Since the wireframe
     177        // renderer does not feature any transparency there should be no visual difference.
     178        for(final WaySegment wseg : data.getHighlightedWaySegments()) {
     179            drawSegment(nc.getPoint(wseg.getFirstNode()), nc.getPoint(wseg.getSecondNode()), highlightColor, false);
     180        }
     181        displaySegments();
    171182    }
    172183
    173184    private static final int max(int a, int b, int c, int d) {
     
    227238        return (xd+yd > space);
    228239    }
    229240
    230     public void drawVirtualNodes(Collection<Way> ways) {
    231 
    232         if (virtualNodeSize != 0) {
    233             GeneralPath path = new GeneralPath();
    234             for (Way osm: ways){
    235                 if (osm.isUsable() && !osm.isDisabledAndHidden() && !osm.isDisabled()) {
    236                     visitVirtual(path, osm);
    237                 }
     241    public void drawVirtualNodes(Collection<Way> ways, Collection<WaySegment> highlightVirtualNodes) {
     242        if (virtualNodeSize == 0)
     243            return;
     244        // print normal virtual nodes
     245        GeneralPath path = new GeneralPath();
     246        for (Way osm : ways) {
     247            if (osm.isUsable() && !osm.isDisabledAndHidden() && !osm.isDisabled()) {
     248                visitVirtual(path, osm);
    238249            }
    239             g.setColor(nodeColor);
    240             g.draw(path);
    241250        }
     251        g.setColor(nodeColor);
     252        g.draw(path);
     253        // print highlighted virtual nodes. Since only the color changes, simply
     254        // drawing them over the existing ones works fine (at least in their current
     255        // simple style)
     256        path = new GeneralPath();
     257        for (WaySegment wseg: highlightVirtualNodes){
     258            if (wseg.way.isUsable() && !wseg.way.isDisabled()) {
     259                visitVirtual(path, wseg.toWay());
     260            }
     261        }
     262        g.setColor(highlightColor);
     263        g.draw(path);
    242264    }
    243265
    244266    public void visitVirtual(GeneralPath path, Way w) {
     
    308330
    309331    private Stroke relatedWayStroke = new BasicStroke(
    310332            4, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL);
     333
    311334    public void visit(Relation r) {
    312335        if (r.isIncomplete()) return;
    313336
     
    428451                final double sy = l * (p1.y - p2.y);
    429452
    430453                path.lineTo (p2.x + (int) Math.round(cosPHI * sx - sinPHI * sy), p2.y + (int) Math.round(sinPHI * sx + cosPHI * sy));
    431                 path.moveTo (p2.x + (int) Math.round(cosPHI * sx + sinPHI * sy), p2.y + (int) Math.round(- sinPHI * sx + cosPHI * sy));
     454                path.moveTo (p2.x + (int) Math.round(cosPHI * sx + sinPHI * sy), p2.y + (int) Math.round(-sinPHI * sx + cosPHI * sy));
    432455                path.lineTo(p2.x, p2.y);
    433456            }
    434457        }
  • src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java

     
    44import java.awt.Graphics2D;
    55import java.awt.RenderingHints;
    66import java.util.ArrayList;
     7import java.util.Collection;
    78import java.util.Collections;
    89import java.util.List;
    910
     
    1516import org.openstreetmap.josm.data.osm.OsmPrimitive;
    1617import org.openstreetmap.josm.data.osm.Relation;
    1718import org.openstreetmap.josm.data.osm.Way;
     19import org.openstreetmap.josm.data.osm.WaySegment;
    1820import org.openstreetmap.josm.gui.NavigatableComponent;
    1921import org.openstreetmap.josm.gui.mappaint.AreaElemStyle;
    2022import org.openstreetmap.josm.gui.mappaint.ElemStyle;
     
    219221                Main.pref.getBoolean("mappaint.use-antialiasing", true) ?
    220222                        RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF);
    221223
    222         this.painter = new MapPainter(paintSettings, g, isInactiveMode, nc, renderVirtualNodes, circum, leftHandTraffic);
     224        Collection<WaySegment> hws = data.getHighlightedWaySegments();
    223225
     226        this.painter = new MapPainter(paintSettings, g, isInactiveMode, nc, renderVirtualNodes, circum, leftHandTraffic, hws);
     227
    224228        StyleCollector sc = new StyleCollector(drawArea, drawMultipolygon, drawRestriction);
    225229        collectNodeStyles(data, sc, bbox);
    226230        collectWayStyles(data, sc, bbox);
     
    228232        //long phase1 = System.currentTimeMillis();
    229233        sc.drawAll();
    230234        sc = null;
    231         painter.drawVirtualNodes(data.searchWays(bbox));
     235        painter.drawVirtualNodes(data.searchWays(bbox), data.getHighlightedVirtualNodes());
    232236
    233237        //long now = System.currentTimeMillis();
    234238        //System.err.println(String.format("PAINTING TOOK %d [PHASE1 took %d] (at scale %s)", now - start, phase1 - start, circum));
  • src/org/openstreetmap/josm/command/DeleteCommand.java

     
    233233
    234234        if (parents.isEmpty())
    235235            return null;
    236         if (!checkAndConfirmOutlyingDeletes(layer,parents) && !silent)
     236        if (!silent && !checkAndConfirmOutlyingDeletes(layer,parents))
    237237            return null;
    238238        return new DeleteCommand(layer,parents);
    239239    }
     
    387387    }
    388388
    389389    public static Command deleteWaySegment(OsmDataLayer layer, WaySegment ws) {
     390        if (ws.way.getNodesCount() < 3)
     391            return delete(layer, Collections.singleton(ws.way), false);
     392
    390393        if (ws.way.firstNode() == ws.way.lastNode()) {
    391394            // If the way is circular (first and last nodes are the same),
    392395            // the way shouldn't be splitted