Index: src/org/openstreetmap/josm/actions/mapmode/DrawAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/DrawAction.java	(revision 5093)
+++ src/org/openstreetmap/josm/actions/mapmode/DrawAction.java	(working copy)
@@ -1,19 +1,16 @@
 // License: GPL. See LICENSE file for details.
 package org.openstreetmap.josm.actions.mapmode;

-import javax.swing.JCheckBoxMenuItem;
-import javax.swing.JMenuItem;
+import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
+import static org.openstreetmap.josm.tools.I18n.marktr;
 import static org.openstreetmap.josm.tools.I18n.tr;
 import static org.openstreetmap.josm.tools.I18n.trn;
-import static org.openstreetmap.josm.tools.I18n.marktr;
-import static org.openstreetmap.josm.gui.help.HelpUtil.ht;

 import java.awt.AWTEvent;
 import java.awt.BasicStroke;
 import java.awt.Color;
 import java.awt.Cursor;
 import java.awt.Graphics2D;
-import java.awt.MenuItem;
 import java.awt.Point;
 import java.awt.Stroke;
 import java.awt.Toolkit;
@@ -37,7 +34,10 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
+
 import javax.swing.AbstractAction;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JMenuItem;
 import javax.swing.JOptionPane;
 import javax.swing.JPopupMenu;
 import javax.swing.Timer;
@@ -65,11 +65,11 @@
 import org.openstreetmap.josm.gui.layer.MapViewPaintable;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
+import org.openstreetmap.josm.tools.Geometry;
 import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.Pair;
 import org.openstreetmap.josm.tools.Shortcut;
 import org.openstreetmap.josm.tools.Utils;
-import org.openstreetmap.josm.tools.Geometry;

 /**
  * Mapmode to add nodes, create and extend ways.
@@ -83,7 +83,14 @@

     private Node mouseOnExistingNode;
     private Set<Way> mouseOnExistingWays = new HashSet<Way>();
+    // old highlights store which primitives are currently highlighted. This
+    // is true, even if target highlighting is disabled since the status bar
+    // derives its information from this list as well.
     private Set<OsmPrimitive> oldHighlights = new HashSet<OsmPrimitive>();
+    // new highlights contains a list of primitives that should be highlighted
+    // but haven’t been so far. The idea is to compare old and new and only
+    // repaint if there are changes.
+    private Set<OsmPrimitive> newHighlights = new HashSet<OsmPrimitive>();
     private boolean drawHelperLine;
     private boolean wayIsFinished = false;
     private boolean drawTargetHighlight;
@@ -131,21 +138,45 @@
      */
     private void redrawIfRequired() {
         updateStatusLine();
+        // repaint required if the helper line is active.
+        boolean needsRepaint = drawHelperLine && !wayIsFinished;
+        // move newHighlights to oldHighlights; only update changed primitives
+        for(OsmPrimitive x : newHighlights) {
+            if(oldHighlights.contains(x)) {
+                continue;
+            }
+            needsRepaint = true;
+            x.setHighlighted(true);
+        }
+        oldHighlights.removeAll(newHighlights);
+        for(OsmPrimitive x : oldHighlights) {
+            x.setHighlighted(false);
+            needsRepaint = true;
+        }
+        oldHighlights = newHighlights;
+
         if ((!drawHelperLine || wayIsFinished) && !drawTargetHighlight)
             return;
+
         // update selection to reflect which way being modified
         if (currentBaseNode != null && getCurrentDataSet().getSelected().isEmpty() == false) {
             Way continueFrom = getWayForNode(currentBaseNode);
-            if (alt && continueFrom != null) {
+            if (alt && continueFrom != null && (!currentBaseNode.isSelected() || continueFrom.isSelected())) {
                 getCurrentDataSet().beginUpdate(); // to prevent the selection listener to screw around with the state
                 getCurrentDataSet().addSelected(currentBaseNode);
                 getCurrentDataSet().clearSelection(continueFrom);
                 getCurrentDataSet().endUpdate();
-            } else if (!alt && continueFrom != null) {
+                needsRepaint = true;
+            } else if (!alt && continueFrom != null && !continueFrom.isSelected()) {
                 getCurrentDataSet().addSelected(continueFrom);
+                needsRepaint = true;
             }
         }
-        Main.map.mapView.repaint();
+
+        //System.out.println("redrawIfrequired near the end: " + needsRepaint);
+        if(needsRepaint) {
+            Main.map.mapView.repaint();
+        }
     }

     @Override
@@ -201,6 +232,7 @@
         Main.map.statusLine.getAnglePanel().removeMouseListener(snapHelper.anglePopupListener);

         removeHighlighting();
+        redrawIfRequired();
         try {
             Toolkit.getDefaultToolkit().removeAWTEventListener(this);
         } catch (SecurityException ex) {
@@ -227,7 +259,6 @@
         updateKeyModifiers((InputEvent) event);
         computeHelperLine();
         addHighlighting();
-        redrawIfRequired();
     }

     // events for crossplatform key holding processing
@@ -277,7 +308,6 @@
             return;
         computeHelperLine();
         addHighlighting();
-        redrawIfRequired();
     }

     private void tryAgain(MouseEvent e) {
@@ -706,7 +736,6 @@

         computeHelperLine();
         addHighlighting();
-        redrawIfRequired();
     }

     /**
@@ -723,9 +752,6 @@
             return;
         }

-        double distance = -1;
-        double angle = -1;
-
         Collection<OsmPrimitive> selection = getCurrentDataSet().getSelected();

         Node currentMouseNode = null;
@@ -758,18 +784,20 @@
         }

         determineCurrentBaseNodeAndPreviousNode(selection);
-        if (previousNode == null) snapHelper.noSnapNow();
+        if (previousNode == null) {
+            snapHelper.noSnapNow();
+        }

         if (currentBaseNode == null || currentBaseNode == currentMouseNode)
             return; // Don't create zero length way segments.


         double curHdg = Math.toDegrees(currentBaseNode.getEastNorth()
-            .heading(currentMouseEastNorth));
+                .heading(currentMouseEastNorth));
         double baseHdg=-1;
         if (previousNode != null) {
             baseHdg =  Math.toDegrees(previousNode.getEastNorth()
-                .heading(currentBaseNode.getEastNorth()));
+                    .heading(currentBaseNode.getEastNorth()));
         }

         snapHelper.checkAngleSnapping(currentMouseEastNorth,baseHdg, curHdg);
@@ -822,12 +850,15 @@
         } else if (!selectedWay.isDeleted()) { // fix #7118
             if (selectedNode == selectedWay.getNode(0)){
                 currentBaseNode = selectedNode;
-                if (selectedWay.getNodesCount()>1) previousNode = selectedWay.getNode(1);
+                if (selectedWay.getNodesCount()>1) {
+                    previousNode = selectedWay.getNode(1);
+                }
             }
             if (selectedNode == selectedWay.lastNode()) {
                 currentBaseNode = selectedNode;
-                if (selectedWay.getNodesCount()>1)
+                if (selectedWay.getNodesCount()>1) {
                     previousNode = selectedWay.getNode(selectedWay.getNodesCount()-2);
+                }
             }
         }
     }
@@ -966,18 +997,29 @@
         EastNorth p2=ws.getSecondNode().getEastNorth();
         if (snapHelper.dir2!=null && currentBaseNode!=null) {
             EastNorth xPoint = Geometry.getSegmentSegmentIntersection(p1, p2, snapHelper.dir2, currentBaseNode.getEastNorth());
-            if (xPoint!=null) n.setEastNorth(xPoint);
+            if (xPoint!=null) {
+                n.setEastNorth(xPoint);
+            }
         }
     }
     /**
      * Takes the data from computeHelperLine to determine which ways/nodes should be highlighted
-     * (if feature enabled). Also sets the target cursor if appropriate.
+     * (if feature enabled). Also sets the target cursor if appropriate. It adds the to-be-
+     * highlighted primitives to newHighlights but does not actually highlight them. This work is
+     * done in redrawIfRequired. This means, calling addHighlighting() without redrawIfRequired()
+     * will leave the data in an inconsistent state.
+     *
+     * The status bar derives its information from oldHighlights, so in order to update the status
+     * bar both addHighlighting() and repaintIfRequired() are needed, since former fills newHighlights
+     * and latter processes them into oldHighlights.
      */
     private void addHighlighting() {
-        removeHighlighting();
+        newHighlights = new HashSet<OsmPrimitive>();
+
         // if ctrl key is held ("no join"), don't highlight anything
         if (ctrl) {
             Main.map.mapView.setNewCursor(cursor, this);
+            redrawIfRequired();
             return;
         }

@@ -989,60 +1031,50 @@

         if (mouseOnExistingNode != null) {
             Main.map.mapView.setNewCursor(cursorJoinNode, this);
-            // We also need this list for the statusbar help text
-            oldHighlights.add(mouseOnExistingNode);
-            if(drawTargetHighlight) {
-                mouseOnExistingNode.setHighlighted(true);
-        }
+            newHighlights.add(mouseOnExistingNode);
+            redrawIfRequired();
             return;
         }

         // Insert the node into all the nearby way segments
         if (mouseOnExistingWays.size() == 0) {
             Main.map.mapView.setNewCursor(cursor, this);
+            redrawIfRequired();
             return;
         }

         Main.map.mapView.setNewCursor(cursorJoinWay, this);
-
-        // We also need this list for the statusbar help text
-        oldHighlights.addAll(mouseOnExistingWays);
-        if (!drawTargetHighlight) return;
-        for (Way w : mouseOnExistingWays) {
-            w.setHighlighted(true);
-        }
+        newHighlights.addAll(mouseOnExistingWays);
+        redrawIfRequired();
     }

     /**
-     * Removes target highlighting from primitives
+     * Removes target highlighting from primitives.
      */
     private void removeHighlighting() {
-        for(OsmPrimitive prim : oldHighlights) {
-            prim.setHighlighted(false);
-        }
-        oldHighlights = new HashSet<OsmPrimitive>();
+        newHighlights = new HashSet<OsmPrimitive>();
+        redrawIfRequired();
     }

     public void paint(Graphics2D g, MapView mv, Bounds box) {
         // sanity checks
         if (Main.map.mapView == null || mousePos == null
-        // don't draw line if we don't know where from or where to
-        || currentBaseNode == null || currentMouseEastNorth == null
-        // don't draw line if mouse is outside window
-        || !Main.map.mapView.getBounds().contains(mousePos))
+                // don't draw line if we don't know where from or where to
+                || currentBaseNode == null || currentMouseEastNorth == null
+                // don't draw line if mouse is outside window
+                || !Main.map.mapView.getBounds().contains(mousePos))
             return;

         Graphics2D g2 = g;
         snapHelper.drawIfNeeded(g2,mv);
         if (!drawHelperLine || wayIsFinished || shift)
-          return;
+            return;

         if (!snapHelper.isActive()) { // else use color and stoke from  snapHelper.draw
             g2.setColor(selectedColor);
             g2.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
-        } else if (!snapHelper.drawConstructionGeometry) {
+        } else if (!snapHelper.drawConstructionGeometry)
             return;
-        }
         GeneralPath b = new GeneralPath();
         Point p1=mv.getPoint(currentBaseNode);
         Point p2=mv.getPoint(currentMouseEastNorth);
@@ -1168,16 +1200,18 @@
                         n=(Node) p; // found one node
                         wayIsFinished=false;
                     }  else {
-                    // if more than 1 node were affected by previous command,
-                    // we have no way to continue, so we forget about found node
+                        // if more than 1 node were affected by previous command,
+                        // we have no way to continue, so we forget about found node
                         n=null;
                         break;
                     }
                 }
             }
             // select last added node - maybe we will continue drawing from it
-            if (n!=null) getCurrentDataSet().addSelected(n);
-       }
+            if (n!=null) {
+                getCurrentDataSet().addSelected(n);
+            }
+        }
     }

     private class SnapHelper {
@@ -1225,7 +1259,7 @@
             fixed=false; absoluteFix=false;

             Collection<String> angles = Main.pref.getCollection("draw.anglesnap.angles",
-                Arrays.asList("0","30","45","60","90","120","135","150","180"));
+                    Arrays.asList("0","30","45","60","90","120","135","150","180"));

             snapAngles = new double[2*angles.size()];
             int i=0;
@@ -1250,12 +1284,12 @@
             snapHelperColor = Main.pref.getColor(marktr("draw angle snap"), Color.ORANGE);

             highlightColor = Main.pref.getColor(marktr("draw angle snap highlight"),
-                new Color(Color.ORANGE.getRed(),Color.ORANGE.getGreen(),Color.ORANGE.getBlue(),128));
+                    new Color(Color.ORANGE.getRed(),Color.ORANGE.getGreen(),Color.ORANGE.getBlue(),128));
             highlightStroke = new BasicStroke(10, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);

             float dash1[] = { 4.0f };
             helperStroke = new BasicStroke(1.0f, BasicStroke.CAP_BUTT,
-                BasicStroke.JOIN_MITER, 10.0f, dash1, 0.0f);
+                    BasicStroke.JOIN_MITER, 10.0f, dash1, 0.0f);
         }

         public void saveAngles(String ... angles) {
@@ -1336,8 +1370,12 @@

             if (snapOn && (activeBaseHeading>=0)) {
                 angle = curHeading - activeBaseHeading;
-                if (angle < 0) angle+=360;
-                if (angle > 360) angle=0;
+                if (angle < 0) {
+                    angle+=360;
+                }
+                if (angle > 360) {
+                    angle=0;
+                }

                 double nearestAngle;
                 if (fixed) {
@@ -1380,8 +1418,12 @@

             if (baseHeading >=0 ) { // there is previous line segment with some heading
                 angle = hdg - baseHeading;
-                if (angle < 0) angle+=360;
-                if (angle > 360) angle=0;
+                if (angle < 0) {
+                    angle+=360;
+                }
+                if (angle > 360) {
+                    angle=0;
+                }
             }
             showStatusInfo(angle, hdg, distance);
         }
@@ -1456,8 +1498,12 @@

             double hdg = segmentPoint1.heading(segmentPoint2);
             hdg=Math.toDegrees(hdg);
-            if (hdg<0) hdg+=360;
-            if (hdg>360) hdg-=360;
+            if (hdg<0) {
+                hdg+=360;
+            }
+            if (hdg>360) {
+                hdg-=360;
+            }
             //fixed=true;
             //absoluteFix=true;
             customBaseHeading=hdg;
@@ -1466,8 +1512,9 @@
         private void nextSnapMode() {
             if (snapOn) {
                 // turn off snapping if we are in fixed mode or no actile snapping line exist
-                if (fixed || !active) { snapOn=false; unsetFixedMode(); }
-                else setFixedMode();
+                if (fixed || !active) { snapOn=false; unsetFixedMode(); } else {
+                    setFixedMode();
+                }
             } else {
                 snapOn=true;
                 unsetFixedMode();
@@ -1521,8 +1568,9 @@
                     bestAngle=snapAngles[i];
                 }
             }
-            if (Math.abs(bestAngle-360) < 1e-3)
+            if (Math.abs(bestAngle-360) < 1e-3) {
                 bestAngle=0;
+            }
             return bestAngle;
         }

@@ -1535,10 +1583,11 @@
         }

         private void unFixOrTurnOff() {
-            if (absoluteFix)
+            if (absoluteFix) {
                 unsetFixedMode();
-            else
+            } else {
                 toggleSnapping();
+            }
         }

         MouseListener anglePopupListener = new PopupMenuLauncher( new JPopupMenu() {
@@ -1609,13 +1658,15 @@
     private class SnapChangeAction extends JosmAction {
         public SnapChangeAction() {
             super(tr("Angle snapping"), "anglesnap",
-                tr("Switch angle snapping mode while drawing"), null, false);
+                    tr("Switch angle snapping mode while drawing"), null, false);
             putValue("help", ht("/Action/Draw/AngleSnap"));
         }

         @Override
         public void actionPerformed(ActionEvent e) {
-               if (snapHelper!=null) snapHelper.toggleSnapping();
+            if (snapHelper!=null) {
+                snapHelper.toggleSnapping();
+            }
         }
     }
 }
