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 a70927e Fix numerous problems in the initial GridView implementation
(horizontal scroll bar was not visible, too many GridCell nodes were created,
etc.)
a70927e is described below
commit a70927efb3c9e19ac7320a5497cae673b0189cc1
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Thu Jan 23 18:53:43 2020 +0100
Fix numerous problems in the initial GridView implementation (horizontal
scroll bar was not visible, too many GridCell nodes were created, etc.)
---
.../java/org/apache/sis/gui/coverage/GridCell.java | 19 ++-
.../org/apache/sis/gui/coverage/GridCellSkin.java | 38 ------
.../java/org/apache/sis/gui/coverage/GridRow.java | 28 ++++-
.../org/apache/sis/gui/coverage/GridRowSkin.java | 69 ++++++++---
.../java/org/apache/sis/gui/coverage/GridView.java | 128 +++++++++++++++++----
.../org/apache/sis/gui/coverage/GridViewSkin.java | 103 ++++++++++++++---
.../org/apache/sis/gui/coverage/package-info.java | 2 +-
7 files changed, 276 insertions(+), 111 deletions(-)
diff --git
a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridCell.java
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridCell.java
index 2e84044..7955e8e 100644
---
a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridCell.java
+++
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridCell.java
@@ -18,6 +18,7 @@ package org.apache.sis.gui.coverage;
import javafx.scene.control.IndexedCell;
import javafx.scene.control.Skin;
+import javafx.scene.control.skin.CellSkinBase;
/**
@@ -28,7 +29,7 @@ import javafx.scene.control.Skin;
* @since 1.1
* @module
*/
-final class GridCell extends IndexedCell<Number> {
+final class GridCell extends IndexedCell<String> {
/**
* Creates a new cell.
*/
@@ -47,17 +48,14 @@ final class GridCell extends IndexedCell<Number> {
* It may happen if the image is still loading in a background thread.
*
* @param value the sample value, or {@code null} if not available.
- * @param empty whether this cell is used for filling empty space.
+ * @param empty whether this cell is used for filling empty space
+ * (not to be confused with value not yet available).
*/
@Override
- protected void updateItem(final Number value, final boolean empty) {
+ protected void updateItem(String value, final boolean empty) {
super.updateItem(value, empty);
- if (empty) {
- setText("");
- } else {
- // TODO: format the value.
- setText(String.valueOf(value));
- }
+ if (value == null) value = "";
+ setText(value);
}
/**
@@ -69,6 +67,7 @@ final class GridCell extends IndexedCell<Number> {
*/
@Override
protected Skin<GridCell> createDefaultSkin() {
- return new GridCellSkin(this);
+ // We have nothing to add compared to the base implementation.
+ return new CellSkinBase<>(this);
}
}
diff --git
a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridCellSkin.java
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridCellSkin.java
deleted file mode 100644
index 9c25f1b..0000000
---
a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridCellSkin.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.sis.gui.coverage;
-
-import javafx.scene.control.skin.CellSkinBase;
-
-
-/**
- * The renderer of {@link GridCell} instances.
- * Contains only one child, which is an instance of {@link
javafx.scene.text.Text}.
- *
- * @author Martin Desruisseaux (Geomatys)
- * @version 1.1
- * @since 1.1
- * @module
- */
-final class GridCellSkin extends CellSkinBase<GridCell> {
- /**
- * Creates a new renderer for the specified cell.
- */
- GridCellSkin(final GridCell view) {
- super(view);
- }
-}
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 65abcd0..9b17b0b 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
@@ -40,14 +40,29 @@ import javafx.scene.control.skin.VirtualFlow;
*/
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.
*/
- private final GridView view;
+ final GridView view;
/**
* The arbitrary-based <var>y</var> coordinate in the image. This is not
necessarily the {@code row}
* index in the table since {@link RenderedImage} coordinate system do not
necessarily starts at zero.
- * This value may be outside image bounds, in which case this row should
be rendered as empty.
+ * This value may be outside image bounds, in which case this {@code
GridRow} should be rendered as empty.
*/
private int y;
@@ -63,14 +78,15 @@ 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());
}
/**
* Invoked when this {@code GridRow} is used for showing a new image row.
- * We override this method as an alternative to registering a listener to
{@link #indexProperty()}
- * (for reducing the number of object allocations). This method
{@linkplain #setItem set the item}
- * to the information required for getting pixel values on that row.
+ * We override this method as an alternative to registering a listener to
+ * {@link #indexProperty()} (for reducing the number of object
allocations).
*
* @param row index of the new row.
*/
@@ -89,7 +105,7 @@ final class GridRow extends IndexedCell<Void> {
* @param column zero-based <var>x</var> coordinate of sample to get
(may differ from image coordinate).
* @return the sample value in the specified column, or {@code null} if
not yet available.
*/
- final Number getSampleValue(final int column) {
+ final String getSampleValue(final int column) {
return view.getSampleValue(y, tileRow, 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 94277f3..bd54c0f 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
@@ -16,6 +16,8 @@
*/
package org.apache.sis.gui.coverage;
+import java.util.List;
+import java.util.ArrayList;
import javafx.scene.Node;
import javafx.scene.control.skin.CellSkinBase;
import javafx.collections.ObservableList;
@@ -49,10 +51,16 @@ final class GridRowSkin extends CellSkinBase<GridRow> {
* and to modify text values here, but I have not identified another place
yet. However the
* JavaFX implementation of table skin seems to do the same, so I presume
it is okay.</div>
*
+ * The {@code width} argument can be a large number (for example 24000)
because it includes
+ * the area outside the view. In order to avoid creating a large amount of
{@link GridCell}
+ * instances, this method have to find the current view port area and
render only the cells
+ * in that area. We do not have to do that vertically because the vertical
virtualization
+ * is done by {@link GridViewSkin} parent class.
+ *
* @param x the <var>x</var> position of this row, usually 0.
* @param y the <var>y</var> position of this row, usually 0 (this
is a relative position).
- * @param width width of the region where to render this row (for
example 400).
- * @param height height of the region where to render this row (for
example 400).
+ * @param width width of the row, including the area currently hidden
because out of view.
+ * @param height height of the region where to render this row (for
example 16).
*/
@Override
protected void layoutChildren(final double x, final double y, final double
width, final double height) {
@@ -62,25 +70,52 @@ final class GridRowSkin extends CellSkinBase<GridRow> {
*/
final GridRow row = getSkinnable();
final ObservableList<Node> children = getChildren();
- ((Text) children.get(0)).setText(String.valueOf(row.getIndex()));
+ final Text header = (Text) children.get(0);
+ header.setText(String.valueOf(row.getIndex())); // TODO: format
/*
- * All children starting at index 1 (i.e. children at indices `column
+ 1`)
- * shall be GridCell instances created in this method.
+ * 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
+ * whole row since it would be too many cells (can be millions).
Instead we recycle the cells
+ * 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.
*/
- int column = 0;
- double xc = GridView.cellWidth;
- while (xc < width) {
- final GridCell child;
- if (++column < children.size()) {
- child = (GridCell) children.get(column);
+ 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();
+ final double limit = pos + row.flow.getWidth();
+ int column = (int) (pos / cellWidth);
+ int childIndex = 0;
+ List<GridCell> newChildren = null;
+ header.resizeRelocate(pos, y, headerWidth, height);
+ pos += headerWidth;
+ final int count = children.size();
+ while (pos < limit) {
+ final GridCell cell;
+ if (++childIndex < count) {
+ cell = (GridCell) children.get(childIndex);
} else {
- child = new GridCell();
- children.add(child);
+ cell = new GridCell();
+ if (newChildren == null) {
+ newChildren = new ArrayList<>(1 + (int) ((limit - pos) /
cellWidth));
+ }
+ newChildren.add(cell);
}
- final Number value = row.getSampleValue(column);
- child.updateItem(value, value == null); // TODO: difference
between "empty" and "still loading".
- child.resizeRelocate(xc + GridView.horizontalCellSpacing, 0,
GridView.cellWidth, height);
- xc += GridView.cellWidth + 2*GridView.horizontalCellSpacing;
+ final String value = row.getSampleValue(column++);
+ cell.updateItem(value, value == GridView.OUT_OF_BOUNDS);
// Identity comparison is okay here.
+ cell.resizeRelocate(pos + cellSpacing, 0, available, height);
+ pos += cellWidth;
+ }
+ /*
+ * Add or remove fields only at the end of this method in order to
fire only one change event.
+ * It is important to remove unused fields not only for saving memory,
but also for preventing
+ * those fields to appear at random positions in the rendered region.
+ */
+ if (newChildren != null) {
+ children.addAll(newChildren);
+ } else if (++childIndex < count) {
+ children.remove(childIndex, count);
}
}
}
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 169721b..598b169 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
@@ -19,14 +19,18 @@ package org.apache.sis.gui.coverage;
import java.util.Arrays;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
+import java.awt.image.SampleModel;
import javafx.beans.DefaultProperty;
+import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.Control;
import javafx.scene.control.Skin;
+import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.coverage.grid.GridCoverage;
@@ -47,9 +51,15 @@ import org.apache.sis.coverage.grid.GridCoverage;
*/
@DefaultProperty("image")
public class GridView extends Control {
- /** TODO: temporary setting. */
- static final double cellWidth = 60;
- static final double horizontalCellSpacing = 2;
+ /**
+ * Minimum cell width and height.
+ */
+ static final int MIN_CELL_SIZE = 1;
+
+ /**
+ * The string value for sample values that are out of image bounds.
+ */
+ static final String OUT_OF_BOUNDS = "";
/**
* The data shown in this table. Note that setting this property to a
non-null value may not
@@ -82,6 +92,7 @@ public class GridView extends Control {
/**
* The image band to show in the table.
+ * It should be a number between 0 inclusive and {@link
SampleModel#getNumBands()} exclusive.
*
* @see #getBand()
* @see #setBand(int)
@@ -89,14 +100,62 @@ public class GridView extends Control {
public final IntegerProperty bandProperty;
/**
- * Creates an initially empty grid view. The content can be set after
construction by a call
- * to {@link #setImage(RenderedImage)}.
+ * Width of header cells to be shown in the first column.
+ * The first (header) column contains the row indices, or sometime the
coordinate values.
+ * This size includes the {@linkplain #cellSpacing cell spacing}.
+ * It shall be a number strictly greater than zero.
+ *
+ * <p>We do not define getter/setter for this property; use {@link
DoubleProperty#set(double)}
+ * directly instead. We omit the "Property" suffix for making this
operation more natural.</p>
+ */
+ public final DoubleProperty headerWidth;
+
+ /**
+ * Width of data cell to be shown in other columns than the header column.
+ * This size includes the {@linkplain #cellSpacing cell spacing}.
+ * It shall be a number strictly greater than zero.
+ *
+ * <p>We do not define getter/setter for this property; use {@link
DoubleProperty#set(double)}
+ * directly instead. We omit the "Property" suffix for making this
operation more natural.</p>
+ */
+ public final DoubleProperty cellWidth;
+
+ /**
+ * Height of all rows in the grid.
+ * It shall be a number strictly greater than zero.
+ *
+ * <p>We do not define getter/setter for this property; use {@link
DoubleProperty#set(double)}
+ * directly instead. We omit the "Property" suffix for making this
operation more natural.</p>
+ */
+ public final DoubleProperty cellHeight;
+
+ /**
+ * Horizontal space between cells, as a number equals or greater than zero.
+ * There is no property for vertical cell spacing because increasing the
+ * {@linkplain #cellHeight cell height} should be sufficient.
+ *
+ * <p>We do not define getter/setter for this property; use {@link
DoubleProperty#set(double)}
+ * directly instead. We omit the "Property" suffix for making this
operation more natural.</p>
+ */
+ public final DoubleProperty cellSpacing;
+
+ /**
+ * Creates an initially empty grid view. The content can be set after
+ * construction by a call to {@link #setImage(RenderedImage)}.
*/
public GridView() {
imageProperty = new SimpleObjectProperty<>(this, "image");
+ bandProperty = new SimpleIntegerProperty (this, "band");
+ headerWidth = new SimpleDoubleProperty (this, "headerWidth", 60);
+ cellWidth = new SimpleDoubleProperty (this, "cellWidth", 60);
+ cellHeight = new SimpleDoubleProperty (this, "cellHeight", 20);
+ cellSpacing = new SimpleDoubleProperty (this, "cellSpacing", 2);
+
imageProperty.addListener(this::startImageLoading);
- bandProperty = new SimpleIntegerProperty(this, "band");
- // TODO: add listener. Check value range.
+ // Other listeners registered by GridViewSkin.Flow.
+
+ tileWidth = 1;
+ tileHeight = 1; // For avoiding division by zero.
}
/**
@@ -127,9 +186,9 @@ public class GridView extends Control {
}
/**
- * Returns the number of the band shown in this grid view.
+ * Returns the index of the band shown in this grid view.
*
- * @return the currently visible band number.
+ * @return index of the currently visible band number.
*
* @see #bandProperty
*/
@@ -141,10 +200,17 @@ public class GridView extends Control {
* Sets the number of the band to show in this grid view.
* This value should be from 0 (inclusive) to the number of bands in the
image (exclusive).
*
- * @param visible the band to make visible.
+ * @param index the band to make visible.
+ * @throws IllegalArgumentException if the given band index is out of
bounds.
*/
- public final void setBand(final int visible) {
- bandProperty.set(visible);
+ public final void setBand(final int index) {
+ final RenderedImage image = getImage();
+ if (image != null) {
+ ArgumentChecks.ensureBetween("band", 0,
image.getSampleModel().getNumBands() - 1, index);
+ } else {
+ ArgumentChecks.ensurePositive("band", index);
+ }
+ bandProperty.set(index);
}
/**
@@ -176,14 +242,26 @@ public class GridView extends Control {
tileGridYOffset = Math.toIntExact(((long)
image.getTileGridYOffset()) - minY + ((long) tileHeight) * minTileY);
numXTiles = image.getNumXTiles();
tiles = new Raster[image.getNumYTiles()][];
- final int numBands = image.getSampleModel().getNumBands();
- if (bandProperty.get() > numBands) {
- bandProperty.set(numBands - 1);
+ final int n = image.getSampleModel().getNumBands();
+ if (bandProperty.get() >= n) {
+ bandProperty.set(n - 1);
+ }
+ final Skin<?> skin = getSkin();
+ if (skin instanceof GridViewSkin) {
+ ((GridViewSkin) skin).updateItemCount();
}
}
}
/**
+ * 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.
+ */
+ final double getContentWidth() {
+ return width * Math.max(MIN_CELL_SIZE, cellWidth.get()) +
Math.max(MIN_CELL_SIZE, headerWidth.get());
+ }
+
+ /**
* Returns the number of rows in the image. This is also the number of
rows in the
* {@link GridViewSkin} virtual flow, which is using a vertical primary
direction.
*/
@@ -218,18 +296,19 @@ public class GridView extends Control {
* be refreshed when the tile become available.
*
* <p>The {@code y} parameter is computed by {@link #toImageY(int)} and
the {@code tileRow} parameter
- * is computed by {@link #toTileRow(int)}. Those values are stored in
{@link GridRow}.
+ * is computed by {@link #toTileRow(int)}. Those values are stored in
{@link GridRow}.</p>
*
* @param y arbitrary-based <var>y</var> coordinate in the image
(may differ from table {@code row}).
* @param tileRow zero-based <var>y</var> coordinate of the tile (may
differ from image tile Y).
* @param column zero-based <var>x</var> coordinate of sample to get
(may differ from image coordinate X).
- * @return the sample value in the specified column, or {@code null} if
out of bounds or not yet available.
- * @throws ArithmeticException if an index is too large.
+ * @return the sample value in the specified column, or {@code null} if
unknown (because the loading process
+ * is still under progress), or the empty string ({@code ""}) if
out of bounds.
+ * @throws ArithmeticException if an index is too large for the 32 bits
integer capacity.
*
* @see GridRow#getSampleValue(int)
*/
- final Number getSampleValue(final int y, final int tileRow, final int
column) {
- if (y >= 0 && y < height && column > 0 && column < width) {
+ final String getSampleValue(final int y, final int tileRow, final int
column) {
+ if (y >= 0 && y < height && column >= 0 && column < width) {
final int tx = Math.subtractExact(column, tileGridXOffset) /
tileWidth;
Raster[] row = tiles[tileRow];
if (row == null) {
@@ -239,16 +318,19 @@ public class GridView extends Control {
}
Raster tile = row[tx];
if (tile == null) {
- // TODO: load in background
+ // TODO: load in background and return null for meaning "not
yet available".
tile = getImage().getTile(Math.addExact(tx, minTileX),
Math.addExact(tileRow, minTileY));
row[tx] = tile;
}
final int x = Math.addExact(column, minX);
final int b = getBand();
- return tile.getSampleDouble(x, y, b);
+ final Number value;
// TODO: also return Float or Integer.
+ value = tile.getSampleDouble(x, y, b);
+ // TODO: format.
+ return value.toString();
}
- return null;
+ return OUT_OF_BOUNDS;
}
/**
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 a0825e6..7f88e60 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
@@ -17,8 +17,11 @@
package org.apache.sis.gui.coverage;
import java.awt.image.RenderedImage;
-import javafx.scene.control.skin.VirtualContainerBase;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.scene.Node;
import javafx.scene.control.skin.VirtualFlow;
+import javafx.scene.control.skin.VirtualContainerBase;
/**
@@ -28,7 +31,10 @@ import javafx.scene.control.skin.VirtualFlow;
* <p>Relationships:</p>
* <ul>
* <li>This is created by {@link GridView#createDefaultSkin()}.</li>
- * <li>The {@link GridView} owner is given by {@link #getSkinnable()}.</li>
+ * <li>The {@link GridView} which own this skin is given by {@link
#getSkinnable()}.</li>
+ * <li>This {@code GridViewSkin} contains an arbitrary amount of {@link
GridRow} children.
+ * It should be limited to the number of children that are visible in
same time,
+ * not the total number of rows in the image.</li>
* </ul>
*
* @author Martin Desruisseaux (Geomatys)
@@ -45,7 +51,10 @@ final class GridViewSkin extends
VirtualContainerBase<GridView, GridRow> {
final VirtualFlow<GridRow> flow = getVirtualFlow();
flow.setCellFactory(GridRow::new);
flow.setFocusTraversable(true);
- flow.setPannable(false);
+ flow.setFixedCellSize(Math.max(GridView.MIN_CELL_SIZE,
view.cellHeight.get()));
+ view.cellHeight .addListener(this::cellHeightChanged);
+ view.cellWidth .addListener(this::cellWidthChanged);
+ view.headerWidth.addListener(this::cellWidthChanged);
/*
* The list of children is initially empty. We need to
* add the virtual flow, otherwise nothing will appear.
@@ -53,20 +62,76 @@ final class GridViewSkin extends
VirtualContainerBase<GridView, GridRow> {
getChildren().add(flow);
}
- /*
- * TODO:
- * VirtualFlow.setFixedCellSize​(double): For optimisation purposes, some
use cases can trade
- * dynamic cell length for speed. If fixedCellSize is greater than zero
JavaFX uses that rather
- * than determining it by querying the cell itself.
+ /**
+ * Invoked when the value of {@link GridView#cellHeight} property changed.
*/
+ private void cellHeightChanged(ObservableValue<? extends Number> property,
Number oldValue, Number newValue) {
+ getVirtualFlow().setFixedCellSize(Math.max(GridView.MIN_CELL_SIZE,
newValue.intValue()));
+ }
/**
- * Returns the total number of image rows, including those that are
currently hidden because
- * they are out of view. The returned value is (indirectly) {@link
RenderedImage#getHeight()}.
+ * Invoked when the cell width or cell spacing changed. This method
notifies all children of the new width.
+ */
+ private void cellWidthChanged(ObservableValue<? extends Number> property,
Number oldValue, Number newValue) {
+ final double width = getSkinnable().getContentWidth();
+ for (final Node child : getChildren()) {
+ if (child instanceof GridRow) { // The first instance
if not a GridRow.
+ ((GridRow) child).setPrefWidth(width);
+ }
+ }
+ }
+
+ /**
+ * Creates the virtual flow used by this {@link GridViewSkin}. The virtual
flow
+ * created by this method registers a listener for horizontal scroll bar
events.
*/
@Override
- public int getItemCount() {
- return getSkinnable().getImageHeight();
+ protected VirtualFlow<GridRow> createVirtualFlow() {
+ return new Flow(getSkinnable());
+ }
+
+ /**
+ * The virtual flow used by {@link GridViewSkin}. We define that class
+ * mostly for getting access to the protected {@link #getHbar()} method.
+ */
+ static final class Flow extends VirtualFlow<GridRow> implements
ChangeListener<Number> {
+ /**
+ * Creates a new flow for the given view. This method registers
listeners
+ * on the properties that may require a redrawn of the full view port.
+ */
+ @SuppressWarnings("ThisEscapedInObjectConstruction")
+ Flow(final GridView view) {
+ getHbar().valueProperty().addListener(this);
+ view.bandProperty .addListener(this);
+ view.cellSpacing .addListener(this);
+ // Other listeners are registered by enclosing class.
+ }
+
+ /**
+ * The position of the horizontal scroll bar. This is a value between
0 and
+ * the width that the {@link GridView} would have if we were showing
it fully.
+ */
+ final double getHorizontalPosition() {
+ return getHbar().getValue();
+ }
+
+ /**
+ * Invoked when the content to show changed because of a change in a
property.
+ * The most important event is a change in the position of horizontal
scroll bar,
+ * which is handled as a change of content because we will need to
change values
+ * shown by the cells (because we reuse a small number of cells in
visible region).
+ * But this method is also invoked for real changes of content like
changes in the
+ * index of the band to show, provided that the number of rows and
columns is the same.
+ *
+ * @param property the property that changed (ignored).
+ * @param oldValue the old value (ignored).
+ * @param newValue the new value (ignored).
+ */
+ @Override
+ public void changed(ObservableValue<? extends Number> property, Number
oldValue, Number newValue) {
+ // Inform VirtualFlow that a layout pass should be done, but no
GridRows have been added or removed.
+ reconfigureCells();
+ }
}
/**
@@ -80,13 +145,19 @@ final class GridViewSkin extends
VirtualContainerBase<GridView, GridRow> {
* VirtualFlow.setCellCount(int) indicates the number of cells that
should be in the flow.
* When the cell count changes, VirtualFlow responds by updating the
visuals. If the items
* backing the cells change but the count has not changed, then
reconfigureCells() should
- * be invoked instead.
+ * be invoked instead. This is done by the `Flow` inner class above.
*/
- final VirtualFlow<GridRow> flow = getVirtualFlow();
- flow.setCellCount(getItemCount()); // Fires event
only if count changed.
+ getVirtualFlow().setCellCount(getItemCount()); // Fires event
only if count changed.
}
- // TODO: to update content, invoke getSkinnable().requestLayout().
+ /**
+ * Returns the total number of image rows, including those that are
currently hidden because
+ * they are out of view. The returned value is (indirectly) {@link
RenderedImage#getHeight()}.
+ */
+ @Override
+ public int getItemCount() {
+ return getSkinnable().getImageHeight();
+ }
/**
* Called during the layout pass of the scene graph. Current
implementation sets the virtual
diff --git
a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/package-info.java
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/package-info.java
index fa108e3..7492013 100644
---
a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/package-info.java
+++
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/package-info.java
@@ -16,7 +16,7 @@
*/
/**
- * Widgets showing {@link org.apache.sis.coverage.grid.GridCoverage} images or
values.
+ * Widgets showing {@link org.apache.sis.coverage.grid.GridCoverage} images or
sample values.
*
* @author Martin Desruisseaux (Geomatys)
* @version 1.1