summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJohn Alhroos <john.ahlroos@itmill.com>2010-05-04 13:02:44 +0000
committerJohn Alhroos <john.ahlroos@itmill.com>2010-05-04 13:02:44 +0000
commit2924b070b44a3f140dca181204187c31d5ac8739 (patch)
tree8310b5d934538ed79dd8966b9985fffe4d948b11 /src
parent26d3c1eaeb32461d754ae8c8a754115cca4f9806 (diff)
downloadvaadin-framework-2924b070b44a3f140dca181204187c31d5ac8739.tar.gz
vaadin-framework-2924b070b44a3f140dca181204187c31d5ac8739.zip
Changes in Table:
- Changed keyboard selection mechanism - Added keyboard control with Home,End,Page Up and Page Down - Added focus outline svn changeset:13023/svn branch:6.4
Diffstat (limited to 'src')
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java632
1 files changed, 512 insertions, 120 deletions
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java
index 17b822a204..b7feba223a 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java
@@ -145,12 +145,33 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
* are selecting a range which is over several pages long
*/
private int lastSelectedRowKey = -1;
-
+
+ /*
+ * These are used when jumping between pages when pressing Home and End
+ */
+ private boolean selectLastItemInNextRender = false;
+ private boolean selectFirstItemInNextRender = false;
+ private boolean focusFirstItemInNextRender = false;
+ private boolean focusLastItemInNextRender = false;
+
/*
* The currently focused row
*/
private VScrollTableRow focusedRow;
+ /*
+ * Flag for notifying when the selection has changed and should be sent to
+ * the server
+ */
+ private boolean selectionChanged = false;
+
+ /*
+ * The speed (in pixels) which the scrolling scrolls vertically/horizontally
+ */
+ private int scrollingVelocity = 10;
+
+ private Timer scrollingVelocityTimer = null;;
+
/**
* Represents a select range of rows
*/
@@ -187,6 +208,18 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
public String toString() {
return startRowKey + "-" + endRowKey;
}
+
+ public boolean inRange(int key) {
+ return key >= startRowKey && key <= endRowKey;
+ }
+
+ public int getStartKey() {
+ return startRowKey;
+ }
+
+ public int getEndKey() {
+ return endRowKey;
+ }
};
private final HashSet<SelectionRange> selectedRowRanges = new HashSet<SelectionRange>();
@@ -246,15 +279,13 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
private int multiselectmode;
-
-
public VScrollTable() {
bodyContainerFocus.setStyleName(CLASSNAME + "-body-wrapper");
/*
- * Firefox handler auto-repeat works correctly only if we use a key
- * press handler, other browsers handle it correctly when using a key
- * down handler
+ * Firefox auto-repeat works correctly only if we use a key press
+ * handler, other browsers handle it correctly when using a key down
+ * handler
*/
if (BrowserInfo.get().isGecko()) {
bodyContainerFocus.addKeyPressHandler(this);
@@ -275,24 +306,64 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
add(tFoot);
rowRequestHandler = new RowRequestHandler();
+
+ /*
+ * We need to use the sinkEvents method to catch the keyUp events so we
+ * can cache a single shift. KeyUpHandler cannot do this.
+ */
+ sinkEvents(Event.ONKEYUP);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.user.client.ui.Widget#onBrowserEvent(com.google.gwt.user
+ * .client.Event)
+ */
+ @Override
+ public void onBrowserEvent(Event event) {
+ if (event.getTypeInt() == Event.ONKEYUP) {
+ if (event.getKeyCode() == KeyCodes.KEY_SHIFT) {
+ sendSelectedRows();
+ } else if ((event.getKeyCode() == getNavigationUpKey()
+ || event.getKeyCode() == getNavigationDownKey()
+ || event.getKeyCode() == getNavigationPageUpKey() || event
+ .getKeyCode() == getNavigationPageDownKey())
+ && !event.getShiftKey()) {
+ sendSelectedRows();
+ }
+
+ scrollingVelocityTimer.cancel();
+ scrollingVelocityTimer = null;
+ scrollingVelocity = 10;
+ }
+ }
+
+ /**
+ * Moves the focus one step down
+ *
+ * @return Returns true if succeeded
+ */
+ private boolean moveFocusDown() {
+ return moveFocusDown(0);
}
/**
- * Moves the selection head one row downloads
+ * Moves the focus down by 1+offset rows
*
* @return Returns true if succeeded, else false if the selection could not
* be move downwards
*/
- private boolean moveSelectionDown() {
+ private boolean moveFocusDown(int offset) {
if (selectMode > VScrollTable.SELECT_MODE_NONE) {
- if (focusedRow == null) {
- setRowFocus((VScrollTableRow) scrollBody.iterator().next());
- return true;
+ if (focusedRow == null && scrollBody.iterator().hasNext()) {
+ return setRowFocus((VScrollTableRow) scrollBody.iterator()
+ .next());
} else {
- VScrollTableRow next = getNextRow(focusedRow);
+ VScrollTableRow next = getNextRow(focusedRow, offset);
if (next != null) {
- setRowFocus(next);
- return true;
+ return setRowFocus(next);
}
}
}
@@ -301,22 +372,30 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
}
/**
- * Moves the selection head one row upwards
+ * Moves the selection one step up
+ *
+ * @return Returns true if succeeded
+ */
+ private boolean moveFocusUp() {
+ return moveFocusUp(0);
+ }
+
+ /**
+ * Moves the focus row upwards
*
* @return Returns true if succeeded, else false if the selection could not
* be move upwards
*
*/
- private boolean moveSelectionUp() {
+ private boolean moveFocusUp(int offset) {
if (selectMode > VScrollTable.SELECT_MODE_NONE) {
- if (focusedRow == null) {
- setRowFocus((VScrollTableRow) scrollBody.iterator().next());
- return true;
+ if (focusedRow == null && scrollBody.iterator().hasNext()) {
+ return setRowFocus((VScrollTableRow) scrollBody.iterator()
+ .next());
} else {
- VScrollTableRow prev = getPreviousRow(focusedRow);
+ VScrollTableRow prev = getPreviousRow(focusedRow, offset);
if (prev != null) {
- setRowFocus(prev);
- return true;
+ return setRowFocus(prev);
}
}
}
@@ -335,22 +414,81 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
*/
private void selectFocusedRow(boolean ctrlSelect, boolean shiftSelect) {
if (focusedRow != null) {
- if (ctrlSelect && !shiftSelect && selectMode == SELECT_MODE_MULTI) {
- focusedRow.toggleSelection(ctrlSelect);
- } else if (!ctrlSelect && shiftSelect
- && selectMode == SELECT_MODE_MULTI) {
- focusedRow.toggleShiftSelection(true);
- } else if (ctrlSelect && shiftSelect
- && selectMode == SELECT_MODE_MULTI) {
- focusedRow.toggleShiftSelection(false);
- } else {
+ // Arrows moves the selection and clears previous selections
+ if (selectMode > SELECT_MODE_NONE && !ctrlSelect && !shiftSelect) {
deselectAll();
- focusedRow.toggleSelection(true);
+ focusedRow.toggleSelection(!ctrlSelect);
+ }
+
+ // Ctrl+arrows moves selection head
+ else if (selectMode > SELECT_MODE_NONE && ctrlSelect
+ && !shiftSelect) {
+ // No selection, only selection head is moved
+ }
+
+ // Shift+arrows selection selects a range
+ else if (selectMode == SELECT_MODE_MULTI && !ctrlSelect
+ && shiftSelect) {
+ focusedRow.toggleShiftSelection(shiftSelect);
}
}
}
/**
+ * Sends the selection to the server
+ */
+ private void sendSelectedRows(){
+ // Don't send anything if selection has not changed
+ if (!selectionChanged) {
+ return;
+ }
+
+ // Reset selection changed flag
+ selectionChanged = false;
+
+ // Note: changing the immediateness of this
+ // might
+ // require changes to "clickEvent" immediateness
+ // also.
+ if (multiselectmode == MULTISELECT_MODE_DEFAULT) {
+ // Convert ranges to a set of strings
+ Set<String> ranges = new HashSet<String>();
+ for (SelectionRange range : selectedRowRanges) {
+ ranges.add(range.toString());
+ }
+
+ /*
+ * Clear ranges since they are transformed
+ * on the server side to row selections
+ */
+ if (immediate) {
+ selectedRowRanges.clear();
+ }
+
+ // Send the selected row ranges
+ client
+ .updateVariable(
+ paintableId,
+ "selectedRanges",
+ ranges
+ .toArray(new String[selectedRowRanges
+ .size()]),
+ false);
+ }
+
+ // Send the selected rows
+ client
+ .updateVariable(
+ paintableId,
+ "selected",
+ selectedRowKeys
+ .toArray(new String[selectedRowKeys
+ .size()]),
+ immediate);
+
+ }
+
+ /**
* Get the key that moves the selection head upwards. By default it is the
* up arrow key but by overriding this you can change the key to whatever
* you want.
@@ -405,6 +543,57 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
return 32;
}
+ /**
+ * Get the key the moves the selection one page up in the table. By default
+ * this is the Page Up key but by overriding this you can change the key to
+ * whatever you want.
+ *
+ * @return
+ */
+ protected int getNavigationPageUpKey() {
+ return KeyCodes.KEY_PAGEUP;
+ }
+
+ /**
+ * Get the key the moves the selection one page down in the table. By
+ * default this is the Page Down key but by overriding this you can change
+ * the key to whatever you want.
+ *
+ * @return
+ */
+ protected int getNavigationPageDownKey() {
+ return KeyCodes.KEY_PAGEDOWN;
+ }
+
+ /**
+ * Get the key the moves the selection to the beginning of the table. By
+ * default this is the Home key but by overriding this you can change the
+ * key to whatever you want.
+ *
+ * @return
+ */
+ protected int getNavigationStartKey() {
+ return KeyCodes.KEY_HOME;
+ }
+
+ /**
+ * Get the key the moves the selection to the end of the table. By default
+ * this is the End key but by overriding this you can change the key to
+ * whatever you want.
+ *
+ * @return
+ */
+ protected int getNavigationEndKey() {
+ return KeyCodes.KEY_END;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.gwt.client.Paintable#updateFromUIDL(com.vaadin.terminal
+ * .gwt.client.UIDL, com.vaadin.terminal.gwt.client.ApplicationConnection)
+ */
@SuppressWarnings("unchecked")
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
rendering = true;
@@ -590,10 +779,62 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
hideScrollPositionAnnotation();
purgeUnregistryBag();
+
+ // This is called when the Home button has been pressed and the pages
+ // changes
+ if (selectFirstItemInNextRender) {
+ selectFirstRenderedRow(false);
+ selectFirstItemInNextRender = false;
+ }
+
+ if (focusFirstItemInNextRender) {
+ selectFirstRenderedRow(true);
+ focusFirstItemInNextRender = false;
+ }
+
+ // This is called when the End button has been pressed and the pages
+ // changes
+ if (selectLastItemInNextRender) {
+ selectLastRenderedRow(false);
+ selectLastItemInNextRender = false;
+ }
+
+ if (focusLastItemInNextRender) {
+ selectLastRenderedRow(true);
+ focusLastItemInNextRender = false;
+ }
+
rendering = false;
headerChangedDuringUpdate = false;
}
+ 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 selectFirstRenderedRow(boolean focusOnly) {
+ setRowFocus((VScrollTableRow) scrollBody.iterator().next());
+ if (!focusOnly) {
+ deselectAll();
+ selectFocusedRow(false, false);
+ sendSelectedRows();
+ }
+
+ }
+
private void setCacheRate(double d) {
if (cache_rate != d) {
cache_rate = d;
@@ -812,25 +1053,27 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
}
return null;
}
-
+
/**
* Returns the next row to the given row
*
* @param row
* The row to calculate from
+ *
* @return The next row or null if no row exists
*/
- private VScrollTableRow getNextRow(VScrollTableRow row){
+ private VScrollTableRow getNextRow(VScrollTableRow row, int offset) {
final Iterator<Widget> it = scrollBody.iterator();
VScrollTableRow r = null;
while (it.hasNext()) {
r = (VScrollTableRow) it.next();
if(r == row){
- if (it.hasNext()) {
- return (VScrollTableRow) it.next();
- } else {
- break;
+ r = null;
+ while (offset >= 0 && it.hasNext()) {
+ r = (VScrollTableRow) it.next();
+ offset--;
}
+ return r;
}
}
@@ -844,18 +1087,22 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
* The row to calculate from
* @return The previous row or null if no row exists
*/
- private VScrollTableRow getPreviousRow(VScrollTableRow row) {
+ private VScrollTableRow getPreviousRow(VScrollTableRow row, int offset) {
final Iterator<Widget> it = scrollBody.iterator();
+ final Iterator<Widget> offsetIt = scrollBody.iterator();
VScrollTableRow r = null;
VScrollTableRow prev = null;
while (it.hasNext()) {
r = (VScrollTableRow) it.next();
+ if (offset < 0) {
+ prev = (VScrollTableRow) offsetIt.next();
+ }
if (r == row) {
return prev;
- } else {
- prev = r;
}
+ offset--;
}
+
return null;
}
@@ -3449,35 +3696,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
.setPropertyJSO("onselectstart",
null);
}
-
- // Note: changing the immediateness of this
- // might
- // require changes to "clickEvent" immediateness
- // also.
- if (multiselectmode == MULTISELECT_MODE_DEFAULT) {
- Set<String> ranges = new HashSet<String>();
- for (SelectionRange range : selectedRowRanges) {
- ranges.add(range.toString());
- }
- client
- .updateVariable(
- paintableId,
- "selectedRanges",
- ranges
- .toArray(new String[selectedRowRanges
- .size()]),
- false);
- }
-
- // Send the selected rows
- client
- .updateVariable(
- paintableId,
- "selected",
- selectedRowKeys
- .toArray(new String[selectedRowKeys
- .size()]),
- immediate);
+ sendSelectedRows();
}
break;
case Event.ONCONTEXTMENU:
@@ -3641,6 +3860,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
*/
public void toggleSelection(boolean ctrlSelect) {
selected = !selected;
+ selectionChanged = true;
if (selected) {
if (ctrlSelect) {
lastSelectedRowKey = rowKey;
@@ -3650,6 +3870,40 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
} else {
removeStyleName("v-selected");
selectedRowKeys.remove(String.valueOf(rowKey));
+ removeKeyFromSelectedRange(rowKey);
+ }
+ }
+
+ /**
+ * Removes a key from a range if the key is found in a selected
+ * range
+ *
+ * @param key
+ * The key to remove
+ */
+ private void removeKeyFromSelectedRange(int key){
+ for(SelectionRange range : selectedRowRanges){
+ if (range.inRange(key)) {
+ int start = range.getStartKey();
+ int end = range.getEndKey();
+
+ if (start < key && end > key) {
+ selectedRowRanges.add(new SelectionRange(start,
+ key - 1));
+ selectedRowRanges.add(new SelectionRange(key + 1,
+ end));
+ } else if (start == key && start < end) {
+ selectedRowRanges.add(new SelectionRange(start + 1,
+ end));
+ } else if (end == key && start < end) {
+ selectedRowRanges.add(new SelectionRange(start,
+ end - 1));
+ }
+
+ selectedRowRanges.remove(range);
+
+ break;
+ }
}
}
@@ -3690,19 +3944,31 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
}
// Select the range (not including this row)
- for (int r = startKey; r <= endKey; r++) {
- if (r != rowKey) {
- VScrollTableRow row = getRenderedRowByKey(String
- .valueOf(r));
- if (row != null && !row.isSelected()) {
- row.toggleSelection(false);
- selectedRowKeys.add(String.valueOf(r));
- }
- }
+ VScrollTableRow startRow = getRenderedRowByKey(String
+ .valueOf(startKey));
+ VScrollTableRow endRow = getRenderedRowByKey(String
+ .valueOf(endKey));
+
+ // If start row is null then we have a multipage selection from
+ // above
+ if (startRow == null) {
+ startRow = (VScrollTableRow) scrollBody.iterator().next();
}
- // Toggle clicked rows selection
- toggleSelection(false);
+ Iterator<Widget> rows = scrollBody.iterator();
+ boolean startSelection = false;
+ while (rows.hasNext()) {
+ VScrollTableRow row = (VScrollTableRow) rows.next();
+ if (row == startRow || startSelection) {
+ startSelection = true;
+ row.toggleSelection(false);
+ selectedRowKeys.add(row.getKey());
+ }
+
+ if (row == endRow && row != null) {
+ startSelection = false;
+ }
+ }
// Add range
selectedRowRanges.add(new SelectionRange(startKey, endKey));
@@ -4376,11 +4642,12 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
*
* @param row
* The row to where the selection head should move
+ * @return Returns true if focus was moved successfully, else false
*/
- private void setRowFocus(VScrollTableRow row) {
+ private boolean setRowFocus(VScrollTableRow row) {
if (selectMode == SELECT_MODE_NONE) {
- return;
+ return false;
}
// Remove previous selection
@@ -4389,8 +4656,16 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
}
if (row != null) {
- // Apply focus style to new selection
+
+ // Trying to set focus on already focused row
+ if (row == focusedRow) {
+ return false;
+ }
+
+ // Set new focused row
focusedRow = row;
+
+ // Apply focus style to new selection
focusedRow.addStyleName(CLASSNAME_SELECTION_FOCUS);
// Scroll up or down if needed
@@ -4407,7 +4682,13 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
.getScrollPosition()
- focusedRow.getOffsetHeight());
}
+
+ return true;
+ } else {
+ focusedRow = null;
}
+
+ return false;
}
/**
@@ -4417,64 +4698,149 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
* The keyboard event received
*/
private void handleNavigation(Event event) {
+ if (event.getKeyCode() == KeyCodes.KEY_TAB) {
+ // Do not handle tab key
+ return;
+ }
// Down navigation
if (selectMode == SELECT_MODE_NONE
&& event.getKeyCode() == getNavigationDownKey()) {
- bodyContainer
- .setScrollPosition(bodyContainer.getScrollPosition() + 5);
- event.preventDefault();
+ bodyContainer.setScrollPosition(bodyContainer.getScrollPosition()
+ + scrollingVelocity);
} else if (event.getKeyCode() == getNavigationDownKey()) {
- if (moveSelectionDown()) {
- if (event.getShiftKey()) {
- selectFocusedRow(false, true);
- }
- event.preventDefault();
+ if (selectMode == SELECT_MODE_MULTI && moveFocusDown()) {
+ selectFocusedRow(event.getCtrlKey() || event.getMetaKey(),
+ event.getShiftKey());
+ } else if (selectMode == SELECT_MODE_SINGLE && !event.getShiftKey()
+ && moveFocusDown()) {
+ selectFocusedRow(event.getCtrlKey() || event.getMetaKey(),
+ event.getShiftKey());
}
}
// Up navigation
if (selectMode == SELECT_MODE_NONE
&& event.getKeyCode() == getNavigationUpKey()) {
- bodyContainer
- .setScrollPosition(bodyContainer.getScrollPosition() - 5);
- event.preventDefault();
+ bodyContainer.setScrollPosition(bodyContainer.getScrollPosition()
+ - scrollingVelocity);
} else if (event.getKeyCode() == getNavigationUpKey()) {
- if (moveSelectionUp()) {
- if (event.getShiftKey()) {
- selectFocusedRow(false, true);
- }
- event.preventDefault();
+ if (selectMode == SELECT_MODE_MULTI && moveFocusUp()) {
+ selectFocusedRow(event.getCtrlKey() || event.getMetaKey(),
+ event.getShiftKey());
+ } else if (selectMode == SELECT_MODE_SINGLE && !event.getShiftKey()
+ && moveFocusUp()) {
+ selectFocusedRow(event.getCtrlKey() || event.getMetaKey(),
+ event.getShiftKey());
}
+ }
- // Left navigation
- } else if (event.getKeyCode() == getNavigationLeftKey()) {
+ // Left navigation
+ if (event.getKeyCode() == getNavigationLeftKey()) {
bodyContainer.setHorizontalScrollPosition(bodyContainer
- .getHorizontalScrollPosition() - 5);
- event.preventDefault();
+ .getHorizontalScrollPosition()
+ - scrollingVelocity);
// Right navigation
} else if (event.getKeyCode() == getNavigationRightKey()) {
bodyContainer.setHorizontalScrollPosition(bodyContainer
- .getHorizontalScrollPosition() + 5);
- event.preventDefault();
+ .getHorizontalScrollPosition()
+ + scrollingVelocity);
}
// Select navigation
if (selectMode > SELECT_MODE_NONE
- && event.getKeyCode() == getNavigationSelectKey()) {
- selectFocusedRow(event.getCtrlKey() || event.getMetaKey(),
- event.getShiftKey());
+ && event.getKeyCode() == getNavigationSelectKey()) {
+ if (selectMode == SELECT_MODE_SINGLE) {
+ boolean wasSelected = focusedRow.isSelected();
+ deselectAll();
+ lastSelectedRowKey = -1;
+ if (!wasSelected) {
+ focusedRow.toggleSelection(true);
+ }
- event.preventDefault();
+ } else {
+ focusedRow.toggleSelection(true);
+ }
+
+ sendSelectedRows();
+ }
+
+ // Page Down navigation
+ if (event.getKeyCode() == getNavigationPageDownKey()) {
+ int rowHeight = (int) scrollBody.getRowHeight();
+ int offset = pageLength * rowHeight - rowHeight;
+ bodyContainer.setScrollPosition(bodyContainer.getScrollPosition()
+ + offset);
+ if (selectMode > SELECT_MODE_NONE) {
+ if (!moveFocusDown(pageLength - 2)) {
+ final int lastRendered = scrollBody.getLastRendered();
+ if (lastRendered == totalRows - 1) {
+ selectLastRenderedRow(false);
+ } else {
+ selectLastItemInNextRender = true;
+ }
+ } else {
+ selectFocusedRow(false, false);
+ sendSelectedRows();
+ }
+ }
+ }
- // Send the selected rows
- client
- .updateVariable(paintableId, "selected",
- selectedRowKeys
- .toArray(new String[selectedRowKeys
- .size()]), immediate);
+ // Page Up navigation
+ if (event.getKeyCode() == getNavigationPageUpKey()) {
+ int rowHeight = (int) scrollBody.getRowHeight();
+ int offset = pageLength * rowHeight - rowHeight;
+ bodyContainer.setScrollPosition(bodyContainer.getScrollPosition()
+ - offset);
+ if (selectMode > SELECT_MODE_NONE) {
+ if (!moveFocusUp(pageLength - 2)) {
+ final int firstRendered = scrollBody.getFirstRendered();
+ if (firstRendered == 0) {
+ selectFirstRenderedRow(false);
+ } else {
+ selectFirstItemInNextRender = true;
+ }
+ } else {
+ selectFocusedRow(false, false);
+ sendSelectedRows();
+ }
+ }
+ }
+
+ // Goto start navigation
+ if (event.getKeyCode() == getNavigationStartKey()) {
+ if (selectMode > SELECT_MODE_NONE) {
+ final int firstRendered = scrollBody.getFirstRendered();
+ boolean focusOnly = event.getCtrlKey() || event.getMetaKey();
+ if (firstRendered == 0) {
+ selectFirstRenderedRow(focusOnly);
+ } else if (focusOnly) {
+ focusFirstItemInNextRender = true;
+ } else {
+ selectFirstItemInNextRender = true;
+ }
+ }
+ bodyContainer.setScrollPosition(0);
+ }
+
+ // Goto end navigation
+ if (event.getKeyCode() == getNavigationEndKey()) {
+ if (selectMode > SELECT_MODE_NONE) {
+ final int lastRendered = scrollBody.getLastRendered();
+ boolean focusOnly = event.getCtrlKey() || event.getMetaKey();
+ if (lastRendered == totalRows - 1) {
+ selectLastRenderedRow(focusOnly);
+ } else if (focusOnly) {
+ focusLastItemInNextRender = true;
+ } else {
+ selectLastItemInNextRender = true;
+ }
}
+ bodyContainer.setScrollPosition(scrollBody.getOffsetHeight());
+ }
+
+ event.preventDefault();
}
/*
@@ -4486,6 +4852,17 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
*/
public void onKeyPress(KeyPressEvent event) {
handleNavigation((Event) event.getNativeEvent().cast());
+
+ // Start the velocityTimer
+ if (scrollingVelocityTimer == null) {
+ scrollingVelocityTimer = new Timer() {
+ @Override
+ public void run() {
+ scrollingVelocity++;
+ }
+ };
+ scrollingVelocityTimer.scheduleRepeating(100);
+ }
}
/*
@@ -4497,6 +4874,17 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
*/
public void onKeyDown(KeyDownEvent event) {
handleNavigation((Event) event.getNativeEvent().cast());
+
+ // Start the velocityTimer
+ if (scrollingVelocityTimer == null) {
+ scrollingVelocityTimer = new Timer() {
+ @Override
+ public void run() {
+ scrollingVelocity++;
+ }
+ };
+ scrollingVelocityTimer.scheduleRepeating(100);
+ }
}
/*
@@ -4507,10 +4895,9 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
* .dom.client.FocusEvent)
*/
public void onFocus(FocusEvent event) {
- // Move focus from wrapper to container in FF, ignored in other browsers
- if (BrowserInfo.get().isFF3()) {
- bodyContainer.getElement().focus();
- }
+ bodyContainer.addStyleName("focused");
+
+ // Focus a row if no row is in focus
if (focusedRow == null) {
setRowFocus((VScrollTableRow) scrollBody.iterator().next());
}
@@ -4524,7 +4911,12 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
* .dom.client.BlurEvent)
*/
public void onBlur(BlurEvent event) {
+ bodyContainer.removeStyleName("focused");
+
+ // Unfocus any row
setRowFocus(null);
}
+
+
}