You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2019/11/01 16:44:26 UTC
[sis] branch geoapi-4.0 updated: When a resource is selected in the
TreeView, update the MetadataOverview accordingly.
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 <ma...@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();
}