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: Tune `ColorTable` behavior on mouse click and keyboard "enter" key.
Date Fri, 08 Jan 2021 23:04:41 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 80c2fbc  Tune `ColorTable` behavior on mouse click and keyboard "enter" key.
80c2fbc is described below

commit 80c2fbc9a662e68a1197437077bd61aa5e17f69a
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Fri Jan 8 23:56:47 2021 +0100

    Tune `ColorTable` behavior on mouse click and keyboard "enter" key.
---
 .../apache/sis/gui/coverage/CoverageStyling.java   |  4 +-
 .../apache/sis/internal/gui/control/ColorCell.java | 75 ++++++++++++----------
 .../internal/gui/control/ColorColumnHandler.java   | 63 +++++++++++++-----
 .../apache/sis/internal/gui/control/ColorRamp.java | 24 +++++--
 4 files changed, 108 insertions(+), 58 deletions(-)

diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageStyling.java
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageStyling.java
index 2e3f7ca..8055d93 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageStyling.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageStyling.java
@@ -107,7 +107,7 @@ final class CoverageStyling extends ColorColumnHandler<Category>
implements Func
     }
 
     /**
-     * Invoked by {@link TableColumn} for computing value of a {@link ColorCell}.
+     * Returns the colors to apply for the given category, or {@code null} for transparent.
      * Does the same work as {@link #apply(Category)}, but returns colors as an array of
ARGB codes.
      * Contrarily to {@link #apply(Category)}, this method may return references to internal
arrays;
      * <strong>do not modify.</strong>
@@ -175,10 +175,8 @@ final class CoverageStyling extends ColorColumnHandler<Category>
implements Func
         name.setId("name");
 
         final TableView<Category> table = new TableView<>();
-        table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
         table.getColumns().add(name);
         addColumnTo(table, vocabulary);
-        table.setEditable(true);
         return table;
     }
 
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/control/ColorCell.java
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/control/ColorCell.java
index 4ddd450..139f56f 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/control/ColorCell.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/control/ColorCell.java
@@ -29,6 +29,7 @@ import javafx.scene.control.ListCell;
 import javafx.scene.control.TableCell;
 import javafx.scene.control.TableRow;
 import javafx.scene.control.TableView;
+import javafx.scene.input.MouseEvent;
 import javafx.scene.paint.Color;
 import javafx.scene.paint.Paint;
 import javafx.scene.shape.Rectangle;
@@ -102,7 +103,17 @@ final class ColorCell<S> extends TableCell<S,ColorRamp> implements
EventHandler<
     ColorCell(final ColorColumnHandler<S> handler) {
         this.handler = handler;
         setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
-        setOnMouseClicked((event) -> requestEdit());
+        setOnMouseClicked(ColorCell::mouseClicked);
+    }
+
+    /**
+     * Invoked when user clicked on the cell. If the cell was not already in editing state,
this method
+     * transitions to editing state. It has the effect of showing the color picker or color
ramp chooser.
+     */
+    private static void mouseClicked(final MouseEvent event) {
+        if (((ColorCell<?>) event.getSource()).requestEdit()) {
+            event.consume();
+        }
     }
 
     /**
@@ -169,8 +180,6 @@ final class ColorCell<S> extends TableCell<S,ColorRamp> implements
EventHandler<
              */
             if (isNewControl) {
                 control.setOnAction(this);
-                control.setOnShown((event) -> requestEdit());
-                control.setOnHidden((event) -> hidden());
             }
         }
         setGraphic(control);
@@ -331,9 +340,13 @@ final class ColorCell<S> extends TableCell<S,ColorRamp> implements
EventHandler<
     }
 
     /**
-     * Hides the control button for choosing color(s) in this cell. The focus is transferred
to the parent table.
+     * Removes the control in the cell and paint the color in a rectangle instead.
      * This method does nothing if the control is already hidden.
      *
+     * <p>This method sets the focus to the table before to remove the combo box.
+     * This is necessary for causing the combo box to lost focus, otherwise focus
+     * problems appear next time that the combo box is shown.</p>
+     *
      * @see #showControlButton()
      */
     private void hideControlButton() {
@@ -350,17 +363,22 @@ final class ColorCell<S> extends TableCell<S,ColorRamp>
implements EventHandler<
     /**
      * Requests this cell to transition to editing state. The request is made on the {@link
TableView},
      * which will invoke {@link #startEdit()}. The edition request must be done on {@code
TableView} for
-     * allowing the table to know to row and column index of the cell being edited.
+     * allowing the table to know the row and column indices of the cell being edited.
+     *
+     * @return {@code true} if this cell transitioned to editing state,
+     *         or {@code false} if this cell was already in editing state.
      */
-    private void requestEdit() {
+    private boolean requestEdit() {
         if (isEditing()) {
-            showControlButton();
+            popup(showControlButton());
+            return false;
         } else {
             final int row = getTableRow().getIndex();
             final TableView<S> table = getTableView();
             table.getSelectionModel().select(row);
             table.edit(row, getTableColumn());
             // JavaFX will call `startEdit()`.
+            return true;
         }
     }
 
@@ -381,6 +399,13 @@ final class ColorCell<S> extends TableCell<S,ColorRamp> implements
EventHandler<
          * misinterpret the value change as a user selection.
          */
         super.startEdit();
+        popup(control);
+    }
+
+    /**
+     * Shows the popup window of the given control. This method does nothing if the control
is null.
+     */
+    private static void popup(final ComboBoxBase<?> control) {
         if (control != null) {
             control.requestFocus();     // Must be before `show()`, otherwise there is apparent
focus confusion.
             control.show();             // For requiring one less mouse click by user.
@@ -398,24 +423,6 @@ final class ColorCell<S> extends TableCell<S,ColorRamp> implements
EventHandler<
     }
 
     /**
-     * Invoked when a combo box has been hidden. This method sets the focus to the table
before to remove
-     * the combo box. This is necessary for causing the combo box to lost focus, otherwise
focus problems
-     * appear next time that the combo box is shown.
-     *
-     * <p>If the cell was in editing mode when this method is invoked, it means that
the user clicked outside
-     * the combo box area without validating his/her choice. In this case {@link #commitEdit(Object)}
has not
-     * been invoked and we need to either commit now or cancel. Current implementation cancels.</p>
-     */
-    private void hidden() {
-        if (!isHover()) {
-            if (isEditing()) {
-                getTableView().edit(-1, null);          // Cancel editing.
-            }
-            hideControlButton();
-        }
-    }
-
-    /**
      * Invoked when the user selected a new value in the color picker or color ramp chooser.
      * This handler creates an item for the new color(s). The selected value may be an instance
      * of one of the following classes:
@@ -432,18 +439,16 @@ final class ColorCell<S> extends TableCell<S,ColorRamp>
implements EventHandler<
     @Override
     public final void handle(final ActionEvent event) {
         if (isEditing()) {
+            final Object value = ((ComboBoxBase<?>) event.getSource()).getValue();
             final ColorRamp colors;
-            final Object source = event.getSource();
-            if (source instanceof ComboBoxBase<?>) {
-                final Object value = ((ComboBoxBase<?>) source).getValue();
-                if (value instanceof Color) {
-                    colors = new ColorRamp(GUIUtilities.toARGB((Color) value));
-                } else {
-                    // A ClassCastException here would be a bug in ColorCell editors management.
-                    colors = (ColorRamp) value;
-                }
-                commitEdit(colors);
+            if (value instanceof Color) {
+                colors = new ColorRamp(GUIUtilities.toARGB((Color) value));
+            } else {
+                // A ClassCastException here would be a bug in ColorCell editors management.
+                colors = (ColorRamp) value;
             }
+            commitEdit(colors);
         }
+        hideControlButton();
     }
 }
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/control/ColorColumnHandler.java
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/control/ColorColumnHandler.java
index e89b02c..bb5bad8 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/control/ColorColumnHandler.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/control/ColorColumnHandler.java
@@ -17,10 +17,12 @@
 package org.apache.sis.internal.gui.control;
 
 import javafx.util.Callback;
+import javafx.scene.paint.Color;
 import javafx.scene.input.KeyCode;
 import javafx.scene.input.KeyEvent;
 import javafx.scene.control.TableView;
 import javafx.scene.control.TableColumn;
+import javafx.scene.control.TablePosition;
 import javafx.beans.value.ObservableValue;
 import org.apache.sis.util.resources.Vocabulary;
 import org.apache.sis.internal.gui.ImmutableObjectProperty;
@@ -66,11 +68,23 @@ public abstract class ColorColumnHandler<S> implements Callback<TableColumn.Cell
      * Gets the ARGB codes of colors to shown in the cell for the given row data.
      *
      * @param  row  the row item for which to get ARGB codes to show in color cell.
-     * @return the colors as ARGB codes.
+     * @return the colors as ARGB codes, or {@code null} if none (transparent).
      */
     protected abstract int[] getARGB(S row);
 
     /**
+     * If a {@code Color} instance already exists for the given row, that instance. Otherwise
{@code null}.
+     * In that later case, a {@code Color} or {@code Paint} instance will be created from
{@link #getARGB(S)}.
+     * This method is only for avoiding to create new {@code Color} instances when it already
exists.
+     *
+     * @param  row  the row item for which to get ARGB codes to show in color cell.
+     * @return the color to use for the given row, if an instance already exists.
+     */
+    protected Color getColor(S row) {
+        return null;
+    }
+
+    /**
      * Invoked by {@link TableColumn} for computing the value of a {@link ColorCell}.
      * This method is public as an implementation side-effect; do not rely on that.
      *
@@ -80,13 +94,21 @@ public abstract class ColorColumnHandler<S> implements Callback<TableColumn.Cell
     @Override
     public final ObservableValue<ColorRamp> call(final TableColumn.CellDataFeatures<S,ColorRamp>
cell) {
         final S value = cell.getValue();
-        if (value != null) {
+        if (value == null) {
+            return null;
+        }
+        final ColorRamp ramp;
+        final Color color = getColor(value);
+        if (color != null) {
+            ramp = new ColorRamp(color);
+        } else {
             final int[] ARGB = getARGB(value);
-            if (ARGB != null) {
-                return new ImmutableObjectProperty<>(new ColorRamp(ARGB));
+            if (ARGB == null) {
+                return null;
             }
+            ramp = new ColorRamp(ARGB);
         }
-        return null;
+        return new ImmutableObjectProperty<>(ramp);
     }
 
     /**
@@ -103,22 +125,31 @@ public abstract class ColorColumnHandler<S> implements Callback<TableColumn.Cell
         colors.setSortable(false);
         colors.setId("colors");
         /*
-         * Filters are invoked during the phase when events are propagated from root to target
(in contrast
-         * to handlers which are invoked in a later phase when events are propagated in opposite
direction).
-         * By registering a filter, we intercept (consume) the event early and avoid that
`TableCell` tries
-         * to handle it. This is necessary for avoiding `NullPointerException` observed in
our experiments.
-         * That exception occurred in JavaFX code that we do not control. Note: we tried
to register filter
-         * directly on the cell, but it is apparently too late for preventing the `NullPointerException`.
+         * Handlers are invoked during the phase when events are propagated from target to
root (in contrast
+         * to filters which are invoked in a sooner phase when events are propagated in opposite
direction).
+         * By registering a handler, we intercept (consume) the event and prevent `TableView`
to handle it.
+         * This is necessary for avoiding `NullPointerException` observed in our experiments.
That exception
+         * occurred in JavaFX code that we do not control. Note: we tried to register filter
directly on the
+         * cell, but it didn't prevented the `NullPointerException`.
          */
-        table.addEventFilter(KeyEvent.KEY_PRESSED, (event) -> {
+        table.addEventHandler(KeyEvent.KEY_PRESSED, (event) -> {
             if (event.getCode() == KeyCode.ENTER) {
-                event.consume();
-                final int row = table.getSelectionModel().getSelectedIndex();
-                if (row >= 0) {
-                    table.edit(row, colors);
+                final TablePosition<?,?> focused = table.getFocusModel().getFocusedCell();
+                if (focused != null) {
+                    final TableColumn<?,?> column = focused.getTableColumn();
+                    if (column == null || column == colors) {
+                        event.consume();
+                        final TablePosition<?,?> editing = table.getEditingCell();
+                        final int row = (editing != null ? editing : focused).getRow();
+                        if (row >= 0) {
+                            table.edit(row, colors);
+                        }
+                    }
                 }
             }
         });
         table.getColumns().add(colors);
+        table.setEditable(true);
+        table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
     }
 }
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/control/ColorRamp.java
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/control/ColorRamp.java
index 017016a..8b87dfb 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/control/ColorRamp.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/control/ColorRamp.java
@@ -88,6 +88,7 @@ public final class ColorRamp {
 
     /**
      * A gradient of colors created from {@link #colors} when first needed.
+     * May be an instance of {@link Color} if there is only one color.
      *
      * @see #paint()
      */
@@ -101,6 +102,14 @@ public final class ColorRamp {
     private transient String name;
 
     /**
+     * Creates a new item for the given color.
+     */
+    ColorRamp(final Color color) {
+        paint = this.color = color;
+        colors = new int[] {GUIUtilities.toARGB(color)};
+    }
+
+    /**
      * Creates a new item for the given colors.
      */
     ColorRamp(final int... colors) {
@@ -114,9 +123,13 @@ public final class ColorRamp {
      *
      * @return single color to shown in table cell, or {@code null} if none.
      */
-    final Color color() {
-        if (color == null && colors != null && colors.length != 0) {
-            color = GUIUtilities.fromARGB(colors[colors.length / 2]);
+    public final Color color() {
+        if (color == null) {
+            if (paint instanceof Color) {
+                color = (Color) paint;
+            } else if (colors != null && colors.length != 0) {
+                color = GUIUtilities.fromARGB(colors[colors.length / 2]);
+            }
         }
         return color;
     }
@@ -131,7 +144,10 @@ public final class ColorRamp {
             switch (colors.length) {
                 case 0: break;
                 case 1: {
-                    paint = GUIUtilities.fromARGB(colors[0]);
+                    if (color == null) {
+                        color = GUIUtilities.fromARGB(colors[0]);
+                    }
+                    paint = color;
                     break;
                 }
                 default: {


Mime
View raw message