svn - r34243 - in branches/2.6.x/modules/unsupported/swing: . src/main/java/org/geotools/swing src/main/java/org/geotools/swing/event

1 message Options
Embed this post
Permalink
svn_geotools

svn - r34243 - in branches/2.6.x/modules/unsupported/swing: . src/main/java/org/geotools/swing src/main/java/org/geotools/swing/event

Reply Threaded More More options
Print post
Permalink
Author: mbedward
Date: 2009-10-26 03:07:08 -0400 (Mon, 26 Oct 2009)
New Revision: 34243

Added:
   branches/2.6.x/modules/unsupported/swing/src/main/java/org/geotools/swing/RenderingExecutor.java
Modified:
   branches/2.6.x/modules/unsupported/swing/pom.xml
   branches/2.6.x/modules/unsupported/swing/src/main/java/org/geotools/swing/JMapPane.java
   branches/2.6.x/modules/unsupported/swing/src/main/java/org/geotools/swing/StatusBar.java
   branches/2.6.x/modules/unsupported/swing/src/main/java/org/geotools/swing/event/MapPaneAdapter.java
   branches/2.6.x/modules/unsupported/swing/src/main/java/org/geotools/swing/event/MapPaneEvent.java
   branches/2.6.x/modules/unsupported/swing/src/main/java/org/geotools/swing/event/MapPaneListener.java
Log:
GEOT-2800 added RenderingExecutor class to handle rendering for JMapPane on background thread. Also added new MapPaneEvent types for rendering states

Modified: branches/2.6.x/modules/unsupported/swing/pom.xml
===================================================================
--- branches/2.6.x/modules/unsupported/swing/pom.xml 2009-10-26 07:00:22 UTC (rev 34242)
+++ branches/2.6.x/modules/unsupported/swing/pom.xml 2009-10-26 07:07:08 UTC (rev 34243)
@@ -67,9 +67,13 @@
             <name>Michael Bedward</name>
             <id>mbedward</id>
             <email>[hidden email]</email>
-            <organization>Dept Environment and Climate Change</organization>
+            <organization>DECCW</organization>
             <organizationUrl>http://www.environment.nsw.gov.au</organizationUrl>
             <timezone>+10</timezone>
+            <roles>
+                <role>Module Maintainer</role>
+                <role>Java Developer</role>
+            </roles>
         </developer>
     </developers>
 

Modified: branches/2.6.x/modules/unsupported/swing/src/main/java/org/geotools/swing/JMapPane.java
===================================================================
--- branches/2.6.x/modules/unsupported/swing/src/main/java/org/geotools/swing/JMapPane.java 2009-10-26 07:00:22 UTC (rev 34242)
+++ branches/2.6.x/modules/unsupported/swing/src/main/java/org/geotools/swing/JMapPane.java 2009-10-26 07:07:08 UTC (rev 34243)
@@ -18,6 +18,7 @@
 
 import java.awt.AlphaComposite;
 import java.awt.Color;
+import java.awt.Composite;
 import java.awt.Cursor;
 import java.awt.Graphics;
 import java.awt.Graphics2D;
@@ -64,13 +65,19 @@
 import org.opengis.geometry.Envelope;
 
 /**
- * A simple map display container that works with a GTRenderer and
- * MapContext to display features. Supports the use of tool classes
+ * A map display pane that works with a GTRenderer and
+ * MapContext to display features. It supports the use of tool classes
  * to implement, for example, mouse-controlled zooming and panning.
+ * <p>
+ * Rendering is performed on a background thread and is managed by
+ * the {@linkplain RenderingExecutor} class.
+ * <p>
+ * Adapted from original code by Ian Turton.
+ *
+ * @see JMapFrame
+ * @see MapPaneListener
+ * @see CursorTool
  *
- * Based on original code by Ian Turton. This version does not yet
- * support selection and highlighting of features.
- *
  * @author Michael Bedward
  * @author Ian Turton
  * @since 2.6
@@ -157,10 +164,12 @@
             }
         }
     }
+
     private DragBox dragBox;
     private MapContext context;
     private GTRenderer renderer;
     private LabelCache labelCache;
+    private RenderingExecutor renderingExecutor;
     private MapToolManager toolManager;
     private MapLayerTable layerTable;
     private Set<MapPaneListener> listeners = new HashSet<MapPaneListener>();
@@ -168,11 +177,14 @@
     private AffineTransform screenToWorld;
     private Rectangle curPaintArea;
     private BufferedImage baseImage;
+    private Graphics2D baseImageGraphics;
     private Point imageOrigin;
     private boolean redrawBaseImage;
     private boolean needNewBaseImage;
     private boolean baseImageMoved;
+    private boolean displayAreaChanged;
 
+
     /**
      * Constructor - creates an instance of JMapPane with no map
      * context or renderer initially
@@ -195,6 +207,7 @@
         needNewBaseImage = true;
         redrawBaseImage = true;
         baseImageMoved = false;
+        displayAreaChanged = false;
 
         /*
          * We use a Timer object to avoid rendering delays and
@@ -217,6 +230,8 @@
         setRenderer(renderer);
         setMapContext(context);
 
+        renderingExecutor = new RenderingExecutor(this);
+
         toolManager = new MapToolManager(this);
 
         dragBox = new DragBox();
@@ -250,6 +265,7 @@
             @Override
             public void componentResized(ComponentEvent ev) {
                 acceptRepaintRequests = false;
+                renderingExecutor.cancelTask();
                 resizeTimer.restart();
             }
         });
@@ -386,26 +402,29 @@
      * @param renderer the renderer to use
      */
     public void setRenderer(GTRenderer renderer) {
-        Map<Object, Object> hints;
-        if (renderer instanceof StreamingRenderer) {
-            hints = renderer.getRendererHints();
-            if (hints == null) {
-                hints = new HashMap<Object, Object>();
+        if (renderer != null) {
+            Map<Object, Object> hints;
+            if (renderer instanceof StreamingRenderer) {
+                hints = renderer.getRendererHints();
+                if (hints == null) {
+                    hints = new HashMap<Object, Object>();
+                }
+                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);
+                }
+                renderer.setRendererHints(hints);
+
+                if (this.context != null) {
+                    renderer.setContext(this.context);
+                }
+
             }
-            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);
-            }
-            renderer.setRendererHints(hints);
         }
 
         this.renderer = renderer;
-
-        if (this.context != null) {
-            this.renderer.setContext(this.context);
-        }
     }
 
     /**
@@ -522,7 +541,7 @@
                 pendingDisplayArea = new ReferencedEnvelope(envelope);
             } else {
                 doSetDisplayArea(envelope);
-                labelCache.clear();
+                displayAreaChanged = true;
                 repaint();
             }
             
@@ -760,6 +779,8 @@
      */
     @Override
     protected void paintComponent(Graphics g) {
+        System.out.println("paintComponent");
+
         super.paintComponent(g);
 
         if (acceptRepaintRequests) {
@@ -767,17 +788,23 @@
             if (context == null || renderer == null) {
                 return;
             }
-            if (curPaintArea == null ){
+
+            if (curPaintArea == null ) {
                 return;
             }
+
             if (needNewBaseImage) {
                 baseImage = new BufferedImage(curPaintArea.width + 1, curPaintArea.height + 1, BufferedImage.TYPE_INT_ARGB);
+                if (baseImageGraphics != null) {
+                    baseImageGraphics.dispose();
+                }
+                baseImageGraphics = baseImage.createGraphics();
                 needNewBaseImage = false;
                 redrawBaseImage = true;
                 labelCache.clear();
             }
 
-            ReferencedEnvelope mapAOI = context.getAreaOfInterest();
+            final ReferencedEnvelope mapAOI = context.getAreaOfInterest();
             if (mapAOI == null) {
                 return;
             }
@@ -788,17 +815,80 @@
                     baseImageMoved = false;
                     labelCache.clear();
                 }
-                clearBaseImage();
-                Graphics2D baseGr = baseImage.createGraphics();
-                renderer.paint(baseGr, curPaintArea, mapAOI, worldToScreen);
+
+                if (renderingExecutor.submit(mapAOI, curPaintArea, baseImageGraphics)) {
+                    MapPaneEvent ev = new MapPaneEvent(this, MapPaneEvent.Type.RENDERING_STARTED);
+                    publishEvent(ev);
+
+                    clearBaseImage();
+
+                } else {
+                    onRenderingRejected();
+                }
+
             }
 
-            ((Graphics2D) g).drawImage(baseImage, imageOrigin.x, imageOrigin.y, this);
+            Graphics2D g2 = (Graphics2D) g;
+            g2.drawImage(baseImage, imageOrigin.x, imageOrigin.y, this);
             redrawBaseImage = true;
         }
     }
 
     /**
+     * Called by the {@linkplain JMapPane.RenderingTask} when rendering has been completed
+     * Publishes a {@linkplain MapPaneEvent} of type
+     * {@code MapPaneEvent.Type.RENDERING_STOPPED} to listeners.
+     *
+     * @see MapPaneListener#onRenderingStopped(org.geotools.swing.event.MapPaneEvent)
+     */
+    public void onRenderingCompleted() {
+        System.out.println("onRenderingCompleted");
+
+        if (displayAreaChanged) {
+            labelCache.clear();
+        }
+
+        Graphics2D paneGr = (Graphics2D) this.getGraphics();
+        paneGr.drawImage(baseImage, imageOrigin.x, imageOrigin.y, this);
+
+        MapPaneEvent ev = new MapPaneEvent(this, MapPaneEvent.Type.RENDERING_STOPPED);
+        publishEvent(ev);
+    }
+
+    /**
+     * Called by the {@linkplain JMapPane.RenderingTask} when rendering was cancelled.
+     * Publishes a {@linkplain MapPaneEvent} of type
+     * {@code MapPaneEvent.Type.RENDERING_STOPPED} to listeners.
+     *
+     * @see MapPaneListener#onRenderingStopped(org.geotools.swing.event.MapPaneEvent)
+     */
+    public void onRenderingCancelled() {
+        MapPaneEvent ev = new MapPaneEvent(this, MapPaneEvent.Type.RENDERING_STOPPED);
+        publishEvent(ev);
+    }
+
+    /**
+     * Called by the {@linkplain JMapPane.RenderingTask} when rendering failed.
+     * Publishes a {@linkplain MapPaneEvent} of type
+     * {@code MapPaneEvent.Type.RENDERING_STOPPED} to listeners.
+     *
+     * @see MapPaneListener#onRenderingStopped(org.geotools.swing.event.MapPaneEvent)
+     */
+    public void onRenderingFailed() {
+        MapPaneEvent ev = new MapPaneEvent(this, MapPaneEvent.Type.RENDERING_STOPPED);
+        publishEvent(ev);
+    }
+
+    /**
+     * Called when a rendering request has been rejected. This will be common, such as
+     * when the user pauses during drag-resizing fo the map pane. The base implementation
+     * does nothing. It is provided for sub-classes to override if required.
+     */
+    public void onRenderingRejected() {
+        // do nothing
+    }
+
+    /**
      * Called after the base image has been dragged. Sets the new map area and
      * transforms
      * @param env the display area (world coordinates) prior to the image being moved
@@ -955,12 +1045,13 @@
      * object each time we need to redraw the image
      */
     private void clearBaseImage() {
-        assert(baseImage != null);
-        Graphics2D g2D = baseImage.createGraphics();
-        g2D.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f));
+        assert(baseImage != null && baseImageGraphics != null);
+        Composite composite = baseImageGraphics.getComposite();
+        baseImageGraphics.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f));
         Rectangle2D.Double rect = new Rectangle2D.Double(
                 0, 0, baseImage.getWidth(), baseImage.getHeight());
-        g2D.fill(rect);
+        baseImageGraphics.fill(rect);
+        baseImageGraphics.setComposite(composite);
     }
 
     /**
@@ -987,6 +1078,18 @@
                 case DISPLAY_AREA_CHANGED:
                     listener.onDisplayAreaChanged(ev);
                     break;
+
+                case RENDERING_STARTED:
+                    listener.onRenderingStarted(ev);
+                    break;
+
+                case RENDERING_STOPPED:
+                    listener.onRenderingStopped(ev);
+                    break;
+
+                case RENDERING_PROGRESS:
+                    listener.onRenderingProgress(ev);
+                    break;
             }
         }
     }

Added: branches/2.6.x/modules/unsupported/swing/src/main/java/org/geotools/swing/RenderingExecutor.java
===================================================================
--- branches/2.6.x/modules/unsupported/swing/src/main/java/org/geotools/swing/RenderingExecutor.java                        (rev 0)
+++ branches/2.6.x/modules/unsupported/swing/src/main/java/org/geotools/swing/RenderingExecutor.java 2009-10-26 07:07:08 UTC (rev 34243)
@@ -0,0 +1,261 @@
+/*
+ *    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.
+ */
+
+package org.geotools.swing;
+
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.geotools.geometry.jts.ReferencedEnvelope;
+import org.geotools.renderer.GTRenderer;
+import org.geotools.renderer.RenderListener;
+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$
+ * @version $Id$
+ *
+ * @see JMapPane
+ */
+public class RenderingExecutor {
+
+    private final JMapPane 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 = 200L;
+
+    private long pollingInterval;
+
+    /**
+     * Constants to indicate the result of a rendering task
+     */
+    private enum TaskResult {
+        PENDING,
+        COMPLETED,
+        CANCELLED,
+        FAILED;
+    }
+
+    /**
+     * 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;
+
+        public Task(final ReferencedEnvelope envelope, final Rectangle paintArea, final Graphics2D graphics) {
+            this.envelope = envelope;
+            this.paintArea = paintArea;
+            this.graphics = graphics;
+            cancelled = false;
+            failed = false;
+        }
+
+        public TaskResult call() throws Exception {
+            GTRenderer renderer = mapPane.getRenderer();
+            renderer.addRenderListener(this);
+
+            renderer.paint(graphics, mapPane.getVisibleRect(), envelope, mapPane.getWorldToScreenTransform());
+
+            renderer.removeRenderListener(this);
+
+            if (cancelled) {
+                return TaskResult.CANCELLED;
+            } else if (failed) {
+                return TaskResult.FAILED;
+            } else {
+                return TaskResult.COMPLETED;
+            }
+        }
+
+        public synchronized void cancel() {
+            if (isRunning()) {
+                cancelled = true;
+                mapPane.getRenderer().stopRendering();
+            }
+        }
+
+        public void featureRenderer(SimpleFeature feature) {
+            // @todo update a progress listener
+            }
+
+        public void errorOccurred(Exception e) {
+            failed = true;
+        }
+    }
+
+    private AtomicBoolean taskRunning;
+    private Task task;
+    private Future<TaskResult> taskResult;
+    private ScheduledFuture<?> watcher;
+
+    /**
+     * Constructor
+     *
+     * @param mapPane the map pane to be serviced by this rendering executor
+     */
+    public RenderingExecutor(final JMapPane mapPane) {
+        taskRunning = new AtomicBoolean(false);
+        this.mapPane = mapPane;
+        taskExecutor = Executors.newSingleThreadExecutor();
+        watchExecutor = Executors.newSingleThreadScheduledExecutor();
+        pollingInterval = DEFAULT_POLLING_INTERVAL;
+    }
+
+    /**
+     * 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).
+     *
+     * @param envelope the map area (world coordinates) to be rendered
+     * @param graphics the graphics object to draw on
+     *
+     * @return true if the rendering task was accepted; false if it was
+     *         rejected
+     */
+    public synchronized boolean submit(ReferencedEnvelope envelope, Rectangle paintArea, Graphics2D graphics) {
+        if (!isRunning()) {
+            task = new Task(envelope, paintArea, graphics);
+            taskRunning.set(true);
+            taskResult = taskExecutor.submit(task);
+            watcher = watchExecutor.scheduleAtFixedRate(new Runnable() {
+
+                public void run() {
+                    pollTaskResult();
+                }
+            }, DEFAULT_POLLING_INTERVAL, DEFAULT_POLLING_INTERVAL, TimeUnit.MILLISECONDS);
+
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Cancel the current rendering task if one is running
+     */
+    public void cancelTask() {
+        if (isRunning()) {
+            task.cancel();
+        }
+    }
+
+    private void pollTaskResult() {
+        if (!taskResult.isDone()) {
+            return;
+        }
+
+        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:
+                mapPane.onRenderingCancelled();
+                break;
+
+            case COMPLETED:
+                mapPane.onRenderingCompleted();
+                break;
+
+            case FAILED:
+                mapPane.onRenderingFailed();
+                break;
+        }
+    }
+
+    public synchronized boolean isRunning() {
+        return taskRunning.get();
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        if (this.isRunning()) {
+            taskExecutor.shutdownNow();
+            watchExecutor.shutdownNow();
+        }
+    }
+}
+


Property changes on: branches/2.6.x/modules/unsupported/swing/src/main/java/org/geotools/swing/RenderingExecutor.java
___________________________________________________________________
Added: svn:keywords
   + Id URL

Modified: branches/2.6.x/modules/unsupported/swing/src/main/java/org/geotools/swing/StatusBar.java
===================================================================
--- branches/2.6.x/modules/unsupported/swing/src/main/java/org/geotools/swing/StatusBar.java 2009-10-26 07:00:22 UTC (rev 34242)
+++ branches/2.6.x/modules/unsupported/swing/src/main/java/org/geotools/swing/StatusBar.java 2009-10-26 07:07:08 UTC (rev 34243)
@@ -52,7 +52,7 @@
     private static final ResourceBundle stringRes = ResourceBundle.getBundle("org/geotools/swing/Text");
 
     /** Number of status bar spaces (text areas) */
-    public static final int NUM_SPACES = 3;
+    public static final int NUM_SPACES = 4;
 
     /** Index of the space used for mouse coordinates */
     public static final int COORDS_SPACE = 0;
@@ -60,7 +60,7 @@
     /** Index of the space used for map bounds */
     public static final int BOUNDS_SPACE = 1;
 
-    /** Index of teh space used for the CRS */
+    /** Index of the space used for the CRS */
     public static final int CRS_SPACE = 2;
 
     private JMapPane mapPane;
@@ -69,6 +69,7 @@
     private MapPaneAdapter mapPaneListener;
 
     private JLabel[] spaces;
+    private JLabel renderLabel;
 
     /**
      * Default constructor.
@@ -174,39 +175,56 @@
      * the first space for map coordinates.
      */
     private void init() {
+        Rectangle2D rect;
+        String constraint;
+
         LayoutManager lm = new MigLayout("insets 0");
         this.setLayout(lm);
 
-        spaces = new JLabel[NUM_SPACES];
         Font font = Font.decode("Courier-12");
 
-        int fontH = getFontMetrics(font).getHeight();
+        renderLabel = new JLabel();
+        rect = getFontMetrics(font).getStringBounds(
+                "Rendering... ", renderLabel.getGraphics());
 
-        Rectangle2D rect;
-        String constraint;
+        constraint = String.format("width %d!, height %d!",
+                (int)rect.getWidth() + 10, (int)rect.getHeight() + 6);
 
+        add(renderLabel, constraint);
+
+        spaces = new JLabel[NUM_SPACES];
+
         spaces[COORDS_SPACE] = new JLabel();
         spaces[COORDS_SPACE].setFont(font);
+
         rect = getFontMetrics(font).getStringBounds(
                 "  00000000.000 00000000.000", spaces[0].getGraphics());
+
         constraint = String.format("width %d!, height %d!",
                 (int)rect.getWidth() + 10, (int)rect.getHeight() + 6);
+
         add(spaces[COORDS_SPACE], constraint);
 
         spaces[BOUNDS_SPACE] = new JLabel();
         spaces[BOUNDS_SPACE].setFont(font);
+
         rect = getFontMetrics(font).getStringBounds(
                 "Min: 00000000.000 00000000.000 Span: 00000000.000 00000000.000", spaces[0].getGraphics());
+
         constraint = String.format("width %d!, height %d!",
                 (int)rect.getWidth() + 10, (int)rect.getHeight() + 6);
+
         add(spaces[BOUNDS_SPACE], constraint);
 
         spaces[CRS_SPACE] = new JLabel();
         spaces[CRS_SPACE].setFont(font);
+
         rect = getFontMetrics(font).getStringBounds(
                 "The name of a CRS might be this long", spaces[0].getGraphics());
+
         constraint = String.format("width %d!, height %d!",
                 (int)rect.getWidth() + 20, (int)rect.getHeight() + 6);
+
         add(spaces[CRS_SPACE], constraint);
     }
 
@@ -247,6 +265,22 @@
                 }
             }
 
+            @Override
+            public void onRenderingStarted(MapPaneEvent ev) {
+                renderLabel.setText("Rendering...");
+            }
+
+            @Override
+            public void onRenderingStopped(MapPaneEvent ev) {
+                renderLabel.setText("");
+            }
+
+            @Override
+            public void onRenderingProgress(MapPaneEvent ev) {
+                float progress = ((Number) ev.getData()).floatValue();
+                System.out.println("render progress: " + progress);
+            }
+
         };
     }
 

Modified: branches/2.6.x/modules/unsupported/swing/src/main/java/org/geotools/swing/event/MapPaneAdapter.java
===================================================================
--- branches/2.6.x/modules/unsupported/swing/src/main/java/org/geotools/swing/event/MapPaneAdapter.java 2009-10-26 07:00:22 UTC (rev 34242)
+++ branches/2.6.x/modules/unsupported/swing/src/main/java/org/geotools/swing/event/MapPaneAdapter.java 2009-10-26 07:07:08 UTC (rev 34243)
@@ -57,4 +57,28 @@
      * @param ev the event
      */
     public void onDisplayAreaChanged(MapPaneEvent ev) {}
+
+    /**
+     * Called by the map pane when it has started rendering features
+     *
+     * @param ev the event
+     */
+    public void onRenderingStarted(MapPaneEvent ev) {}
+
+    /**
+     * Called by the map pane when it has stopped rendering features
+     *
+     * @param ev the event
+     */
+    public void onRenderingStopped(MapPaneEvent ev) {}
+
+    /**
+     * Called by the map pane when it is rendering features. The
+     * event will be carrying data: a floating point value between
+     * 0 and 1 indicating rendering progress.
+     *
+     * @param ev the event
+     */
+    public void onRenderingProgress(MapPaneEvent ev) {}
+
 }

Modified: branches/2.6.x/modules/unsupported/swing/src/main/java/org/geotools/swing/event/MapPaneEvent.java
===================================================================
--- branches/2.6.x/modules/unsupported/swing/src/main/java/org/geotools/swing/event/MapPaneEvent.java 2009-10-26 07:00:22 UTC (rev 34242)
+++ branches/2.6.x/modules/unsupported/swing/src/main/java/org/geotools/swing/event/MapPaneEvent.java 2009-10-26 07:07:08 UTC (rev 34243)
@@ -56,14 +56,34 @@
          * include both changes in bounds and in the
          * coordinate reference system.
          */
-        DISPLAY_AREA_CHANGED;
+        DISPLAY_AREA_CHANGED,
+
+        /**
+         * The map pane has started rendering features.
+         */
+        RENDERING_STARTED,
+
+        /**
+         * The map pane has stopped rendering features.
+         */
+        RENDERING_STOPPED,
+
+        /**
+         * The map pane is rendering features. The event
+         * will carry data that can be retrieved as a floating
+         * point value between 0 and 1.
+         */
+        RENDERING_PROGRESS;
     }
 
     /** Type of mappane event */
     private Type type;
 
+    /** Data associated with some event types */
+    private Object data;
+
     /**
-     * Constructor
+     * Constructor for an event with no associated data
      *
      * @param source the map pane issuing this event
      * @param type the type of event
@@ -74,6 +94,20 @@
     }
 
     /**
+     * Constructor for an event with associated data. The new event
+     * object takes ownership of the data object.
+     *
+     * @param source the map pane issuing this event
+     * @param type the type of event
+     * @param data the event data
+     */
+    public MapPaneEvent(JMapPane source, Type type, Object data) {
+        super(source);
+        this.type = type;
+        this.data = data;
+    }
+
+    /**
      * Get the type of this event
      * @return event type
      */
@@ -81,4 +115,12 @@
         return type;
     }
 
+    /**
+     * Get the data associated with this event, if any
+     *
+     * @return event data or {@code null} if not applicable
+     */
+    public Object getData() {
+        return data;
+    }
 }

Modified: branches/2.6.x/modules/unsupported/swing/src/main/java/org/geotools/swing/event/MapPaneListener.java
===================================================================
--- branches/2.6.x/modules/unsupported/swing/src/main/java/org/geotools/swing/event/MapPaneListener.java 2009-10-26 07:00:22 UTC (rev 34242)
+++ branches/2.6.x/modules/unsupported/swing/src/main/java/org/geotools/swing/event/MapPaneListener.java 2009-10-26 07:07:08 UTC (rev 34243)
@@ -56,4 +56,27 @@
      */
     public void onDisplayAreaChanged(MapPaneEvent ev);
 
+    /**
+     * Called by the map pane when it has started rendering features
+     *
+     * @param ev the event
+     */
+    public void onRenderingStarted(MapPaneEvent ev);
+
+    /**
+     * Called by the map pane when it has stopped rendering features
+     *
+     * @param ev the event
+     */
+    public void onRenderingStopped(MapPaneEvent ev);
+
+    /**
+     * Called by the map pane when it is rendering features. The
+     * event will be carrying data: a floating point value between
+     * 0 and 1 indicating rendering progress.
+     *
+     * @param ev the event
+     */
+    public void onRenderingProgress(MapPaneEvent ev);
+
 }


------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
GeoTools-commits mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/geotools-commits