/** * OrbisGIS is a java GIS application dedicated to research in GIScience. * OrbisGIS is developed by the GIS group of the DECIDE team of the * Lab-STICC CNRS laboratory, see <http://www.lab-sticc.fr/>. * * The GIS group of the DECIDE team is located at : * * Laboratoire Lab-STICC – CNRS UMR 6285 * Equipe DECIDE * UNIVERSITÉ DE BRETAGNE-SUD * Institut Universitaire de Technologie de Vannes * 8, Rue Montaigne - BP 561 56017 Vannes Cedex * * OrbisGIS is distributed under GPL 3 license. * * Copyright (C) 2007-2014 CNRS (IRSTV FR CNRS 2488) * Copyright (C) 2015-2017 CNRS (Lab-STICC UMR CNRS 6285) * * This file is part of OrbisGIS. * * OrbisGIS is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * OrbisGIS is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * OrbisGIS. If not, see <http://www.gnu.org/licenses/>. * * For more information, please consult: <http://www.orbisgis.org/> * or contact directly: * info_at_ orbisgis.org */ package org.orbisgis.coremap.layerModel; import com.vividsolutions.jts.geom.Envelope; import java.net.URI; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import net.opengis.ows_context.LayerType; import org.orbisgis.coremap.stream.GeoStream; import org.orbisgis.corejdbc.DataManager; import org.orbisgis.coremap.renderer.se.Rule; import org.orbisgis.coremap.renderer.se.Style; public class LayerCollection extends BeanLayer { private List<ILayer> layerCollection; public LayerCollection(String layerName) { super(layerName); layerCollection = new ArrayList<ILayer>(); } /** * Create a new LayerCollection with the name name. * @param layerType */ public LayerCollection(LayerType layerType) { super(layerType); layerCollection = new ArrayList<ILayer>(); } @Override public void setDataUri(URI uri) { throw new UnsupportedOperationException("LayerCollection does not hold resources"); } @Override public DataManager getDataManager() { return null; } /** * Retrieve the layer collection as a list of layers. * @return */ List<ILayer> getLayerCollection() { return layerCollection; } /** * Returns the index of the first occurrence of the specified element in this list, * or -1 if this list does not contain the element. * @param layer * @return */ @Override public int getIndex(ILayer layer) { return layerCollection.indexOf(layer); } @Override public GeoStream getStream() throws LayerException { return null; } /** * Get the layer stored at the given index in the collection. * @param index * @return */ @Override public ILayer getLayer(final int index) { //TODO : get will throw a IndexOutOfBoundsException which is nor catch neither managed here... return layerCollection.get(index); } @Override public boolean isSerializable(){ return true; } @Override public void addLayer(final ILayer layer) throws LayerException { addLayer(layer, false); } /** * Insert layer at the given index. * @param layer * @param index * @throws LayerException */ @Override public void insertLayer(final ILayer layer, int index) throws LayerException { insertLayer(layer, index, false); } /** * Removes the layer from the collection * * @param layerName * @return the layer removed or null if the layer does not exists * @throws LayerException * */ @Override public ILayer remove(final String layerName) throws LayerException { for (int i = 0; i < size(); i++) { if (layerName.equals(layerCollection.get(i).getName())) { return remove(layerCollection.get(i)); } } return null; } /** * Retrieve the children of this node as an array. * @return */ @Override public ILayer[] getChildren() { if (null != layerCollection) { ILayer[] result = new ILayer[size()]; return layerCollection.toArray(result); } else { return null; } } /** * Return the number of children in this collection. * @return */ private int size() { return layerCollection.size(); } /** * Check if this layer is visible or not. It is visible if at least one of its children is visible, * false otherwise. * @see org.orbisgis.coremap.layerModel.ILayer#isVisible() */ @Override public boolean isVisible() { for (ILayer layer : getChildren()) { if (layer.isVisible()) { return true; } } return false; } /** * Set the visible attribute. We don't see this object (which is a collection, * not a layer) but its leaves. Consequently, whe using this method, we set * the visible attribute to isVisible for all the leaves of this collection. * @param isVisible * @throws LayerException * @see org.orbisgis.coremap.layerModel.ILayer#setVisible(boolean) */ @Override public void setVisible(boolean isVisible) throws LayerException { super.setVisible(isVisible); for (ILayer layer : getChildren()) { layer.setVisible(isVisible); } } @Override public void setStyle(int i, Style fts) { throw new UnsupportedOperationException("Not supported yet."); } @Override public ArrayList<Rule> getRenderingRule() throws LayerException { throw new UnsupportedOperationException("A layer collection doesn't have any rule !"); } /** * * @return */ @Override public Envelope getEnvelope() { final GetEnvelopeLayerAction tmp = new GetEnvelopeLayerAction(); processLayersLeaves(this, tmp); return tmp.getGlobalEnvelope(); } @Override public void clearCache() { } @Override public ILayer remove(ILayer layer) throws LayerException { return remove(layer, false); } /** * Inform if children can be added to this layer. It is a collection, so they are. * @return true. */ @Override public boolean acceptsChilds() { return true; } /**Add the LayerListener listener to this, and to each child of this. * * @param listener */ @Override public void addLayerListenerRecursively(LayerListener listener) { this.addLayerListener(listener); for (ILayer layer : layerCollection) { layer.addLayerListenerRecursively(listener); } } /** * Remove the LayerListener listener of this' listeners, and of its children's listeners * @param listener */ @Override public void removeLayerListenerRecursively(LayerListener listener) { this.removeLayerListener(listener); for (ILayer layer : layerCollection) { layer.removeLayerListenerRecursively(listener); } } /** * Close this layer and all its children. * @throws LayerException */ @Override public void close() throws LayerException { for (ILayer layer : layerCollection) { layer.close(); } } /** * Open the layer and all its children. * @throws LayerException */ @Override public void open() throws LayerException { for (ILayer layer : layerCollection) { layer.open(); } } /** * Add a new layer to this collection. * @param layer * @param isMoving * if {@code false}, {@code fireLayerAddedEvent} is called. It is not * called if {@code isMoving} is true. * @throws LayerException */ @Override public void addLayer(ILayer layer, boolean isMoving) throws LayerException { insertLayer(layer, layerCollection.size(),isMoving); } @Override public ILayer remove(ILayer layer, boolean isMoving) throws LayerException { if (layerCollection.contains(layer)) { if (isMoving) { if (layerCollection.remove(layer)) { return layer; } else { return null; } } else { ILayer[] toRemove = new ILayer[] { layer }; if (fireLayerRemovingEvent(toRemove)) { if (layerCollection.remove(layer)) { fireLayerRemovedEvent(toRemove); return layer; } else { return null; } } else { return null; } } } else { return null; } } @Override public void insertLayer(ILayer layer, int index, boolean isMoving) throws LayerException { if (null != layer) { int i = Math.min(index, this.layerCollection.size()); setNamesRecursively(layer, getRoot().getAllLayersNames()); layerCollection.add(i, layer); layer.setParent(this); if(!isMoving){ fireLayerAddedEvent(new ILayer[] { layer }); } } } @Override public int getLayerCount() { return layerCollection.size(); } @Override public ILayer getLayerByName(String layerName) { for (ILayer layer : layerCollection) { if (layer.getName().equals(layerName)) { return layer; } else { ILayer ret = layer.getLayerByName(layerName); if (ret != null) { return ret; } } } return null; } /** * Retrieve the children of this collection that are raster layers * @return * @throws LayerException */ @Override public ILayer[] getRasterLayers() throws LayerException { ILayer[] allLayers = getLayersRecursively(); ArrayList<ILayer> filterLayer = new ArrayList<ILayer>(); for (int i = 0; i < allLayers.length; i++) { if (allLayers[i].isRaster()) { filterLayer.add(allLayers[i]); } } return filterLayer.toArray(new ILayer[filterLayer.size()]); } /** * Retrieve the children of this collection that are vector layers * @return * @throws LayerException */ @Override public ILayer[] getVectorLayers() throws LayerException { ILayer[] allLayers = getLayersRecursively(); ArrayList<ILayer> filterLayer = new ArrayList<ILayer>(); for (int i = 0; i < allLayers.length; i++) { if (allLayers[i].isVectorial()) { filterLayer.add(allLayers[i]); } } return filterLayer.toArray(new ILayer[filterLayer.size()]); } /** * Used to determine if this layer is a raster layer. It is not, it is a layer collection. * @return false */ @Override public boolean isRaster() { return false; } /** * Used to determine if this layer is a vector layer. It is not, it is a layer collection. * @return false */ @Override public boolean isVectorial() { return false; } /** * Used to determine if this layer is a stream layer. It is not, it is a layer collection. * @return false */ @Override public boolean isStream() { return false; } @Override public String getTableReference() { return ""; } @Override public URI getDataUri() { return null; } @Override public Set<String> getAllLayersNames() { final Set<String> result = new HashSet<String>(); final LayerCollection lc = this; if (null != lc.getLayerCollection()) { for (ILayer layer : lc.getChildren()) { if (layer instanceof LayerCollection) { result.addAll(layer.getAllLayersNames()); } else { result.add(layer.getName()); } } } result.addAll(super.getAllLayersNames()); return result; } //////////////////Unsupported methods//////////////////////// @Override public void setSelection(Set<Long> newSelection) { throw new UnsupportedOperationException(I18N.tr("No row selection in a layer collection")); } @Override public Style getStyle(int i){ throw new UnsupportedOperationException("Cannot set " + "a legend on a layer collection"); } @Override public List<Style> getStyles(){ throw new UnsupportedOperationException("Cannot set " + "a legend on a layer collection"); } @Override public void setStyles(List<Style> s){ throw new UnsupportedOperationException("Cannot set " + "a legend on a layer collection"); } ///////////Static methods/////////////////////////////// /** * Aooky action to each leave of this layer tree * @param root * @param action */ public static void processLayersLeaves(ILayer root, ILayerAction action) { if (root instanceof LayerCollection) { ILayer lc = root; ILayer[] layers = lc.getChildren(); for (ILayer layer : layers) { processLayersLeaves(layer, action); } } else { action.action(root); } } /** * Apply action to each node of this tree of layers. * @param root * @param action */ public static void processLayersNodes(ILayer root, ILayerAction action) { if (root instanceof LayerCollection) { ILayer lc = root; ILayer[] layers = lc.getChildren(); for (ILayer layer : layers) { processLayersNodes(layer, action); } } action.action(root); } /** * Count the number of leaves in this tree of layers. * @param root * @return */ public static int getNumberOfLeaves(final ILayer root) { CountLeavesAction ila = new CountLeavesAction(); LayerCollection.processLayersLeaves(root, ila); return ila.getNumberOfLeaves(); } ///////////Private methods////////////////////////// /* * This method will guarantee that layer, and all its potential inner * layers, will have names that are not already owned by another, declared, layer. */ private void setNamesRecursively(final ILayer layer, final Set<String> allLayersNames) throws LayerException { layer.setName(provideNewLayerName(layer.getName(), allLayersNames)); if (layer instanceof LayerCollection) { LayerCollection lc = (LayerCollection) layer; if (null != lc.getLayerCollection()) { for (ILayer layerItem : lc.getChildren()) { setNamesRecursively(layerItem, allLayersNames); } } } } @Override public void addStyle(Style style) { throw new UnsupportedOperationException("Not supported yet."); } @Override public void addStyle(int i, Style style) { throw new UnsupportedOperationException("Not supported yet."); } @Override public int indexOf(Style s) { throw new UnsupportedOperationException("Not supported yet."); } //////////Private classes////////////////////////// private class GetEnvelopeLayerAction implements ILayerAction { private Envelope globalEnvelope; @Override public void action(ILayer layer) { if (null == globalEnvelope) { globalEnvelope = new Envelope(layer.getEnvelope()); } else { globalEnvelope.expandToInclude(layer.getEnvelope()); } } public Envelope getGlobalEnvelope() { return globalEnvelope; } } private static class CountLeavesAction implements ILayerAction { private int numberOfLeaves = 0; @Override public void action(ILayer layer) { numberOfLeaves++; } public int getNumberOfLeaves() { return numberOfLeaves; } } }