This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit 37e5d1cfc57ff64501aa52123fe5cfe890182c5f
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Sun Nov 28 15:30:56 2021 +0100

    Reduce the number of image rendering events in the `PropertyView`.
    If rendering requests happen faster that we can redraw, only the last 
request is executed.
---
 .../org/apache/sis/internal/gui/PropertyView.java  | 71 +++++++++++++++-------
 1 file changed, 49 insertions(+), 22 deletions(-)

diff --git 
a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/PropertyView.java
 
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/PropertyView.java
index a57ff74..3b10cb2 100644
--- 
a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/PropertyView.java
+++ 
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/PropertyView.java
@@ -32,7 +32,6 @@ import java.awt.image.RenderedImage;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
 import javafx.beans.property.ObjectProperty;
-import javafx.concurrent.Task;
 import javafx.geometry.Insets;
 import javafx.scene.Node;
 import javafx.scene.text.Font;
@@ -123,9 +122,10 @@ public final class PropertyView extends 
CompoundFormat<Object> implements Change
     private Rectangle visibleImageBounds;
 
     /**
-     * If a work is under progress, that work. Otherwise {@code null}.
+     * The work which is under progress in a background thread (running) or
+     * which is waiting for execution (pending), or {@code null} if none.
      */
-    private Task<?> runningTask;
+    private ImageConverter runningTask, pendingTask;
 
     /**
      * Creates a new property view.
@@ -134,6 +134,7 @@ public final class PropertyView extends 
CompoundFormat<Object> implements Change
      * @param  view        the property where to set the node showing the 
value.
      * @param  background  the image background color, or {@code null} if none.
      */
+    @SuppressWarnings("ThisEscapedInObjectConstruction")
     public PropertyView(final Locale locale, final ObjectProperty<Node> view, 
final ObjectProperty<Background> background) {
         super(locale, null);
         this.view = view;
@@ -217,24 +218,32 @@ public final class PropertyView extends 
CompoundFormat<Object> implements Change
     public void set(final Object newValue, final Rectangle visibleBounds) {
         final boolean boundsChanged = !Objects.equals(visibleBounds, 
visibleImageBounds);
         if (newValue != value || boundsChanged) {
-            if (runningTask != null) {
-                runningTask.cancel(BackgroundThreads.NO_INTERRUPT_DURING_IO);
-                runningTask = null;
-            }
             visibleImageBounds = visibleBounds;
             final Node content;
-            if (newValue == null) {
-                content = null;
-            } else if (newValue instanceof RenderedImage) {
+            if (newValue instanceof RenderedImage) {
                 content = setImage((RenderedImage) newValue, boundsChanged);
-            } else if (newValue instanceof Throwable) {
-                content = setText((Throwable) newValue);
-            } else if (newValue instanceof Collection<?>) {
-                content = setList(((Collection<?>) newValue).toArray());
-            } else if (newValue.getClass().isArray()) {
-                content = setList(newValue);
             } else {
-                content = setText(formatValue(newValue));
+                /*
+                 * The `setImage(…)` method manages itself the `runningTaks` 
and `pendingTask` fields.
+                 * But if the new property requires a different method, we 
need to cancel everything.
+                 */
+                final ImageConverter task = runningTask;
+                if (task != null) {
+                    runningTask = null;
+                    pendingTask = null;
+                    task.cancel(BackgroundThreads.NO_INTERRUPT_DURING_IO);
+                }
+                if (newValue == null) {
+                    content = null;
+                } else if (newValue instanceof Throwable) {
+                    content = setText((Throwable) newValue);
+                } else if (newValue instanceof Collection<?>) {
+                    content = setList(((Collection<?>) newValue).toArray());
+                } else if (newValue.getClass().isArray()) {
+                    content = setList(newValue);
+                } else {
+                    content = setText(formatValue(newValue));
+                }
             }
             view.set(content);
             value = newValue;           // Assign only on success.
@@ -285,7 +294,7 @@ public final class PropertyView extends 
CompoundFormat<Object> implements Change
     /**
      * Sets the property value to the given image.
      *
-     * @param  image  the property value to set, or {@code null}.
+     * @param  image          the property value to set, or {@code null}.
      * @param  boundsChanged  whether {@link #visibleImageBounds} changed 
since last call.
      */
     private Node setImage(final RenderedImage image, final boolean 
boundsChanged) {
@@ -326,19 +335,38 @@ public final class PropertyView extends 
CompoundFormat<Object> implements Change
                 taskCompleted(null);
                 view.set(setText(e.getSource().getException()));
             });
-            runningTask = converter;
-            BackgroundThreads.execute(converter);
+            /*
+             * If an image rendering is already in progress, we will wait for 
its completion before to start
+             * a new background thread. That way, if many `setImage(…)` 
invocations happen before the current
+             * rendering finished, we will start only one new rendering 
process instead of as many processes
+             * as they were `setImage(…)` invocations.
+             */
+            if (runningTask != null) {
+                pendingTask = converter;
+            } else {
+                runningTask = converter;
+                BackgroundThreads.execute(converter);
+            }
         }
         return imagePane;
     }
 
     /**
      * Invoked when {@link #runningTask} completed its work, either 
successfully or with a failure.
+     * This method updates the text containing statistic values in the status 
bar below the image.
+     * If new rendering request happened during the time the task was running, 
start the last request.
      *
      * @param  statistics  statistics for each band of the source image 
(before conversion to JavaFX).
      */
     private void taskCompleted(final Statistics[] statistics) {
-        runningTask  = null;
+        runningTask = pendingTask;
+        pendingTask = null;
+        if (runningTask != null) {
+            BackgroundThreads.execute(runningTask);
+        }
+        /*
+         * Update the status bar with statistics computed by background thread.
+         */
         String range = null;
         String mean  = null;
         if (statistics != null && statistics.length != 0) {
@@ -360,7 +388,6 @@ public final class PropertyView extends 
CompoundFormat<Object> implements Change
         }
         sampleValueRange.setText(range);
         meanValue.setText(mean);
-        changed(null, null, null);      // For centering the image.
     }
 
     /**

Reply via email to