sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] 02/06: Consolidation of the we relate "tabular data window" and "visualization window".
Date Sat, 22 Feb 2020 17:04:13 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

commit 89b62936a49f64da05b497f8817434cfaee3387e
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Sat Feb 22 12:22:56 2020 +0100

    Consolidation of the we relate "tabular data window" and "visualization window".
---
 .../apache/sis/gui/coverage/CoverageExplorer.java  |  24 ++--
 .../org/apache/sis/gui/dataset/DataWindow.java     | 125 ++++++++++++---------
 .../org/apache/sis/internal/gui/Resources.java     |  10 ++
 .../apache/sis/internal/gui/Resources.properties   |   2 +
 .../sis/internal/gui/Resources_fr.properties       |   2 +
 .../org/apache/sis/internal/gui/ToolbarButton.java | 120 +++++++++++++++++---
 6 files changed, 209 insertions(+), 74 deletions(-)

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 a94993d..09bf287 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
@@ -26,6 +26,7 @@ import javafx.collections.ObservableList;
 import javafx.geometry.Insets;
 import javafx.scene.control.Accordion;
 import javafx.scene.control.Control;
+import javafx.scene.control.Button;
 import javafx.scene.control.Label;
 import javafx.scene.control.Slider;
 import javafx.scene.control.SplitPane;
@@ -41,6 +42,7 @@ import javafx.scene.layout.Region;
 import javafx.scene.layout.VBox;
 import org.apache.sis.coverage.SampleDimension;
 import org.apache.sis.coverage.grid.GridCoverage;
+import org.apache.sis.internal.gui.Resources;
 import org.apache.sis.internal.gui.Styles;
 import org.apache.sis.internal.gui.ToolbarButton;
 import org.apache.sis.util.resources.Vocabulary;
@@ -125,7 +127,7 @@ public class CoverageExplorer {
         }
         /*
          * "Display" section with the following controls:
-         *    - Number format as a localized pattern (TODO).
+         *    - Number format as a localized pattern.
          *    - Cell width as a slider.
          */
         final VBox displayPane;
@@ -183,12 +185,20 @@ addRows:    for (int row = 0;; row++) {
          * they are managed by org.apache.sis.gui.dataset.DataWindow. We only declare here
the
          * text and action for each button.
          */
-        content.getProperties().put(ToolbarButton.PROPERTY_KEY, new ToolbarButton[] {
-            new ToolbarButton() {
-                @Override public String getText() {return "\uD83D\uDDFA\uFE0F";}      //
World map character.
-                @Override public Region createView() {
-                    return new CoverageView(null).getView();
-                }
+        ToolbarButton.insert(content, new ToolbarButton.RelatedWindow() {
+            /** 🗺 — World map. */
+            @Override public Button createButton(final Resources localized) {
+                return createButton("\uD83D\uDDFA\uFE0F", localized, Resources.Keys.Visualize);
+            }
+
+            /** 🔢 — Input symbol for numbers. */
+            @Override public Button createBackButton(final Resources localized) {
+                return createButton("\uD83D\uDD22\uFE0F", localized, Resources.Keys.TabularData);
+            }
+
+            /** Creates a visualization of the coverage. */
+            @Override public Region createView(final Locale locale) {
+                return new CoverageView(locale).getView();
             }
         });
     }
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/DataWindow.java
b/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/DataWindow.java
index 40244cd..59ca2cc 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/DataWindow.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/DataWindow.java
@@ -46,25 +46,31 @@ import org.apache.sis.internal.gui.ToolbarButton;
  */
 final class DataWindow extends Stage {
     /**
-     * The locale for this window.
+     * The locale for texts and tooltips in this window.
      */
     private final Locale locale;
 
     /**
-     * The tools bar. Removed from the pane when going in full screen mode,
-     * and reinserted when exiting full screen mode.
+     * The tools bar. Removed from the pane when going in full screen mode, and reinserted
+     * when exiting full screen mode. The first button in this toolbar shall be the "home"
+     * button (for showing the main window on front) — if a different position is desired,
+     * revisit {@link #getHomeButton()}.
+     *
+     * @see #getHomeButton()
+     * @see #onFullScreen(boolean)
      */
     private final ToolBar tools;
 
     /**
      * Creates a new window for the given data selected in the explorer or determined by
the active tab.
+     * The new window will be positioned in the screen center but not yet shown.
      *
      * @param  home  the window containing the main explorer, to be the target of "home"
button.
      * @param  data  the data selected by user, to show in a new window.
      */
     DataWindow(final Stage home, final SelectedData data) {
-        this(null, data.createView(), data.localized,
-                (event) -> {home.show(); home.toFront();});
+        this(data.createView(), data.localized);
+        getHomeButton().setOnAction((e) -> {home.show(); home.toFront();});
         /*
          * We use an initial size covering a large fraction of the screen because
          * this window is typically used for showing image or large tabular data.
@@ -75,57 +81,54 @@ final class DataWindow extends Stage {
     }
 
     /**
-     * Creates a new window for the given content. The {@code home} and {@code localized}
arguments
-     * shall be non-null only if {@code originator} is null.
+     * Returns the "home" button. This implementation assumes that "home" is the first button
on the toolbar.
+     * This method is kept close to the following constructor for making easier to verify
its assumption.
+     */
+    private Button getHomeButton() {
+        return ((Button) tools.getItems().get(0));
+    }
+
+    /**
+     * Creates a new window for the given content. After this constructor returned,
+     * caller should set an action on {@link #getHomeButton()} and set the window size.
      *
-     * @param  originator  the window from which this window is derived, or {@code null}
if none.
-     * @param  content     content of the window to create.
-     * @param  localized   {@link Resources} instance provided because often know by the
caller.
-     * @param  home        the action to execute when user clicks on the "home" button.
+     * @param  content    content of the window to create.
+     * @param  localized  {@link Resources} instance, provided because often known by the
caller.
      */
-    private DataWindow(final DataWindow originator, final Region content, Resources localized,
EventHandler<ActionEvent> home) {
-        if (originator != null) {
-            home = ((Button) originator.tools.getItems().get(0)).getOnAction();
-            localized = Resources.forLocale(originator.locale);
-        }
+    private DataWindow(final Region content, final Resources localized) {
         locale = localized.getLocale();
         /*
-         * Build the tools bar. This bar will be hidden in full screen mode.
-         * Note that code above assumes that this button is the first button in the toolbar.
+         * Build the tools bar. This bar will be hidden in full screen mode. Note that above
+         * method assumes that the "home" button created below is the first one in the toolbar.
          */
         final Button mainWindow = new Button("\u2302\uFE0F");               // ⌂ — house
         mainWindow.setTooltip(new Tooltip(localized.getString(Resources.Keys.MainWindow)));
-        mainWindow.setOnAction(home);
 
         final Button fullScreen = new Button("\u21F1\uFE0F");               // ⇱ — North
West Arrow to Corner
         fullScreen.setTooltip(new Tooltip(localized.getString(Resources.Keys.FullScreen)));
         fullScreen.setOnAction((event) -> setFullScreen(true));
-        /*
-         * Hide/show the toolbar when entering/exiting full screen mode.
-         */
-        tools = new ToolBar(mainWindow, fullScreen);
         fullScreenProperty().addListener((source, oldValue, newValue) -> onFullScreen(newValue));
 
-        if (originator != null) {
-            final Button related = new Button("\uD83D\uDD22\uFE0F");    // Input symbol for
numbers.
-            related.setOnAction((event) -> {originator.show(); originator.toFront();});
-            tools.getItems().add(related);
-        }
+        tools = new ToolBar(mainWindow, fullScreen);
         /*
          * Add content-specific buttons. We use the "org.apache.sis.gui.ToolbarButton" property
          * as a way to transfer ToolbarButton accross packages without making this class
public.
          */
-        final ToolbarButton[] contentButtons = (ToolbarButton[]) content.getProperties().remove(ToolbarButton.PROPERTY_KEY);
-        if (contentButtons != null) {
-            for (final ToolbarButton tb : contentButtons) {
-                final Button b = new Button(tb.getText());
-                b.setOnAction(new Related(this, tb));
-                tools.getItems().add(b);
+        for (final ToolbarButton specialized : ToolbarButton.remove(content)) {
+            final Node button = specialized.createButton(localized);
+            if (specialized instanceof ToolbarButton.RelatedWindow) {
+                ((Button) button).setOnAction(new Related(this, (ToolbarButton.RelatedWindow)
specialized));
             }
+            tools.getItems().add(button);
         }
-        final Font bf = Font.font(20);
+        /*
+         * After we finished adding all buttons, set the font of all of them to a larger
size.
+         */
+        final Font font = Font.font(20);
         for (final Node node : tools.getItems()) {
-            ((Button) node).setFont(bf);
+            if (node instanceof Button) {
+                ((Button) node).setFont(font);
+            }
         }
         /*
          * Main content. After this constructor returned, caller
@@ -139,8 +142,8 @@ final class DataWindow extends Stage {
 
     /**
      * Manage the creation and display of another window related to the enclosing {@link
DataWindow}.
-     * For example is the enclosing window shown the tabular data, the window created by
this class
-     * may shown the map.
+     * For example is the enclosing window shows the tabular data, the window created by
this class
+     * may show the map.
      */
     private static final class Related implements EventHandler<ActionEvent> {
         /**
@@ -149,41 +152,56 @@ final class DataWindow extends Stage {
         private static final int LOCATION = 40;
 
         /**
-         * The object that can create the window.
-         * This is set to {@code null} when no longer needed.
+         * The object for creating the window on the first time that the user clicks on the
button.
+         * This is set to {@code null} when no longer needed, in which case {@link #window}
should
+         * be a reference to the window that we created.
          */
-        private ToolbarButton creator;
+        private ToolbarButton.RelatedWindow creator;
 
         /**
          * The related window. If {@link #creator} is non-null, then this is the original
window that
          * created this {@code Related} instance. If {@link #creator} is null, this is the
new window
-         * that has been created.
+         * that this class has created.
          */
         private DataWindow window;
 
         /**
          * Prepares an action for invoking {@code creator.createView()} when first needed.
+         * The given {@code originator} window will be the target of the "back" button.
+         *
+         * @param  originator  the original window that created this {@code Related} instance.
+         * @param  creator     a factory for the new window to create when the user request
it.
          */
-        Related(final DataWindow originator, final ToolbarButton creator) {
+        Related(final DataWindow originator, final ToolbarButton.RelatedWindow creator) {
             this.window  = originator;
             this.creator = creator;
         }
 
         /**
-         * Invoked when the user clicked on the button for showing the window managed by
this {@code Related}.
-         * On the first click, the related window is created. On subsequent click, that window
is brought to front.
+         * Invoked when the user clicked on the button for showing the window managed by
this {@code Related} object.
+         * On the first click, the related window is created. On subsequent clicks, that
window is brought to front.
          */
         @Override
         public void handle(final ActionEvent event) {
             if (creator != null) {
-                final String title = window.getTitle();     // TODO! make the title different.
-                final DataWindow rw = new DataWindow(window, creator.createView(), null,
null);
-                rw.setTitle(title);
-                rw.setWidth (window.getWidth());
-                rw.setHeight(window.getHeight());
-                rw.setX(window.getX() + LOCATION);
-                rw.setY(window.getY() + LOCATION);
-                window  = rw;                   // Set only on success.
+                final DataWindow originator = window;
+                final Resources  localized  = Resources.forLocale(originator.locale);
+                final Region     content    = creator.createView(originator.locale);
+                final Button     backButton = creator.createBackButton(localized);
+                backButton.setOnAction((e) -> {originator.show(); originator.toFront();});
+                ToolbarButton.insert(content, new ToolbarButton() {
+                    @Override public Node createButton(Resources localized) {
+                        return backButton;
+                    }
+                });
+                final DataWindow rw = new DataWindow(content, localized);
+                rw.getHomeButton().setOnAction(originator.getHomeButton().getOnAction());
+                rw.setTitle (originator.getTitle());
+                rw.setWidth (originator.getWidth());
+                rw.setHeight(originator.getHeight());
+                rw.setX(originator.getX() + LOCATION);
+                rw.setY(originator.getY() + LOCATION);
+                window  = rw;                                       // Set only on success.
                 creator = null;
             }
             window.show();
@@ -193,6 +211,7 @@ final class DataWindow extends Stage {
 
     /**
      * Invoked when entering or existing the full screen mode.
+     * Used for hiding/showing the toolbar when entering/exiting full screen mode.
      */
     private void onFullScreen(final boolean entering) {
         final BorderPane pane = (BorderPane) getScene().getRoot();
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources.java
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources.java
index 782474b..162ffad 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources.java
@@ -291,6 +291,11 @@ public final class Resources extends IndexedResourceBundle {
         public static final short Summary = 29;
 
         /**
+         * Tabular data
+         */
+        public static final short TabularData = 51;
+
+        /**
          * Topic category:
          */
         public static final short TopicCategory = 25;
@@ -301,6 +306,11 @@ public final class Resources extends IndexedResourceBundle {
         public static final short TypeOfResource = 26;
 
         /**
+         * Visualize
+         */
+        public static final short Visualize = 52;
+
+        /**
          * Windows
          */
         public static final short Windows = 43;
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources.properties
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources.properties
index 581194d..e0dd468 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources.properties
+++ b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources.properties
@@ -67,6 +67,8 @@ SelectCRS              = Select a coordinate reference system
 SendTo                 = Send to
 StandardErrorStream    = Standard error stream
 Summary                = Summary
+TabularData            = Tabular data
 TopicCategory          = Topic category:
 TypeOfResource         = Type of resource:
+Visualize              = Visualize
 Windows                = Windows
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources_fr.properties
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources_fr.properties
index de60cb6..ef7cf2a 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources_fr.properties
+++ b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources_fr.properties
@@ -72,6 +72,8 @@ SelectCRS              = Choisir un syst\u00e8me de r\u00e9f\u00e9rence
des coor
 SendTo                 = Envoyer vers
 StandardErrorStream    = Flux d\u2019erreur standard
 Summary                = R\u00e9sum\u00e9
+TabularData            = Tableau de valeurs
 TopicCategory          = Cat\u00e9gorie th\u00e9matique\u00a0:
 TypeOfResource         = Type de ressource\u00a0:
+Visualize              = Visualiser
 Windows                = Fen\u00eatres
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/ToolbarButton.java
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/ToolbarButton.java
index 94a2384..d3f2109 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/ToolbarButton.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/ToolbarButton.java
@@ -16,17 +16,23 @@
  */
 package org.apache.sis.internal.gui;
 
+import java.util.Locale;
 import javafx.scene.Node;
+import javafx.scene.control.Button;
+import javafx.scene.control.Tooltip;
 import javafx.scene.layout.Region;
+import org.apache.sis.util.ArraysExt;
 
 
 /**
- * A button in a the toolbar of a {@link org.apache.sis.gui.dataset.DataWindow},
- * other than the common buttons provided by {@code DataWindow} itself.
- * Those button depends on the window content.
+ * Description of a button to add in a the {@link org.apache.sis.gui.dataset.DataWindow}
toolbar.
+ * This class is used only for content-specific buttons; it is not used for buttons managed
directly by
+ * {@code DataWindow} itself. A {@code ToolbarButton} can create and configure a button with
its icon,
+ * tooltip text and action to execute when the button is pushed. {@code ToolbarButton} instances
exist
+ * only temporarily and are discarded after the button has been created and placed in the
toolbar.
  *
- * <p>Current API is for creating a new window of related data. A future version
- * may move that API in a subclass if we need to support other kinds of service.</p>
+ * <p>This class is defined in this internal package for allowing interactions between
classes
+ * in different packages without making toolbar API public.</p>
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @version 1.1
@@ -38,7 +44,40 @@ public abstract class ToolbarButton {
      * The property to use in {@link Node#getProperties()} for storing instances of this
class.
      * Values associated to this key shall be arrays of {@code ToolbarButton[]} type.
      */
-    public static final String PROPERTY_KEY = "org.apache.sis.gui.ToolbarButton";
+    private static final String PROPERTY_KEY = "org.apache.sis.gui.ToolbarButton";
+
+    /**
+     * Gets and removes the toolbar buttons associated to the given content pane. Those buttons
+     * should have been specified by a previous call to {@link #insert(Node, ToolbarButton...)}.
+     * They will be requested by {@link org.apache.sis.gui.dataset.DataWindow} only once,
+     * which is why we remove them afterward.
+     *
+     * @param  content  the pane for which to get the toolbar buttons.
+     * @return the toolbar buttons (never null, but may be empty).
+     */
+    public static ToolbarButton[] remove(final Node content) {
+        final ToolbarButton[] buttons = (ToolbarButton[]) content.getProperties().remove(PROPERTY_KEY);
+        return (buttons != null) ? buttons : new ToolbarButton[0];
+    }
+
+    /**
+     * Sets the toolbar buttons that the given pane which to have in the data window.
+     * If the pane already has buttons, the new one will be inserted before existing ones.
+     *
+     * @param  content  the pane for which to set the toolbar buttons.
+     * @param  buttons  the toolbar buttons to add.
+     */
+    public static void insert(final Node content, final ToolbarButton... buttons) {
+        content.getProperties().merge(PROPERTY_KEY, buttons, ToolbarButton::prepend);
+    }
+
+    /**
+     * Invoked if toolbar buttons already exist for a pane, in which case the new ones
+     * are inserted before the existing ones.
+     */
+    private static Object prepend(final Object oldValue, final Object newValue) {
+        return ArraysExt.append((ToolbarButton[]) newValue, (ToolbarButton[]) oldValue);
+    }
 
     /**
      * For subclass constructors.
@@ -47,18 +86,71 @@ public abstract class ToolbarButton {
     }
 
     /**
-     * Returns the text to show in the button.
+     * Creates a button configured with its icon, tooltip and action.
+     * The button will be added to the toolbar by the caller.
+     *
+     * <p>If this {@code ToolbarButton} is an instance of {@link RelatedWindow},
+     * then this method does not need to set an action on the button because it
+     * will be done by the caller.</p>
      *
-     * @return the button text.
+     * @param  localized  an instance of {@link Resources} for current locale.
+     * @return the button configured with text or icon, tooltip and action.
      */
-    public abstract String getText();
+    public abstract Node createButton(Resources localized);
 
     /**
-     * Creates the content of the window to show when the user click on the button.
-     * This method is invoked only on the first click. For all subsequent clicks,
-     * the existing window will be shown again.
+     * Convenience method for creating a button.
      *
-     * @return content of the window to show.
+     * @param  icon       the text to put in the button, as a Unicode emoji.
+     * @param  localized  an instance of {@link Resources} for current locale.
+     * @param  tooltip    the {@link Resources.Keys} value for the tooltip.
+     * @return the button configured with text or icon, tooltip and action.
      */
-    public abstract Region createView();
+    protected static Button createButton(final String icon, final Resources localized, final
short tooltip) {
+        final Button b = new Button(icon);
+        b.setTooltip(new Tooltip(localized.getString(tooltip)));
+        return b;
+    }
+
+    /**
+     * A toolbar button for creating and showing a new window related to the window in which
the button has been pushed.
+     * The button action will create a new instance of {@link org.apache.sis.gui.dataset.DataWindow}
which will itself
+     * contain a button for going back to the original window.
+     */
+    public abstract static class RelatedWindow extends ToolbarButton {
+        /**
+         * For subclass constructors.
+         */
+        protected RelatedWindow() {
+        }
+
+        /**
+         * Creates a button configured with its icon, tooltip and action.
+         * This button does not need to contain an action; it will be set by the caller.
+         *
+         * @param  localized  an instance of {@link Resources} for current locale.
+         * @return the button configured with text or icon and tooltip.
+         */
+        @Override
+        public abstract Button createButton(Resources localized);
+
+        /**
+         * Creates the button for navigation back to the original window.
+         * This button does not need to contain an action; it will be set by the caller.
+         *
+         * @param  localized  an instance of {@link Resources} for current locale.
+         * @return the button configured with text or icon and tooltip.
+         */
+        public abstract Button createBackButton(Resources localized);
+
+        /**
+         * Creates the content of the window to show when the user click on the button.
+         * This method is invoked only on the first click. For all subsequent clicks,
+         * the existing window will be shown again.
+         *
+         * @param  locale  locale of the window creating a new window.
+         * @return content of the window to show.
+         */
+        public abstract Region createView(Locale locale);
+    }
 }


Mime
View raw message