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 48633f037761e8b77ee14b8d3aacb23615d93802
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Mon Mar 30 11:07:38 2026 +0200

    Adds a "Layers" panel and move the "Visual indication of tile loading" 
checkbox as a map item.
    This is the beginning of a `MapContextView` widget as a tree view with a 
configuration panel.
---
 .../org/apache/sis/util/resources/Vocabulary.java  |   5 +
 .../sis/util/resources/Vocabulary.properties       |   1 +
 .../sis/util/resources/Vocabulary_fr.properties    |   1 +
 .../apache/sis/gui/coverage/CoverageCanvas.java    |  42 ++++++-
 .../apache/sis/gui/coverage/CoverageControls.java  |  50 +++++++--
 .../apache/sis/gui/coverage/CoverageExplorer.java  |  22 ++--
 .../apache/sis/gui/coverage/StyleController.java   |  77 +++++++++++++
 .../org/apache/sis/gui/dataset/WindowHandler.java  |  27 +++--
 .../apache/sis/gui/internal/DataStoreOpener.java   |  56 +++++++---
 .../apache/sis/gui/map/style/ItemController.java   |  50 +++++++++
 .../apache/sis/gui/map/style/MapContextView.java   | 122 +++++++++++++++++++++
 .../package-info.java => map/style/MapItem.java}   |  27 ++++-
 .../package-info.java => map/style/MapLayer.java}  |  29 ++++-
 .../{referencing => map/style}/package-info.java   |  10 +-
 .../gui/referencing/RecentReferenceSystems.java    |  73 ++++++++----
 .../apache/sis/gui/referencing/package-info.java   |   2 +-
 16 files changed, 502 insertions(+), 92 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary.java
 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary.java
index 2bf1d664eb..9fea4b3345 100644
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary.java
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary.java
@@ -699,6 +699,11 @@ public class Vocabulary extends IndexedResourceBundle {
          */
         public static final short Latitude = 112;
 
+        /**
+         * Layers
+         */
+        public static final short Layers = 285;
+
         /**
          * Layout
          */
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary.properties
 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary.properties
index da9cf8472e..b7e9cbf0e0 100644
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary.properties
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary.properties
@@ -145,6 +145,7 @@ JavaHome                = Java home directory
 Julian                  = Julian
 Latitude                = Latitude
 Longitude               = Longitude
+Layers                  = Layers
 Layout                  = Layout
 Legend                  = Legend
 Level                   = Level
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary_fr.properties
 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary_fr.properties
index 67fa5590ea..98b196c92d 100644
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary_fr.properties
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary_fr.properties
@@ -152,6 +152,7 @@ JavaHome                = R\u00e9pertoire du Java
 Julian                  = Julien
 Latitude                = Latitude
 Longitude               = Longitude
+Layers                  = Couches
 Layout                  = Disposition
 Legend                  = L\u00e9gende
 Level                   = Niveau
diff --git 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CoverageCanvas.java
 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CoverageCanvas.java
index 20ceee15a7..7433c89b84 100644
--- 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CoverageCanvas.java
+++ 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CoverageCanvas.java
@@ -207,6 +207,14 @@ public class CoverageCanvas extends MapCanvasAWT {
      */
     private boolean hasCoverageOrResource;
 
+    /**
+     * Whether to skip the rendering of the coverage.
+     * OTher features such as the isolines may still be rendered.
+     *
+     * @see #setCoverageHidden(boolean)
+     */
+    private boolean isCoverageHidden;
+
     /**
      * A subspace of the grid coverage extent where all dimensions except two 
have a size of 1 cell.
      * May be {@code null} if the grid coverage has only two dimensions with a 
size greater than 1 cell.
@@ -488,6 +496,19 @@ public class CoverageCanvas extends MapCanvasAWT {
         }
     }
 
+    /**
+     * Set whether to skip the rendering of the coverage.
+     * OTher features such as the isolines may still be rendered.
+     *
+     * @param  hidden  whether to skip the rendering of the coverage.
+     */
+    final void setCoverageHidden(final boolean hidden) {
+        if (isCoverageHidden != hidden) {
+            isCoverageHidden = hidden;
+            requestRepaint();
+        }
+    }
+
     /**
      * Invoked when image colors changed. Derived features such are isolines 
are assumed unchanged.
      * This method should be invoked explicitly when the {@link Colorizer} 
changes its internal state.
@@ -945,13 +966,13 @@ public class CoverageCanvas extends MapCanvasAWT {
         /**
          * The {@link #recoloredImage} after resampling is applied.
          * May be {@code null} if not yet computed, in which case it will be 
computed by {@link #render()}.
+         * This image should not be cached after rendering operation is 
completed.
          */
         private RenderedImage resampledImage;
 
         /**
-         * The resampled image with tiles computed in advance. The set of 
prefetched
-         * tiles may differ at each rendering event. This image should not be 
cached
-         * after rendering operation is completed.
+         * The resampled image with tiles computed in advance.
+         * The set of prefetched tiles may differ at each rendering event.
          */
         private RenderedImage prefetchedImage;
 
@@ -965,6 +986,12 @@ public class CoverageCanvas extends MapCanvasAWT {
          */
         private AffineTransform resampledToDisplay;
 
+        /**
+         * Whether to skip the rendering of the coverage.
+         * OTher features such as the isolines may still be rendered.
+         */
+        private final boolean isCoverageHidden;
+
         /**
          * Snapshot of information required for rendering isolines, or {@code 
null} if none.
          */
@@ -983,6 +1010,7 @@ public class CoverageCanvas extends MapCanvasAWT {
             displayBounds      = canvas.getDisplayBounds();
             objectivePOI       = canvas.getPointOfInterest(true);
             recoloredImage     = 
canvas.derivedImages.get(data.selectedDerivative);
+            isCoverageHidden   = canvas.isCoverageHidden;
             if (data.validateCRS(objectiveCRS)) {
                 resampledImage = canvas.resampledImage;
             }
@@ -1092,7 +1120,9 @@ public class CoverageCanvas extends MapCanvasAWT {
                  * We cannot invoke it sooner because it needs some 
`resampleAndConvert(…)` results.
                  */
                 final Future<Isolines[]> newIsolines = data.generate(isolines);
-                prefetchedImage = data.prefetch(resampledImage, 
resampledToDisplay, displayBounds);
+                if (!isCoverageHidden) {
+                    prefetchedImage = data.prefetch(resampledImage, 
resampledToDisplay, displayBounds);
+                }
                 if (newIsolines != null) {
                     IsolineRenderer.complete(isolines, newIsolines);
                 }
@@ -1112,7 +1142,7 @@ public class CoverageCanvas extends MapCanvasAWT {
                 ((TileErrorHandler.Executor) prefetchedImage).execute(
                         () -> 
gr.drawRenderedImage(RenderingWorkaround.wrap(prefetchedImage), 
resampledToDisplay),
                         new TileErrorHandler(data.processor.getErrorHandler(), 
CoverageCanvas.class, "paint"));
-            } else {
+            } else if (!isCoverageHidden) {
                 
gr.drawRenderedImage(RenderingWorkaround.wrap(prefetchedImage), 
resampledToDisplay);
             }
             if (isolines != null) {
@@ -1399,7 +1429,7 @@ public class CoverageCanvas extends MapCanvasAWT {
                 }
             });
             if (error != null) {
-                unexpectedException(error);
+                Logging.recoverableException(LOGGER, TileReadListener.class, 
"run", error);
             }
         }
 
diff --git 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CoverageControls.java
 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CoverageControls.java
index 9e39751247..2daf592fc9 100644
--- 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CoverageControls.java
+++ 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CoverageControls.java
@@ -18,9 +18,9 @@ package org.apache.sis.gui.coverage;
 
 import java.util.List;
 import java.util.Locale;
+import javafx.application.Platform;
 import javafx.scene.control.TitledPane;
 import javafx.scene.control.ChoiceBox;
-import javafx.scene.control.CheckBox;
 import javafx.scene.control.Label;
 import javafx.scene.control.TableView;
 import javafx.scene.control.Tooltip;
@@ -29,18 +29,25 @@ import javafx.scene.layout.Region;
 import javafx.scene.layout.VBox;
 import javafx.scene.layout.Priority;
 import javafx.collections.ObservableList;
+import org.apache.sis.image.Interpolation;
 import org.apache.sis.coverage.Category;
 import org.apache.sis.coverage.grid.GridCoverage;
 import org.apache.sis.storage.GridCoverageResource;
+import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.gui.dataset.WindowHandler;
 import org.apache.sis.gui.map.MapMenu;
-import org.apache.sis.image.Interpolation;
+import org.apache.sis.gui.map.style.MapLayer;
+import org.apache.sis.gui.map.style.MapContextView;
 import org.apache.sis.gui.internal.GUIUtilities;
 import org.apache.sis.gui.internal.Styles;
 import org.apache.sis.gui.internal.Resources;
+import org.apache.sis.gui.internal.DataStoreOpener;
+import org.apache.sis.gui.internal.BackgroundThreads;
+import static org.apache.sis.gui.internal.LogHandler.LOGGER;
 import org.apache.sis.gui.controls.ValueColorMapper;
 import org.apache.sis.gui.controls.SyncWindowList;
 import org.apache.sis.util.resources.Vocabulary;
+import org.apache.sis.util.logging.Logging;
 
 
 /**
@@ -58,6 +65,12 @@ final class CoverageControls extends ViewAndControls {
      */
     final CoverageCanvas view;
 
+    /**
+     * Provides widget for controlling the rendering of the coverage.
+     * This is the root of the {@link MapContextView} tree.
+     */
+    private final StyleController style;
+
     /**
      * The control showing categories and their colors for the current 
coverage.
      */
@@ -100,6 +113,13 @@ final class CoverageControls extends ViewAndControls {
         final MapMenu menu = new MapMenu(view);
         menu.addReferenceSystems(owner.referenceSystems);
         menu.addCopyOptions(status);
+        /*
+         * "Layers" section with the following controls:
+         *    - Tree of layers associated to the coverage (styling, isolines, 
visual indication of loaded tiles).
+         */
+        final var layers = new MapContextView(resources);
+        style = new StyleController(view, resources);
+        layers.setRootItem(style);
         /*
          * "Display" section with the following controls:
          *    - Current CRS
@@ -129,19 +149,13 @@ final class CoverageControls extends ViewAndControls {
             styling = new CoverageStyling(view);
             categoryTable = styling.createCategoryTable(resources, vocabulary);
             VBox.setVgrow(categoryTable, Priority.ALWAYS);
-            /*
-             * Whether to show a visual indication of which tiles are read.
-             */
-            final var showTileReads = new 
CheckBox(resources.getString(Resources.Keys.ShowTileReadEvents));
-            showTileReads.selectedProperty().addListener((p,o,n) -> 
view.showTileReads(n));
             /*
              * All sections put together.
              */
             displayPane = new VBox(
                     labelOfGroup(vocabulary, Vocabulary.Keys.ReferenceSystem, 
crsControl,    true),  crsControl,
                     labelOfGroup(vocabulary, Vocabulary.Keys.Values,          
valuesControl, false), valuesControl,
-                    labelOfGroup(vocabulary, Vocabulary.Keys.Categories,      
categoryTable, false), categoryTable,
-                    showTileReads);
+                    labelOfGroup(vocabulary, Vocabulary.Keys.Categories,      
categoryTable, false), categoryTable);
         }
         /*
          * "Isolines" section with the following controls:
@@ -168,6 +182,7 @@ final class CoverageControls extends ViewAndControls {
          */
         final TitledPane deferred;                  // Control to be built 
only if requested.
         controlPanes = new TitledPane[] {
+            new TitledPane(vocabulary.getString(Vocabulary.Keys.Layers),   
layers.getView()),
             new TitledPane(vocabulary.getString(Vocabulary.Keys.Display),  
displayPane),
             new TitledPane(vocabulary.getString(Vocabulary.Keys.Isolines), 
isolinesPane),
             new TitledPane(resources.getString(Resources.Keys.Windows), 
windows.getView()),
@@ -196,6 +211,23 @@ final class CoverageControls extends ViewAndControls {
         if (isAdjustingSlice) {
             return;
         }
+        BackgroundThreads.execute(() -> {
+            final Locale locale = owner.getLocale();
+            String name;
+            try {
+                name = DataStoreOpener.findLabel(resource, locale, true);
+            } catch (DataStoreException | RuntimeException e) {
+                // Declare `setResource` as the public method invoking 
(indirectly) this method.
+                Logging.recoverableException(LOGGER, CoverageExplorer.class, 
"setResource", e);
+                name = DataStoreOpener.fallbackLabel(resource, locale);
+            }
+            final var layer = new MapLayer<>(resource, name);
+            Platform.runLater(() -> {
+                if (owner.getResource() == resource) {      // Verify that the 
resource did not changed concurrently.
+                    style.setData(layer);
+                }
+            });
+        });
         final ObservableList<Category> items = categoryTable.getItems();
         if (coverage == null) {
             items.clear();
diff --git 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CoverageExplorer.java
 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CoverageExplorer.java
index 71ac26f3b2..3379cc7228 100644
--- 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CoverageExplorer.java
+++ 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CoverageExplorer.java
@@ -33,6 +33,7 @@ import javafx.scene.layout.Region;
 import javafx.event.ActionEvent;
 import javafx.beans.property.ObjectProperty;
 import javafx.beans.property.SimpleObjectProperty;
+import org.apache.sis.util.logging.Logging;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.GridCoverageResource;
 import org.apache.sis.coverage.grid.GridCoverage;
@@ -44,6 +45,8 @@ import org.apache.sis.gui.internal.Resources;
 import org.apache.sis.gui.internal.ToolbarButton;
 import org.apache.sis.gui.internal.NonNullObjectProperty;
 import org.apache.sis.gui.internal.PrivateAccess;
+import org.apache.sis.gui.internal.BackgroundThreads;
+import static org.apache.sis.gui.internal.LogHandler.LOGGER;
 import org.apache.sis.gui.referencing.RecentReferenceSystems;
 import org.apache.sis.gui.dataset.WindowHandler;
 import org.apache.sis.gui.map.StatusBar;
@@ -608,16 +611,17 @@ public class CoverageExplorer extends Widget {
      */
     final void notifyDataChanged(final GridCoverageResource resource, final 
GridCoverage coverage) {
         if (coverage != null) {
-            String name;
-            try {
-                name = DataStoreOpener.findLabel(resource, getLocale(), true);
-            } catch (DataStoreException e) {
-                name = e.getLocalizedMessage();
-                if (name == null) {
-                    name = e.getClass().getSimpleName();
+            BackgroundThreads.execute(() -> {
+                String name;
+                try {
+                    name = DataStoreOpener.findLabel(resource, getLocale(), 
true);
+                } catch (DataStoreException | RuntimeException e) {
+                    // Declare `setResource` as the public method invoking 
(indirectly) this method.
+                    Logging.recoverableException(LOGGER, 
CoverageExplorer.class, "setResource", e);
+                    name = DataStoreOpener.fallbackLabel(resource, 
getLocale());
                 }
-            }
-            referenceSystems.setGridReferencing(true, Map.of(name, 
coverage.getGridGeometry()));
+                referenceSystems.setGridReferencing(true, Map.of(name, 
coverage.getGridGeometry()));
+            });
         }
         /*
          * Following calls will NOT forward the new values to the views 
because this `notifyDataChanged(…)`
diff --git 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/StyleController.java
 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/StyleController.java
new file mode 100644
index 0000000000..18548647a8
--- /dev/null
+++ 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/StyleController.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.gui.coverage;
+
+import javafx.scene.control.TreeItem;
+import javafx.collections.ObservableList;
+import org.apache.sis.gui.internal.Resources;
+import org.apache.sis.gui.map.style.MapItem;
+import org.apache.sis.gui.map.style.ItemController;
+import org.apache.sis.gui.map.style.MapLayer;
+import org.apache.sis.storage.GridCoverageResource;
+import org.apache.sis.storage.tiling.TiledGridCoverageResource;
+
+
+/**
+ * A node shown in a tree of map items for controlling the rendering of a 
single grid coverage.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ */
+final class StyleController extends ItemController {
+    /**
+     * Whether to show a visual indication of which tiles are read.
+     */
+    private final ItemController showTileReads;
+
+    /**
+     * Creates a controller for a map layer.
+     * The controller is initially selected.
+     *
+     * @param  view       where the coverage will be rendered.
+     * @param  resources  resources for localized <abbr>GUI</abbr> elements.
+     */
+    StyleController(final CoverageCanvas view, final Resources resources) {
+        setSelected(true);
+        setIndependent(true);
+        selectedProperty().addListener((p,o,n) -> view.setCoverageHidden(!n));
+        showTileReads = new ItemController(new 
MapItem(resources.getString(Resources.Keys.ShowTileReadEvents)));
+        showTileReads.selectedProperty().addListener((p,o,n) -> 
view.showTileReads(n));
+        showTileReads.setIndependent(true);
+        getChildren().add(showTileReads);
+    }
+
+    /**
+     * Sets the item to show.
+     *
+     * @param  item  the new item, or {@code null} if none.
+     */
+    final void setData(final MapLayer<GridCoverageResource> item) {
+        setValue(item);
+        final boolean isTiled = (item.resource instanceof 
TiledGridCoverageResource);
+        final ObservableList<TreeItem<MapItem>> children = getChildren();
+        final int last = children.size() - 1;
+        if (last >= 0 && children.get(last) == showTileReads) {
+            if (!isTiled) {
+                children.remove(last);
+            }
+        } else {
+            if (isTiled) {
+                children.add(showTileReads);
+            }
+        }
+    }
+}
diff --git 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/dataset/WindowHandler.java
 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/dataset/WindowHandler.java
index 9b2cb5a22e..c6226552bb 100644
--- 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/dataset/WindowHandler.java
+++ 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/dataset/WindowHandler.java
@@ -28,7 +28,6 @@ import javafx.beans.value.ChangeListener;
 import javafx.beans.property.StringProperty;
 import javafx.beans.property.SimpleStringProperty;
 import javafx.collections.ObservableList;
-import org.apache.sis.util.resources.Vocabulary;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.storage.Resource;
 import org.apache.sis.storage.DataStoreException;
@@ -52,7 +51,7 @@ import static org.apache.sis.gui.internal.LogHandler.LOGGER;
  * It may also be a tile in a mosaic of windows.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.4
+ * @version 1.7
  * @since   1.3
  */
 public abstract class WindowHandler {
@@ -104,16 +103,20 @@ public abstract class WindowHandler {
      * @return {@code this} for method call chaining.
      */
     final WindowHandler finish() {
-        String text;
-        if (manager.main == this) {
-            text = 
Resources.forLocale(manager.locale).getString(Resources.Keys.MainWindow);
-        } else try {
-            text = DataStoreOpener.findLabel(getResource(), manager.locale, 
true);
-        } catch (DataStoreException | RuntimeException e) {
-            text = 
Vocabulary.forLocale(manager.locale).getString(Vocabulary.Keys.NotKnown);
-            Logging.recoverableException(LOGGER, WindowHandler.class, 
"<init>", e);
-        }
-        title.set(text);
+        BackgroundThreads.execute(() -> {
+            String text;
+            final Locale locale = manager.locale;
+            if (manager.main == this) {
+                text = 
Resources.forLocale(locale).getString(Resources.Keys.MainWindow);
+            } else try {
+                text = DataStoreOpener.findLabel(getResource(), locale, true);
+            } catch (DataStoreException | RuntimeException e) {
+                text = DataStoreOpener.fallbackLabel(getResource(), locale);
+                Logging.recoverableException(LOGGER, WindowHandler.class, 
"<init>", e);
+            }
+            final String label = text;      // Because lambda functions want 
final variable.
+            Platform.runLater(() -> title.set(label));
+        });
         manager.modifiableWindowList.add(this);
         return this;
     }
diff --git 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/DataStoreOpener.java
 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/DataStoreOpener.java
index 8e2a3317ce..8ac65413e9 100644
--- 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/DataStoreOpener.java
+++ 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/DataStoreOpener.java
@@ -43,13 +43,13 @@ import org.apache.sis.storage.StorageConnector;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.DataStores;
 import org.apache.sis.storage.DataStore;
+import org.apache.sis.storage.folder.ConcurrentCloser;
 import org.apache.sis.util.collection.Cache;
 import org.apache.sis.util.resources.Vocabulary;
 import org.apache.sis.util.internal.shared.Strings;
 import org.apache.sis.io.stream.IOUtilities;
 import org.apache.sis.io.stream.ChannelFactory;
 import org.apache.sis.io.stream.InternalOptionKey;
-import org.apache.sis.storage.folder.ConcurrentCloser;
 import org.apache.sis.gui.DataViewer;
 
 
@@ -212,7 +212,7 @@ public final class DataStoreOpener extends Task<DataStore> {
     }
 
     /**
-     * Set the provider of wrappers around channels used for reading data.
+     * Sets the provider of wrappers around channels used for reading data.
      * Those wrappers can be used for listening to file accesses.
      *
      * @param  wrapper  the wrapper, or {@code null} if none.
@@ -248,21 +248,20 @@ public final class DataStoreOpener extends 
Task<DataStore> {
         if (resource != null) {
             final Long logID = LogHandler.loadingStart(resource);
             try {
-                /*
-                 * The data store display name is typically the file name. We 
give precedence to that name
-                 * instead of the citation title because the citation may be 
the same for many files of
-                 * the same product, while the display name have better 
chances to be distinct for each file.
-                 */
-                if (resource instanceof DataStore) {
-                    final String name = Strings.trimOrNull(((DataStore) 
resource).getDisplayName());
-                    if (name != null) return name;
+                GenericName identifier = resource.getIdentifier().orElse(null);
+                if (identifier != null) {
+                    if (qualified) {
+                        String t = 
string(identifier.toFullyQualifiedName().toInternationalString(), locale);
+                        if (t != null) return t;    // Should never be null, 
but we are paranoiac.
+                    } else {
+                        identifier = identifier.tip();
+                    }
                 }
                 /*
                  * Search for a title in metadata first because it has better 
chances to be human-readable
                  * compared to the resource identifier. If the title is the 
same text as the identifier,
                  * then execute the code path for identifier (i.e. try to find 
a more informative text).
                  */
-                GenericName name = resource.getIdentifier().orElse(null);
                 Collection<? extends Identification> identifications = null;
                 final Metadata metadata = resource.getMetadata();
                 if (metadata != null) {
@@ -272,7 +271,7 @@ public final class DataStoreOpener extends Task<DataStore> {
                             final Citation citation = 
identification.getCitation();
                             if (citation != null) {
                                 final String t = string(citation.getTitle(), 
locale);
-                                if (t != null && (name == null || 
!t.equals(name.tip().toString()))) {
+                                if (t != null && (identifier == null || 
!t.equals(identifier.tip().toString()))) {
                                     return t;
                                 }
                             }
@@ -284,17 +283,25 @@ public final class DataStoreOpener extends 
Task<DataStore> {
                  * We search for explicitly declared identifier first before 
to fallback on
                  * metadata identifier, because the latter is more subject to 
interpretation.
                  */
-                if (name != null) {
-                    name = qualified ? name.toFullyQualifiedName() : 
name.tip();
-                    final String t = string(name.toInternationalString(), 
locale);
+                if (identifier != null) {
+                    String t = string(identifier.toInternationalString(), 
locale);
                     if (t != null) return t;
                 }
                 if (identifications != null) {
                     for (final Identification identification : 
identifications) {
-                        final String t = 
Citations.getIdentifier(identification.getCitation());
+                        String t = 
Citations.getIdentifier(identification.getCitation());
                         if (t != null) return t;
                     }
                 }
+                /*
+                 * Check for data store display name in last resort, because 
it depends on the input object.
+                 * It may be a filename if the resource was opened from a 
`java.nio.Path`, but may also be a
+                 * class name if the resource was opened from a stream.
+                 */
+                if (resource instanceof DataStore) {
+                    String t = Strings.trimOrNull(((DataStore) 
resource).getDisplayName());
+                    if (t != null) return t;
+                }
             } finally {
                 LogHandler.loadingStop(logID);
             }
@@ -302,6 +309,23 @@ public final class DataStoreOpener extends Task<DataStore> 
{
         return Vocabulary.forLocale(locale).getString(Vocabulary.Keys.Unnamed);
     }
 
+    /**
+     * Returns the label to use as a fallback if {@link #findLabel(Resource, 
Locale, boolean)} threw an exception.
+     * The fallback may be the "Not known" text. Note that we do not use the 
"Unnamed" text because we don't know
+     * if the resource is really unnamed. This method should be quick enough 
for invocation from the JavaFX thread.
+     *
+     * @param  resource  the resource for which to get a label, or {@code 
null}.
+     * @param  locale    the locale to use for localizing international 
strings.
+     * @return a label to use as a fallback (never {@code null}).
+     */
+    public static String fallbackLabel(final Resource resource, final Locale 
locale) {
+        if (resource instanceof DataStore) {
+            final String text = Strings.trimOrNull(((DataStore) 
resource).getDisplayName());
+            if (text != null) return text;
+        }
+        return 
Vocabulary.forLocale(locale).getString(Vocabulary.Keys.NotKnown);
+    }
+
     /**
      * Returns the given international string as a non-empty localized string, 
or {@code null} if none.
      */
diff --git 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/style/ItemController.java
 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/style/ItemController.java
new file mode 100644
index 0000000000..86e14a75ff
--- /dev/null
+++ 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/style/ItemController.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.gui.map.style;
+
+import javafx.scene.control.CheckBoxTreeItem;
+
+
+/**
+ * Base class of controller for configuring a map item (data and style).
+ * An {@code ItemController} contains indirectly the following properties:
+ *
+ * <ul>
+ *   <li>A human-readable {@linkplain MapItem#title title} to show in the 
<abbr>GUI</abbr>.</li>
+ *   <li>A narrative {@linkplain MapItem#description description} providing 
more details.</li>
+ *   <li>Whether the map item {@linkplain #selectedProperty() should be shown} 
on the map.</li>
+ * </ul>
+ *
+ * @author  Johann Sorel (Geomatys)
+ * @author  Martin Desruisseaux (Geomatys)
+ */
+public class ItemController extends CheckBoxTreeItem<MapItem> {
+    /**
+     * Creates an initially empty controller.
+     */
+    public ItemController() {
+    }
+
+    /**
+     * Creates a controller for the given map item.
+     *
+     * @param  item  the map item, or {@code null} if none.
+     */
+    public ItemController(final MapItem item) {
+        super(item);
+    }
+}
diff --git 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/style/MapContextView.java
 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/style/MapContextView.java
new file mode 100644
index 0000000000..0c3d8d7cef
--- /dev/null
+++ 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/style/MapContextView.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.gui.map.style;
+
+import javafx.util.Callback;
+import javafx.util.StringConverter;
+import javafx.beans.value.ObservableValue;
+import javafx.geometry.Orientation;
+import javafx.scene.control.SplitPane;
+import javafx.scene.control.TreeView;
+import javafx.scene.control.TreeCell;
+import javafx.scene.control.TreeItem;
+import javafx.scene.control.CheckBoxTreeItem;
+import javafx.scene.control.cell.CheckBoxTreeCell;
+import javafx.scene.layout.Region;
+import org.apache.sis.gui.Widget;
+import org.apache.sis.gui.internal.Resources;
+
+
+/**
+ * Tree of portrayal objects such as map layers, together with controls for 
configuring their appearance.
+ * When an item in the tree is selected, controls for configuring that item 
are shown.
+ *
+ * @author  Johann Sorel (Geomatys)
+ * @author  Martin Desruisseaux (Geomatys)
+ */
+public class MapContextView extends Widget {
+    /**
+     * The method to invoke for creating tree cells for a map item.
+     */
+    private static final class CellFactory extends 
StringConverter<TreeItem<MapItem>>
+            implements Callback<TreeView<MapItem>, TreeCell<MapItem>>
+    {
+        /** The unique instance. */
+        static final CellFactory INSTANCE = new CellFactory();
+
+        /** The function to invoke for getting the property describing whether 
the item is selected. */
+        private final Callback<TreeItem<MapItem>, ObservableValue<Boolean>> 
selectedProperty;
+
+        /** Creates the unique instance. */
+        private CellFactory() {
+            selectedProperty = (item) -> item instanceof CheckBoxTreeItem<?> ? 
((CheckBoxTreeItem<?>)item).selectedProperty() : null;
+        }
+
+        /** Creates an initially empty tree cell for the given tree view. */
+        @Override public TreeCell<MapItem> call(final TreeView<MapItem> item) {
+            return new CheckBoxTreeCell<>(selectedProperty, this);
+        }
+
+        /** Returns the text to show in the tree node. */
+        @Override public String toString(final TreeItem<MapItem> item) {
+            if (item != null) {
+                final MapItem value = item.getValue();
+                if (value != null) return value.title;
+            }
+            return null;
+        }
+
+        /** Returns a new item with the given text. Defined as a matter of 
principle, but should not be invoked. */
+        @Override public TreeItem<MapItem> fromString(final String text) {
+            return new ItemController(new MapItem(text));
+        }
+    }
+
+    /**
+     * The map items to show in a tree.
+     */
+    private final TreeView<MapItem> items;
+
+    /**
+     * The tree of map items in the top part,
+     * together with configuration options for the selected item in the bottom 
part.
+     */
+    private final SplitPane itemsAndConfiguration;
+
+    /**
+     * Creates an initially empty tree.
+     *
+     * @param  resources  the resource to use for localized labels.
+     *         Should not be in public API, appears in argument for now only 
for convenience.
+     */
+    public MapContextView(final Resources resources) {
+        items = new TreeView<>();
+        items.setCellFactory(CellFactory.INSTANCE);
+        itemsAndConfiguration = new SplitPane(items);
+        itemsAndConfiguration.setOrientation(Orientation.VERTICAL);
+    }
+
+    /**
+     * Returns the encapsulated JavaFX component to add in a scene graph for 
making the tree visible.
+     * The {@code Region} subclass is implementation dependent and may change 
in any future SIS version.
+     *
+     * @return the JavaFX component to insert in a scene graph.
+     */
+    @Override
+    public Region getView() {
+        return itemsAndConfiguration;
+    }
+
+    /**
+     * Sets the root item.
+     *
+     * @param  root  the new root item, or {@code null} if none.
+     */
+    public void setRootItem(final ItemController root) {
+        items.setRoot(root);
+    }
+}
diff --git 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/package-info.java
 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/style/MapItem.java
similarity index 52%
copy from 
optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/package-info.java
copy to 
optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/style/MapItem.java
index e6ff89407e..c4f207de58 100644
--- 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/package-info.java
+++ 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/style/MapItem.java
@@ -14,13 +14,28 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package org.apache.sis.gui.map.style;
+
 
 /**
- * Widgets about coordinate reference systems.
+ * Placeholder for {@code org.apache.sis.map.MapItem}.
+ * We use this temporary class because {@code org.apache.sis.map.MapItem} is 
in incubator.
  *
- * @author  Johann Sorel (Geomatys)
- * @author  Martin Desruisseaux (Geomatys)
- * @version 1.6
- * @since   1.1
+ * @todo Replace by {@link org.apache.sis.map.MapItem}.
  */
-package org.apache.sis.gui.referencing;
+public class MapItem {
+    /**
+     * A human-readable short description for labeling the map item in a tree 
view.
+     * This title should be user friendly. It shall not be used as an 
identifier.
+     */
+    public final String title;
+
+    /**
+     * Creates a new map item with the given text.
+     *
+     * @param  title  a human-readable short description for labeling the map 
item in a tree view.
+     */
+    public MapItem(final String title) {
+        this.title = title;
+    }
+}
diff --git 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/package-info.java
 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/style/MapLayer.java
similarity index 53%
copy from 
optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/package-info.java
copy to 
optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/style/MapLayer.java
index e6ff89407e..055981d4cc 100644
--- 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/package-info.java
+++ 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/style/MapLayer.java
@@ -14,13 +14,30 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package org.apache.sis.gui.map.style;
+
+import org.apache.sis.storage.Resource;
+
 
 /**
- * Widgets about coordinate reference systems.
+ * Placeholder for {@code org.apache.sis.map.MapLayer}.
+ * We use this temporary class because {@code org.apache.sis.map.MapLayer} is 
in incubator.
  *
- * @author  Johann Sorel (Geomatys)
- * @author  Martin Desruisseaux (Geomatys)
- * @version 1.6
- * @since   1.1
+ * @todo Replace by {@link org.apache.sis.map.MapLayer}.
  */
-package org.apache.sis.gui.referencing;
+public final class MapLayer<R extends Resource> extends MapItem {
+    /**
+     * The resource managed by this map layer.
+     */
+    public final R resource;
+
+    /**
+     * Creates a new map item with the given resource.
+     *
+     * @param  resource  the resource managed by this map layer.
+     */
+    public MapLayer(final R resource, final String title) {
+        super(title);
+        this.resource = resource;
+    }
+}
diff --git 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/package-info.java
 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/style/package-info.java
similarity index 83%
copy from 
optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/package-info.java
copy to 
optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/style/package-info.java
index e6ff89407e..7d10bdd35a 100644
--- 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/package-info.java
+++ 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/style/package-info.java
@@ -16,11 +16,13 @@
  */
 
 /**
- * Widgets about coordinate reference systems.
+ * Controls for styling a map.
+ *
+ * <STRONG>Do not use!</STRONG>
+ *
+ * This is an experimental package not yet ready for public usage.
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.6
- * @since   1.1
  */
-package org.apache.sis.gui.referencing;
+package org.apache.sis.gui.map.style;
diff --git 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/RecentReferenceSystems.java
 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/RecentReferenceSystems.java
index c80476dc0e..26ff43c839 100644
--- 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/RecentReferenceSystems.java
+++ 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/RecentReferenceSystems.java
@@ -21,6 +21,8 @@ import java.util.List;
 import java.util.ArrayList;
 import java.util.Locale;
 import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
+import javafx.application.Platform;
 import javafx.beans.property.ObjectProperty;
 import javafx.beans.property.SimpleObjectProperty;
 import javafx.beans.value.ChangeListener;
@@ -81,7 +83,7 @@ import static org.apache.sis.gui.internal.LogHandler.LOGGER;
  * </ul>
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.6
+ * @version 1.7
  * @since   1.1
  */
 public class RecentReferenceSystems {
@@ -202,8 +204,8 @@ public class RecentReferenceSystems {
      * then is filtered by {@link #filterReferenceSystems(ImmutableEnvelope, 
ComparisonMode)} for resolving authority
      * codes and removing duplicated elements.</p>
      *
-     * <p>All accesses to this field and to {@link #isModified} field shall be 
done in a block synchronized
-     * on {@code systemsOrCodes}.</p>
+     * <p>All accesses to this field and all accesses to the {@link 
#isModified}
+     * field shall be done in a block synchronized on {@code 
systemsOrCodes}.</p>
      */
     private final List<Object> systemsOrCodes;
 
@@ -274,6 +276,12 @@ public class RecentReferenceSystems {
      */
     private boolean isAdjusting;
 
+    /**
+     * For detecting when the {@code RecentReferenceSystems} state has been 
modified concurrently.
+     * Used only in contexts where the state is computed by a background 
thread.
+     */
+    private final AtomicInteger modificationCount;
+
     /**
      * Creates a builder which will use a default authority factory.
      * The factory will be capable to handle at least some EPSG codes.
@@ -294,11 +302,12 @@ public class RecentReferenceSystems {
     public RecentReferenceSystems(final CRSAuthorityFactory factory, final 
Locale locale) {
         this.factory         = factory;
         this.locale          = locale;
+        controlValues        = new ArrayList<>();
         systemsOrCodes       = new ArrayList<>();
         cellIndiceSystems    = new ArrayList<>();
+        modificationCount    = new AtomicInteger();
         areaOfInterest       = new SimpleObjectProperty<>(this, 
"areaOfInterest");
         duplicationCriterion = new NonNullObjectProperty<>(this, 
"duplicationCriterion", ComparisonMode.ALLOW_VARIANT);
-        controlValues        = new ArrayList<>();
         duplicationCriterion.addListener((e) -> listModified());
         areaOfInterest.addListener((e,o,n) -> {
             geographicAOI = Utils.toGeographic(RecentReferenceSystems.class, 
"areaOfInterest", n);
@@ -317,6 +326,15 @@ public class RecentReferenceSystems {
      *   <li>Sets the content of "Referencing by cell indices" sub-menu.</li>
      * </ul>
      *
+     * Above information are derived from the values of the {@code geometries} 
map.
+     * For each entry, the map key should be the {@link 
org.apache.sis.storage.Resource#getIdentifier() identifier} of
+     * the resource that provided the {@link GridGeometry} value, or other 
text allowing the user to identify the resource.
+     * Those keys are used for naming the <abbr>CRS</abbr>s of cell 
coordinates, which are different for each grid coverage.
+     *
+     * <p>This method can be invoked from any thread. The reference systems 
are collected in the current thread,
+     * then the state of this {@code RecentReferenceSystems} is updated in the 
JavaFX thread after all reference
+     * systems are ready.</p>
+     *
      * @param  replaceByAuthoritativeDefinition  whether the reference systems 
should be replaced by authoritative definition.
      * @param  geometries  grid coverage names together with their grid 
geometry. May be empty.
      *
@@ -334,8 +352,8 @@ public class RecentReferenceSystems {
         int countCIR = 0;
         final Envelope[] envelopes = new Envelope[geometries.size()];
         final DerivedCRS[] derived = new DerivedCRS[geometries.size()];
-        final CoordinateReferenceSystem[] alt = new 
CoordinateReferenceSystem[Math.max(derived.length - 1, 0)];
-        CoordinateReferenceSystem preferred = null;
+        final var alt = new CoordinateReferenceSystem[Math.max(derived.length 
- 1, 0)];
+        CoordinateReferenceSystem firstCRS = null;
         for (final Map.Entry<String,GridGeometry> entry : 
geometries.entrySet()) {
             final GridGeometry gg = entry.getValue();
             if (gg.isDefined(GridGeometry.ENVELOPE)) {
@@ -343,8 +361,8 @@ public class RecentReferenceSystems {
             }
             if (gg.isDefined(GridGeometry.CRS)) {
                 final CoordinateReferenceSystem crs = 
gg.getCoordinateReferenceSystem();
-                if (preferred == null) {
-                    preferred = crs;
+                if (firstCRS == null) {
+                    firstCRS = crs;
                 } else {
                     alt[countCRS++] = crs;
                 }
@@ -353,31 +371,40 @@ public class RecentReferenceSystems {
                 }
             }
         }
-        Envelope aoi = null;
+        Envelope union;
         try {
-            aoi = Envelopes.union(envelopes);       // No need to trim null 
elements.
+            union = Envelopes.union(envelopes);       // No need to trim null 
elements.
         } catch (TransformException e) {
             errorOccurred("setGridReferencing", e);
+            union = null;
         }
         /*
          * Modify now the state of `this` object but with `listModified()` 
made almost no-op.
          * The intent is to have only one effective call to `listModified()` 
at the end,
          * in order to have only one call to `filterReferenceSystems(…)`.
          */
-        final ObservableList<ReferenceSystem> savedReferenceSystemList = 
referenceSystems;
-        try {
-            referenceSystems = null;
-            if (preferred != null) {
-                setPreferred(replaceByAuthoritativeDefinition, preferred);
-                addAlternatives(replaceByAuthoritativeDefinition, alt);        
 // No need to trim null elements.
-                cellIndiceSystems.clear();
-                
cellIndiceSystems.addAll(Containers.viewAsUnmodifiableList(derived, 0, 
countCIR));
+        final Envelope aoi = union;     // Because lambda functions want a 
final variable.
+        final CoordinateReferenceSystem preferred = firstCRS;
+        final List<DerivedCRS> cellCRS = 
Containers.viewAsUnmodifiableList(derived, 0, countCIR);
+        final int stamp = modificationCount.incrementAndGet();
+        Platform.runLater(() -> {
+            if (modificationCount.get() == stamp) {
+                final ObservableList<ReferenceSystem> savedReferenceSystemList 
= referenceSystems;
+                try {
+                    referenceSystems = null;
+                    if (preferred != null) {
+                        setPreferred(replaceByAuthoritativeDefinition, 
preferred);
+                        addAlternatives(replaceByAuthoritativeDefinition, 
alt);         // No need to trim null elements.
+                        cellIndiceSystems.clear();
+                        cellIndiceSystems.addAll(cellCRS);
+                    }
+                    areaOfInterest.set(aoi);
+                } finally {
+                    referenceSystems = savedReferenceSystemList;
+                }
+                listModified();
             }
-            areaOfInterest.set(aoi);
-        } finally {
-            referenceSystems = savedReferenceSystemList;
-        }
-        listModified();
+        });
     }
 
     /**
diff --git 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/package-info.java
 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/package-info.java
index e6ff89407e..a7a22fcb04 100644
--- 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/package-info.java
+++ 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/package-info.java
@@ -20,7 +20,7 @@
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.6
+ * @version 1.7
  * @since   1.1
  */
 package org.apache.sis.gui.referencing;

Reply via email to