sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] branch geoapi-4.0 updated: When a resource is selected in the TreeView, update the MetadataOverview accordingly.
Date Fri, 01 Nov 2019 16:44:26 GMT
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


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new f1f225f  When a resource is selected in the TreeView, update the MetadataOverview
accordingly.
f1f225f is described below

commit f1f225f92b88773ab018a5604360790429975d4d
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Fri Nov 1 15:24:03 2019 +0100

    When a resource is selected in the TreeView, update the MetadataOverview accordingly.
---
 .../main/java/org/apache/sis/gui/DataViewer.java   |   2 +-
 .../apache/sis/gui/dataset/MetadataOverview.java   | 576 ++++++++++++---------
 .../apache/sis/gui/dataset/ResourceExplorer.java   |  32 +-
 .../org/apache/sis/gui/dataset/ResourceTree.java   |   5 +-
 4 files changed, 372 insertions(+), 243 deletions(-)

diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/DataViewer.java b/application/sis-javafx/src/main/java/org/apache/sis/gui/DataViewer.java
index 1f27107..f81021d 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/DataViewer.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/DataViewer.java
@@ -133,7 +133,7 @@ public class DataViewer extends Application {
         content = new ResourceExplorer();
         final BorderPane pane = new BorderPane();
         pane.setTop(menus);
-        pane.setCenter(content.getPane());
+        pane.setCenter(content.getView());
         Scene scene = new Scene(pane);
         window.setTitle("Apache Spatial Information System");
         window.setScene(scene);
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/MetadataOverview.java
b/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/MetadataOverview.java
index c6e4530..15c0a9d 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/MetadataOverview.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/MetadataOverview.java
@@ -21,34 +21,31 @@ import java.io.InputStream;
 import java.text.DateFormat;
 import java.text.NumberFormat;
 import java.util.Collection;
-import java.util.HashMap;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.Locale;
-import java.util.Map;
-import javafx.beans.value.ObservableValue;
-import javafx.collections.FXCollections;
+import javafx.application.Platform;
 import javafx.collections.ObservableList;
+import javafx.concurrent.Task;
 import javafx.event.ActionEvent;
-import javafx.event.Event;
+import javafx.event.EventHandler;
 import javafx.geometry.Insets;
 import javafx.scene.Node;
 import javafx.scene.canvas.Canvas;
 import javafx.scene.control.ComboBox;
 import javafx.scene.control.Label;
 import javafx.scene.control.TitledPane;
-import javafx.scene.control.Toggle;
-import javafx.scene.control.ToggleButton;
-import javafx.scene.control.ToggleGroup;
 import javafx.scene.image.Image;
 import javafx.scene.layout.GridPane;
-import javafx.scene.layout.HBox;
-import javafx.scene.layout.Priority;
-import javafx.scene.layout.StackPane;
+import javafx.scene.layout.Region;
 import javafx.scene.layout.VBox;
 import javafx.scene.paint.Color;
 import org.opengis.metadata.Metadata;
+import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.citation.CitationDate;
 import org.opengis.metadata.citation.Party;
+import org.opengis.metadata.citation.Individual;
+import org.opengis.metadata.citation.Organisation;
 import org.opengis.metadata.citation.Responsibility;
 import org.opengis.metadata.extent.Extent;
 import org.opengis.metadata.extent.GeographicBoundingBox;
@@ -60,109 +57,250 @@ import org.opengis.metadata.identification.TopicCategory;
 import org.opengis.metadata.spatial.Dimension;
 import org.opengis.metadata.spatial.SpatialRepresentation;
 import org.opengis.metadata.spatial.SpatialRepresentationType;
+import org.opengis.metadata.spatial.GridSpatialRepresentation;
 import org.opengis.referencing.ReferenceSystem;
 import org.opengis.util.InternationalString;
-import org.apache.sis.metadata.iso.DefaultMetadata;
-import org.apache.sis.metadata.iso.citation.DefaultIndividual;
-import org.apache.sis.metadata.iso.citation.DefaultOrganisation;
-import org.apache.sis.metadata.iso.spatial.DefaultGridSpatialRepresentation;
+import org.apache.sis.metadata.iso.citation.Citations;
+import org.apache.sis.internal.gui.BackgroundThreads;
+import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.Resource;
+import org.apache.sis.util.resources.Vocabulary;
 import org.apache.sis.util.iso.Types;
 
 
 /**
- * Metadata Viewer.
+ * A panel showing a summary of metadata.
  *
  * @author  Smaniotto Enzo
  * @version 1.1
  * @since   1.1
  * @module
  */
-class MetadataOverview extends StackPane {
-
+final class MetadataOverview {
+    /**
+     * Titles panes for different metadata sections (identification info, spatial information,
<i>etc</i>).
+     * This is similar to {@link javafx.scene.control.Accordion} except that we allow an
arbitrary amount
+     * of titled panes to be opened in same time.
+     */
+    private final VBox panes;
+
+    /**
+     * The locale to use for international strings.
+     */
+    private final Locale textLocale;
+
+    /**
+     * The locale to use for date/number formatters.
+     */
+    private final Locale formatLocale;
+
+    /**
+     * The metadata to show, or {@code null} if none.
+     * This is set by {@link #setMetadata(Metadata)}.
+     */
     private Metadata metadata;
-    private final Locale locale = Locale.getDefault();
 
-    public MetadataOverview() {
+    /**
+     * If the metadata can not be obtained, the reason.
+     */
+    private Throwable failure;
+
+    /**
+     * Incremented every time that a new metadata needs to be shown.
+     * This is used in case two calls to {@link #setMetadata(Resource)}
+     * are run concurrently and do not finish in the order they were started.
+     */
+    private int selectionCounter;
+
+    /**
+     * Creates an initially empty metadata overview.
+     */
+    MetadataOverview(final Locale locale) {
+        textLocale   = locale;
+        formatLocale = Locale.getDefault(Locale.Category.FORMAT);
+        panes        = new VBox();
     }
 
-    public void setMetadata(final DefaultMetadata md) {
-        this.metadata = md;
-        VBox root = new VBox();
-        root.setStyle("-fx-background-color: linear-gradient(to bottom right, #aeb7c4, #fafafa);");
-
-        // Creation of the differents views.
-        VBox summaryView = createSummaryView();
-        MetadataNode advancedView = new MetadataNode(md.asTreeTable());
-        advancedView.setMaxHeight(Double.MAX_VALUE);
-        VBox.setVgrow(advancedView, Priority.ALWAYS);
-
-        // Create and configure view selection buttons.
-        ToggleGroup buttonGroup = new ToggleGroup();
-        ToggleButton tb1 = new ToggleButton("Summary");
-        ToggleButton tb2 = new ToggleButton("Advanced");
-        tb1.setStyle("-fx-text-fill: white; -fx-font-family: Arial Narrow;-fx-font-weight:
bold; -fx-background-color: linear-gradient(#61a2b1, #2A5058); -fx-effect: dropshadow( three-pass-box
, rgba(0,0,0,0.6) , 5, 0.0 , 0 , 1 ); -fx-padding: 0.8em;");
-        tb2.setStyle("-fx-text-fill: white; -fx-font-family: Arial Narrow;-fx-font-weight:
bold; -fx-background-color: linear-gradient(#61a2b1, #2A5058); -fx-effect: dropshadow( three-pass-box
, rgba(0,0,0,0.6) , 5, 0.0 , 0 , 1 ); -fx-padding: 0.8em;");
-
-        tb1.setToggleGroup(buttonGroup);
-        tb1.setSelected(true);
-        tb1.setDisable(true);
-        tb2.setToggleGroup(buttonGroup);
-        buttonGroup.selectToggle(tb1);
-        buttonGroup.selectedToggleProperty().addListener((ObservableValue<? extends Toggle>
observable, Toggle oldValue, Toggle newValue) -> {
-            if (tb2.isSelected()) {
-                tb2.setDisable(true);
-                root.getChildren().remove(summaryView);
-                root.getChildren().add(advancedView);
-                tb1.setDisable(false);
-            } else {
-                tb1.setDisable(true);
-                root.getChildren().add(summaryView);
-                root.getChildren().remove(advancedView);
-                tb2.setDisable(false);
-            }
-        });
+    /**
+     * Returns the region containing the visual components managed by this {@code MetadataOverview}.
+     * The subclass is implementation dependent and may change in any future version.
+     *
+     * @return the region to show.
+     */
+    public final Region getView() {
+        return panes;
+    }
 
-        HBox toggleGroupLayout = new HBox();
-        toggleGroupLayout.getChildren().addAll(tb1, tb2);
-        toggleGroupLayout.setPadding(new Insets(0, 0, 10, 0));
+    /**
+     * Fetches the metadata in a background thread and delegates to {@link #setMetadata(Metadata)}
when ready.
+     *
+     * @param  resource  the resource for which to show metadata, or {@code null}.
+     */
+    public void setMetadata(final Resource resource) {
+        assert Platform.isFxApplicationThread();
+        if (resource == null) {
+            setMetadata((Metadata) null);
+        } else {
+            final int sequence = ++selectionCounter;
+            final class Getter extends Task<Metadata> {
+                /** Invoked in a background thread for fetching metadata. */
+                @Override protected Metadata call() throws DataStoreException {
+                    return resource.getMetadata();
+                }
 
-        root.getChildren().add(toggleGroupLayout);
-        root.getChildren().add(summaryView);
+                /** Shows the result, unless another {@link #setMetadata(Resource)} has been
invoked. */
+                @Override protected void succeeded() {
+                    if (sequence == selectionCounter) {
+                        setMetadata(getValue());
+                    }
+                }
 
-        this.getChildren().setAll(root);
+                /** Invoked when an error occurred while fetching metadata. à*/
+                @Override protected void failed() {
+                    setMetadata((Metadata) null);
+                    failure = getException();
+                }
+            }
+            BackgroundThreads.execute(new Getter());
+        }
     }
 
-    private VBox createSummaryView() {
-        VBox vb = new VBox();
-        TitledPane idPane = new TitledPane("Identification info", createIdGridPane());
-        GridPane createSpatialGridPane = createSpatialGridPane();
-        vb.getChildren().add(idPane);
-        if (!createSpatialGridPane.getChildren().isEmpty()) {
-            TitledPane spatialPane = new TitledPane("Spatial representation", createSpatialGridPane);
-            vb.getChildren().add(spatialPane);
+    /**
+     * Sets the content of this pane to the given metadata.
+     *
+     * @param  md  the metadata to show, or {@code null}.
+     */
+    public void setMetadata(final Metadata md) {
+        assert Platform.isFxApplicationThread();
+        metadata = md;
+        failure  = null;
+        final ObservableList<Node> children = panes.getChildren();
+        children.clear();
+        if (md != null) {
+            addIfNonEmpty(children, "Identification info",    createIdGridPane());
+            addIfNonEmpty(children, "Spatial representation", createSpatialGridPane());
         }
-        return vb;
     }
 
-    private GridPane createIdGridPane() {
-        GridPane gp = new GridPane();
-        gp.setHgap(10.00);
-        int j = 0, k = 1;
+    /**
+     * Adds the given pane to the list of children if the pane is non-null and non-empty.
+     * If added, a {@link TitledPane} is created with the given title.
+     */
+    private static void addIfNonEmpty(final ObservableList<Node> children, final String
title, final GridPane pane) {
+        if (pane != null && !pane.getChildren().isEmpty()) {
+            children.add(new TitledPane(title, pane));
+        }
+    }
 
-        HashMap<String, Identification> m = new HashMap<>();
-        ComboBox<String> comboBox = createComboBox(m);
-        comboBox.setStyle("-fx-font-weight: bold; -fx-font-size: 2em;");
-        if (!comboBox.isVisible()) {
-            Label la = new Label(comboBox.getValue());
-            la.setStyle("-fx-font-weight: bold; -fx-font-size: 2em;");
-            gp.add(la, j, k++, 2, 1);
-        } else {
-            gp.add(comboBox, j, k++, 2, 1);
+
+
+
+    /**
+     * The pane where to show the values of {@link Identification} objects.
+     * The same pane can be used for an arbitrary amount of identifications.
+     * Each instance is identified by its title.
+     */
+    private final class IdentificationInfo extends GridPane implements EventHandler<ActionEvent>
{
+        /**
+         * The citation titles, one per {@link Identification} instance to show.
+         * This combo box usually has only one element.
+         */
+        private final ComboBox<String> choices;
+
+        /**
+         * Identification of resources. Shall have the same number of elements than {@link
#choices}.
+         */
+        private Identification[] identifications;
+
+        /**
+         * Creates an initially empty view for identification information.
+         */
+        IdentificationInfo() {
+            setPadding(new Insets(10));
+            setVgap(10);
+            setHgap(10);
+            choices = new ComboBox<>();
+            choices.setOnAction(this);
+            add(new Label("Title"), 0, 0); add(choices, 1, 0);
+        }
+
+        /**
+         * Sets the identification information to show.
+         * The given collection usually contains only one element.
+         *
+         * @param  info  identification information, or {@code null} if none.
+         */
+        void setInfo(Collection<? extends Identification> info) {
+            if (info == null) {
+                info = Collections.emptyList();
+            }
+            identifications = info.toArray(new Identification[info.size()]);
+            /*
+             * Setup the combo box with the title of all identification.
+             * If no title is found, identifiers are used as fallback.
+             */
+            int firstWithTitle = -1;
+            final String[] titles = new String[identifications.length];
+            for (int i=0; i<titles.length; i++) {
+                String title = null;
+                final Identification id = identifications[i];
+                if (id != null) {
+                    final Citation citation = id.getCitation();
+                    if (citation != null) {
+                        title = string(citation.getTitle());
+                        if (title == null) {
+                            title = Citations.getIdentifier(citation);
+                        }
+                    }
+                }
+                if (title == null) {
+                    title = Vocabulary.getResources(textLocale).getString(Vocabulary.Keys.Untitled);
+                } else if (firstWithTitle < 0) {
+                    firstWithTitle = i;
+                }
+                titles[i] = title;
+            }
+            /*
+             * At this point we prepared all titles. If the titles were missing in all objects,
+             * take the first "untitled" element as the initial selection.
+             */
+            choices.getItems().setAll(titles);
+            if (titles.length != 0) {
+                choices.getSelectionModel().clearAndSelect​(Math.max(firstWithTitle, 0));
+            }
+            handle(null);               // For forcing a refrech of pane content.
         }
 
+        /**
+         * Invoked when the user selected a new title.
+         *
+         * @param  event  ignored, can be null.
+         */
+        @Override
+        public void handle(final ActionEvent event) {
+            Identification id = null;
+            if (identifications != null) {
+                final int selected = choices.getSelectionModel().getSelectedIndex();
+                if (selected >= 0 && selected < identifications.length) {
+                    id = identifications[selected];
+                }
+            }
+            onIdSelected(this, id);
+        }
+    }
+
+    /**
+     * The pane when to show the values of {@link Identification} objects.
+     * The same pane can be used for an arbitrary amount of identifications.
+     * Each instance is identified by its title.
+     */
+    private GridPane createIdGridPane() {
+        final IdentificationInfo info = new IdentificationInfo();
+        info.setInfo(metadata.getIdentificationInfo());
+
         // Show author information.
-        Collection<? extends Responsibility> contacts = this.metadata.getContacts();
-        if (!contacts.isEmpty()) {
+        Collection<? extends Responsibility> contacts = metadata.getContacts();
+        if (false && !contacts.isEmpty()) {     // TODO
             Responsibility contact = contacts.iterator().next();
             Collection<? extends Party> parties = contact.getParties();
             if (!parties.isEmpty()) {
@@ -171,145 +309,127 @@ class MetadataOverview extends StackPane {
                     Label partyType = new Label("Party");
                     Label partyValue = new Label(party.getName().toString());
                     partyValue.setWrapText(true);
-                    if (party instanceof DefaultOrganisation) {
+                    if (party instanceof Organisation) {
                         partyType.setText("Organisation");
-                    } else if (party instanceof DefaultIndividual) {
+                    } else if (party instanceof Individual) {
                         partyType.setText("Author");
                     }
-                    gp.add(partyType, j, k);
-                    gp.add(partyValue, ++j, k++);
-                    j = 0;
+                    info.add(partyType,  0, 1);
+                    info.add(partyValue, 1, 2);
                 }
             }
         }
+        return info;
+    }
 
-        GridPane gpi = new GridPane();
-        gpi.setHgap(10.00);
-
-        comboBox.setOnAction(e -> {
-            gpi.getChildren().clear();
-            Identification id = m.get(comboBox.getValue());
-            if (comboBox.getValue().equals("No data to show")) {
-                return;
-            }
-
-            // Show the abstract or the credit, the topic category, the creation date, the
type of data, the representation system info and also the geographical area.
-            Object ab = id.getAbstract();
-            if (ab != null) {
-                InternationalString abs = (InternationalString) ab;
-                Label crd = new Label("Abstract");
-                Label crdValue = new Label(abs.toString(locale));
+    private void onIdSelected(final GridPane content, final Identification id) {
+        if (id == null) return;
+        final ObservableList<Node> children = content.getChildren();
+        children.subList(2, children.size()).clear();   // Do not remove the 2 first elements,
which are the combo box.
+
+        int row = 1;
+
+        // Show the abstract or the credit, the topic category, the creation date, the type
of data, the representation system info and also the geographical area.
+        Object ab = id.getAbstract();
+        if (ab != null) {
+            InternationalString abs = (InternationalString) ab;
+            Label crd = new Label("Abstract");
+            Label crdValue = new Label(string(abs));
+            crdValue.setWrapText(true);
+            content.add(crd,      0, row);
+            content.add(crdValue, 1, row++);
+        } else {
+            Collection<? extends InternationalString> credits = id.getCredits();
+            if (!credits.isEmpty()) {
+                InternationalString credit = credits.iterator().next();
+                Label crd = new Label("Credit");
+                Label crdValue = new Label(credit.toString());
                 crdValue.setWrapText(true);
-                gpi.add(crd, 0, 1);
-                gpi.add(crdValue, 1, 1);
-            } else {
-                Collection<? extends InternationalString> credits = id.getCredits();
-                if (!credits.isEmpty()) {
-                    InternationalString credit = credits.iterator().next();
-                    Label crd = new Label("Credit");
-                    Label crdValue = new Label(credit.toString());
-                    crdValue.setWrapText(true);
-                    gpi.add(crd, 0, 1);
-                    gpi.add(crdValue, 1, 1);
-                }
+                content.add(crd,      0, row);
+                content.add(crdValue, 1, row++);
             }
+        }
 
-            Collection<TopicCategory> tcs = id.getTopicCategories();
-            if (!tcs.isEmpty()) {
-                TopicCategory tc = tcs.iterator().next();
-                Label topicC = new Label("Topic Category");
-                Label topicValue = new Label(tc.toString());
-                topicValue.setWrapText(true);
-                gpi.add(topicC, 0, 2);
-                gpi.add(topicValue, 1, 2);
-            }
+        Collection<TopicCategory> tcs = id.getTopicCategories();
+        if (!tcs.isEmpty()) {
+            TopicCategory tc = tcs.iterator().next();
+            Label topicC = new Label("Topic Category");
+            Label topicValue = new Label(tc.toString());
+            topicValue.setWrapText(true);
+            content.add(topicC,     0, row);
+            content.add(topicValue, 1, row++);
+        }
 
-            if (!id.getCitation().getDates().isEmpty()) {
-                CitationDate dateAndType = id.getCitation().getDates().iterator().next();
-                DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.MEDIUM,
locale);
-                String dateStr = dateFormat.format(dateAndType.getDate());
-                String s = dateAndType.getDateType().toString();
-                s = s.replace("DateType[", "");
-                s = s.replace("]", "");
-                Label dt = new Label("Date type: " + s.toLowerCase());
-                Label dtValue = new Label(dateStr);
-                dtValue.setWrapText(true);
-                gpi.add(dt, 0, 3);
-                gpi.add(dtValue, 1, 3);
-            }
+        if (!id.getCitation().getDates().isEmpty()) {
+            CitationDate dateAndType = id.getCitation().getDates().iterator().next();
+            DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.MEDIUM,
formatLocale);
+            String dateStr = dateFormat.format(dateAndType.getDate());
+            String s = dateAndType.getDateType().toString();
+            s = s.replace("DateType[", "");
+            s = s.replace("]", "");
+            Label dt = new Label("Date type: " + s.toLowerCase());
+            Label dtValue = new Label(dateStr);
+            dtValue.setWrapText(true);
+            content.add(dt,      0, row);
+            content.add(dtValue, 1, row++);
+        }
 
-            if (id instanceof DataIdentification) {
-                Label topicC = new Label("Object type");
-                Label topicValue = new Label("Data");
-                topicValue.setWrapText(true);
-                gpi.add(topicC, 0, 4);
-                gpi.add(topicValue, 1, 4);
-            } else {
-                Label topicC = new Label("Object type");
-                Label topicValue = new Label("Service");
-                topicValue.setWrapText(true);
-                gpi.add(topicC, 0, 4);
-                gpi.add(topicValue, 1, 4);
-            }
+        if (id instanceof DataIdentification) {
+            Label topicC = new Label("Object type");
+            Label topicValue = new Label("Data");
+            topicValue.setWrapText(true);
+            content.add(topicC,     0, row);
+            content.add(topicValue, 1, row++);
+        } else {
+            Label topicC = new Label("Object type");
+            Label topicValue = new Label("Service");
+            topicValue.setWrapText(true);
+            content.add(topicC,     0, row);
+            content.add(topicValue, 1, row++);
+        }
 
-            Collection<SpatialRepresentationType> spatialRepresentationTypes = id.getSpatialRepresentationTypes();
-            Iterator<SpatialRepresentationType> its = spatialRepresentationTypes.iterator();
-            String typeList = "Spatial representation type: ";
-            while (its.hasNext()) {
-                SpatialRepresentationType spatialRepresentationType = its.next();
-                typeList += spatialRepresentationType.toString().toLowerCase(locale).replace("spatialrepresentationtype[",
"").replace(']', '\0') + ", ";
-            }
-            if (!typeList.equals("Spatial representation type: ")) {
-                Label list = new Label(typeList.substring(0, typeList.length() - 2));
-                list.setWrapText(true);
-                gpi.add(list, 0, 5, 2, 1);
-            }
+        Collection<SpatialRepresentationType> spatialRepresentationTypes = id.getSpatialRepresentationTypes();
+        Iterator<SpatialRepresentationType> its = spatialRepresentationTypes.iterator();
+        String typeList = "Spatial representation type: ";
+        while (its.hasNext()) {
+            SpatialRepresentationType spatialRepresentationType = its.next();
+            typeList += spatialRepresentationType.toString().toLowerCase(textLocale).replace("spatialrepresentationtype[",
"").replace(']', '\0') + ", ";
+        }
+        if (!typeList.equals("Spatial representation type: ")) {
+            Label list = new Label(typeList.substring(0, typeList.length() - 2));
+            list.setWrapText(true);
+            content.add(list, 0, 5, 2, 1);
+        }
 
-            Collection<? extends Extent> exs = id.getExtents();
-            if (!exs.isEmpty()) {
-                Extent ex = exs.iterator().next();
-                Collection<? extends GeographicExtent> ges = ex.getGeographicElements();
-                Iterator<? extends GeographicExtent> it = ges.iterator();
-                while (it.hasNext()) {
-                    GeographicExtent ge = it.next();
-                    Label geoEx = new Label("Zone");
-                    Label geoExValue = new Label(ge.toString());
-                    geoExValue.setWrapText(true);
-                    if (ge instanceof GeographicBoundingBox) {
-                        geoEx.setText("");
-                        GeographicBoundingBox gbd = (GeographicBoundingBox) ge;
-                        geoExValue.setText("");
-                        Canvas c = createMap(gbd.getNorthBoundLatitude(), gbd.getEastBoundLongitude(),
gbd.getSouthBoundLatitude(), gbd.getWestBoundLongitude());
-                        if (c != null) {
-                            gpi.add(c, 0, 6, 2, 1);
-                        } else {
-                            geoEx.setText("Impossible to load the map.");
-                            gpi.add(geoEx, 0, 6);
-                            gpi.add(geoExValue, 1, 6);
-                        }
-                    } else if (ge instanceof GeographicDescription) {
-                        geoEx.setText("Geographic description");
-                        GeographicDescription gd = (GeographicDescription) ge;
-                        geoExValue.setText(gd.getGeographicIdentifier().getCode());
+        Collection<? extends Extent> exs = id.getExtents();
+        if (!exs.isEmpty()) {
+            Extent ex = exs.iterator().next();
+            Collection<? extends GeographicExtent> ges = ex.getGeographicElements();
+            Iterator<? extends GeographicExtent> it = ges.iterator();
+            while (it.hasNext()) {
+                GeographicExtent ge = it.next();
+                Label geoEx = new Label("Zone");
+                Label geoExValue = new Label(ge.toString());
+                geoExValue.setWrapText(true);
+                if (ge instanceof GeographicBoundingBox) {
+                    geoEx.setText("");
+                    GeographicBoundingBox gbd = (GeographicBoundingBox) ge;
+                    geoExValue.setText("");
+                    Canvas c = createMap(gbd.getNorthBoundLatitude(), gbd.getEastBoundLongitude(),
gbd.getSouthBoundLatitude(), gbd.getWestBoundLongitude());
+                    if (c != null) {
+                        content.add(c, 0, 6, 2, 1);
+                    } else {
+                        geoEx.setText("Impossible to load the map.");
+                        content.add(geoEx,      0, row);
+                        content.add(geoExValue, 1, row++);
                     }
+                } else if (ge instanceof GeographicDescription) {
+                    geoEx.setText("Geographic description");
+                    GeographicDescription gd = (GeographicDescription) ge;
+                    geoExValue.setText(gd.getGeographicIdentifier().getCode());
                 }
             }
-        });
-
-        Event.fireEvent(comboBox, new ActionEvent());
-        gp.add(gpi, j, k++, 2, 1);
-
-        int ind = 0;
-        for (Node n : gp.getChildren()) {
-            if (ind++ != 0) {
-                n.setStyle("-fx-padding: 0 83 10 0;");
-            } else {
-                n.setStyle("-fx-padding: 0 0 10 0; -fx-font-weight: bold; -fx-font-size:
2em;");
-            }
         }
-        gpi.getChildren().forEach(n -> n.setStyle("-fx-padding: 0 0 10 0;"));
-
-        return gp;
     }
 
     private Canvas createMap(double north, double east, double south, double west) {
@@ -371,11 +491,11 @@ class MetadataOverview extends StackPane {
         if (sris.isEmpty()) {
             return gp;
         }
-        NumberFormat numberFormat = NumberFormat.getIntegerInstance(locale);
+        NumberFormat numberFormat = NumberFormat.getIntegerInstance(formatLocale);
         for (SpatialRepresentation sri : sris) {
             String currentValue = "• ";
-            if (sri instanceof DefaultGridSpatialRepresentation) {
-                DefaultGridSpatialRepresentation sr = (DefaultGridSpatialRepresentation)
sri;
+            if (sri instanceof GridSpatialRepresentation) {
+                GridSpatialRepresentation sr = (GridSpatialRepresentation) sri;
 
                 Iterator<? extends Dimension> it = sr.getAxisDimensionProperties().iterator();
                 while (it.hasNext()) {
@@ -398,34 +518,16 @@ class MetadataOverview extends StackPane {
         return gp;
     }
 
-    private ComboBox<String> createComboBox(final Map<String, Identification>
m) {
-        ComboBox<String> cb = new ComboBox<>();
-        Collection<? extends Identification> ids = this.metadata.getIdentificationInfo();
-        ObservableList<String> options = FXCollections.observableArrayList();
-        int i = 1;
-        if (ids.size() > 1) {
-            for (Identification id : ids) {
-                String currentName;
-                if (id.getCitation() != null) {
-                    currentName = id.getCitation().getTitle().toString();
-                } else {
-                    currentName = Integer.toString(i);
-                }
-                options.add(currentName);
-                m.put(currentName, id);
+    /**
+     * Returns the given international string as a non-empty localized string, or {@code
null} if none.
+     */
+    private String string(final InternationalString i18n) {
+        if (i18n != null) {
+            String t = i18n.toString(textLocale);
+            if (t != null && !(t = t.trim()).isEmpty()) {
+                return t;
             }
-            cb.setItems(options);
-            cb.setValue(ids.iterator().next().getCitation().getTitle().toString());
-        } else if (ids.size() == 1) {
-            if (ids.iterator().next().getCitation() != null) {
-                m.put(ids.iterator().next().getCitation().getTitle().toString(), ids.iterator().next());
-                cb.setValue(ids.iterator().next().getCitation().getTitle().toString());
-                cb.setVisible(false);
-            }
-        } else {
-            cb.setValue("No data to show");
-            cb.setVisible(false);
         }
-        return cb;
+        return null;
     }
 }
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/ResourceExplorer.java
b/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/ResourceExplorer.java
index 0919317..57c97a4 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/ResourceExplorer.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/ResourceExplorer.java
@@ -17,8 +17,10 @@
 package org.apache.sis.gui.dataset;
 
 import java.util.Collection;
+import javafx.collections.ListChangeListener;
 import javafx.scene.layout.Region;
 import javafx.scene.control.SplitPane;
+import javafx.scene.control.TreeItem;
 import org.apache.sis.storage.Resource;
 
 
@@ -26,6 +28,7 @@ import org.apache.sis.storage.Resource;
  * A panel showing a {@linkplain ResourceTree tree of resources} together with their metadata.
  *
  * @author  Smaniotto Enzo
+ * @author  Martin Desruisseaux (Geomatys)
  * @version 1.1
  * @since   1.1
  * @module
@@ -52,24 +55,28 @@ public class ResourceExplorer {
      */
     public ResourceExplorer() {
         resources = new ResourceTree();
-        metadata  = new MetadataOverview();
+        metadata  = new MetadataOverview(resources.getLocale());
         pane      = new SplitPane();
-        pane.getItems().setAll(resources, metadata);
+        pane.getItems().setAll(resources, metadata.getView());
+        resources.getSelectionModel().getSelectedItems().addListener(this::selectResource);
     }
 
     /**
      * Returns the region containing the resource tree, metadata panel or any other control
managed
-     * by this {@code ResourceExplorer}.
+     * by this {@code ResourceExplorer}. The subclass is implementation dependent and may
change in
+     * any future version.
      *
      * @return the region to show.
      */
-    public final Region getPane() {
+    public final Region getView() {
         return pane;
     }
 
     /**
      * Adds all the given resources to the resource tree. The given collection typically
contains
      * files to load, but may also contain {@link Resource} instances to add directly.
+     * This method forwards the files to {@link ResourceTree#loadResource(Object)},
+     * which will allocate a background thread for each resource to load.
      *
      * @param  files  the source of the resource to load. They are usually
      *                {@link java.io.File} or {@link java.nio.file.Path} instances.
@@ -81,4 +88,21 @@ public class ResourceExplorer {
             resources.loadResource(file);
         }
     }
+
+    /**
+     * Invoked when a new item is selected in the resource tree.
+     * This method takes the first non-null resource and forward to the children.
+     *
+     * @param  change  a change event with the new resource to show.
+     */
+    private void selectResource(final ListChangeListener.Change<? extends TreeItem<Resource>>
change) {
+        Resource resource = null;
+        for (final TreeItem<Resource> item : change.getList()) {
+            if (item != null) {
+                resource = item.getValue();
+                if (resource != null) break;
+            }
+        }
+        metadata.setMetadata(resource);
+    }
 }
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/ResourceTree.java
b/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/ResourceTree.java
index 2b62235..1e65ef1 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/ResourceTree.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/ResourceTree.java
@@ -26,6 +26,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Optional;
+import javafx.application.Platform;
 import javafx.concurrent.Task;
 import javafx.collections.ObservableList;
 import javafx.event.ActionEvent;
@@ -131,6 +132,7 @@ public class ResourceTree extends TreeView<Resource> {
      *         if it was already presents or if the given resource is {@code null}.
      */
     public boolean addResource(final Resource resource) {
+        assert Platform.isFxApplicationThread();
         if (resource == null) {
             return false;
         }
@@ -259,6 +261,7 @@ public class ResourceTree extends TreeView<Resource> {
      * @return whether the resource has been found in the roots.
      */
     private boolean findOrRemove(final Resource resource, final boolean remove) {
+        assert Platform.isFxApplicationThread();
         if (resource != null) {
             final TreeItem<Resource> item = getRoot();
             if (item != null) {
@@ -297,7 +300,7 @@ public class ResourceTree extends TreeView<Resource> {
     /**
      * Returns the locale to use for titles, messages, labels, etc.
      */
-    private Locale getLocale() {
+    final Locale getLocale() {
         return localized.getLocale();
     }
 


Mime
View raw message