Ticket #12633: patch-layer-position-strategy.patch

File patch-layer-position-strategy.patch, 10.1 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 83e9b36..f509eac 100644
    a b import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache  
    5757import org.openstreetmap.josm.gui.layer.GpxLayer;
    5858import org.openstreetmap.josm.gui.layer.ImageryLayer;
    5959import org.openstreetmap.josm.gui.layer.Layer;
     60import org.openstreetmap.josm.gui.layer.LayerPositionStrategy;
    6061import org.openstreetmap.josm.gui.layer.MapViewPaintable;
    61 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    6262import org.openstreetmap.josm.gui.layer.NativeScaleLayer;
     63import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    6364import org.openstreetmap.josm.gui.layer.geoimage.GeoImageLayer;
    6465import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
    6566import org.openstreetmap.josm.gui.layer.markerlayer.PlayHeadMarker;
    implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer  
    346347    }
    347348
    348349    /**
    349      * Adds a GPX layer. A GPX layer is added below the lowest data layer.
    350      * <p>
    351      * Does not call {@link #fireLayerAdded(Layer)}.
    352      *
    353      * @param layer the GPX layer
    354      */
    355     protected void addGpxLayer(GpxLayer layer) {
    356         synchronized (layers) {
    357             if (layers.isEmpty()) {
    358                 layers.add(layer);
    359                 return;
    360             }
    361             for (int i = layers.size()-1; i >= 0; i--) {
    362                 if (layers.get(i) instanceof OsmDataLayer) {
    363                     if (i == layers.size()-1) {
    364                         layers.add(layer);
    365                     } else {
    366                         layers.add(i+1, layer);
    367                     }
    368                     return;
    369                 }
    370             }
    371             layers.add(0, layer);
    372         }
    373     }
    374 
    375     /**
    376350     * Add a layer to the current MapView. The layer will be added at topmost
    377351     * position.
    378352     * @param layer The layer to add
    implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer  
    388362                playHeadMarker = PlayHeadMarker.create();
    389363            }
    390364
    391             if (layer instanceof GpxLayer) {
    392                 addGpxLayer((GpxLayer) layer);
    393             } else if (layers.isEmpty()) {
    394                 layers.add(layer);
    395             } else if (layer.isBackgroundLayer()) {
    396                 int i = 0;
    397                 for (; i < layers.size(); i++) {
    398                     if (layers.get(i).isBackgroundLayer()) {
    399                         break;
    400                     }
    401                 }
    402                 layers.add(i, layer);
    403             } else {
    404                 layers.add(0, layer);
    405             }
     365            LayerPositionStrategy positionStrategy = layer.getDefaultLayerPosition();
     366            int position = positionStrategy.getPosition(this);
     367            checkPosition(position);
     368            insertLayerAt(layer, position);
    406369
    407370            if (isOsmDataLayer || oldActiveLayer == null) {
    408371                // autoselect the new layer
    implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer  
    429392        }
    430393    }
    431394
     395    /**
     396     * Check if the (new) position is valid
     397     * @param position The position index
     398     * @throws IndexOutOfBoundsException if it is not.
     399     */
     400    private void checkPosition(int position) {
     401        if (position < 0 || position > layers.size()) {
     402            throw new IndexOutOfBoundsException("Position " + position + " out of range.");
     403        }
     404    }
     405
     406    /**
     407     * Insert a layer at a given position.
     408     * @param layer The layer to add.
     409     * @param position The position on which we should add it.
     410     */
     411    private void insertLayerAt(Layer layer, int position) {
     412        if (position == layers.size()) {
     413            layers.add(layer);
     414        } else {
     415            layers.add(position, layer);
     416        }
     417    }
     418
    432419    @Override
    433420    protected DataSet getCurrentDataSet() {
    434421        synchronized (layers) {
  • src/org/openstreetmap/josm/gui/layer/GpxLayer.java

    diff --git a/src/org/openstreetmap/josm/gui/layer/GpxLayer.java b/src/org/openstreetmap/josm/gui/layer/GpxLayer.java
    index 6bdf88a..4e4fde2 100644
    a b public class GpxLayer extends Layer {  
    384384        return SaveActionBase.createAndOpenSaveFileChooser(tr("Save GPX file"), GpxImporter.getFileFilter());
    385385    }
    386386
     387    @Override
     388    public LayerPositionStrategy getDefaultLayerPosition() {
     389        return LayerPositionStrategy.AFTER_LAST_DATA_LAYER;
     390    }
    387391}
  • src/org/openstreetmap/josm/gui/layer/Layer.java

    diff --git a/src/org/openstreetmap/josm/gui/layer/Layer.java b/src/org/openstreetmap/josm/gui/layer/Layer.java
    index 26842aa..0a5fcb5 100644
    a b public abstract class Layer implements Destroyable, MapViewPaintable, Projection  
    580580    protected long estimateMemoryUsage() {
    581581        return 0;
    582582    }
     583
     584    /**
     585     * Gets the strategy that specifies where this layer should be inserted in a layer list.
     586     * @return That strategy.
     587     */
     588    public LayerPositionStrategy getDefaultLayerPosition() {
     589        if (isBackgroundLayer()) {
     590            return LayerPositionStrategy.BEFORE_FIRST_BACKGROUND_LAYER;
     591        } else {
     592            return LayerPositionStrategy.AFTER_LAST_VALIDATION_LAYER;
     593        }
     594    }
    583595}
  • new file src/org/openstreetmap/josm/gui/layer/LayerPositionStrategy.java

    diff --git a/src/org/openstreetmap/josm/gui/layer/LayerPositionStrategy.java b/src/org/openstreetmap/josm/gui/layer/LayerPositionStrategy.java
    new file mode 100644
    index 0000000..6aa94c4
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.gui.layer;
     3
     4import java.util.List;
     5
     6import org.openstreetmap.josm.gui.MapView;
     7import org.openstreetmap.josm.tools.Predicate;
     8import org.openstreetmap.josm.tools.Predicates;
     9
     10/**
     11 * This class defines a position to insert a given layer in the list of layers.
     12 * @author Michael Zangl
     13 */
     14public abstract class LayerPositionStrategy {
     15
     16    /**
     17     * always inserts at the front of the stack.
     18     */
     19    public static final LayerPositionStrategy IN_FRONT = new LayerPositionStrategy() {
     20        @Override
     21        public int getPosition(MapView manager) {
     22            return 0;
     23        }
     24    };
     25
     26    /**
     27     * A GPX layer is added below the lowest data layer.
     28     */
     29    public static final LayerPositionStrategy AFTER_LAST_DATA_LAYER = afterLast(new Predicate<Layer>() {
     30        @Override
     31        public boolean evaluate(Layer object) {
     32            return object instanceof OsmDataLayer || object instanceof ValidatorLayer;
     33        };
     34    });
     35
     36    /**
     37     * A normal layer is added after all validation layers.
     38     */
     39    public static final LayerPositionStrategy AFTER_LAST_VALIDATION_LAYER = afterLast(new Predicate<Layer>() {
     40        @Override
     41        public boolean evaluate(Layer object) {
     42            return object instanceof ValidatorLayer;
     43        };
     44    });
     45
     46    /**
     47     * The default for background layers: They are added before the first background layer in the list. If there is n one, they are added at the end of the list.
     48     */
     49    public static final LayerPositionStrategy BEFORE_FIRST_BACKGROUND_LAYER = inFrontOfFirst(new Predicate<Layer>() {
     50        @Override
     51        public boolean evaluate(Layer object) {
     52            return object.isBackgroundLayer();
     53        }
     54    });
     55
     56    /**
     57     * Gets a {@link LayerPositionStrategy} that inserts this layer in front of a given layer
     58     * @param other The layer before which to insert this layer
     59     * @return The strategy
     60     */
     61    public static LayerPositionStrategy inFrontOf(Layer other) {
     62        return inFrontOfFirst(Predicates.equalTo(other));
     63    }
     64
     65    /**
     66     * Gets a {@link LayerPositionStrategy} that inserts the layer in front of the first layer that matches a condition.
     67     * @param what The condition to match.
     68     * @return The strategy.
     69     */
     70    public static LayerPositionStrategy inFrontOfFirst(final Predicate<Layer> what) {
     71        return new LayerPositionStrategy() {
     72            @Override
     73            public int getPosition(MapView manager) {
     74                List<Layer> layers = manager.getAllLayersAsList();
     75                for (int i = 0; i < layers.size(); i++) {
     76                    if (what.evaluate(layers.get(i))) {
     77                        return i;
     78                    }
     79                }
     80                return layers.size();
     81            }
     82        };
     83    }
     84
     85    /**
     86     * Creates a strategy that places the layer after the last layer of a given kind or at the beginning of the list if no such layer exists.
     87     * @param what what to search for
     88     * @return The strategy.
     89     */
     90    public static LayerPositionStrategy afterLast(final Predicate<Layer> what) {
     91        return new LayerPositionStrategy() {
     92            @Override
     93            public int getPosition(MapView manager) {
     94                List<Layer> layers = manager.getAllLayersAsList();
     95                for (int i = layers.size() - 1; i >= 0; i--) {
     96                    if (what.evaluate(layers.get(i))) {
     97                        return i + 1;
     98                    }
     99                }
     100                return 0;
     101            }
     102        };
     103    }
     104
     105    /**
     106     * Gets the position where the layer should be inserted
     107     * @param manager The layer manager to insert the layer in.
     108     * @return The position in the range 0...layers.size
     109     */
     110    public abstract int getPosition(MapView manager);
     111}
  • src/org/openstreetmap/josm/gui/layer/ValidatorLayer.java

    diff --git a/src/org/openstreetmap/josm/gui/layer/ValidatorLayer.java b/src/org/openstreetmap/josm/gui/layer/ValidatorLayer.java
    index 1f0c0be..82c57d6 100644
    a b public class ValidatorLayer extends Layer implements LayerChangeListener {  
    159159            OsmValidator.errorLayer = null;
    160160        }
    161161    }
     162
     163    @Override
     164    public LayerPositionStrategy getDefaultLayerPosition() {
     165        return LayerPositionStrategy.IN_FRONT;
     166    }
    162167}