/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2009-2010, Geomatys
*
* 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.geotoolkit.display2d.container.stateless;
import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.beans.PropertyChangeEvent;
import java.lang.ref.SoftReference;
import java.util.Collection;
import java.util.EventObject;
import java.util.List;
import org.geotoolkit.display.canvas.RenderingContext;
import org.geotoolkit.display.VisitFilter;
import org.geotoolkit.display.SearchArea;
import org.geotoolkit.display2d.canvas.J2DCanvas;
import org.geotoolkit.display2d.canvas.RenderingContext2D;
import org.geotoolkit.display2d.primitive.GraphicJ2D;
import org.geotoolkit.map.GraphicBuilder;
import org.geotoolkit.map.LayerListener;
import org.geotoolkit.map.MapItem;
import org.geotoolkit.map.MapLayer;
import org.geotoolkit.util.collection.CollectionChangeEvent;
import org.opengis.display.primitive.Graphic;
/**
*
* @author Johann Sorel (Geomatys)
* @module
*/
public class StatelessMapLayerJ2D<T extends MapLayer> extends StatelessMapItemJ2D<T> {
private final LayerListener ll = new LayerListener() {
@Override
public void styleChange(MapLayer source, EventObject event) {
//event is catch in the property change
}
@Override
public void itemChange(CollectionChangeEvent<MapItem> event) {
//handle by parent
}
@Override
public void propertyChange(PropertyChangeEvent event) {
if(getCanvas().isAutoRepaint()){
final String propName = event.getPropertyName();
if(MapLayer.VISIBILITY_PROPERTY.equals(propName)){
//handle in StatelessMapItemJ2D
} else if (item.isVisible() &&
( MapLayer.STYLE_PROPERTY.equals(propName)
|| MapLayer.SELECTION_FILTER_PROPERTY.equals(propName)
|| MapLayer.OPACITY_PROPERTY.equals(propName)
|| MapLayer.QUERY_PROPERTY.equals(propName) )){
//TODO should call a repaint only on this graphic
getCanvas().repaint();
}
}
}
};
private final LayerListener.Weak weakListener = new LayerListener.Weak(ll);
private SoftReference<Collection<? extends GraphicJ2D>> weakGraphic = null;
public StatelessMapLayerJ2D(final J2DCanvas canvas, final T layer, boolean allowChildren){
//do not use layer crs here, to long to calculate
super(canvas, layer, allowChildren);
weakListener.registerSource(layer);
}
@Override
public void dispose() {
super.dispose();
weakListener.dispose();
}
@Override
public void paint(final RenderingContext2D context) {
//we abort painting if the layer is not visible.
if (!item.isVisible()) return;
//we abort if opacity is to low
final double opacity = item.getOpacity();
if(opacity < 1e-6) return;
if(1-opacity < 1e-6){
//we are very close to opacity one, no need to create a intermediate image
paintLayer(context);
}else{
//create an intermediate layer which will be painted on the main context
//after with the given opacity
final Rectangle rect = context.getCanvasDisplayBounds();
final BufferedImage inter = createBufferedImage(ColorModel.getRGBdefault(),
ColorModel.getRGBdefault().createCompatibleSampleModel(rect.width, rect.height));
final Graphics2D g2d = inter.createGraphics();
final RenderingContext2D interContext = context.create(g2d);
paintLayer(interContext);
//paint intermediate image
context.switchToDisplayCRS();
final Graphics2D g = context.getGraphics();
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float)opacity));
g.drawImage(inter, 0, 0, null);
recycleBufferedImage(inter);
}
}
/**
* Render layer, will only be painted if an appropriate graphic builder is attached
* to it.
*/
protected void paintLayer(final RenderingContext2D context){
//get graphics from the cache first
if(weakGraphic != null){
final Collection<? extends GraphicJ2D> graphics = weakGraphic.get();
if(graphics != null){
for(GraphicJ2D g : graphics){
g.paint(context);
}
}
return;
}
final GraphicBuilder<? extends GraphicJ2D> builder = item.getGraphicBuilder(GraphicJ2D.class);
if(builder != null){
final Collection<? extends GraphicJ2D> graphics = builder.createGraphics(item, canvas);
weakGraphic = new SoftReference<Collection<? extends GraphicJ2D>>(graphics);
for(GraphicJ2D g : graphics){
g.paint(context);
}
}
}
/**
* pick layer, will only be picked if an appropriate graphic builder is attached
* to it.
*/
@Override
public List<Graphic> getGraphicAt(final RenderingContext context, final SearchArea mask, final VisitFilter filter, List<Graphic> graphics) {
final GraphicBuilder<GraphicJ2D> builder = (GraphicBuilder<GraphicJ2D>) item.getGraphicBuilder(GraphicJ2D.class);
if(builder != null){
//this layer hasa special graphic rendering, use it instead of normal rendering
final Collection<GraphicJ2D> gras = builder.createGraphics(item, canvas);
for(final GraphicJ2D gra : gras){
graphics = gra.getGraphicAt(context, mask, filter,graphics);
}
return graphics;
}else{
//since this is a custom layer, we have no way to find a child graphic.
graphics.add(this);
return graphics;
}
}
}