/*---------------- FILE HEADER ------------------------------------------
This file is part of deegree.
Copyright (C) 2001-2006 by:
EXSE, 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
53115 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.graphics;
import java.awt.Graphics;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.deegree.framework.log.ILogger;
import org.deegree.framework.log.LoggerFactory;
import org.deegree.graphics.displayelements.DisplayElement;
import org.deegree.graphics.displayelements.DisplayElementFactory;
import org.deegree.graphics.displayelements.LabelDisplayElement;
import org.deegree.graphics.sld.UserStyle;
import org.deegree.io.datastore.PropertyPathResolvingException;
import org.deegree.model.feature.Feature;
import org.deegree.model.feature.FeatureProperty;
import org.deegree.model.spatialschema.GeometryException;
import org.opengis.coverage.grid.GridCoverage;
/**
* A Theme is for usual a homogenious collection of Features coupled with
* a portrayal model for their graphical representation. Considering the OGC
* Styled Layer Descriptor specification this is not nessecary the case. In
* confirmation with the SLD a theme can be build from a lot of thematic
* completly different feature types.<p></p>
* From a theoretical point of view this isn't very satisfying. But it will
* be supported by the <tt>Theme</tt> class.<p></p>
* Assigned to the Theme are:
* <ul>
* <li>a Layer that contains the data (features)
* <li>a Portrayal model that determines how the features shall be rendered
* <li>a Selector that offers method for selection and de-selection of
* features
* <li>a event listener that handles event occuring on a theme that's
* for usual part of a map.
* </ul>
*
* <p>------------------------------------------------------------------------</p>
*
* @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
* @version $Revision: 1.23 $ $Date: 2006/09/28 15:39:01 $
*/
public class Theme {
private static final ILogger LOG = LoggerFactory.getLogger( Theme.class );
private String name = null;
private Layer layer = null;
private UserStyle[] styles = null;
private ArrayList displayElements = null;
/**
* the MapView (map) the theme is associated to
*
*/
private MapView parent = null;
/**
* this ArrayList contains all DisplayElements (and so the features) that
* are marked as selected.
*/
private List selector = Collections.synchronizedList( new ArrayList() );
private List highlighter = Collections.synchronizedList( new ArrayList() );
private List eventController = Collections.synchronizedList( new ArrayList() );
/**
*
* @param name
* @param layer
* @param styles
*/
protected Theme( String name, Layer layer, UserStyle[] styles ) {
this.layer = layer;
this.name = name;
displayElements = new ArrayList( 1000 );
setStyles( styles );
}
/**
* sets the parent MapView of the Theme.
*
*/
public void setParent( MapView parent ) {
this.parent = parent;
}
/**
* returns the name of the layer
*
*/
public String getName() {
return name;
}
/**
* renders the layer to the submitted graphic context
*/
public void paint( Graphics g ) {
double scale = parent.getScale();
if ( layer instanceof LazyRasterLayer ) {
// re-create raster displayelements to adapt current
// current boundingbox
createLazyRasterDisplayElements();
} else if ( layer instanceof OWSRasterLayer ) {
createOWSRasterDisplayElements();
}
for ( int i = 0; i < displayElements.size(); i++ ) {
DisplayElement de = (DisplayElement) displayElements.get( i );
if ( de.doesScaleConstraintApply( scale ) ) {
de.paint( g, parent.getProjection(), scale );
}
}
}
/**
* renders the display elements matching the submitted ids
*/
public void paint( Graphics g, String[] ids ) {
double scale = parent.getScale();
if ( layer instanceof LazyRasterLayer ) {
// re-create raster displayelements to adapt current
// current boundingbox
createLazyRasterDisplayElements();
}
for ( int k = 0; k < displayElements.size(); k++ ) {
DisplayElement de = (DisplayElement) displayElements.get( k );
for ( int i = 0; i < ids.length; i++ ) {
if ( de.getAssociateFeatureId().equals( ids[i] ) ) {
de.paint( g, parent.getProjection(), scale );
break;
}
}
}
}
/**
* renders the selected display elements of the layer
*/
public void paintSelected( Graphics g ) {
double scale = parent.getScale();
if ( layer instanceof LazyRasterLayer ) {
// re-create raster displayelements to adapt current
// current boundingbox
createLazyRasterDisplayElements();
}
if ( layer instanceof OWSRasterLayer ) {
}
for ( int i = 0; i < displayElements.size(); i++ ) {
DisplayElement de = ( (DisplayElement) displayElements.get( i ) );
if ( de.isSelected() ) {
de.paint( g, parent.getProjection(), scale );
}
}
}
/**
* renders the highlighted display elements of the layer
*/
public void paintHighlighted( Graphics g ) {
double scale = parent.getScale();
if ( layer instanceof LazyRasterLayer ) {
// re-create raster displayelements to adapt current
// current boundingbox
createLazyRasterDisplayElements();
}
for ( int i = 0; i < displayElements.size(); i++ ) {
DisplayElement de = ( (DisplayElement) displayElements.get( i ) );
if ( de.isHighlighted() ) {
de.paint( g, parent.getProjection(), scale );
}
}
}
/**
* A selector is a class that offers methods for selecting and
* deselecting single DisplayElements or groups of DisplayElements.
* A selector may offers methods like 'select all DisplayElements
* within a specified bounding box' or 'select all DisplayElements
* thats area is larger than 120 km�' etc.
*/
public void addSelector( Selector selector ) {
this.selector.add( selector );
selector.addTheme( this );
}
/**
* @see org.deegree.graphics.Theme#addSelector(Selector)
*/
public void removeSelector( Selector selector ) {
this.selector.remove( selector );
selector.removeTheme( this );
}
/**
* A Highlighter is a class that is responsible for managing the highlight
* capabilities for one or more Themes.
*/
public void addHighlighter( Highlighter highlighter ) {
this.highlighter.add( highlighter );
highlighter.addTheme( this );
}
/**
* @see org.deegree.graphics.Theme#addHighlighter(Highlighter)
*/
public void removeHighlighter( Highlighter highlighter ) {
this.highlighter.remove( highlighter );
highlighter.removeTheme( this );
}
/**
* adds an eventcontroller to the theme that's reponsible for handling
* events that targets the theme.
*/
public void addEventController( ThemeEventController controller ) {
eventController.add( controller );
controller.addTheme( this );
}
/**
* @see org.deegree.graphics.Theme#addEventController(ThemeEventController)
*/
public void removeEventController( ThemeEventController controller ) {
eventController.remove( controller );
controller.removeTheme( this );
}
/**
* Sets the styles used for this <tt>Theme</tt>. If this method will be
* called all <tt>DisplayElement</tt>s will be recreated to consider the
* new style definitions.
*
*/
public void setStyles( UserStyle[] styles ) {
this.styles = styles;
displayElements.clear();
if ( layer instanceof FeatureLayer ) {
createFeatureDisplayElements();
} else if ( layer instanceof RasterLayer ) {
createRasterDisplayElements( );
} else {
createLazyRasterDisplayElements( );
}
}
/**
* creates <code>DisplayElement</code>s for <code>Feature</code> instances
*/
private void createFeatureDisplayElements( ) {
displayElements.clear();
DisplayElementFactory fac = new DisplayElementFactory();
// keep LabelDisplayElements separate from the other elements
// and append them to the end of the DisplayElement-list
ArrayList labelDisplayElements = new ArrayList( 100 );
try {
// instance of FeatureLayer
for ( int i = 0; i < ( (FeatureLayer) layer ).getSize(); i++ ) {
Feature feature = ( (FeatureLayer) layer ).getFeature( i );
featureToDisplayElement( styles, fac, labelDisplayElements, feature );
}
} catch ( Exception e ) {
LOG.logError( e.getMessage(), e );
}
displayElements.addAll( labelDisplayElements );
}
/**
* creates <code>DisplayElement</code>s for <code>GridCoverage</code> instances
*/
private void createRasterDisplayElements( ) {
displayElements.clear();
DisplayElementFactory fac = new DisplayElementFactory();
try {
// instance of RasterLayer
RasterLayer rl = (RasterLayer) layer;
DisplayElement[] de = fac.createDisplayElement( rl.getRaster(), styles );
for ( int k = 0; k < de.length; k++ ) {
displayElements.add( de[k] );
}
} catch ( Exception e ) {
LOG.logError( e.getMessage(), e );
}
}
/**
* creates <code>DisplayElement</code>s for <code>GridCoverage</code> instances that
* are loaded depending on current boundingbox.
*/
private void createLazyRasterDisplayElements( ) {
displayElements.clear();
DisplayElementFactory fac = new DisplayElementFactory();
try {
if ( parent != null ) {
LazyRasterLayer rl = (LazyRasterLayer) layer;
double w = parent.getProjection().getDestRect().getWidth();
double d = parent.getBoundingBox().getWidth()/w;
GridCoverage gc = rl.getRaster( parent.getBoundingBox(), d );
//gc can be null if e.g. the area covered by the raster
// layer is outside the visible area.
if ( gc != null ) {
DisplayElement[] de = fac.createDisplayElement( gc, styles );
for ( int k = 0; k < de.length; k++ ) {
displayElements.add( de[k] );
}
}
}
} catch ( Exception e ) {
LOG.logError( e.getMessage(), e );
}
}
private void createOWSRasterDisplayElements( ) {
displayElements.clear();
DisplayElementFactory fac = new DisplayElementFactory();
try {
if ( parent != null ) {
OWSRasterLayer rl = (OWSRasterLayer) layer;
double w = parent.getProjection().getDestRect().getWidth();
double h = parent.getProjection().getDestRect().getHeight();
GridCoverage gc = rl.getRaster( parent.getBoundingBox(), w, h );
if ( gc != null ){
DisplayElement[] de =
fac.createDisplayElement( gc, styles );
for ( int k = 0; k < de.length; k++ ) {
displayElements.add( de[k] );
}
}
}
} catch ( Exception e ) {
LOG.logError( e.getMessage(), e );
}
}
/**
*
* @param styles
* @param fac
* @param labelDisplayElements
* @param feature
* @throws ClassNotFoundException
* @throws IllegalAccessException
* @throws InstantiationException
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws GeometryException
* @throws PropertyPathResolvingException
*/
private void featureToDisplayElement( UserStyle[] styles, DisplayElementFactory fac,
ArrayList labelDisplayElements, Feature feature )
throws ClassNotFoundException, IllegalAccessException,
InstantiationException, NoSuchMethodException,
InvocationTargetException, GeometryException,
PropertyPathResolvingException {
DisplayElement[] de = fac.createDisplayElement( feature, styles );
for ( int k = 0; k < de.length; k++ ) {
if ( de[k] instanceof LabelDisplayElement ) {
labelDisplayElements.add( de[k] );
} else {
displayElements.add( de[k] );
}
}
FeatureProperty[] fp = feature.getProperties();
for ( int i = 0; i < fp.length; i++ ) {
if ( fp[i].getValue() != null && fp[i].getValue() instanceof Feature ) {
featureToDisplayElement( styles, fac, labelDisplayElements,
(Feature) fp[i].getValue() );
}
}
}
/**
* returns the styles used for this <tt>Theme</tt>.
*
*/
public UserStyle[] getStyles() {
return styles;
}
/**
* returns the layer that holds the data of the theme
*
*/
public Layer getLayer() {
return layer;
}
/**
* Returns all <tt>DisplayElements</tt> that this <tt>Theme</tt> contains.
* <p>
* @return <tt>ArrayList</tt> containing <tt>DisplayElements</tt>
*
*/
public ArrayList getDisplayElements() {
return displayElements;
}
/**
* returns the <tt>DisplayElements</tt> of the Theme
*
*/
public void setDisplayElements( ArrayList de ) {
this.displayElements = de;
}
}
/* ********************************************************************
Changes to this class. What the people have been up to:
$Log: Theme.java,v $
Revision 1.23 2006/09/28 15:39:01 poth
bug fix - using LazyRasterLayer
Revision 1.22 2006/09/22 12:16:28 taddei
made constructor protected
Revision 1.21 2006/09/07 13:26:20 taddei
handling/ignoring exceptions in OWSRasterlayer; and using img dimension
Revision 1.20 2006/08/25 14:11:39 taddei
added code for OWSRasterLayer
Revision 1.19 2006/08/24 09:58:19 poth
support for OWSRasterLayer added
Revision 1.18 2006/05/31 17:53:33 poth
bug fix
Revision 1.17 2006/05/31 17:23:59 poth
first implementation of LazyRasterLayer
Revision 1.16 2006/05/26 06:43:23 poth
bug fix creating display elements
Revision 1.15 2006/05/25 16:16:46 poth
bug fix in all paint methods
Revision 1.14 2006/05/24 08:05:23 poth
support for LazyRasterLayer added
********************************************************************** */