/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2008-2011, 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.swing;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.util.HashMap;
import java.util.Map;
import org.geotools.map.MapContent;
import org.geotools.renderer.GTRenderer;
import org.geotools.renderer.label.LabelCacheImpl;
import org.geotools.renderer.lite.LabelCache;
import org.geotools.renderer.lite.StreamingRenderer;
/**
* A lightweight map pane which uses a single renderer and backing image.
* Used by {@linkplain JMapFrame} for the GeoTools tutorial applications.
*
* @author Michael Bedward
* @author Ian Turton
* @since 2.6
*
* @source $URL$
* @version $Id$
*/
public class JMapPane extends AbstractMapPane {
private GTRenderer renderer;
private BufferedImage baseImage;
private Graphics2D baseImageGraphics;
/**
* Creates a new map pane.
*/
public JMapPane() {
this(null);
}
/**
* Creates a new map pane.
*
* @param content the map content containing the layers to display
* (may be {@code null})
*/
public JMapPane(MapContent content) {
this(content, null, null);
}
/**
* Creates a new map pane. Any or all arguments may be {@code null}
*
* @param content the map content containing the layers to display
* @param executor the rendering executor to manage drawing
* @param renderer the renderer to use for drawing layers
*/
public JMapPane(MapContent content, RenderingExecutor executor, GTRenderer renderer) {
super(content, executor);
doSetRenderer(renderer);
}
/**
* {@inheritDoc}
*/
@Override
public void setMapContent(MapContent content) {
super.setMapContent(content);
if (content != null && renderer != null) {
renderer.setMapContent(mapContent);
}
}
/**
* Gets the renderer, creating a default one if required.
*
* @return the renderer
*/
public GTRenderer getRenderer() {
if (renderer == null) {
doSetRenderer(new StreamingRenderer());
}
return renderer;
}
/**
* Sets the renderer to be used by this map pane.
*
* @param renderer the renderer to use
*/
public void setRenderer(GTRenderer renderer) {
doSetRenderer(renderer);
}
private void doSetRenderer(GTRenderer newRenderer) {
if (newRenderer != null) {
Map<Object, Object> hints = newRenderer.getRendererHints();
if (hints == null) {
hints = new HashMap<Object, Object>();
}
if (newRenderer instanceof StreamingRenderer) {
if (hints.containsKey(StreamingRenderer.LABEL_CACHE_KEY)) {
labelCache = (LabelCache) hints.get(StreamingRenderer.LABEL_CACHE_KEY);
} else {
labelCache = new LabelCacheImpl();
hints.put(StreamingRenderer.LABEL_CACHE_KEY, labelCache);
}
}
newRenderer.setRendererHints(hints);
if (mapContent != null) {
newRenderer.setMapContent(mapContent);
}
}
renderer = newRenderer;
}
/**
* Retrieve the map pane's current base image.
* <p>
* The map pane caches the most recent rendering of map layers
* as an image to avoid time-consuming rendering requests whenever
* possible. The base image will be re-drawn whenever there is a
* change to map layer data, style or visibility; and it will be
* replaced by a new image when the pane is resized.
* <p>
* This method returns a <b>live</b> reference to the current
* base image. Use with caution.
*
* @return a live reference to the current base image
*/
public RenderedImage getBaseImage() {
return this.baseImage;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (drawingLock.tryLock()) {
try {
if (baseImage != null) {
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(baseImage, imageOrigin.x, imageOrigin.y, null);
}
} finally {
drawingLock.unlock();
}
}
}
@Override
protected void drawLayers(boolean createNewImage) {
drawingLock.lock();
try {
if (mapContent != null
&& !mapContent.getViewport().isEmpty()
&& acceptRepaintRequests.get()) {
Rectangle r = getVisibleRect();
if (baseImage == null || createNewImage) {
baseImage = GraphicsEnvironment.getLocalGraphicsEnvironment().
getDefaultScreenDevice().getDefaultConfiguration().
createCompatibleImage(r.width, r.height, Transparency.TRANSLUCENT);
if (baseImageGraphics != null) {
baseImageGraphics.dispose();
}
baseImageGraphics = baseImage.createGraphics();
clearLabelCache.set(true);
} else {
baseImageGraphics.setBackground(getBackground());
baseImageGraphics.clearRect(0, 0, r.width, r.height);
}
if (mapContent != null && !mapContent.layers().isEmpty()) {
getRenderingExecutor().submit(mapContent, getRenderer(), baseImageGraphics, this);
}
}
} finally {
drawingLock.unlock();
}
}
}