Ticket #19885: 19885-wip.patch

File 19885-wip.patch, 19.5 KB (added by GerdP, 4 years ago)
  • src/org/openstreetmap/josm/actions/CreateCircleAction.java

     
    1515import javax.swing.JOptionPane;
    1616
    1717import org.openstreetmap.josm.command.AddCommand;
    18 import org.openstreetmap.josm.command.ChangeCommand;
     18import org.openstreetmap.josm.command.ChangeNodesCommand;
    1919import org.openstreetmap.josm.command.Command;
    2020import org.openstreetmap.josm.command.SequenceCommand;
    2121import org.openstreetmap.josm.data.UndoRedoHandler;
     
    233233            newWay.setNodes(nodesToAdd);
    234234            cmds.add(new AddCommand(ds, newWay));
    235235        } else {
    236             Way newWay = new Way(existingWay);
    237             newWay.setNodes(nodesToAdd);
    238             cmds.add(new ChangeCommand(ds, existingWay, newWay));
     236            cmds.add(new ChangeNodesCommand(ds, existingWay, nodesToAdd));
    239237        }
    240238
    241239        UndoRedoHandler.getInstance().add(new SequenceCommand(tr("Create Circle"), cmds));
  • src/org/openstreetmap/josm/actions/SimplifyWayAction.java

     
    3030import javax.swing.event.ChangeEvent;
    3131import javax.swing.event.ChangeListener;
    3232
    33 import org.openstreetmap.josm.command.ChangeCommand;
     33import org.openstreetmap.josm.command.ChangeNodesCommand;
    3434import org.openstreetmap.josm.command.Command;
    3535import org.openstreetmap.josm.command.DeleteCommand;
    3636import org.openstreetmap.josm.command.SequenceCommand;
     
    410410        if (delNodes.isEmpty()) return null;
    411411
    412412        Collection<Command> cmds = new LinkedList<>();
    413         Way newWay = new Way(w);
    414         newWay.setNodes(newNodes);
    415         cmds.add(new ChangeCommand(w, newWay));
     413        cmds.add(new ChangeNodesCommand(w, newNodes));
    416414        cmds.add(new DeleteCommand(w.getDataSet(), delNodes));
    417415        w.getDataSet().clearSelection(delNodes);
    418416        return new SequenceCommand(
  • src/org/openstreetmap/josm/actions/corrector/TagCorrector.java

     
    194194                    // save the clone
    195195                    if (!keysChanged.isEmpty()) {
    196196                        commands.add(new ChangeCommand(dataSet, primitive, clone));
     197                    } else {
     198                        clone.removeFromChildren();
    197199                    }
    198200                }
    199201                for (Entry<OsmPrimitive, List<RoleCorrection>> entry : roleCorrectionMap.entrySet()) {
  • src/org/openstreetmap/josm/actions/mapmode/ImproveWayAccuracyAction.java

     
    489489                        if (deleteCmd != null) {
    490490                            UndoRedoHandler.getInstance().add(deleteCmd);
    491491                        }
     492                        newWay.setNodes(null);
    492493                    } else {
    493494                        UndoRedoHandler.getInstance().add(new ChangeCommand(targetWay, newWay));
    494495                    }
  • src/org/openstreetmap/josm/actions/mapmode/SelectAction.java

     
    2222
    2323import org.openstreetmap.josm.actions.MergeNodesAction;
    2424import org.openstreetmap.josm.command.AddCommand;
    25 import org.openstreetmap.josm.command.ChangeCommand;
     25import org.openstreetmap.josm.command.ChangeNodesCommand;
    2626import org.openstreetmap.josm.command.Command;
    2727import org.openstreetmap.josm.command.MoveCommand;
    2828import org.openstreetmap.josm.command.RotateCommand;
     
    12431243                Way w = virtualWay.way;
    12441244                Way wnew = new Way(w);
    12451245                wnew.addNode(virtualWay.lowerIndex + 1, virtualNode);
    1246                 virtualCmds.add(new ChangeCommand(ds, w, wnew));
     1246                virtualCmds.add(new ChangeNodesCommand(ds, w, wnew.getNodes()));
     1247                wnew.removeFromChildren();
    12471248            }
    12481249            virtualCmds.add(new MoveCommand(ds, virtualNode, startEN, currentEN));
    12491250            String text = trn("Add and move a virtual new node to way",
  • src/org/openstreetmap/josm/command/Command.java

     
    227227        for (OsmPrimitive osm : primitives) {
    228228            if (osm.isIncomplete()) {
    229229                res |= IS_INCOMPLETE;
    230             } else if ((osm.isOutsideDownloadArea()
     230            } else if ((res & IS_OUTSIDE) == 0 && (osm.isOutsideDownloadArea()
    231231                    || (osm instanceof Node && !osm.isNew() && osm.getDataSet() != null && osm.getDataSet().getDataSourceBounds().isEmpty()))
    232232                            && (ignore == null || !ignore.contains(osm))) {
    233233                res |= IS_OUTSIDE;
  • src/org/openstreetmap/josm/command/DeleteCommand.java

     
    184184    @Override
    185185    public boolean executeCommand() {
    186186        ensurePrimitivesAreInDataset();
    187         // Make copy and remove all references (to prevent inconsistent dataset (delete referenced) while command is executed)
    188         for (OsmPrimitive osm: toDelete) {
    189             if (osm.isDeleted())
    190                 throw new IllegalArgumentException(osm + " is already deleted");
    191             clonedPrimitives.put(osm, osm.save());
    192187
    193             if (osm instanceof Way) {
    194                 ((Way) osm).setNodes(null);
    195             } else if (osm instanceof Relation) {
    196                 ((Relation) osm).setMembers(null);
     188        getAffectedDataSet().update(() -> {
     189            // Make copy and remove all references (to prevent inconsistent dataset (delete referenced) while command is executed)
     190            for (OsmPrimitive osm : toDelete) {
     191                if (osm.isDeleted())
     192                    throw new IllegalArgumentException(osm + " is already deleted");
     193                clonedPrimitives.put(osm, osm.save());
     194
     195                if (osm instanceof Way) {
     196                    ((Way) osm).setNodes(null);
     197                } else if (osm instanceof Relation) {
     198                    ((Relation) osm).setMembers(null);
     199                }
    197200            }
    198         }
    199201
    200         for (OsmPrimitive osm: toDelete) {
    201             osm.setDeleted(true);
    202         }
    203 
     202            for (OsmPrimitive osm : toDelete) {
     203                osm.setDeleted(true);
     204            }
     205        });
    204206        return true;
    205207    }
    206208
     
    208210    public void undoCommand() {
    209211        ensurePrimitivesAreInDataset();
    210212
    211         for (OsmPrimitive osm: toDelete) {
    212             osm.setDeleted(false);
    213         }
     213        getAffectedDataSet().update(() -> {
     214            for (OsmPrimitive osm : toDelete) {
     215                osm.setDeleted(false);
     216            }
    214217
    215         for (Entry<OsmPrimitive, PrimitiveData> entry: clonedPrimitives.entrySet()) {
    216             entry.getKey().load(entry.getValue());
    217         }
     218            for (Entry<OsmPrimitive, PrimitiveData> entry : clonedPrimitives.entrySet()) {
     219                entry.getKey().load(entry.getValue());
     220            }
     221        });
    218222    }
    219223
    220224    @Override
     
    426430        Collection<Command> cmds = new LinkedList<>();
    427431        Set<Node> nodesToRemove = new HashSet<>(Utils.filteredCollection(primitivesToDelete, Node.class));
    428432        for (Way w : waysToBeChanged) {
    429             Way wnew = new Way(w);
    430             wnew.removeNodes(nodesToRemove);
    431             if (wnew.getNodesCount() < 2) {
     433            if (primitivesToDelete.contains(w))
     434                continue;
     435            List<Node> remainingNodes = w.calculateRemoveNodes(nodesToRemove);
     436            if (remainingNodes.size() < 2) {
    432437                primitivesToDelete.add(w);
    433438            } else {
    434                 cmds.add(new ChangeNodesCommand(w, wnew.getNodes()));
     439                cmds.add(new ChangeNodesCommand(w, remainingNodes));
    435440            }
    436441        }
    437442
  • src/org/openstreetmap/josm/data/osm/DatasetConsistencyTest.java

     
    6868    }
    6969
    7070    /**
    71      * Checks for womplete ways with incomplete nodes.
     71     * Checks for complete ways with incomplete nodes.
    7272     */
    7373    public void checkCompleteWaysWithIncompleteNodes() {
    7474        final Stopwatch stopwatch = Stopwatch.createStarted();
     
    182182        printElapsedTime(stopwatch);
    183183    }
    184184
     185    private void searchParentsWithoutDataset() {
     186        final Stopwatch stopwatch = Stopwatch.createStarted();
     187        long dubiousParents  = 0;
     188        for (OsmPrimitive p : dataSet.allPrimitives()) {
     189            dubiousParents += p.checkReferrersWithoutDataset(false);
     190        }
     191        if (dubiousParents > 0) {
     192            printError("WARN - Memory leak",
     193                    "Dataset contains %d pointers to parents which do not belong to the dataset", dubiousParents);
     194        }
     195        printElapsedTime(stopwatch);
     196
     197    }
     198
    185199    private void printElapsedTime(Stopwatch stopwatch) {
    186200        if (Logging.isDebugEnabled()) {
    187201            StackTraceElement item = Thread.currentThread().getStackTrace()[2];
     
    203217            searchNodes();
    204218            searchWays();
    205219            checkZeroNodesWays();
     220            searchParentsWithoutDataset();
    206221            printElapsedTime(stopwatch);
    207222            if (errorCount > MAX_ERRORS) {
    208223                writer.println((errorCount - MAX_ERRORS) + " more...");
  • src/org/openstreetmap/josm/data/osm/Node.java

     
    394394    protected void updateDirectionFlags() {
    395395        // Nodes do not need/have a direction, greatly improves performance, see #18886
    396396    }
     397
     398    @Override
     399    public void removeFromChildren() {
     400        // nothing to do
     401    }
    397402}
  • src/org/openstreetmap/josm/data/osm/OsmPrimitive.java

     
    787787    }
    788788
    789789    /**
     790     * Find all referrers which have no dataset.
     791     * @param doRemove if {@code true} remove the found referrers
     792     * @return number of (possibly removed) referrers without a dataset
     793     */
     794    final int checkReferrersWithoutDataset(boolean doRemove) {
     795        if (dataSet == null) {
     796            return 0;
     797        }
     798        if (doRemove)
     799            checkDatasetNotReadOnly();
     800
     801        if (referrers == null) {
     802            return 0;
     803        }
     804        if (referrers instanceof OsmPrimitive) {
     805            if (((OsmPrimitive) referrers).getDataSet() == null) {
     806                if (doRemove)
     807                    referrers = null;
     808                return 1;
     809            }
     810            return 0;
     811        }
     812        OsmPrimitive[] array = ((OsmPrimitive[]) referrers);
     813        long oldCount = array.length;
     814        long badCount = Arrays.stream(array).filter(p -> p.getDataSet() == null).count();
     815        if (badCount > 0 && doRemove) {
     816            OsmPrimitive[] smaller = new OsmPrimitive[(int) (oldCount - badCount)];
     817            int k = 0;
     818            for (int i = 0; i < oldCount; i++) {
     819                if (array[i].getDataSet() != null)
     820                    smaller[k++] = array[i];
     821            }
     822            referrers = smaller;
     823        }
     824        return (int) badCount;
     825    }
     826
     827    /**
    790828     * <p>Visits {@code visitor} for all referrers.</p>
    791829     *
    792830     * @param visitor the visitor. Ignored, if null.
     
    11461184     * @since 11269
    11471185     */
    11481186    protected abstract void addToBBox(BBox box, Set<PrimitiveId> visited);
     1187
     1188    /**
     1189     * If this primitive has children,
     1190     * @since xxx
     1191     */
     1192    public abstract void removeFromChildren();
    11491193}
  • src/org/openstreetmap/josm/data/osm/Relation.java

     
    563563    public UniqueIdGenerator getIdGenerator() {
    564564        return idGenerator;
    565565    }
     566
     567    @Override
     568    public void removeFromChildren() {
     569        setMembers(null);
     570    }
     571
    566572}
  • src/org/openstreetmap/josm/data/osm/Way.java

     
    363363        if (selection == null || isIncomplete()) return;
    364364        boolean locked = writeLock();
    365365        try {
    366             boolean closed = isClosed() && selection.contains(lastNode());
    367             List<Node> copy = Arrays.stream(nodes)
    368                     .filter(n -> !selection.contains(n))
    369                     .collect(Collectors.toList());
    370 
    371             int i = copy.size();
    372             if (closed && i > 2) {
    373                 copy.add(copy.get(0));
    374             } else if (i >= 2 && i <= 3 && copy.get(0) == copy.get(i-1)) {
    375                 copy.remove(i-1);
    376             }
    377             setNodes(removeDouble(copy));
     366            setNodes(calculateRemoveNodes(selection));
    378367            for (Node n : selection) {
    379368                n.clearCachedStyle();
    380369            }
     
    384373    }
    385374
    386375    /**
     376     * Calculate the remaining nodes after a removal of the given set of {@link Node nodes} from this way.
     377     * @param selection The selection of nodes to remove. Ignored, if null
     378     * @return result of the removal, can be empty
     379     * @since xxx
     380     */
     381    public List<Node> calculateRemoveNodes(Set<? extends Node> selection) {
     382        if (selection == null || isIncomplete())
     383            return getNodes();
     384        boolean closed = isClosed() && selection.contains(lastNode());
     385        List<Node> copy = Arrays.stream(nodes)
     386                .filter(n -> !selection.contains(n))
     387                .collect(Collectors.toList());
     388
     389        int i = copy.size();
     390        if (closed && i > 2) {
     391            copy.add(copy.get(0));
     392        } else if (i >= 2 && i <= 3 && copy.get(0) == copy.get(i-1)) {
     393            copy.remove(i-1);
     394        }
     395        return removeDouble(copy);
     396    }
     397
     398    /**
    387399     * Adds a node to the end of the list of nodes. Ignored, if n is null.
    388400     *
    389401     * @param n the node. Ignored, if null
     
    756768    public UniqueIdGenerator getIdGenerator() {
    757769        return idGenerator;
    758770    }
     771
     772    @Override
     773    public void removeFromChildren() {
     774        setNodes(null);
     775    }
     776
    759777}
  • src/org/openstreetmap/josm/data/osm/visitor/paint/AbstractMapRenderer.java

     
    1212import org.openstreetmap.josm.data.osm.INode;
    1313import org.openstreetmap.josm.data.osm.IWay;
    1414import org.openstreetmap.josm.data.osm.OsmData;
     15import org.openstreetmap.josm.data.osm.Way;
    1516import org.openstreetmap.josm.data.osm.WaySegment;
    1617import org.openstreetmap.josm.gui.MapViewState;
    1718import org.openstreetmap.josm.gui.MapViewState.MapViewPoint;
     
    148149            path = new GeneralPath();
    149150            for (WaySegment wseg: data.getHighlightedVirtualNodes()) {
    150151                if (wseg.way.isUsable() && !wseg.way.isDisabled()) {
    151                     visitVirtual(path, wseg.toWay());
     152                    Way tmpWay = wseg.toWay();
     153                    visitVirtual(path, tmpWay);
     154                    tmpWay.removeFromChildren();
    152155                }
    153156            }
    154157            g.setColor(highlightColor);
  • src/org/openstreetmap/josm/data/validation/tests/Coastlines.java

     
    1313import java.util.List;
    1414import java.util.Set;
    1515
    16 import org.openstreetmap.josm.command.ChangeCommand;
     16import org.openstreetmap.josm.command.ChangeNodesCommand;
    1717import org.openstreetmap.josm.command.Command;
    1818import org.openstreetmap.josm.data.osm.Node;
    1919import org.openstreetmap.josm.data.osm.OsmPrimitive;
     
    260260            Iterator<? extends OsmPrimitive> it = testError.getPrimitives().iterator();
    261261            if (it.hasNext()) {
    262262                Way way = (Way) it.next();
    263                 Way newWay = new Way(way);
    264263
    265                 List<Node> nodesCopy = newWay.getNodes();
     264                List<Node> nodesCopy = way.getNodes();
    266265                Collections.reverse(nodesCopy);
    267                 newWay.setNodes(nodesCopy);
    268266
    269                 return new ChangeCommand(way, newWay);
     267                return new ChangeNodesCommand(way, nodesCopy);
    270268            }
    271269        }
    272270        return null;
  • src/org/openstreetmap/josm/data/validation/tests/TagChecker.java

     
    987987            if (countDeprecated(clone) > unchangedDeprecated)
    988988                iter.remove();
    989989        }
     990        clone.removeFromChildren();
    990991    }
    991992
    992993    private int countDeprecated(OsmPrimitive p) {
  • src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java

     
    950950                relation.addMember(new RelationMember(roles.size() == 1 ? roles.iterator().next() : "", p));
    951951                modified = true;
    952952            }
    953             return modified ? new ChangeCommand(orig, relation) : null;
     953            if (!modified) {
     954                relation.removeFromChildren();
     955                return null;
     956            }
     957            return new ChangeCommand(orig, relation);
    954958        } catch (AddAbortException ign) {
    955959            Logging.trace(ign);
    956960            return null;