/* * 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.awt.geom.AffineTransform; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import org.geotools.coverage.grid.GridCoverage2D; import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader; import org.geotools.data.FeatureSource; import org.geotools.data.memory.CollectionSource; 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.MapBoundsEvent; import org.geotools.map.event.MapLayerEvent; import org.geotools.map.event.MapLayerListEvent; import org.geotools.map.event.MapLayerListener; import org.geotools.referencing.CRS; import org.geotools.referencing.crs.DefaultGeographicCRS; import org.geotools.resources.coverage.FeatureUtilities; import org.geotools.styling.Style; import org.opengis.coverage.grid.GridCoverage; import org.opengis.feature.Feature; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.feature.type.FeatureType; import org.opengis.referencing.FactoryException; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.TransformException; import com.vividsolutions.jts.geom.Envelope; import org.geotools.styling.SLD; /** * The default implementation of the {@linkplain org.geotools.map.MapContext} * interface * * @author Andrea Aime * @source $URL$ */ public class DefaultMapContext implements MapContext { /** The logger for the map module. */ static public final Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geotools.map"); /** List of MapLayers */ List<MapLayer> layerList = new ArrayList<MapLayer>(); /** Current area of interest */ ReferencedEnvelope areaOfInterest; /** Utility field used by event firing mechanism. */ protected javax.swing.event.EventListenerList listenerList = null; protected MapLayerListener layerListener = new MapLayerListener() { public void layerChanged(MapLayerEvent event) { fireAsListEvent(event); } public void layerShown(MapLayerEvent event) { fireAsListEvent(event); } public void layerHidden(MapLayerEvent event) { fireAsListEvent(event); } public void layerSelected(MapLayerEvent event) { fireAsListEvent(event); } public void layerDeselected(MapLayerEvent event) { fireAsListEvent(event); } private void fireAsListEvent(MapLayerEvent event) { MapLayer layer = (MapLayer) event.getSource(); int position = layerList.indexOf(layer); fireMapLayerListListenerLayerChanged(new MapLayerListEvent( DefaultMapContext.this, layer, position, event)); } }; /** Holds value of property abstracts. */ protected String abstracts; /** Utility field used by bound properties. */ protected java.beans.PropertyChangeSupport propertyChangeSupport = new java.beans.PropertyChangeSupport( this); /** Holds value of property contactInformation. */ protected String contactInformation; /** Holds value of property keywords. */ protected String[] keywords; /** Holds value of property title. */ protected String title; /** * Creates a default empty map context. The coordinate reference system * for the map context should be set explicitly, or implicitly via * {@code addLayer} prior to using the context. */ public DefaultMapContext() { this((CoordinateReferenceSystem) null); } /** * Creates a default empty map context * * @param crs the coordindate reference system to be used with this * context (may be null and set later) */ public DefaultMapContext(final CoordinateReferenceSystem crs) { this(null, null, null, null, null, crs); } /** * Creates a map context with the provided layers. * <p> * Note, the coordinate reference system for the context will be * set from that of the first layer with an available CRS. * * @param layers an array of MapLayer objects (may be empty or null) * to be added to this context */ public DefaultMapContext(MapLayer[] layers) { this(layers, DefaultGeographicCRS.WGS84); } /** * Creates a map context with the provided layers and coordinate * reference system * * @param layers an array of MapLayer objects (may be empty or null) * to be added to this context * @param crs the coordindate reference system to be used with this * context (may be null and set later) */ public DefaultMapContext(MapLayer[] layers, final CoordinateReferenceSystem crs) { this(layers, null, null, null, null, crs); } /** * Creates a map context * <p> * Note, the coordinate reference system for the context will be * set from that of the first layer with an available CRS. * * @param layers an array of MapLayer objects (may be empty or null) * to be added to this context * * @param title a title for this context (e.g. might be used by client-code * that is displaying the context's layers); may be null or an empty string * * @param contextAbstract a short description of the context and its * contents; may be null or an empty string * * @param contactInformation can be used, for example, to record the * creators or custodians of the data that are, or will be, held by this context; * may be null or an empty string * * @param keywords an optional array of key words pertaining to the * data that are, or will be, held by this context; * may be null or a zero-length String array * */ public DefaultMapContext(MapLayer[] layers, String title, String contextAbstract, String contactInformation, String[] keywords) { this(layers, title, contextAbstract, contactInformation, keywords, null); } /** * Creates a new map context * * @param layers an array of MapLayer objects (may be empty or null) * to be added to this context * * @param title a title for this context (e.g. might be used by client-code * that is displaying the context's layers); may be null or an empty string * * @param contextAbstract a short description of the context and its * contents; may be null or an empty string * * @param contactInformation can be used, for example, to record the * creators or custodians of the data that are, or will be, held by this context; * may be null or an empty string * * @param keywords an optional array of key words pertaining to the * data that are, or will be, held by this context; * may be null or a zero-length String array * * @param crs the coordindate reference system to be used with this * context (may be null and set later) */ public DefaultMapContext(MapLayer[] layers, String title, String contextAbstract, String contactInformation, String[] keywords, final CoordinateReferenceSystem crs) { setTitle(title); setAbstract(contextAbstract); setContactInformation(contactInformation); setKeywords(keywords); this.areaOfInterest = new ReferencedEnvelope(crs); addLayers(layers); } /** * Add a new layer if not already present and trigger a {@linkplain MapLayerListEvent}. * If a coordinate reference system has not been set for the context an attempt is * made to retrieve one from the new layer and use that as the context's CRS. * * @param index the position at which to insert the layer in the list of layers * held by this context * * @param layer the map layer to add * * @return true if the layer was added; false otherwise (layer was already present) */ public boolean addLayer(int index, MapLayer layer) { if (layerList.contains(layer)) { return false; } checkCRS(layer); layerList.add(index, layer); layer.addMapLayerListener(layerListener); fireMapLayerListListenerLayerAdded(new MapLayerListEvent(this, layer, index)); return true; } /** * Add a new layer, if not already present, to the end of the list of layers held * by this context and trigger a {@linkplain MapLayerListEvent} * If a coordinate reference system has not been set for the context an attempt is * made to retrieve one from the new layer and use that as the context's CRS. * * @param layer the map layer to add * * @return true if the layer was added; false otherwise (layer was already present) */ public boolean addLayer(MapLayer layer) { if (layerList.contains(layer)) { return false; } checkCRS(layer); layerList.add(layer); layer.addMapLayerListener(layerListener); fireMapLayerListListenerLayerAdded(new MapLayerListEvent(this, layer, indexOf(layer))); return true; } /** * Add the given feature source as a new layer to the end of the list of layers held * by this context and trigger a {@linkplain MapLayerListEvent}. * This is a convenience method equivalent to * {@linkplain #addLayer}(new DefaultMapLayer(featureSource, style). * <p> * If a coordinate reference system has not been set for the context an attempt is * made to retrieve one from the new layer and use that as the context's CRS. * <p> * If {@code style} is null, a default style is created using * {@linkplain SLD#createSimpleStyle(org.opengis.feature.simple.SimpleFeatureType)}. * * @param featureSource the source of the features for the new layer * * @param style a Style object to be used in rendering this layer. */ public void addLayer(FeatureSource<SimpleFeatureType, SimpleFeature> featureSource, Style style) { checkCRS(featureSource); Style layerStyle = checkStyle(style, featureSource.getSchema()); addLayer(new DefaultMapLayer(featureSource, layerStyle, "")); } /** * Add the given collection source as a new layer to the end of the list of layers held * by this context and trigger a {@linkplain MapLayerListEvent}. * This is a convenience method equivalent to * {@linkplain #addLayer}(new DefaultMapLayer(source, style). * <p> * If a coordinate reference system has not been set for the context an attempt is * made to retrieve one from the new layer and use that as the context's CRS. * * @param source the source of the features for the new layer * @param style a Style object to be used in rendering this layer */ public void addLayer(CollectionSource source, Style style) { // JG: for later when feature source extends source // if( source instanceof FeatureSource){ // addLayer( (FeatureSource<SimpleFeatureType, SimpleFeature>) source, style); // } this.addLayer(new DefaultMapLayer(source, style, "")); } /** * Add a grid coverage as a new layer to the end of the list of layers held by * this context. * <p> * If a coordinate reference system has not been set for the context an attempt is * made to retrieve one from the grid coverage and use that as the context's CRS. * * @param gc the grid coverage * @param style a Style to be used when rendering the new layer */ public void addLayer(GridCoverage gc, Style style) { if (style == null) { throw new IllegalArgumentException("style cannot be null"); } checkCRS(gc.getCoordinateReferenceSystem()); try { this.addLayer(FeatureUtilities.wrapGridCoverage((GridCoverage2D) gc), style); } catch (TransformException e) { DefaultMapContext.LOGGER.log(Level.WARNING, "Could not use gc", e); } catch (FactoryRegistryException e) { DefaultMapContext.LOGGER.log(Level.WARNING, "Could not use gc", e); } catch (SchemaException e) { DefaultMapContext.LOGGER.log(Level.WARNING, "Could not use gc", e); } } /** * Add a grid coverage data to be supplied by the given reader as a new layer * to the end of the list of layers held by this context. * <p> * If a coordinate reference system has not been set for the context an attempt is * made to retrieve one from the reader and use that as the context's CRS. * * @param reader the grid coverage reader * @param style a Style to be used when rendering the new layer */ public void addLayer(AbstractGridCoverage2DReader reader, Style style) { if (style == null) { throw new IllegalArgumentException("style cannot be null"); } checkCRS( reader.getCrs() ); try { this.addLayer(FeatureUtilities.wrapGridCoverageReader(reader, null), style); } catch (TransformException e) { DefaultMapContext.LOGGER.log(Level.WARNING, "Could not use gc", e); } catch (FactoryRegistryException e) { DefaultMapContext.LOGGER.log(Level.WARNING, "Could not use gc", e); } catch (SchemaException e) { DefaultMapContext.LOGGER.log(Level.WARNING, "Could not use gc", e); } } /** * Add the given feature collection as a new layer to the end of the list of layers held * by this context and trigger a {@linkplain MapLayerListEvent}. * This is a convenience method equivalent to * {@linkplain #addLayer}(new DefaultMapLayer(collection, style). * * @param collection the collection of features for the new layer * @param style a Style object to be used in rendering this layer */ public void addLayer(FeatureCollection<SimpleFeatureType, SimpleFeature> collection, Style style) { Style layerStyle = checkStyle(style, collection.getSchema()); this.addLayer(new DefaultMapLayer(collection, layerStyle, "")); } /** * Add the given collection as a new layer to the end of the list of layers held * by this context and trigger a {@linkplain MapLayerListEvent}. * This is a convenience method equivalent to * {@linkplain #addLayer}(new DefaultMapLayer(collection, style). * * @param collection the collection of features for the new layer * @param style a Style object to be used in rendering this layer */ public void addLayer(Collection collection, Style style) { if (collection instanceof FeatureCollection) { this.addLayer(new DefaultMapLayer((FeatureCollection<SimpleFeatureType, SimpleFeature>) collection, style, "")); return; } this.addLayer(new DefaultMapLayer(collection, style, "")); } /** * If a CRS has not been defined for this context, attempt to * get one from this map layer and set it as the context's CRS. * Invoked by addLayer methods. * * @param layer a map layer being added to the context */ private void checkCRS(MapLayer layer) { FeatureSource<? extends FeatureType, ? extends Feature> featureSource = layer.getFeatureSource(); if (featureSource != null) { checkCRS(featureSource); } else { CollectionSource source = layer.getSource(); if (source != null) { checkCRS( source.getCRS() ); } } } /** * If a CRS has not been defined for this context, attempt to * get one from this featureSource and set it as the context's CRS. * Invoked by addLayer. * * @param featureSource a feature source being added in a new layer */ private void checkCRS(FeatureSource<? extends FeatureType, ? extends Feature> featureSource) { if (featureSource != null) { checkCRS( featureSource.getSchema().getCoordinateReferenceSystem() ); } } /** * If a CRS has not been defined for this context yet use * the one provided if it is not null. We do this rather than * call setCoordinateReferenceSystem because we don't want to * trigger a change event being published to listeners. */ private void checkCRS(CoordinateReferenceSystem crs) { if (crs != null) { if (areaOfInterest.getCoordinateReferenceSystem() == null) { this.areaOfInterest = new ReferencedEnvelope(areaOfInterest, crs); } } } /** * Helper for some addLayer methods that tkae a Style argument. * Checks if the style is null and, if so, attepts to create a default Style. * @param style style argument that was passed to addLayer * @param featureType feature type for which a default style be will made if * required * * @return the input Style object if not {@code null}, or a Style instance * for a default style */ private Style checkStyle(Style style, SimpleFeatureType featureType) { if (style != null) { return style; } Style defaultStyle = SLD.createSimpleStyle(featureType); if (defaultStyle == null) { throw new IllegalStateException("Failed to creaate a default style for the layer"); } return defaultStyle; } /** * Remove the given layer from this context, if present, and * trigger a {@linkplain MapLayerListEvent} * * @param layer the layer to be removed * * @return true if the layer was present; false otherwise */ public boolean removeLayer(MapLayer layer) { int index = indexOf(layer); // getLayerBounds(); if (index == -1) { return false; } else { removeLayer(index); return true; } } /** * Remove the layer at the given position in the list of * layers held by this context. The position must be valid or * an IndexOutOfBoundsException will result. CAlling this method * triggers a {@linkplain MapLayerListEvent}. * * @param index the position of the layer in this context's list of layers * * @return the layer that was removed */ public MapLayer removeLayer(int index) { MapLayer layer = layerList.remove(index); // getLayerBounds(); layer.removeMapLayerListener(layerListener); fireMapLayerListListenerLayerRemoved(new MapLayerListEvent(this, layer, index)); return layer; } /** * Add an array of new layers to this context and trigger a {@link MapLayerListEvent}. * * @param layers the new layers that are to be added. * * @return the number of new layers actually added (will be less than the * length of the layers array if some layers were already present) */ public int addLayers(MapLayer[] layers) { if ((layers == null) || (layers.length == 0)) { return 0; } int layerAdded = 0; MapLayer lastLayer = null; final int length = layers.length; for (int i = 0; i < length; i++) { if (!layerList.contains(layers[i])) { checkCRS(layers[i]); layerList.add(layers[i]); layerAdded++; lastLayer = layers[i]; layers[i].addMapLayerListener(layerListener); } } if (layerAdded > 0) { int fromIndex = layerList.size() - layerAdded; int toIndex = layerList.size() - 1; if (layerAdded == 1) { fireMapLayerListListenerLayerAdded(new MapLayerListEvent(this, lastLayer, fromIndex, toIndex)); } else { fireMapLayerListListenerLayerAdded(new MapLayerListEvent(this, null, fromIndex, toIndex)); } } // getLayerBounds(); return layerAdded; } /** * Remove an array of layers, if present, and trigger a {@link MapLayerListEvent}. * * @param layers * The layers that are to be removed. */ public void removeLayers(MapLayer[] layers) { if ((layers == null) || (layers.length == 0) || (layerList.size() == 0)) { return; } // compute minimum and maximum index changed int fromIndex = layerList.size(); int toIndex = 0; int layersRemoved = 0; int length = layers.length; for (int i = 0; i < length; i++) { int index = layerList.indexOf(layers[i]); if (index == -1) { continue; } layersRemoved++; if (index < fromIndex) { fromIndex = index; } if (index > toIndex) { toIndex = index; } } if (layersRemoved == 0) { return; } // remove layerslength=layers.length; for (int i = 0; i < layersRemoved; i++) { if (layerList.remove(layers[i])) { layers[i].removeMapLayerListener(layerListener); } } // getLayerBounds(); // fire event fireMapLayerListListenerLayerRemoved(new MapLayerListEvent(this, null, fromIndex, toIndex)); } /** * Return this model's list of layers. If no layers are present, then an * empty array is returned. * * @return This model's list of layers. */ public MapLayer[] getLayers() { MapLayer[] layers = new MapLayer[layerList.size()]; return layerList.toArray(new MapLayer[0]); } /** * Return the requested layer. * * @param index * index of layer to return. * * @return the layer at the specified position * * @throws IndexOutOfBoundsException * if the index is out of range */ public MapLayer getLayer(int index) throws IndexOutOfBoundsException { return layerList.get(index); } /** * @see org.geotools.map.MapContext#indexOf(org.geotools.map.MapLayer) */ public int indexOf(MapLayer layer) { return layerList.indexOf(layer); } /** * Returns an iterator over the layers in this context in proper sequence. * * @return an iterator over the layers in this context in proper sequence. */ public Iterator iterator() { return layerList.iterator(); } /** * Get the bounding box of all the layers in this MapContext. If all the * layers cannot determine the bounding box in the speed required for each * layer, then null is returned. The bounds will be expressed in the * MapContext coordinate system. * * @return The bounding box of the features or null if unknown and too * expensive for the method to calculate. TODO: when coordinate * system information will be added reproject the bounds according * to the current coordinate system * * @throws IOException * DOCUMENT ME! * */ public ReferencedEnvelope getLayerBounds() throws IOException { ReferencedEnvelope result = null; CoordinateReferenceSystem crs = areaOfInterest.getCoordinateReferenceSystem(); final int length = layerList.size(); MapLayer layer; FeatureSource<SimpleFeatureType, SimpleFeature> fs; ReferencedEnvelope env; CoordinateReferenceSystem sourceCrs; for (int i = 0; i < length; i++) { layer = layerList.get(i); /*fs = layer.getFeatureSource(); sourceCrs = fs.getSchema().getDefaultGeometry() .getCoordinateSystem(); env = new ReferencedEnvelope(fs.getBounds(), sourceCrs);*/ env = layer.getBounds(); if (env == null) { continue; } else { try { sourceCrs = env.getCoordinateReferenceSystem(); if ((sourceCrs != null) && crs != null && !CRS.equalsIgnoreMetadata(sourceCrs, crs)) { env = env.transform(crs, true); } } catch (FactoryException e) { LOGGER.log( Level.SEVERE, "Data source and map context coordinate system differ, yet it was not possible to get a projected bounds estimate...", e); } catch (TransformException e) { LOGGER.log( Level.SEVERE, "Data source and map context coordinate system differ, yet it was not possible to get a projected bounds estimate...", e); } if (result == null) { result = env; } else { result.expandToInclude(env); } } } return result; } /** * Gets the current area of interest. If no area of interest is set, the * default is to fall back on the layer bounds * * @return Current area of interest * */ public ReferencedEnvelope getAreaOfInterest() { if (areaOfInterest.isEmpty()) { try { final Envelope e = getLayerBounds(); if (e != null) { areaOfInterest = new ReferencedEnvelope(e, getCoordinateReferenceSystem()); } else { return null; } } catch (IOException e) { LOGGER.log( Level.SEVERE, "Can't get layer bounds, and area of interest is not set", e); return null; } } return new ReferencedEnvelope(this.areaOfInterest); } /** * Get the current coordinate system of this context * * @return the coordinate system (may be null) */ public CoordinateReferenceSystem getCoordinateReferenceSystem() { return areaOfInterest.getCoordinateReferenceSystem(); } /** * Transform the current area of interest for this context using the provided transform. * This may be useful for zooming and panning processes. * * @param transform The transform to change area of interest. */ public void transform(AffineTransform transform) { ReferencedEnvelope oldAreaOfInterest = this.areaOfInterest; double[] coords = new double[4]; coords[0] = areaOfInterest.getMinX(); coords[1] = areaOfInterest.getMinY(); coords[2] = areaOfInterest.getMaxX(); coords[3] = areaOfInterest.getMaxY(); transform.transform(coords, 0, coords, 0, 2); this.areaOfInterest = new ReferencedEnvelope(coords[0], coords[2], coords[1], coords[3], areaOfInterest.getCoordinateReferenceSystem()); fireMapBoundsListenerMapBoundsChanged(new MapBoundsEvent(this, MapBoundsEvent.AREA_OF_INTEREST_MASK, oldAreaOfInterest, new ReferencedEnvelope(this.areaOfInterest))); } /** * Change the position of a layer in this context's list of map layers. * This triggers a MapLayerList event. * * @param sourcePosition the layer's current position * @param destPosition the new position * * @throws IndexOutOfBoundsException if either position is less than zero or * not less than the number of layers. */ public void moveLayer(int sourcePosition, int destPosition) { if ((sourcePosition < 0) || (sourcePosition >= layerList.size())) { throw new IndexOutOfBoundsException("Source position " + sourcePosition + " out of bounds"); } if ((destPosition < 0) || (destPosition >= layerList.size())) { throw new IndexOutOfBoundsException("Destination position " + destPosition + " out of bounds"); } MapLayer layer = layerList.remove(sourcePosition); layerList.add(destPosition, layer); fireMapLayerListListenerLayerMoved(new MapLayerListEvent(this, layer, Math.min(sourcePosition, destPosition), Math.max( sourcePosition, destPosition))); } /** * Remove all of the map layers from this context. * This triggers a MapLayerListEvent. * */ public void clearLayerList() { final int size = layerList.size(); for (int i = 0; i < size; i++) { MapLayer layer = layerList.get(i); layer.removeMapLayerListener(layerListener); } layerList.clear(); fireMapLayerListListenerLayerRemoved(new MapLayerListEvent(this, null, 0, 1)); } /** * Returns the number of layers in this map context * * @return the number of layers in this map context */ public int getLayerCount() { return layerList.size(); } /** * Getter for property abstracts. * * @return Value of property abstracts. */ public String getAbstract() { return this.abstracts; } /** * Setter for property abstracts. * * @param abstractValue * New value of property abstracts. * */ public void setAbstract(String abstractValue) { String oldAbstracts = this.abstracts; this.abstracts = (abstractValue == null ? "" : abstractValue); propertyChangeSupport.firePropertyChange("abstract", oldAbstracts, abstracts); } /** * Getter for property contactInformation. * * @return Value of property contactInformation. */ public String getContactInformation() { return this.contactInformation; } /** * Setter for property contactInformation. * * @param contactInformation * New value of property contactInformation. */ public void setContactInformation(String contactInformation) { String oldContactInformation = this.contactInformation; this.contactInformation = (contactInformation == null ? "" : contactInformation); propertyChangeSupport.firePropertyChange("contactInformation", oldContactInformation, contactInformation); } /** * Getter for property keywords. * * @return Value of property keywords. */ public String[] getKeywords() { if (this.keywords.length == 0) { return this.keywords; } else { String[] copy = new String[keywords.length]; System.arraycopy(keywords, 0, copy, 0, keywords.length); return copy; } } /** * Setter for property keywords. * * @param keywords * New value of property keywords. */ public void setKeywords(String[] keywords) { String[] oldKeywords = this.keywords; this.keywords = (keywords == null ? new String[0] : keywords); propertyChangeSupport.firePropertyChange("keywords", oldKeywords, keywords); } /** * Getter for property title. * * @return Value of property title. */ public String getTitle() { return this.title; } /** * Setter for property title. * * @param title * New value of property title. */ public void setTitle(String title) { String oldTitle = this.title; this.title = (title == null ? "" : title); propertyChangeSupport.firePropertyChange("title", oldTitle, title); } // ------------------------------------------------------------------------ // EVENT LISTENERS AND EVENT FIRING CODE // ------------------------------------------------------------------------ /** * Registers MapLayerListListener to receive events. * * @param listener * The listener to register. */ public synchronized void addMapLayerListListener( org.geotools.map.event.MapLayerListListener listener) { if (listenerList == null) { listenerList = new javax.swing.event.EventListenerList(); } listenerList.add(org.geotools.map.event.MapLayerListListener.class, listener); } /** * Removes MapLayerListListener from the list of listeners. * * @param listener * The listener to remove. */ public synchronized void removeMapLayerListListener( org.geotools.map.event.MapLayerListListener listener) { if (listenerList == null) { return; } listenerList.remove(org.geotools.map.event.MapLayerListListener.class, listener); } /** * Notifies all registered listeners about the event. * * @param event * The event to be fired */ private void fireMapLayerListListenerLayerAdded( org.geotools.map.event.MapLayerListEvent event) { if (listenerList == null) { return; } Object[] listeners = listenerList.getListenerList(); final int length = listeners.length; for (int i = length - 2; i >= 0; i -= 2) { if (listeners[i] == org.geotools.map.event.MapLayerListListener.class) { ((org.geotools.map.event.MapLayerListListener) listeners[i + 1]).layerAdded(event); } } } /** * Notifies all registered listeners about the event. * * @param event * The event to be fired */ private void fireMapLayerListListenerLayerRemoved( org.geotools.map.event.MapLayerListEvent event) { if (listenerList == null) { return; } Object[] listeners = listenerList.getListenerList(); final int length = listeners.length; for (int i = length - 2; i >= 0; i -= 2) { if (listeners[i] == org.geotools.map.event.MapLayerListListener.class) { ((org.geotools.map.event.MapLayerListListener) listeners[i + 1]).layerRemoved(event); } } } /** * Notifies all registered listeners about the event. * * @param event * The event to be fired */ private void fireMapLayerListListenerLayerChanged( org.geotools.map.event.MapLayerListEvent event) { if (listenerList == null) { return; } Object[] listeners = listenerList.getListenerList(); final int length = listeners.length; for (int i = length - 2; i >= 0; i -= 2) { if (listeners[i] == org.geotools.map.event.MapLayerListListener.class) { ((org.geotools.map.event.MapLayerListListener) listeners[i + 1]).layerChanged(event); } } } /** * Notifies all registered listeners about the event. * * @param event * The event to be fired */ private void fireMapLayerListListenerLayerMoved( org.geotools.map.event.MapLayerListEvent event) { if (listenerList == null) { return; } Object[] listeners = listenerList.getListenerList(); final int length = listeners.length; for (int i = length - 2; i >= 0; i -= 2) { if (listeners[i] == org.geotools.map.event.MapLayerListListener.class) { ((org.geotools.map.event.MapLayerListListener) listeners[i + 1]).layerMoved(event); } } } /** * Registers PropertyChangeListener to receive events. * * @param listener * The listener to register. */ public synchronized void addPropertyChangeListener( java.beans.PropertyChangeListener listener) { propertyChangeSupport.addPropertyChangeListener(listener); } /** * Removes PropertyChangeListener from the list of listeners. * * @param listener * The listener to remove. */ public synchronized void removePropertyChangeListener( java.beans.PropertyChangeListener listener) { if (listenerList == null) { return; } propertyChangeSupport.removePropertyChangeListener(listener); } /** * Registers MapBoundsListener to receive events. * * @param listener * The listener to register. */ public synchronized void addMapBoundsListener( org.geotools.map.event.MapBoundsListener listener) { if (listenerList == null) { listenerList = new javax.swing.event.EventListenerList(); } listenerList.add(org.geotools.map.event.MapBoundsListener.class, listener); } /** * Removes MapBoundsListener from the list of listeners. * * @param listener * The listener to remove. */ public synchronized void removeMapBoundsListener( org.geotools.map.event.MapBoundsListener listener) { if (listenerList == null) { return; } listenerList.remove(org.geotools.map.event.MapBoundsListener.class, listener); } /** * Notifies all registered listeners about the event. * * @param event * The event to be fired */ private void fireMapBoundsListenerMapBoundsChanged( org.geotools.map.event.MapBoundsEvent event) { if (listenerList == null) { return; } Object[] listeners = listenerList.getListenerList(); final int length = listeners.length; for (int i = length - 2; i >= 0; i -= 2) { if (listeners[i] == org.geotools.map.event.MapBoundsListener.class) { ((org.geotools.map.event.MapBoundsListener) listeners[i + 1]).mapBoundsChanged(event); } } } /** * Set the area of interest. This triggers a MapBoundsEvent to be * published. * * @param areaOfInterest the new area of interest * * @throws IllegalArgumentException if the argument is {@code null} * * @deprecated Use of this method is not safe. Please use * {@linkplain #setAreaOfInterest(Envelope, CoordinateReferenceSystem)} * instead. */ public void setAreaOfInterest(Envelope areaOfInterest) throws IllegalArgumentException { CoordinateReferenceSystem crs = this.areaOfInterest.getCoordinateReferenceSystem(); if (crs == null) { crs = DefaultGeographicCRS.WGS84; } ReferencedEnvelope refEnv = new ReferencedEnvelope(areaOfInterest, crs); setAreaOfInterest(refEnv); } /** * Set the area of interest. This triggers a MapBoundsEvent to be * published. * * @param areaOfInterest the new area of interest * @param coordinateReferenceSystem the CRS for the new area of interest * * @throws IllegalArgumentException if areaOfInterest is {@code null} */ public void setAreaOfInterest(Envelope areaOfInterest, CoordinateReferenceSystem crs) throws IllegalArgumentException { if (areaOfInterest == null) { throw new IllegalArgumentException("areaOfInterest should not be null"); } setAreaOfInterest(new ReferencedEnvelope(areaOfInterest, crs)); } /** * Set the area of interest. This triggers a MapBoundsEvent to be * published. * * @param areaOfInterest the new area of interest * * @throws IllegalArgumentException if the provided areaOfInterest is {@code null} * or does not have a coordinate reference system */ public void setAreaOfInterest(ReferencedEnvelope areaOfInterest) { if (areaOfInterest == null) { throw new IllegalArgumentException("areaOfInterest must not be null"); } ReferencedEnvelope oldAreaOfInterest = this.areaOfInterest; CoordinateReferenceSystem oldCRS = this.areaOfInterest.getCoordinateReferenceSystem(); this.areaOfInterest = new ReferencedEnvelope(areaOfInterest); int flags = 0; if (oldCRS != null) { if (!CRS.equalsIgnoreMetadata( this.areaOfInterest.getCoordinateReferenceSystem(), oldCRS )) { flags |= MapBoundsEvent.COORDINATE_SYSTEM_MASK; } } else if (this.areaOfInterest.getCoordinateReferenceSystem() != null) { flags |= MapBoundsEvent.COORDINATE_SYSTEM_MASK; } if (!this.areaOfInterest.boundsEquals2D(oldAreaOfInterest, 1.0e-4d)) { flags |= MapBoundsEvent.AREA_OF_INTEREST_MASK; } fireMapBoundsListenerMapBoundsChanged( new MapBoundsEvent(this, flags, oldAreaOfInterest, new ReferencedEnvelope(this.areaOfInterest))); } /** * Set or change the coordinate reference system for this context. * This will trigger a MapBoundsEvent to be published to listeners. * * @throws FactoryException * @throws TransformException * */ public void setCoordinateReferenceSystem(CoordinateReferenceSystem crs) throws TransformException, FactoryException { final ReferencedEnvelope oldAreaOfInterest = this.areaOfInterest; final CoordinateReferenceSystem oldCRS = this.areaOfInterest.getCoordinateReferenceSystem(); if (oldCRS != null) { if (!CRS.equalsIgnoreMetadata(crs, oldCRS)) { this.areaOfInterest = this.areaOfInterest.transform(crs, true); } } else { this.areaOfInterest = new ReferencedEnvelope(areaOfInterest, crs); } fireMapBoundsListenerMapBoundsChanged(new MapBoundsEvent(this, MapBoundsEvent.COORDINATE_SYSTEM_MASK, oldAreaOfInterest, new ReferencedEnvelope(this.areaOfInterest))); } }