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 65e63cc  Complete the formatting of header row on top of the grid view 
area.
65e63cc is described below

commit 65e63cc4d3188c16d1b5e87e66cc07255478299c
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Sat Jan 25 15:32:53 2020 +0100

    Complete the formatting of header row on top of the grid view area.
---
 .../java/org/apache/sis/gui/coverage/GridRow.java  |  16 --
 .../org/apache/sis/gui/coverage/GridRowSkin.java   |  44 ++---
 .../java/org/apache/sis/gui/coverage/GridView.java |  60 ++++--
 .../org/apache/sis/gui/coverage/GridViewSkin.java  | 218 ++++++++++++++++-----
 4 files changed, 230 insertions(+), 108 deletions(-)

diff --git 
a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridRow.java 
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridRow.java
index ad89f85..361fd4c 100644
--- 
a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridRow.java
+++ 
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridRow.java
@@ -42,22 +42,7 @@ import javafx.scene.text.FontWeight;
  */
 final class GridRow extends IndexedCell<Void> {
     /**
-     * The {@link VirtualFlow} which is managing this row. This is the value 
given to the constructor,
-     * casted to the type used by {@link GridView}. There is two main 
properties that we want to access:
-     *
-     * <ul>
-     *   <li>{@link GridViewSkin.Flow#getHorizontalPosition()} for the 
position of the horizontal scroll bar.</li>
-     *   <li>{@link GridViewSkin.Flow#getWidth()} for the width of the visible 
region.
-     * </ul>
-     *
-     * Those two properties are used for creating the minimal amount of {@link 
GridCell} needed
-     * for rendering this row.
-     */
-    final GridViewSkin.Flow flow;
-
-    /**
      * The grid view where this row will be shown.
-     * This is {@code flow.getParent()} but fetched once for efficiency.
      */
     final GridView view;
 
@@ -80,7 +65,6 @@ final class GridRow extends IndexedCell<Void> {
      * This constructor is referenced by lambda-function in {@link 
GridViewSkin}.
      */
     GridRow(final VirtualFlow<GridRow> owner) {
-        flow = (GridViewSkin.Flow) owner;
         view = (GridView) owner.getParent();
         setPrefWidth(view.getContentWidth());
         setFont(Font.font(null, FontWeight.BOLD, -1));      // Apply only to 
the header column.
diff --git 
a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridRowSkin.java
 
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridRowSkin.java
index b085114..4bb4390 100644
--- 
a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridRowSkin.java
+++ 
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridRowSkin.java
@@ -50,7 +50,7 @@ final class GridRowSkin extends CellSkinBase<GridRow> {
      */
     final void setRowIndex(final int index) {
         final Text header = (Text) getChildren().get(0);
-        header.setText(getSkinnable().view.formatHeaderValue(index));
+        header.setText(getSkinnable().view.formatHeaderValue(index, true));
     }
 
     /**
@@ -76,9 +76,18 @@ final class GridRowSkin extends CellSkinBase<GridRow> {
     protected void layoutChildren(final double x, final double y, final double 
width, final double height) {
         /*
          * Do not invoke super.layoutChildren(…) since we are doing a 
different layout.
-         * The first child is a javafx.scene.text.Text instance, which we use 
for row header.
+         * The first child is a `javafx.scene.text.Text`, which we use for row 
header.
          */
+        final ObservableList<Node> children = getChildren();
         final GridRow row = getSkinnable();
+        final GridViewSkin layout = (GridViewSkin) row.view.getSkin();
+        /*
+         * Set the position of the header cell, but not its content. The 
content has been set by
+         * `setRowIndex(int)` and does not need to be recomputed even during 
horizontal scroll.
+         */
+        double pos = layout.leftPosition;               // Horizontal position 
in the virtual view.
+        ((Text) children.get(0)).resizeRelocate(pos, y, layout.headerWidth, 
height);
+        pos += layout.headerWidth;
         /*
          * Get the beginning (pos) and end (limit) of the region to render. We 
create only the amount
          * of GridCell instances needed for rendering this region. We should 
not create cells for the
@@ -86,30 +95,19 @@ final class GridRowSkin extends CellSkinBase<GridRow> {
          * in a list of children that we try to keep small. All children 
starting at index 1 shall be
          * GridCell instances created in this method.
          */
-        final double headerWidth = row.view.headerWidth.get();
-        final double cellWidth   = row.view.cellWidth.get();            // 
Includes the cell spacing.
-        final double cellSpacing = row.view.cellSpacing.get();
-        final double available   = cellWidth - cellSpacing;
-        double pos = row.flow.getHorizontalPosition();                  // 
Horizontal position in the virtual view.
-        final double limit = pos + row.flow.getWidth();                 // 
Horizontal position where to stop.
-        int column = (int) (pos / cellWidth);                           // 
Column index in the RenderedImage.
-        /*
-         * Set the position of the header cell, but not its content. The 
content has been set by
-         * `setRowIndex(int)` and does not need to be recomputed even during 
horizontal scroll.
-         */
-        final ObservableList<Node> children = getChildren();
-        final Text header = (Text) children.get(0);
-        header.resizeRelocate(pos + cellSpacing, y, headerWidth - cellSpacing, 
height);
-        pos += headerWidth;
-        /*
-         * For sample value, we need to recompute both the values and the 
position. Note that even if
-         * the cells appear at the same positions visually (with different 
content), they moved in the
-         * virtual flow if some scrolling occurred.
-         */
-        int childIndex = 0;
+        final double cellWidth  = layout.cellWidth;             // Includes 
the cell spacing.
+        final double available  = layout.cellInnerWidth;
+        final double limit      = layout.rightPosition;         // Horizontal 
position where to stop.
+        int          column     = layout.firstVisibleColumn;    // Column 
index in the RenderedImage.
+        int          childIndex = 0;
         List<GridCell> newChildren = null;
         final int count = children.size();
         while (pos < limit) {
+            /*
+             * For sample value, we need to recompute both the values and the 
position. Note that even if
+             * the cells appear at the same positions visually (with different 
content), they moved in the
+             * virtual flow if some scrolling occurred.
+             */
             final GridCell cell;
             if (++childIndex < count) {
                 cell = (GridCell) children.get(childIndex);
diff --git 
a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridView.java
 
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridView.java
index e7b9b6f..45b1407 100644
--- 
a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridView.java
+++ 
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridView.java
@@ -57,7 +57,9 @@ import org.apache.sis.coverage.grid.GridCoverage;
 @DefaultProperty("image")
 public class GridView extends Control {
     /**
-     * Minimum cell width and height.
+     * Minimum cell width and height. Must be greater than zero, otherwise 
infinite loops may happen.
+     *
+     * @see #getSizeValue(DoubleProperty)
      */
     static final int MIN_CELL_SIZE = 1;
 
@@ -325,18 +327,6 @@ public class GridView extends Control {
     }
 
     /**
-     * Invoked when the content may have changed. If {@code all} is {@code 
true}, then everything
-     * may have changed including the number of rows and columns. If {@code 
all} is {@code false}
-     * then the number of rows and columns is assumed the same.
-     */
-    final void contentChanged(final boolean all) {
-        final Skin<?> skin = getSkin();             // May be null if the view 
is not yet shown.
-        if (skin instanceof GridViewSkin) {         // Could be a user 
instance (not recommended).
-            ((GridViewSkin) skin).contentChanged(all);
-        }
-    }
-
-    /**
      * Invoked when the {@link #cellFormat} configuration changed.
      *
      * @param  notify  whether to notify the renderer about the change. Can be 
{@code false}
@@ -351,11 +341,30 @@ public class GridView extends Control {
     }
 
     /**
+     * Invoked when the content may have changed. If {@code all} is {@code 
true}, then everything
+     * may have changed including the number of rows and columns. If {@code 
all} is {@code false}
+     * then the number of rows and columns is assumed the same.
+     */
+    private void contentChanged(final boolean all) {
+        final Skin<?> skin = getSkin();             // May be null if the view 
is not yet shown.
+        if (skin instanceof GridViewSkin) {         // Could be a user 
instance (not recommended).
+            ((GridViewSkin) skin).contentChanged(all);
+        }
+    }
+
+    /**
      * Returns the width that this view would have if it was fully shown 
(without horizontal scroll bar).
      * This value depends on the number of columns in the image and the size 
of each cell.
+     * This method does not take in account the space occupied by the vertical 
scroll bar.
      */
     final double getContentWidth() {
-        return width * Math.max(MIN_CELL_SIZE, cellWidth.get()) + 
Math.max(MIN_CELL_SIZE, headerWidth.get());
+        /*
+         * Add one more column for avoiding offsets caused by the rounding of 
scroll bar position
+         * to integer multiple of column size. The 20 minimal value used below 
is arbitrary;
+         * we take a value close to the vertical scrollbar width as a safety.
+         */
+        final double w = getSizeValue(cellWidth);
+        return width * w + getSizeValue(headerWidth) + Math.max(w, 20);
     }
 
     /**
@@ -446,10 +455,17 @@ public class GridView extends Control {
 
     /**
      * Formats a row index or column index.
+     *
+     * @param  index     the row or column index to format.
+     * @param  vertical  {@code true} if formatting row index, or {@code 
false} if formatting column index.
      */
-    final String formatHeaderValue(final int index) {
-        buffer.setLength(0);
-        return headerFormat.format(index, buffer, formatField).toString();
+    final String formatHeaderValue(final int index, final boolean vertical) {
+        if (index >= 0 && index < (vertical ? height : width)) {
+            buffer.setLength(0);
+            return headerFormat.format(index, buffer, formatField).toString();
+        } else {
+            return OUT_OF_BOUNDS;
+        }
     }
 
     /**
@@ -464,4 +480,14 @@ public class GridView extends Control {
     protected final Skin<GridView> createDefaultSkin() {
         return new GridViewSkin(this);
     }
+
+    /**
+     * Returns the value of the given property as a real number not smaller 
than {@value #MIN_CELL_SIZE}.
+     * We use this method instead of {@link Math#max(double, double)} because 
we want {@link Double#NaN}
+     * values to be replaced by {@value #MIN_CELL_SIZE}.
+     */
+    static double getSizeValue(final DoubleProperty property) {
+        final double value = property.get();
+        return (value >= MIN_CELL_SIZE) ? value : MIN_CELL_SIZE;
+    }
 }
diff --git 
a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridViewSkin.java
 
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridViewSkin.java
index 8b81e0d..a41bb0b 100644
--- 
a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridViewSkin.java
+++ 
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridViewSkin.java
@@ -20,10 +20,13 @@ import java.awt.image.RenderedImage;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
 import javafx.collections.ObservableList;
+import javafx.geometry.HPos;
+import javafx.geometry.VPos;
 import javafx.scene.Node;
 import javafx.scene.control.ScrollBar;
 import javafx.scene.control.skin.VirtualFlow;
 import javafx.scene.control.skin.VirtualContainerBase;
+import javafx.scene.layout.HBox;
 import javafx.scene.shape.Rectangle;
 
 
@@ -47,68 +50,109 @@ import javafx.scene.shape.Rectangle;
  */
 final class GridViewSkin extends VirtualContainerBase<GridView, GridRow> {
     /**
+     * The cells that we put in the header row on the top of the view. This 
list is initially empty;
+     * new elements are added or removed when first needed and when the view 
size changed.
+     */
+    private final ObservableList<Node> headerRow;
+
+    /**
+     * Background of the header row (top side) and header column (left side) 
of the view.
+     */
+    private final Rectangle topBackground, leftBackground;
+
+    /**
+     * Image index of the first column visible in the view, ignoring the 
header column.
+     * This is a {@link RenderedImage} <var>x</var> index (with an arbitrary 
origin),
+     * not necessarily the same value than the zero-based index used in JavaFX 
views.
+     *
+     * <p>This field is written by {@link #layoutChildren(double, double, 
double, double)}.
+     * All other accesses (especially from outside of this class) should be 
read-only.</p>
+     */
+    int firstVisibleColumn;
+
+    /**
+     * Horizontal position in the virtual flow where to start writing the text 
of the header column.
+     * This value changes during horizontal scrolls, even if the cells 
continue to start at the same
+     * visual position on the screen. The position of the column showing 
{@link #firstVisibleColumn}
+     * sample values is {@code leftPosition} + {@link #headerWidth}, and that 
position is incremented
+     * by {@link #cellWidth} for all other columns.
+     *
+     * <p>This field is written by {@link #layoutChildren(double, double, 
double, double)}.
+     * All other accesses (especially from outside of this class) should be 
read-only.</p>
+     */
+    double leftPosition;
+
+    /**
+     * Horizontal position where to stop rendering the cells.
+     * This is {@link #leftPosition} + the view width.
+     *
+     * <p>This field is written by {@link #layoutChildren(double, double, 
double, double)}.
+     * All other accesses (especially from outside of this class) should be 
read-only.</p>
+     */
+    double rightPosition;
+
+    /**
+     * Width of the header column ({@code headerWidth}) and of all other 
columns ({@code cellWidth}).
+     * Must be greater than zero, otherwise infinite loop may happen.
+     *
+     * <p>This field is written by {@link #layoutChildren(double, double, 
double, double)}.
+     * All other accesses (especially from outside of this class) should be 
read-only.</p>
+     */
+    double headerWidth, cellWidth;
+
+    /**
+     * Width of the region where to write the text in a cell. Should be equals 
or slightly smaller
+     * than {@link #cellWidth}. We use a smaller width for leaving a small 
margin between cells.
+     *
+     * <p>This field is written by {@link #layoutChildren(double, double, 
double, double)}.
+     * All other accesses (especially from outside of this class) should be 
read-only.</p>
+     */
+    double cellInnerWidth;
+
+    /**
      * Creates a new skin for the specified view.
      */
     GridViewSkin(final GridView view) {
         super(view);
+        final HBox header = new HBox();
+        headerRow = header.getChildren();
+        /*
+         * Main content where sample values will be shown.
+         */
         final VirtualFlow<GridRow> flow = getVirtualFlow();
         flow.setCellFactory(GridRow::new);
         flow.setFocusTraversable(true);
-        flow.setFixedCellSize(Math.max(GridView.MIN_CELL_SIZE, 
view.cellHeight.get()));
+        flow.setFixedCellSize(GridView.getSizeValue(view.cellHeight));
         view.cellHeight .addListener(this::cellHeightChanged);
         view.cellWidth  .addListener(this::cellWidthChanged);
         view.headerWidth.addListener(this::cellWidthChanged);
         /*
          * Rectangles for filling the background of the cells in the header 
row and header column.
-         * Those rectangles will be resized when the GridView size changes or 
cells size changes.
+         * Those rectangles will be resized and relocated in `layout(…)` 
method.
          */
-        final Rectangle topBackground  = new Rectangle();
-        final Rectangle leftBackground = new Rectangle();
-        topBackground.setHeight(view.cellHeight.get());
-        leftBackground.setY(topBackground.getHeight());
-        leftBackground.widthProperty().bind(view.headerWidth);
-        leftBackground.fillProperty() .bind(view.headerBackground);
-        topBackground .fillProperty() .bind(view.headerBackground);
+        topBackground  = new Rectangle();
+        leftBackground = new Rectangle();
+        leftBackground.fillProperty().bind(view.headerBackground);
+        topBackground .fillProperty().bind(view.headerBackground);
         /*
          * The list of children is initially empty. We need to
          * add the virtual flow, otherwise nothing will appear.
          */
-        getChildren().addAll(topBackground, leftBackground, flow);
-        flow.widthProperty() .addListener(this::gridSizeChanged);
-        flow.heightProperty().addListener(this::gridSizeChanged);
+        getChildren().addAll(topBackground, leftBackground, header, flow);
     }
 
     /**
-     * Invoked when the width or height of {@link GridView} changed. This 
method recomputes the size of
-     * the rectangles used for painting backgrounds. We listen to changes in 
width and height together
-     * because a change of width may show or hide the horizontal scroll bar, 
which change the height
-     * (and conversely for the vertical scroll bar).
-     */
-    private void gridSizeChanged(ObservableValue<? extends Number> property, 
Number oldValue, Number newValue) {
-        final Flow flow = (Flow) getVirtualFlow();
-        final ObservableList<Node> children = getChildren();
-        Rectangle r;
-        r = (Rectangle) children.get(0); r.setWidth (flow.getVisibleWidth()  - 
r.getX());
-        r = (Rectangle) children.get(1); r.setHeight(flow.getVisibleHeight() - 
r.getY());
-    }
-
-    /**
-     * Invoked when the value of {@link GridView#cellHeight} property changed. 
This method copies the new value
-     * into {@link VirtualFlow#fixedCellSizeProperty()} after bounds check, 
then adjusts the size and position
-     * of rectangles filling the header background.
+     * Invoked when the value of {@link GridView#cellHeight} property changed.
+     * This method copies the new value into {@link 
VirtualFlow#fixedCellSizeProperty()} after bounds check.
      */
     private void cellHeightChanged(ObservableValue<? extends Number> property, 
Number oldValue, Number newValue) {
         final Flow flow = (Flow) getVirtualFlow();
-        final ObservableList<Node> children = getChildren();
-        final double height = Math.max(GridView.MIN_CELL_SIZE, 
newValue.doubleValue());
-        flow.setFixedCellSize(height);
-        Rectangle r;
-        r = (Rectangle) children.get(0); r.setHeight(height);
-        r = (Rectangle) children.get(1); r.setHeight(flow.getVisibleHeight() - 
height); r.setY(height);
+        final double value = newValue.doubleValue();
+        flow.setFixedCellSize(value >= GridView.MIN_CELL_SIZE ? value : 
GridView.MIN_CELL_SIZE);
     }
 
     /**
-     * Invoked when the cell width or cell spacing changed.
+     * Invoked when the cell width or header width changed.
      * This method notifies all children about the new width.
      */
     private void cellWidthChanged(ObservableValue<? extends Number> property, 
Number oldValue, Number newValue) {
@@ -125,6 +169,9 @@ final class GridViewSkin extends 
VirtualContainerBase<GridView, GridRow> {
      * may have changed including the number of rows and columns. If {@code 
all} is {@code false}
      * then the number of rows and columns is assumed the same.
      *
+     * <p>This method is invoked by {@link GridView} when the image has 
changed,
+     * or the band in the image  to show has changed.</p>
+     *
      * @see GridView#contentChanged(boolean)
      */
     final void contentChanged(final boolean all) {
@@ -150,6 +197,15 @@ final class GridViewSkin extends 
VirtualContainerBase<GridView, GridRow> {
     /**
      * The virtual flow used by {@link GridViewSkin}. We define that class
      * mostly for getting access to the protected {@link #getHbar()} method.
+     * There is two main properties that we want:
+     *
+     * <ul>
+     *   <li>{@link #getHorizontalPosition()} for the position of the 
horizontal scroll bar.</li>
+     *   <li>{@link #getWidth()} for the width of the visible region.
+     * </ul>
+     *
+     * Those two properties are used for creating the minimal amount
+     * of {@link GridCell}s needed for rendering the {@link GridRow}.
      */
     static final class Flow extends VirtualFlow<GridRow> implements 
ChangeListener<Number> {
         /**
@@ -159,8 +215,8 @@ final class GridViewSkin extends 
VirtualContainerBase<GridView, GridRow> {
         @SuppressWarnings("ThisEscapedInObjectConstruction")
         Flow(final GridView view) {
             getHbar().valueProperty().addListener(this);
-            view.bandProperty .addListener(this);
-            view.cellSpacing  .addListener(this);
+            view.bandProperty.addListener(this);
+            view.cellSpacing .addListener(this);
             // Other listeners are registered by enclosing class.
         }
 
@@ -173,19 +229,9 @@ final class GridViewSkin extends 
VirtualContainerBase<GridView, GridRow> {
         }
 
         /**
-         * Returns the width of the view port area, not counting the vertical 
scroll bar.
-         */
-        final double getVisibleWidth() {
-            double width = getWidth();
-            final ScrollBar bar = getVbar();
-            if (bar.isVisible()) {
-                width -= bar.getWidth();
-            }
-            return width;
-        }
-
-        /**
-         * Returns the height of the view port area, not counting the 
horizontal scroll bar.
+         * Returns the height of the view area, not counting the horizontal 
scroll bar.
+         * This height does not include the row header neither, because it is 
managed by
+         * a separated node ({@link #headerRow}).
          */
         final double getVisibleHeight() {
             double height = getHeight();
@@ -252,6 +298,74 @@ final class GridViewSkin extends 
VirtualContainerBase<GridView, GridRow> {
          * It does not perform any layout by itself in this method.
          */
         super.layoutChildren(x, y, width, height);
-        getVirtualFlow().resizeRelocate(x, y, width, height);
+        /*
+         * Do layout of the flow first because it may cause scroll bars to 
appear or disappear,
+         * which may change the size calculations done after that. The flow is 
located below the
+         * header row, so we adjust y and height accordingly.
+         */
+        final Flow    flow       = (Flow) getVirtualFlow();
+        final double  cellHeight = flow.getFixedCellSize();
+        final double  dataY      = y + cellHeight;
+        final double  dataHeight = height - cellHeight;
+        final boolean resized    = (flow.getWidth() != width) || 
(flow.getHeight() != dataHeight);
+        flow.resizeRelocate(x, dataY, width, dataHeight);
+        /*
+         * Recompute all values which will be needed by GridRowSkin. They are 
mostly information about
+         * the horizontal dimension, because the vertical dimension is already 
managed by VirtualFlow.
+         * We compute here for avoiding to recompute the same values in each 
GridRowSkin instance.
+         */
+        final double oldPos = leftPosition;
+        final GridView view = getSkinnable();
+        headerWidth         = GridView.getSizeValue(view.headerWidth);
+        cellWidth           = GridView.getSizeValue(view.cellWidth);
+        double cellSpacing  = Math.min(view.cellSpacing.get(), cellWidth);
+        if (!(cellSpacing  >= 0)) cellSpacing = 0;                  // Use ! 
for catching NaN (can not use Math.max).
+        cellInnerWidth      = cellWidth - cellSpacing;
+        leftPosition        = flow.getHorizontalPosition();         // 
Horizontal position in the virtual view.
+        rightPosition       = leftPosition + width;                 // 
Horizontal position where to stop.
+        firstVisibleColumn  = (int) (leftPosition / cellWidth);     // Column 
index in the RenderedImage.
+        /*
+         * Set the rectangle position before to do final adjustment on cell 
position,
+         * because the background to fill should include the `cellSpacing` 
margin.
+         */
+        topBackground .setX(x);                                     // As a 
matter of principle, but should be zero.
+        topBackground .setY(y);
+        topBackground .setWidth(width);
+        topBackground .setHeight(cellHeight);
+        leftBackground.setX(x);
+        leftBackground.setY(dataY);
+        leftBackground.setWidth(headerWidth);
+        leftBackground.setHeight(flow.getVisibleHeight());
+        if (cellSpacing < headerWidth) {
+            headerWidth  -= cellSpacing;
+            leftPosition += cellSpacing;
+        }
+        /*
+         * Reformat the row header if its content changed. It may be because a 
horizontal scroll has been
+         * detected (in which case values changed), or because the view size 
changed (in which case cells
+         * may need to be added or removed).
+         */
+        if (resized || oldPos != leftPosition) {
+            final int count   = headerRow.size();
+            final int missing = (int) Math.ceil((width - headerWidth) / 
cellWidth) - count;
+            if (missing != 0) {
+                if (missing < 0) {
+                    headerRow.remove(missing + count, count);       // Too 
many children. Remove the extra ones.
+                } else {
+                    final GridCell[] more = new GridCell[missing];
+                    for (int i=0; i<missing; i++) {
+                        more[i] = new GridCell();
+                    }
+                    headerRow.addAll(more);             // Single addAll(…) 
operation for sending only one event.
+                }
+            }
+            double pos = x + headerWidth;
+            int column = firstVisibleColumn;
+            for (final Node cell : headerRow) {
+                ((GridCell) cell).setText(view.formatHeaderValue(column++, 
false));
+                layoutInArea(cell, pos, y, cellWidth, cellHeight, 0, 
HPos.CENTER, VPos.CENTER);
+                pos += cellWidth;
+            }
+        }
     }
 }

Reply via email to