/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2012, 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.statefull;
import java.beans.PropertyChangeEvent;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.logging.Level;
import org.apache.sis.measure.NumberRange;
import org.geotoolkit.storage.coverage.CoverageReference;
import org.geotoolkit.storage.coverage.PyramidalCoverageReference;
import org.geotoolkit.display.canvas.RenderingContext;
import org.geotoolkit.display.VisitFilter;
import org.geotoolkit.display.primitive.SceneNode;
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.CoverageMapLayer;
import org.geotoolkit.map.FeatureMapLayer;
import org.geotoolkit.map.ItemListener;
import org.geotoolkit.map.MapItem;
import org.geotoolkit.map.MapLayer;
import org.geotoolkit.util.collection.CollectionChangeEvent;
import org.opengis.display.primitive.Graphic;
import org.opengis.geometry.Envelope;
/**
*
* @author Johann Sorel (Geomatys)
* @module
*/
public class StatefullMapItemJ2D<T extends MapItem> extends GraphicJ2D implements ItemListener{
private final ItemListener.Weak weakListener = new ItemListener.Weak(this);
//childs
private final Map<MapItem, GraphicJ2D> itemGraphics = new HashMap<>();
protected final T item;
public StatefullMapItemJ2D(final J2DCanvas canvas,final T item, boolean allowChildren){
super(canvas, allowChildren);
this.item = item;
//build children nodes
final List<MapItem> childs = item.items();
for(int i=0,n=childs.size(); i<n; i++){
final MapItem child = childs.get(i);
final GraphicJ2D gj2d = parseChild(child);
itemGraphics.put(child, gj2d);
getChildren().add(gj2d);
}
//listen to mapitem changes
weakListener.registerSource(item);
}
protected ThreadPoolExecutor getExecutor(){
if(parent instanceof StatefullMapItemJ2D){
return ((StatefullMapItemJ2D)parent).getExecutor();
}else if(parent instanceof RootSceneNode){
return ((RootSceneNode)parent).getExecutor();
}else{
throw new RuntimeException("Get not access executor if node is not linked to the scene root.");
}
}
@Override
public T getUserObject() {
return item;
}
@Override
public void dispose() {
super.dispose();
weakListener.dispose();
for(GraphicJ2D graphic : itemGraphics.values()){
graphic.dispose();
}
itemGraphics.clear();
}
@Override
public Envelope getEnvelope() {
return null;
}
// create graphics ---------------------------------------------------------
protected GraphicJ2D parseChild(final MapItem child){
final StatefullMapItemJ2D g2d;
if (child instanceof FeatureMapLayer){
g2d = new StatefullFeatureMapLayerJ2D(getCanvas(), (FeatureMapLayer)child);
}else if (child instanceof CoverageMapLayer){
final CoverageMapLayer layer = (CoverageMapLayer) child;
final CoverageReference ref = layer.getCoverageReference();
if(ref != null && ref instanceof PyramidalCoverageReference){
//pyramidal model, we can improve rendering
g2d = new StatefullPyramidalCoverageLayerJ2D(getCanvas(), (CoverageMapLayer)child);
}else{
//normal coverage
g2d = new StatefullMapLayerJ2D(getCanvas(), (CoverageMapLayer)child, false);
}
}else if (child instanceof MapLayer){
g2d = new StatefullMapLayerJ2D(getCanvas(), (MapLayer)child, false);
}else{
g2d = new StatefullMapItemJ2D(getCanvas(), child, true);
}
return g2d;
}
@Override
public void paint(final RenderingContext2D renderingContext) {
//we abort painting if the item is not visible.
if (!item.isVisible()) return;
for(final MapItem child : item.items()){
if(renderingContext.getMonitor().stopRequested()) break;
final GraphicJ2D gra = itemGraphics.get(child);
if(gra != null){
gra.paint(renderingContext);
}else{
getLogger().log(Level.WARNING, "GraphicContextJ2D, paint method : strange, no graphic object affected to layer :{0}", child.getName());
}
}
}
/**
* {@inheritDoc }
*/
@Override
public List<Graphic> getGraphicAt(final RenderingContext rdcontext, final SearchArea mask, final VisitFilter filter, List<Graphic> graphics) {
//we abort painting if the item is not visible.
if (!item.isVisible()) return graphics;
final List<MapItem> children = item.items();
for(int i=children.size()-1; i>=0; i--){
final MapItem child = children.get(i);
final GraphicJ2D gra = itemGraphics.get(child);
graphics = gra.getGraphicAt(rdcontext,mask,filter,graphics);
}
return graphics;
}
// item listener ----------------------------------------------
@Override
public void propertyChange(final PropertyChangeEvent event) {
}
@Override
public void itemChange(final CollectionChangeEvent<MapItem> event) {
final int type = event.getType();
if(CollectionChangeEvent.ITEM_ADDED == type){
final NumberRange range = event.getRange();
int index = (int) range.getMinDouble();
for(final MapItem child : event.getItems()){
final GraphicJ2D gj2d = parseChild(child);
getChildren().add(index,(SceneNode)gj2d);
itemGraphics.put(child, gj2d);
index++;
}
//TODO should call a repaint only on this graphic
getCanvas().repaint();
}else if(CollectionChangeEvent.ITEM_REMOVED == type){
for(final MapItem child : event.getItems()){
//remove the graphic
final GraphicJ2D gra = itemGraphics.remove(child);
if(gra != null){
getChildren().remove(gra);
gra.dispose();
}
}
//TODO should call a repaint only on this graphic
getCanvas().repaint();
}
}
}