diff options
author | Matti Tahvonen <matti.tahvonen@itmill.com> | 2010-09-03 14:54:50 +0000 |
---|---|---|
committer | Matti Tahvonen <matti.tahvonen@itmill.com> | 2010-09-03 14:54:50 +0000 |
commit | a28defb307f38d987a7735331f4bb7d8494bc92c (patch) | |
tree | 4ebed7179ff71ae594af075d5691b8da64d01b88 /src/com | |
parent | bfd1816dc28e09a492697125b9b3b9e97b730d62 (diff) | |
download | vaadin-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.java | 291 |
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(); } } |