Ignore:
Timestamp:
2018-05-11T23:39:43+02:00 (19 months ago)
Author:
Don-vip
Message:

fix #16260 - fix major performance problems seen during first JOSM launch:

  • new API to notify about undo/redo changes
  • use this API in Command Stack dialog to alter lightly the undo/redo trees instead of rebuilding them entirely at each command (very costly operation for large trees)
  • purge the command stack after computing the left/right traffic data to avoid starting JOSM with already many thousands nodes in undo/redo trees
  • avoid memory leak with JoinAreasAction when computing the left/right traffic data
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/UndoRedoHandler.java

    r13010 r13729  
    22package org.openstreetmap.josm.data;
    33
     4import java.util.EventObject;
    45import java.util.Iterator;
    56import java.util.LinkedList;
     7import java.util.Objects;
    68
    79import org.openstreetmap.josm.Main;
     
    3032
    3133    private final LinkedList<CommandQueueListener> listenerCommands = new LinkedList<>();
     34    private final LinkedList<CommandQueuePreciseListener> preciseListenerCommands = new LinkedList<>();
    3235
    3336    /**
     
    3942
    4043    /**
    41      * A listener that gets notified of command queue (undo/redo) size changes.
     44     * A simple listener that gets notified of command queue (undo/redo) size changes.
     45     * @see CommandQueuePreciseListener
    4246     * @since 12718 (moved from {@code OsmDataLayer}
    4347     */
     
    5054         */
    5155        void commandChanged(int queueSize, int redoSize);
     56    }
     57
     58    /**
     59     * A listener that gets notified of command queue (undo/redo) operations individually.
     60     * @see CommandQueueListener
     61     * @since 13729
     62     */
     63    public interface CommandQueuePreciseListener {
     64
     65        /**
     66         * Notifies the listener about a new command added to the queue.
     67         * @param e event
     68         */
     69        void commandAdded(CommandAddedEvent e);
     70
     71        /**
     72         * Notifies the listener about commands being cleaned.
     73         * @param e event
     74         */
     75        void cleaned(CommandQueueCleanedEvent e);
     76
     77        /**
     78         * Notifies the listener about a command that has been undone.
     79         * @param e event
     80         */
     81        void commandUndone(CommandUndoneEvent e);
     82
     83        /**
     84         * Notifies the listener about a command that has been redone.
     85         * @param e event
     86         */
     87        void commandRedone(CommandRedoneEvent e);
     88    }
     89
     90    abstract static class CommandQueueEvent extends EventObject {
     91        protected CommandQueueEvent(UndoRedoHandler source) {
     92            super(Objects.requireNonNull(source));
     93        }
     94
     95        /**
     96         * Calls the appropriate method of the listener for this event.
     97         * @param listener dataset listener to notify about this event
     98         */
     99        abstract void fire(CommandQueuePreciseListener listener);
     100
     101        @Override
     102        public final UndoRedoHandler getSource() {
     103            return (UndoRedoHandler) super.getSource();
     104        }
     105    }
     106
     107    /**
     108     * Event fired after a command has been added to the command queue.
     109     * @since xxx
     110     */
     111    public static final class CommandAddedEvent extends CommandQueueEvent {
     112
     113        private final Command cmd;
     114
     115        private CommandAddedEvent(UndoRedoHandler source, Command cmd) {
     116            super(source);
     117            this.cmd = Objects.requireNonNull(cmd);
     118        }
     119
     120        /**
     121         * Returns the added command.
     122         * @return the added command
     123         */
     124        public Command getCommand() {
     125            return cmd;
     126        }
     127
     128        @Override
     129        void fire(CommandQueuePreciseListener listener) {
     130            listener.commandAdded(this);
     131        }
     132    }
     133
     134    /**
     135     * Event fired after the command queue has been cleaned.
     136     * @since xxx
     137     */
     138    public static final class CommandQueueCleanedEvent extends CommandQueueEvent {
     139
     140        private final DataSet ds;
     141
     142        private CommandQueueCleanedEvent(UndoRedoHandler source, DataSet ds) {
     143            super(source);
     144            this.ds = ds;
     145        }
     146
     147        /**
     148         * Returns the affected dataset.
     149         * @return the affected dataset, or null if the queue has been globally emptied
     150         */
     151        public DataSet getDataSet() {
     152            return ds;
     153        }
     154
     155        @Override
     156        void fire(CommandQueuePreciseListener listener) {
     157            listener.cleaned(this);
     158        }
     159    }
     160
     161    /**
     162     * Event fired after a command has been undone.
     163     * @since xxx
     164     */
     165    public static final class CommandUndoneEvent extends CommandQueueEvent {
     166
     167        private final Command cmd;
     168
     169        private CommandUndoneEvent(UndoRedoHandler source, Command cmd) {
     170            super(source);
     171            this.cmd = Objects.requireNonNull(cmd);
     172        }
     173
     174        /**
     175         * Returns the undone command.
     176         * @return the undone command
     177         */
     178        public Command getCommand() {
     179            return cmd;
     180        }
     181
     182        @Override
     183        void fire(CommandQueuePreciseListener listener) {
     184            listener.commandUndone(this);
     185        }
     186    }
     187
     188    /**
     189     * Event fired after a command has been redone.
     190     * @since xxx
     191     */
     192    public static final class CommandRedoneEvent extends CommandQueueEvent {
     193
     194        private final Command cmd;
     195
     196        private CommandRedoneEvent(UndoRedoHandler source, Command cmd) {
     197            super(source);
     198            this.cmd = Objects.requireNonNull(cmd);
     199        }
     200
     201        /**
     202         * Returns the redone command.
     203         * @return the redone command
     204         */
     205        public Command getCommand() {
     206            return cmd;
     207        }
     208
     209        @Override
     210        void fire(CommandQueuePreciseListener listener) {
     211            listener.commandRedone(this);
     212        }
    52213    }
    53214
     
    80241    /**
    81242     * Fires a commands change event after adding a command.
    82      */
    83     public void afterAdd() {
     243     * @param cmd command added
     244     */
     245    public void afterAdd(Command cmd) {
     246        if (cmd != null) {
     247            fireEvent(new CommandAddedEvent(this, cmd));
     248        }
    84249        fireCommandsChanged();
    85250    }
     
    91256    public synchronized void add(final Command c) {
    92257        addNoRedraw(c);
    93         afterAdd();
     258        afterAdd(c);
    94259    }
    95260
     
    117282                c.undoCommand();
    118283                redoCommands.addFirst(c);
     284                fireEvent(new CommandUndoneEvent(this, c));
    119285                if (commands.isEmpty()) {
    120286                    break;
     
    147313            c.executeCommand();
    148314            commands.add(c);
     315            fireEvent(new CommandRedoneEvent(this, c));
    149316            if (redoCommands.isEmpty()) {
    150317                break;
     
    163330    }
    164331
     332    private void fireEvent(CommandQueueEvent e) {
     333        preciseListenerCommands.forEach(e::fire);
     334    }
     335
    165336    /**
    166337     * Resets the undo/redo list.
     
    169340        redoCommands.clear();
    170341        commands.clear();
     342        fireEvent(new CommandQueueCleanedEvent(this, null));
    171343        fireCommandsChanged();
    172344    }
     
    194366        }
    195367        if (changed) {
     368            fireEvent(new CommandQueueCleanedEvent(this, dataSet));
    196369            fireCommandsChanged();
    197370        }
     
    208381    /**
    209382     * Adds a command queue listener.
    210      * @param l The commands queue listener to add
     383     * @param l The command queue listener to add
    211384     * @return {@code true} if the listener has been added, {@code false} otherwise
    212385     */
     
    214387        return listenerCommands.add(l);
    215388    }
     389
     390    /**
     391     * Removes a precise command queue listener.
     392     * @param l The precise command queue listener to remove
     393     * @since 13729
     394     */
     395    public void removeCommandQueuePreciseListener(CommandQueuePreciseListener l) {
     396        preciseListenerCommands.remove(l);
     397    }
     398
     399    /**
     400     * Adds a precise command queue listener.
     401     * @param l The precise command queue listener to add
     402     * @return {@code true} if the listener has been added, {@code false} otherwise
     403     * @since 13729
     404     */
     405    public boolean addCommandQueuePreciseListener(CommandQueuePreciseListener l) {
     406        return preciseListenerCommands.add(l);
     407    }
    216408}
Note: See TracChangeset for help on using the changeset viewer.