001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.layer;
003
004import java.util.List;
005
006import org.openstreetmap.josm.tools.Predicate;
007import org.openstreetmap.josm.tools.Predicates;
008
009/**
010 * This class defines a position to insert a given layer in the list of layers.
011 * @author Michael Zangl
012 * @since 10008
013 */
014public abstract class LayerPositionStrategy {
015
016    /**
017     * always inserts at the front of the stack.
018     */
019    public static final LayerPositionStrategy IN_FRONT = new LayerPositionStrategy() {
020        @Override
021        public int getPosition(LayerManager manager) {
022            return 0;
023        }
024    };
025
026    /**
027     * A GPX layer is added below the lowest data layer.
028     */
029    public static final LayerPositionStrategy AFTER_LAST_DATA_LAYER = afterLast(new Predicate<Layer>() {
030        @Override
031        public boolean evaluate(Layer object) {
032            return object instanceof OsmDataLayer || object instanceof ValidatorLayer;
033        }
034    });
035
036    /**
037     * A normal layer is added after all validation layers.
038     */
039    public static final LayerPositionStrategy AFTER_LAST_VALIDATION_LAYER = afterLast(new Predicate<Layer>() {
040        @Override
041        public boolean evaluate(Layer object) {
042            return object instanceof ValidatorLayer;
043        }
044    });
045
046    /**
047     * The default for background layers: They are added before the first background layer in the list.
048     * If there is none, they are added at the end of the list.
049     */
050    public static final LayerPositionStrategy BEFORE_FIRST_BACKGROUND_LAYER = inFrontOfFirst(new Predicate<Layer>() {
051        @Override
052        public boolean evaluate(Layer object) {
053            return object.isBackgroundLayer();
054        }
055    });
056
057    /**
058     * Gets a {@link LayerPositionStrategy} that inserts this layer in front of a given layer
059     * @param other The layer before which to insert this layer
060     * @return The strategy
061     */
062    public static LayerPositionStrategy inFrontOf(Layer other) {
063        return inFrontOfFirst(Predicates.equalTo(other));
064    }
065
066    /**
067     * Gets a {@link LayerPositionStrategy} that inserts the layer in front of the first layer that matches a condition.
068     * @param what The condition to match.
069     * @return The strategy.
070     */
071    public static LayerPositionStrategy inFrontOfFirst(final Predicate<Layer> what) {
072        return new LayerPositionStrategy() {
073            @Override
074            public int getPosition(LayerManager manager) {
075                List<Layer> layers = manager.getLayers();
076                for (int i = 0; i < layers.size(); i++) {
077                    if (what.evaluate(layers.get(i))) {
078                        return i;
079                    }
080                }
081                return layers.size();
082            }
083        };
084    }
085
086    /**
087     * 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.
088     * @param what what to search for
089     * @return The strategy.
090     */
091    public static LayerPositionStrategy afterLast(final Predicate<Layer> what) {
092        return new LayerPositionStrategy() {
093            @Override
094            public int getPosition(LayerManager manager) {
095                List<Layer> layers = manager.getLayers();
096                for (int i = layers.size() - 1; i >= 0; i--) {
097                    if (what.evaluate(layers.get(i))) {
098                        return i + 1;
099                    }
100                }
101                return 0;
102            }
103        };
104    }
105
106    /**
107     * Gets the position where the layer should be inserted
108     * @param manager The layer manager to insert the layer in.
109     * @return The position in the range 0...layers.size
110     */
111    public abstract int getPosition(LayerManager manager);
112}