/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2003-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library 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 * Lesser General Public License for more details. */ package org.geotools.map; import java.util.Collection; import org.geotools.coverage.grid.GridCoverage2D; import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader; import org.geotools.data.DataUtilities; import org.geotools.data.FeatureSource; import org.geotools.data.Query; import org.geotools.data.memory.CollectionSource; import org.geotools.data.simple.SimpleFeatureCollection; import org.geotools.factory.FactoryRegistryException; import org.geotools.feature.FeatureCollection; import org.geotools.feature.SchemaException; import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.map.event.MapLayerListener; import org.geotools.styling.Style; import org.opengis.coverage.grid.GridCoverage; import org.opengis.feature.Feature; import org.opengis.feature.type.FeatureType; import org.opengis.parameter.GeneralParameterValue; import org.opengis.referencing.operation.TransformException; /** * MapLayer is a clean wrapper around the Layer class used for rendering; primarily used for user * interface code. * <p> * Please note that not all Layer implementations support Query and/or Style. * * @author Cameron Shorter * @author Martin Desruisseaux * * @source $URL$ * http://svn.osgeo.org/geotools/trunk/modules/library/render/src/main/java/org/geotools * /map/MapLayer.java $ * @version $Id$ * @deprecated Use an appropriate Layer such as FeatureLayer, GridCoverageLayer or GridReaderLayer * @since 2.0 * @version 8.0 */ public class MapLayer { /** * This is the internal delegate */ protected Layer internal; /** * Wrap up a layer in a DefaultMapLayer; generally used to ensure layer is shown to the world as * a feature source even if it happens to be a WMS or something. */ public MapLayer(Layer layer) { this.internal = layer; } /** * Creates a new instance of DefaultMapLayer * * @param featureSource * the data source for this layer * @param style * the style used to represent this layer * @param title * the layer title * * @throws NullPointerException * DOCUMENT ME! */ @SuppressWarnings("unchecked") public MapLayer(FeatureSource featureSource, Style style, String title) { internal = new FeatureLayer(featureSource, style, title); } public MapLayer(CollectionSource source, Style style, String title) { throw new UnsupportedOperationException( "Raw Collections not supported; please use FeatureCollection"); } /** * Creates a new instance of DefaultMapLayer * * @param featureSource * the data source for this layer * @param style * the style used to represent this layer */ @SuppressWarnings("unchecked") public MapLayer(FeatureSource featureSource, Style style) { internal = new FeatureLayer(featureSource, style); } /** * Creates a new instance of DefaultMapLayer using a non-emtpy feature collection as a parameter * * @param collection * the source feature collection * @param style * the style used to represent this layer * @param title * Title of map layer */ public MapLayer(FeatureCollection collection, Style style, String title) { internal = new FeatureLayer(collection, style, title); } @SuppressWarnings("unchecked") public MapLayer(Collection collection, Style style, String title) { if (collection instanceof FeatureCollection) { internal = new FeatureLayer((FeatureCollection) collection, style, title); } else { throw new UnsupportedOperationException( "Raw collections not supported; please use FeatureCollection"); } } /** * Creates a new instance of DefaultMapLayer using a non-emtpy feature collection as a parameter * * @param collection * the source feature collection * @param style * the style used to represent this layer */ public MapLayer(FeatureCollection collection, Style style) { internal = new FeatureLayer((FeatureCollection) collection, style); } @SuppressWarnings("unchecked") public MapLayer(Collection collection, Style style) { if (collection instanceof FeatureCollection) { internal = new FeatureLayer((FeatureCollection) collection, style); } else { throw new UnsupportedOperationException( "Raw collections not supported; please use FeatureCollection"); } } /** * * Add a new layer and trigger a {@link LayerListEvent}. * * @param coverage * The new layer that has been added. * @param style * @throws SchemaException * @throws FactoryRegistryException * @throws TransformException */ public MapLayer(GridCoverage coverage, Style style) throws TransformException, FactoryRegistryException, SchemaException { internal = new GridCoverageLayer((GridCoverage2D) coverage, style); } /** * Constructor which adds a new layer and trigger a {@link LayerListEvent}. * * @param reader * a reader with the new layer that will be added. * @param style * @param title * @param params * GeneralParameterValue[] that describe how the {@link AbstractGridCoverage2DReader} * shall read the images * * @throws SchemaException * @throws FactoryRegistryException * @throws TransformException */ public MapLayer(AbstractGridCoverage2DReader reader, Style style, String title, GeneralParameterValue[] params) throws TransformException, FactoryRegistryException, SchemaException { internal = new GridReaderLayer(reader, style, title, params); } /** * Constructor which adds a new layer and trigger a {@link LayerListEvent}. * * @param reader * a reader with the new layer that will be added. * @param style * @param title * * @throws SchemaException * @throws FactoryRegistryException * @throws TransformException */ public MapLayer(AbstractGridCoverage2DReader reader, Style style, String title) { internal = new GridReaderLayer(reader, style, title); } /** * Constructor which adds a new layer and triggers a {@link LayerListEvent}. * * @param reader * a reader with the new layer that will be added * @param style * * @throws SchemaException * @throws FactoryRegistryException * @throws TransformException */ public MapLayer(AbstractGridCoverage2DReader reader, Style style) { internal = new GridReaderLayer(reader, style); } /** * * Add a new layer and trigger a {@link LayerListEvent}. * * @param coverage * The new layer that has been added. * @param style * @param title * @throws SchemaException * @throws FactoryRegistryException * @throws TransformException */ public MapLayer(GridCoverage coverage, Style style, String title) throws TransformException, FactoryRegistryException, SchemaException { internal = new GridCoverageLayer((GridCoverage2D) coverage, style, title); } /** * Access to raw layer object used for rendering. * * @return Layer used for rendering */ public Layer toLayer() { return internal; } /** * Get the feature collection for this layer; if available. * * @return The features for this layer, null if not available. */ @SuppressWarnings("unchecked") public FeatureSource getFeatureSource() { return internal.getFeatureSource(); // if (internal instanceof FeatureLayer) { // FeatureLayer layer = (FeatureLayer) internal; // return layer.getFeatureSource(); // } // else { // FeatureSource source = (FeatureSource) internal.getUserData().get("source"); // if( source == null ){ // if (internal instanceof GridCoverageLayer) { // GridCoverageLayer layer = (GridCoverageLayer) internal; // SimpleFeatureCollection featureCollection = layer.toFeatureCollection(); // source = DataUtilities.source(featureCollection); // layer.getUserData().put("source", source ); // } // if (internal instanceof GridReaderLayer) { // GridReaderLayer layer = (GridReaderLayer) internal; // SimpleFeatureCollection featureCollection = layer.toFeatureCollection(); // source = DataUtilities.source(featureCollection); // layer.getUserData().put("source", source ); // } // } // return source; // } } /** * Get the data source for this layer. * * @return Data source for this layer, null if not yet set or if {@link FeatureSource} is used */ public CollectionSource getSource() { return null; // no longer supported } /** * Get the style for this layer. If style has not been set, then null is returned. * * @return The style (SLD). */ public Style getStyle(){ return internal.getStyle(); // if (internal instanceof FeatureLayer) { // FeatureLayer layer = (FeatureLayer) internal; // return layer.getStyle(); // } // if (internal instanceof GridCoverageLayer) { // GridCoverageLayer layer = (GridCoverageLayer) internal; // return layer.getStyle(); // } // if (internal instanceof GridReaderLayer) { // GridReaderLayer layer = (GridReaderLayer) internal; // return layer.getStyle(); // } // return null; } /** * Sets the style for this layer. If a style has not been defined a default one is used. * * @param style * The new style */ public void setStyle(Style style){ if (style == null) { throw new NullPointerException("Style required"); } else if (internal instanceof StyleLayer) { StyleLayer layer = (StyleLayer) internal; layer.setStyle(style); } // else if (internal instanceof GridCoverageLayer) { // GridCoverageLayer layer = (GridCoverageLayer) internal; // layer.setStyle(style); // } // else if (internal instanceof GridReaderLayer) { // GridReaderLayer layer = (GridReaderLayer) internal; // layer.setStyle(style); // } else { throw new IllegalStateException("Style not supported by "+internal); } } /** * Get the title of this layer. If title has not been defined then an empty string is returned. * * @return The title of this layer. */ public String getTitle(){ return internal.getTitle(); } /** * Set the title of this layer. A {@link LayerEvent} is fired if the new title is different from * the previous one. * * @param title * The title of this layer. */ public void setTitle(String title) { if (title == null) { throw new NullPointerException("Title required"); } internal.setTitle(title); } /** * Determine whether this layer is visible on a map pane or whether the layer is hidden. * * @return <code>true</code> if the layer is visible, or <code>false</code> if the layer is * hidden. */ public boolean isVisible(){ return internal.isVisible(); } /** * Specify whether this layer is visible on a map pane or whether the layer is hidden. A * {@link LayerEvent} is fired if the visibility changed. * * @param visible * Show the layer if <code>true</code>, or hide the layer if <code>false</code> */ public void setVisible(boolean visible){ internal.setVisible(visible); } /** * Determine whether this layer is currently selected. * * @return <code>true</code> if the layer is selected, or <code>false</code> otherwise */ public boolean isSelected(){ Boolean selected = (Boolean) internal.getUserData().get("selected"); return selected == null ? false : selected; } /** * Specify whether this layer is selected. A {@link LayerEvent} iw fired if the selected status * is changed. * * @param selected * Set the layer as selected if <code>true</code> or as unselected if * <code>false</code> */ public void setSelected(boolean selected){ Boolean current = (Boolean) internal.getUserData().get("selected"); if (current != null && current == selected) { return; } internal.getUserData().put("selected", selected); if (selected) { internal.fireMapLayerListenerLayerSelected(); } else { internal.fireMapLayerListenerLayerDeselected(); } } /** * Returns the definition query (filter) for this layer. If no definition query has been defined * {@link Query.ALL} is returned. * @return the definition query established for this layer. If not set, just returns * {@link Query.ALL}, if set, returns a copy of the actual query object to avoid * external modification */ public Query getQuery(){ Query query = internal.getQuery(); if( query == null || query == Query.ALL ){ return Query.ALL; } else { // note query is already a copy return query; } // if( internal instanceof FeatureLayer ){ // FeatureLayer layer = (FeatureLayer) internal; // Query query = layer.getQuery(); // if( query == null || query == Query.ALL){ // return Query.ALL; // } // else { // return new Query( query ); // } // } // return Query.ALL; } /** * Sets a definition query for the layer which acts as a filter for the features that the layer * will draw. * * <p> * A consumer must ensure that this query is used in combination with the bounding box filter * generated on each map interaction to limit the number of features returned to those that * complains both the definition query and relies inside the area of interest. * </p> * <p> * IMPORTANT: only include attribute names in the query if you want them to be ALWAYS returned. * It is desirable to not include attributes at all but let the renderer * decide which attributes are actually needed to perform its required operation. * </p> * <p> * WARNING: We do not check if your query is suitable for the layer {@code FeatureSource} * you may accidentally return no features; resulting in an "empty" layer. * * @param query * the full filter for this layer. * * @throws NullPointerException * if no query is passed on. If you want to reset a definition query, pass it * {@link Query.ALL} instead of <code>null</code> * * @see org.geotools.map.FeatureLayer#setQuery(org.geotools.data.Query) */ public void setQuery(Query query){ if (query == null) { throw new NullPointerException("must provide a Query. Do you mean Query.ALL?"); } if( internal instanceof FeatureLayer ){ FeatureLayer layer = (FeatureLayer) internal; layer.setQuery( new Query(query)); } else { throw new IllegalStateException("Query not supported by "+ internal ); } } /** * find out the bounds of the layer * * @return - the layer's bounds */ public ReferencedEnvelope getBounds(){ return internal.getBounds(); } // ------------------------------------------------------------------------ // EVENT HANDLING CODE // ------------------------------------------------------------------------ /** * Registers MapLayerListener to receive events. * * @param listener * The listener to register. */ public synchronized void addMapLayerListener(org.geotools.map.event.MapLayerListener listener) { internal.addMapLayerListener(listener); } /** * Removes MapLayerListener from the list of listeners. * * @param listener * The listener to remove. */ public synchronized void removeMapLayerListener(org.geotools.map.event.MapLayerListener listener) { internal.removeMapLayerListener(listener); } /** * Notifies all registered listeners about the event. * * @param event * The event to be fired */ // protected void fireMapLayerListenerLayerChanged(org.geotools.map.event.MapLayerEvent event) { // internal.fireMapLayerListenerLayerChanged(event.getReason()); // } /** * Notifies all registered listeners about the event. * * @param event * The event to be fired */ // protected void fireMapLayerListenerLayerShown(org.geotools.map.event.MapLayerEvent event) { // internal.fireMapLayerListenerLayerShown(); // } /** * Notifies all registered listeners about the event. * * @param event * The event to be fired */ // protected void fireMapLayerListenerLayerHidden(org.geotools.map.event.MapLayerEvent event) { // internal.fireMapLayerListenerLayerHidden(); // } /** * Notifies all registered listeners about the selection event. * * @param event * The event to be fired */ // protected void fireMapLayerListenerLayerSelected(org.geotools.map.event.MapLayerEvent event) { // internal.fireMapLayerListenerLayerSelected(); // } /** * Notifies all registered listeners about the deselection event. * * @param event * The event to be fired */ // protected void fireMapLayerListenerLayerDeselected(org.geotools.map.event.MapLayerEvent event) { // internal.fireMapLayerListenerLayerDeselected(); // } // // Object Contract // /** Hashcode based on internal Layer */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((internal == null) ? 0 : internal.hashCode()); return result; } /** Equals based on internal layer */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof MapLayer)) { return false; } MapLayer other = (MapLayer) obj; if (internal == null) { if (other.internal != null) { return false; } } else if (!internal.equals(other.internal)) { return false; } return true; } public String toString() { StringBuilder buf = new StringBuilder(); buf.append("MapLayer:"); buf.append( internal ); return buf.toString(); } }