summaryrefslogtreecommitdiffstats
path: root/src/com
diff options
context:
space:
mode:
authorMatti Tahvonen <matti.tahvonen@itmill.com>2010-09-03 14:54:50 +0000
committerMatti Tahvonen <matti.tahvonen@itmill.com>2010-09-03 14:54:50 +0000
commita28defb307f38d987a7735331f4bb7d8494bc92c (patch)
tree4ebed7179ff71ae594af075d5691b8da64d01b88 /src/com
parentbfd1816dc28e09a492697125b9b3b9e97b730d62 (diff)
downloadvaadin-framework-a28defb307f38d987a7735331f4bb7d8494bc92c.tar.gz
vaadin-framework-a28defb307f38d987a7735331f4bb7d8494bc92c.zip
refactored pagedown/up and home/end navigation, should fix excessive server visits and some other related issues. Note, tested only on Safari/mac atm.
svn changeset:14713/svn branch:6.4
Diffstat (limited to 'src/com')
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java291
1 files changed, 203 insertions, 88 deletions
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java
index 1120c5cf1d..59ac999692 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java
@@ -842,29 +842,26 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
selectionChanged = false;
}
- // This is called when the Home button has been pressed and the pages
- // changes
- if (selectFirstItemInNextRender) {
- selectFirstRenderedRow(false);
- selectFirstItemInNextRender = false;
- }
- // The same if the table is not selectable
- if (focusFirstItemInNextRender) {
- selectFirstRenderedRow(true);
- focusFirstItemInNextRender = false;
+ /*
+ * This is called when the Home or page up button has been pressed in
+ * selectable mode and the next selected row was not yet rendered in the
+ * client
+ */
+ if (selectFirstItemInNextRender || focusFirstItemInNextRender) {
+ selectFirstRenderedRowInViewPort(focusFirstItemInNextRender);
+ selectFirstItemInNextRender = focusFirstItemInNextRender = false;
}
- // This is called when the End button has been pressed and the pages
- // changes
- if (selectLastItemInNextRender) {
- selectLastRenderedRow(false);
- selectLastItemInNextRender = false;
- }
- // the same if not selectable
- if (focusLastItemInNextRender) {
- selectLastRenderedRow(true);
- focusLastItemInNextRender = false;
+ /*
+ * This is called when the page down or end button has been pressed in
+ * selectable mode and the next selected row was not yet rendered in the
+ * client
+ */
+ if (selectLastItemInNextRender || focusLastItemInNextRender) {
+ selectLastRenderedRowInViewPort(focusLastItemInNextRender);
+ selectLastItemInNextRender = focusLastItemInNextRender = false;
}
+ multiselectPending = false;
if (focusedRow != null) {
if (!focusedRow.isAttached()) {
@@ -894,42 +891,48 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
}
/**
- * Selects the last rendered row in the table
+ * Selects the last row visible in the table
*
* @param focusOnly
* Should the focus only be moved to the last row
*/
- private void selectLastRenderedRow(boolean focusOnly) {
- VScrollTableRow row = null;
- Iterator<Widget> it = scrollBody.iterator();
- while (it.hasNext()) {
- row = (VScrollTableRow) it.next();
- }
- if (row != null) {
- setRowFocus(row);
- if (!focusOnly) {
- deselectAll();
- selectFocusedRow(false, false);
- sendSelectedRows();
- }
+ private void selectLastRenderedRowInViewPort(boolean focusOnly) {
+ int index = firstRowInViewPort + getFullyVisibleRowCount();
+ VScrollTableRow lastRowInViewport = scrollBody.getRowByRowIndex(index);
+ if (lastRowInViewport == null) {
+ // this should not happen in normal situations (white space at the
+ // end of viewport). Select the last rendered as a fallback.
+ lastRowInViewport = scrollBody.getRowByRowIndex(scrollBody
+ .getLastRendered());
+ if (lastRowInViewport == null) {
+ return; // empty table
+ }
+ }
+ setRowFocus(lastRowInViewport);
+ if (!focusOnly) {
+ selectFocusedRow(false, multiselectPending);
+ sendSelectedRows();
}
-
}
/**
- * Selects the first rendered row
+ * Selects the first row visible in the table
*
* @param focusOnly
* Should the focus only be moved to the first row
*/
- private void selectFirstRenderedRow(boolean focusOnly) {
- setRowFocus((VScrollTableRow) scrollBody.iterator().next());
+ private void selectFirstRenderedRowInViewPort(boolean focusOnly) {
+ int index = firstRowInViewPort;
+ VScrollTableRow firstInViewport = scrollBody.getRowByRowIndex(index);
+ if (firstInViewport == null) {
+ // this should not happen in normal situations
+ return;
+ }
+ setRowFocus(firstInViewport);
if (!focusOnly) {
- deselectAll();
- selectFocusedRow(false, false);
+ selectFocusedRow(false, multiselectPending);
sendSelectedRows();
}
-
}
private void setCacheRate(double d) {
@@ -1609,10 +1612,10 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
@Override
public void run() {
- if (client.hasActiveRequest()) {
+ if (client.hasActiveRequest() || navKeyDown) {
// if client connection is busy, don't bother loading it more
+ ApplicationConnection.getConsole().log("Postponed rowfetch");
schedule(250);
-
} else {
int firstToBeRendered = scrollBody.firstRendered;
@@ -1669,10 +1672,6 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
return reqFirstRow;
}
- public int getReqRows() {
- return reqRows;
- }
-
/**
* Sends request to refresh content at this position.
*/
@@ -3169,7 +3168,11 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
public VScrollTableRow getRowByRowIndex(int indexInTable) {
int internalIndex = indexInTable - firstRendered;
- return (VScrollTableRow) renderedRows.get(internalIndex);
+ if (internalIndex >= 0 && internalIndex < renderedRows.size()) {
+ return (VScrollTableRow) renderedRows.get(internalIndex);
+ } else {
+ return null;
+ }
}
/**
@@ -4578,6 +4581,8 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
private int scrollLeft;
private int scrollTop;
private VScrollTableDropHandler dropHandler;
+ private boolean navKeyDown;
+ private boolean multiselectPending;
/**
* @return border top + border bottom of the scrollable area of table
@@ -5095,85 +5100,190 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
// Page Down navigation
if (keycode == getNavigationPageDownKey()) {
- int rowHeight = (int) scrollBody.getRowHeight();
- int offset = pageLength * rowHeight - rowHeight;
- scrollBodyPanel.setScrollPosition(scrollBodyPanel
- .getScrollPosition() + offset);
if (isSelectable()) {
- if (!moveFocusDown(pageLength - 2)) {
- final int lastRendered = scrollBody.getLastRendered();
- if (lastRendered == totalRows - 1) {
- selectLastRenderedRow(false);
+ /*
+ * If selectable we plagiate MSW behaviour: first scroll to the
+ * end of current view. If at the end, scroll down one page
+ * length and keep the selected row in the bottom part of
+ * visible area.
+ */
+ if (!isFocusAtTheEndOfTable()) {
+ VScrollTableRow lastVisibleRowInViewPort = scrollBody
+ .getRowByRowIndex(firstRowInViewPort
+ + getFullyVisibleRowCount() - 1);
+ if (lastVisibleRowInViewPort != null
+ && lastVisibleRowInViewPort != focusedRow) {
+ // focused row is not at the end of the table, move
+ // focus and select the last visible row
+ setRowFocus(lastVisibleRowInViewPort);
+ selectFocusedRow(ctrl, shift);
+ sendSelectedRows();
} else {
- selectLastItemInNextRender = true;
+ int indexOfToBeFocused = focusedRow.getIndex()
+ + getFullyVisibleRowCount();
+ if (indexOfToBeFocused >= totalRows) {
+ indexOfToBeFocused = totalRows - 1;
+ }
+ VScrollTableRow toBeFocusedRow = scrollBody
+ .getRowByRowIndex(indexOfToBeFocused);
+
+ if (toBeFocusedRow != null) {
+ /*
+ * if the next focused row is rendered
+ */
+ setRowFocus(toBeFocusedRow);
+ selectFocusedRow(ctrl, shift);
+ // TODO needs scrollintoview ?
+ sendSelectedRows();
+ } else {
+ // scroll down by pixels and return, to wait for
+ // new rows, then select the last item in the
+ // viewport
+ selectLastItemInNextRender = true;
+ multiselectPending = shift;
+ scrollByPagelenght(1);
+ }
}
- } else {
- selectFocusedRow(false, false);
- sendSelectedRows();
}
+ } else {
+ /* No selections, go page down by scrolling */
+ scrollByPagelenght(1);
}
return true;
}
// Page Up navigation
if (keycode == getNavigationPageUpKey()) {
- int rowHeight = (int) scrollBody.getRowHeight();
- int offset = pageLength * rowHeight - rowHeight;
- scrollBodyPanel.setScrollPosition(scrollBodyPanel
- .getScrollPosition() - offset);
if (isSelectable()) {
- if (!moveFocusUp(pageLength - 2)) {
- final int firstRendered = scrollBody.getFirstRendered();
- if (firstRendered == 0) {
- selectFirstRenderedRow(false);
+ /*
+ * If selectable we plagiate MSW behaviour: first scroll to the
+ * end of current view. If at the end, scroll down one page
+ * length and keep the selected row in the bottom part of
+ * visible area.
+ */
+ if (!isFocusAtTheBeginningOfTable()) {
+ VScrollTableRow firstVisibleRowInViewPort = scrollBody
+ .getRowByRowIndex(firstRowInViewPort);
+ if (firstVisibleRowInViewPort != null
+ && firstVisibleRowInViewPort != focusedRow) {
+ // focus is not at the beginning of the table, move
+ // focus and select the first visible row
+ setRowFocus(firstVisibleRowInViewPort);
+ selectFocusedRow(ctrl, shift);
+ sendSelectedRows();
} else {
- selectFirstItemInNextRender = true;
+ int indexOfToBeFocused = focusedRow.getIndex()
+ - getFullyVisibleRowCount();
+ if (indexOfToBeFocused < 0) {
+ indexOfToBeFocused = 0;
+ }
+ VScrollTableRow toBeFocusedRow = scrollBody
+ .getRowByRowIndex(indexOfToBeFocused);
+
+ if (toBeFocusedRow != null) { // if the next focused row
+ // is rendered
+ setRowFocus(toBeFocusedRow);
+ selectFocusedRow(ctrl, shift);
+ // TODO needs scrollintoview ?
+ sendSelectedRows();
+ } else {
+ // unless waiting for the next rowset already
+ // scroll down by pixels and return, to wait for
+ // new rows, then select the last item in the
+ // viewport
+ selectFirstItemInNextRender = true;
+ multiselectPending = shift;
+ scrollByPagelenght(-1);
+ }
}
- } else {
- selectFocusedRow(false, false);
- sendSelectedRows();
}
+ } else {
+ /* No selections, go page up by scrolling */
+ scrollByPagelenght(-1);
}
+
return true;
}
// Goto start navigation
if (keycode == getNavigationStartKey()) {
+ scrollBodyPanel.setScrollPosition(0);
if (isSelectable()) {
- final int firstRendered = scrollBody.getFirstRendered();
- boolean focusOnly = ctrl;
- if (firstRendered == 0) {
- selectFirstRenderedRow(focusOnly);
- } else if (focusOnly) {
- focusFirstItemInNextRender = true;
+ if (focusedRow != null && focusedRow.getIndex() == 0) {
+ return false;
} else {
- selectFirstItemInNextRender = true;
+ VScrollTableRow rowByRowIndex = (VScrollTableRow) scrollBody
+ .iterator().next();
+ if (rowByRowIndex.getIndex() == 0) {
+ setRowFocus(rowByRowIndex);
+ selectFocusedRow(ctrl, shift);
+ sendSelectedRows();
+ } else {
+ // first row of table will come in next row fetch
+ if (ctrl) {
+ focusFirstItemInNextRender = true;
+ } else {
+ selectFirstItemInNextRender = true;
+ multiselectPending = shift;
+ }
+ }
}
}
- scrollBodyPanel.setScrollPosition(0);
return true;
}
// Goto end navigation
if (keycode == getNavigationEndKey()) {
+ scrollBodyPanel.setScrollPosition(scrollBody.getOffsetHeight());
if (isSelectable()) {
final int lastRendered = scrollBody.getLastRendered();
- boolean focusOnly = ctrl;
- if (lastRendered == totalRows - 1) {
- selectLastRenderedRow(focusOnly);
- } else if (focusOnly) {
- focusLastItemInNextRender = true;
+ if (lastRendered + 1 == totalRows) {
+ VScrollTableRow rowByRowIndex = scrollBody
+ .getRowByRowIndex(lastRendered);
+ if (focusedRow != rowByRowIndex) {
+ setRowFocus(rowByRowIndex);
+ selectFocusedRow(ctrl, shift);
+ sendSelectedRows();
+ }
} else {
- selectLastItemInNextRender = true;
+ if (ctrl) {
+ focusLastItemInNextRender = true;
+ } else {
+ selectLastItemInNextRender = true;
+ multiselectPending = shift;
+ }
}
}
- scrollBodyPanel.setScrollPosition(scrollBody.getOffsetHeight());
return true;
}
return false;
}
+ private boolean isFocusAtTheBeginningOfTable() {
+ return focusedRow.getIndex() == 0;
+ }
+
+ private boolean isFocusAtTheEndOfTable() {
+ return focusedRow.getIndex() + 1 >= totalRows;
+ }
+
+ private int getFullyVisibleRowCount() {
+ return (int) (scrollBodyPanel.getOffsetHeight() / scrollBody
+ .getRowHeight());
+ }
+
+ private void scrollByPagelenght(int i) {
+ int pixels = i
+ * (int) (getFullyVisibleRowCount() * scrollBody.getRowHeight());
+ int newPixels = scrollBodyPanel.getScrollPosition() + pixels;
+ if (newPixels < 0) {
+ newPixels = 0;
+ } // else if too high, NOP (all know browsers accept illegally big
+ // values here)
+ scrollBodyPanel.setScrollPosition(newPixels);
+ }
+
/*
* (non-Javadoc)
*
@@ -5214,6 +5324,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
if (handleNavigation(event.getNativeEvent().getKeyCode(),
event.isControlKeyDown() || event.isMetaKeyDown(),
event.isShiftKeyDown())) {
+ navKeyDown = true;
event.preventDefault();
}
@@ -5261,6 +5372,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
public void onBlur(BlurEvent event) {
scrollBodyPanel.removeStyleName("focused");
hasFocus = false;
+ navKeyDown = false;
// Unfocus any row
setRowFocus(null);
@@ -5358,6 +5470,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
scrollingVelocityTimer = null;
scrollingVelocity = 10;
}
+ navKeyDown = false;
}
}
@@ -5370,6 +5483,8 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
return keyCode == getNavigationUpKey()
|| keyCode == getNavigationDownKey()
|| keyCode == getNavigationPageUpKey()
- || keyCode == getNavigationPageDownKey();
+ || keyCode == getNavigationPageDownKey()
+ || keyCode == getNavigationEndKey()
+ || keyCode == getNavigationStartKey();
}
}