summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--client/src/com/vaadin/client/connectors/GridConnector.java32
-rw-r--r--client/src/com/vaadin/client/widgets/Grid.java40
-rw-r--r--server/src/com/vaadin/ui/Grid.java2
-rw-r--r--shared/src/com/vaadin/shared/ui/grid/GridState.java4
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java1
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridFocusTest.java79
6 files changed, 150 insertions, 8 deletions
diff --git a/client/src/com/vaadin/client/connectors/GridConnector.java b/client/src/com/vaadin/client/connectors/GridConnector.java
index d31baaa665..3eb92ab94c 100644
--- a/client/src/com/vaadin/client/connectors/GridConnector.java
+++ b/client/src/com/vaadin/client/connectors/GridConnector.java
@@ -32,11 +32,17 @@ import java.util.logging.Logger;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.NativeEvent;
+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.shared.HandlerRegistration;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ComponentConnector;
import com.vaadin.client.ConnectorHierarchyChangeEvent;
import com.vaadin.client.DeferredWorker;
+import com.vaadin.client.EventHelper;
import com.vaadin.client.MouseEventDetailsBuilder;
import com.vaadin.client.annotations.OnStateChange;
import com.vaadin.client.communication.StateChangeEvent;
@@ -80,6 +86,7 @@ import com.vaadin.client.widgets.Grid.FooterRow;
import com.vaadin.client.widgets.Grid.HeaderCell;
import com.vaadin.client.widgets.Grid.HeaderRow;
import com.vaadin.shared.Connector;
+import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc;
import com.vaadin.shared.data.sort.SortDirection;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.grid.DetailsConnectorChange;
@@ -112,7 +119,7 @@ import elemental.json.JsonValue;
*/
@Connect(com.vaadin.ui.Grid.class)
public class GridConnector extends AbstractHasComponentsConnector implements
- SimpleManagedLayout, DeferredWorker {
+ SimpleManagedLayout, DeferredWorker, FocusHandler, BlurHandler {
private static final class CustomCellStyleGenerator implements
CellStyleGenerator<JsonObject> {
@@ -757,6 +764,9 @@ public class GridConnector extends AbstractHasComponentsConnector implements
private final LazyDetailsScrollAdjuster lazyDetailsScrollAdjuster = new LazyDetailsScrollAdjuster();
+ private HandlerRegistration focusHandlerRegistration = null;
+ private HandlerRegistration blurHandlerRegistration = null;
+
@Override
@SuppressWarnings("unchecked")
public Grid<JsonObject> getWidget() {
@@ -982,6 +992,12 @@ public class GridConnector extends AbstractHasComponentsConnector implements
getWidget().resetSizesFromDom();
lastKnownTheme = activeTheme;
}
+
+ // Focus and blur events
+ focusHandlerRegistration = EventHelper.updateFocusHandler(this,
+ focusHandlerRegistration);
+ blurHandlerRegistration = EventHelper.updateBlurHandler(this,
+ blurHandlerRegistration);
}
private void updateSelectDeselectAllowed() {
@@ -1418,4 +1434,18 @@ public class GridConnector extends AbstractHasComponentsConnector implements
public DetailsListener getDetailsListener() {
return detailsListener;
}
+
+ @Override
+ public void onFocus(FocusEvent event) {
+ // EventHelper.updateFocusHandler ensures that this is called only when
+ // there is a listener on server side
+ getRpcProxy(FocusAndBlurServerRpc.class).focus();
+ }
+
+ @Override
+ public void onBlur(BlurEvent event) {
+ // EventHelper.updateFocusHandler ensures that this is called only when
+ // there is a listener on server side
+ getRpcProxy(FocusAndBlurServerRpc.class).blur();
+ }
}
diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java
index c20bdb0bd4..9768a589f6 100644
--- a/client/src/com/vaadin/client/widgets/Grid.java
+++ b/client/src/com/vaadin/client/widgets/Grid.java
@@ -74,12 +74,14 @@ import com.google.gwt.user.client.ui.ResizeComposite;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.BrowserInfo;
import com.vaadin.client.DeferredWorker;
+import com.vaadin.client.Focusable;
import com.vaadin.client.WidgetUtil;
import com.vaadin.client.data.DataChangeHandler;
import com.vaadin.client.data.DataSource;
import com.vaadin.client.renderers.ComplexRenderer;
import com.vaadin.client.renderers.Renderer;
import com.vaadin.client.renderers.WidgetRenderer;
+import com.vaadin.client.ui.FocusUtil;
import com.vaadin.client.ui.SubPartAware;
import com.vaadin.client.ui.dd.DragAndDropHandler;
import com.vaadin.client.widget.escalator.Cell;
@@ -203,8 +205,8 @@ import com.vaadin.shared.util.SharedUtil;
* @author Vaadin Ltd
*/
public class Grid<T> extends ResizeComposite implements
- HasSelectionHandlers<T>, SubPartAware, DeferredWorker, HasWidgets,
- HasEnabled {
+ HasSelectionHandlers<T>, SubPartAware, DeferredWorker, Focusable,
+ com.google.gwt.user.client.ui.Focusable, HasWidgets, HasEnabled {
/**
* Enum describing different sections of Grid.
@@ -6158,6 +6160,14 @@ public class Grid<T> extends ResizeComposite implements
return;
}
+ String eventType = event.getType();
+
+ if (eventType.equals(BrowserEvents.FOCUS)
+ || eventType.equals(BrowserEvents.BLUR)) {
+ super.onBrowserEvent(event);
+ return;
+ }
+
EventTarget target = event.getEventTarget();
if (!Element.is(target) || isOrContainsInSpacer(Element.as(target))) {
@@ -6168,7 +6178,6 @@ public class Grid<T> extends ResizeComposite implements
RowContainer container = escalator.findRowContainer(e);
Cell cell;
- String eventType = event.getType();
if (container == null) {
if (eventType.equals(BrowserEvents.KEYDOWN)
|| eventType.equals(BrowserEvents.KEYUP)
@@ -7773,4 +7782,29 @@ public class Grid<T> extends ResizeComposite implements
sidebar.close();
}
}
+
+ @Override
+ public int getTabIndex() {
+ return FocusUtil.getTabIndex(this);
+ }
+
+ @Override
+ public void setAccessKey(char key) {
+ FocusUtil.setAccessKey(this, key);
+ }
+
+ @Override
+ public void setFocus(boolean focused) {
+ FocusUtil.setFocus(this, focused);
+ }
+
+ @Override
+ public void setTabIndex(int index) {
+ FocusUtil.setTabIndex(this, index);
+ }
+
+ @Override
+ public void focus() {
+ setFocus(true);
+ }
}
diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java
index 075020b312..534146e3d7 100644
--- a/server/src/com/vaadin/ui/Grid.java
+++ b/server/src/com/vaadin/ui/Grid.java
@@ -172,7 +172,7 @@ import elemental.json.JsonValue;
* @since 7.4
* @author Vaadin Ltd
*/
-public class Grid extends AbstractComponent implements SelectionNotifier,
+public class Grid extends AbstractFocusable implements SelectionNotifier,
SortNotifier, SelectiveRenderer, ItemClickNotifier {
/**
diff --git a/shared/src/com/vaadin/shared/ui/grid/GridState.java b/shared/src/com/vaadin/shared/ui/grid/GridState.java
index e039f70988..bb35659591 100644
--- a/shared/src/com/vaadin/shared/ui/grid/GridState.java
+++ b/shared/src/com/vaadin/shared/ui/grid/GridState.java
@@ -19,9 +19,9 @@ package com.vaadin.shared.ui.grid;
import java.util.ArrayList;
import java.util.List;
-import com.vaadin.shared.AbstractComponentState;
import com.vaadin.shared.annotations.DelegateToWidget;
import com.vaadin.shared.data.sort.SortDirection;
+import com.vaadin.shared.ui.TabIndexState;
/**
* The shared state for the {@link com.vaadin.ui.components.grid.Grid} component
@@ -29,7 +29,7 @@ import com.vaadin.shared.data.sort.SortDirection;
* @since 7.4
* @author Vaadin Ltd
*/
-public class GridState extends AbstractComponentState {
+public class GridState extends TabIndexState {
/**
* A description of which of the three bundled SelectionModels is currently
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java
index 18f2d02e93..8d8be84169 100644
--- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java
@@ -627,7 +627,6 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
}
}
});
-
createBooleanAction("Single select allow deselect", "State",
singleSelectAllowDeselect, new Command<Grid, Boolean>() {
@Override
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridFocusTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridFocusTest.java
new file mode 100644
index 0000000000..ca9d78409c
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridFocusTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.components.grid.basicfeatures.server;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.vaadin.testbench.elements.MenuBarElement;
+import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest;
+
+/**
+ * Test for server-side Grid focus features.
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+public class GridFocusTest extends GridBasicFeaturesTest {
+
+ @Before
+ public void setUp() {
+ openTestURL();
+ }
+
+ @Test
+ public void testFocusListener() {
+ selectMenuPath("Component", "Listeners", "Focus listener");
+
+ getGridElement().click();
+
+ assertTrue("Focus listener should be invoked",
+ getLogRow(0).contains("FocusEvent"));
+ }
+
+ @Test
+ public void testBlurListener() {
+ selectMenuPath("Component", "Listeners", "Blur listener");
+
+ getGridElement().click();
+ $(MenuBarElement.class).first().click();
+
+ assertTrue("Blur listener should be invoked",
+ getLogRow(0).contains("BlurEvent"));
+ }
+
+ @Test
+ public void testProgrammaticFocus() {
+ selectMenuPath("Component", "State", "Set focus");
+
+ assertTrue("Grid cell (0, 0) should be focused", getGridElement()
+ .getCell(0, 0).isFocused());
+ }
+
+ @Test
+ public void testTabIndex() {
+ assertEquals(getGridElement().getAttribute("tabindex"), "0");
+
+ selectMenuPath("Component", "State", "Tab index", "-1");
+ assertEquals(getGridElement().getAttribute("tabindex"), "-1");
+
+ selectMenuPath("Component", "State", "Tab index", "10");
+ assertEquals(getGridElement().getAttribute("tabindex"), "10");
+ }
+}