Ignore:
Timestamp:
2017-02-05T13:32:08+01:00 (8 years ago)
Author:
donvip
Message:

fix #josm12711 - AlignWayS plugin crashes (patch by IdealChain)

Location:
applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysAlgnSegment.java

    r32921 r33136  
    66import java.awt.Point;
    77import java.awt.Shape;
     8import java.awt.RenderingHints;
    89import java.awt.geom.Ellipse2D;
    910import java.awt.geom.Line2D;
     
    3839    private enum PivotLocations {
    3940        NONE, NODE1, NODE2, CENTRE
    40     };
     41    }
    4142
    4243    private PivotLocations currPivot;
     
    119120            switch (pp) {
    120121            case NODE1:
    121                 return segment.way.getNode(segment.lowerIndex).getEastNorth();
     122                return segment.getFirstNode().getEastNorth();
    122123            case NODE2:
    123                 return segment.way.getNode(segment.lowerIndex + 1).getEastNorth();
     124                return segment.getSecondNode().getEastNorth();
    124125            case CENTRE:
    125126                n1 = getPivotCoord(PivotLocations.NODE1);
     
    227228    @Override
    228229    public void paint(Graphics2D g, MapView mv, Bounds bbox) {
    229         // Note: segment should never be null here
    230230        super.paint(g, mv, bbox);
     231
     232        // Note: segment should never be null here, and its nodes should never be missing.
     233        // If they are, it's a bug, possibly related to tracking of DataSet deletions.
     234        if (segment.way.getNodesCount() <= segment.lowerIndex + 1) {
     235            Main.warn("Not drawing AlignWays pivot points: underlying nodes disappeared");
     236            return;
     237        }
    231238
    232239        // Ensure consistency
     
    247254        g.setColor(pivotColor);
    248255        g.setStroke(new BasicStroke());
     256        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    249257
    250258        Shape pvCentrePoint = new Ellipse2D.Double(
     
    272280        g.setColor(crossColor);
    273281        g.setStroke(new BasicStroke());
     282        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
     283
    274284        g.draw(crossV);
    275285        g.draw(crossH);
  • applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysCmdKeepLength.java

    r30737 r33136  
    1010import java.util.HashSet;
    1111import java.util.Map;
     12import java.util.Collections;
    1213
    1314import javax.swing.Icon;
     
    9293        this.displaceableNodes = algnSeg.getSegmentEndPoints();
    9394
    94         EastNorth enRefNode1 = refWS.way.getNode(refWS.lowerIndex)
    95                 .getEastNorth();
    96         EastNorth enRefNode2 = refWS.way.getNode(refWS.lowerIndex + 1)
    97                 .getEastNorth();
    98 
    99         EastNorth enAlgnNode1 = algnWS.way.getNode(algnWS.lowerIndex)
    100                 .getEastNorth();
    101         EastNorth enAlgnNode2 = algnWS.way.getNode(algnWS.lowerIndex + 1)
    102                 .getEastNorth();
     95        EastNorth enRefNode1 = refWS.getFirstNode().getEastNorth();
     96        EastNorth enRefNode2 = refWS.getSecondNode().getEastNorth();
     97
     98        EastNorth enAlgnNode1 = algnWS.getFirstNode().getEastNorth();
     99        EastNorth enAlgnNode2 = algnWS.getSecondNode().getEastNorth();
    103100
    104101        // Calculate the rotation angle
     
    203200            modified.add(osm);
    204201        }
     202    }
     203
     204    @Override
     205    public Collection<? extends OsmPrimitive> getParticipatingPrimitives() {
     206        Collection<OsmPrimitive> prims = new HashSet<>(displaceableNodes);
     207        prims.add(algnSeg.getSegment().way);
     208        return Collections.unmodifiableCollection(prims);
    205209    }
    206210
  • applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysDialog.java

    r30345 r33136  
    1111import java.awt.event.ActionEvent;
    1212import java.awt.event.ActionListener;
     13import java.util.Objects;
    1314
    1415import javax.swing.BorderFactory;
     
    117118    @Override
    118119    public void actionPerformed(ActionEvent e) {
    119         if (e.getActionCommand() == "awOptKeepLen") {
     120        if (Objects.equals(e.getActionCommand(), "awOptKeepLen")) {
    120121            awOpt = AligningModeOption.ALGN_OPT_KEEP_LENGTH;
    121122            infoText.setText(tr("<html>Aligns the way segment to the reference so that its length is preserved.</html>"));
    122         } else if (e.getActionCommand() == "awOptKeepAng") {
     123        } else if (Objects.equals(e.getActionCommand(), "awOptKeepAng")) {
    123124            awOpt = AligningModeOption.ALGN_OPT_KEEP_ANGLE;
    124125            infoText.setText(tr("<html>Aligns the way segment to the reference so that the angles of its adjacent segments are preserved.<br/>" +
     
    136137
    137138    /**
    138      * @param action If set to true, the dialog will show the mode options, otherwise it will show some instructions
     139     * @param activeMode If set to true, the dialog will show the mode options, otherwise it will show some instructions
    139140     */
    140141    public void activate(boolean activeMode) {
  • applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysMode.java

    r32920 r33136  
    2121import org.openstreetmap.josm.actions.mapmode.MapMode;
    2222import org.openstreetmap.josm.data.osm.DataSet;
     23import org.openstreetmap.josm.data.osm.event.AbstractDatasetChangedEvent;
     24import org.openstreetmap.josm.data.osm.event.DataChangedEvent;
     25import org.openstreetmap.josm.data.osm.event.DataSetListener;
     26import org.openstreetmap.josm.data.osm.event.NodeMovedEvent;
     27import org.openstreetmap.josm.data.osm.event.PrimitivesAddedEvent;
     28import org.openstreetmap.josm.data.osm.event.PrimitivesRemovedEvent;
     29import org.openstreetmap.josm.data.osm.event.RelationMembersChangedEvent;
     30import org.openstreetmap.josm.data.osm.event.TagsChangedEvent;
     31import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent;
    2332import org.openstreetmap.josm.gui.IconToggleButton;
    2433import org.openstreetmap.josm.gui.MapFrame;
    2534import org.openstreetmap.josm.gui.layer.Layer;
     35import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    2636import org.openstreetmap.josm.tools.Shortcut;
    2737
     
    3141 *
    3242 */
    33 public class AlignWaysMode extends MapMode /* implements MapViewPaintable */{
     43public class AlignWaysMode extends MapMode implements DataSetListener {
    3444
    3545    private static final long serialVersionUID = -1090955708412011141L;
     
    7888        awSegs = AlignWaysSegmentMgr.getInstance(Main.map.mapView);
    7989        Main.map.mapView.addMouseListener(this);
     90        DataSet ds = Main.getLayerManager().getEditDataSet();
     91        if (ds != null)
     92            ds.addDataSetListener(this);
    8093        setCurrentState(noneSelected);
    8194    }
     
    95108        setCurrentState(noneSelected);
    96109        Main.map.mapView.removeMouseListener(this);
     110        DataSet ds = Main.getLayerManager().getEditDataSet();
     111        if (ds != null)
     112            ds.removeDataSetListener(this);
    97113        AlignWaysPlugin.getAwAction().setEnabled(false);
    98114    }
     
    128144        }
    129145
    130         // Activate the Align Ways button if we have enough selections
    131         if (currentState == bothSelected) {
    132             AlignWaysPlugin.getAwAction().setEnabled(true);
    133         } else {
    134             AlignWaysPlugin.getAwAction().setEnabled(false);
    135         }
    136146        Main.map.mapView.repaint();
    137147    }
    138148
    139149    /**
    140      * @param currentState
    141      *            One of the AlignWays states
     150     * Sets the current state based on the selected segments.
     151     * @param mgr AlignWays segment manager singleton
     152     */
     153    public void setCurrentState(AlignWaysSegmentMgr mgr) {
     154
     155        boolean algnSelected = mgr.getAlgnSeg() != null;
     156        boolean refSelected = mgr.getRefSeg() != null;
     157
     158        if (algnSelected && refSelected)
     159            setCurrentState(getBothSelected());
     160        else if (algnSelected)
     161            setCurrentState(getAligneeSelected());
     162        else if (refSelected)
     163            setCurrentState(getReferenceSelected());
     164        else
     165            setCurrentState(getNoneSelected());
     166    }
     167
     168    /**
     169     * Sets the current state.
     170     * @param currentState One of the AlignWays states
    142171     */
    143172    public void setCurrentState(AlignWaysState currentState) {
     
    145174        currentState.setHelpText();
    146175
     176        // Activate the Align Ways button if we have enough selections
     177        AlignWaysPlugin.getAwAction().setEnabled(currentState == bothSelected);
     178
    147179        if (currentState == noneSelected) {
    148180            awSegs.cleanupWays();
    149             // TODO getCurrentDataSet may return null when the editable layer had
     181
     182            // getEditDataSet() may return null when the editable layer had
    150183            // already been removed by JOSM. This happens e.g. when the user closes
    151184            // JOSM while AlignWays mode is still active.
     
    183216    public AlignWaysState getBothSelected() {
    184217        return bothSelected;
    185     }
    186 
    187     /**
    188      * @return the current state
    189      */
    190     public AlignWaysState getCurrentState() {
    191         return currentState;
    192218    }
    193219
     
    229255    @Override
    230256    public boolean layerIsSupported(Layer l) {
    231         if (l == null)
    232             return false;
    233         else
    234             return true;
     257        return l instanceof OsmDataLayer;
     258    }
     259
     260    @Override
     261    protected void updateEnabledState() {
     262        setEnabled(getLayerManager().getEditLayer() != null);
     263    }
     264
     265    /* --------------- *
     266     * DataSetListener *
     267     * --------------- */
     268
     269    @Override
     270    public void primitivesAdded(PrimitivesAddedEvent event) {
     271    }
     272
     273    @Override
     274    public void primitivesRemoved(PrimitivesRemovedEvent event) {
     275        awSegs = AlignWaysSegmentMgr.getInstance(Main.map.mapView);
     276
     277        // Check whether any of the removed primitives were part of a highlighted alignee or reference segment.
     278        // If so: remove the affected segment and update the state accordingly.
     279        if (awSegs.primitivesRemoved(event.getPrimitives()))
     280            setCurrentState(awSegs);
     281    }
     282
     283    @Override
     284    public void tagsChanged(TagsChangedEvent event) {
     285    }
     286
     287    @Override
     288    public void nodeMoved(NodeMovedEvent event) {
     289    }
     290
     291    @Override
     292    public void wayNodesChanged(WayNodesChangedEvent event) {
     293    }
     294
     295    @Override
     296    public void relationMembersChanged(RelationMembersChangedEvent event) {
     297    }
     298
     299    @Override
     300    public void otherDatasetChange(AbstractDatasetChangedEvent event) {
     301    }
     302
     303    @Override
     304    public void dataChanged(DataChangedEvent event) {
    235305    }
    236306}
  • applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysSegment.java

    r33133 r33136  
    1010import java.awt.Graphics2D;
    1111import java.awt.Point;
     12import java.awt.RenderingHints;
    1213import java.awt.geom.Line2D;
    1314import java.util.Collection;
     
    1920import org.openstreetmap.josm.data.osm.Node;
    2021import org.openstreetmap.josm.data.osm.OsmPrimitive;
     22import org.openstreetmap.josm.data.osm.Way;
    2123import org.openstreetmap.josm.data.osm.WaySegment;
    2224import org.openstreetmap.josm.gui.MapView;
     
    5759        if (segment != null) {
    5860            try {
    59                 Node node1 = segment.way.getNode(segment.lowerIndex);
    60                 Node node2 = segment.way.getNode(segment.lowerIndex + 1);
    61 
    6261                segmentEndPoints = new HashSet<>();
    63                 segmentEndPoints.add(node1);
    64                 segmentEndPoints.add(node2);
     62                segmentEndPoints.add(segment.getFirstNode());
     63                segmentEndPoints.add(segment.getSecondNode());
    6564            } catch (IndexOutOfBoundsException e) {
    6665                Main.error(e);
     
    8988    @Override
    9089    public void paint(Graphics2D g, MapView mv, Bounds bbox) {
     90        // Note: segment should never be null here, and its nodes should never be missing.
     91        // If they are, it's a bug, possibly related to tracking of DataSet deletions.
     92        if (segment.way.getNodesCount() <= segment.lowerIndex + 1) {
     93            Main.warn("Not drawing AlignWays highlighting segment: underlying nodes disappeared");
     94            return;
     95        }
     96
    9197        highlightSegment(segmentColor, g, mv);
    9298    }
    9399
    94100    protected void highlightSegment(Color c, Graphics2D g, MapView mv) {
    95         if (segment.way.getNodesCount() == 0) {
    96             return;
    97         }
    98 
    99101        g.setColor(c);
    100102        g.setStroke(new BasicStroke(6, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
     103        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    101104        drawSegment(g, mv);
    102105    }
     
    104107    protected void drawSegment(Graphics2D g, MapView mv) {
    105108        try {
    106             Node n1 = segment.way.getNode(segment.lowerIndex);
    107             Node n2 = segment.way.getNode(segment.lowerIndex + 1);
     109            Node n1 = segment.getFirstNode();
     110            Node n2 = segment.getSecondNode();
    108111
    109112            g.draw(new Line2D.Double(mv.getPoint(n1), mv.getPoint(n2)));
     
    111114            Main.error(e);
    112115        }
     116    }
     117
     118    protected boolean containsPrimitive(OsmPrimitive primitive) {
     119        if (segment == null)
     120            return false;
     121
     122        return (primitive instanceof Way && segment.way.equals(primitive)) ||
     123                (primitive instanceof Node && segmentEndPoints.contains(primitive));
     124
    113125    }
    114126
  • applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysSegmentMgr.java

    r27348 r33136  
    55import java.awt.Point;
    66import java.util.Collection;
     7import java.util.List;
    78
    89import javax.swing.JOptionPane;
     
    1011import org.openstreetmap.josm.Main;
    1112import org.openstreetmap.josm.data.osm.Node;
     13import org.openstreetmap.josm.data.osm.OsmPrimitive;
    1214import org.openstreetmap.josm.gui.MapView;
    1315
     
    3133    }
    3234
     35    /**
     36     * Get or creates the segment manager instance belonging to a given MapView.
     37     */
    3338    public static AlignWaysSegmentMgr getInstance(MapView mapView) {
    34         if (singleton == null) {
    35             synchronized (AlignWaysSegmentMgr.class) {
    36                 if (singleton == null) {
    37                     singleton = new AlignWaysSegmentMgr(mapView);
    38                 }
     39        synchronized (AlignWaysSegmentMgr.class) {
     40            if (singleton == null || !singleton.getMapView().equals(mapView)) {
     41                singleton = new AlignWaysSegmentMgr(mapView);
    3942            }
    4043        }
    4144        return singleton;
     45    }
     46
     47    /**
     48     * @return The MapView this segment manager belongs to.
     49     */
     50    private MapView getMapView() {
     51        return mv;
    4252    }
    4353
     
    4959    public boolean algnUpdate(Point clickedPoint) {
    5060
    51         if (algnSeg != null) {
    52             // Check first if there is a pivot point nearby that needs selection
    53             if (algnSeg.updatePivot(clickedPoint))
    54                 // Updated pivot, alignee reference unchanged
    55                 return false;
     61        // Check first if there is a pivot point nearby that needs selection
     62        if (algnSeg != null && algnSeg.updatePivot(clickedPoint)) {
     63            // Updated pivot, alignee reference unchanged
     64            return false;
    5665        }
    5766
    5867        // Previous attempt of pivot update unsuccessful, check alignee update
    59         AlignWaysAlgnSegment tmpAlgnSeg = new AlignWaysAlgnSegment(mv,
    60                 clickedPoint);
     68        AlignWaysAlgnSegment tmpAlgnSeg = new AlignWaysAlgnSegment(mv, clickedPoint);
    6169        if (tmpAlgnSeg.getSegment() == null)
    6270            return false;
    63         else {
    64             // Found a segment
    65             // It may happen that the new segment is identical with the already
    66             // selected reference:
    67             if ((refSeg != null) && (tmpAlgnSeg.equals(refSeg))) {
    68                 // This action is then ignored (we won't clear the reference
    69                 // segment)
    70                 JOptionPane.showMessageDialog(Main.parent,
    71                         tr("Segment to be aligned cannot be the same with the reference segment.\n" +
    72                         "Please choose a different segment to be aligned."),
    73                         tr("AlignWayS message"), JOptionPane.WARNING_MESSAGE);
    74                 return false;
    75             }
    76             // This will be a new alignee, old alignee (if any) will be lost:
    77             if (algnSeg != null) {
    78                 algnSeg.destroy();
    79             }
    8071
    81             // Update alignee
    82             algnSeg = tmpAlgnSeg;
    83 
    84             return true;
     72        // Found a segment - it may happen that the new segment is identical with the already
     73        // selected asignee or reference segment. This action is then ignored.
     74        if (algnSeg != null && tmpAlgnSeg.equals(algnSeg)) {
     75            return false;
     76        }
     77        else if (refSeg != null && tmpAlgnSeg.equals(refSeg)) {
     78            JOptionPane.showMessageDialog(Main.parent,
     79                    tr("Segment to be aligned cannot be the same with the reference segment.\n" +
     80                    "Please choose a different segment to be aligned."),
     81                    tr("AlignWayS message"), JOptionPane.WARNING_MESSAGE);
     82            return false;
    8583        }
    8684
     85        // This will be a new alignee, old alignee (if any) will be lost:
     86        if (algnSeg != null) {
     87            algnSeg.destroy();
     88        }
     89
     90        // Update alignee
     91        algnSeg = tmpAlgnSeg;
     92        return true;
    8793    }
    8894
     
    94100    public boolean refUpdate(Point clickedPoint) {
    95101
    96         AlignWaysRefSegment tmpRefSeg = new AlignWaysRefSegment(mv,
    97                 clickedPoint);
    98         // TODO Have to check what happens when refSeg wasn't null previously
     102        AlignWaysRefSegment tmpRefSeg = new AlignWaysRefSegment(mv, clickedPoint);
    99103        if (tmpRefSeg.getSegment() == null)
    100104            return false;
    101         else {
    102             // Found a segment
    103             // It may happen that the new segment is identical with the already
    104             // selected alignee:
    105             if ((algnSeg != null) && (tmpRefSeg.equals(algnSeg))) {
    106                 // This action is then ignored (we won't clear the alignee
    107                 // segment)
    108                 JOptionPane.showMessageDialog(Main.parent,
    109                         tr("Reference segment cannot be the same with the segment to be aligned.\n" +
    110                         "Please choose a different reference segment."),
    111                         tr("AlignWayS message"), JOptionPane.WARNING_MESSAGE);
    112                 return false;
    113             }
    114             // This will be a new reference, old reference (if any) will be lost:
    115             if (refSeg != null) {
    116                 refSeg.destroy();
    117             }
    118105
    119             // Update reference
    120             refSeg = tmpRefSeg;
    121             return true;
    122 
     106        // Found a segment - it may happen that the new segment is identical with the already
     107        // selected asignee or reference segment. This action is then ignored.
     108        if (refSeg != null && refSeg.equals(tmpRefSeg)) {
     109            return false;
     110        }
     111        else if (algnSeg != null && tmpRefSeg.equals(algnSeg)) {
     112            JOptionPane.showMessageDialog(Main.parent,
     113                    tr("Reference segment cannot be the same with the segment to be aligned.\n" +
     114                    "Please choose a different reference segment."),
     115                    tr("AlignWayS message"), JOptionPane.WARNING_MESSAGE);
     116            return false;
    123117        }
    124118
     119        // This will be a new reference, old reference (if any) will be lost:
     120        if (refSeg != null) {
     121            refSeg.destroy();
     122        }
     123
     124        // Update reference
     125        refSeg = tmpRefSeg;
     126        return true;
    125127    }
    126128
     
    159161    }
    160162
     163
     164    /**
     165     * Handles the event that OSM primitives were removed and checks whether
     166     * this invalidates the currently selected alignee or reference segment.
     167     * @return Whether any of the selected segments were invalidated.
     168     * @param primitives List of primitives that were removed.
     169     */
     170    public boolean primitivesRemoved(List<? extends OsmPrimitive> primitives) {
     171        boolean changed = false;
     172        for (OsmPrimitive p : primitives) {
     173            if (algnSeg != null && algnSeg.containsPrimitive(p)) {
     174                algnSeg.destroy();
     175                algnSeg = null;
     176                changed = true;
     177            }
     178            if (refSeg != null && refSeg.containsPrimitive(p)) {
     179                refSeg.destroy();
     180                refSeg = null;
     181                changed = true;
     182            }
     183        }
     184        return changed;
     185    }
    161186}
Note: See TracChangeset for help on using the changeset viewer.