Ticket #12896: patch-layer-manager-track-removed-layers.patch

File patch-layer-manager-track-removed-layers.patch, 6.2 KB (added by michael2402, 10 years ago)
  • src/org/openstreetmap/josm/gui/MapView.java

    diff --git a/src/org/openstreetmap/josm/gui/MapView.java b/src/org/openstreetmap/josm/gui/MapView.java
    index d32dc94..9f819de 100644
    a b import org.openstreetmap.josm.gui.layer.GpxLayer;  
    5757import org.openstreetmap.josm.gui.layer.ImageryLayer;
    5858import org.openstreetmap.josm.gui.layer.Layer;
    5959import org.openstreetmap.josm.gui.layer.LayerManager;
     60import org.openstreetmap.josm.gui.layer.LayerManager.CyclicLayerRemoveException;
    6061import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent;
    6162import org.openstreetmap.josm.gui.layer.LayerManager.LayerOrderChangeEvent;
    6263import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent;
    LayerManager.LayerChangeListener, MainLayerManager.ActiveLayerChangeListener {  
    659660     */
    660661    @Deprecated
    661662    public void removeLayer(Layer layer) {
    662         layerManager.removeLayer(layer);
     663        try {
     664            layerManager.removeLayer(layer);
     665        } catch (CyclicLayerRemoveException e) {
     666            // ignore...
     667            Main.warn(e);
     668        }
    663669    }
    664670
    665671    @Override
  • src/org/openstreetmap/josm/gui/layer/LayerManager.java

    diff --git a/src/org/openstreetmap/josm/gui/layer/LayerManager.java b/src/org/openstreetmap/josm/gui/layer/LayerManager.java
    index e6c4895..ceb41f0 100644
    a b package org.openstreetmap.josm.gui.layer;  
    33
    44import java.util.ArrayList;
    55import java.util.Collections;
     6import java.util.IdentityHashMap;
    67import java.util.List;
     8import java.util.Set;
    79import java.util.concurrent.CopyOnWriteArrayList;
    810
    911import org.openstreetmap.josm.gui.util.GuiHelper;
    public class LayerManager {  
    114116        LayerOrderChangeEvent(LayerManager source) {
    115117            super(source);
    116118        }
     119    }
     120
     121    /**
     122     * An exception to be thrown when a cyclic remove is detected (remove inside removed listener)
     123     * @author Michael Zangl
     124     * @since xxx
     125     */
     126    public static class CyclicLayerRemoveException extends IllegalArgumentException {
     127
     128        /**
     129         * Create a new exception
     130         * @param message The message
     131         */
     132        public CyclicLayerRemoveException(String message) {
     133            super(message);
     134        }
    117135
     136        @Override
     137        public String toString() {
     138            return "CyclicLayerRemoveException [" + getMessage() + "]";
     139        }
    118140    }
    119141
    120142    /**
    public class LayerManager {  
    125147    private final List<LayerChangeListener> layerChangeListeners = new CopyOnWriteArrayList<>();
    126148
    127149    /**
     150     * A set of layers that are currently removed. To detect {@link #removeLayer(Layer)} calls in the layer remove listener.
     151     */
     152    private final Set<Layer> removingLayers = Collections.newSetFromMap(new IdentityHashMap<Layer, Boolean>());
     153
     154    /**
    128155     * Add a layer. The layer will be added at a given psoition.
    129156     * @param layer The layer to add
    130157     */
    public class LayerManager {  
    154181     * Remove the layer from the mapview. If the layer was in the list before,
    155182     * an LayerChange event is fired.
    156183     * @param layer The layer to remove
     184     * @throws IllegalArgumentException When the layer is not in this list
     185     * @throws CyclicLayerRemoveException When {@link #removeLayer(Layer)} is called for a removed layer inside the layer removed listener.
    157186     */
    158187    public void removeLayer(final Layer layer) {
    159188        // we force this on to the EDT Thread to make events fire from there.
    public class LayerManager {  
    161190        GuiHelper.runInEDTAndWaitWithException(new Runnable() {
    162191            @Override
    163192            public void run() {
    164                 realRemoveLayer(layer);
     193                checkContainsLayer(layer);
     194                if (!removingLayers.add(layer)) {
     195                    throw new CyclicLayerRemoveException("Caclic remove for layer " + layer);
     196                }
     197                try {
     198                    realRemoveLayer(layer);
     199                } finally {
     200                    removingLayers.remove(layer);
     201                }
    165202            }
    166203        });
    167204    }
    168205
    169206    protected synchronized void realRemoveLayer(Layer layer) {
    170         checkContainsLayer(layer);
    171 
    172207        fireLayerRemoving(layer);
    173208        layers.remove(layer);
    174209    }
  • test/unit/org/openstreetmap/josm/gui/layer/LayerManagerTest.java

    diff --git a/test/unit/org/openstreetmap/josm/gui/layer/LayerManagerTest.java b/test/unit/org/openstreetmap/josm/gui/layer/LayerManagerTest.java
    index 36205de..a6078a3 100644
    a b import org.junit.Test;  
    2121import org.openstreetmap.josm.data.Bounds;
    2222import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
    2323import org.openstreetmap.josm.gui.MapView;
     24import org.openstreetmap.josm.gui.layer.LayerManager.CyclicLayerRemoveException;
    2425import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent;
    2526import org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener;
    2627import org.openstreetmap.josm.gui.layer.LayerManager.LayerOrderChangeEvent;
    public class LayerManagerTest {  
    229230    }
    230231
    231232    /**
     233     * {@link LayerManager#removeLayer(Layer)} fails if a removeLayer of a layer that is removed is called inside the layer remove listener.
     234     */
     235    @Test(expected = CyclicLayerRemoveException.class)
     236    public void testRemoveLayerFailsWhenRemoveCycle() {
     237        final AbstractTestLayer layer1 = new AbstractTestLayer();
     238        AbstractTestLayer layer2 = new AbstractTestLayer();
     239        layerManager.addLayer(layer1);
     240        layerManager.addLayer(layer2);
     241
     242        layerManager.addLayerChangeListener(new LayerChangeListener() {
     243            @Override
     244            public void layerRemoving(LayerRemoveEvent e) {
     245                layerManager.removeLayer(layer1);
     246            }
     247
     248            @Override
     249            public void layerOrderChanged(LayerOrderChangeEvent e) {
     250            }
     251
     252            @Override
     253            public void layerAdded(LayerAddEvent e) {
     254            }
     255        });
     256        layerManager.removeLayer(layer1);
     257    }
     258    /**
    232259     * {@link LayerManager#moveLayer(Layer, int)}
    233260     */
    234261    @Test