Ticket #12711: alignways-datasetlistener.patch

File alignways-datasetlistener.patch, 23.0 KB (added by IdealChain, 9 years ago)
  • plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysAlgnSegment.java

     
    55import java.awt.Graphics2D;
    66import java.awt.Point;
    77import java.awt.Shape;
     8import java.awt.RenderingHints;
    89import java.awt.geom.Ellipse2D;
    910import java.awt.geom.Line2D;
    1011import java.util.ArrayList;
     
    3738
    3839    private enum PivotLocations {
    3940        NONE, NODE1, NODE2, CENTRE
    40     };
     41    }
    4142
    4243    private PivotLocations currPivot;
    4344    Map<PivotLocations, EastNorth> pivotList = new EnumMap<>(
     
    118119            EastNorth n2;
    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);
    126127                n2 = getPivotCoord(PivotLocations.NODE2);
     
    226227
    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);
    231231
     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        }
     238
    232239        // Ensure consistency
    233240        updatePivotsEndpoints();
    234241
     
    246253    private void highlightPivot(Graphics2D g, MapView mv, EastNorth pivot) {
    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(
    251259                mv.getPoint(pivot).getX() - 5.0f,
     
    271279
    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);
    276286
  • plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysCmdKeepLength.java

     
    99import java.util.HashMap;
    1010import java.util.HashSet;
    1111import java.util.Map;
     12import java.util.Collections;
    1213
    1314import javax.swing.Icon;
    1415import javax.swing.JOptionPane;
     
    9192        this.pivot = algnSeg.getCurrPivotCoord();
    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();
     95        EastNorth enRefNode1 = refWS.getFirstNode().getEastNorth();
     96        EastNorth enRefNode2 = refWS.getSecondNode().getEastNorth();
    9897
    99         EastNorth enAlgnNode1 = algnWS.way.getNode(algnWS.lowerIndex)
    100                 .getEastNorth();
    101         EastNorth enAlgnNode2 = algnWS.way.getNode(algnWS.lowerIndex + 1)
    102                 .getEastNorth();
     98        EastNorth enAlgnNode1 = algnWS.getFirstNode().getEastNorth();
     99        EastNorth enAlgnNode2 = algnWS.getSecondNode().getEastNorth();
    103100
    104101        // Calculate the rotation angle
    105102        double refAngle = Math.atan2(enRefNode1.north() - enRefNode2.north(),
     
    205202    }
    206203
    207204    @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);
     209    }
     210
     211    @Override
    208212    public boolean executeCommand() {
    209213        rotateNodes(true);
    210214        return true;
  • plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysDialog.java

     
    1010import java.awt.GridLayout;
    1111import java.awt.event.ActionEvent;
    1212import java.awt.event.ActionListener;
     13import java.util.Objects;
    1314
    1415import javax.swing.BorderFactory;
    1516import javax.swing.Box;
     
    116117
    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/>" +
    125126                    "The length of the aligned segment is likely to change as result.</html>"));
     
    135136
    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) {
    141142
  • plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysMode.java

     
    2020import org.openstreetmap.josm.Main;
    2121import org.openstreetmap.josm.actions.mapmode.MapMode;
    2222import org.openstreetmap.josm.data.osm.DataSet;
     23import org.openstreetmap.josm.data.osm.event.*;
    2324import org.openstreetmap.josm.gui.IconToggleButton;
    2425import org.openstreetmap.josm.gui.MapFrame;
    2526import org.openstreetmap.josm.gui.layer.Layer;
     27import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    2628import org.openstreetmap.josm.tools.Shortcut;
    2729
    2830/**
     
    3032 * Handles the state machine and user interaction (mouse clicks).
    3133 *
    3234 */
    33 public class AlignWaysMode extends MapMode /* implements MapViewPaintable */{
     35public class AlignWaysMode extends MapMode implements DataSetListener {
    3436
    3537    private static final long serialVersionUID = -1090955708412011141L;
    3638    private final AlignWaysState noneSelected;
     
    7779
    7880        awSegs = AlignWaysSegmentMgr.getInstance(Main.map.mapView);
    7981        Main.map.mapView.addMouseListener(this);
     82        DataSet ds = Main.getLayerManager().getEditDataSet();
     83        if (ds != null)
     84            ds.addDataSetListener(this);
    8085        setCurrentState(noneSelected);
    8186    }
    8287
     
    9499
    95100        setCurrentState(noneSelected);
    96101        Main.map.mapView.removeMouseListener(this);
     102        DataSet ds = Main.getLayerManager().getEditDataSet();
     103        if (ds != null)
     104            ds.removeDataSetListener(this);
    97105        AlignWaysPlugin.getAwAction().setEnabled(false);
    98106    }
    99107
     
    127135            }
    128136        }
    129137
    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         }
    136138        Main.map.mapView.repaint();
    137139    }
    138140
    139141    /**
    140      * @param currentState
    141      *            One of the AlignWays states
     142     * Sets the current state based on the selected segments.
     143     * @param mgr AlignWays segment manager singleton
    142144     */
     145    public void setCurrentState(AlignWaysSegmentMgr mgr) {
     146
     147        boolean algnSelected = mgr.getAlgnSeg() != null;
     148        boolean refSelected = mgr.getRefSeg() != null;
     149
     150        if (algnSelected && refSelected)
     151            setCurrentState(getBothSelected());
     152        else if (algnSelected)
     153            setCurrentState(getAligneeSelected());
     154        else if (refSelected)
     155            setCurrentState(getReferenceSelected());
     156        else
     157            setCurrentState(getNoneSelected());
     158    }
     159
     160    /**
     161     * Sets the current state.
     162     * @param currentState One of the AlignWays states
     163     */
    143164    public void setCurrentState(AlignWaysState currentState) {
    144165        this.currentState = currentState;
    145166        currentState.setHelpText();
    146167
     168        // Activate the Align Ways button if we have enough selections
     169        AlignWaysPlugin.getAwAction().setEnabled(currentState == bothSelected);
     170
    147171        if (currentState == noneSelected) {
    148172            awSegs.cleanupWays();
    149             // TODO getCurrentDataSet may return null when the editable layer had
     173
     174            // getEditDataSet() may return null when the editable layer had
    150175            // already been removed by JOSM. This happens e.g. when the user closes
    151176            // JOSM while AlignWays mode is still active.
    152177            DataSet ds = getLayerManager().getEditDataSet();
     
    184209        return bothSelected;
    185210    }
    186211
    187     /**
    188      * @return the current state
    189      */
    190     public AlignWaysState getCurrentState() {
    191         return currentState;
    192     }
    193 
    194212    private void showTips() {
    195213
    196214        AlignWaysTipsPanel atp = new AlignWaysTipsPanel();
     
    228246
    229247    @Override
    230248    public boolean layerIsSupported(Layer l) {
    231         if (l == null)
    232             return false;
    233         else
    234             return true;
     249        return l instanceof OsmDataLayer;
    235250    }
     251
     252    @Override
     253    protected void updateEnabledState() {
     254        setEnabled(getLayerManager().getEditLayer() != null);
     255    }
     256
     257    /* --------------- *
     258     * DataSetListener *
     259     * --------------- */
     260
     261    @Override
     262    public void primitivesAdded(PrimitivesAddedEvent event) {
     263    }
     264
     265    @Override
     266    public void primitivesRemoved(PrimitivesRemovedEvent event) {
     267        awSegs = AlignWaysSegmentMgr.getInstance(Main.map.mapView);
     268
     269        // Check whether any of the removed primitives were part of a highlighted alignee or reference segment.
     270        // If so: remove the affected segment and update the state accordingly.
     271        if (awSegs.primitivesRemoved(event.getPrimitives()))
     272            setCurrentState(awSegs);
     273    }
     274
     275    @Override
     276    public void tagsChanged(TagsChangedEvent event) {
     277    }
     278
     279    @Override
     280    public void nodeMoved(NodeMovedEvent event) {
     281    }
     282
     283    @Override
     284    public void wayNodesChanged(WayNodesChangedEvent event) {
     285    }
     286
     287    @Override
     288    public void relationMembersChanged(RelationMembersChangedEvent event) {
     289    }
     290
     291    @Override
     292    public void otherDatasetChange(AbstractDatasetChangedEvent event) {
     293    }
     294
     295    @Override
     296    public void dataChanged(DataChangedEvent event) {
     297    }
     298
    236299}
  • plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysSegment.java

     
    99import java.awt.Color;
    1010import java.awt.Graphics2D;
    1111import java.awt.Point;
     12import java.awt.RenderingHints;
    1213import java.awt.geom.Line2D;
    1314import java.util.Collection;
    1415import java.util.HashSet;
     
    1819import org.openstreetmap.josm.data.Bounds;
    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;
    2325import org.openstreetmap.josm.gui.layer.MapViewPaintable;
     
    5658    void setSegmentEndpoints(WaySegment segment) {
    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);
    6766            }
     
    8887
    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    }
    103106
    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)));
    110113        } catch (IndexOutOfBoundsException e) {
     
    112115        }
    113116    }
    114117
     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
     125    }
     126
    115127     @Override
    116128     public int hashCode() {
    117129        if (segment == null) {
  • plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysSegmentMgr.java

     
    44
    55import java.awt.Point;
    66import java.util.Collection;
     7import java.util.List;
    78
    89import javax.swing.JOptionPane;
    910
    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
    1416/**
     
    3032        mv = mapView;
    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;
     
    4245    }
    4346
    4447    /**
     48     * @return The MapView this segment manager belongs to.
     49     */
     50    private MapView getMapView() {
     51        return mv;
     52    }
     53
     54    /**
    4555     * @param clickedPoint
    4656     *            Point nearby where user probably clicked
    4757     * @return true, if alignee changed, false otherwise
     
    4858     */
    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;
     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;
     83        }
    8384
    84             return true;
     85        // This will be a new alignee, old alignee (if any) will be lost:
     86        if (algnSeg != null) {
     87            algnSeg.destroy();
    8588        }
    8689
     90        // Update alignee
     91        algnSeg = tmpAlgnSeg;
     92        return true;
    8793    }
    8894
    8995    /**
     
    9399     */
    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;
     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;
     117        }
    122118
     119        // This will be a new reference, old reference (if any) will be lost:
     120        if (refSeg != null) {
     121            refSeg.destroy();
    123122        }
    124123
     124        // Update reference
     125        refSeg = tmpRefSeg;
     126        return true;
    125127    }
    126128
    127129    /**
     
    158160        return refSeg;
    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}