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 cad51c79cdcfe95f9be28d5b01a1dab96954a894 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Thu Dec 2 12:40:42 2021 +0100 Avoid creation of an unused `Accordion` control. Remember which title pane was expanded when switching view. --- .../apache/sis/gui/coverage/CoverageControls.java | 21 ++++---- .../apache/sis/gui/coverage/CoverageExplorer.java | 13 +++-- .../org/apache/sis/gui/coverage/GridControls.java | 15 +++--- .../apache/sis/gui/coverage/ViewAndControls.java | 33 +++++++++++- .../apache/sis/gui/dataset/ResourceExplorer.java | 59 +++++++++++++++------- 5 files changed, 95 insertions(+), 46 deletions(-) diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageControls.java b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageControls.java index 9b829ff..4286fca 100644 --- a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageControls.java +++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageControls.java @@ -17,8 +17,6 @@ package org.apache.sis.gui.coverage; import java.util.Locale; -import javafx.scene.control.Accordion; -import javafx.scene.control.Control; import javafx.scene.control.TitledPane; import javafx.scene.layout.BorderPane; import javafx.scene.layout.GridPane; @@ -70,7 +68,7 @@ final class CoverageControls extends ViewAndControls { /** * The controls for changing {@link #view}. */ - private final Accordion controls; + private final TitledPane[] controls; /** * The image together with the status bar. @@ -148,11 +146,12 @@ final class CoverageControls extends ViewAndControls { * Put all sections together and have the first one expanded by default. * The "Properties" section will be built by `PropertyPaneCreator` only if requested. */ - final TitledPane p1 = new TitledPane(vocabulary.getString(Vocabulary.Keys.Display), displayPane); - final TitledPane p2 = new TitledPane(vocabulary.getString(Vocabulary.Keys.Isolines), isolinesPane); - final TitledPane p3 = new TitledPane(vocabulary.getString(Vocabulary.Keys.Properties), null); - controls = new Accordion(p1, p2, p3); - controls.setExpandedPane(p1); + controls = new TitledPane[] { + new TitledPane(vocabulary.getString(Vocabulary.Keys.Display), displayPane), + new TitledPane(vocabulary.getString(Vocabulary.Keys.Isolines), isolinesPane), + new TitledPane(vocabulary.getString(Vocabulary.Keys.Properties), null) + }; + final TitledPane delayed = controls[2]; // Control to be built only if requested. /* * Set listeners: changes on `CoverageCanvas` properties are propagated to the corresponding * `CoverageExplorer` properties. This constructor does not install listeners in the opposite @@ -160,7 +159,7 @@ final class CoverageControls extends ViewAndControls { */ view.resourceProperty.addListener((p,o,n) -> onPropertySet(n, null)); view.coverageProperty.addListener((p,o,n) -> onPropertySet(null, n)); - p3.expandedProperty().addListener(new PropertyPaneCreator(view, p3)); + delayed.expandedProperty().addListener(new PropertyPaneCreator(view, delayed)); } /** @@ -213,9 +212,11 @@ final class CoverageControls extends ViewAndControls { /** * Returns the controls for controlling the view of tabular data. + * This method does not clone the returned array; do not modify! */ @Override - final Control controls() { + @SuppressWarnings("ReturnOfCollectionOrArrayField") + final TitledPane[] controlPanes() { return controls; } } diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageExplorer.java b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageExplorer.java index 6ddd16a..6a4ad70 100644 --- a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageExplorer.java +++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageExplorer.java @@ -25,6 +25,7 @@ import javafx.scene.control.SplitPane; import javafx.scene.control.Separator; import javafx.scene.control.ToggleGroup; import javafx.scene.control.Toggle; +import javafx.scene.control.TitledPane; import javafx.scene.layout.Region; import javafx.event.ActionEvent; import javafx.beans.property.ObjectProperty; @@ -259,8 +260,7 @@ public class CoverageExplorer extends Widget { case IMAGE: c = new CoverageControls(this); break; default: throw new AssertionError(type); } - SplitPane.setResizableWithParent(c.controls(), Boolean.FALSE); - SplitPane.setResizableWithParent(c.view(), Boolean.TRUE); + SplitPane.setResizableWithParent(c.view(), Boolean.TRUE); views.put(type, c); load = true; } @@ -342,17 +342,16 @@ public class CoverageExplorer extends Widget { } /** - * Returns the region containing only the controls, without data visualization component. - * The {@link Region} subclass returned by this method is implementation dependent and may - * change in any future version. + * Returns the panes containing the controls, without data visualization component. + * The {@link TitledPane} contents are implementation dependent and may change in any future version. * * @param type whether to obtain controls for {@link GridView} or {@link CoverageCanvas}. * @return the controls on specified data view. */ - public final Region getControls(final View type) { + public final TitledPane[] getControls(final View type) { assert Platform.isFxApplicationThread(); ArgumentChecks.ensureNonNull("type", type); - return getViewAndControls(type, false).controls(); + return getViewAndControls(type, false).controlPanes().clone(); } /** diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridControls.java b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridControls.java index 0c6c628..8300303 100644 --- a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridControls.java +++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridControls.java @@ -18,8 +18,6 @@ package org.apache.sis.gui.coverage; import javafx.beans.property.DoubleProperty; import javafx.collections.ObservableList; -import javafx.scene.control.Accordion; -import javafx.scene.control.Control; import javafx.scene.control.Slider; import javafx.scene.control.TableView; import javafx.scene.control.TitledPane; @@ -52,7 +50,7 @@ final class GridControls extends ViewAndControls { /** * The controls for changing {@link #view}. */ - private final Accordion controls; + private final TitledPane[] controls; /** * The control showing sample dimensions for the current coverage. @@ -90,13 +88,12 @@ final class GridControls extends ViewAndControls { labelOfGroup(vocabulary, Vocabulary.Keys.Cells, gp, false), gp); } /* - * Put all sections together and have the first one expanded by default. + * All sections put together. */ - controls = new Accordion( + controls = new TitledPane[] { new TitledPane(vocabulary.getString(Vocabulary.Keys.Display), displayPane) // TODO: more controls to be added in a future version. - ); - controls.setExpandedPane(controls.getPanes().get(0)); + }; } /** @@ -150,9 +147,11 @@ final class GridControls extends ViewAndControls { /** * Returns the controls for controlling the view of tabular data. + * This method does not clone the returned array; do not modify! */ @Override - final Control controls() { + @SuppressWarnings("ReturnOfCollectionOrArrayField") + final TitledPane[] controlPanes() { return controls; } } diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/ViewAndControls.java b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/ViewAndControls.java index 9205b98..935e08f 100644 --- a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/ViewAndControls.java +++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/ViewAndControls.java @@ -20,6 +20,9 @@ import javafx.geometry.Insets; import javafx.scene.control.Control; import javafx.scene.control.Label; import javafx.scene.control.Toggle; +import javafx.scene.control.TitledPane; +import javafx.scene.control.Accordion; +import javafx.scene.control.SplitPane; import javafx.scene.layout.Region; import javafx.scene.text.Font; import javafx.scene.text.FontWeight; @@ -65,6 +68,15 @@ abstract class ViewAndControls { Toggle selector; /** + * The controls put together in an accordion. Built only if requested + * (may never be requested if the caller creates its own accordion with additional panes, + * as {@link org.apache.sis.gui.dataset.ResourceExplorer} does). + * + * @see #controls() + */ + private Accordion controls; + + /** * The widget which contain this view. This is the widget to inform when the coverage changed. * Subclasses should define the following method: * @@ -136,10 +148,27 @@ abstract class ViewAndControls { abstract Region view(); /** + * Returns the list of control panels for controlling the view. + * They are the components to show on the left (smaller) part of the split pane. + * Callers will typically put those components in an {@link javafx.scene.control.Accordion}. + * + * @return the controls. This method does not clone the returned array; do not modify! + */ + abstract TitledPane[] controlPanes(); + + /** * Returns the controls for controlling the view. - * This is the component to shown on the left (smaller) part of the split pane. + * This is the component to show on the left (smaller) part of the split pane. */ - abstract Control controls(); + final Accordion controls() { + if (controls == null) { + final TitledPane[] panes = controlPanes(); + controls = new Accordion(panes); + controls.setExpandedPane(panes[0]); + SplitPane.setResizableWithParent(controls, Boolean.FALSE); + } + return controls; + } /** * Sets the view content to the given resource, coverage or image. 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 91668cd..9abe7c8 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 @@ -16,6 +16,7 @@ */ package org.apache.sis.gui.dataset; +import java.util.EnumMap; import java.util.Objects; import java.util.Collection; import java.util.logging.Level; @@ -112,6 +113,20 @@ public class ResourceExplorer extends WindowManager { private FeatureTable features; /** + * The type of view (image or table) for the coverage, or {@code null} if the coverage is not currently shown. + * We save this information because we need to know what was the previous view when a new view is selected. + * + * @see #getCoverageView() + */ + private CoverageExplorer.View coverageView; + + /** + * The pane which is expanded for a given type of view. + * This is used for restoring the expanded tab when user switch tab. + */ + private final EnumMap<CoverageExplorer.View, TitledPane> expandedPane; + + /** * Controls for the image or tabular data. The first titled pane on top contains the * {@link #resources} tree and all other panes below are resource-dependent controls. * @@ -166,6 +181,7 @@ public class ResourceExplorer extends WindowManager { final TitledPane resourcesPane = new TitledPane(vocabulary.getString(Vocabulary.Keys.Resources), resources); controls = new Accordion(resourcesPane); controls.setExpandedPane(resourcesPane); + expandedPane = new EnumMap<>(CoverageExplorer.View.class); /* * "Summary" tab showing a summary of resource metadata. */ @@ -417,6 +433,7 @@ public class ResourceExplorer extends WindowManager { * Returns the enumeration value that describe the kind of content to show in {@link CoverageExplorer}. * The type depends on which tab is visible. If no coverage data tab is visible, then returns null. * + * @see #coverageView * @see #dataShown */ private CoverageExplorer.View getCoverageView() { @@ -436,14 +453,14 @@ public class ResourceExplorer extends WindowManager { * @see #updateDataTabWithDefault(Resource) */ private boolean updateDataTab(final Resource resource) { - Region image = null; - Region table = null; - FeatureSet data = null; - ImageRequest grid = null; - Region controlPanel = null; - CoverageExplorer.View type = null; + Region image = null; + Region table = null; + FeatureSet data = null; + ImageRequest grid = null; + TitledPane[] cpanes = null; + final CoverageExplorer.View type = getCoverageView(); if (resource instanceof GridCoverageResource) { - type = getCoverageView(); // A null value here would be a violation of method contract. + // A null `type` value here would be a violation of method contract. if (coverage == null) { coverage = new CoverageExplorer(type); } else { @@ -455,7 +472,7 @@ public class ResourceExplorer extends WindowManager { case TABLE: table = view; break; } grid = new ImageRequest((GridCoverageResource) resource, null, null); - controlPanel = coverage.getControls(type); + cpanes = coverage.getControls(type); } else if (resource instanceof FeatureSet) { data = (FeatureSet) resource; if (features == null) { @@ -474,23 +491,27 @@ public class ResourceExplorer extends WindowManager { final boolean isEmpty = (image == null & table == null); setNewWindowDisabled(isEmpty); /* - * Adds or removes controls for the selected view. + * Add or remove controls for the selected view. + * Information about the expanded pane needs to be saved before to remove controls, + * and restored (for a potentially different view) after new controls have been added. */ + TitledPane expanded = controls.getExpandedPane(); + if (expanded != null && coverageView != null) { + expandedPane.put(coverageView, expanded); + } final ObservableList<TitledPane> items = controls.getPanes(); final int size = items.size(); items.remove(1, size); - if (controlPanel != null) { - if (controlPanel instanceof Accordion) { - /* - * It is okay to use the same controls in another JavaFX node because the `controlPanel` will - * never be shown (we will only show its components). The children are in only one scene graph. - */ - items.addAll(((Accordion) controlPanel).getPanes()); - } else { - items.add(new TitledPane(Vocabulary.getResources(getLocale()) - .getString(Vocabulary.Keys.Controls), controlPanel)); + if (cpanes != null) { + items.addAll(cpanes); + if (!items.contains(expanded)) { + expanded = expandedPane.get(type); + if (expanded != null) { + controls.setExpandedPane(expanded); + } } } + coverageView = type; return !isEmpty | (resource == null); }