[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