Changeset 12688 in josm for trunk/src/org


Ignore:
Timestamp:
2017-08-28T18:48:58+02:00 (7 years ago)
Author:
Don-vip
Message:

see #15182 - refactor PurgeAction/PurgeCommand to avoid unneeded dependence on action

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

Legend:

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

    r12641 r12688  
    1313import java.util.ArrayList;
    1414import java.util.Collection;
    15 import java.util.HashSet;
    1615import java.util.List;
    17 import java.util.Set;
    1816
    1917import javax.swing.AbstractAction;
     
    3230import org.openstreetmap.josm.command.PurgeCommand;
    3331import org.openstreetmap.josm.data.osm.DataSet;
    34 import org.openstreetmap.josm.data.osm.Node;
    3532import org.openstreetmap.josm.data.osm.OsmPrimitive;
    36 import org.openstreetmap.josm.data.osm.Relation;
    37 import org.openstreetmap.josm.data.osm.RelationMember;
    38 import org.openstreetmap.josm.data.osm.Way;
    3933import org.openstreetmap.josm.gui.ConditionalOptionPaneUtil;
    4034import org.openstreetmap.josm.gui.MainApplication;
     
    6458    protected boolean modified;
    6559
    66     protected transient Set<OsmPrimitive> toPurge;
    67     /**
    68      * finally, contains all objects that are purged
    69      */
    70     protected transient Set<OsmPrimitive> toPurgeChecked;
    71     /**
    72      * Subset of toPurgeChecked. Marks primitives that remain in the dataset, but incomplete.
    73      */
    74     protected transient Set<OsmPrimitive> makeIncomplete;
    7560    /**
    7661     * Subset of toPurgeChecked. Those that have not been in the selection.
     
    8267     */
    8368    public PurgeAction() {
    84         this(true);
    85     }
    86 
    87     /**
    88      * Constructs a new {@code PurgeAction} with optional shortcut.
    89      * @param addShortcut controls whether the shortcut should be registered or not, as for toolbar registration
    90      * @since 11611
    91      */
    92     public PurgeAction(boolean addShortcut) {
    9369        /* translator note: other expressions for "purge" might be "forget", "clean", "obliterate", "prune" */
    94         super(tr("Purge..."), "purge", tr("Forget objects but do not delete them on server when uploading."), addShortcut ?
    95                 Shortcut.registerShortcut("system:purge", tr("Edit: {0}", tr("Purge")), KeyEvent.VK_P, Shortcut.CTRL_SHIFT)
    96                 : null, addShortcut);
     70        super(tr("Purge..."), "purge", tr("Forget objects but do not delete them on server when uploading."),
     71                Shortcut.registerShortcut("system:purge", tr("Edit: {0}", tr("Purge")), KeyEvent.VK_P, Shortcut.CTRL_SHIFT),
     72                true);
    9773        putValue("help", HelpUtil.ht("/Action/Purge"));
    9874    }
     
    141117    public PurgeCommand getPurgeCommand(Collection<OsmPrimitive> sel) {
    142118        layer = getLayerManager().getEditLayer();
    143 
    144         toPurge = new HashSet<>(sel);
    145119        toPurgeAdditionally = new ArrayList<>();
    146         toPurgeChecked = new HashSet<>();
    147 
    148         // Add referrer, unless the object to purge is not new and the parent is a relation
    149         Set<OsmPrimitive> toPurgeRecursive = new HashSet<>();
    150         while (!toPurge.isEmpty()) {
    151 
    152             for (OsmPrimitive osm: toPurge) {
    153                 for (OsmPrimitive parent: osm.getReferrers()) {
    154                     if (toPurge.contains(parent) || toPurgeChecked.contains(parent) || toPurgeRecursive.contains(parent)) {
    155                         continue;
    156                     }
    157                     if (parent instanceof Way || (parent instanceof Relation && osm.isNew())) {
    158                         toPurgeAdditionally.add(parent);
    159                         toPurgeRecursive.add(parent);
    160                     }
    161                 }
    162                 toPurgeChecked.add(osm);
    163             }
    164             toPurge = toPurgeRecursive;
    165             toPurgeRecursive = new HashSet<>();
    166         }
    167 
    168         makeIncomplete = new HashSet<>();
    169 
    170         // Find the objects that will be incomplete after purging.
    171         // At this point, all parents of new to-be-purged primitives are
    172         // also to-be-purged and
    173         // all parents of not-new to-be-purged primitives are either
    174         // to-be-purged or of type relation.
    175         TOP:
    176             for (OsmPrimitive child : toPurgeChecked) {
    177                 if (child.isNew()) {
    178                     continue;
    179                 }
    180                 for (OsmPrimitive parent : child.getReferrers()) {
    181                     if (parent instanceof Relation && !toPurgeChecked.contains(parent)) {
    182                         makeIncomplete.add(child);
    183                         continue TOP;
    184                     }
    185                 }
    186             }
    187 
    188         // Add untagged way nodes. Do not add nodes that have other referrers not yet to-be-purged.
    189         if (Main.pref.getBoolean("purge.add_untagged_waynodes", true)) {
    190             Set<OsmPrimitive> wayNodes = new HashSet<>();
    191             for (OsmPrimitive osm : toPurgeChecked) {
    192                 if (osm instanceof Way) {
    193                     Way w = (Way) osm;
    194                     NODE:
    195                         for (Node n : w.getNodes()) {
    196                             if (n.isTagged() || toPurgeChecked.contains(n)) {
    197                                 continue;
    198                             }
    199                             for (OsmPrimitive ref : n.getReferrers()) {
    200                                 if (ref != w && !toPurgeChecked.contains(ref)) {
    201                                     continue NODE;
    202                                 }
    203                             }
    204                             wayNodes.add(n);
    205                         }
    206                 }
    207             }
    208             toPurgeChecked.addAll(wayNodes);
    209             toPurgeAdditionally.addAll(wayNodes);
    210         }
    211 
    212         if (Main.pref.getBoolean("purge.add_relations_with_only_incomplete_members", true)) {
    213             Set<Relation> relSet = new HashSet<>();
    214             for (OsmPrimitive osm : toPurgeChecked) {
    215                 for (OsmPrimitive parent : osm.getReferrers()) {
    216                     if (parent instanceof Relation
    217                             && !(toPurgeChecked.contains(parent))
    218                             && hasOnlyIncompleteMembers((Relation) parent, toPurgeChecked, relSet)) {
    219                         relSet.add((Relation) parent);
    220                     }
    221                 }
    222             }
    223 
    224             // Add higher level relations (list gets extended while looping over it)
    225             List<Relation> relLst = new ArrayList<>(relSet);
    226             for (int i = 0; i < relLst.size(); ++i) { // foreach loop not applicable since list gets extended while looping over it
    227                 for (OsmPrimitive parent : relLst.get(i).getReferrers()) {
    228                     if (!(toPurgeChecked.contains(parent))
    229                             && hasOnlyIncompleteMembers((Relation) parent, toPurgeChecked, relLst)) {
    230                         relLst.add((Relation) parent);
    231                     }
    232                 }
    233             }
    234             relSet = new HashSet<>(relLst);
    235             toPurgeChecked.addAll(relSet);
    236             toPurgeAdditionally.addAll(relSet);
    237         }
    238 
    239         modified = false;
    240         for (OsmPrimitive osm : toPurgeChecked) {
    241             if (osm.isModified()) {
    242                 modified = true;
    243                 break;
    244             }
    245         }
    246 
    247         return layer != null ? new PurgeCommand(layer, toPurgeChecked, makeIncomplete) :
    248             new PurgeCommand(toPurgeChecked.iterator().next().getDataSet(), toPurgeChecked, makeIncomplete);
     120        PurgeCommand cmd = PurgeCommand.build(layer, sel, toPurgeAdditionally);
     121        modified = cmd.getParticipatingPrimitives().stream().anyMatch(OsmPrimitive::isModified);
     122        return cmd;
    249123    }
    250124
     
    323197        setEnabled(selection != null && !selection.isEmpty());
    324198    }
    325 
    326     private static boolean hasOnlyIncompleteMembers(
    327             Relation r, Collection<OsmPrimitive> toPurge, Collection<? extends OsmPrimitive> moreToPurge) {
    328         for (RelationMember m : r.getMembers()) {
    329             if (!m.getMember().isIncomplete() && !toPurge.contains(m.getMember()) && !moreToPurge.contains(m.getMember()))
    330                 return false;
    331         }
    332         return true;
    333     }
    334199}
  • trunk/src/org/openstreetmap/josm/command/PurgeCommand.java

    r12672 r12688  
    1616import javax.swing.Icon;
    1717
     18import org.openstreetmap.josm.Main;
    1819import org.openstreetmap.josm.data.conflict.Conflict;
    1920import org.openstreetmap.josm.data.conflict.ConflictCollection;
     
    2627import org.openstreetmap.josm.data.osm.Relation;
    2728import org.openstreetmap.josm.data.osm.RelationData;
     29import org.openstreetmap.josm.data.osm.RelationMember;
    2830import org.openstreetmap.josm.data.osm.Storage;
    2931import org.openstreetmap.josm.data.osm.Way;
     
    309311                Objects.equals(purgedConflicts, that.purgedConflicts);
    310312    }
     313
     314    /**
     315     * Creates a new {@code PurgeCommand} to purge selected OSM primitives.
     316     * @param layer optional osm data layer, can be null
     317     * @param sel selected OSM primitives
     318     * @param toPurgeAdditionally optional list that will be filled with primitives to be purged that have not been in the selection
     319     * @return command to purge selected OSM primitives
     320     * @since 12688
     321     */
     322    public static PurgeCommand build(OsmDataLayer layer, Collection<OsmPrimitive> sel, List<OsmPrimitive> toPurgeAdditionally) {
     323        Set<OsmPrimitive> toPurge = new HashSet<>(sel);
     324        // finally, contains all objects that are purged
     325        Set<OsmPrimitive> toPurgeChecked = new HashSet<>();
     326
     327        // Add referrer, unless the object to purge is not new and the parent is a relation
     328        Set<OsmPrimitive> toPurgeRecursive = new HashSet<>();
     329        while (!toPurge.isEmpty()) {
     330
     331            for (OsmPrimitive osm: toPurge) {
     332                for (OsmPrimitive parent: osm.getReferrers()) {
     333                    if (toPurge.contains(parent) || toPurgeChecked.contains(parent) || toPurgeRecursive.contains(parent)) {
     334                        continue;
     335                    }
     336                    if (parent instanceof Way || (parent instanceof Relation && osm.isNew())) {
     337                        if (toPurgeAdditionally != null) {
     338                            toPurgeAdditionally.add(parent);
     339                        }
     340                        toPurgeRecursive.add(parent);
     341                    }
     342                }
     343                toPurgeChecked.add(osm);
     344            }
     345            toPurge = toPurgeRecursive;
     346            toPurgeRecursive = new HashSet<>();
     347        }
     348
     349        // Subset of toPurgeChecked. Marks primitives that remain in the dataset, but incomplete.
     350        Set<OsmPrimitive> makeIncomplete = new HashSet<>();
     351
     352        // Find the objects that will be incomplete after purging.
     353        // At this point, all parents of new to-be-purged primitives are
     354        // also to-be-purged and
     355        // all parents of not-new to-be-purged primitives are either
     356        // to-be-purged or of type relation.
     357        TOP:
     358            for (OsmPrimitive child : toPurgeChecked) {
     359                if (child.isNew()) {
     360                    continue;
     361                }
     362                for (OsmPrimitive parent : child.getReferrers()) {
     363                    if (parent instanceof Relation && !toPurgeChecked.contains(parent)) {
     364                        makeIncomplete.add(child);
     365                        continue TOP;
     366                    }
     367                }
     368            }
     369
     370        // Add untagged way nodes. Do not add nodes that have other referrers not yet to-be-purged.
     371        if (Main.pref.getBoolean("purge.add_untagged_waynodes", true)) {
     372            Set<OsmPrimitive> wayNodes = new HashSet<>();
     373            for (OsmPrimitive osm : toPurgeChecked) {
     374                if (osm instanceof Way) {
     375                    Way w = (Way) osm;
     376                    NODE:
     377                        for (Node n : w.getNodes()) {
     378                            if (n.isTagged() || toPurgeChecked.contains(n)) {
     379                                continue;
     380                            }
     381                            for (OsmPrimitive ref : n.getReferrers()) {
     382                                if (ref != w && !toPurgeChecked.contains(ref)) {
     383                                    continue NODE;
     384                                }
     385                            }
     386                            wayNodes.add(n);
     387                        }
     388                }
     389            }
     390            toPurgeChecked.addAll(wayNodes);
     391            if (toPurgeAdditionally != null) {
     392                toPurgeAdditionally.addAll(wayNodes);
     393            }
     394        }
     395
     396        if (Main.pref.getBoolean("purge.add_relations_with_only_incomplete_members", true)) {
     397            Set<Relation> relSet = new HashSet<>();
     398            for (OsmPrimitive osm : toPurgeChecked) {
     399                for (OsmPrimitive parent : osm.getReferrers()) {
     400                    if (parent instanceof Relation
     401                            && !(toPurgeChecked.contains(parent))
     402                            && hasOnlyIncompleteMembers((Relation) parent, toPurgeChecked, relSet)) {
     403                        relSet.add((Relation) parent);
     404                    }
     405                }
     406            }
     407
     408            // Add higher level relations (list gets extended while looping over it)
     409            List<Relation> relLst = new ArrayList<>(relSet);
     410            for (int i = 0; i < relLst.size(); ++i) { // foreach loop not applicable since list gets extended while looping over it
     411                for (OsmPrimitive parent : relLst.get(i).getReferrers()) {
     412                    if (!(toPurgeChecked.contains(parent))
     413                            && hasOnlyIncompleteMembers((Relation) parent, toPurgeChecked, relLst)) {
     414                        relLst.add((Relation) parent);
     415                    }
     416                }
     417            }
     418            relSet = new HashSet<>(relLst);
     419            toPurgeChecked.addAll(relSet);
     420            if (toPurgeAdditionally != null) {
     421                toPurgeAdditionally.addAll(relSet);
     422            }
     423        }
     424
     425        return layer != null ? new PurgeCommand(layer, toPurgeChecked, makeIncomplete)
     426                : new PurgeCommand(toPurgeChecked.iterator().next().getDataSet(), toPurgeChecked, makeIncomplete);
     427    }
     428
     429    private static boolean hasOnlyIncompleteMembers(
     430            Relation r, Collection<OsmPrimitive> toPurge, Collection<? extends OsmPrimitive> moreToPurge) {
     431        for (RelationMember m : r.getMembers()) {
     432            if (!m.getMember().isIncomplete() && !toPurge.contains(m.getMember()) && !moreToPurge.contains(m.getMember()))
     433                return false;
     434        }
     435        return true;
     436    }
    311437}
  • trunk/src/org/openstreetmap/josm/tools/RightAndLefthandTraffic.java

    r12620 r12688  
    2121import org.openstreetmap.josm.actions.JoinAreasAction.JoinAreasResult;
    2222import org.openstreetmap.josm.actions.JoinAreasAction.Multipolygon;
    23 import org.openstreetmap.josm.actions.PurgeAction;
     23import org.openstreetmap.josm.command.PurgeCommand;
    2424import org.openstreetmap.josm.data.coor.LatLon;
    2525import org.openstreetmap.josm.data.osm.DataSet;
     
    104104        }
    105105        // Purge all other ways and relations so dataset only contains lefthand traffic data
    106         new PurgeAction(false).getPurgeCommand(toPurge).executeCommand();
     106        PurgeCommand.build(null, toPurge, null).executeCommand();
    107107        // Combine adjacent countries into a single polygon
    108108        Collection<Way> optimizedWays = new ArrayList<>();
Note: See TracChangeset for help on using the changeset viewer.