//$HeadURL$
/*---------------- FILE HEADER ------------------------------------------
This file is part of deegree.
Copyright (C) 2001-2008 by:
Department of Geography, University of Bonn
http://www.giub.uni-bonn.de/deegree/
lat/lon GmbH
http://www.lat-lon.de
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; either
version 2.1 of the License, or (at your option) any later version.
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.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact:
Andreas Poth
lat/lon GmbH
Aennchenstr. 19
53177 Bonn
Germany
E-Mail: poth@lat-lon.de
Prof. Dr. Klaus Greve
Department of Geography
University of Bonn
Meckenheimer Allee 166
53115 Bonn
Germany
E-Mail: greve@giub.uni-bonn.de
---------------------------------------------------------------------------*/
package org.deegree.igeo.mapmodel;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.xml.bind.JAXBElement;
import org.deegree.framework.log.ILogger;
import org.deegree.framework.log.LoggerFactory;
import org.deegree.framework.util.CollectionUtils.Mapper;
import org.deegree.framework.util.ImageUtils;
import org.deegree.graphics.sld.AbstractLayer;
import org.deegree.graphics.sld.AbstractStyle;
import org.deegree.graphics.sld.NamedLayer;
import org.deegree.graphics.sld.StyledLayerDescriptor;
import org.deegree.igeo.ChangeListener;
import org.deegree.igeo.ValueChangedEvent;
import org.deegree.igeo.config.AbstractDatasourceType;
import org.deegree.igeo.config.DatabaseDatasourceType;
import org.deegree.igeo.config.DatasourceType;
import org.deegree.igeo.config.DefinedStyleType;
import org.deegree.igeo.config.DirectStyleType;
import org.deegree.igeo.config.ExternalResourceType;
import org.deegree.igeo.config.FileDatasourceType;
import org.deegree.igeo.config.IdentifierType;
import org.deegree.igeo.config.LayerType;
import org.deegree.igeo.config.LayerType.MetadataURL;
import org.deegree.igeo.config.MemoryDatasourceType;
import org.deegree.igeo.config.NamedStyleType;
import org.deegree.igeo.config.NamedStyleType.LegendURL;
import org.deegree.igeo.config.ObjectFactory;
import org.deegree.igeo.config.OnlineResourceType;
import org.deegree.igeo.config.StyleType;
import org.deegree.igeo.config.Util;
import org.deegree.igeo.config.WCSDatasourceType;
import org.deegree.igeo.config.WFSDatasourceType;
import org.deegree.igeo.config.WMSDatasourceType;
import org.deegree.igeo.dataadapter.Adapter;
import org.deegree.igeo.dataadapter.AdapterEvent;
import org.deegree.igeo.dataadapter.DataAccessAdapter;
import org.deegree.igeo.dataadapter.DataAccessException;
import org.deegree.igeo.dataadapter.DataAccessFactory;
import org.deegree.igeo.dataadapter.FeatureAdapter;
import org.deegree.igeo.i18n.Messages;
import org.deegree.igeo.mapmodel.LayerChangedEvent.LAYER_CHANGE_TYPE;
import org.deegree.io.datastore.PropertyPathResolvingException;
import org.deegree.model.Identifier;
import org.deegree.model.feature.Feature;
import org.deegree.model.feature.FeatureCollection;
import org.deegree.model.feature.FeatureFactory;
import org.deegree.model.feature.FeatureProperty;
import org.deegree.model.feature.schema.FeatureType;
import org.deegree.model.filterencoding.Filter;
import org.deegree.model.filterencoding.FilterEvaluationException;
import org.deegree.model.spatialschema.Envelope;
import org.deegree.model.spatialschema.Point;
import org.deegree.ogcbase.PropertyPath;
/**
* Implementation of interface {@link MapModelEntry} for modelling a Layer. A layer is always assigned to a
* {@link Datasource} and can access its data via an according {@link DataAccessAdapter}.
*
*
* @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
* @author last edited by: $Author$
*
* @version. $Revision$, $Date$
*/
public class Layer implements MapModelEntry {
private static final ILogger LOG = LoggerFactory.getLogger( Layer.class );
transient protected List<ChangeListener> listeners = new ArrayList<ChangeListener>();
private LayerGroup parent;
private MapModel owner;
private List<Datasource> datasources;
private List<NamedStyle> styles;
private List<DataAccessAdapter> dataAccess;
private Map<String, DataAccessException> dataAccessExceptions = new HashMap<String, DataAccessException>();
transient private FeatureCollection selectedFeatures;
transient private List<FeatureProperty> selectedGeometries;
private LayerType layerType;
/**
*
* @param owner
* @param identifier
* @param title
* @param abstract_
*/
public Layer( MapModel owner, Identifier identifier, String title, String abstract_ ) {
this( owner, identifier, title, abstract_, new ArrayList<Datasource>(), new ArrayList<MetadataURL>() );
}
/**
*
* @param owner
* @param identifier
* @param title
* @param abstract_
* @param datasources
* @param metadataURLs
*/
public Layer( MapModel owner, Identifier identifier, String title, String abstract_, List<Datasource> datasources,
List<MetadataURL> metadataURLs ) {
layerType = new LayerType();
IdentifierType id = new IdentifierType();
id.setValue( identifier.getValue() );
if ( identifier.getNamespace() != null ) {
id.setNamespace( identifier.getNamespace().toASCIIString() );
}
layerType.setIdentifier( id );
layerType.setTitle( title );
layerType.setAbstract( abstract_ );
layerType.setMinScaleDenominator( 0d );
layerType.setMaxScaleDenominator( 9E99 );
layerType.setEditable( true );
layerType.setQueryable( true );
layerType.setVisible( true );
setMetadataURL( metadataURLs );
List<String> crs = new ArrayList<String>();
crs.add( owner.getCoordinateSystem().getPrefixedName() );
NamedStyleType nst = new NamedStyleType();
nst.setName( "default" );
nst.setTitle( "default" );
nst.setAbstract( "default" );
nst.setCurrent( true );
List<StyleType> styleTypes = layerType.getStyle();
styleTypes.clear();
StyleType st = new StyleType();
st.setNamedStyle( new ObjectFactory().createNamedStyle( nst ) );
styleTypes.add( st );
NamedStyle nStyle = new NamedStyle( nst, this );
nStyle.setCurrent( true );
styles = new ArrayList<NamedStyle>();
styles.add( nStyle );
this.owner = owner;
// must use set-Method to avoid in consistent states
setDatasources( datasources );
this.selectedFeatures = FeatureFactory.createFeatureCollection( new Identifier().getAsQualifiedString(), 10 );
}
/**
*
* @param layerType
* @param owner
* @param datasources
* @param styles
*/
public Layer( LayerType layerType, MapModel owner, List<Datasource> datasources, List<NamedStyle> styles ) {
this.layerType = layerType;
this.styles = styles;
this.owner = owner;
// must use set-Method to avoid in consistent states
setDatasources( datasources );
this.selectedFeatures = FeatureFactory.createFeatureCollection( new Identifier().getAsQualifiedString(), 10 );
}
/**
*
* @return encapsulated configuration layer
*/
public LayerType getLayerType() {
return layerType;
}
/**
*
* @return abstract
*/
public String getAbstract() {
return layerType.getAbstract();
}
/**
*
* @param abstract_
*/
public void setAbstract( String abstract_ ) {
layerType.setAbstract( abstract_ );
}
/**
*
* @return list of used datasources
*/
public List<Datasource> getDatasources() {
if ( this.datasources == null ) {
this.datasources = new ArrayList<Datasource>();
}
return this.datasources;
}
/**
* @return a list of exceptions occured during trying to access a datasource
*/
public Map<String, DataAccessException> getDataAccessExceptions() {
return dataAccessExceptions;
}
/**
* adds a data source to a layer
*
* @param datasource
*/
public void addDatasource( Datasource datasource ) {
if ( this.datasources == null ) {
this.datasources = new ArrayList<Datasource>();
}
this.datasources.add( datasource );
// a new data access object must be created if a data source is added to a layer
dataAccess.add( DataAccessFactory.createDataAccessAdapter( datasource, owner, this ) );
DatasourceType dt = new DatasourceType();
AbstractDatasourceType dsType = datasource.getDatasourceType();
JAXBElement<? extends AbstractDatasourceType> ds = null;
if ( dsType instanceof FileDatasourceType ) {
ds = new ObjectFactory().createFileDatasource( (FileDatasourceType) dsType );
} else if ( dsType instanceof DatabaseDatasourceType ) {
ds = new ObjectFactory().createDatabaseDatasource( (DatabaseDatasourceType) dsType );
} else if ( dsType instanceof WMSDatasourceType ) {
ds = new ObjectFactory().createWMSDatasource( (WMSDatasourceType) dsType );
} else if ( dsType instanceof WFSDatasourceType ) {
ds = new ObjectFactory().createWFSDatasource( (WFSDatasourceType) dsType );
} else if ( dsType instanceof WCSDatasourceType ) {
ds = new ObjectFactory().createWCSDatasource( (WCSDatasourceType) dsType );
} else if ( dsType instanceof MemoryDatasourceType ) {
ds = new ObjectFactory().createMemoryDatasource( (MemoryDatasourceType) dsType );
}
dt.setAbstractDatasource( ds );
layerType.getDatasource().add( dt );
}
/**
* sets a complete new list of {@link Datasource}es
*
* @param datasources
*/
public void setDatasources( List<Datasource> datasources ) {
if ( this.datasources == null ) {
this.datasources = new ArrayList<Datasource>();
} else {
this.datasources.clear();
}
if ( dataAccess == null ) {
this.dataAccess = new ArrayList<DataAccessAdapter>( datasources.size() );
} else {
this.dataAccess.clear();
}
this.dataAccessExceptions.clear();
layerType.getDatasource().clear();
for ( Datasource datasource : datasources ) {
try {
addDatasource( datasource );
} catch ( DataAccessException e ) {
this.dataAccessExceptions.put( datasource.getName(), e );
}
}
}
/**
* removes a datasource from a layer
*
* @param datasource
*/
public void removeDatasource( Datasource datasource ) {
this.datasources.remove( datasource );
if ( dataAccess != null ) {
ListIterator<DataAccessAdapter> iter = dataAccess.listIterator();
while ( iter.hasNext() ) {
if ( iter.next().getDatasource() == datasource ) {
iter.remove();
}
}
}
}
/**
*
* @return list of assigend external resources
*/
public List<ExternalResourceType> getExternalResources() {
return layerType.getExternalResource();
}
/**
*
* @param externalResources
*/
public void setExternalResources( List<ExternalResourceType> externalResources ) {
List<ExternalResourceType> tmp = layerType.getExternalResource();
tmp.addAll( externalResources );
}
/**
*
* @param externalResource
*/
public void addExternalResources( ExternalResourceType externalResource ) {
List<ExternalResourceType> tmp = layerType.getExternalResource();
tmp.add( externalResource );
}
/**
*
* @param externalResource
*/
public void removeExternalResources( ExternalResourceType externalResource ) {
List<ExternalResourceType> tmp = layerType.getExternalResource();
tmp.remove( externalResource );
}
/**
*
* @return layers identifier
*/
public Identifier getIdentifier() {
return Util.convertIdentifier( layerType.getIdentifier() );
}
/**
*
* @return true if queryable (e.g. GetFeatureInfo or GetFeature)
*/
public boolean isQueryable() {
return layerType.isQueryable();
}
/**
*
* @param isQueryable
*/
public void setQueryable( boolean isQueryable ) {
layerType.setQueryable( isQueryable );
}
/**
*
* @return true if visible
*/
public boolean isVisible() {
return layerType.isVisible();
}
/**
*
* @param visible
*/
public void setVisible( boolean visible ) {
if ( visible != layerType.isVisible() ) {
layerType.setVisible( visible );
if ( !visible ) {
unselectAllFeatures();
}
fireLayerChangedEvent( LAYER_CHANGE_TYPE.visibilityChanged, visible );
}
}
/**
* @return the isEditable
*/
public boolean isEditable() {
return layerType.isEditable();
}
/**
* @param isEditable
* the isEditable to set
*/
public void setEditable( boolean isEditable ) {
layerType.setEditable( isEditable );
}
/**
*
* @return maximum scale denominator
*/
public double getMaxScaleDenominator() {
return layerType.getMaxScaleDenominator();
}
/**
*
* @param maxScaleDenominator
*/
public void setMaxScaleDenominator( double maxScaleDenominator ) {
layerType.setMaxScaleDenominator( maxScaleDenominator );
}
/**
*
* @return list of assigend metadata URLs
*/
public List<MetadataURL> getMetadataURLs() {
return layerType.getMetadataURL();
}
/**
*
* @param metadataURLs
*/
public void setMetadataURL( List<MetadataURL> metadataURLs ) {
if ( metadataURLs != null ) {
List<MetadataURL> tmp = layerType.getMetadataURL();
tmp.clear();
tmp.addAll( metadataURLs );
}
}
/**
*
* @param metadataURL
*/
public void addMetadataURL( MetadataURL metadataURL ) {
List<MetadataURL> tmp = layerType.getMetadataURL();
tmp.add( metadataURL );
}
/**
*
* @param metadataURL
*/
public void removeMetadataURL( MetadataURL metadataURL ) {
List<MetadataURL> tmp = layerType.getMetadataURL();
tmp.remove( metadataURL );
}
/**
*
* @return minimum scale denominator
*/
public double getMinScaleDenominator() {
return layerType.getMinScaleDenominator();
}
/**
*
* @param minScaleDenominator
*/
public void setMinScaleDenominator( double minScaleDenominator ) {
layerType.setMinScaleDenominator( minScaleDenominator );
}
/**
*
* @return id of layers parent; may be <code>null</code>
*/
public LayerGroup getParent() {
return this.parent;
}
/**
*
* @return antecessor layer or <code>null</code> if a layer do not have an antecessor
*/
public Layer getAntecessor() {
Layer antecessor = null;
List<MapModelEntry> mme = this.parent.getMapModelEntries();
for ( int i = 1; i < mme.size(); i++ ) {
if ( mme.get( i ).equals( this ) && mme.get( i - 1 ) instanceof Layer ) {
antecessor = (Layer) mme.get( i - 1 );
break;
}
}
return antecessor;
}
/**
*
* @param parent
*/
public void setParent( LayerGroup parent ) {
if ( parent != null && !parent.equals( this.parent ) ) {
// remove from old parent
if ( this.parent != null ) {
this.parent.removeLayer( this );
}
this.parent = parent;
// add to new parent
this.parent.addLayer( this );
} else if ( parent == null ) {
this.parent = null;
}
}
/**
* @return the owner
*/
public MapModel getOwner() {
return owner;
}
/**
*
* @return list of action a layer is selected for
*/
public List<String> getSelectedFor() {
return layerType.getSelectedFor();
}
/**
*
* @param selectedFor
*/
public void setSelectedFor( List<String> selectedFor ) {
List<String> tmp = layerType.getSelectedFor();
tmp.clear();
tmp.addAll( selectedFor );
fireLayerChangedEvent( LAYER_CHANGE_TYPE.selectedForChanged, selectedFor );
}
/**
*
* @param selectedFor
*/
public void addSelectedFor( String selectedFor ) {
List<String> tmp = layerType.getSelectedFor();
if ( !tmp.contains( selectedFor ) ) {
tmp.add( selectedFor );
fireLayerChangedEvent( LAYER_CHANGE_TYPE.selectedForChanged, selectedFor );
}
}
/**
*
* @param selectedFor
*/
public void removeSelectedFor( String selectedFor ) {
List<String> tmp = layerType.getSelectedFor();
if ( tmp.contains( selectedFor ) ) {
tmp.remove( selectedFor );
fireLayerChangedEvent( LAYER_CHANGE_TYPE.selectedForChanged, selectedFor );
}
}
/**
*
* @return list of assigend styles
*/
public List<NamedStyle> getStyles() {
return this.styles;
}
/**
*
* @param styles
* @throws URISyntaxException
* @throws IOException
*/
public void setStyles( List<NamedStyle> styles )
throws URISyntaxException, IOException {
this.styles = styles;
List<StyleType> styleTypes = layerType.getStyle();
styleTypes.clear();
for ( NamedStyle namedStyle : this.styles ) {
StyleType st = createStyleType( namedStyle );
styleTypes.add( st );
}
fireLayerChangedEvent( LAYER_CHANGE_TYPE.stylesSet, this.styles );
}
private StyleType createStyleType( NamedStyle namedStyle )
throws URISyntaxException, IOException {
NamedStyleType nst = null;
if ( namedStyle instanceof DirectStyle ) {
nst = new DirectStyleType();
AbstractLayer al = new NamedLayer( getTitle(), null, new AbstractStyle[] { namedStyle.getStyle() } );
StyledLayerDescriptor sld = new StyledLayerDescriptor( new AbstractLayer[] { al }, "1.0.0" );
( (DirectStyleType) nst ).setSld( sld.exportAsXML() );
} else {
nst = new NamedStyleType();
}
if ( nst instanceof DefinedStyleType && namedStyle instanceof DefinedStyle ) {
( (DefinedStyleType) nst ).setUom( ( (DefinedStyle) namedStyle ).getUom() );
}
nst.setCurrent( namedStyle.isCurrent() );
nst.setAbstract( namedStyle.getAbstract() );
nst.setName( namedStyle.getName() );
nst.setTitle( namedStyle.getTitle() );
if ( namedStyle.getLegendURL() != null ) {
LegendURL lu = new NamedStyleType.LegendURL();
OnlineResourceType ort = new OnlineResourceType();
ort.setHref( namedStyle.getLegendURL().toExternalForm() );
lu.setOnlineResource( ort );
nst.setLegendURL( lu );
} else if ( namedStyle.getLegendImage() != null ) {
BufferedImage bi = namedStyle.getLegendImage();
ByteArrayOutputStream bos = new ByteArrayOutputStream( 2000 );
ImageUtils.saveImage( bi, bos, "png", 1f );
nst.setLegendImage( bos.toByteArray() );
bos.close();
}
StyleType st = new StyleType();
if ( nst instanceof DirectStyleType ) {
st.setNamedStyle( new ObjectFactory().createDirectStyle( (DirectStyleType) nst ) );
} else {
st.setNamedStyle( new ObjectFactory().createNamedStyle( nst ) );
}
return st;
}
/**
*
* @param style
* @throws IOException
* @throws URISyntaxException
*/
public void addStyle( NamedStyle style )
throws URISyntaxException, IOException {
if ( this.styles == null ) {
this.styles = new ArrayList<NamedStyle>();
}
this.styles.add( style );
layerType.getStyle().add( createStyleType( style ) );
}
/**
*
* @param style
*/
public void removeStyle( NamedStyle style ) {
this.styles.remove( style );
}
/**
*
* @return layers title
*/
public String getTitle() {
return layerType.getTitle();
}
/**
*
* @param title
*/
public void setTitle( String title ) {
layerType.setTitle( title );
}
/**
*
* @return data access object for a layer
*/
public List<DataAccessAdapter> getDataAccess() {
return dataAccess;
}
/**
*
* @return current style a layers data shall be displayed
*/
public NamedStyle getCurrentStyle() {
for ( NamedStyle style : this.styles ) {
if ( style.isCurrent() ) {
return style;
}
}
this.styles.get( 0 ).setCurrent( true );
return this.styles.get( 0 );
}
/**
*
* @return selected features or an empty feature collection, if no features are selected or a adapted layer just
* contains grid coverage data sources
*/
public FeatureCollection getSelectedFeatures() {
return selectedFeatures;
}
/**
* removes all features from the internal feature collection storing currently selected features
*
*/
public void unselectAllFeatures() {
if ( selectedFeatures.size() > 0 ) {
FeatureCollection fc = FeatureFactory.createFeatureCollection( new Identifier().getAsQualifiedString(),
selectedFeatures.toArray() );
selectedFeatures.clear();
fireLayerChangedEvent( LAYER_CHANGE_TYPE.featureUnselected, fc );
}
}
/**
* conveniece method for selecting features by a point
*
* @param point
* @param additive
* if true features at the passed point will be added to current collection otherwise a new collection
* will be initialized first
*/
public void selectFeatures( Point point, boolean additive ) {
if ( !additive ) {
unselectAllFeatures();
}
int size = selectedFeatures.size();
for ( DataAccessAdapter adapter : dataAccess ) {
if ( adapter instanceof FeatureAdapter ) {
FeatureCollection fc;
try {
fc = ( (FeatureAdapter) adapter ).getFeatureCollection( point );
} catch ( FilterEvaluationException e ) {
LOG.logError( e.getMessage(), e );
throw new DataAccessException( Messages.getMessage( Locale.getDefault(), "$DG10052" ) );
}
Iterator<Feature> iterator = fc.iterator();
while ( iterator.hasNext() ) {
Feature feature2 = (Feature) iterator.next();
if ( additive && selectedFeatures.getFeature( feature2.getId() ) != null ) {
selectedFeatures.remove( feature2 );
} else {
selectedFeatures.add( feature2 );
}
}
}
}
if ( size != selectedFeatures.size() ) {
fireLayerChangedEvent( LAYER_CHANGE_TYPE.featureSelected, selectedFeatures );
}
}
/**
* conveniece method for selecting features by a bbox
*
* @param envelope
* @param additive
* if true features at the passed point will be added to current collection otherwise a new collection
* will be initialized first
*/
public void selectFeatures( Envelope envelope, boolean additive ) {
if ( !additive ) {
unselectAllFeatures();
}
int size = selectedFeatures.size();
for ( DataAccessAdapter adapter : dataAccess ) {
if ( adapter instanceof FeatureAdapter ) {
FeatureCollection fc;
try {
fc = ( (FeatureAdapter) adapter ).getFeatureCollection( envelope );
} catch ( FilterEvaluationException e ) {
LOG.logError( e.getMessage(), e );
throw new DataAccessException( Messages.getMessage( Locale.getDefault(), "$DG10053" ) );
}
Iterator<Feature> iterator = fc.iterator();
while ( iterator.hasNext() ) {
Feature feature2 = iterator.next();
if ( additive && selectedFeatures.getFeature( feature2.getId() ) != null ) {
selectedFeatures.remove( feature2 );
} else {
selectedFeatures.add( feature2 );
}
}
}
}
if ( size != selectedFeatures.size() ) {
fireLayerChangedEvent( LAYER_CHANGE_TYPE.featureSelected, selectedFeatures );
}
}
/**
* selecting features by a user defined filter expression
*
* @param filter
* @param additive
* if true features at the passed point will be added to current collection otherwise a new collection
* will be initialized first
*/
public void selectFeatures( Filter filter, boolean additive ) {
if ( !additive ) {
unselectAllFeatures();
}
int size = selectedFeatures.size();
for ( DataAccessAdapter adapter : dataAccess ) {
if ( adapter instanceof FeatureAdapter ) {
FeatureCollection fc;
try {
fc = ( (FeatureAdapter) adapter ).getFeatureCollection( filter );
} catch ( FilterEvaluationException e ) {
LOG.logError( e.getMessage(), e );
throw new DataAccessException( Messages.getMessage( Locale.getDefault(), "$DG10054" ) );
}
Iterator<Feature> iterator = fc.iterator();
while ( iterator.hasNext() ) {
Feature feature2 = (Feature) iterator.next();
if ( additive && selectedFeatures.getFeature( feature2.getId() ) != null ) {
selectedFeatures.remove( feature2 );
} else {
selectedFeatures.add( feature2 );
}
}
}
}
if ( size != selectedFeatures.size() ) {
fireLayerChangedEvent( LAYER_CHANGE_TYPE.featureSelected, selectedFeatures );
}
}
/**
* selects a feature by its fid
*
* @param fids
* @param additive
* if true features at the passed point will be added to current collection otherwise a new collection
* will be initialized first
*/
public void selectFeatures( List<Identifier> fids, boolean additive ) {
if ( !additive ) {
unselectAllFeatures();
}
int size = selectedFeatures.size();
for ( DataAccessAdapter adapter : dataAccess ) {
if ( adapter instanceof FeatureAdapter ) {
FeatureCollection fc = ( (FeatureAdapter) adapter ).getFeatureCollection();
for ( Identifier fid : fids ) {
Feature feature = fc.getFeature( fid.getAsQualifiedString() );
if ( feature != null && selectedFeatures.getFeature( feature.getId() ) == null ) {
selectedFeatures.add( feature );
}
}
}
}
if ( size != selectedFeatures.size() ) {
fireLayerChangedEvent( LAYER_CHANGE_TYPE.featureSelected, selectedFeatures );
}
}
/**
* marks a geometry being part of a feature as selected
*
* @param fid
* id of feature from which a geometry should be selected
* @param propertyPath
* path of the geometry to be selected
* @throws PropertyPathResolvingException
*/
public void selectGeometry( Identifier fid, PropertyPath propertyPath )
throws PropertyPathResolvingException {
for ( DataAccessAdapter adapter : dataAccess ) {
if ( adapter instanceof FeatureAdapter ) {
FeatureType ft = ( (FeatureAdapter) adapter ).getSchema();
if ( ft.getName().equals( propertyPath.getStep( 0 ).getPropertyName() ) ) {
FeatureCollection fc = ( (FeatureAdapter) adapter ).getFeatureCollection();
Feature feature = fc.getFeature( fid.getAsQualifiedString() );
if ( feature != null ) {
FeatureProperty featureProperty = feature.getDefaultProperty( propertyPath );
if ( selectedGeometries == null ) {
selectedGeometries = new ArrayList<FeatureProperty>();
}
selectedGeometries.add( featureProperty );
}
}
}
}
}
/**
*
*
*/
public void unselectGeometries() {
if ( selectedGeometries != null ) {
selectedGeometries.clear();
}
}
/**
* fires a layer changed event encapsulating a feature changed envent that has caused layer changing
*
* @param changeType
*/
protected void fireLayerChangedEvent( LAYER_CHANGE_TYPE changeType, Object value ) {
LayerChangedEvent event = new LayerChangedEvent( this, value, changeType, null );
for ( int i = 0; i < this.listeners.size(); i++ ) {
this.listeners.get( i ).valueChanged( event );
}
owner.valueChanged( event );
}
/**
* informes all listeres that the state of a layer been changed in a way that requires repainting
*
*/
public void fireRepaintEvent() {
LayerChangedEvent event = new LayerChangedEvent( this, null, LAYER_CHANGE_TYPE.dataChanged, null );
for ( int i = 0; i < this.listeners.size(); i++ ) {
this.listeners.get( i ).valueChanged( event );
}
}
/**
* informs a layer that one of its data access objects has been refreshed
*
* @param adapter
*/
public void setDataRefreshed( DataAccessAdapter adapter ) {
fireLayerChangedEvent( LAYER_CHANGE_TYPE.datasourceChanged, adapter );
}
/**
* adds alistener to a layer
*
* @param listener
*/
public void addChangeListener( ChangeListener listener ) {
this.listeners.add( listener );
}
/**
* removes a listener from a layer
*
* @param listener
*/
public void removeChangeListener( ChangeListener listener ) {
if ( this.listeners != null ) {
this.listeners.remove( listener );
}
}
/*
* (non-Javadoc)
*
* @see org.deegree.igeo.ChangeListener#valueChanged(org.deegree.igeo.ValueChangedEvent)
*/
public void valueChanged( ValueChangedEvent event ) {
LayerChangedEvent ev = null;
if ( event instanceof AdapterEvent ) {
ev = new LayerChangedEvent( this, event.getValue(), LAYER_CHANGE_TYPE.dataLoadState, event );
} else {
ev = new LayerChangedEvent( this, event.getValue(), LAYER_CHANGE_TYPE.dataChanged, event );
}
for ( int i = 0; i < this.listeners.size(); i++ ) {
listeners.get( i ).valueChanged( ev );
}
}
/**
*
* @return legend image for a layer
*/
public BufferedImage getLegend() {
BufferedImage bi = getCurrentStyle().getLegendImage();
if ( bi == null ) {
try {
bi = ImageIO.read( Adapter.class.getResource( "missingLegend.png" ) );
BufferedImage tmp = new BufferedImage( bi.getWidth() + 130, bi.getHeight(), BufferedImage.TYPE_INT_ARGB );
Graphics g = tmp.getGraphics();
g.setColor( Color.WHITE );
g.fillRect( 0, 0, tmp.getWidth(), tmp.getHeight() );
g.setColor( Color.black );
g.drawString( getTitle(), bi.getWidth() + 10, bi.getHeight() / 2 + 8 );
g.drawImage( bi, 0, 0, null );
g.dispose();
bi = tmp;
} catch ( Exception e ) {
LOG.logWarning( e.getMessage(), e );
throw new DataAccessException( Messages.getMessage( Locale.getDefault(), "$DG10055",
"missingLegend.png" ) );
}
}
return bi;
}
@Override
public boolean equals( Object other ) {
if ( other == null || !( other instanceof Layer ) ) {
return false;
}
return getIdentifier().equals( ( (Layer) other ).getIdentifier() );
}
@Override
public int hashCode() {
return getIdentifier().hashCode();
}
@Override
public String toString() {
return getTitle();
}
/**
* Can be used to convert a collection of layers to a collection of its titles.
*/
public static final Mapper<String, Layer> ToTitles = new Mapper<String, Layer>() {
@Override
public String apply( Layer u ) {
return u.getTitle();
}
};
public void destroy() {
listeners = null;
if ( dataAccess != null ) {
for ( DataAccessAdapter da : this.dataAccess ) {
da.removeChangeListener( this );
da.invalidate();
}
dataAccess = null;
}
}
}