Changeset 2521 in josm for trunk/src/org


Ignore:
Timestamp:
2009-11-27T21:46:49+01:00 (14 years ago)
Author:
jttt
Message:

Fixed #3704 Relation memberships are not handled at all when a way is splitted or deleted by deleting a segment, rewritten DeleteAction a bit (delete commands are no longer build in updateCursor())

Location:
trunk/src/org/openstreetmap/josm
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/SplitWayAction.java

    r2412 r2521  
    2828import org.openstreetmap.josm.data.osm.Node;
    2929import org.openstreetmap.josm.data.osm.OsmPrimitive;
     30import org.openstreetmap.josm.data.osm.PrimitiveId;
    3031import org.openstreetmap.josm.data.osm.Relation;
    3132import org.openstreetmap.josm.data.osm.RelationMember;
     
    4748    private Way selectedWay;
    4849    private List<Node> selectedNodes;
     50
     51    public static class SplitWayResult {
     52        private final Command command;
     53        private final List<? extends PrimitiveId> newSelection;
     54
     55        public SplitWayResult(Command command, List<? extends PrimitiveId> newSelection) {
     56            this.command = command;
     57            this.newSelection = newSelection;
     58        }
     59
     60        public Command getCommand() {
     61            return command;
     62        }
     63
     64        public List<? extends PrimitiveId> getNewSelection() {
     65            return newSelection;
     66        }
     67    }
    4968
    5069    /**
     
    267286        //Main.debug("way id: " + selectedWay.id);
    268287
     288        SplitWayResult result = splitWay(selectedWay, wayChunks);
     289        Main.main.undoRedo.add(result.getCommand());
     290        getCurrentDataSet().setSelected(result.getNewSelection());
     291    }
     292
     293    public static SplitWayResult splitWay(Way way, List<List<Node>> wayChunks) {
    269294        // build a list of commands, and also a new selection list
    270295        Collection<Command> commandList = new ArrayList<Command>(wayChunks.size());
    271         Collection<Way> newSelection = new ArrayList<Way>(wayChunks.size());
     296        List<Way> newSelection = new ArrayList<Way>(wayChunks.size());
    272297
    273298        Iterator<List<Node>> chunkIt = wayChunks.iterator();
    274299
    275300        // First, change the original way
    276         Way changedWay = new Way(selectedWay);
     301        Way changedWay = new Way(way);
    277302        changedWay.setNodes(chunkIt.next());
    278         commandList.add(new ChangeCommand(selectedWay, changedWay));
    279         newSelection.add(selectedWay);
     303        commandList.add(new ChangeCommand(way, changedWay));
     304        newSelection.add(way);
    280305
    281306        Collection<Way> newWays = new ArrayList<Way>();
     
    283308        while (chunkIt.hasNext()) {
    284309            Way wayToAdd = new Way();
    285             wayToAdd.setKeys(selectedWay.getKeys());
     310            wayToAdd.setKeys(way.getKeys());
    286311            newWays.add(wayToAdd);
    287312            wayToAdd.setNodes(chunkIt.next());
     
    295320        // now copy all relations to new way also
    296321
    297         for (Relation r : OsmPrimitive.getFilteredList(selectedWay.getReferrers(), Relation.class)) {
     322        for (Relation r : OsmPrimitive.getFilteredList(way.getReferrers(), Relation.class)) {
    298323            if (!r.isUsable()) {
    299324                continue;
     
    308333            for (RelationMember rm : r.getMembers()) {
    309334                if (rm.isWay()) {
    310                     if (rm.getMember() == selectedWay) {
     335                    if (rm.getMember() == way) {
    311336                        if (!("route".equals(type)) && !("multipolygon".equals(type))) {
    312337                            warnme = true;
     
    355380        }
    356381
    357         Main.main.undoRedo.add(
    358                 new SequenceCommand(tr("Split way {0} into {1} parts",
    359                         selectedWay.getDisplayName(DefaultNameFormatter.getInstance()),
    360                         wayChunks.size()),
    361                         commandList));
    362         getCurrentDataSet().setSelected(newSelection);
     382
     383        return new SplitWayResult(new SequenceCommand(tr("Split way {0} into {1} parts",
     384                way.getDisplayName(DefaultNameFormatter.getInstance()),
     385                wayChunks.size()),
     386                commandList), newSelection);
    363387    }
    364388
  • trunk/src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java

    r2512 r2521  
    1313import java.awt.event.KeyEvent;
    1414import java.awt.event.MouseEvent;
    15 import java.util.Collection;
    1615import java.util.Collections;
    17 import java.util.HashSet;
    1816
    1917import org.openstreetmap.josm.Main;
     
    2119import org.openstreetmap.josm.command.DeleteCommand;
    2220import org.openstreetmap.josm.data.osm.Node;
    23 import org.openstreetmap.josm.data.osm.OsmPrimitive;
    2421import org.openstreetmap.josm.data.osm.Relation;
    25 import org.openstreetmap.josm.data.osm.Way;
    2622import org.openstreetmap.josm.data.osm.WaySegment;
    2723import org.openstreetmap.josm.gui.MapFrame;
     
    6359    private MouseEvent oldEvent = null;
    6460
    65     private enum Cursors {
    66         none,
    67         node,
    68         segment,
    69         way_node_only,
    70         way_normal,
    71         way_only;
    72 
    73         private Cursor c = null;
    74         // This loads and caches the cursor for each
     61    private enum DeleteMode {
     62        none("delete"),
     63        segment("delete_segment"),
     64        node("delete_node"),
     65        node_with_references("delete_node"),
     66        way("delete_way_only"),
     67        way_with_references("delete_way_normal"),
     68        way_with_nodes("delete_way_node_only");
     69
     70        private final Cursor c;
     71
     72        private DeleteMode(String cursorName) {
     73            c = ImageProvider.getCursor("normal", cursorName);
     74        }
     75
    7576        public Cursor cursor() {
    76             if(c == null) {
    77                 String nm = "delete_" + this.name().toLowerCase();
    78                 // "None" has no special icon
    79                 nm = nm.equals("delete_none") ? "delete" : nm;
    80                 this.c = ImageProvider.getCursor("normal", nm);
    81             }
    8277            return c;
    8378        }
    8479    }
    85     private Cursors currCursor = Cursors.none;
     80    private DeleteMode currentMode = DeleteMode.none;
     81
     82    private static class DeleteParameters {
     83        DeleteMode mode;
     84        Node nearestNode;
     85        WaySegment nearestSegment;
     86    }
    8687
    8788    /**
     
    110111        try {
    111112            Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.KEY_EVENT_MASK);
    112         } catch (SecurityException ex) {}
    113 
    114         currCursor = Cursors.none;
     113        } catch (SecurityException ex) {
     114            System.out.println(ex);
     115        }
     116
     117        currentMode = DeleteMode.none;
    115118    }
    116119
     
    121124        try {
    122125            Toolkit.getDefaultToolkit().removeAWTEventListener(this);
    123         } catch (SecurityException ex) {}
     126        } catch (SecurityException ex) {
     127            System.out.println(ex);
     128        }
    124129    }
    125130
     
    172177     *
    173178     * @param MouseEvent
    174      * @parm int modifiers
     179     * @param int modifiers
    175180     */
    176181    private void updateCursor(MouseEvent e, int modifiers) {
    177         if (!Main.isDisplayingMapView()) {
    178             return;
    179         }
     182        if (!Main.isDisplayingMapView())
     183            return;
    180184        if(!Main.map.mapView.isActiveLayerVisible() || e == null)
    181185            return;
     
    184188        //cleanOldHighlights();
    185189
    186         Command c = buildDeleteCommands(e, modifiers, true);
    187         if(c == null) {
    188             setCursor(Cursors.none);
    189             return;
    190         }
    191 
    192         Collection<OsmPrimitive> prims = new HashSet<OsmPrimitive>();
    193         Collection<OsmPrimitive> mods = new HashSet<OsmPrimitive>();
    194         c.fillModifiedData(mods, prims, prims);
    195 
    196         if(prims.size() == 0 && mods.size() == 0) {
    197             // Default-Cursor
    198             setCursor(Cursors.none);
    199             return;
    200         }
    201 
    202         // There are no deleted parts if solely a way segment is deleted
    203         // This is no the case when actually deleting only a segment but that
    204         // segment happens to be the whole way. This is an acceptable error
    205         // though
    206         if(prims.size() == 0) {
    207             setCursor(Cursors.segment);
    208         } else if(prims.size() == 1 && prims.toArray()[0] instanceof Node) {
    209             setCursor(Cursors.node);
    210         } else if(prims.size() == 1 && prims.toArray()[0] instanceof Way) {
    211             setCursor(Cursors.way_only);
    212         } else {
    213             // Decide between non-accel click where "useless" nodes are deleted
    214             // and ctrl-click where nodes and ways are deleted
    215             boolean ctrl = (modifiers & ActionEvent.CTRL_MASK) != 0;
    216             if(ctrl) {
    217                 setCursor(Cursors.way_node_only);
    218             } else {
    219                 setCursor(Cursors.way_normal);
    220             }
    221 
    222         }
     190        DeleteParameters parameters = getDeleteParameters(e, modifiers);
     191        setCursor(parameters.mode);
    223192
    224193        // Needs to implement WaySegment highlight first
     
    306275    }
    307276
     277    private DeleteParameters getDeleteParameters(MouseEvent e, int modifiers) {
     278        // Note: CTRL is the only modifier that is checked in MouseMove, don't
     279        // forget updating it there
     280        boolean ctrl = (modifiers & ActionEvent.CTRL_MASK) != 0;
     281        boolean shift = (modifiers & ActionEvent.SHIFT_MASK) != 0;
     282        boolean alt = (modifiers & (ActionEvent.ALT_MASK|InputEvent.ALT_GRAPH_MASK)) != 0;
     283
     284        DeleteParameters result = new DeleteParameters();
     285
     286        result.nearestNode = Main.map.mapView.getNearestNode(e.getPoint());
     287        if (result.nearestNode == null) {
     288            result.nearestSegment = Main.map.mapView.getNearestWaySegment(e.getPoint());
     289            if (result.nearestSegment != null) {
     290                if (shift) {
     291                    result.mode = DeleteMode.segment;
     292                } else if (ctrl) {
     293                    result.mode = DeleteMode.way_with_references;
     294                } else {
     295                    result.mode = alt?DeleteMode.way:DeleteMode.way_with_nodes;
     296                }
     297            } else {
     298                result.mode = DeleteMode.none;
     299            }
     300        } else if (ctrl) {
     301            result.mode = DeleteMode.node_with_references;
     302        } else {
     303            result.mode = DeleteMode.node;
     304        }
     305
     306        return result;
     307    }
     308
    308309    /**
    309310     * This function takes any mouse event argument and builds the list of elements
     
    316317     */
    317318    private Command buildDeleteCommands(MouseEvent e, int modifiers, boolean silent) {
    318         // Note: CTRL is the only modifier that is checked in MouseMove, don't
    319         // forget updating it there
    320         boolean ctrl = (modifiers & ActionEvent.CTRL_MASK) != 0;
    321         boolean shift = (modifiers & ActionEvent.SHIFT_MASK) != 0;
    322         boolean alt = (modifiers & (ActionEvent.ALT_MASK|InputEvent.ALT_GRAPH_MASK)) != 0;
    323 
    324         OsmPrimitive sel = Main.map.mapView.getNearestNode(e.getPoint());
    325         Command c = null;
    326         if (sel == null) {
    327             WaySegment ws = Main.map.mapView.getNearestWaySegment(e.getPoint());
    328             if (ws != null) {
    329                 if (shift) {
    330                     c = DeleteCommand.deleteWaySegment(getEditLayer(),ws);
    331                 } else if (ctrl) {
    332                     c = DeleteCommand.deleteWithReferences(getEditLayer(),Collections.singleton((OsmPrimitive)ws.way),true);
    333                 } else {
    334                     c = DeleteCommand.delete(getEditLayer(),Collections.singleton((OsmPrimitive)ws.way), !alt, silent);
    335                 }
    336             }
    337         } else if (ctrl) {
    338             c = DeleteCommand.deleteWithReferences(getEditLayer(),Collections.singleton(sel));
    339         } else {
    340             c = DeleteCommand.delete(getEditLayer(),Collections.singleton(sel), !alt, silent);
    341         }
    342 
    343         return c;
     319        DeleteParameters parameters = getDeleteParameters(e, modifiers);
     320        switch (parameters.mode) {
     321        case node:
     322            return DeleteCommand.delete(getEditLayer(),Collections.singleton(parameters.nearestNode), false, silent);
     323        case node_with_references:
     324            return DeleteCommand.deleteWithReferences(getEditLayer(),Collections.singleton(parameters.nearestNode));
     325        case segment:
     326            return DeleteCommand.deleteWaySegment(getEditLayer(), parameters.nearestSegment);
     327        case way:
     328            return DeleteCommand.delete(getEditLayer(), Collections.singleton(parameters.nearestSegment.way), false, silent);
     329        case way_with_nodes:
     330            return DeleteCommand.delete(getEditLayer(), Collections.singleton(parameters.nearestSegment.way), true, silent);
     331        case way_with_references:
     332            return DeleteCommand.deleteWithReferences(getEditLayer(),Collections.singleton(parameters.nearestSegment.way),true);
     333        default:
     334            return null;
     335        }
    344336    }
    345337
     
    351343     * @param c
    352344     */
    353     private void setCursor(final Cursors c) {
    354         if(currCursor.equals(c) || (!drawTargetCursor && currCursor.equals(Cursors.none)))
     345    private void setCursor(final DeleteMode c) {
     346        if(currentMode.equals(c) || (!drawTargetCursor && currentMode.equals(DeleteMode.none)))
    355347            return;
    356348        try {
     
    366358                }
    367359            });
    368             currCursor = c;
     360            currentMode = c;
    369361        } catch(Exception e) {}
    370362    }
  • trunk/src/org/openstreetmap/josm/command/DeleteCommand.java

    r2512 r2521  
    2323
    2424import org.openstreetmap.josm.Main;
     25import org.openstreetmap.josm.actions.SplitWayAction;
    2526import org.openstreetmap.josm.data.osm.BackreferencedDataSet;
    2627import org.openstreetmap.josm.data.osm.Node;
     
    253254    protected static Collection<Node> computeNodesToDelete(BackreferencedDataSet backreferences, OsmDataLayer layer, Collection<OsmPrimitive> primitivesToDelete) {
    254255        Collection<Node> nodesToDelete = new HashSet<Node>();
    255         //CollectBackReferencesVisitor v = new CollectBackReferencesVisitor(layer.data, false);
    256256        for (Way way : OsmPrimitive.getFilteredList(primitivesToDelete, Way.class)) {
    257257            for (Node n : way.getNodes()) {
     
    259259                    continue;
    260260                }
    261                 //v.initialize();
    262                 //n.visit(v);
    263261                Collection<OsmPrimitive> referringPrimitives = backreferences.getParents(n);
    264262                referringPrimitives.removeAll(primitivesToDelete);
     
    385383    public static Command deleteWaySegment(OsmDataLayer layer, WaySegment ws) {
    386384        if (ws.way.getNodesCount() < 3)
    387             return new DeleteCommand(layer, Collections.singleton(ws.way));
     385            return delete(layer, Collections.singleton(ws.way));
    388386
    389387        if (ws.way.firstNode() == ws.way.lastNode()) {
     
    416414            return new ChangeCommand(ws.way, wnew);
    417415        } else {
    418             Collection<Command> cmds = new LinkedList<Command>();
    419 
    420             wnew.setNodes(n1);
    421             cmds.add(new ChangeCommand(ws.way, wnew));
    422 
    423             Way wnew2 = new Way();
    424             wnew2.setKeys(wnew.getKeys());
    425             wnew2.setNodes(n2);
    426             cmds.add(new AddCommand(wnew2));
    427 
    428             // FIXME: relation memberships are not handled
    429 
    430             return new SequenceCommand(tr("Split way segment"), cmds);
     416            List<List<Node>> chunks = new ArrayList<List<Node>>(2);
     417            chunks.add(n1);
     418            chunks.add(n2);
     419            return SplitWayAction.splitWay(ws.way, chunks).getCommand();
    431420        }
    432421    }
  • trunk/src/org/openstreetmap/josm/data/osm/DatasetConsistencyTest.java

    r2501 r2521  
    2626    private void checkReferrers() {
    2727        for (Way way:dataSet.getWays()) {
    28             for (Node n:way.getNodes()) {
    29                 if (!n.getReferrers().contains(way)) {
    30                     writer.println(String.format("%s is part of %s but is not in referrers", n, way));
     28            if (!way.isDeleted()) {
     29                for (Node n:way.getNodes()) {
     30                    if (!n.getReferrers().contains(way)) {
     31                        writer.println(String.format("%s is part of %s but is not in referrers", n, way));
     32                    }
    3133                }
    3234            }
     
    3436
    3537        for (Relation relation:dataSet.getRelations()) {
    36             for (RelationMember m:relation.getMembers()) {
    37                 if (!m.getMember().getReferrers().contains(relation)) {
    38                     writer.println(String.format("%s is part of %s but is not in referrers", m.getMember(), relation));
     38            if (!relation.isDeleted()) {
     39                for (RelationMember m:relation.getMembers()) {
     40                    if (!m.getMember().getReferrers().contains(relation)) {
     41                        writer.println(String.format("%s is part of %s but is not in referrers", m.getMember(), relation));
     42                    }
    3943                }
    4044            }
Note: See TracChangeset for help on using the changeset viewer.