aboutsummaryrefslogtreecommitdiffstats
path: root/client/src
diff options
context:
space:
mode:
authorPatrik Lindström <patrik@vaadin.com>2014-02-11 15:36:24 +0200
committerHenrik Paul <henrik@vaadin.com>2014-02-18 15:47:40 +0000
commitd2027d8344313b048bf3b82e2a988ab40b0bb596 (patch)
treec387db0400b72af93bcb4205e241229e44a4cb29 /client/src
parent0ad5587c2f5dba0678995402dab482e81867f366 (diff)
downloadvaadin-framework-d2027d8344313b048bf3b82e2a988ab40b0bb596.tar.gz
vaadin-framework-d2027d8344313b048bf3b82e2a988ab40b0bb596.zip
Implement programmatic scrolling (#13327)
Further changes required for this, included in the same patch: - created GridClientRpc interface - created test case UI for server-side controlled Grid programmatic scrolling - refactored getScrollPos logic into Escalator and moved ScrollDestination enum to shared package Change-Id: Ibf72a4f75831807d83fb5941597a6ce3fda08e17
Diffstat (limited to 'client/src')
-rw-r--r--client/src/com/vaadin/client/ui/grid/Escalator.java143
-rw-r--r--client/src/com/vaadin/client/ui/grid/Grid.java90
-rw-r--r--client/src/com/vaadin/client/ui/grid/GridConnector.java19
-rw-r--r--client/src/com/vaadin/client/ui/grid/ScrollDestination.java102
-rw-r--r--client/src/com/vaadin/shared/ui/grid/ScrollDestination.java55
5 files changed, 250 insertions, 159 deletions
diff --git a/client/src/com/vaadin/client/ui/grid/Escalator.java b/client/src/com/vaadin/client/ui/grid/Escalator.java
index a1d895c2dd..77a8c2dbd9 100644
--- a/client/src/com/vaadin/client/ui/grid/Escalator.java
+++ b/client/src/com/vaadin/client/ui/grid/Escalator.java
@@ -52,6 +52,7 @@ import com.vaadin.client.ui.grid.PositionFunction.WebkitTranslate3DPosition;
import com.vaadin.client.ui.grid.ScrollbarBundle.HorizontalScrollbarBundle;
import com.vaadin.client.ui.grid.ScrollbarBundle.VerticalScrollbarBundle;
import com.vaadin.shared.ui.grid.Range;
+import com.vaadin.shared.ui.grid.ScrollDestination;
import com.vaadin.shared.util.SharedUtil;
/*-
@@ -548,6 +549,80 @@ public class Escalator extends Widget {
private static final int ROW_HEIGHT_PX = 20;
+ /**
+ * ScrollDestination case-specific handling logic.
+ */
+ private static double getScrollPos(final ScrollDestination destination,
+ final double targetStartPx, final double targetEndPx,
+ final double viewportStartPx, final double viewportEndPx,
+ final int padding) {
+
+ final double viewportLength = viewportEndPx - viewportStartPx;
+
+ switch (destination) {
+
+ /*
+ * Scroll as little as possible to show the target element. If the
+ * element fits into view, this works as START or END depending on the
+ * current scroll position. If the element does not fit into view, this
+ * works as START.
+ */
+ case ANY: {
+ final double startScrollPos = targetStartPx - padding;
+ final double endScrollPos = targetEndPx + padding - viewportLength;
+
+ if (startScrollPos < viewportStartPx) {
+ return startScrollPos;
+ } else if (targetEndPx + padding > viewportEndPx) {
+ return endScrollPos;
+ } else {
+ // NOOP, it's already visible
+ return viewportStartPx;
+ }
+ }
+
+ /*
+ * Scrolls so that the element is shown at the end of the viewport. The
+ * viewport will, however, not scroll before its first element.
+ */
+ case END: {
+ return targetEndPx + padding - viewportLength;
+ }
+
+ /*
+ * Scrolls so that the element is shown in the middle of the viewport.
+ * The viewport will, however, not scroll beyond its contents, given
+ * more elements than what the viewport is able to show at once. Under
+ * no circumstances will the viewport scroll before its first element.
+ */
+ case MIDDLE: {
+ final double targetMiddle = targetStartPx
+ + (targetEndPx - targetStartPx) / 2;
+ return targetMiddle - viewportLength / 2;
+ }
+
+ /*
+ * Scrolls so that the element is shown at the start of the viewport.
+ * The viewport will, however, not scroll beyond its contents.
+ */
+ case START: {
+ return targetStartPx - padding;
+ }
+
+ /*
+ * Throw an error if we're here. This can only mean that
+ * ScrollDestination has been carelessly amended..
+ */
+ default: {
+ throw new IllegalArgumentException(
+ "Internal: ScrollDestination has been modified, "
+ + "but Escalator.getScrollPos has not been updated "
+ + "to match new values.");
+ }
+ }
+
+ }
+
/** An inner class that handles all logic related to scrolling. */
private class Scroller extends JsniWorkaround {
private double lastScrollTop = 0;
@@ -900,7 +975,7 @@ public class Escalator extends Widget {
viewportEndPx -= Util.getNativeScrollbarSize();
}
- final double scrollLeft = destination.getScrollPos(targetStartPx,
+ final double scrollLeft = getScrollPos(destination, targetStartPx,
targetEndPx, viewportStartPx, viewportEndPx, padding);
/*
@@ -921,7 +996,7 @@ public class Escalator extends Widget {
final double viewportEndPx = viewportStartPx
+ body.calculateHeight();
- final double scrollTop = destination.getScrollPos(targetStartPx,
+ final double scrollTop = getScrollPos(destination, targetStartPx,
targetEndPx, viewportStartPx, viewportEndPx, padding);
/*
@@ -3307,33 +3382,6 @@ public class Escalator extends Widget {
/**
* Scrolls the body horizontally so that the column at the given index is
- * visible.
- *
- * @param columnIndex
- * the index of the column to scroll to
- * @param destination
- * where the column should be aligned visually after scrolling
- * @throws IndexOutOfBoundsException
- * if {@code columnIndex} is not a valid index for an existing
- * column
- * @throws IllegalArgumentException
- * if the column is frozen
- */
- public void scrollToColumn(final int columnIndex,
- final ScrollDestination destination)
- throws IndexOutOfBoundsException, IllegalArgumentException {
- verifyValidColumnIndex(columnIndex);
-
- if (columnIndex < columnConfiguration.frozenColumns) {
- throw new IllegalArgumentException("The given column index "
- + columnIndex + " is frozen.");
- }
-
- scroller.scrollToColumn(columnIndex, destination, 0);
- }
-
- /**
- * Scrolls the body horizontally so that the column at the given index is
* visible and there is at least {@code padding} pixels to the given scroll
* destination.
*
@@ -3348,14 +3396,15 @@ public class Escalator extends Widget {
* if {@code columnIndex} is not a valid index for an existing
* column
* @throws IllegalArgumentException
- * if {@code destination} is {@link ScrollDestination#MIDDLE},
- * because having a padding on a centered column is undefined
- * behavior or if the column is frozen
+ * if {@code destination} is {@link ScrollDestination#MIDDLE}
+ * and padding is nonzero, because having a padding on a
+ * centered column is undefined behavior, or if the column is
+ * frozen
*/
public void scrollToColumn(final int columnIndex,
final ScrollDestination destination, final int padding)
throws IndexOutOfBoundsException, IllegalArgumentException {
- if (destination == ScrollDestination.MIDDLE) {
+ if (destination == ScrollDestination.MIDDLE && padding != 0) {
throw new IllegalArgumentException(
"You cannot have a padding with a MIDDLE destination");
}
@@ -3379,26 +3428,6 @@ public class Escalator extends Widget {
}
/**
- * Scrolls the body vertically so that the row at the given index is
- * visible.
- *
- * @param rowIndex
- * the index of the row to scroll to
- * @param destination
- * where the row should be aligned visually after scrolling
- * @throws IndexOutOfBoundsException
- * if {@code rowIndex} is not a valid index for an existing
- * logical row
- */
- public void scrollToRow(final int rowIndex,
- final ScrollDestination destination)
- throws IndexOutOfBoundsException {
- verifyValidRowIndex(rowIndex);
-
- scroller.scrollToRow(rowIndex, destination, 0);
- }
-
- /**
* Scrolls the body vertically so that the row at the given index is visible
* and there is at least {@literal padding} pixels to the given scroll
* destination.
@@ -3413,14 +3442,14 @@ public class Escalator extends Widget {
* @throws IndexOutOfBoundsException
* if {@code rowIndex} is not a valid index for an existing row
* @throws IllegalArgumentException
- * if {@code destination} is {@link ScrollDestination#MIDDLE},
- * because having a padding on a centered row is undefined
- * behavior
+ * if {@code destination} is {@link ScrollDestination#MIDDLE}
+ * and padding is nonzero, because having a padding on a
+ * centered row is undefined behavior
*/
public void scrollToRow(final int rowIndex,
final ScrollDestination destination, final int padding)
throws IndexOutOfBoundsException, IllegalArgumentException {
- if (destination == ScrollDestination.MIDDLE) {
+ if (destination == ScrollDestination.MIDDLE && padding != 0) {
throw new IllegalArgumentException(
"You cannot have a padding with a MIDDLE destination");
}
diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java
index 015028765b..02aa194655 100644
--- a/client/src/com/vaadin/client/ui/grid/Grid.java
+++ b/client/src/com/vaadin/client/ui/grid/Grid.java
@@ -18,6 +18,7 @@ package com.vaadin.client.ui.grid;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.logging.Logger;
import com.google.gwt.core.shared.GWT;
import com.google.gwt.dom.client.Element;
@@ -28,6 +29,8 @@ import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.data.DataChangeHandler;
import com.vaadin.client.data.DataSource;
import com.vaadin.client.ui.grid.renderers.TextRenderer;
+import com.vaadin.shared.ui.grid.GridConstants;
+import com.vaadin.shared.ui.grid.ScrollDestination;
import com.vaadin.shared.util.SharedUtil;
/**
@@ -1225,4 +1228,91 @@ public class Grid<T> extends Composite {
*/
return escalator.addRowVisibilityChangeHandler(handler);
}
+
+ /**
+ * Scrolls to a certain row, using {@link ScrollDestination#ANY}.
+ *
+ * @param rowIndex
+ * zero-based index of the row to scroll to.
+ * @throws IllegalArgumentException
+ * if rowIndex is below zero, or above the maximum value
+ * supported by the data source.
+ */
+ public void scrollToRow(int rowIndex) throws IllegalArgumentException {
+ scrollToRow(rowIndex, ScrollDestination.ANY,
+ GridConstants.DEFAULT_PADDING);
+ }
+
+ /**
+ * Scrolls to a certain row, using user-specified scroll destination.
+ *
+ * @param rowIndex
+ * zero-based index of the row to scroll to.
+ * @param destination
+ * desired destination placement of scrolled-to-row. See
+ * {@link ScrollDestination} for more information.
+ * @throws IllegalArgumentException
+ * if rowIndex is below zero, or above the maximum value
+ * supported by the data source.
+ */
+ public void scrollToRow(int rowIndex, ScrollDestination destination)
+ throws IllegalArgumentException {
+ scrollToRow(rowIndex, destination,
+ destination == ScrollDestination.MIDDLE ? 0
+ : GridConstants.DEFAULT_PADDING);
+ }
+
+ /**
+ * Scrolls to a certain row using only user-specified parameters.
+ *
+ * @param rowIndex
+ * zero-based index of the row to scroll to.
+ * @param destination
+ * desired destination placement of scrolled-to-row. See
+ * {@link ScrollDestination} for more information.
+ * @param paddingPx
+ * number of pixels to overscroll. Behavior depends on
+ * destination.
+ * @throws IllegalArgumentException
+ * if {@code destination} is {@link ScrollDestination#MIDDLE}
+ * and padding is nonzero, because having a padding on a
+ * centered row is undefined behavior, or if rowIndex is below
+ * zero or above the row count of the data source.
+ */
+ private void scrollToRow(int rowIndex, ScrollDestination destination,
+ int paddingPx) throws IllegalArgumentException {
+ int maxsize = escalator.getBody().getRowCount() - 1;
+
+ if (rowIndex < 0) {
+ throw new IllegalArgumentException("Row index (" + rowIndex
+ + ") is below zero!");
+ }
+
+ if (rowIndex > maxsize) {
+ throw new IllegalArgumentException("Row index (" + rowIndex
+ + ") is above maximum (" + maxsize + ")!");
+ }
+
+ escalator.scrollToRow(rowIndex, destination, paddingPx);
+ }
+
+ /**
+ * Scrolls to the beginning of the very first row.
+ */
+ public void scrollToStart() {
+ scrollToRow(0, ScrollDestination.START);
+ }
+
+ /**
+ * Scrolls to the end of the very last row.
+ */
+ public void scrollToEnd() {
+ scrollToRow(escalator.getBody().getRowCount() - 1,
+ ScrollDestination.END);
+ }
+
+ private static final Logger getLogger() {
+ return Logger.getLogger(Grid.class.getName());
+ }
+
}
diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java
index f04326c7e6..5e0664667d 100644
--- a/client/src/com/vaadin/client/ui/grid/GridConnector.java
+++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java
@@ -29,9 +29,11 @@ import com.vaadin.client.ui.AbstractComponentConnector;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.grid.ColumnGroupRowState;
import com.vaadin.shared.ui.grid.ColumnGroupState;
+import com.vaadin.shared.ui.grid.GridClientRpc;
import com.vaadin.shared.ui.grid.GridColumnState;
import com.vaadin.shared.ui.grid.GridServerRpc;
import com.vaadin.shared.ui.grid.GridState;
+import com.vaadin.shared.ui.grid.ScrollDestination;
/**
* Connects the client side {@link Grid} widget with the server side
@@ -96,6 +98,23 @@ public class GridConnector extends AbstractComponentConnector {
event.getVisibleRowCount());
}
});
+
+ registerRpc(GridClientRpc.class, new GridClientRpc() {
+ @Override
+ public void scrollToStart() {
+ getWidget().scrollToStart();
+ }
+
+ @Override
+ public void scrollToEnd() {
+ getWidget().scrollToEnd();
+ }
+
+ @Override
+ public void scrollToRow(int row, ScrollDestination destination) {
+ getWidget().scrollToRow(row, destination);
+ }
+ });
}
@Override
diff --git a/client/src/com/vaadin/client/ui/grid/ScrollDestination.java b/client/src/com/vaadin/client/ui/grid/ScrollDestination.java
deleted file mode 100644
index e14f50ff7c..0000000000
--- a/client/src/com/vaadin/client/ui/grid/ScrollDestination.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2000-2013 Vaadin Ltd.
- *
- * Licensed 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 com.vaadin.client.ui.grid;
-
-/**
- * The destinations that are supported in an Escalator when scrolling rows or
- * columns into view.
- *
- * @since 7.2
- * @author Vaadin Ltd
- */
-public enum ScrollDestination {
-
- /**
- * Scroll as little as possible to show the target element. If the element
- * fits into view, this works as START or END depending on the current
- * scroll position. If the element does not fit into view, this works as
- * START.
- */
- ANY {
- @Override
- double getScrollPos(final double targetStartPx,
- final double targetEndPx, final double viewportStartPx,
- final double viewportEndPx, final int padding) {
-
- final double startScrollPos = targetStartPx - padding;
- final double viewportLength = viewportEndPx - viewportStartPx;
- final double endScrollPos = targetEndPx + padding - viewportLength;
-
- if (startScrollPos < viewportStartPx) {
- return startScrollPos;
- } else if (targetEndPx + padding > viewportEndPx) {
- return endScrollPos;
- } else {
- // NOOP, it's already visible
- return viewportStartPx;
- }
- }
- },
-
- /**
- * Scrolls so that the element is shown at the start of the viewport. The
- * viewport will, however, not scroll beyond its contents.
- */
- START {
- @Override
- double getScrollPos(final double targetStartPx,
- final double targetEndPx, final double viewportStartPx,
- final double viewportEndPx, final int padding) {
- return targetStartPx - padding;
- }
- },
-
- /**
- * Scrolls so that the element is shown in the middle of the viewport. The
- * viewport will, however, not scroll beyond its contents, given more
- * elements than what the viewport is able to show at once. Under no
- * circumstances will the viewport scroll before its first element.
- */
- MIDDLE {
- @Override
- double getScrollPos(final double targetStartPx,
- final double targetEndPx, final double viewportStartPx,
- final double viewportEndPx, final int padding) {
- final double targetMiddle = targetStartPx
- + (targetEndPx - targetStartPx) / 2;
- final double viewportLength = viewportEndPx - viewportStartPx;
- return targetMiddle - viewportLength / 2;
- }
- },
-
- /**
- * Scrolls so that the element is shown at the end of the viewport. The
- * viewport will, however, not scroll before its first element.
- */
- END {
- @Override
- double getScrollPos(final double targetStartPx,
- final double targetEndPx, final double viewportStartPx,
- final double viewportEndPx, final int padding) {
- final double viewportLength = viewportEndPx - viewportStartPx;
- return targetEndPx + padding - viewportLength;
- }
- };
-
- abstract double getScrollPos(final double targetStartPx,
- final double targetEndPx, final double viewportStartPx,
- final double viewportEndPx, final int padding);
-}
diff --git a/client/src/com/vaadin/shared/ui/grid/ScrollDestination.java b/client/src/com/vaadin/shared/ui/grid/ScrollDestination.java
new file mode 100644
index 0000000000..decc2fab5f
--- /dev/null
+++ b/client/src/com/vaadin/shared/ui/grid/ScrollDestination.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed 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 com.vaadin.shared.ui.grid;
+
+/**
+ * Enumeration, specifying the destinations that are supported when scrolling
+ * rows or columns into view.
+ *
+ * @since 7.2
+ * @author Vaadin Ltd
+ */
+public enum ScrollDestination {
+
+ /**
+ * Scroll as little as possible to show the target element. If the element
+ * fits into view, this works as START or END depending on the current
+ * scroll position. If the element does not fit into view, this works as
+ * START.
+ */
+ ANY,
+
+ /**
+ * Scrolls so that the element is shown at the start of the viewport. The
+ * viewport will, however, not scroll beyond its contents.
+ */
+ START,
+
+ /**
+ * Scrolls so that the element is shown in the middle of the viewport. The
+ * viewport will, however, not scroll beyond its contents, given more
+ * elements than what the viewport is able to show at once. Under no
+ * circumstances will the viewport scroll before its first element.
+ */
+ MIDDLE,
+
+ /**
+ * Scrolls so that the element is shown at the end of the viewport. The
+ * viewport will, however, not scroll before its first element.
+ */
+ END
+
+}