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

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

commit a334b6967ed1f2b044b165e5ff0252991de8f53f
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Wed Apr 22 11:49:48 2026 +0200

    Fix a wrong transformation of coordinates after a change of CRS in the 
status bar.
    Documentation improvement as a side-effect of the search for the bug.
---
 .../sis/geometry/AbstractDirectPosition.java       |   2 +
 .../apache/sis/gui/coverage/GridSliceSelector.java |   2 +-
 .../main/org/apache/sis/gui/internal/Styles.java   |   2 +-
 .../main/org/apache/sis/gui/map/StatusBar.java     | 102 +++++++++++++--------
 4 files changed, 66 insertions(+), 42 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/geometry/AbstractDirectPosition.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/geometry/AbstractDirectPosition.java
index 7f317671cd..eabb56d1bd 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/geometry/AbstractDirectPosition.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/geometry/AbstractDirectPosition.java
@@ -191,6 +191,8 @@ public abstract class AbstractDirectPosition extends 
FormattableObject implement
                         continue;
                     }
                     coordinate -= shift;
+                } else {
+                    continue;
                 }
                 setCoordinate(i, coordinate);
                 changed = true;
diff --git 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/GridSliceSelector.java
 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/GridSliceSelector.java
index 28bd73e208..cca5a333b9 100644
--- 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/GridSliceSelector.java
+++ 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/GridSliceSelector.java
@@ -458,7 +458,7 @@ public class GridSliceSelector extends Widget {
         final void setPosition(final boolean adjusting, final long position) {
             final StatusBar bar = status;
             if (bar != null) {
-                bar.setInfoMessage(adjusting ? toString(position, true) : 
null);
+                bar.setProgressMessage(adjusting ? toString(position, true) : 
null);
             }
             if (!adjusting) {
                 final GridExtent extent = selectedExtent.get();
diff --git 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/Styles.java 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/Styles.java
index 1cfe119d32..e8c8a3494e 100644
--- 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/Styles.java
+++ 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/Styles.java
@@ -72,7 +72,7 @@ public final class Styles {
      * Color of text for information purpose but which are not the main topic.
      * This is using a lighter color for avoiding to be a source of 
distraction.
      */
-    public static final Color FAINT_TEXT = Color.GRAY;
+    public static final Color FAINT_TEXT = Color.DIMGRAY;
 
     /**
      * Color of the text saying that data are in process of being loaded.
diff --git 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/StatusBar.java 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/StatusBar.java
index 61a9603443..5a349925da 100644
--- a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/StatusBar.java
+++ b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/StatusBar.java
@@ -171,7 +171,7 @@ public class StatusBar extends Widget implements 
EventHandler<MouseEvent> {
     /**
      * The tool tip to show on the default message, or {@code null} if none.
      */
-    private Tooltip defaultMessageTeooltip;
+    private Tooltip defaultMessageTooltip;
 
     /**
      * Message to write in the middle of the status bar.
@@ -179,7 +179,7 @@ public class StatusBar extends Widget implements 
EventHandler<MouseEvent> {
      * It takes all the space before {@link #position}.
      *
      * @see #getMessage()
-     * @see #setInfoMessage(String)
+     * @see #setProgressMessage(String)
      * @see #setErrorMessage(String, Throwable)
      * @see #setDefaultMessage(String, Tooltip)
      */
@@ -245,30 +245,34 @@ public class StatusBar extends Widget implements 
EventHandler<MouseEvent> {
 
     /**
      * Conversion from local coordinates to geographic or projected 
coordinates of rendered data.
-     * The local coordinates are the coordinates of the JavaFX view, as given 
for example in {@link MouseEvent}
-     * The objective coordinates are geographic or projected coordinates of 
rendered data, ignoring all CRS changes
-     * that may result from user selecting a different CRS in the contextual 
menu. Consequently while this transform
-     * is often the conversion from pixel coordinates to the coordinates shown 
in this status bar,
-     * this is not always the case.
+     * The local coordinates are the coordinates of the JavaFX view, as given 
for example in {@link MouseEvent}.
+     * The objective coordinates are the (usually geographic or projected) 
coordinates of the image shown in the
+     * {@link MapCanvas} or other control associated with this status bar. 
Objective coordinates are not
+     * necessarily the coordinates shown in the status bar, because another 
transformation step may happen
+     * if the user selected a different <abbr>CRS</abbr> in the contextual 
menu of the status bar.
      *
      * <p>This transform shall never be null. It is initially an identity 
transform and is modified by
      * {@link #applyCanvasGeometry(GridGeometry)}. The transform is usually 
(but not necessarily) affine
      * and should have no {@linkplain 
CoordinateOperation#getCoordinateOperationAccuracy() inaccuracy}
-     * (ignoring rounding error). This transform is normally the inverse of 
{@linkplain #canvas}
+     * (ignoring rounding error). This transform is normally the inverse of 
the canvas's
      * {@linkplain MapCanvas#getObjectiveToDisplay() objective to display} 
transform,
      * but temporary mismatches may exist during gesture events such as pans, 
zooms and rotations.</p>
      *
-     * <p>If this transform is set to a new value, the given transform must 
have the same number of source
-     * and target dimensions than the previous value (if a change in the 
number of dimension is desired,
-     * use {@link #applyCanvasGeometry(GridGeometry)} instead). The status bar 
is updated as if the new
-     * conversion was applied <em>before</em> any CRS changes resulting from 
user selecting a different
-     * CRS in the contextual menu. Note however that any specified transform 
may be overwritten if some
-     * {@linkplain #canvas} gesture events happen later; setting an explicit 
transform is more useful
-     * when this {@code StatusBar} is <em>not</em> associated to a {@link 
MapCanvas}
-     * (for example it may be used with a {@link 
org.apache.sis.gui.coverage.GridView} instead).</p>
+     * <p>This transform may change continuously as a result of gesture events 
such as zooms and pans.
+     * It is possible to set explicitly a value to this property, but the 
specified value may be overwritten
+     * by the next gesture event. Therefore, setting an explicit value is more 
useful when this status bar is
+     * <em>not</em> associated to a {@link MapCanvas}. For example, it may be 
associated to a
+     * {@link org.apache.sis.gui.coverage.GridView} instead).</p>
+     *
+     * <h4>Setting a value explicitly</h4>
+     * If this transform is set to a new value, the given transform must have 
the same number of source
+     * and target dimensions as the previous value (if a change in the number 
of dimensions is desired,
+     * use {@link #applyCanvasGeometry(GridGeometry)} instead).
+     * The status bar is updated as if the specified transform was applied 
<em>before</em> transformation
+     * to the <abbr>CRS</abbr> specified through the contextual menu.
      *
      * <h4>API note</h4>
-     * We do not provide getter/setter for this property; use {@link 
ObjectProperty#set(Object)}
+     * We do not provide getter/setter for this property. Use {@link 
ObjectProperty#set(Object)}
      * directly instead. We omit the "Property" suffix for making this 
operation more natural.
      *
      * @see MapCanvas#getObjectiveCRS()
@@ -522,7 +526,6 @@ public class StatusBar extends Widget implements 
EventHandler<MouseEvent> {
         lowestAccuracy          = new SimpleObjectProperty<>(this, 
"lowestAccuracy");
 
         message = new Label();
-        message.setVisible(false);                      // Waiting for getting 
a message to display.
         message.setMaxWidth(Double.POSITIVE_INFINITY);
         HBox.setHgrow(message, Priority.ALWAYS);
 
@@ -841,11 +844,14 @@ public class StatusBar extends Widget implements 
EventHandler<MouseEvent> {
         if (localToCRS == null) {
             localToCRS = MathTransforms.identity(BIDIMENSIONAL);
         }
+        final MathTransform localToWritten;
         if (sameCRS && objectiveToPositionCRS != null) {
-            localToCRS = MathTransforms.concatenate(localToCRS, 
objectiveToPositionCRS);
+            localToWritten = MathTransforms.concatenate(localToCRS, 
objectiveToPositionCRS);
+        } else {
+            localToWritten = localToCRS;
         }
-        final int srcDim = Math.max(localToCRS.getSourceDimensions(), 
BIDIMENSIONAL);
-        final int tgtDim = localToCRS.getTargetDimensions();
+        final int srcDim = Math.max(localToWritten.getSourceDimensions(), 
BIDIMENSIONAL);
+        final int tgtDim = localToWritten.getTargetDimensions();
         /*
          * Remaining code should not fail, so we can start modifying the 
`StatusBar` fields.
          * The buffers for source and target coordinates are recreated because 
the number of
@@ -859,7 +865,7 @@ public class StatusBar extends Widget implements 
EventHandler<MouseEvent> {
         sourceCoordinates   = Arrays.copyOf(pointOfInterest, srcDim);
         targetCoordinates   = new GeneralDirectPosition(tgtDim);
         objectiveCRS        = crs;
-        localToPositionCRS  = localToCRS;
+        localToPositionCRS  = localToWritten;
         inflatePrecisions   = inflate;
         precisions          = null;
         lastX = lastY       = Double.NaN;           // Not valid anymove — see 
above block comment.
@@ -926,7 +932,7 @@ public class StatusBar extends Widget implements 
EventHandler<MouseEvent> {
      * a background thread for computing the coordinate operation. That task 
may be long
      * the first time that it is executed, but should be fast on subsequent 
invocations.
      *
-     * @param  crs  the new CRS, or {@code null} for {@link #objectiveCRS}.
+     * @param  crs  the new <abbr>CRS</abbr>, or {@code null} for {@link 
#objectiveCRS}.
      *
      * @see #setPositionRID(ReferencingByIdentifiers)
      * @see #getPositionCRS()
@@ -989,13 +995,11 @@ public class StatusBar extends Widget implements 
EventHandler<MouseEvent> {
         } else {
             /*
              * If the requested CRS is the objective CRS, avoid above costly 
operation.
-             * The work that we need to do is to cancel the effect of 
`localToPositionCRS`.
-             * As a special case if `objectiveCRS` was unknown before this 
method call,
-             * set it to the given value. This is needed for initializing the 
format CRS
-             * to the first reference system listed in 
`RecentReferenceSystems` choices.
-             * We could not do this work at construction time because the CRS 
choices may
-             * be computed in a background thread, in which case it became 
known only a
-             * little bit later and given to `StatusBar` through listeners.
+             * Instead, we only need to remove the `localToPositionCRS` 
transform step.
+             * If `objectiveCRS` was unknown before this method call, use the 
given value.
+             * This is needed for initializing the format CRS to the first 
reference system
+             * listed in `RecentReferenceSystems` choices. This initialization 
could not be
+             * done at construction time because the CRS choices may be 
computed in a background thread.
              */
             if (objectiveCRS == null) {
                 objectiveCRS = crs;
@@ -1529,7 +1533,7 @@ public class StatusBar extends Widget implements 
EventHandler<MouseEvent> {
     private boolean isPositionVisible() {
         if (position.isVisible()) {
             final String text = position.getText();
-            return text != null && text != outsideText;           // Identity 
comparison is okay for that value.
+            return text != null && !text.isBlank() && text != outsideText;  // 
Identity comparison is okay for that value.
         }
         return false;
     }
@@ -1633,11 +1637,12 @@ public class StatusBar extends Widget implements 
EventHandler<MouseEvent> {
     }
 
     /**
-     * Returns the message currently shown. It may be an error message or an 
informative message.
+     * Returns the message currently shown. It may be an error message, a 
message for an operation in progress
+     * or a default message to show when there is no error or operation in 
progress.
      *
      * @return the current message, or an empty value if none.
      *
-     * @see #setInfoMessage(String)
+     * @see #setProgressMessage(String)
      * @see #setErrorMessage(String, Throwable)
      * @see #setDefaultMessage(String, Tooltip)
      *
@@ -1658,19 +1663,19 @@ public class StatusBar extends Widget implements 
EventHandler<MouseEvent> {
         if (text == null) {
             text     = defaultMessage;
             textFill = Styles.FAINT_TEXT;
-            tooltip  = defaultMessageTeooltip;
+            tooltip  = defaultMessageTooltip;
         }
-        message.setVisible(text != null);
         message.setText(text);
         message.setTextFill(textFill);
         message.setTooltip(tooltip);
     }
 
     /**
-     * Sets the default message to show when there is no error or operation in 
progress.
-     * If {@link #setInfoMessage(String)} or {@link #setErrorMessage(String, 
Throwable)}
+     * Sets the default message to show when there is no error and no 
operation in progress.
+     * If {@link #setProgressMessage(String)} or {@link 
#setErrorMessage(String, Throwable)}
      * is invoked, the informative or error message has precedence over this 
default message.
-     * When the informative or error message is reset to {@code null}, the 
default message is restored.
+     * When the informative and error message are reset to {@code null},
+     * this default message is restored.
      *
      * @param  text     message to show when there is no other kind of 
message, or {@code null} if none.
      * @param  tooltip  optional tool tip to show on the default message, or 
{@code null} if none.
@@ -1680,9 +1685,9 @@ public class StatusBar extends Widget implements 
EventHandler<MouseEvent> {
     public void setDefaultMessage(String text, final Tooltip tooltip) {
         text = Strings.trimOrNull(text);
         defaultMessage = text;
-        defaultMessageTeooltip = tooltip;
+        defaultMessageTooltip = tooltip;
         // Use the text fill as a way to identify that the message is not an 
error or information.
-        if (message.getText() == null || message.getTextFill() == 
Styles.FAINT_TEXT) {
+        if (Strings.isNullOrEmpty(message.getText()) || message.getTextFill() 
== Styles.FAINT_TEXT) {
             message.setTextFill(Styles.FAINT_TEXT);
             message.setText(text);
             message.setTooltip(tooltip);
@@ -1696,8 +1701,25 @@ public class StatusBar extends Widget implements 
EventHandler<MouseEvent> {
      * @param  text  the message to show, or {@code null} if none.
      *
      * @since 1.3
+     * @deprecated Renamed {@link #setProgressMessage(String)}.
      */
+    @Deprecated(since = "1.7", forRemoval = true)
     public void setInfoMessage(String text) {
+        setProgressMessage(text);
+    }
+
+    /**
+     * Shows or hides a message for an operation in progress.
+     * The given text should be a temporary message, for example for telling 
that a loading is in progress.
+     * If {@code text} is non-null, it replaces the {@linkplain 
#setDefaultMessage default message}.
+     * If {@code text} is null (typically after completion of the operation 
which was in progress),
+     * the default message is restored.
+     *
+     * @param  text  the message to show, or {@code null} for restoring the 
default message.
+     *
+     * @since 1.7
+     */
+    public void setProgressMessage(String text) {
         setMessage(Strings.trimOrNull(text), Styles.LOADING_TEXT);
         message.setGraphic(null);
     }

Reply via email to