Ticket #7503: same_thing_for_draw_action.patch

File same_thing_for_draw_action.patch, 16.9 KB (added by xeen, 14 years ago)

This patch brings the only-repaint-on-highlight-change to the draw action. Please ignore eclipse enforcing the coding style. The patch is only useful if the rubber band helper line is not being drawn; otherwise the repaints are required to paint the helper line. Thus it would only reduce CPU usage in a helper-off target-on scenario (but not improve performance, see above). I doubt this is a common case. I’ll look into painting the helper line onto its own component, so no complete redraws are required.

  • src/org/openstreetmap/josm/actions/mapmode/DrawAction.java

     
    11// License: GPL. See LICENSE file for details.
    22package org.openstreetmap.josm.actions.mapmode;
    33
    4 import javax.swing.JCheckBoxMenuItem;
    5 import javax.swing.JMenuItem;
     4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
     5import static org.openstreetmap.josm.tools.I18n.marktr;
    66import static org.openstreetmap.josm.tools.I18n.tr;
    77import static org.openstreetmap.josm.tools.I18n.trn;
    8 import static org.openstreetmap.josm.tools.I18n.marktr;
    9 import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
    108
    119import java.awt.AWTEvent;
    1210import java.awt.BasicStroke;
    1311import java.awt.Color;
    1412import java.awt.Cursor;
    1513import java.awt.Graphics2D;
    16 import java.awt.MenuItem;
    1714import java.awt.Point;
    1815import java.awt.Stroke;
    1916import java.awt.Toolkit;
     
    3734import java.util.Map;
    3835import java.util.Set;
    3936import java.util.TreeSet;
     37
    4038import javax.swing.AbstractAction;
     39import javax.swing.JCheckBoxMenuItem;
     40import javax.swing.JMenuItem;
    4141import javax.swing.JOptionPane;
    4242import javax.swing.JPopupMenu;
    4343import javax.swing.Timer;
     
    6565import org.openstreetmap.josm.gui.layer.MapViewPaintable;
    6666import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    6767import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
     68import org.openstreetmap.josm.tools.Geometry;
    6869import org.openstreetmap.josm.tools.ImageProvider;
    6970import org.openstreetmap.josm.tools.Pair;
    7071import org.openstreetmap.josm.tools.Shortcut;
    7172import org.openstreetmap.josm.tools.Utils;
    72 import org.openstreetmap.josm.tools.Geometry;
    7373
    7474/**
    7575 * Mapmode to add nodes, create and extend ways.
     
    8383
    8484    private Node mouseOnExistingNode;
    8585    private Set<Way> mouseOnExistingWays = new HashSet<Way>();
     86    // old highlights store which primitives are currently highlighted. This
     87    // is true, even if target highlighting is disabled since the status bar
     88    // derives its information from this list as well.
    8689    private Set<OsmPrimitive> oldHighlights = new HashSet<OsmPrimitive>();
     90    // new highlights contains a list of primitives that should be highlighted
     91    // but haven’t been so far. The idea is to compare old and new and only
     92    // repaint if there are changes.
     93    private Set<OsmPrimitive> newHighlights = new HashSet<OsmPrimitive>();
    8794    private boolean drawHelperLine;
    8895    private boolean wayIsFinished = false;
    8996    private boolean drawTargetHighlight;
     
    131138     */
    132139    private void redrawIfRequired() {
    133140        updateStatusLine();
     141        // repaint required if the helper line is active.
     142        boolean needsRepaint = drawHelperLine && !wayIsFinished;
     143        // move newHighlights to oldHighlights; only update changed primitives
     144        for(OsmPrimitive x : newHighlights) {
     145            if(oldHighlights.contains(x)) {
     146                continue;
     147            }
     148            needsRepaint = true;
     149            x.setHighlighted(true);
     150        }
     151        oldHighlights.removeAll(newHighlights);
     152        for(OsmPrimitive x : oldHighlights) {
     153            x.setHighlighted(false);
     154            needsRepaint = true;
     155        }
     156        oldHighlights = newHighlights;
     157
    134158        if ((!drawHelperLine || wayIsFinished) && !drawTargetHighlight)
    135159            return;
     160
    136161        // update selection to reflect which way being modified
    137162        if (currentBaseNode != null && getCurrentDataSet().getSelected().isEmpty() == false) {
    138163            Way continueFrom = getWayForNode(currentBaseNode);
    139             if (alt && continueFrom != null) {
     164            if (alt && continueFrom != null && (!currentBaseNode.isSelected() || continueFrom.isSelected())) {
    140165                getCurrentDataSet().beginUpdate(); // to prevent the selection listener to screw around with the state
    141166                getCurrentDataSet().addSelected(currentBaseNode);
    142167                getCurrentDataSet().clearSelection(continueFrom);
    143168                getCurrentDataSet().endUpdate();
    144             } else if (!alt && continueFrom != null) {
     169                needsRepaint = true;
     170            } else if (!alt && continueFrom != null && !continueFrom.isSelected()) {
    145171                getCurrentDataSet().addSelected(continueFrom);
     172                needsRepaint = true;
    146173            }
    147174        }
    148         Main.map.mapView.repaint();
     175
     176        //System.out.println("redrawIfrequired near the end: " + needsRepaint);
     177        if(needsRepaint) {
     178            Main.map.mapView.repaint();
     179        }
    149180    }
    150181
    151182    @Override
     
    201232        Main.map.statusLine.getAnglePanel().removeMouseListener(snapHelper.anglePopupListener);
    202233
    203234        removeHighlighting();
     235        redrawIfRequired();
    204236        try {
    205237            Toolkit.getDefaultToolkit().removeAWTEventListener(this);
    206238        } catch (SecurityException ex) {
     
    227259        updateKeyModifiers((InputEvent) event);
    228260        computeHelperLine();
    229261        addHighlighting();
    230         redrawIfRequired();
    231262    }
    232263
    233264    // events for crossplatform key holding processing
     
    277308            return;
    278309        computeHelperLine();
    279310        addHighlighting();
    280         redrawIfRequired();
    281311    }
    282312
    283313    private void tryAgain(MouseEvent e) {
     
    706736
    707737        computeHelperLine();
    708738        addHighlighting();
    709         redrawIfRequired();
    710739    }
    711740
    712741    /**
     
    723752            return;
    724753        }
    725754
    726         double distance = -1;
    727         double angle = -1;
    728 
    729755        Collection<OsmPrimitive> selection = getCurrentDataSet().getSelected();
    730756
    731757        Node currentMouseNode = null;
     
    758784        }
    759785
    760786        determineCurrentBaseNodeAndPreviousNode(selection);
    761         if (previousNode == null) snapHelper.noSnapNow();
     787        if (previousNode == null) {
     788            snapHelper.noSnapNow();
     789        }
    762790
    763791        if (currentBaseNode == null || currentBaseNode == currentMouseNode)
    764792            return; // Don't create zero length way segments.
    765793
    766794
    767795        double curHdg = Math.toDegrees(currentBaseNode.getEastNorth()
    768             .heading(currentMouseEastNorth));
     796                .heading(currentMouseEastNorth));
    769797        double baseHdg=-1;
    770798        if (previousNode != null) {
    771799            baseHdg =  Math.toDegrees(previousNode.getEastNorth()
    772                 .heading(currentBaseNode.getEastNorth()));
     800                    .heading(currentBaseNode.getEastNorth()));
    773801        }
    774802
    775803        snapHelper.checkAngleSnapping(currentMouseEastNorth,baseHdg, curHdg);
     
    822850        } else if (!selectedWay.isDeleted()) { // fix #7118
    823851            if (selectedNode == selectedWay.getNode(0)){
    824852                currentBaseNode = selectedNode;
    825                 if (selectedWay.getNodesCount()>1) previousNode = selectedWay.getNode(1);
     853                if (selectedWay.getNodesCount()>1) {
     854                    previousNode = selectedWay.getNode(1);
     855                }
    826856            }
    827857            if (selectedNode == selectedWay.lastNode()) {
    828858                currentBaseNode = selectedNode;
    829                 if (selectedWay.getNodesCount()>1)
     859                if (selectedWay.getNodesCount()>1) {
    830860                    previousNode = selectedWay.getNode(selectedWay.getNodesCount()-2);
     861                }
    831862            }
    832863        }
    833864    }
     
    966997        EastNorth p2=ws.getSecondNode().getEastNorth();
    967998        if (snapHelper.dir2!=null && currentBaseNode!=null) {
    968999            EastNorth xPoint = Geometry.getSegmentSegmentIntersection(p1, p2, snapHelper.dir2, currentBaseNode.getEastNorth());
    969             if (xPoint!=null) n.setEastNorth(xPoint);
     1000            if (xPoint!=null) {
     1001                n.setEastNorth(xPoint);
     1002            }
    9701003        }
    9711004    }
    9721005    /**
    9731006     * Takes the data from computeHelperLine to determine which ways/nodes should be highlighted
    974      * (if feature enabled). Also sets the target cursor if appropriate.
     1007     * (if feature enabled). Also sets the target cursor if appropriate. It adds the to-be-
     1008     * highlighted primitives to newHighlights but does not actually highlight them. This work is
     1009     * done in redrawIfRequired. This means, calling addHighlighting() without redrawIfRequired()
     1010     * will leave the data in an inconsistent state.
     1011     *
     1012     * The status bar derives its information from oldHighlights, so in order to update the status
     1013     * bar both addHighlighting() and repaintIfRequired() are needed, since former fills newHighlights
     1014     * and latter processes them into oldHighlights.
    9751015     */
    9761016    private void addHighlighting() {
    977         removeHighlighting();
     1017        newHighlights = new HashSet<OsmPrimitive>();
     1018
    9781019        // if ctrl key is held ("no join"), don't highlight anything
    9791020        if (ctrl) {
    9801021            Main.map.mapView.setNewCursor(cursor, this);
     1022            redrawIfRequired();
    9811023            return;
    9821024        }
    9831025
     
    9891031
    9901032        if (mouseOnExistingNode != null) {
    9911033            Main.map.mapView.setNewCursor(cursorJoinNode, this);
    992             // We also need this list for the statusbar help text
    993             oldHighlights.add(mouseOnExistingNode);
    994             if(drawTargetHighlight) {
    995                 mouseOnExistingNode.setHighlighted(true);
    996         }
     1034            newHighlights.add(mouseOnExistingNode);
     1035            redrawIfRequired();
    9971036            return;
    9981037        }
    9991038
    10001039        // Insert the node into all the nearby way segments
    10011040        if (mouseOnExistingWays.size() == 0) {
    10021041            Main.map.mapView.setNewCursor(cursor, this);
     1042            redrawIfRequired();
    10031043            return;
    10041044        }
    10051045
    10061046        Main.map.mapView.setNewCursor(cursorJoinWay, this);
    1007 
    1008         // We also need this list for the statusbar help text
    1009         oldHighlights.addAll(mouseOnExistingWays);
    1010         if (!drawTargetHighlight) return;
    1011         for (Way w : mouseOnExistingWays) {
    1012             w.setHighlighted(true);
    1013         }
     1047        newHighlights.addAll(mouseOnExistingWays);
     1048        redrawIfRequired();
    10141049    }
    10151050
    10161051    /**
    1017      * Removes target highlighting from primitives
     1052     * Removes target highlighting from primitives.
    10181053     */
    10191054    private void removeHighlighting() {
    1020         for(OsmPrimitive prim : oldHighlights) {
    1021             prim.setHighlighted(false);
    1022         }
    1023         oldHighlights = new HashSet<OsmPrimitive>();
     1055        newHighlights = new HashSet<OsmPrimitive>();
     1056        redrawIfRequired();
    10241057    }
    10251058
    10261059    public void paint(Graphics2D g, MapView mv, Bounds box) {
    10271060        // sanity checks
    10281061        if (Main.map.mapView == null || mousePos == null
    1029         // don't draw line if we don't know where from or where to
    1030         || currentBaseNode == null || currentMouseEastNorth == null
    1031         // don't draw line if mouse is outside window
    1032         || !Main.map.mapView.getBounds().contains(mousePos))
     1062                // don't draw line if we don't know where from or where to
     1063                || currentBaseNode == null || currentMouseEastNorth == null
     1064                // don't draw line if mouse is outside window
     1065                || !Main.map.mapView.getBounds().contains(mousePos))
    10331066            return;
    10341067
    10351068        Graphics2D g2 = g;
    10361069        snapHelper.drawIfNeeded(g2,mv);
    10371070        if (!drawHelperLine || wayIsFinished || shift)
    1038           return;
     1071            return;
    10391072
    10401073        if (!snapHelper.isActive()) { // else use color and stoke from  snapHelper.draw
    10411074            g2.setColor(selectedColor);
    10421075            g2.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
    1043         } else if (!snapHelper.drawConstructionGeometry) {
     1076        } else if (!snapHelper.drawConstructionGeometry)
    10441077            return;
    1045         }
    10461078        GeneralPath b = new GeneralPath();
    10471079        Point p1=mv.getPoint(currentBaseNode);
    10481080        Point p2=mv.getPoint(currentMouseEastNorth);
     
    11681200                        n=(Node) p; // found one node
    11691201                        wayIsFinished=false;
    11701202                    }  else {
    1171                     // if more than 1 node were affected by previous command,
    1172                     // we have no way to continue, so we forget about found node
     1203                        // if more than 1 node were affected by previous command,
     1204                        // we have no way to continue, so we forget about found node
    11731205                        n=null;
    11741206                        break;
    11751207                    }
    11761208                }
    11771209            }
    11781210            // select last added node - maybe we will continue drawing from it
    1179             if (n!=null) getCurrentDataSet().addSelected(n);
    1180        }
     1211            if (n!=null) {
     1212                getCurrentDataSet().addSelected(n);
     1213            }
     1214        }
    11811215    }
    11821216
    11831217    private class SnapHelper {
     
    12251259            fixed=false; absoluteFix=false;
    12261260
    12271261            Collection<String> angles = Main.pref.getCollection("draw.anglesnap.angles",
    1228                 Arrays.asList("0","30","45","60","90","120","135","150","180"));
     1262                    Arrays.asList("0","30","45","60","90","120","135","150","180"));
    12291263
    12301264            snapAngles = new double[2*angles.size()];
    12311265            int i=0;
     
    12501284            snapHelperColor = Main.pref.getColor(marktr("draw angle snap"), Color.ORANGE);
    12511285
    12521286            highlightColor = Main.pref.getColor(marktr("draw angle snap highlight"),
    1253                 new Color(Color.ORANGE.getRed(),Color.ORANGE.getGreen(),Color.ORANGE.getBlue(),128));
     1287                    new Color(Color.ORANGE.getRed(),Color.ORANGE.getGreen(),Color.ORANGE.getBlue(),128));
    12541288            highlightStroke = new BasicStroke(10, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
    12551289
    12561290            float dash1[] = { 4.0f };
    12571291            helperStroke = new BasicStroke(1.0f, BasicStroke.CAP_BUTT,
    1258                 BasicStroke.JOIN_MITER, 10.0f, dash1, 0.0f);
     1292                    BasicStroke.JOIN_MITER, 10.0f, dash1, 0.0f);
    12591293        }
    12601294
    12611295        public void saveAngles(String ... angles) {
     
    13361370
    13371371            if (snapOn && (activeBaseHeading>=0)) {
    13381372                angle = curHeading - activeBaseHeading;
    1339                 if (angle < 0) angle+=360;
    1340                 if (angle > 360) angle=0;
     1373                if (angle < 0) {
     1374                    angle+=360;
     1375                }
     1376                if (angle > 360) {
     1377                    angle=0;
     1378                }
    13411379
    13421380                double nearestAngle;
    13431381                if (fixed) {
     
    13801418
    13811419            if (baseHeading >=0 ) { // there is previous line segment with some heading
    13821420                angle = hdg - baseHeading;
    1383                 if (angle < 0) angle+=360;
    1384                 if (angle > 360) angle=0;
     1421                if (angle < 0) {
     1422                    angle+=360;
     1423                }
     1424                if (angle > 360) {
     1425                    angle=0;
     1426                }
    13851427            }
    13861428            showStatusInfo(angle, hdg, distance);
    13871429        }
     
    14561498
    14571499            double hdg = segmentPoint1.heading(segmentPoint2);
    14581500            hdg=Math.toDegrees(hdg);
    1459             if (hdg<0) hdg+=360;
    1460             if (hdg>360) hdg-=360;
     1501            if (hdg<0) {
     1502                hdg+=360;
     1503            }
     1504            if (hdg>360) {
     1505                hdg-=360;
     1506            }
    14611507            //fixed=true;
    14621508            //absoluteFix=true;
    14631509            customBaseHeading=hdg;
     
    14661512        private void nextSnapMode() {
    14671513            if (snapOn) {
    14681514                // turn off snapping if we are in fixed mode or no actile snapping line exist
    1469                 if (fixed || !active) { snapOn=false; unsetFixedMode(); }
    1470                 else setFixedMode();
     1515                if (fixed || !active) { snapOn=false; unsetFixedMode(); } else {
     1516                    setFixedMode();
     1517                }
    14711518            } else {
    14721519                snapOn=true;
    14731520                unsetFixedMode();
     
    15211568                    bestAngle=snapAngles[i];
    15221569                }
    15231570            }
    1524             if (Math.abs(bestAngle-360) < 1e-3)
     1571            if (Math.abs(bestAngle-360) < 1e-3) {
    15251572                bestAngle=0;
     1573            }
    15261574            return bestAngle;
    15271575        }
    15281576
     
    15351583        }
    15361584
    15371585        private void unFixOrTurnOff() {
    1538             if (absoluteFix)
     1586            if (absoluteFix) {
    15391587                unsetFixedMode();
    1540             else
     1588            } else {
    15411589                toggleSnapping();
     1590            }
    15421591        }
    15431592
    15441593        MouseListener anglePopupListener = new PopupMenuLauncher( new JPopupMenu() {
     
    16091658    private class SnapChangeAction extends JosmAction {
    16101659        public SnapChangeAction() {
    16111660            super(tr("Angle snapping"), "anglesnap",
    1612                 tr("Switch angle snapping mode while drawing"), null, false);
     1661                    tr("Switch angle snapping mode while drawing"), null, false);
    16131662            putValue("help", ht("/Action/Draw/AngleSnap"));
    16141663        }
    16151664
    16161665        @Override
    16171666        public void actionPerformed(ActionEvent e) {
    1618                if (snapHelper!=null) snapHelper.toggleSnapping();
     1667            if (snapHelper!=null) {
     1668                snapHelper.toggleSnapping();
     1669            }
    16191670        }
    16201671    }
    16211672}