Ignore:
Timestamp:
2009-07-26T17:03:00+02:00 (15 years ago)
Author:
Gubaer
Message:

improved deleting relations

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/command/DeleteCommand.java

    r1838 r1856  
    3434import org.openstreetmap.josm.gui.ExtendedDialog;
    3535import org.openstreetmap.josm.gui.PrimitiveNameFormatter;
     36import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    3637import org.openstreetmap.josm.tools.ImageProvider;
    3738
     
    6364    }
    6465
    65     @Override public boolean executeCommand() {
     66    /**
     67     * Constructor for a single data item. Use the collection constructor to delete multiple
     68     * objects.
     69     *
     70     * @param layer the layer context for deleting this primitive
     71     * @param data the primitive to delete
     72     */
     73    public DeleteCommand(OsmDataLayer layer, OsmPrimitive data) {
     74        super(layer);
     75        this.toDelete = Collections.singleton(data);
     76    }
     77
     78    /**
     79     * Constructor for a collection of data to be deleted in the context of
     80     * a specific layer
     81     *
     82     * @param layer the layer context for deleting these primitives
     83     * @param data the primitives to delete
     84     */
     85    public DeleteCommand(OsmDataLayer layer, Collection<? extends OsmPrimitive> data) {
     86        super(layer);
     87        this.toDelete = data;
     88    }
     89
     90    @Override
     91    public boolean executeCommand() {
    6692        super.executeCommand();
    6793        for (OsmPrimitive osm : toDelete) {
     
    7197    }
    7298
    73     @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted,
     99    @Override
     100    public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted,
    74101            Collection<OsmPrimitive> added) {
    75102        deleted.addAll(toDelete);
    76103    }
    77104
    78     @Override public MutableTreeNode description() {
     105    @Override
     106    public MutableTreeNode description() {
    79107        if (toDelete.size() == 1) {
    80108            OsmPrimitive primitive = toDelete.iterator().next();
    81             return new DefaultMutableTreeNode(
    82                     new JLabel(
    83                             tr("Delete {1} {0}",
    84                                     new PrimitiveNameFormatter().getName(primitive),
    85                                     OsmPrimitiveType.from(primitive).getLocalizedDisplayNameSingular()
    86                             ),
    87                             ImageProvider.get(OsmPrimitiveType.from(primitive)),
    88                             JLabel.HORIZONTAL));
     109            return new DefaultMutableTreeNode(new JLabel(tr("Delete {1} {0}", new PrimitiveNameFormatter()
     110            .getName(primitive), OsmPrimitiveType.from(primitive).getLocalizedDisplayNameSingular()),
     111            ImageProvider.get(OsmPrimitiveType.from(primitive)), JLabel.HORIZONTAL));
    89112        }
    90113
     
    106129                cname, cnamem, toDelete.size())), ImageProvider.get("data", apiname), JLabel.HORIZONTAL));
    107130        for (OsmPrimitive osm : toDelete) {
    108             root.add(new DefaultMutableTreeNode(
    109                     new JLabel(
    110                             new PrimitiveNameFormatter().getName(osm),
    111                             ImageProvider.get(OsmPrimitiveType.from(osm)),
    112                             JLabel.HORIZONTAL)
    113             )
    114             );
     131            root.add(new DefaultMutableTreeNode(new JLabel(new PrimitiveNameFormatter().getName(osm), ImageProvider
     132                    .get(OsmPrimitiveType.from(osm)), JLabel.HORIZONTAL)));
    115133        }
    116134        return root;
     
    119137    /**
    120138     * Delete the primitives and everything they reference.
    121      *
     139     * 
    122140     * If a node is deleted, the node and all ways and relations the node is part of are deleted as
    123141     * well.
    124      *
     142     * 
    125143     * If a way is deleted, all relations the way is member of are also deleted.
    126      *
     144     * 
    127145     * If a way is deleted, only the way and no nodes are deleted.
    128      *
     146     * 
    129147     * @param selection The list of all object to be deleted.
    130148     * @return command A command to perform the deletions, or null of there is nothing to delete.
    131149     */
    132     public static Command deleteWithReferences(Collection<? extends OsmPrimitive> selection) {
    133         CollectBackReferencesVisitor v = new CollectBackReferencesVisitor(Main.main.getCurrentDataSet());
     150    public static Command deleteWithReferences(OsmDataLayer layer, Collection<? extends OsmPrimitive> selection) {
     151        CollectBackReferencesVisitor v = new CollectBackReferencesVisitor(layer.data);
    134152        for (OsmPrimitive osm : selection) {
    135153            osm.visit(v);
     
    138156        if (v.data.isEmpty())
    139157            return null;
    140         if (!checkAndConfirmOutlyingDeletes(v.data))
     158        if (!checkAndConfirmOutlyingDeletes(layer,v.data))
    141159            return null;
    142         return new DeleteCommand(v.data);
     160        return new DeleteCommand(layer,v.data);
    143161    }
    144162
     
    153171        }
    154172        if (role.length() > 0)
    155             return new ExtendedDialog(
    156                     Main.parent,
    157                     tr("Conflicting relation"),
    158                     tr("Selection \"{0}\" is used by relation \"{1}\" with role {2}.\nDelete from relation?",
    159                             formatter.getName(osm), formatter.getName(ref), role),
    160                             new String[] {tr("Delete from relation"), tr("Cancel")},
    161                             new String[] {"dialogs/delete.png", "cancel.png"}).getValue();
     173            return new ExtendedDialog(Main.parent, tr("Conflicting relation"), tr(
     174                    "Selection \"{0}\" is used by relation \"{1}\" with role {2}.\nDelete from relation?", formatter
     175                    .getName(osm), formatter.getName(ref), role), new String[] { tr("Delete from relation"),
     176                tr("Cancel") }, new String[] { "dialogs/delete.png", "cancel.png" }).getValue();
    162177        else
    163             return new ExtendedDialog(Main.parent,
    164                     tr("Conflicting relation"),
    165                     tr("Selection \"{0}\" is used by relation \"{1}\".\nDelete from relation?",
    166                             formatter.getName(osm), formatter.getName(ref)),
    167                             new String[] {tr("Delete from relation"), tr("Cancel")},
    168                             new String[] {"dialogs/delete.png", "cancel.png"}).getValue();
    169     }
    170 
    171     public static Command delete(Collection<? extends OsmPrimitive> selection) {
    172         return delete(selection, true);
     178            return new ExtendedDialog(Main.parent, tr("Conflicting relation"), tr(
     179                    "Selection \"{0}\" is used by relation \"{1}\".\nDelete from relation?", formatter.getName(osm),
     180                    formatter.getName(ref)), new String[] { tr("Delete from relation"), tr("Cancel") }, new String[] {
     181                "dialogs/delete.png", "cancel.png" }).getValue();
     182    }
     183
     184    public static Command delete(OsmDataLayer layer, Collection<? extends OsmPrimitive> selection) {
     185        return delete(layer, selection, true);
     186    }
     187
     188    /**
     189     * Replies the collection of nodes referred to by primitives in <code>primitivesToDelete</code> which
     190     * can be deleted too. A node can be deleted if
     191     * <ul>
     192     *    <li>it is untagged (see {@see Node#isTagged()}</li>
     193     *    <li>it is not referred to by other primitives outside of  <code>primitivesToDelete</code></li>
     194     * <ul>
     195     * @param layer  the layer in whose context primitives are deleted
     196     * @param primitivesToDelete  the primitives to delete
     197     * @return the collection of nodes referred to by primitives in <code>primitivesToDelete</code> which
     198     * can be deleted too
     199     */
     200    protected static Collection<Node> computeNodesToDelete(OsmDataLayer layer, Collection<OsmPrimitive> primitivesToDelete) {
     201        Collection<Node> nodesToDelete = new HashSet<Node>();
     202        for (OsmPrimitive osm : primitivesToDelete) {
     203            if (! (osm instanceof Way) ) {
     204                continue;
     205            }
     206            for (Node n : ((Way) osm).nodes) {
     207                if (n.isTagged()) {
     208                    continue;
     209                }
     210                CollectBackReferencesVisitor v = new CollectBackReferencesVisitor(layer.data, false);
     211                n.visit(v);
     212                v.data.removeAll(primitivesToDelete);
     213                if (v.data.isEmpty()) {
     214                    nodesToDelete.add(n);
     215                }
     216            }
     217        }
     218        return nodesToDelete;
    173219    }
    174220
    175221    /**
    176222     * Try to delete all given primitives.
    177      *
     223     * 
    178224     * If a node is used by a way, it's removed from that way. If a node or a way is used by a
    179225     * relation, inform the user and do not delete.
    180      *
     226     * 
    181227     * If this would cause ways with less than 2 nodes to be created, delete these ways instead. If
    182228     * they are part of a relation, inform the user and do not delete.
    183      *
     229     *
     230     * @param layer the {@see OsmDataLayer} in whose context a primitive the primitives are deleted
    184231     * @param selection The objects to delete.
    185232     * @param alsoDeleteNodesInWay <code>true</code> if nodes should be deleted as well
    186      * @return command A command to perform the deletions, or null of there is nothing to delete.
    187      */
    188     public static Command delete(Collection<? extends OsmPrimitive> selection, boolean alsoDeleteNodesInWay) {
     233     * @return command a command to perform the deletions, or null if there is nothing to delete.
     234     */
     235    public static Command delete(OsmDataLayer layer, Collection<? extends OsmPrimitive> selection, boolean alsoDeleteNodesInWay) {
    189236        if (selection.isEmpty())
    190237            return null;
    191238
    192         Collection<OsmPrimitive> del = new HashSet<OsmPrimitive>(selection);
     239        Collection<OsmPrimitive> primitivesToDelete = new HashSet<OsmPrimitive>(selection);
    193240        Collection<Way> waysToBeChanged = new HashSet<Way>();
    194241        HashMap<OsmPrimitive, Collection<OsmPrimitive>> relationsToBeChanged = new HashMap<OsmPrimitive, Collection<OsmPrimitive>>();
    195242
    196243        if (alsoDeleteNodesInWay) {
    197             // Delete untagged nodes that are to be unreferenced.
    198             Collection<OsmPrimitive> delNodes = new HashSet<OsmPrimitive>();
    199             for (OsmPrimitive osm : del) {
    200                 if (osm instanceof Way) {
    201                     for (Node n : ((Way) osm).nodes) {
    202                         if (!n.isTagged()) {
    203                             CollectBackReferencesVisitor v = new CollectBackReferencesVisitor(Main.main.getCurrentDataSet(), false);
    204                             n.visit(v);
    205                             v.data.removeAll(del);
    206                             if (v.data.isEmpty()) {
    207                                 delNodes.add(n);
    208                             }
    209                         }
    210                     }
    211                 }
    212             }
    213             del.addAll(delNodes);
    214         }
    215 
    216         if (!checkAndConfirmOutlyingDeletes(del))
     244            // delete untagged nodes only referenced by primitives in primitivesToDelete,
     245            // too
     246            Collection<Node> nodesToDelete = computeNodesToDelete(layer, primitivesToDelete);
     247            primitivesToDelete.addAll(nodesToDelete);
     248        }
     249
     250        if (!checkAndConfirmOutlyingDeletes(layer,primitivesToDelete))
    217251            return null;
    218252
    219         for (OsmPrimitive osm : del) {
    220             CollectBackReferencesVisitor v = new CollectBackReferencesVisitor(Main.main.getCurrentDataSet(), false);
     253        for (OsmPrimitive osm : primitivesToDelete) {
     254            CollectBackReferencesVisitor v = new CollectBackReferencesVisitor(layer.data, false);
    221255            osm.visit(v);
    222256            for (OsmPrimitive ref : v.data) {
    223                 if (del.contains(ref)) {
     257                if (primitivesToDelete.contains(ref)) {
    224258                    continue;
    225259                }
     
    244278        for (Way w : waysToBeChanged) {
    245279            Way wnew = new Way(w);
    246             wnew.removeNodes(del);
     280            wnew.removeNodes(primitivesToDelete);
    247281            if (wnew.nodes.size() < 2) {
    248                 del.add(w);
    249 
    250                 CollectBackReferencesVisitor v = new CollectBackReferencesVisitor(Main.main.getCurrentDataSet(), false);
     282                primitivesToDelete.add(w);
     283
     284                CollectBackReferencesVisitor v = new CollectBackReferencesVisitor(layer.data, false);
    251285                w.visit(v);
    252286                for (OsmPrimitive ref : v.data) {
    253                     if (del.contains(ref)) {
     287                    if (primitivesToDelete.contains(ref)) {
    254288                        continue;
    255289                    }
     
    296330        // deleted way is saved (or sent to the API) with a dangling reference to a node
    297331        // Example:
    298         //  <node id='2' action='delete' visible='true' version='1' ... />
    299         //  <node id='1' action='delete' visible='true' version='1' ... />
    300         //  <!-- missing node with id -1 because new deleted nodes are not persisted -->
    301         //   <way id='3' action='delete' visible='true' version='1'>
    302         //     <nd ref='1' />
    303         //     <nd ref='-1' /> <!-- heres the problem -->
    304         //     <nd ref='2' />
    305         //   </way>
    306         for (OsmPrimitive primitive : del) {
    307             if (! (primitive instanceof Way)) {
     332        // <node id='2' action='delete' visible='true' version='1' ... />
     333        // <node id='1' action='delete' visible='true' version='1' ... />
     334        // <!-- missing node with id -1 because new deleted nodes are not persisted -->
     335        // <way id='3' action='delete' visible='true' version='1'>
     336        // <nd ref='1' />
     337        // <nd ref='-1' /> <!-- heres the problem -->
     338        // <nd ref='2' />
     339        // </way>
     340        for (OsmPrimitive primitive : primitivesToDelete) {
     341            if (!(primitive instanceof Way)) {
    308342                continue;
    309343            }
    310             Way w = (Way)primitive;
     344            Way w = (Way) primitive;
    311345            if (w.id == 0) { // new ways with id == 0 are fine,
    312                 continue;    // process existing ways only
     346                continue; // process existing ways only
    313347            }
    314348            Way wnew = new Way(w);
     
    317351            // nodes ...
    318352            for (Node n : wnew.nodes) {
    319                 if (n.id == 0 && del.contains(n)) {
     353                if (n.id == 0 && primitivesToDelete.contains(n)) {
    320354                    nodesToStrip.add(n);
    321355                }
     
    325359            wnew.nodes.removeAll(nodesToStrip);
    326360            if (!nodesToStrip.isEmpty()) {
    327                 cmds.add(new ChangeCommand(w,wnew));
    328             }
    329         }
    330 
    331         if (!del.isEmpty()) {
    332             cmds.add(new DeleteCommand(del));
     361                cmds.add(new ChangeCommand(w, wnew));
     362            }
     363        }
     364
     365        if (!primitivesToDelete.isEmpty()) {
     366            cmds.add(new DeleteCommand(layer,primitivesToDelete));
    333367        }
    334368
     
    336370    }
    337371
    338     public static Command deleteWaySegment(WaySegment ws) {
     372    public static Command deleteWaySegment(OsmDataLayer layer, WaySegment ws) {
    339373        List<Node> n1 = new ArrayList<Node>(), n2 = new ArrayList<Node>();
    340374
     
    343377
    344378        if (n1.size() < 2 && n2.size() < 2)
    345             return new DeleteCommand(Collections.singleton(ws.way));
     379            return new DeleteCommand(layer, Collections.singleton(ws.way));
    346380
    347381        Way wnew = new Way(ws.way);
     
    372406
    373407    /**
    374      * Check whether user is about to delete data outside of the download area.
    375      * Request confirmation if he is.
    376      */
    377     private static boolean checkAndConfirmOutlyingDeletes(Collection<OsmPrimitive> del) {
    378         Area a = Main.main.getCurrentDataSet().getDataSourceArea();
     408     * Check whether user is about to delete data outside of the download area. Request confirmation
     409     * if he is.
     410     *
     411     * @param layer the layer in whose context data is deleted
     412     * @param primitivesToDelete the primitives to delete
     413     * @return true, if deleting outlying primitives is OK; false, otherwise
     414     */
     415    private static boolean checkAndConfirmOutlyingDeletes(OsmDataLayer layer, Collection<OsmPrimitive> primitivesToDelete) {
     416        Area a = layer.data.getDataSourceArea();
    379417        if (a != null) {
    380             for (OsmPrimitive osm : del) {
     418            for (OsmPrimitive osm : primitivesToDelete) {
    381419                if (osm instanceof Node && osm.id != 0) {
    382420                    Node n = (Node) osm;
     
    385423                        msg.add(new JLabel(
    386424                                "<html>" +
    387                                 // leave message in one tr() as there is a grammatical connection.
    388                                 tr("You are about to delete nodes outside of the area you have downloaded." +
    389                                         "<br>" +
    390                                         "This can cause problems because other objects (that you don't see) might use them." +
    391                                         "<br>" +
    392                                 "Do you really want to delete?") + "</html>"));
     425                                // leave message in one tr() as there is a grammatical
     426                                // connection.
     427                                tr("You are about to delete nodes outside of the area you have downloaded."
     428                                        + "<br>"
     429                                        + "This can cause problems because other objects (that you don't see) might use them."
     430                                        + "<br>" + "Do you really want to delete?") + "</html>"));
    393431                        return ConditionalOptionPaneUtil.showConfirmationDialog(
    394432                                "delete_outside_nodes",
Note: See TracChangeset for help on using the changeset viewer.