Browse Source

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
tags/6.7.0.beta1
Matti Tahvonen 13 years ago
parent
commit
a28defb307
1 changed files with 203 additions and 88 deletions
  1. 203
    88
      src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java

+ 203
- 88
src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java View File

@@ -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();
}
}

Loading…
Cancel
Save