summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Alhroos <john.ahlroos@itmill.com>2010-04-29 12:26:11 +0000
committerJohn Alhroos <john.ahlroos@itmill.com>2010-04-29 12:26:11 +0000
commit001309748a3836f64ffc5a73b62314934cc7c018 (patch)
tree985ecc8e1f8799ce20c8f8ae0f41b154b03294f5
parentb76d365acf27491b795c5872623e96f79d50c6b0 (diff)
downloadvaadin-framework-001309748a3836f64ffc5a73b62314934cc7c018.tar.gz
vaadin-framework-001309748a3836f64ffc5a73b62314934cc7c018.zip
Added keyboard navigation to Table #2390
svn changeset:12925/svn branch:6.4
-rw-r--r--WebContent/VAADIN/themes/base/table/table.css4
-rw-r--r--WebContent/VAADIN/themes/reindeer/table/table.css11
-rw-r--r--WebContent/VAADIN/themes/runo/styles.css20
-rw-r--r--WebContent/VAADIN/themes/runo/table/table.css9
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java437
-rw-r--r--src/com/vaadin/ui/Table.java12
6 files changed, 463 insertions, 30 deletions
diff --git a/WebContent/VAADIN/themes/base/table/table.css b/WebContent/VAADIN/themes/base/table/table.css
index becffeaa8b..421aad5488 100644
--- a/WebContent/VAADIN/themes/base/table/table.css
+++ b/WebContent/VAADIN/themes/base/table/table.css
@@ -180,6 +180,10 @@
display: block;
text-align: center;
}
+.v-table-body:focus,
+.v-table-body-wrapper:focus{
+ outline: none;
+}
/* row in column selector */
.v-on {
diff --git a/WebContent/VAADIN/themes/reindeer/table/table.css b/WebContent/VAADIN/themes/reindeer/table/table.css
index b6052424bb..fc9db768df 100644
--- a/WebContent/VAADIN/themes/reindeer/table/table.css
+++ b/WebContent/VAADIN/themes/reindeer/table/table.css
@@ -97,6 +97,17 @@
.v-table .v-selected .v-table-cell-content {
border-right-color: #466c90;
}
+.v-table-body:focus{
+ outline: none;
+}
+.v-table .v-table-focus .v-table-cell-content{
+ border-top: 1px dotted black;
+ border-bottom: 1px dotted black;
+}
+.v-table .v-table-focus .v-table-cell-content .v-table-cell-wrapper{
+ padding-top:2px;
+ padding-bottom:2px;
+}
.v-table-column-selector {
width: 16px;
height: 20px;
diff --git a/WebContent/VAADIN/themes/runo/styles.css b/WebContent/VAADIN/themes/runo/styles.css
index d98adbe7da..3c6e578d37 100644
--- a/WebContent/VAADIN/themes/runo/styles.css
+++ b/WebContent/VAADIN/themes/runo/styles.css
@@ -1,5 +1,5 @@
-.v-theme-version:after {content:"6_4_0_dev-20100420";}
-.v-theme-version-6_4_0_dev-20100420 {display: none;}
+.v-theme-version:after {content:"6_4_0_dev-20100429";}
+.v-theme-version-6_4_0_dev-20100429 {display: none;}
/* Automatically compiled css file from subdirectories. */
.v-absolutelayout-wrapper {
@@ -1452,10 +1452,9 @@ div.v-progressindicator-indeterminate-disabled {
border-top: none;
background: #efefef;
}
-.v-table-footer table,
-.v-table-table {
+.v-table-footer table{
border-spacing: 0;
- border-collapse: separate;
+ border-collapse: collapse;
margin: 0;
padding: 0;
border: 0;
@@ -1575,6 +1574,10 @@ div.v-progressindicator-indeterminate-disabled {
display: block;
text-align: center;
}
+.v-table-body:focus,
+.v-table-body-wrapper:focus{
+ outline: none;
+}
/* row in column selector */
.v-on {
@@ -3356,6 +3359,13 @@ div.v-window-header {
filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="VAADIN/themes/default/table/img/scroll-position-bg.png", sizingMethod="scale");
filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="/VAADIN/themes/default/table/img/scroll-position-bg.png", sizingMethod="scale");
}
+.v-table .v-table-focus .v-table-cell-content{
+ border-top: 1px dotted black;
+ border-bottom: 1px dotted black;
+}
+.v-table .v-table-focus .v-table-cell-content .v-table-cell-wrapper{
+ line-height: 21px;
+}
.v-tabsheet-tabs {
height: 48px;
diff --git a/WebContent/VAADIN/themes/runo/table/table.css b/WebContent/VAADIN/themes/runo/table/table.css
index 30053523fd..7f4b99d229 100644
--- a/WebContent/VAADIN/themes/runo/table/table.css
+++ b/WebContent/VAADIN/themes/runo/table/table.css
@@ -138,4 +138,11 @@
filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="../VAADIN/themes/default/table/img/scroll-position-bg.png", sizingMethod="scale");
filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="VAADIN/themes/default/table/img/scroll-position-bg.png", sizingMethod="scale");
filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="/VAADIN/themes/default/table/img/scroll-position-bg.png", sizingMethod="scale");
-} \ No newline at end of file
+}
+.v-table .v-table-focus .v-table-cell-content{
+ border-top: 1px dotted black;
+ border-bottom: 1px dotted black;
+}
+.v-table .v-table-focus .v-table-cell-content .v-table-cell-wrapper{
+ line-height: 21px;
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java
index b04e5f998d..17b822a204 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java
@@ -24,6 +24,15 @@ import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.dom.client.Style.Visibility;
+import com.google.gwt.event.dom.client.BlurEvent;
+import com.google.gwt.event.dom.client.BlurHandler;
+import com.google.gwt.event.dom.client.FocusEvent;
+import com.google.gwt.event.dom.client.FocusHandler;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.event.dom.client.KeyDownEvent;
+import com.google.gwt.event.dom.client.KeyDownHandler;
+import com.google.gwt.event.dom.client.KeyPressEvent;
+import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.dom.client.ScrollEvent;
import com.google.gwt.event.dom.client.ScrollHandler;
import com.google.gwt.user.client.Command;
@@ -34,6 +43,7 @@ import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.FocusPanel;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
@@ -81,9 +91,12 @@ import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation;
* TODO implement unregistering for child components in Cells
*/
public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
- VHasDropHandler {
+ VHasDropHandler, KeyPressHandler, KeyDownHandler, FocusHandler,
+ BlurHandler {
public static final String CLASSNAME = "v-table";
+ public static final String CLASSNAME_SELECTION_FOCUS = CLASSNAME + "-focus";
+
public static final String ITEM_CLICK_EVENT_ID = "itemClick";
public static final String HEADER_CLICK_EVENT_ID = "handleHeaderClick";
public static final String FOOTER_CLICK_EVENT_ID = "handleFooterClick";
@@ -127,6 +140,17 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
private final HashSet<String> selectedRowKeys = new HashSet<String>();
+ /*
+ * We need to store the selection head so we now what range to select if we
+ * are selecting a range which is over several pages long
+ */
+ private int lastSelectedRowKey = -1;
+
+ /*
+ * The currently focused row
+ */
+ private VScrollTableRow focusedRow;
+
/**
* Represents a select range of rows
*/
@@ -179,6 +203,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
private final TableFooter tFoot = new TableFooter();
private final ScrollPanel bodyContainer = new ScrollPanel();
+ private final FocusPanel bodyContainerFocus = new FocusPanel(bodyContainer);
private int totalRows;
@@ -220,20 +245,166 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
private int dragmode;
private int multiselectmode;
- private int lastSelectedRowKey = -1;
+
+
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
+ */
+ if (BrowserInfo.get().isGecko()) {
+ bodyContainerFocus.addKeyPressHandler(this);
+ } else {
+ bodyContainerFocus.addKeyDownHandler(this);
+ }
+
+ bodyContainerFocus.addFocusHandler(this);
+ bodyContainerFocus.addBlurHandler(this);
+
bodyContainer.addScrollHandler(this);
bodyContainer.setStyleName(CLASSNAME + "-body");
setStyleName(CLASSNAME);
+
add(tHead);
- add(bodyContainer);
+ add(bodyContainerFocus);
add(tFoot);
rowRequestHandler = new RowRequestHandler();
}
+ /**
+ * Moves the selection head one row downloads
+ *
+ * @return Returns true if succeeded, else false if the selection could not
+ * be move downwards
+ */
+ private boolean moveSelectionDown() {
+ if (selectMode > VScrollTable.SELECT_MODE_NONE) {
+ if (focusedRow == null) {
+ setRowFocus((VScrollTableRow) scrollBody.iterator().next());
+ return true;
+ } else {
+ VScrollTableRow next = getNextRow(focusedRow);
+ if (next != null) {
+ setRowFocus(next);
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Moves the selection head one row upwards
+ *
+ * @return Returns true if succeeded, else false if the selection could not
+ * be move upwards
+ *
+ */
+ private boolean moveSelectionUp() {
+ if (selectMode > VScrollTable.SELECT_MODE_NONE) {
+ if (focusedRow == null) {
+ setRowFocus((VScrollTableRow) scrollBody.iterator().next());
+ return true;
+ } else {
+ VScrollTableRow prev = getPreviousRow(focusedRow);
+ if (prev != null) {
+ setRowFocus(prev);
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Selects a row where the current selection head is
+ *
+ * @param ctrlSelect
+ * Is the selection a ctrl+selection
+ * @param shiftSelect
+ * Is the selection a shift+selection
+ * @return Returns truw
+ */
+ 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 {
+ deselectAll();
+ focusedRow.toggleSelection(true);
+ }
+ }
+ }
+
+ /**
+ * 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.
+ *
+ * @return The keycode of the key
+ */
+ protected int getNavigationUpKey() {
+ return KeyCodes.KEY_UP;
+ }
+
+ /**
+ * Get the key that moves the selection head downwards. By default it is the
+ * down arrow key but by overriding this you can change the key to whatever
+ * you want.
+ *
+ * @return The keycode of the key
+ */
+ protected int getNavigationDownKey() {
+ return KeyCodes.KEY_DOWN;
+ }
+
+ /**
+ * Get the key that scrolls to the left in the table. By default it is the
+ * left arrow key but by overriding this you can change the key to whatever
+ * you want.
+ *
+ * @return The keycode of the key
+ */
+ protected int getNavigationLeftKey() {
+ return KeyCodes.KEY_LEFT;
+ }
+
+ /**
+ * Get the key that scroll to the right on the table. By default it is the
+ * right arrow key but by overriding this you can change the key to whatever
+ * you want.
+ *
+ * @return The keycode of the key
+ */
+ protected int getNavigationRightKey() {
+ return KeyCodes.KEY_RIGHT;
+ }
+
+ /**
+ * Get the key that selects an item in the table. By default it is the space
+ * bar key but by overriding this you can change the key to whatever you
+ * want.
+ *
+ * @return
+ */
+ protected int getNavigationSelectKey() {
+ return 32;
+ }
+
@SuppressWarnings("unchecked")
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
rendering = true;
@@ -314,10 +485,12 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
if (uidl.hasVariable("selected")) {
final Set<String> selectedKeys = uidl
.getStringArrayVariableAsSet("selected");
- selectedRowKeys.clear();
- selectedRowRanges.clear();
+ deselectAll();
for (String string : selectedKeys) {
- selectedRowKeys.add(string);
+ VScrollTableRow row = getRenderedRowByKey(string);
+ if (row != null && !row.isSelected()) {
+ row.toggleSelection(false);
+ }
}
}
@@ -621,6 +794,13 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
return tHead.getHeaderCell(colKey).getWidth();
}
+ /**
+ * Get a rendered row by its key
+ *
+ * @param key
+ * The key to search with
+ * @return
+ */
private VScrollTableRow getRenderedRowByKey(String key) {
final Iterator<Widget> it = scrollBody.iterator();
VScrollTableRow r = null;
@@ -632,6 +812,52 @@ 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){
+ 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;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the previous row from the given row
+ *
+ * @param row
+ * The row to calculate from
+ * @return The previous row or null if no row exists
+ */
+ private VScrollTableRow getPreviousRow(VScrollTableRow row) {
+ final Iterator<Widget> it = scrollBody.iterator();
+ VScrollTableRow r = null;
+ VScrollTableRow prev = null;
+ while (it.hasNext()) {
+ r = (VScrollTableRow) it.next();
+ if (r == row) {
+ return prev;
+ } else {
+ prev = r;
+ }
+ }
+ return null;
+ }
private void reOrderColumn(String columnKey, int newIndex) {
@@ -1255,6 +1481,9 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
onResizeEvent(event);
} else {
handleCaptionEvent(event);
+ if (DOM.eventGetType(event) == Event.ONMOUSEUP) {
+ onFocus(null);
+ }
}
}
}
@@ -1289,10 +1518,11 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
}
/**
- * Fires a header click event after the user has clicked a column header cell
+ * Fires a header click event after the user has clicked a column header
+ * cell
*
* @param event
- * The click event
+ * The click event
*/
private void fireHeaderClickedEvent(Event event) {
if (client.hasEventListeners(VScrollTable.this,
@@ -1300,8 +1530,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
MouseEventDetails details = new MouseEventDetails(event);
client.updateVariable(paintableId, "headerClickEvent", details
.toString(), false);
- client
- .updateVariable(paintableId, "headerClickCID", cid,
+ client.updateVariable(paintableId, "headerClickCID", cid,
immediate);
}
}
@@ -2122,6 +2351,10 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
public void onBrowserEvent(Event event) {
if (enabled && event != null) {
handleCaptionEvent(event);
+
+ if (DOM.eventGetType(event) == Event.ONMOUSEUP) {
+ onFocus(null);
+ }
}
}
@@ -2927,7 +3160,8 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
rowElement = Document.get().createTRElement();
setElement(rowElement);
DOM.sinkEvents(getElement(), Event.MOUSEEVENTS
- | Event.ONDBLCLICK | Event.ONCONTEXTMENU);
+ | Event.ONDBLCLICK | Event.ONCONTEXTMENU
+ | Event.ONKEYDOWN);
}
private void paintComponent(Paintable p, UIDL uidl) {
@@ -3117,6 +3351,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
client.updateVariable(paintableId, "clickedKey", ""
+ rowKey, false);
+
if (getElement() == targetTdOrTr.getParentElement()) {
/* A specific column was clicked */
int childIndex = DOM.getChildIndex(getElement(),
@@ -3172,6 +3407,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
case Event.ONMOUSEUP:
mDown = false;
handleClickEvent(event, targetTdOrTr);
+ onFocus(null);
if (event.getButton() == Event.BUTTON_LEFT
&& selectMode > Table.SELECT_MODE_NONE) {
@@ -3181,6 +3417,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
&& selectMode == SELECT_MODE_MULTI
&& multiselectmode == MULTISELECT_MODE_DEFAULT) {
toggleShiftSelection(false);
+ setRowFocus(this);
// Ctrl click
} else if ((event.getCtrlKey() || event
@@ -3188,6 +3425,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
&& selectMode == SELECT_MODE_MULTI
&& multiselectmode == MULTISELECT_MODE_DEFAULT) {
toggleSelection(true);
+ setRowFocus(this);
// Shift click
} else if (event.getShiftKey()
@@ -3200,14 +3438,16 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
if (multiselectmode == MULTISELECT_MODE_DEFAULT) {
deselectAll();
}
+
toggleSelection(multiselectmode == MULTISELECT_MODE_DEFAULT);
+ setRowFocus(this);
}
// Remove IE text selection hack
if (BrowserInfo.get().isIE()) {
((Element) event.getEventTarget().cast())
- .setPropertyJSO(
- "onselectstart", null);
+ .setPropertyJSO("onselectstart",
+ null);
}
// Note: changing the immediateness of this
@@ -3229,6 +3469,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
false);
}
+ // Send the selected rows
client
.updateVariable(
paintableId,
@@ -3301,9 +3542,9 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
// Prevent default text selection in IE
if (BrowserInfo.get().isIE()) {
((Element) event.getEventTarget().cast())
- .setPropertyJSO(
- "onselectstart",
- applyDisableTextSelectionIEHack());
+ .setPropertyJSO(
+ "onselectstart",
+ applyDisableTextSelectionIEHack());
}
event.stopPropagation();
@@ -3407,8 +3648,8 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
selectedRowKeys.add(String.valueOf(rowKey));
addStyleName("v-selected");
} else {
- selectedRowKeys.remove(String.valueOf(rowKey));
removeStyleName("v-selected");
+ selectedRowKeys.remove(String.valueOf(rowKey));
}
}
@@ -3425,7 +3666,8 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
* Ensures that we are in multiselect mode and that we have a
* previous selection which was not a deselection
*/
- if (selectedRowKeys.isEmpty() || lastSelectedRowKey < 0) {
+ if (selectedRowKeys.isEmpty() || lastSelectedRowKey < 0
+ || selectMode == SELECT_MODE_SINGLE) {
// No previous selection found
deselectAll();
toggleSelection(true);
@@ -3454,10 +3696,11 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
.valueOf(r));
if (row != null && !row.isSelected()) {
row.toggleSelection(false);
+ selectedRowKeys.add(String.valueOf(r));
}
}
}
-
+
// Toggle clicked rows selection
toggleSelection(false);
@@ -4128,4 +4371,160 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
}
+ /**
+ * Moves the selection head to a specific row
+ *
+ * @param row
+ * The row to where the selection head should move
+ */
+ private void setRowFocus(VScrollTableRow row) {
+
+ if (selectMode == SELECT_MODE_NONE) {
+ return;
+ }
+
+ // Remove previous selection
+ if (focusedRow != null) {
+ focusedRow.removeStyleName(CLASSNAME_SELECTION_FOCUS);
+ }
+
+ if (row != null) {
+ // Apply focus style to new selection
+ focusedRow = row;
+ focusedRow.addStyleName(CLASSNAME_SELECTION_FOCUS);
+
+ // Scroll up or down if needed
+ int rowTop = focusedRow.getElement().getAbsoluteTop();
+ int scrollTop = bodyContainer.getElement().getAbsoluteTop();
+ int scrollBottom = scrollTop
+ + bodyContainer.getElement().getOffsetHeight();
+ if (rowTop > scrollBottom - focusedRow.getOffsetHeight()) {
+ bodyContainer.setScrollPosition(bodyContainer
+ .getScrollPosition()
+ + focusedRow.getOffsetHeight());
+ } else if (rowTop < scrollTop) {
+ bodyContainer.setScrollPosition(bodyContainer
+ .getScrollPosition()
+ - focusedRow.getOffsetHeight());
+ }
+ }
+ }
+
+ /**
+ * Handles the keyboard events handled by the table
+ *
+ * @param event
+ * The keyboard event received
+ */
+ private void handleNavigation(Event event) {
+
+ // Down navigation
+ if (selectMode == SELECT_MODE_NONE
+ && event.getKeyCode() == getNavigationDownKey()) {
+ bodyContainer
+ .setScrollPosition(bodyContainer.getScrollPosition() + 5);
+ event.preventDefault();
+ } else if (event.getKeyCode() == getNavigationDownKey()) {
+ if (moveSelectionDown()) {
+ if (event.getShiftKey()) {
+ selectFocusedRow(false, true);
+ }
+ event.preventDefault();
+ }
+ }
+
+ // Up navigation
+ if (selectMode == SELECT_MODE_NONE
+ && event.getKeyCode() == getNavigationUpKey()) {
+ bodyContainer
+ .setScrollPosition(bodyContainer.getScrollPosition() - 5);
+ event.preventDefault();
+ } else if (event.getKeyCode() == getNavigationUpKey()) {
+ if (moveSelectionUp()) {
+ if (event.getShiftKey()) {
+ selectFocusedRow(false, true);
+ }
+ event.preventDefault();
+ }
+
+ // Left navigation
+ } else if (event.getKeyCode() == getNavigationLeftKey()) {
+ bodyContainer.setHorizontalScrollPosition(bodyContainer
+ .getHorizontalScrollPosition() - 5);
+ event.preventDefault();
+
+ // Right navigation
+ } else if (event.getKeyCode() == getNavigationRightKey()) {
+ bodyContainer.setHorizontalScrollPosition(bodyContainer
+ .getHorizontalScrollPosition() + 5);
+ event.preventDefault();
+ }
+
+ // Select navigation
+ if (selectMode > SELECT_MODE_NONE
+ && event.getKeyCode() == getNavigationSelectKey()) {
+ selectFocusedRow(event.getCtrlKey() || event.getMetaKey(),
+ event.getShiftKey());
+
+ event.preventDefault();
+
+ // Send the selected rows
+ client
+ .updateVariable(paintableId, "selected",
+ selectedRowKeys
+ .toArray(new String[selectedRowKeys
+ .size()]), immediate);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.event.dom.client.KeyPressHandler#onKeyPress(com.google
+ * .gwt.event.dom.client.KeyPressEvent)
+ */
+ public void onKeyPress(KeyPressEvent event) {
+ handleNavigation((Event) event.getNativeEvent().cast());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.event.dom.client.KeyDownHandler#onKeyDown(com.google.gwt
+ * .event.dom.client.KeyDownEvent)
+ */
+ public void onKeyDown(KeyDownEvent event) {
+ handleNavigation((Event) event.getNativeEvent().cast());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.event.dom.client.FocusHandler#onFocus(com.google.gwt.event
+ * .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();
+ }
+ if (focusedRow == null) {
+ setRowFocus((VScrollTableRow) scrollBody.iterator().next());
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.event.dom.client.BlurHandler#onBlur(com.google.gwt.event
+ * .dom.client.BlurEvent)
+ */
+ public void onBlur(BlurEvent event) {
+ setRowFocus(null);
+ }
+
}
diff --git a/src/com/vaadin/ui/Table.java b/src/com/vaadin/ui/Table.java
index 234173c2f1..dcebfa2672 100644
--- a/src/com/vaadin/ui/Table.java
+++ b/src/com/vaadin/ui/Table.java
@@ -1926,11 +1926,13 @@ public class Table extends AbstractSelect implements Action.Container,
}
// Add range items
- for (String range : ranges) {
- String[] limits = range.split("-");
- int start = Integer.valueOf(limits[0]);
- int end = Integer.valueOf(limits[1]);
- s.addAll(getItemIdsInRange(start, end));
+ if (ranges != null) {
+ for (String range : ranges) {
+ String[] limits = range.split("-");
+ int start = Integer.valueOf(limits[0]);
+ int end = Integer.valueOf(limits[1]);
+ s.addAll(getItemIdsInRange(start, end));
+ }
}
setValue(s, true);