[Schmitzm-commits] r529 - in branches/1.0-gt2-2.6/src: gtmig/org/geotools/swing skrueger/geotools
scm-commit@wald.intevation.org
scm-commit at wald.intevation.org
Wed Nov 18 21:47:01 CET 2009
Author: alfonx
Date: 2009-11-18 21:47:00 +0100 (Wed, 18 Nov 2009)
New Revision: 529
Modified:
branches/1.0-gt2-2.6/src/gtmig/org/geotools/swing/XMapPane.java
branches/1.0-gt2-2.6/src/skrueger/geotools/RenderingExecutor.java
Log:
XMapPane and RenderingExecutor now work together without leaking memory through their BufferedImages...
Modified: branches/1.0-gt2-2.6/src/gtmig/org/geotools/swing/XMapPane.java
===================================================================
--- branches/1.0-gt2-2.6/src/gtmig/org/geotools/swing/XMapPane.java 2009-11-18 20:46:08 UTC (rev 528)
+++ branches/1.0-gt2-2.6/src/gtmig/org/geotools/swing/XMapPane.java 2009-11-18 20:47:00 UTC (rev 529)
@@ -20,7 +20,6 @@
* In addition to
*/
-import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Font;
@@ -41,14 +40,11 @@
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
-import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
@@ -67,6 +63,7 @@
import org.geotools.renderer.GTRenderer;
import org.geotools.renderer.label.LabelCacheImpl;
import org.geotools.renderer.lite.LabelCache;
+import org.geotools.renderer.lite.StreamingRenderer;
import org.geotools.swing.JMapPane;
import org.geotools.swing.event.MapMouseEvent;
import org.geotools.swing.event.MapPaneEvent;
@@ -83,14 +80,16 @@
import schmitzm.geotools.gui.SelectableXMapPane;
import schmitzm.geotools.map.event.JMapPaneListener;
import schmitzm.geotools.map.event.MapLayerAdapter;
+import schmitzm.lang.LangUtil;
import schmitzm.swing.SwingUtil;
import skrueger.geotools.RenderingExecutor;
+import skrueger.swing.formatter.MbDecimalFormatter;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
-public class XMapPane extends JPanel implements PropertyChangeListener {
+public class XMapPane extends JPanel {
private static Logger LOGGER = Logger.getLogger(XMapPane.class);
/**
@@ -188,9 +187,10 @@
* with previews.
*/
public static final long REPEATING_REPAINT_DELAY = 500;
-
+
/**
- * The initial delay in milliseconds until the {@link #finalImage} is updated the first time.
+ * The initial delay in milliseconds until the {@link #finalImage} is
+ * updated the first time.
*/
public static final long INITIAL_REPAINT_DELAY = 1000;
@@ -216,23 +216,6 @@
protected Envelope oldMapArea = null;
/**
- * the size of the pane last time we drew
- */
- protected Rectangle oldRect = null;
-
- /**
- * The Renderer for the Background uses this Image. When set to null, please
- * dispose the {@link Graphics2D}
- */
- protected BufferedImage bgImage;
-
- /**
- * The Renderer for the LocalLayers uses this Image. When set to null,
- * please dispose this {@link Graphics2D}
- */
- volatile protected BufferedImage localImage;
-
- /**
* compass and icon are rendered into this image
*/
// protected BufferedImage gadgetsImage;
@@ -360,7 +343,7 @@
* @param localContext
* - {@link MapContext} of layer to render.
*/
- public XMapPane(final MapContext localContext,
+ public XMapPane(final MapContext localContext_,
Map<Object, Object> rendererHints) {
super(true);
@@ -368,8 +351,12 @@
setOpaque(true);
- setLocalContext(localContext);
+ localRenderer = GTUtil.createGTRenderer();
+ localRenderer.setJava2DHints(getJava2dHints());
+ if (localContext_ != null)
+ setLocalContext(localContext_);
+
/**
* Adding the #zoomMapPaneMouseListener
*/
@@ -433,8 +420,8 @@
public void actionPerformed(ActionEvent e) {
synchronized (requestStartRendering) {
if (requestStartRendering && isWellDefined()) {
-
- if (localExecuter.isRunning()){
+
+ if (localExecuter.isRunning()) {
localExecuter.cancelTask();
} else {
requestStartRendering = false;
@@ -747,6 +734,12 @@
public void layerAdded(final MapLayerListEvent event) {
event.getLayer().addMapLayerListener(localMapLayerListener);
+// System.out.println("added a layer context, now it'S "
+// + getContext().getLayerCount() + " layers");
+// ;
+
+ localRenderer.setContext(getContext());
+
if (localContext.getLayers().length == 1) { // the first one
// if the Area of Interest is unset, the LayerBounds are used
if (!setMapArea(localContext.getAreaOfInterest()))
@@ -768,6 +761,7 @@
event.getLayer().removeMapLayerListener(localMapLayerListener);
// mapImageInvalid = true;
// repaint();
+ localRenderer.setContext(getContext());
requestStartRendering();
}
@@ -775,6 +769,7 @@
public void layerChanged(final MapLayerListEvent event) {
// mapImageInvalid = true;
// repaint();
+ localRenderer.setContext(getContext());
requestStartRendering();
}
@@ -782,6 +777,7 @@
public void layerMoved(final MapLayerListEvent event) {
// mapImageInvalid = true;
// repaint();
+ localRenderer.setContext(getContext());
requestStartRendering();
}
};
@@ -858,6 +854,7 @@
@Override
public void layerChanged(MapLayerEvent event) {
+ localRenderer.setContext(getContext()); // betters for SLD changes?!
// Change of SLD for example
// mapImageInvalid = true;
// repaint();
@@ -920,8 +917,7 @@
public MapContext getContext() {
if (localContext == null) {
- this.localContext = new DefaultMapContext();
- this.localContext.addMapLayerListListener(localContextListener);
+ setLocalContext(new DefaultMapContext());
}
return localContext;
}
@@ -948,8 +944,11 @@
this.localContext = context;
if (context != null) {
+
setMapArea(localContext.getAreaOfInterest());
+ localRenderer.setContext(localContext);
+
this.localContext.addMapLayerListListener(localContextListener);
// adding listener to all layers
@@ -997,19 +996,16 @@
*/
public Envelope getMapArea() {
if (mapArea == null) {
- final Rectangle paneBounds = getBounds();
-
+ ReferencedEnvelope mapArea_ = null;
try {
- mapArea = localContext.getLayerBounds();
+ mapArea_ = localContext.getLayerBounds();
} catch (final IOException e) {
LOGGER.warn("context.getLayerBounds()", e);
}
- if (mapArea != null) {
- /* either the viewer size has changed or we've done a reset */
+ if (mapArea_ != null) {
mapImageInvalid = true; /* note we need to redraw */
- oldRect = paneBounds; /* store what the current size is */
- mapArea = bestAllowedMapArea(mapArea);
+ setMapArea(mapArea_);
}
}
@@ -1082,7 +1078,7 @@
mapAreaChanged = true;
repaint();
-// LOGGER.debug("New maparea = " + mapArea);
+ // LOGGER.debug("New maparea = " + mapArea);
return true;
}
@@ -1115,10 +1111,8 @@
public static final int NONE = -123;
- private RenderingExecutor localExecuter = new RenderingExecutor(this, 150l);
+ private RenderingExecutor localExecuter = new RenderingExecutor(this);
- private BufferedImage finalImage;
-
/**
* A flag set it {@link #setMapArea(Envelope)} to indicated the
* {@link #paintComponent(Graphics)} method, that the image on-screen is
@@ -1128,18 +1122,36 @@
**/
private boolean mapAreaChanged = false;
- private JFrame finalImageFrame;
-
private volatile Boolean requestStartRendering = false;
- private BufferedImage preFinalImage;
+ /**
+ * The Renderer for the Background uses this Image. When set to null, please
+ * dispose the {@link Graphics2D}
+ */
+ private BufferedImage bgImage;// = new
+ // BufferedImage(600,600,BufferedImage.TYPE_INT_ARGB);
+
+ private BufferedImage finalImage;
+
+ /**
+ * The Renderer for the LocalLayers uses this Image. When set to null,
+ * please dispose this {@link Graphics2D}
+ */
+ private BufferedImage localImage;// = new
+ // BufferedImage(600,600,BufferedImage.TYPE_INT_ARGB);
+ private BufferedImage preFinalImage;// = new
+
+ // BufferedImage(600,600,BufferedImage.TYPE_INT_ARGB);
+
protected void paintComponent(final Graphics g) {
+ if (!acceptsRepaintCalls)
+ return;
+
// Maybe update the cursor
updateCursor();
+
+ super.paintComponent(g);
- if (!acceptsRepaintCalls)
- return;
-
boolean paintedSomething = false;
if (mapImageInvalid) { /* if the map changed then redraw */
@@ -1167,10 +1179,21 @@
if (paneResized) {
paneResized = false;
- preFinalImage = null;
- finalImage = null;
- localImage = null;
- bgImage = null;
+
+ // if (preFinalImage != null)
+ // preFinalImage.flush();
+ // preFinalImage = null;
+ // if (finalImage != null) {
+ // finalImage.flush();
+ // }
+ // finalImage = null;
+ // if (localImage != null)
+ // localImage.flush();
+ // localImage = null;
+ // if (bgImage != null)
+ // bgImage.flush();
+ // bgImage = null;
+
// gadgetsImage = null;
}
@@ -1184,8 +1207,10 @@
// TODO Should just paint the getFinalImage(). Update should be
// called by timer every 300ms, and the repaint() until all threads
// are done.
- g.drawImage(getFinalImage(), 0, 0, this);
+ g.drawImage(getFinalImage(), 0, 0, null);
+ g.dispose();
+
paintedSomething = true;
}
@@ -1202,7 +1227,7 @@
if (localExecuter != null)
localExecuter.cancelTask();
requestStartRendering = true;
-
+
}
/**
@@ -1261,8 +1286,6 @@
* to give the user something to look at while we are rendering. Method
* should be called after {@link #setMapArea(Envelope)} has been set to the
* new mapArea and transform has been reset.<br/>
- * This method does nothing if the {@link #lastRenderingDuration} is smaller
- * then a trashhold.
*
* @param g
* Graphics2D to paint the preview into
@@ -1311,7 +1334,7 @@
quickPreviewHint = 0;
graphics.dispose();
-
+
// Something has been drawn
return true;
}
@@ -1327,17 +1350,19 @@
if (mapImage != null)
graphics.drawImage(mapImage, getBounds().width
- mapImage.getWidth() - 10, getBounds().height
- - mapImage.getHeight() - 10, this);
+ - mapImage.getHeight() - 10, null);
// If still rendering, paint a gray shadow or so...
if (bgExecuter != null && bgExecuter.isRunning()
|| localExecuter != null && localExecuter.isRunning()) {
+
+ Color c = graphics.getColor();
graphics.setColor(Color.BLACK);
graphics.setFont(waitFont);
- graphics.drawString("Wait...", 40, 70); //i8n
-
- graphics.setColor(getMapBackgroundColor());
+ graphics.drawString("Wait...", 40, 70); // i8n
+
+ graphics.setColor(c);
}
}
@@ -1347,28 +1372,27 @@
*
* @return
*/
- synchronized protected BufferedImage updateFinalImage() {
+ synchronized protected Image updateFinalImage() {
- final Graphics2D finalG = (Graphics2D) getFinalImage().getGraphics();
- finalG.setBackground(getMapBackgroundColor());
-
// Render the two map images first, into the preFinalImage
- if (bgExecuter != null)
- {
+ if (bgExecuter != null) {
final Graphics2D preFinalG = (Graphics2D) getPreFinalImage()
.getGraphics();
preFinalG.setBackground(getMapBackgroundColor());
preFinalG.drawImage(getBgImage(), 0, 0, getMapBackgroundColor(),
null);
-
+
// // Draw the local layers image
preFinalG.drawImage(getLocalImage(), 0, 0, null);
preFinalG.dispose();
+
} else {
preFinalImage = getLocalImage();
}
+ final Graphics2D finalG = getFinalImage().createGraphics();
+ finalG.setBackground(getMapBackgroundColor());
finalG.drawImage(getPreFinalImage(), imageOrigin.x, imageOrigin.y,
getMapBackgroundColor(), null);
@@ -1386,13 +1410,12 @@
return finalImage;
}
- private Image getFinalImage() {
-
+ private BufferedImage getFinalImage() {
+ //
if (finalImage == null) {
- finalImage = null;
- Rectangle curPaintArea = getVisibleRect();
- finalImage = new BufferedImage(curPaintArea.width,
- curPaintArea.height, BufferedImage.TYPE_INT_RGB);
+ // Rectangle curPaintArea = getVisibleRect();
+ finalImage = new BufferedImage(getBounds().width,
+ getBounds().height, BufferedImage.TYPE_INT_RGB);
requestStartRendering();
}
@@ -1400,15 +1423,16 @@
}
private Image getPreFinalImage() {
- if (preFinalImage == null) {
- preFinalImage = null;
- Rectangle curPaintArea = getVisibleRect();
-
- preFinalImage = new BufferedImage(curPaintArea.width,
- curPaintArea.height, BufferedImage.TYPE_INT_RGB);
-
- requestStartRendering();
- }
+ // if (preFinalImage == null) {
+ //
+ // // Rectangle curPaintArea = getVisibleRect();
+ // // preFinalImage = new BufferedImage(curPaintArea.width,
+ // // curPaintArea.height, BufferedImage.TYPE_INT_RGB);
+ //
+ // preFinalImage = createImage(getBounds().width, getBounds().height);
+ //
+ // requestStartRendering();
+ // }
return preFinalImage;
}
@@ -1417,6 +1441,7 @@
* cached images while setting it together.
**/
Point imageOrigin = new Point(0, 0);
+ private final GTRenderer localRenderer;
/**
* Starts rendering on one or two threads
@@ -1426,43 +1451,49 @@
if (!isWellDefined())
return;
- if (bgExecuter != null){
+ if (bgExecuter != null) {
// Stop all renderers
bgExecuter.cancelTask();
}
- if (localExecuter != null){
+ if (localExecuter != null) {
localExecuter.cancelTask();
}
-
+
Rectangle curPaintArea = getVisibleRect();
- labelCache.clear();
/**
* We have to set new renderer
*/
if (getBgContext() != null) {
- bgExecuter = new RenderingExecutor(this, 333l);
- LOGGER.debug("starting bg renderer:");
- // /* System.out.println("rendering"); */
- final GTRenderer createGTRenderer = GTUtil.createGTRenderer(
- bgContext, getRendererHints());
- createGTRenderer.setJava2DHints(getJava2dHints());
- bgExecuter.submit(getBgContext().getAreaOfInterest(), curPaintArea,
- (Graphics2D) getBgImage().getGraphics(), createGTRenderer);
+ // bgExecuter = new RenderingExecutor();
+ // LOGGER.debug("starting bg renderer:");
+ // // /* System.out.println("rendering"); */
+ // final GTRenderer createGTRenderer = GTUtil.createGTRenderer(
+ // bgContext, getRendererHints());
+ // createGTRenderer.setJava2DHints(getJava2dHints());
+ // bgExecuter.submit(getBgContext().getAreaOfInterest(),
+ // curPaintArea,
+ // (Graphics2D) getBgImage().getGraphics(), createGTRenderer);
}
if (getContext() != null) {
-// localExecuter = new RenderingExecutor(this, 150l);
- LOGGER.debug("starting local renderer:");
- final GTRenderer createGTRenderer = GTUtil.createGTRenderer(
- localContext, getRendererHints());
- createGTRenderer.setJava2DHints(getJava2dHints());
- localExecuter.submit(getContext().getAreaOfInterest(),
+ // localExecuter = new RenderingExecutor(this, 150l);
+// LOGGER.debug("starting local renderer:");
+
+ // Clear label cache
+ labelCache.clear();
+ Map<Object, Object> rh = localRenderer.getRendererHints();
+ rh.put(StreamingRenderer.LABEL_CACHE_KEY, labelCache);
+ localRenderer.setRendererHints(rh);
+
+ boolean submitted = localExecuter.submit(getContext().getAreaOfInterest(),
curPaintArea, (Graphics2D) getLocalImage().getGraphics(),
- createGTRenderer);
+ localRenderer, getWorldToScreenTransform());
+ if (submitted) repainterTimer.restart();
+ else requestStartRendering = true; // Try to start rendering again in a moment
}
updateCursor();
@@ -1472,15 +1503,12 @@
/**
* Lazyly initializes a {@link BufferedImage} for the background renderer.
*/
- private BufferedImage getBgImage() {
+ private Image getBgImage() {
+ //
+ // if (bgImage == null) {
+ // bgImage = createImage(getBounds().width, getBounds().height);
+ // }
- if (bgImage == null) {
- Rectangle curPaintArea = getVisibleRect();
-
- bgImage = new BufferedImage(curPaintArea.width + 1,
- curPaintArea.height + 1, BufferedImage.TYPE_INT_ARGB);
- }
-
return bgImage;
}
@@ -1515,17 +1543,13 @@
private BufferedImage getLocalImage() {
if (localImage == null) {
-
- Rectangle curPaintArea = getVisibleRect();
-
- localImage = new BufferedImage(curPaintArea.width + 1,
- curPaintArea.height + 1, BufferedImage.TYPE_INT_ARGB);
+ localImage = new BufferedImage(getBounds().width,
+ getBounds().height, BufferedImage.TYPE_INT_ARGB);
}
return localImage;
}
-
/**
* Called by the {@linkplain XMapPane.RenderingTask} when rendering has been
* completed Publishes a {@linkplain MapPaneEvent} of type {@code
@@ -1569,17 +1593,6 @@
}
-
- @Override
- public void propertyChange(final PropertyChangeEvent evt) {
- final String prop = evt.getPropertyName();
-
- if (prop.equalsIgnoreCase("crs")) {
- localContext.setAreaOfInterest(localContext.getAreaOfInterest(),
- (CoordinateReferenceSystem) evt.getNewValue());
- }
- }
-
/**
* Korrigiert den {@link Envelope} aka {@code mapArea} auf die beste
* erlaubte Flaeche damit die Massstabsbeschaenkungen noch eingehalten
@@ -1898,8 +1911,8 @@
mapPaneListeners.remove(l);
}
- /** Stored the time used for the last real rendering in ms. **/
- private long lastRenderingDuration = Long.MAX_VALUE;
+// /** Stored the time used for the last real rendering in ms. **/
+// private long lastRenderingDuration = Long.MAX_VALUE;
// if null, no quick preview will be shown
private int quickPreviewHint = 0;
@@ -1913,14 +1926,14 @@
*/
private RenderingHints java2dHints;
- /**
- * Returns in milli seconds the time the last rending of the
- * {@link SelectableXMapPane} took. #Long.MAX_VALUE if the JMapPane has not
- * been rendered yet.
- */
- public long getLastRenderingDuration() {
- return lastRenderingDuration;
- }
+// /**
+// * Returns in milli seconds the time the last rending of the
+// * {@link SelectableXMapPane} took. #Long.MAX_VALUE if the JMapPane has not
+// * been rendered yet.
+// */
+// public long getLastRenderingDuration() {
+// return lastRenderingDuration;
+// }
/**
* Should be called when the {@link JMapPane} is not needed no more to help
@@ -1934,9 +1947,11 @@
public void dispose() {
if (isDisposed())
return;
+
+ setPainting(false);
-
- setPainting(false);
+ resizeTimer.stop();
+ startRenderThreadsTimer.stop();
disposed = true;
@@ -1946,21 +1961,48 @@
}
if (localExecuter != null) {
+ int i = 0;
localExecuter.cancelTask();
+ while (i++ < 10 && localExecuter.isRunning()){
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ if (localExecuter.isRunning()) {
+ System.out.println("BAD BAD BAD... still running the thread....");
+ }
localExecuter.dispose();
}
- startRenderThreadsTimer.stop();
- if (bgImage != null)
- bgImage.flush();
- if (localImage != null)
- localImage.flush();
- if (finalImage != null)
- finalImage.flush();
- if (preFinalImage != null)
- preFinalImage.flush();
+ if (bgImage != null) {
+ bgImage = dispose(bgImage);
+ bgImage = null;
+// LangUtil.gcTotal();
+ }
+ if (localImage != null) {
+ localImage = dispose(localImage);
+ localImage = null;
+// LangUtil.gcTotal();
+ }
+
+ if (finalImage != null) {
+ finalImage = dispose(finalImage);
+ finalImage = null;
+// LangUtil.gcTotal();
+ }
+
+ if (preFinalImage != null) {
+ preFinalImage = dispose(preFinalImage);
+ preFinalImage=null;
+ }
+
+// LangUtil.gcTotal();
+
// Alle mapPaneListener entfernen
mapPaneListeners.clear();
@@ -1975,6 +2017,18 @@
removeAll();
}
+ private BufferedImage dispose(BufferedImage bi) {
+
+// System.out.println("vorher = "
+// + new MbDecimalFormatter().format(LangUtil.gcTotal()));
+ bi.flush();
+ return bi = null;
+// System.out.println("nacher = "
+// + new MbDecimalFormatter().format(LangUtil.gcTotal()));
+//
+// System.out.println("\n");
+ }
+
/**
* A flag indicating if dispose() has already been called. If true, then
* further use of this {@link SelectableXMapPane} is undefined.
@@ -2117,6 +2171,8 @@
drawRectangle(graphics, startPos, lastPos);
}
+ graphics.dispose();
+
}
}
@@ -2127,9 +2183,10 @@
*/
protected void drawRectangle(final Graphics graphics, Point startPos,
Point e) {
-
- if (!isWellDefined()) return;
-
+
+ if (!isWellDefined())
+ return;
+
// undraw last box/draw new box
final int left = Math.min(startPos.x, e.x);
final int right = Math.max(startPos.x, e.x);
@@ -2167,7 +2224,7 @@
}
public void onRenderingPending() {
-// LOGGER.debug("Pending rendering updates the preview...");
+ // LOGGER.debug("Pending rendering updates the preview...");
updateFinalImage();
repaint();
}
Modified: branches/1.0-gt2-2.6/src/skrueger/geotools/RenderingExecutor.java
===================================================================
--- branches/1.0-gt2-2.6/src/skrueger/geotools/RenderingExecutor.java 2009-11-18 20:46:08 UTC (rev 528)
+++ branches/1.0-gt2-2.6/src/skrueger/geotools/RenderingExecutor.java 2009-11-18 20:47:00 UTC (rev 529)
@@ -1,23 +1,5 @@
package skrueger.geotools;
-/*
- * GeoTools - The Open Source Java GIS Toolkit
- * http://geotools.org
- *
- * (C) 2002-2008, 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.
- */
-
-
import gtmig.org.geotools.swing.XMapPane;
import java.awt.AlphaComposite;
@@ -25,6 +7,7 @@
import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.Rectangle;
+import java.awt.geom.AffineTransform;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
@@ -41,215 +24,16 @@
import org.geotools.swing.JMapPane;
import org.opengis.feature.simple.SimpleFeature;
-/**
- * This class is used by {@code JMapPane} to handle the scheduling and running of
- * rendering tasks on a background thread. It functions as a single thread, non-
- * queueing executor, ie. only one rendering task can run at any given time and,
- * while it is running, any other submitted tasks will be rejected.
- * <p>
- * Whether a rendering task is accepted or rejected can be tested on submission:
- * <pre><code>
- * ReferencedEnvelope areaToDraw = ...
- * Graphics2D graphicsToDrawInto = ...
- * boolean accepted = renderingExecutor.submit(areaToDraw, graphicsToDrawInto);
- * </code></pre>
- *
- * The status of the executor can also be checked at any time like this:
- * <pre><code>
- * boolean busy = renderingExecutor.isRunning();
- * </code></pre>
- *
- * While a rendering task is running it is regularly polled to see if it has completed
- * and, if so, whether it finished normally, was cancelled or failed. The interval between
- * polling can be adjusted which might be useful to tune the executor for particular
- * applications:
- * <pre><code>
- * RenderingExecutor re = new RenderingExecutor( mapPane );
- * re.setPollingInterval( 150 ); // 150 milliseconds
- * </code></pre>
- *
- * @author Michael Bedward
- * @since 2.7
- * @source $URL: http://svn.osgeo.org/geotools/branches/2.6.x/modules/unsupported/swing/src/main/java/org/geotools/swing/RenderingExecutor.java $
- * @version $Id: RenderingExecutor.java 34285 2009-10-30 10:48:49Z mbedward $
- *
- * @see JMapPane
- */
public class RenderingExecutor {
- private final XMapPane mapPane;
- private final ExecutorService taskExecutor;
- private final ScheduledExecutorService watchExecutor;
-
-// /** The default interval (milliseconds) for polling the result of a rendering task */
-// public static final long DEFAULT_POLLING_INTERVAL = 300L;
-
- private long pollingInterval;
-
- /*
- * This latch is used to avoid a race between the cancellation of
- * a current task and the submittal of a new task
- */
- private CountDownLatch cancelLatch;
-
- /**
- * Constants to indicate the result of a rendering task
- */
- public enum TaskResult {
- PENDING,
- COMPLETED,
- CANCELLED,
- FAILED;
+private volatile RenderThread task;
+private final XMapPane mapPane;
+ public RenderingExecutor(XMapPane mapPane) {
+ this.mapPane = mapPane;
}
- private long numFeatures;
/**
- * A rendering task
- */
- private class Task implements Callable<TaskResult>, RenderListener {
-
- private final ReferencedEnvelope envelope;
- private final Rectangle paintArea;
- private final Graphics2D graphics;
-
- private boolean cancelled;
- private boolean failed;
- final private GTRenderer renderer;
-
- /**
- * Constructor. Creates a new rendering task
- *
- * @param envelope map area to render (world coordinates)
- * @param paintArea drawing area (image or display coordinates)a
- * @param graphics graphics object used to draw into the image or display
- */
- public Task(final ReferencedEnvelope envelope, final Rectangle paintArea, final Graphics2D graphics, GTRenderer renderer) {
- this.envelope = envelope;
- this.paintArea = paintArea;
- this.graphics = graphics;
- this.cancelled = false;
- this.renderer = renderer;
- failed = false;
- }
-
- /**
- * Called by the executor to run this rendering task.
- *
- * @return result of the task: completed, cancelled or failed
- * @throws Exception
- */
- public TaskResult call() throws Exception {
- if (!cancelled) {
-
- try {
- renderer.addRenderListener(this);
-
- Composite composite = graphics.getComposite();
- //graphics.setComposite(AlphaComposite.Src);
- //graphics.setBackground(Color.WHITE);
- graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f));
- graphics.fill(paintArea);
- graphics.setComposite(composite);
-
-
- numFeatures = 0;
- renderer.paint(graphics, mapPane.getVisibleRect(), envelope, mapPane.getWorldToScreenTransform());
-
- } finally {
- renderer.removeRenderListener(this);
- }
- }
-
- if (cancelled) {
- return TaskResult.CANCELLED;
- } else if (failed) {
- return TaskResult.FAILED;
- } else {
- return TaskResult.COMPLETED;
- }
- }
-
- /**
- * Cancel the rendering task if it is running. If called before
- * being run the task will be abandoned.
- */
- public synchronized void cancel() {
- if (isRunning()) {
- cancelled = true;
- renderer.stopRendering();
- }
- }
-
- /**
- * Called by the renderer when each feature is drawn.
- *
- * @param feature the feature just drawn
- */
- public void featureRenderer(SimpleFeature feature) {
- // @todo update a progress listener
- numFeatures++ ;
- }
-
- /**
- * Called by the renderer on error
- *
- * @param e cause of the error
- */
- public void errorOccurred(Exception e) {
- renderingException = e;
- graphics.setColor(Color.white);
- graphics.drawString(e.getMessage(), 11, 11);
- graphics.drawString(e.getMessage(), 9, 9);
- graphics.setColor(Color.black);
- graphics.drawString(e.getMessage(), 10, 10);
- failed = true;
- }
-
- }
-
- private AtomicBoolean taskRunning;
- private Task task;
- private Future<TaskResult> taskResult;
- private ScheduledFuture<?> watcher;
- private Exception renderingException;
-
- /**
- * Constructor. Creates a new executor to service the specified map pane.
- *
- * @param mapPane the map pane to be serviced
- * @param l
- */
- public RenderingExecutor(final XMapPane mapPane, long pollingInterval) {
- taskRunning = new AtomicBoolean(false);
- this.mapPane = mapPane;
- taskExecutor = Executors.newSingleThreadExecutor();
- watchExecutor = Executors.newSingleThreadScheduledExecutor();
- this.pollingInterval = pollingInterval;
- cancelLatch = new CountDownLatch(0);
- }
-
- /**
- * Get the interval for polling the result of a rendering task
- *
- * @return polling interval in milliseconds
- */
- public long getPollingInterval() {
- return pollingInterval;
- }
-
- /**
- * Set the interval for polling the result of a rendering task
- *
- * @param interval interval in milliseconds (values {@code <=} 0 are ignored)
- */
- public void setPollingInterval(long interval) {
- if (interval > 0) {
- pollingInterval = interval;
- }
- }
-
- /**
* Submit a new rendering task. If no rendering task is presently running
* this new task will be accepted; otherwise it will be rejected (ie. there
* is no task queue).
@@ -260,97 +44,109 @@
* @return true if the rendering task was accepted; false if it was
* rejected
*/
- public synchronized boolean submit(ReferencedEnvelope envelope, Rectangle paintArea, Graphics2D graphics, final GTRenderer renderer) {
- if (!isRunning()) {
-// try {
-// // wait for any cancelled task to finish its shutdown
-// cancelLatch.await();
-// } catch (InterruptedException ex) {
-// return false;
-// }
-
- task = new Task(envelope, paintArea, graphics, renderer);
- taskRunning.set(true);
- taskResult = taskExecutor.submit(task);
- watcher = watchExecutor.scheduleAtFixedRate(new Runnable() {
-
- public void run() {
- pollTaskResult();
- }
- }, pollingInterval, pollingInterval, TimeUnit.MILLISECONDS);
-
+ public synchronized boolean submit(ReferencedEnvelope envelope, Rectangle paintArea, Graphics2D graphics, final GTRenderer renderer, AffineTransform worldToScreen) {
+ System.out.println("submit..:");
+ if (task == null || !task.isAlive()) {
+ System.out.println("is vacant... starting thread!");
+
+ task = new RenderThread(paintArea, graphics, renderer, worldToScreen);
+ task.start();
+
return true;
+ } else {
+ System.out.println("is busy... requesting stop!");
+ task.getRenderer().stopRendering();
}
return false;
}
+
+ class RenderThread extends Thread {
+
+ private final GTRenderer renderer;
+// private final Rectangle paintArea;
+// private final AffineTransform worldToScreen;
+// private final Graphics2D graphics;
- /**
- * Cancel the current rendering task if one is running
- */
- public synchronized void cancelTask() {
- if (isRunning()) {
- task.cancel();
-
- // Cancelling to often... can that be the reason?
- if (cancelLatch.getCount() < 1) {
- cancelLatch = new CountDownLatch(1);
- }
- }
+ public RenderThread(final Rectangle paintArea, final Graphics2D graphics, GTRenderer renderer, AffineTransform worldToScreen) {
+ super( new RenderRun(paintArea, graphics, renderer, worldToScreen));
+// this.paintArea = paintArea;
+// this.graphics = graphics;
+ this.renderer = renderer;
+// this.worldToScreen = worldToScreen;
+
+ System.out.println("starting render thread "+getName());
+ }
+
+ public GTRenderer getRenderer() {
+ return renderer;
+ }
+
}
+
+ class RenderRun implements Runnable, RenderListener {
+ private final Rectangle paintArea;
+ private final Graphics2D graphics;
+ private final AffineTransform worldToScreen;
+ private final GTRenderer renderer;
- private void pollTaskResult() {
- if (!taskResult.isDone()) {
- return;
- }
+ public RenderRun(Rectangle paintArea, Graphics2D graphics,
+ GTRenderer renderer, AffineTransform worldToScreen) {
+ this.paintArea = paintArea;
+ this.graphics = graphics;
+ this.renderer = renderer;
+ this.worldToScreen = worldToScreen;
+ }
+ @Override
+ public void run() {
+ try {
+ renderer.addRenderListener(this);
+ System.out.println("start rendering...");
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ renderer.paint(graphics, paintArea, worldToScreen);
+
+ mapPane.onRenderingCompleted();
+ } finally {
+ renderer.removeRenderListener(this);
+ }
+ }
+ @Override
+ public void errorOccurred(Exception e) {
+// System.out.println("rendering error");
+ mapPane.onRenderingFailed(e);
+ }
- TaskResult result = TaskResult.PENDING;
-
- try {
- result = taskResult.get();
- } catch (Exception ex) {
- throw new IllegalStateException("When getting rendering result", ex);
- }
-
- watcher.cancel(false);
- taskRunning.set(false);
-
- switch (result) {
- case CANCELLED:
- cancelLatch.countDown();
- mapPane.onRenderingCancelled();
- break;
-
- case COMPLETED:
- mapPane.onRenderingCompleted();
- break;
-
- case FAILED:
- mapPane.onRenderingFailed(renderingException);
- break;
-
- case PENDING:
- mapPane.onRenderingPending();
- break;
-
- }
+ @Override
+ public void featureRenderer(SimpleFeature feature) {
+ }
+
}
- public synchronized boolean isRunning() {
- return taskRunning.get();
- }
+ public void cancelTask() {
+ if (task!=null && task.isAlive()) {
+// System.out.println("request stop for thread " +task.getName());
+ task.getRenderer().stopRendering();
+ }
+ }
- @Override
- protected void finalize() throws Throwable {
- if (this.isRunning()) {
- taskExecutor.shutdownNow();
- watchExecutor.shutdownNow();
- }
- }
+ public boolean isRunning() {
+// if (task != null)
+// System.out.println("is running "+task.getName()+" = true");
+ return (task != null && task.isAlive());
+ }
+
+ public void dispose() {
+ if (task != null) {
+ task.renderer.stopRendering();
+ task = null;
+ }
+ }
- public void dispose() {
- taskExecutor.shutdownNow();
- watchExecutor.shutdownNow();
- }
+
}
More information about the Schmitzm-commits
mailing list