summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--client/src/com/vaadin/client/ApplicationConnection.java11
-rw-r--r--client/src/com/vaadin/client/EventHelper.java17
-rw-r--r--client/src/com/vaadin/client/connectors/GridConnector.java34
-rw-r--r--client/src/com/vaadin/client/ui/ConnectorFocusAndBlurHandler.java87
-rw-r--r--client/src/com/vaadin/client/ui/VButton.java3
-rw-r--r--client/src/com/vaadin/client/ui/button/ButtonConnector.java38
-rw-r--r--client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java34
-rw-r--r--client/src/com/vaadin/client/ui/nativebutton/NativeButtonConnector.java35
-rw-r--r--client/src/com/vaadin/client/ui/nativeselect/NativeSelectConnector.java44
-rw-r--r--client/src/com/vaadin/client/ui/ui/UIConnector.java18
-rw-r--r--client/src/com/vaadin/client/widget/grid/events/EditorCloseEvent.java34
-rw-r--r--client/src/com/vaadin/client/widget/grid/events/EditorEvent.java108
-rw-r--r--client/src/com/vaadin/client/widget/grid/events/EditorEventHandler.java49
-rw-r--r--client/src/com/vaadin/client/widget/grid/events/EditorMoveEvent.java34
-rw-r--r--client/src/com/vaadin/client/widget/grid/events/EditorOpenEvent.java34
-rw-r--r--client/src/com/vaadin/client/widgets/Grid.java213
-rw-r--r--server/src/com/vaadin/ui/AbstractFocusable.java134
-rw-r--r--server/src/com/vaadin/ui/Button.java105
-rw-r--r--server/src/com/vaadin/ui/Grid.java184
-rw-r--r--shared/src/com/vaadin/shared/ui/grid/GridConstants.java15
-rw-r--r--shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java25
-rw-r--r--shared/src/com/vaadin/shared/ui/grid/GridState.java8
-rw-r--r--uitest/src/com/vaadin/tests/components/AbstractComponentTest.java41
-rw-r--r--uitest/src/com/vaadin/tests/components/abstractfield/AbstractFieldTest.java11
-rw-r--r--uitest/src/com/vaadin/tests/components/button/Buttons2.java3
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java38
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java217
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java260
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java178
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridFocusTest.java79
30 files changed, 1597 insertions, 494 deletions
diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java
index 64511059d9..510994745e 100644
--- a/client/src/com/vaadin/client/ApplicationConnection.java
+++ b/client/src/com/vaadin/client/ApplicationConnection.java
@@ -63,6 +63,7 @@ import com.google.gwt.user.client.Window.ClosingHandler;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ApplicationConfiguration.ErrorMessage;
+import com.vaadin.client.ApplicationConnection.ApplicationStoppedEvent;
import com.vaadin.client.ResourceLoader.ResourceLoadEvent;
import com.vaadin.client.ResourceLoader.ResourceLoadListener;
import com.vaadin.client.communication.HasJavaScriptConnectorHelper;
@@ -94,7 +95,6 @@ import com.vaadin.client.ui.VOverlay;
import com.vaadin.client.ui.dd.VDragAndDropManager;
import com.vaadin.client.ui.ui.UIConnector;
import com.vaadin.client.ui.window.WindowConnector;
-import com.vaadin.shared.AbstractComponentState;
import com.vaadin.shared.ApplicationConstants;
import com.vaadin.shared.JsonConstants;
import com.vaadin.shared.VaadinUriResolver;
@@ -3441,20 +3441,19 @@ public class ApplicationConnection implements HasHandlers {
* before the component is updated so the value is correct if called from
* updatedFromUIDL.
*
- * @param paintable
+ * @param connector
* The connector to register event listeners for
* @param eventIdentifier
* The identifier for the event
* @return true if at least one listener has been registered on server side
* for the event identified by eventIdentifier.
* @deprecated As of 7.0. Use
- * {@link AbstractComponentState#hasEventListener(String)}
- * instead
+ * {@link AbstractConnector#hasEventListener(String)} instead
*/
@Deprecated
- public boolean hasEventListeners(ComponentConnector paintable,
+ public boolean hasEventListeners(ComponentConnector connector,
String eventIdentifier) {
- return paintable.hasEventListener(eventIdentifier);
+ return connector.hasEventListener(eventIdentifier);
}
/**
diff --git a/client/src/com/vaadin/client/EventHelper.java b/client/src/com/vaadin/client/EventHelper.java
index f251215d41..1ee252af0f 100644
--- a/client/src/com/vaadin/client/EventHelper.java
+++ b/client/src/com/vaadin/client/EventHelper.java
@@ -51,7 +51,6 @@ import com.google.gwt.user.client.ui.Widget;
*
*
* </pre>
- *
*/
public class EventHelper {
@@ -69,7 +68,7 @@ public class EventHelper {
*/
public static <T extends ComponentConnector & FocusHandler> HandlerRegistration updateFocusHandler(
T connector, HandlerRegistration handlerRegistration) {
- return updateHandler(connector, FOCUS, handlerRegistration,
+ return updateHandler(connector, connector, FOCUS, handlerRegistration,
FocusEvent.getType(), connector.getWidget());
}
@@ -89,7 +88,7 @@ public class EventHelper {
*/
public static <T extends ComponentConnector & FocusHandler> HandlerRegistration updateFocusHandler(
T connector, HandlerRegistration handlerRegistration, Widget widget) {
- return updateHandler(connector, FOCUS, handlerRegistration,
+ return updateHandler(connector, connector, FOCUS, handlerRegistration,
FocusEvent.getType(), widget);
}
@@ -107,7 +106,7 @@ public class EventHelper {
*/
public static <T extends ComponentConnector & BlurHandler> HandlerRegistration updateBlurHandler(
T connector, HandlerRegistration handlerRegistration) {
- return updateHandler(connector, BLUR, handlerRegistration,
+ return updateHandler(connector, connector, BLUR, handlerRegistration,
BlurEvent.getType(), connector.getWidget());
}
@@ -128,23 +127,21 @@ public class EventHelper {
*/
public static <T extends ComponentConnector & BlurHandler> HandlerRegistration updateBlurHandler(
T connector, HandlerRegistration handlerRegistration, Widget widget) {
- return updateHandler(connector, BLUR, handlerRegistration,
+ return updateHandler(connector, connector, BLUR, handlerRegistration,
BlurEvent.getType(), widget);
}
- private static <H extends EventHandler> HandlerRegistration updateHandler(
- ComponentConnector connector, String eventIdentifier,
+ public static <H extends EventHandler> HandlerRegistration updateHandler(
+ ComponentConnector connector, H handler, String eventIdentifier,
HandlerRegistration handlerRegistration, Type<H> type, Widget widget) {
if (connector.hasEventListener(eventIdentifier)) {
if (handlerRegistration == null) {
- handlerRegistration = widget.addDomHandler((H) connector, type);
+ handlerRegistration = widget.addDomHandler(handler, type);
}
} else if (handlerRegistration != null) {
handlerRegistration.removeHandler();
handlerRegistration = null;
}
return handlerRegistration;
-
}
-
}
diff --git a/client/src/com/vaadin/client/connectors/GridConnector.java b/client/src/com/vaadin/client/connectors/GridConnector.java
index d3fa678c3e..8e27f526bf 100644
--- a/client/src/com/vaadin/client/connectors/GridConnector.java
+++ b/client/src/com/vaadin/client/connectors/GridConnector.java
@@ -46,6 +46,7 @@ import com.vaadin.client.data.DataSource.RowHandle;
import com.vaadin.client.renderers.Renderer;
import com.vaadin.client.ui.AbstractFieldConnector;
import com.vaadin.client.ui.AbstractHasComponentsConnector;
+import com.vaadin.client.ui.ConnectorFocusAndBlurHandler;
import com.vaadin.client.ui.SimpleManagedLayout;
import com.vaadin.client.widget.grid.CellReference;
import com.vaadin.client.widget.grid.CellStyleGenerator;
@@ -59,6 +60,10 @@ import com.vaadin.client.widget.grid.events.ColumnReorderEvent;
import com.vaadin.client.widget.grid.events.ColumnReorderHandler;
import com.vaadin.client.widget.grid.events.ColumnVisibilityChangeEvent;
import com.vaadin.client.widget.grid.events.ColumnVisibilityChangeHandler;
+import com.vaadin.client.widget.grid.events.EditorCloseEvent;
+import com.vaadin.client.widget.grid.events.EditorEventHandler;
+import com.vaadin.client.widget.grid.events.EditorMoveEvent;
+import com.vaadin.client.widget.grid.events.EditorOpenEvent;
import com.vaadin.client.widget.grid.events.GridClickEvent;
import com.vaadin.client.widget.grid.events.GridDoubleClickEvent;
import com.vaadin.client.widget.grid.events.SelectAllEvent;
@@ -905,9 +910,38 @@ public class GridConnector extends AbstractHasComponentsConnector implements
getWidget().addColumnReorderHandler(columnReorderHandler);
getWidget().addColumnVisibilityChangeHandler(
columnVisibilityChangeHandler);
+
+ ConnectorFocusAndBlurHandler.addHandlers(this);
+
getWidget().setDetailsGenerator(customDetailsGenerator);
getLayoutManager().registerDependency(this, getWidget().getElement());
+ getWidget().addEditorEventHandler(new EditorEventHandler() {
+ @Override
+ public void onEditorOpen(EditorOpenEvent e) {
+ if (hasEventListener(GridConstants.EDITOR_OPEN_EVENT_ID)) {
+ String rowKey = getRowKey((JsonObject) e.getRow());
+ getRpcProxy(GridServerRpc.class).editorOpen(rowKey);
+ }
+ }
+
+ @Override
+ public void onEditorMove(EditorMoveEvent e) {
+ if (hasEventListener(GridConstants.EDITOR_MOVE_EVENT_ID)) {
+ String rowKey = getRowKey((JsonObject) e.getRow());
+ getRpcProxy(GridServerRpc.class).editorMove(rowKey);
+ }
+ }
+
+ @Override
+ public void onEditorClose(EditorCloseEvent e) {
+ if (hasEventListener(GridConstants.EDITOR_CLOSE_EVENT_ID)) {
+ String rowKey = getRowKey((JsonObject) e.getRow());
+ getRpcProxy(GridServerRpc.class).editorClose(rowKey);
+ }
+ }
+ });
+
layout();
}
diff --git a/client/src/com/vaadin/client/ui/ConnectorFocusAndBlurHandler.java b/client/src/com/vaadin/client/ui/ConnectorFocusAndBlurHandler.java
new file mode 100644
index 0000000000..817d070a9f
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/ConnectorFocusAndBlurHandler.java
@@ -0,0 +1,87 @@
+/*
+ * 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.client.ui;
+
+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.ui.Widget;
+import com.vaadin.client.EventHelper;
+import com.vaadin.client.communication.StateChangeEvent;
+import com.vaadin.client.communication.StateChangeEvent.StateChangeHandler;
+import com.vaadin.shared.EventId;
+import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc;
+
+/**
+ * A handler for focus and blur events which uses {@link FocusAndBlurServerRpc}
+ * to transmit received events to the server. Events are only handled if there
+ * is a corresponding listener on the server side.
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+public class ConnectorFocusAndBlurHandler implements StateChangeHandler,
+ FocusHandler, BlurHandler {
+
+ private final AbstractComponentConnector connector;
+ private final Widget widget;
+ private HandlerRegistration focusRegistration = null;
+ private HandlerRegistration blurRegistration = null;
+
+ public static void addHandlers(AbstractComponentConnector connector) {
+ addHandlers(connector, connector.getWidget());
+ }
+
+ public static void addHandlers(AbstractComponentConnector connector,
+ Widget widget) {
+ connector.addStateChangeHandler("registeredEventListeners",
+ new ConnectorFocusAndBlurHandler(connector, widget));
+ }
+
+ private ConnectorFocusAndBlurHandler(AbstractComponentConnector connector,
+ Widget widget) {
+ this.connector = connector;
+ this.widget = widget;
+ }
+
+ @Override
+ public void onStateChanged(StateChangeEvent stateChangeEvent) {
+ focusRegistration = EventHelper.updateHandler(connector, this,
+ EventId.FOCUS, focusRegistration, FocusEvent.getType(), widget);
+ blurRegistration = EventHelper.updateHandler(connector, this,
+ EventId.BLUR, blurRegistration, BlurEvent.getType(), widget);
+ }
+
+ @Override
+ public void onFocus(FocusEvent event) {
+ // updateHandler ensures that this is called only when
+ // there is a listener on the server side
+ getRpc().focus();
+ }
+
+ @Override
+ public void onBlur(BlurEvent event) {
+ // updateHandler ensures that this is called only when
+ // there is a listener on the server side
+ getRpc().blur();
+ }
+
+ private FocusAndBlurServerRpc getRpc() {
+ return connector.getRpcProxy(FocusAndBlurServerRpc.class);
+ }
+}
diff --git a/client/src/com/vaadin/client/ui/VButton.java b/client/src/com/vaadin/client/ui/VButton.java
index bf321f7f00..2eb967c4fa 100644
--- a/client/src/com/vaadin/client/ui/VButton.java
+++ b/client/src/com/vaadin/client/ui/VButton.java
@@ -23,7 +23,6 @@ import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
-import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.FocusWidget;
@@ -94,8 +93,6 @@ public class VButton extends FocusWidget implements ClickHandler {
/** For internal use only. May be removed or replaced in the future. */
public int clickShortcut = 0;
- private HandlerRegistration focusHandlerRegistration;
- private HandlerRegistration blurHandlerRegistration;
private long lastClickTime = 0;
public VButton() {
diff --git a/client/src/com/vaadin/client/ui/button/ButtonConnector.java b/client/src/com/vaadin/client/ui/button/ButtonConnector.java
index 2d13d62a91..2c2006e19b 100644
--- a/client/src/com/vaadin/client/ui/button/ButtonConnector.java
+++ b/client/src/com/vaadin/client/ui/button/ButtonConnector.java
@@ -16,24 +16,17 @@
package com.vaadin.client.ui.button;
-import com.google.gwt.event.dom.client.BlurEvent;
-import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
-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.DOM;
-import com.vaadin.client.EventHelper;
import com.vaadin.client.MouseEventDetailsBuilder;
import com.vaadin.client.VCaption;
import com.vaadin.client.annotations.OnStateChange;
-import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.ui.AbstractComponentConnector;
+import com.vaadin.client.ui.ConnectorFocusAndBlurHandler;
import com.vaadin.client.ui.Icon;
import com.vaadin.client.ui.VButton;
import com.vaadin.shared.MouseEventDetails;
-import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.Connect.LoadStyle;
import com.vaadin.shared.ui.button.ButtonServerRpc;
@@ -42,10 +35,7 @@ import com.vaadin.ui.Button;
@Connect(value = Button.class, loadStyle = LoadStyle.EAGER)
public class ButtonConnector extends AbstractComponentConnector implements
- BlurHandler, FocusHandler, ClickHandler {
-
- private HandlerRegistration focusHandlerRegistration = null;
- private HandlerRegistration blurHandlerRegistration = null;
+ ClickHandler {
@Override
public boolean delegateCaptionHandling() {
@@ -57,6 +47,7 @@ public class ButtonConnector extends AbstractComponentConnector implements
super.init();
getWidget().addClickHandler(this);
getWidget().client = getConnection();
+ ConnectorFocusAndBlurHandler.addHandlers(this);
}
@OnStateChange("errorMessage")
@@ -90,15 +81,6 @@ public class ButtonConnector extends AbstractComponentConnector implements
}
}
- @Override
- public void onStateChanged(StateChangeEvent stateChangeEvent) {
- super.onStateChanged(stateChangeEvent);
- focusHandlerRegistration = EventHelper.updateFocusHandler(this,
- focusHandlerRegistration);
- blurHandlerRegistration = EventHelper.updateBlurHandler(this,
- blurHandlerRegistration);
- }
-
@OnStateChange({ "caption", "captionAsHtml" })
void setCaption() {
VCaption.setCaptionText(getWidget().captionElement, getState());
@@ -127,20 +109,6 @@ public class ButtonConnector extends AbstractComponentConnector implements
}
@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();
- }
-
- @Override
public void onClick(ClickEvent event) {
if (getState().disableOnClick) {
// Simulate getting disabled from the server without waiting for the
diff --git a/client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java b/client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java
index 63984ff225..3daac849d0 100644
--- a/client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java
+++ b/client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java
@@ -16,25 +16,19 @@
package com.vaadin.client.ui.checkbox;
import com.google.gwt.dom.client.Style.Display;
-import com.google.gwt.event.dom.client.BlurEvent;
-import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
-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.DOM;
import com.google.gwt.user.client.Event;
-import com.vaadin.client.EventHelper;
import com.vaadin.client.MouseEventDetailsBuilder;
import com.vaadin.client.VCaption;
import com.vaadin.client.VTooltip;
import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.ui.AbstractFieldConnector;
+import com.vaadin.client.ui.ConnectorFocusAndBlurHandler;
import com.vaadin.client.ui.Icon;
import com.vaadin.client.ui.VCheckBox;
import com.vaadin.shared.MouseEventDetails;
-import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.checkbox.CheckBoxServerRpc;
import com.vaadin.shared.ui.checkbox.CheckBoxState;
@@ -42,10 +36,7 @@ import com.vaadin.ui.CheckBox;
@Connect(CheckBox.class)
public class CheckBoxConnector extends AbstractFieldConnector implements
- FocusHandler, BlurHandler, ClickHandler {
-
- private HandlerRegistration focusHandlerRegistration;
- private HandlerRegistration blurHandlerRegistration;
+ ClickHandler {
@Override
public boolean delegateCaptionHandling() {
@@ -55,21 +46,18 @@ public class CheckBoxConnector extends AbstractFieldConnector implements
@Override
protected void init() {
super.init();
+
getWidget().addClickHandler(this);
getWidget().client = getConnection();
getWidget().id = getConnectorId();
+ ConnectorFocusAndBlurHandler.addHandlers(this);
}
@Override
public void onStateChanged(StateChangeEvent stateChangeEvent) {
super.onStateChanged(stateChangeEvent);
- focusHandlerRegistration = EventHelper.updateFocusHandler(this,
- focusHandlerRegistration);
- blurHandlerRegistration = EventHelper.updateBlurHandler(this,
- blurHandlerRegistration);
-
if (null != getState().errorMessage) {
getWidget().setAriaInvalid(true);
@@ -127,20 +115,6 @@ public class CheckBoxConnector extends AbstractFieldConnector implements
}
@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();
- }
-
- @Override
public void onClick(ClickEvent event) {
if (!isEnabled()) {
return;
diff --git a/client/src/com/vaadin/client/ui/nativebutton/NativeButtonConnector.java b/client/src/com/vaadin/client/ui/nativebutton/NativeButtonConnector.java
index 2aae9beae6..65d4a1eb9b 100644
--- a/client/src/com/vaadin/client/ui/nativebutton/NativeButtonConnector.java
+++ b/client/src/com/vaadin/client/ui/nativebutton/NativeButtonConnector.java
@@ -15,30 +15,20 @@
*/
package com.vaadin.client.ui.nativebutton;
-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.DOM;
-import com.vaadin.client.EventHelper;
import com.vaadin.client.VCaption;
import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.ui.AbstractComponentConnector;
+import com.vaadin.client.ui.ConnectorFocusAndBlurHandler;
import com.vaadin.client.ui.Icon;
import com.vaadin.client.ui.VNativeButton;
-import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.button.ButtonServerRpc;
import com.vaadin.shared.ui.button.NativeButtonState;
import com.vaadin.ui.NativeButton;
@Connect(NativeButton.class)
-public class NativeButtonConnector extends AbstractComponentConnector implements
- BlurHandler, FocusHandler {
-
- private HandlerRegistration focusHandlerRegistration;
- private HandlerRegistration blurHandlerRegistration;
+public class NativeButtonConnector extends AbstractComponentConnector {
@Override
public void init() {
@@ -47,6 +37,8 @@ public class NativeButtonConnector extends AbstractComponentConnector implements
getWidget().buttonRpcProxy = getRpcProxy(ButtonServerRpc.class);
getWidget().client = getConnection();
getWidget().paintableId = getConnectorId();
+
+ ConnectorFocusAndBlurHandler.addHandlers(this);
}
@Override
@@ -59,10 +51,6 @@ public class NativeButtonConnector extends AbstractComponentConnector implements
super.onStateChanged(stateChangeEvent);
getWidget().disableOnClick = getState().disableOnClick;
- focusHandlerRegistration = EventHelper.updateFocusHandler(this,
- focusHandlerRegistration);
- blurHandlerRegistration = EventHelper.updateBlurHandler(this,
- blurHandlerRegistration);
// Set text
VCaption.setCaptionText(getWidget(), getState());
@@ -107,19 +95,4 @@ public class NativeButtonConnector extends AbstractComponentConnector implements
public NativeButtonState getState() {
return (NativeButtonState) super.getState();
}
-
- @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/ui/nativeselect/NativeSelectConnector.java b/client/src/com/vaadin/client/ui/nativeselect/NativeSelectConnector.java
index 938903da9a..d6ff2015b4 100644
--- a/client/src/com/vaadin/client/ui/nativeselect/NativeSelectConnector.java
+++ b/client/src/com/vaadin/client/ui/nativeselect/NativeSelectConnector.java
@@ -16,55 +16,23 @@
package com.vaadin.client.ui.nativeselect;
-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.vaadin.client.EventHelper;
-import com.vaadin.client.annotations.OnStateChange;
+import com.vaadin.client.ui.ConnectorFocusAndBlurHandler;
import com.vaadin.client.ui.VNativeSelect;
import com.vaadin.client.ui.optiongroup.OptionGroupBaseConnector;
-import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc;
import com.vaadin.shared.ui.Connect;
import com.vaadin.ui.NativeSelect;
@Connect(NativeSelect.class)
-public class NativeSelectConnector extends OptionGroupBaseConnector implements
- BlurHandler, FocusHandler {
+public class NativeSelectConnector extends OptionGroupBaseConnector {
- private HandlerRegistration focusHandlerRegistration = null;
- private HandlerRegistration blurHandlerRegistration = null;
-
- public NativeSelectConnector() {
- super();
- }
-
- @OnStateChange("registeredEventListeners")
- private void onServerEventListenerChanged() {
- focusHandlerRegistration = EventHelper.updateFocusHandler(this,
- focusHandlerRegistration, getWidget().getSelect());
- blurHandlerRegistration = EventHelper.updateBlurHandler(this,
- blurHandlerRegistration, getWidget().getSelect());
+ @Override
+ protected void init() {
+ super.init();
+ ConnectorFocusAndBlurHandler.addHandlers(this, getWidget().getSelect());
}
@Override
public VNativeSelect getWidget() {
return (VNativeSelect) super.getWidget();
}
-
- @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/ui/ui/UIConnector.java b/client/src/com/vaadin/client/ui/ui/UIConnector.java
index 264b2de0e1..8249b45855 100644
--- a/client/src/com/vaadin/client/ui/ui/UIConnector.java
+++ b/client/src/com/vaadin/client/ui/ui/UIConnector.java
@@ -59,6 +59,7 @@ import com.vaadin.client.ResourceLoader.ResourceLoadEvent;
import com.vaadin.client.ResourceLoader.ResourceLoadListener;
import com.vaadin.client.ServerConnector;
import com.vaadin.client.UIDL;
+import com.vaadin.client.Util;
import com.vaadin.client.VConsole;
import com.vaadin.client.ValueMap;
import com.vaadin.client.annotations.OnStateChange;
@@ -319,19 +320,19 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
Scheduler.get().scheduleDeferred(new Command() {
@Override
public void execute() {
- ComponentConnector paintable = (ComponentConnector) uidl
+ ComponentConnector connector = (ComponentConnector) uidl
.getPaintableAttribute("focused", getConnection());
- if (paintable == null) {
+ if (connector == null) {
// Do not try to focus invisible components which not
// present in UIDL
return;
}
- final Widget toBeFocused = paintable.getWidget();
+ final Widget toBeFocused = connector.getWidget();
/*
* Two types of Widgets can be focused, either implementing
- * GWT HasFocus of a thinner Vaadin specific Focusable
+ * GWT Focusable of a thinner Vaadin specific Focusable
* interface.
*/
if (toBeFocused instanceof com.google.gwt.user.client.ui.Focusable) {
@@ -340,7 +341,14 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
} else if (toBeFocused instanceof Focusable) {
((Focusable) toBeFocused).focus();
} else {
- VConsole.log("Could not focus component");
+ getLogger()
+ .severe("Server is trying to set focus to the widget of connector "
+ + Util.getConnectorString(connector)
+ + " but it is not focusable. The widget should implement either "
+ + com.google.gwt.user.client.ui.Focusable.class
+ .getName()
+ + " or "
+ + Focusable.class.getName());
}
}
});
diff --git a/client/src/com/vaadin/client/widget/grid/events/EditorCloseEvent.java b/client/src/com/vaadin/client/widget/grid/events/EditorCloseEvent.java
new file mode 100644
index 0000000000..99f59aa82a
--- /dev/null
+++ b/client/src/com/vaadin/client/widget/grid/events/EditorCloseEvent.java
@@ -0,0 +1,34 @@
+/*
+ * 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.client.widget.grid.events;
+
+import com.vaadin.client.widget.grid.CellReference;
+
+/**
+ * Event that gets fired when an open editor is closed (and not reopened
+ * elsewhere)
+ */
+public class EditorCloseEvent extends EditorEvent {
+
+ public EditorCloseEvent(CellReference<?> cell) {
+ super(cell);
+ }
+
+ @Override
+ protected void dispatch(EditorEventHandler handler) {
+ handler.onEditorClose(this);
+ }
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/widget/grid/events/EditorEvent.java b/client/src/com/vaadin/client/widget/grid/events/EditorEvent.java
new file mode 100644
index 0000000000..eb34033197
--- /dev/null
+++ b/client/src/com/vaadin/client/widget/grid/events/EditorEvent.java
@@ -0,0 +1,108 @@
+/*
+ * 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.client.widget.grid.events;
+
+import com.google.gwt.event.shared.GwtEvent;
+import com.vaadin.client.widget.grid.CellReference;
+import com.vaadin.client.widgets.Grid;
+import com.vaadin.client.widgets.Grid.Column;
+
+/**
+ * Base class for editor events.
+ */
+public abstract class EditorEvent extends GwtEvent<EditorEventHandler> {
+ public static final Type<EditorEventHandler> TYPE = new Type<EditorEventHandler>();
+
+ private CellReference<?> cell;
+
+ protected EditorEvent(CellReference<?> cell) {
+ this.cell = cell;
+ }
+
+ @Override
+ public Type<EditorEventHandler> getAssociatedType() {
+ return TYPE;
+ }
+
+ /**
+ * Get a reference to the Grid that fired this Event.
+ *
+ * @return a Grid reference
+ */
+ @SuppressWarnings("unchecked")
+ public <T> Grid<T> getGrid() {
+ return (Grid<T>) cell.getGrid();
+ }
+
+ /**
+ * Get a reference to the cell that was active when this Event was fired.
+ * NOTE: do <i>NOT</i> rely on this information remaining accurate after
+ * leaving the event handler.
+ *
+ * @return a cell reference
+ */
+ @SuppressWarnings("unchecked")
+ public <T> CellReference<T> getCell() {
+ return (CellReference<T>) cell;
+ }
+
+ /**
+ * Get a reference to the row that was active when this Event was fired.
+ * NOTE: do <i>NOT</i> rely on this information remaining accurate after
+ * leaving the event handler.
+ *
+ * @return a row data object
+ */
+ @SuppressWarnings("unchecked")
+ public <T> T getRow() {
+ return (T) cell.getRow();
+ }
+
+ /**
+ * Get the index of the row that was active when this Event was fired. NOTE:
+ * do <i>NOT</i> rely on this information remaining accurate after leaving
+ * the event handler.
+ *
+ * @return an integer value
+ */
+ public int getRowIndex() {
+ return cell.getRowIndex();
+ }
+
+ /**
+ * Get a reference to the column that was active when this Event was fired.
+ * NOTE: do <i>NOT</i> rely on this information remaining accurate after
+ * leaving the event handler.
+ *
+ * @return a column object
+ */
+ @SuppressWarnings("unchecked")
+ public <C, T> Column<C, T> getColumn() {
+ return (Column<C, T>) cell.getColumn();
+ }
+
+ /**
+ * Get the index of the column that was active when this Event was fired.
+ * NOTE: do <i>NOT</i> rely on this information remaining accurate after
+ * leaving the event handler.
+ *
+ * @return an integer value
+ */
+ public int getColumnIndex() {
+ return cell.getColumnIndex();
+ }
+
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/widget/grid/events/EditorEventHandler.java b/client/src/com/vaadin/client/widget/grid/events/EditorEventHandler.java
new file mode 100644
index 0000000000..4f9396a9f1
--- /dev/null
+++ b/client/src/com/vaadin/client/widget/grid/events/EditorEventHandler.java
@@ -0,0 +1,49 @@
+/*
+ * 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.client.widget.grid.events;
+
+import com.google.gwt.event.shared.EventHandler;
+
+/**
+ * Common handler interface for editor events
+ */
+public interface EditorEventHandler extends EventHandler {
+
+ /**
+ * Action to perform when the editor has been opened
+ *
+ * @param e
+ * an editor open event object
+ */
+ public void onEditorOpen(EditorOpenEvent e);
+
+ /**
+ * Action to perform when the editor is re-opened on another row
+ *
+ * @param e
+ * an editor move event object
+ */
+ public void onEditorMove(EditorMoveEvent e);
+
+ /**
+ * Action to perform when the editor is closed
+ *
+ * @param e
+ * an editor close event object
+ */
+ public void onEditorClose(EditorCloseEvent e);
+
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/widget/grid/events/EditorMoveEvent.java b/client/src/com/vaadin/client/widget/grid/events/EditorMoveEvent.java
new file mode 100644
index 0000000000..0e5e2dcd7b
--- /dev/null
+++ b/client/src/com/vaadin/client/widget/grid/events/EditorMoveEvent.java
@@ -0,0 +1,34 @@
+/*
+ * 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.client.widget.grid.events;
+
+import com.vaadin.client.widget.grid.CellReference;
+
+/**
+ * Event that gets fired when an already open editor is closed and re-opened on
+ * another row
+ */
+public class EditorMoveEvent extends EditorEvent {
+
+ public EditorMoveEvent(CellReference<?> cell) {
+ super(cell);
+ }
+
+ @Override
+ protected void dispatch(EditorEventHandler handler) {
+ handler.onEditorMove(this);
+ }
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/widget/grid/events/EditorOpenEvent.java b/client/src/com/vaadin/client/widget/grid/events/EditorOpenEvent.java
new file mode 100644
index 0000000000..df0171945f
--- /dev/null
+++ b/client/src/com/vaadin/client/widget/grid/events/EditorOpenEvent.java
@@ -0,0 +1,34 @@
+/*
+ * 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.client.widget.grid.events;
+
+import com.vaadin.client.widget.grid.CellReference;
+
+/**
+ * Event that gets fired when the editor is opened
+ */
+public class EditorOpenEvent extends EditorEvent {
+
+ public EditorOpenEvent(CellReference<?> cell) {
+ super(cell);
+ }
+
+ @Override
+ protected void dispatch(EditorEventHandler handler) {
+ handler.onEditorOpen(this);
+ }
+
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java
index 22a0ae27fb..2717dc3580 100644
--- a/client/src/com/vaadin/client/widgets/Grid.java
+++ b/client/src/com/vaadin/client/widgets/Grid.java
@@ -41,6 +41,7 @@ import com.google.gwt.dom.client.EventTarget;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Node;
import com.google.gwt.dom.client.Style;
+import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.dom.client.TableCellElement;
import com.google.gwt.dom.client.TableRowElement;
@@ -120,6 +121,11 @@ import com.vaadin.client.widget.grid.events.ColumnReorderEvent;
import com.vaadin.client.widget.grid.events.ColumnReorderHandler;
import com.vaadin.client.widget.grid.events.ColumnVisibilityChangeEvent;
import com.vaadin.client.widget.grid.events.ColumnVisibilityChangeHandler;
+import com.vaadin.client.widget.grid.events.EditorCloseEvent;
+import com.vaadin.client.widget.grid.events.EditorEvent;
+import com.vaadin.client.widget.grid.events.EditorEventHandler;
+import com.vaadin.client.widget.grid.events.EditorMoveEvent;
+import com.vaadin.client.widget.grid.events.EditorOpenEvent;
import com.vaadin.client.widget.grid.events.FooterClickHandler;
import com.vaadin.client.widget.grid.events.FooterDoubleClickHandler;
import com.vaadin.client.widget.grid.events.FooterKeyDownHandler;
@@ -205,8 +211,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.
@@ -1192,6 +1198,7 @@ public class Grid<T> extends ResizeComposite implements
+ " remember to call success() or fail()?");
}
};
+
private final EditorRequestImpl.RequestCallback<T> bindRequestCallback = new EditorRequestImpl.RequestCallback<T>() {
@Override
public void onSuccess(EditorRequest<T> request) {
@@ -1226,6 +1233,12 @@ public class Grid<T> extends ResizeComposite implements
/** A set of all the columns that display an error flag. */
private final Set<Column<?, T>> columnErrors = new HashSet<Grid.Column<?, T>>();
+ private boolean buffered = true;
+
+ /** Original position of editor */
+ private double originalTop;
+ /** Original scroll position of grid when editor was opened */
+ private double originalScrollTop;
public Editor() {
saveButton = new Button();
@@ -1256,6 +1269,10 @@ public class Grid<T> extends ResizeComposite implements
messageWrapper.appendChild(message);
}
}
+ // In unbuffered mode only show message wrapper if there is an error
+ if (!isBuffered()) {
+ setMessageAndButtonsWrapperVisible(errorMessage != null);
+ }
}
public int getRow() {
@@ -1337,6 +1354,7 @@ public class Grid<T> extends ResizeComposite implements
handler.cancel(request);
state = State.INACTIVE;
updateSelectionCheckboxesAsNeeded(true);
+ grid.fireEvent(new EditorCloseEvent(grid.eventCell));
}
private void updateSelectionCheckboxesAsNeeded(boolean isEnabled) {
@@ -1436,11 +1454,19 @@ public class Grid<T> extends ResizeComposite implements
EditorRequest<T> request = new EditorRequestImpl<T>(grid,
rowIndex, bindRequestCallback);
handler.bind(request);
- grid.getEscalator().setScrollLocked(Direction.VERTICAL, true);
+ grid.getEscalator().setScrollLocked(Direction.VERTICAL,
+ isBuffered());
updateSelectionCheckboxesAsNeeded(false);
}
}
+ protected void hide() {
+ hideOverlay();
+ grid.getEscalator().setScrollLocked(Direction.VERTICAL, false);
+ state = State.INACTIVE;
+ updateSelectionCheckboxesAsNeeded(true);
+ }
+
protected void setGrid(final Grid<T> grid) {
assert grid != null : "Grid cannot be null";
assert this.grid == null : "Can only attach editor to Grid once";
@@ -1481,7 +1507,7 @@ public class Grid<T> extends ResizeComposite implements
/**
* Equivalent to {@code showOverlay()}. The argument is ignored.
- *
+ *
* @param unused
* ignored argument
*
@@ -1509,6 +1535,9 @@ public class Grid<T> extends ResizeComposite implements
@Override
public void onScroll(ScrollEvent event) {
updateHorizontalScrollPosition();
+ if (!isBuffered()) {
+ updateVerticalScrollPosition();
+ }
}
});
@@ -1549,8 +1578,12 @@ public class Grid<T> extends ResizeComposite implements
messageAndButtonsWrapper.appendChild(buttonsWrapper);
}
- attachWidget(saveButton, buttonsWrapper);
- attachWidget(cancelButton, buttonsWrapper);
+ if (isBuffered()) {
+ attachWidget(saveButton, buttonsWrapper);
+ attachWidget(cancelButton, buttonsWrapper);
+ }
+
+ setMessageAndButtonsWrapperVisible(isBuffered());
updateHorizontalScrollPosition();
@@ -1562,9 +1595,11 @@ public class Grid<T> extends ResizeComposite implements
int gridTop = gridElement.getAbsoluteTop();
double overlayTop = rowTop + bodyTop - gridTop;
- if (buttonsShouldBeRenderedBelow(tr)) {
+ originalScrollTop = grid.getScrollTop();
+ if (!isBuffered() || buttonsShouldBeRenderedBelow(tr)) {
// Default case, editor buttons are below the edited row
editorOverlay.getStyle().setTop(overlayTop, Unit.PX);
+ originalTop = overlayTop;
editorOverlay.getStyle().clearBottom();
} else {
// Move message and buttons wrapper on top of cell wrapper if
@@ -1684,6 +1719,35 @@ public class Grid<T> extends ResizeComposite implements
cellWrapper.getStyle().setLeft(-scrollLeft, Unit.PX);
}
+ /**
+ * Moves the editor overlay on scroll so that it stays on top of the
+ * edited row. This will also snap the editor to top or bottom of the
+ * row container if the edited row is scrolled out of the visible area.
+ */
+ private void updateVerticalScrollPosition() {
+ double newScrollTop = grid.getScrollTop();
+
+ int gridTop = grid.getElement().getAbsoluteTop();
+ int editorHeight = editorOverlay.getOffsetHeight();
+
+ Escalator escalator = grid.getEscalator();
+ TableSectionElement header = escalator.getHeader().getElement();
+ int footerTop = escalator.getFooter().getElement().getAbsoluteTop();
+ int headerBottom = header.getAbsoluteBottom();
+
+ double newTop = originalTop - (newScrollTop - originalScrollTop);
+
+ if (newTop + gridTop < headerBottom) {
+ // Snap editor to top of the row container
+ newTop = header.getOffsetHeight();
+ } else if (newTop + gridTop > footerTop - editorHeight) {
+ // Snap editor to the bottom of the row container
+ newTop = footerTop - editorHeight - gridTop;
+ }
+
+ editorOverlay.getStyle().setTop(newTop, Unit.PX);
+ }
+
protected void setGridEnabled(boolean enabled) {
// TODO: This should be informed to handler as well so possible
// fields can be disabled.
@@ -1760,6 +1824,23 @@ public class Grid<T> extends ResizeComposite implements
public boolean isEditorColumnError(Column<?, T> column) {
return columnErrors.contains(column);
}
+
+ public void setBuffered(boolean buffered) {
+ this.buffered = buffered;
+ setMessageAndButtonsWrapperVisible(buffered);
+ }
+
+ public boolean isBuffered() {
+ return buffered;
+ }
+
+ private void setMessageAndButtonsWrapperVisible(boolean visible) {
+ if (visible) {
+ messageAndButtonsWrapper.getStyle().clearDisplay();
+ } else {
+ messageAndButtonsWrapper.getStyle().setDisplay(Display.NONE);
+ }
+ }
}
public static abstract class AbstractGridKeyEvent<HANDLER extends AbstractGridKeyEventHandler>
@@ -5117,7 +5198,7 @@ public class Grid<T> extends ResizeComposite implements
sinkEvents(getHeader().getConsumedEvents());
sinkEvents(Arrays.asList(BrowserEvents.KEYDOWN, BrowserEvents.KEYUP,
BrowserEvents.KEYPRESS, BrowserEvents.DBLCLICK,
- BrowserEvents.MOUSEDOWN));
+ BrowserEvents.MOUSEDOWN, BrowserEvents.CLICK));
// Make ENTER and SHIFT+ENTER in the header perform sorting
addHeaderKeyUpHandler(new HeaderKeyUpHandler() {
@@ -5781,6 +5862,19 @@ public class Grid<T> extends ResizeComposite implements
return editor;
}
+ /**
+ * Add handler for editor open/move/close events
+ *
+ * @param handler
+ * editor handler object
+ * @return a {@link HandlerRegistration} object that can be used to remove
+ * the event handler
+ */
+ public HandlerRegistration addEditorEventHandler(EditorEventHandler handler) {
+ return addHandler(handler, EditorEvent.TYPE);
+
+ }
+
protected Escalator getEscalator() {
return escalator;
}
@@ -6235,6 +6329,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))) {
@@ -6245,7 +6347,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)
@@ -6357,27 +6458,44 @@ public class Grid<T> extends ResizeComposite implements
}
private boolean handleEditorEvent(Event event, RowContainer container) {
+ final int type = event.getTypeInt();
+ final int key = event.getKeyCode();
+ final boolean editorIsActive = editor.getState() != Editor.State.INACTIVE;
- final boolean closeEvent = event.getTypeInt() == Event.ONKEYDOWN
- && event.getKeyCode() == Editor.KEYCODE_HIDE;
- final boolean openEvent = event.getTypeInt() == Event.ONDBLCLICK
- || (event.getTypeInt() == Event.ONKEYDOWN && event.getKeyCode() == Editor.KEYCODE_SHOW);
+ final boolean openEvent = eventCell.isBody()
+ && (type == Event.ONDBLCLICK || (type == Event.ONKEYDOWN && key == Editor.KEYCODE_SHOW));
+
+ final boolean moveEvent = eventCell.isBody() && type == Event.ONCLICK;
+
+ final boolean closeEvent = type == Event.ONKEYDOWN
+ && key == Editor.KEYCODE_HIDE;
+
+ if (!editorIsActive && editor.isEnabled() && openEvent) {
+ editor.editRow(eventCell.getRowIndex(),
+ eventCell.getColumnIndexDOM());
+ fireEvent(new EditorOpenEvent(eventCell));
- if (editor.getState() != Editor.State.INACTIVE) {
- if (closeEvent) {
- editor.cancel();
- FocusUtil.setFocus(this, true);
- }
return true;
- }
- if (container == escalator.getBody() && editor.isEnabled() && openEvent) {
+ } else if (editorIsActive && moveEvent) {
+ editor.hide();
+ cellFocusHandler.setCellFocus(eventCell);
+
editor.editRow(eventCell.getRowIndex(),
eventCell.getColumnIndexDOM());
+
+ fireEvent(new EditorMoveEvent(eventCell));
+
+ return true;
+
+ } else if (editorIsActive && closeEvent) {
+ editor.cancel();
+ FocusUtil.setFocus(this, true);
+
return true;
}
- return false;
+ return editorIsActive;
}
private boolean handleRendererEvent(Event event, RowContainer container) {
@@ -7574,6 +7692,11 @@ public class Grid<T> extends ResizeComposite implements
@Override
public void execute() {
recalculateColumnWidths();
+ // Vertical resizing could make editor positioning invalid so it
+ // needs to be recalculated on resize
+ if (isEditorActive()) {
+ editor.updateVerticalScrollPosition();
+ }
}
});
}
@@ -7866,6 +7989,54 @@ public class Grid<T> extends ResizeComposite implements
}
}
+ @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);
+ }
+
+ /**
+ * Sets the buffered editor mode.
+ *
+ * @since
+ * @param editorUnbuffered
+ * <code>true</code> to enable buffered editor,
+ * <code>false</code> to disable it
+ */
+ public void setEditorBuffered(boolean editorBuffered) {
+ editor.setBuffered(editorBuffered);
+ }
+
+ /**
+ * Gets the buffered editor mode.
+ *
+ * @since
+ * @return <code>true</code> if buffered editor is enabled,
+ * <code>false</code> otherwise
+ */
+ public boolean isEditorBuffered() {
+ return editor.isBuffered();
+ }
+
/**
* Returns the {@link EventCellReference} for the latest event fired from
* this Grid.
diff --git a/server/src/com/vaadin/ui/AbstractFocusable.java b/server/src/com/vaadin/ui/AbstractFocusable.java
new file mode 100644
index 0000000000..b9705cef6a
--- /dev/null
+++ b/server/src/com/vaadin/ui/AbstractFocusable.java
@@ -0,0 +1,134 @@
+/*
+ * 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.ui;
+
+import com.vaadin.event.FieldEvents.BlurEvent;
+import com.vaadin.event.FieldEvents.BlurListener;
+import com.vaadin.event.FieldEvents.BlurNotifier;
+import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcImpl;
+import com.vaadin.event.FieldEvents.FocusEvent;
+import com.vaadin.event.FieldEvents.FocusListener;
+import com.vaadin.event.FieldEvents.FocusNotifier;
+import com.vaadin.shared.ui.TabIndexState;
+import com.vaadin.ui.Component.Focusable;
+
+/**
+ * An abstract base class for focusable components. Includes API for setting the
+ * tab index, programmatic focusing, and adding focus and blur listeners.
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+public abstract class AbstractFocusable extends AbstractComponent implements
+ Focusable, FocusNotifier, BlurNotifier {
+
+ protected AbstractFocusable() {
+ registerRpc(new FocusAndBlurServerRpcImpl(this) {
+ @Override
+ protected void fireEvent(Event event) {
+ AbstractFocusable.this.fireEvent(event);
+ }
+ });
+ }
+
+ @Override
+ public void addBlurListener(BlurListener listener) {
+ addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener,
+ BlurListener.blurMethod);
+ }
+
+ /**
+ * @deprecated As of 7.0, replaced by {@link #addBlurListener(BlurListener)}
+ */
+ @Override
+ @Deprecated
+ public void addListener(BlurListener listener) {
+ addBlurListener(listener);
+ }
+
+ @Override
+ public void removeBlurListener(BlurListener listener) {
+ removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener);
+ }
+
+ /**
+ * @deprecated As of 7.0, replaced by
+ * {@link #removeBlurListener(BlurListener)}
+ */
+ @Override
+ @Deprecated
+ public void removeListener(BlurListener listener) {
+ removeBlurListener(listener);
+
+ }
+
+ @Override
+ public void addFocusListener(FocusListener listener) {
+ addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener,
+ FocusListener.focusMethod);
+
+ }
+
+ /**
+ * @deprecated As of 7.0, replaced by
+ * {@link #addFocusListener(FocusListener)}
+ */
+ @Override
+ @Deprecated
+ public void addListener(FocusListener listener) {
+ addFocusListener(listener);
+ }
+
+ @Override
+ public void removeFocusListener(FocusListener listener) {
+ removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener);
+ }
+
+ /**
+ * @deprecated As of 7.0, replaced by
+ * {@link #removeFocusListener(FocusListener)}
+ */
+ @Override
+ @Deprecated
+ public void removeListener(FocusListener listener) {
+ removeFocusListener(listener);
+ }
+
+ @Override
+ public void focus() {
+ super.focus();
+ }
+
+ @Override
+ public int getTabIndex() {
+ return getState(false).tabIndex;
+ }
+
+ @Override
+ public void setTabIndex(int tabIndex) {
+ getState().tabIndex = tabIndex;
+ }
+
+ @Override
+ protected TabIndexState getState() {
+ return (TabIndexState) super.getState();
+ }
+
+ @Override
+ protected TabIndexState getState(boolean markAsDirty) {
+ return (TabIndexState) super.getState(markAsDirty);
+ }
+}
diff --git a/server/src/com/vaadin/ui/Button.java b/server/src/com/vaadin/ui/Button.java
index 6beb6ed686..a918780a60 100644
--- a/server/src/com/vaadin/ui/Button.java
+++ b/server/src/com/vaadin/ui/Button.java
@@ -24,12 +24,7 @@ import org.jsoup.nodes.Attributes;
import org.jsoup.nodes.Element;
import com.vaadin.event.Action;
-import com.vaadin.event.FieldEvents;
-import com.vaadin.event.FieldEvents.BlurEvent;
-import com.vaadin.event.FieldEvents.BlurListener;
import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcImpl;
-import com.vaadin.event.FieldEvents.FocusEvent;
-import com.vaadin.event.FieldEvents.FocusListener;
import com.vaadin.event.ShortcutAction;
import com.vaadin.event.ShortcutAction.KeyCode;
import com.vaadin.event.ShortcutAction.ModifierKey;
@@ -38,7 +33,6 @@ import com.vaadin.server.Resource;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.ui.button.ButtonServerRpc;
import com.vaadin.shared.ui.button.ButtonState;
-import com.vaadin.ui.Component.Focusable;
import com.vaadin.ui.declarative.DesignAttributeHandler;
import com.vaadin.ui.declarative.DesignContext;
import com.vaadin.util.ReflectTools;
@@ -50,8 +44,7 @@ import com.vaadin.util.ReflectTools;
* @since 3.0
*/
@SuppressWarnings("serial")
-public class Button extends AbstractComponent implements
- FieldEvents.BlurNotifier, FieldEvents.FocusNotifier, Focusable,
+public class Button extends AbstractFocusable implements
Action.ShortcutNotifier {
private ButtonServerRpc rpc = new ButtonServerRpc() {
@@ -72,20 +65,11 @@ public class Button extends AbstractComponent implements
}
};
- FocusAndBlurServerRpcImpl focusBlurRpc = new FocusAndBlurServerRpcImpl(this) {
-
- @Override
- protected void fireEvent(Event event) {
- Button.this.fireEvent(event);
- }
- };
-
/**
* Creates a new push button.
*/
public Button() {
registerRpc(rpc);
- registerRpc(focusBlurRpc);
}
/**
@@ -393,67 +377,6 @@ public class Button extends AbstractComponent implements
fireEvent(new Button.ClickEvent(this, details));
}
- @Override
- public void addBlurListener(BlurListener listener) {
- addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener,
- BlurListener.blurMethod);
- }
-
- /**
- * @deprecated As of 7.0, replaced by {@link #addBlurListener(BlurListener)}
- **/
- @Override
- @Deprecated
- public void addListener(BlurListener listener) {
- addBlurListener(listener);
- }
-
- @Override
- public void removeBlurListener(BlurListener listener) {
- removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener);
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #removeBlurListener(BlurListener)}
- **/
- @Override
- @Deprecated
- public void removeListener(BlurListener listener) {
- removeBlurListener(listener);
- }
-
- @Override
- public void addFocusListener(FocusListener listener) {
- addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener,
- FocusListener.focusMethod);
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #addFocusListener(FocusListener)}
- **/
- @Override
- @Deprecated
- public void addListener(FocusListener listener) {
- addFocusListener(listener);
- }
-
- @Override
- public void removeFocusListener(FocusListener listener) {
- removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener);
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #removeFocusListener(FocusListener)}
- **/
- @Override
- @Deprecated
- public void removeListener(FocusListener listener) {
- removeFocusListener(listener);
- }
-
/*
* Actions
*/
@@ -575,32 +498,6 @@ public class Button extends AbstractComponent implements
getState().disableOnClick = disableOnClick;
}
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.ui.Component.Focusable#getTabIndex()
- */
- @Override
- public int getTabIndex() {
- return getState(false).tabIndex;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.ui.Component.Focusable#setTabIndex(int)
- */
- @Override
- public void setTabIndex(int tabIndex) {
- getState().tabIndex = tabIndex;
- }
-
- @Override
- public void focus() {
- // Overridden only to make public
- super.focus();
- }
-
@Override
protected ButtonState getState() {
return (ButtonState) super.getState();
diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java
index c061a81b73..74f58ecf74 100644
--- a/server/src/com/vaadin/ui/Grid.java
+++ b/server/src/com/vaadin/ui/Grid.java
@@ -57,6 +57,7 @@ import com.vaadin.data.RpcDataProviderExtension.DetailComponentManager;
import com.vaadin.data.Validator.InvalidValueException;
import com.vaadin.data.fieldgroup.DefaultFieldGroupFieldFactory;
import com.vaadin.data.fieldgroup.FieldGroup;
+import com.vaadin.data.fieldgroup.FieldGroup.BindException;
import com.vaadin.data.fieldgroup.FieldGroup.CommitException;
import com.vaadin.data.fieldgroup.FieldGroupFieldFactory;
import com.vaadin.data.sort.Sort;
@@ -172,7 +173,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 {
/**
@@ -511,6 +512,100 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
}
/**
+ * Interface for an editor event listener
+ */
+ public interface EditorListener extends Serializable {
+
+ public static final Method EDITOR_OPEN_METHOD = ReflectTools
+ .findMethod(EditorListener.class, "editorOpened",
+ EditorOpenEvent.class);
+ public static final Method EDITOR_MOVE_METHOD = ReflectTools
+ .findMethod(EditorListener.class, "editorMoved",
+ EditorMoveEvent.class);
+ public static final Method EDITOR_CLOSE_METHOD = ReflectTools
+ .findMethod(EditorListener.class, "editorClosed",
+ EditorCloseEvent.class);
+
+ /**
+ * Called when an editor is opened
+ *
+ * @param e
+ * an editor open event object
+ */
+ public void editorOpened(EditorOpenEvent e);
+
+ /**
+ * Called when an editor is reopened without closing it first
+ *
+ * @param e
+ * an editor move event object
+ */
+ public void editorMoved(EditorMoveEvent e);
+
+ /**
+ * Called when an editor is closed
+ *
+ * @param e
+ * an editor close event object
+ */
+ public void editorClosed(EditorCloseEvent e);
+
+ }
+
+ /**
+ * Base class for editor related events
+ */
+ public static abstract class EditorEvent extends Component.Event {
+
+ private Object itemID;
+
+ protected EditorEvent(Grid source, Object itemID) {
+ super(source);
+ this.itemID = itemID;
+ }
+
+ /**
+ * Get the item (row) for which this editor was opened
+ */
+ public Object getItem() {
+ return itemID;
+ }
+
+ }
+
+ /**
+ * This event gets fired when an editor is opened
+ */
+ public static class EditorOpenEvent extends EditorEvent {
+
+ public EditorOpenEvent(Grid source, Object itemID) {
+ super(source, itemID);
+ }
+ }
+
+ /**
+ * This event gets fired when an editor is opened while another row is being
+ * edited (i.e. editor focus moves elsewhere)
+ */
+ public static class EditorMoveEvent extends EditorEvent {
+
+ public EditorMoveEvent(Grid source, Object itemID) {
+ super(source, itemID);
+ }
+ }
+
+ /**
+ * This event gets fired when an editor is dismissed or closed by other
+ * means.
+ */
+ public static class EditorCloseEvent extends EditorEvent {
+
+ public EditorCloseEvent(Grid source, Object itemID) {
+ super(source, itemID);
+ }
+ }
+
+ /**
* Default error handler for the editor
*
*/
@@ -3856,6 +3951,24 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
detailComponentManager.getAndResetConnectorChanges(),
fetchId);
}
+
+ @Override
+ public void editorOpen(String rowKey) {
+ fireEvent(new EditorOpenEvent(Grid.this, getKeyMapper()
+ .getItemId(rowKey)));
+ }
+
+ @Override
+ public void editorMove(String rowKey) {
+ fireEvent(new EditorMoveEvent(Grid.this, getKeyMapper()
+ .getItemId(rowKey)));
+ }
+
+ @Override
+ public void editorClose(String rowKey) {
+ fireEvent(new EditorCloseEvent(Grid.this, getKeyMapper()
+ .getItemId(rowKey)));
+ }
});
registerRpc(new EditorServerRpc() {
@@ -3865,13 +3978,13 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
boolean success = false;
try {
Object id = getContainerDataSource().getIdByIndex(rowIndex);
- if (editedItemId == null) {
+ if (!isEditorBuffered() || editedItemId == null) {
editedItemId = id;
}
if (editedItemId.equals(id)) {
- success = true;
doEditItem();
+ success = true;
}
} catch (Exception e) {
handleError(e);
@@ -5934,6 +6047,70 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
return getState(false).editorCancelCaption;
}
+ /**
+ * Add an editor event listener
+ *
+ * @param listener
+ * the event listener object to add
+ */
+ public void addEditorListener(EditorListener listener) {
+ addListener(GridConstants.EDITOR_OPEN_EVENT_ID, EditorOpenEvent.class,
+ listener, EditorListener.EDITOR_OPEN_METHOD);
+ addListener(GridConstants.EDITOR_MOVE_EVENT_ID, EditorMoveEvent.class,
+ listener, EditorListener.EDITOR_MOVE_METHOD);
+ addListener(GridConstants.EDITOR_CLOSE_EVENT_ID,
+ EditorCloseEvent.class, listener,
+ EditorListener.EDITOR_CLOSE_METHOD);
+ }
+
+ /**
+ * Remove an editor event listener
+ *
+ * @param listener
+ * the event listener object to remove
+ */
+ public void removeEditorListener(EditorListener listener) {
+ removeListener(GridConstants.EDITOR_OPEN_EVENT_ID,
+ EditorOpenEvent.class, listener);
+ removeListener(GridConstants.EDITOR_MOVE_EVENT_ID,
+ EditorMoveEvent.class, listener);
+ removeListener(GridConstants.EDITOR_CLOSE_EVENT_ID,
+ EditorCloseEvent.class, listener);
+ }
+
+ /**
+ * Sets the buffered editor mode. The default mode is buffered (
+ * <code>true</code>).
+ *
+ * @since
+ * @param editorBuffered
+ * <code>true</code> to enable buffered editor,
+ * <code>false</code> to disable it
+ * @throws IllegalStateException
+ * If editor is active while attempting to change the buffered
+ * mode.
+ */
+ public void setEditorBuffered(boolean editorBuffered)
+ throws IllegalStateException {
+ if (isEditorActive()) {
+ throw new IllegalStateException(
+ "Can't change editor unbuffered mode while editor is active.");
+ }
+ getState().editorBuffered = editorBuffered;
+ editorFieldGroup.setBuffered(editorBuffered);
+ }
+
+ /**
+ * Gets the buffered editor mode.
+ *
+ * @since
+ * @return <code>true</code> if buffered editor is enabled,
+ * <code>false</code> otherwise
+ */
+ public boolean isEditorBuffered() {
+ return getState().editorBuffered;
+ }
+
@Override
public void addItemClickListener(ItemClickListener listener) {
addListener(GridConstants.ITEM_CLICK_EVENT_ID, ItemClickEvent.class,
@@ -6228,6 +6405,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
result.add("footer-visible");
result.add("editor-error-handler");
result.add("height-mode");
+
return result;
}
}
diff --git a/shared/src/com/vaadin/shared/ui/grid/GridConstants.java b/shared/src/com/vaadin/shared/ui/grid/GridConstants.java
index 0606e4b1cc..5b2ac96975 100644
--- a/shared/src/com/vaadin/shared/ui/grid/GridConstants.java
+++ b/shared/src/com/vaadin/shared/ui/grid/GridConstants.java
@@ -74,4 +74,19 @@ public final class GridConstants implements Serializable {
/** The default cancel button caption in the editor */
public static final String DEFAULT_CANCEL_CAPTION = "Cancel";
+
+ /**
+ * Event ID constant for editor open event
+ */
+ public static final String EDITOR_OPEN_EVENT_ID = "editorOpen";
+
+ /**
+ * Event ID constant for editor move event
+ */
+ public static final String EDITOR_MOVE_EVENT_ID = "editorMove";
+
+ /**
+ * Event ID constant for editor close event
+ */
+ public static final String EDITOR_CLOSE_EVENT_ID = "editorClose";
}
diff --git a/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java b/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java
index dca55c11c4..99b339765a 100644
--- a/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java
+++ b/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java
@@ -37,6 +37,31 @@ public interface GridServerRpc extends ServerRpc {
boolean userOriginated);
/**
+ * Informs the server that the editor was opened (fresh) on a certain row
+ *
+ * @param rowKey
+ * a key identifying item the editor was opened on
+ */
+ void editorOpen(String rowKey);
+
+ /**
+ * Informs the server that the editor was reopened (without closing it in
+ * between) on another row
+ *
+ * @param rowKey
+ * a key identifying item the editor was opened on
+ */
+ void editorMove(String rowKey);
+
+ /**
+ * Informs the server that the editor was closed
+ *
+ * @param rowKey
+ * a key identifying item the editor was opened on
+ */
+ void editorClose(String rowKey);
+
+ /**
* Informs the server that an item has been clicked in Grid.
*
* @param rowKey
diff --git a/shared/src/com/vaadin/shared/ui/grid/GridState.java b/shared/src/com/vaadin/shared/ui/grid/GridState.java
index c23c931683..c4121cbf45 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
@@ -156,6 +156,10 @@ public class GridState extends AbstractComponentState {
/** The enabled state of the editor interface */
public boolean editorEnabled = false;
+ /** Buffered editor mode */
+ @DelegateToWidget
+ public boolean editorBuffered = true;
+
/** Whether row data might contain generated row styles */
public boolean hasRowStyleGenerator;
/** Whether row data might contain generated cell styles */
diff --git a/uitest/src/com/vaadin/tests/components/AbstractComponentTest.java b/uitest/src/com/vaadin/tests/components/AbstractComponentTest.java
index b289279b86..aca617aa5a 100644
--- a/uitest/src/com/vaadin/tests/components/AbstractComponentTest.java
+++ b/uitest/src/com/vaadin/tests/components/AbstractComponentTest.java
@@ -20,6 +20,7 @@ import com.vaadin.server.ThemeResource;
import com.vaadin.tests.util.Log;
import com.vaadin.tests.util.LoremIpsum;
import com.vaadin.ui.AbstractComponent;
+import com.vaadin.ui.Component.Focusable;
import com.vaadin.ui.MenuBar;
import com.vaadin.ui.MenuBar.MenuItem;
import com.vaadin.ui.themes.BaseTheme;
@@ -242,16 +243,18 @@ public abstract class AbstractComponentTest<T extends AbstractComponent>
createStyleNameSelect(CATEGORY_DECORATIONS);
+ createFocusActions();
}
protected Command<T, Boolean> focusListenerCommand = new Command<T, Boolean>() {
@Override
public void execute(T c, Boolean value, Object data) {
+ FocusNotifier fn = (FocusNotifier) c;
if (value) {
- ((FocusNotifier) c).addListener(AbstractComponentTest.this);
+ fn.addFocusListener(AbstractComponentTest.this);
} else {
- ((FocusNotifier) c).removeListener(AbstractComponentTest.this);
+ fn.removeFocusListener(AbstractComponentTest.this);
}
}
};
@@ -259,10 +262,11 @@ public abstract class AbstractComponentTest<T extends AbstractComponent>
@Override
public void execute(T c, Boolean value, Object data) {
+ BlurNotifier bn = (BlurNotifier) c;
if (value) {
- ((BlurNotifier) c).addListener(AbstractComponentTest.this);
+ bn.addBlurListener(AbstractComponentTest.this);
} else {
- ((BlurNotifier) c).removeListener(AbstractComponentTest.this);
+ bn.removeBlurListener(AbstractComponentTest.this);
}
}
};
@@ -279,6 +283,35 @@ public abstract class AbstractComponentTest<T extends AbstractComponent>
}
+ private void createFocusActions() {
+ if (FocusNotifier.class.isAssignableFrom(getTestClass())) {
+ createFocusListener(CATEGORY_LISTENERS);
+ }
+ if (BlurNotifier.class.isAssignableFrom(getTestClass())) {
+ createBlurListener(CATEGORY_LISTENERS);
+ }
+ if (Focusable.class.isAssignableFrom(getTestClass())) {
+ LinkedHashMap<String, Integer> tabIndexes = new LinkedHashMap<String, Integer>();
+ tabIndexes.put("0", 0);
+ tabIndexes.put("-1", -1);
+ tabIndexes.put("10", 10);
+ createSelectAction("Tab index", "State", tabIndexes, "0",
+ new Command<T, Integer>() {
+ @Override
+ public void execute(T c, Integer tabIndex, Object data) {
+ ((Focusable) c).setTabIndex(tabIndex);
+ }
+ });
+
+ createClickAction("Set focus", "State", new Command<T, Void>() {
+ @Override
+ public void execute(T c, Void value, Object data) {
+ ((Focusable) c).focus();
+ }
+ }, null);
+ }
+ }
+
private void createStyleNameSelect(String category) {
LinkedHashMap<String, String> options = new LinkedHashMap<String, String>();
options.put("-", null);
diff --git a/uitest/src/com/vaadin/tests/components/abstractfield/AbstractFieldTest.java b/uitest/src/com/vaadin/tests/components/abstractfield/AbstractFieldTest.java
index 692ca25b07..496a44a6c1 100644
--- a/uitest/src/com/vaadin/tests/components/abstractfield/AbstractFieldTest.java
+++ b/uitest/src/com/vaadin/tests/components/abstractfield/AbstractFieldTest.java
@@ -13,8 +13,6 @@ import com.vaadin.data.Property;
import com.vaadin.data.Property.ReadOnlyStatusChangeEvent;
import com.vaadin.data.Property.ReadOnlyStatusChangeListener;
import com.vaadin.data.Property.ValueChangeListener;
-import com.vaadin.event.FieldEvents.BlurNotifier;
-import com.vaadin.event.FieldEvents.FocusNotifier;
import com.vaadin.tests.components.AbstractComponentTest;
import com.vaadin.ui.AbstractField;
import com.vaadin.ui.MenuBar;
@@ -29,15 +27,9 @@ public abstract class AbstractFieldTest<T extends AbstractField> extends
@Override
protected void createActions() {
super.createActions();
+
createBooleanAction("Required", CATEGORY_STATE, false, requiredCommand);
createRequiredErrorSelect(CATEGORY_DECORATIONS);
- if (FocusNotifier.class.isAssignableFrom(getTestClass())) {
- createFocusListener(CATEGORY_LISTENERS);
- }
-
- if (BlurNotifier.class.isAssignableFrom(getTestClass())) {
- createBlurListener(CATEGORY_LISTENERS);
- }
createValueChangeListener(CATEGORY_LISTENERS);
createReadOnlyStatusChangeListener(CATEGORY_LISTENERS);
@@ -52,7 +44,6 @@ public abstract class AbstractFieldTest<T extends AbstractField> extends
// * invalidallowed
// * error indicator
//
- // * tabindex
// * validation visible
// * ShortcutListener
diff --git a/uitest/src/com/vaadin/tests/components/button/Buttons2.java b/uitest/src/com/vaadin/tests/components/button/Buttons2.java
index 7526e7dbc3..4f75dfbfef 100644
--- a/uitest/src/com/vaadin/tests/components/button/Buttons2.java
+++ b/uitest/src/com/vaadin/tests/components/button/Buttons2.java
@@ -42,9 +42,6 @@ public class Buttons2<T extends Button> extends AbstractComponentTest<T>
protected void createActions() {
super.createActions();
- createFocusListener(CATEGORY_LISTENERS);
- createBlurListener(CATEGORY_LISTENERS);
-
createBooleanAction("Disable on click", CATEGORY_FEATURES, false,
disableOnClickCommand);
addClickListener(CATEGORY_LISTENERS);
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 ecf3d53385..c98ee5c53b 100644
--- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java
@@ -57,6 +57,10 @@ import com.vaadin.ui.Grid.ColumnReorderListener;
import com.vaadin.ui.Grid.ColumnVisibilityChangeEvent;
import com.vaadin.ui.Grid.ColumnVisibilityChangeListener;
import com.vaadin.ui.Grid.DetailsGenerator;
+import com.vaadin.ui.Grid.EditorCloseEvent;
+import com.vaadin.ui.Grid.EditorListener;
+import com.vaadin.ui.Grid.EditorMoveEvent;
+import com.vaadin.ui.Grid.EditorOpenEvent;
import com.vaadin.ui.Grid.FooterCell;
import com.vaadin.ui.Grid.HeaderCell;
import com.vaadin.ui.Grid.HeaderRow;
@@ -405,6 +409,7 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
}
protected void createGridActions() {
+
LinkedHashMap<String, String> primaryStyleNames = new LinkedHashMap<String, String>();
primaryStyleNames.put("v-grid", "v-grid");
primaryStyleNames.put("v-escalator", "v-escalator");
@@ -661,7 +666,6 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
}
}
});
-
createBooleanAction("Single select allow deselect", "State",
singleSelectAllowDeselect, new Command<Grid, Boolean>() {
@Override
@@ -1206,6 +1210,14 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
}
});
+ createBooleanAction("Buffered mode", "Editor", true,
+ new Command<Grid, Boolean>() {
+ @Override
+ public void execute(Grid c, Boolean value, Object data) {
+ c.setEditorBuffered(value);
+ }
+ });
+
createClickAction("Edit item 5", "Editor", new Command<Grid, String>() {
@Override
public void execute(Grid c, String value, Object data) {
@@ -1253,6 +1265,30 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
c.setEditorCancelCaption("ʃǝɔuɐↃ");
}
}, null);
+
+ createClickAction("Add editor state listener", "Editor",
+ new Command<Grid, String>() {
+ @Override
+ public void execute(Grid grid, String value, Object data) {
+ grid.addEditorListener(new EditorListener() {
+ @Override
+ public void editorOpened(EditorOpenEvent e) {
+ log("Editor opened");
+ }
+
+ @Override
+ public void editorMoved(EditorMoveEvent e) {
+ log("Editor moved");
+ }
+
+ @Override
+ public void editorClosed(EditorCloseEvent e) {
+ log("Editor closed");
+ }
+ });
+ }
+ }, null);
+
}
@SuppressWarnings("boxing")
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java
new file mode 100644
index 0000000000..9f55d2adcb
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java
@@ -0,0 +1,217 @@
+/*
+ * 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.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.Keys;
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.interactions.Actions;
+
+import com.vaadin.shared.ui.grid.GridConstants;
+import com.vaadin.testbench.elements.GridElement.GridCellElement;
+import com.vaadin.testbench.elements.GridElement.GridEditorElement;
+import com.vaadin.testbench.elements.NotificationElement;
+
+public class GridEditorBufferedTest extends GridEditorTest {
+
+ @Override
+ @Before
+ public void setUp() {
+ super.setUp();
+ }
+
+ @Test
+ public void testSave() {
+ selectMenuPath(EDIT_ITEM_100);
+
+ WebElement textField = getEditorWidgets().get(0);
+
+ textField.click();
+
+ textField.sendKeys(" changed");
+
+ WebElement saveButton = getEditor().findElement(
+ By.className("v-grid-editor-save"));
+
+ saveButton.click();
+
+ assertEquals("(100, 0) changed", getGridElement().getCell(100, 0)
+ .getText());
+ }
+
+ @Test
+ public void testProgrammaticSave() {
+ selectMenuPath(EDIT_ITEM_100);
+
+ WebElement textField = getEditorWidgets().get(0);
+
+ textField.click();
+
+ textField.sendKeys(" changed");
+
+ selectMenuPath("Component", "Editor", "Save");
+
+ assertEquals("(100, 0) changed", getGridElement().getCell(100, 0)
+ .getText());
+ }
+
+ @Test
+ public void testInvalidEdition() {
+ selectMenuPath(EDIT_ITEM_5);
+ assertFalse(logContainsText("Exception occured, java.lang.IllegalStateException"));
+
+ GridEditorElement editor = getGridElement().getEditor();
+
+ assertFalse(
+ "Field 7 should not have been marked with an error before error",
+ editor.isFieldErrorMarked(7));
+
+ WebElement intField = editor.getField(7);
+ intField.clear();
+ intField.sendKeys("banana phone");
+ editor.save();
+
+ assertEquals("Column 7: Could not convert value to Integer",
+ editor.getErrorMessage());
+ assertTrue("Field 7 should have been marked with an error after error",
+ editor.isFieldErrorMarked(7));
+ editor.cancel();
+
+ selectMenuPath(EDIT_ITEM_100);
+ assertFalse("Exception should not exist",
+ isElementPresent(NotificationElement.class));
+ assertEquals("There should be no editor error message", null,
+ editor.getErrorMessage());
+ }
+
+ @Test
+ public void testEditorInDisabledGrid() {
+ int originalScrollPos = getGridVerticalScrollPos();
+
+ selectMenuPath(EDIT_ITEM_5);
+ assertEditorOpen();
+
+ selectMenuPath("Component", "State", "Enabled");
+ assertEditorOpen();
+
+ GridEditorElement editor = getGridElement().getEditor();
+ editor.save();
+ assertEditorOpen();
+
+ editor.cancel();
+ assertEditorOpen();
+
+ selectMenuPath("Component", "State", "Enabled");
+
+ scrollGridVerticallyTo(100);
+ assertEquals(
+ "Grid shouldn't scroll vertically while editing in buffered mode",
+ originalScrollPos, getGridVerticalScrollPos());
+ }
+
+ @Test
+ public void testCaptionChange() {
+ selectMenuPath(EDIT_ITEM_5);
+ assertEquals("Save button caption should've been \""
+ + GridConstants.DEFAULT_SAVE_CAPTION + "\" to begin with",
+ GridConstants.DEFAULT_SAVE_CAPTION, getSaveButton().getText());
+ assertEquals("Cancel button caption should've been \""
+ + GridConstants.DEFAULT_CANCEL_CAPTION + "\" to begin with",
+ GridConstants.DEFAULT_CANCEL_CAPTION, getCancelButton()
+ .getText());
+
+ selectMenuPath("Component", "Editor", "Change save caption");
+ assertNotEquals(
+ "Save button caption should've changed while editor is open",
+ GridConstants.DEFAULT_SAVE_CAPTION, getSaveButton().getText());
+
+ getCancelButton().click();
+
+ selectMenuPath("Component", "Editor", "Change cancel caption");
+ selectMenuPath(EDIT_ITEM_5);
+ assertNotEquals(
+ "Cancel button caption should've changed while editor is closed",
+ GridConstants.DEFAULT_CANCEL_CAPTION, getCancelButton()
+ .getText());
+ }
+
+ @Test(expected = NoSuchElementException.class)
+ public void testVerticalScrollLocking() {
+ selectMenuPath(EDIT_ITEM_5);
+ getGridElement().getCell(200, 0);
+ }
+
+ @Test
+ public void testNoScrollAfterEditByAPI() {
+ int originalScrollPos = getGridVerticalScrollPos();
+
+ selectMenuPath(EDIT_ITEM_5);
+
+ scrollGridVerticallyTo(100);
+ assertEquals(
+ "Grid shouldn't scroll vertically while editing in buffered mode",
+ originalScrollPos, getGridVerticalScrollPos());
+ }
+
+ @Test
+ public void testNoScrollAfterEditByMouse() {
+ int originalScrollPos = getGridVerticalScrollPos();
+
+ GridCellElement cell_5_0 = getGridElement().getCell(5, 0);
+ new Actions(getDriver()).doubleClick(cell_5_0).perform();
+
+ scrollGridVerticallyTo(100);
+ assertEquals(
+ "Grid shouldn't scroll vertically while editing in buffered mode",
+ originalScrollPos, getGridVerticalScrollPos());
+ }
+
+ @Test
+ public void testNoScrollAfterEditByKeyboard() {
+ int originalScrollPos = getGridVerticalScrollPos();
+
+ GridCellElement cell_5_0 = getGridElement().getCell(5, 0);
+ cell_5_0.click();
+ new Actions(getDriver()).sendKeys(Keys.ENTER).perform();
+
+ scrollGridVerticallyTo(100);
+ assertEquals(
+ "Grid shouldn't scroll vertically while editing in buffered mode",
+ originalScrollPos, getGridVerticalScrollPos());
+ }
+
+ @Test
+ public void testMouseOpeningClosing() {
+
+ getGridElement().getCell(4, 0).doubleClick();
+ assertEditorOpen();
+
+ getCancelButton().click();
+ assertEditorClosed();
+
+ selectMenuPath(TOGGLE_EDIT_ENABLED);
+ getGridElement().getCell(4, 0).doubleClick();
+ assertEditorClosed();
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java
index 0c39b3e509..0a6d884251 100644
--- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java
@@ -17,7 +17,6 @@ package com.vaadin.tests.components.grid.basicfeatures.server;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -28,24 +27,22 @@ import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
-import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
-import com.vaadin.shared.ui.grid.GridConstants;
+import com.vaadin.testbench.TestBenchElement;
import com.vaadin.testbench.elements.GridElement.GridCellElement;
import com.vaadin.testbench.elements.GridElement.GridEditorElement;
-import com.vaadin.testbench.elements.NotificationElement;
import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeatures;
import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest;
-public class GridEditorTest extends GridBasicFeaturesTest {
+public abstract class GridEditorTest extends GridBasicFeaturesTest {
- private static final String[] EDIT_ITEM_5 = new String[] { "Component",
+ protected static final String[] EDIT_ITEM_5 = new String[] { "Component",
"Editor", "Edit item 5" };
- private static final String[] EDIT_ITEM_100 = new String[] { "Component",
+ protected static final String[] EDIT_ITEM_100 = new String[] { "Component",
"Editor", "Edit item 100" };
- private static final String[] TOGGLE_EDIT_ENABLED = new String[] {
+ protected static final String[] TOGGLE_EDIT_ENABLED = new String[] {
"Component", "Editor", "Enabled" };
@Before
@@ -88,26 +85,6 @@ public class GridEditorTest extends GridBasicFeaturesTest {
assertEditorOpen();
}
- @Test(expected = NoSuchElementException.class)
- public void testVerticalScrollLocking() {
- selectMenuPath(EDIT_ITEM_5);
- getGridElement().getCell(200, 0);
- }
-
- @Test
- public void testMouseOpeningClosing() {
-
- getGridElement().getCell(4, 0).doubleClick();
- assertEditorOpen();
-
- getCancelButton().click();
- assertEditorClosed();
-
- selectMenuPath(TOGGLE_EDIT_ENABLED);
- getGridElement().getCell(4, 0).doubleClick();
- assertEditorClosed();
- }
-
@Test
public void testKeyboardOpeningClosing() {
@@ -141,173 +118,23 @@ public class GridEditorTest extends GridBasicFeaturesTest {
assertEquals("<b>100</b>", widgets.get(8).getAttribute("value"));
}
- @Test
- public void testSave() {
- selectMenuPath(EDIT_ITEM_100);
-
- WebElement textField = getEditorWidgets().get(0);
-
- textField.click();
-
- textField.sendKeys(" changed");
-
- WebElement saveButton = getEditor().findElement(
- By.className("v-grid-editor-save"));
-
- saveButton.click();
-
- assertEquals("(100, 0) changed", getGridElement().getCell(100, 0)
- .getText());
- }
-
- @Test
- public void testProgrammaticSave() {
- selectMenuPath(EDIT_ITEM_100);
-
- WebElement textField = getEditorWidgets().get(0);
-
- textField.click();
-
- textField.sendKeys(" changed");
-
- selectMenuPath("Component", "Editor", "Save");
-
- assertEquals("(100, 0) changed", getGridElement().getCell(100, 0)
- .getText());
- }
-
- @Test
- public void testCaptionChange() {
- selectMenuPath(EDIT_ITEM_5);
- assertEquals("Save button caption should've been \""
- + GridConstants.DEFAULT_SAVE_CAPTION + "\" to begin with",
- GridConstants.DEFAULT_SAVE_CAPTION, getSaveButton().getText());
- assertEquals("Cancel button caption should've been \""
- + GridConstants.DEFAULT_CANCEL_CAPTION + "\" to begin with",
- GridConstants.DEFAULT_CANCEL_CAPTION, getCancelButton()
- .getText());
-
- selectMenuPath("Component", "Editor", "Change save caption");
- assertNotEquals(
- "Save button caption should've changed while editor is open",
- GridConstants.DEFAULT_SAVE_CAPTION, getSaveButton().getText());
-
- getCancelButton().click();
-
- selectMenuPath("Component", "Editor", "Change cancel caption");
- selectMenuPath(EDIT_ITEM_5);
- assertNotEquals(
- "Cancel button caption should've changed while editor is closed",
- GridConstants.DEFAULT_CANCEL_CAPTION, getCancelButton()
- .getText());
- }
-
- private void assertEditorOpen() {
+ protected void assertEditorOpen() {
assertNotNull("Editor is supposed to be open", getEditor());
assertEquals("Unexpected number of widgets",
GridBasicFeatures.EDITABLE_COLUMNS, getEditorWidgets().size());
}
- private void assertEditorClosed() {
+ protected void assertEditorClosed() {
assertNull("Editor is supposed to be closed", getEditor());
}
- private List<WebElement> getEditorWidgets() {
+ protected List<WebElement> getEditorWidgets() {
assertNotNull(getEditor());
return getEditor().findElements(By.className("v-textfield"));
}
@Test
- public void testInvalidEdition() {
- selectMenuPath(EDIT_ITEM_5);
- assertFalse(logContainsText("Exception occured, java.lang.IllegalStateException"));
-
- GridEditorElement editor = getGridElement().getEditor();
-
- assertFalse(
- "Field 7 should not have been marked with an error before error",
- editor.isFieldErrorMarked(7));
-
- WebElement intField = editor.getField(7);
- intField.clear();
- intField.sendKeys("banana phone");
- editor.save();
-
- assertEquals("Column 7: Could not convert value to Integer",
- editor.getErrorMessage());
- assertTrue("Field 7 should have been marked with an error after error",
- editor.isFieldErrorMarked(7));
- editor.cancel();
-
- selectMenuPath(EDIT_ITEM_100);
- assertFalse("Exception should not exist",
- isElementPresent(NotificationElement.class));
- assertEquals("There should be no editor error message", null,
- getGridElement().getEditor().getErrorMessage());
- }
-
- @Test
- public void testNoScrollAfterProgrammaticOpen() {
- int originalScrollPos = getGridVerticalScrollPos();
-
- selectMenuPath(EDIT_ITEM_5);
-
- scrollGridVerticallyTo(100);
- assertEquals("Grid shouldn't scroll vertically while editing",
- originalScrollPos, getGridVerticalScrollPos());
- }
-
- @Test
- public void testNoScrollAfterMouseOpen() {
- int originalScrollPos = getGridVerticalScrollPos();
-
- GridCellElement cell_5_0 = getGridElement().getCell(5, 0);
- new Actions(getDriver()).doubleClick(cell_5_0).perform();
-
- scrollGridVerticallyTo(100);
- assertEquals("Grid shouldn't scroll vertically while editing",
- originalScrollPos, getGridVerticalScrollPos());
- }
-
- @Test
- public void testNoScrollAfterKeyboardOpen() {
- int originalScrollPos = getGridVerticalScrollPos();
-
- GridCellElement cell_5_0 = getGridElement().getCell(5, 0);
- cell_5_0.click();
- new Actions(getDriver()).sendKeys(Keys.ENTER).perform();
-
- scrollGridVerticallyTo(100);
- assertEquals("Grid shouldn't scroll vertically while editing",
- originalScrollPos, getGridVerticalScrollPos());
- }
-
- @Test
- public void testEditorInDisabledGrid() {
- int originalScrollPos = getGridVerticalScrollPos();
-
- selectMenuPath(EDIT_ITEM_5);
- assertEditorOpen();
-
- selectMenuPath("Component", "State", "Enabled");
- assertEditorOpen();
-
- GridEditorElement editor = getGridElement().getEditor();
- editor.save();
- assertEditorOpen();
-
- editor.cancel();
- assertEditorOpen();
-
- selectMenuPath("Component", "State", "Enabled");
-
- scrollGridVerticallyTo(100);
- assertEquals("Grid shouldn't scroll vertically while editing",
- originalScrollPos, getGridVerticalScrollPos());
- }
-
- @Test
public void testFocusOnMouseOpen() {
GridCellElement cell = getGridElement().getCell(4, 2);
@@ -345,11 +172,6 @@ public class GridEditorTest extends GridBasicFeaturesTest {
focused.getAttribute("id"));
}
- @Override
- protected WebElement getFocusedElement() {
- return (WebElement) executeScript("return document.activeElement;");
- }
-
@Test
public void testUneditableColumn() {
selectMenuPath(EDIT_ITEM_5);
@@ -367,11 +189,73 @@ public class GridEditorTest extends GridBasicFeaturesTest {
}
- private WebElement getSaveButton() {
+ @Test
+ public void testNoOpenFromHeaderOrFooter() {
+ selectMenuPath("Component", "Footer", "Visible");
+
+ getGridElement().getHeaderCell(0, 0).doubleClick();
+ assertEditorClosed();
+
+ new Actions(getDriver()).sendKeys(Keys.ENTER).perform();
+ assertEditorClosed();
+
+ getGridElement().getFooterCell(0, 0).doubleClick();
+ assertEditorClosed();
+
+ new Actions(getDriver()).sendKeys(Keys.ENTER).perform();
+ assertEditorClosed();
+ }
+
+ public void testEditorMoveOnResize() {
+ selectMenuPath("Component", "Size", "Height", "500px");
+ getGridElement().getCell(22, 0).doubleClick();
+ assertEditorOpen();
+
+ GridEditorElement editor = getGridElement().getEditor();
+ TestBenchElement tableWrapper = getGridElement().getTableWrapper();
+
+ int tableWrapperBottom = tableWrapper.getLocation().getY()
+ + tableWrapper.getSize().getHeight();
+ int editorBottom = editor.getLocation().getY()
+ + editor.getSize().getHeight();
+
+ assertTrue("Editor should not be initially outside grid",
+ tableWrapperBottom - editorBottom <= 2);
+
+ selectMenuPath("Component", "Size", "Height", "300px");
+ assertEditorOpen();
+
+ tableWrapperBottom = tableWrapper.getLocation().getY()
+ + tableWrapper.getSize().getHeight();
+ editorBottom = editor.getLocation().getY()
+ + editor.getSize().getHeight();
+
+ assertTrue("Editor should not be outside grid after resize",
+ tableWrapperBottom - editorBottom <= 2);
+ }
+
+ public void testEditorDoesNotMoveOnResizeIfNotNeeded() {
+ selectMenuPath("Component", "Size", "Height", "500px");
+
+ selectMenuPath(EDIT_ITEM_5);
+ assertEditorOpen();
+
+ GridEditorElement editor = getGridElement().getEditor();
+
+ int editorPos = editor.getLocation().getY();
+
+ selectMenuPath("Component", "Size", "Height", "300px");
+ assertEditorOpen();
+
+ assertTrue("Editor should not have moved due to resize",
+ editorPos == editor.getLocation().getY());
+ }
+
+ protected WebElement getSaveButton() {
return getDriver().findElement(By.className("v-grid-editor-save"));
}
- private WebElement getCancelButton() {
+ protected WebElement getCancelButton() {
return getDriver().findElement(By.className("v-grid-editor-cancel"));
}
}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java
new file mode 100644
index 0000000000..80e273ff1d
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java
@@ -0,0 +1,178 @@
+/*
+ * 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.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.Keys;
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.interactions.Actions;
+
+import com.vaadin.testbench.elements.GridElement.GridCellElement;
+
+public class GridEditorUnbufferedTest extends GridEditorTest {
+
+ private static final String[] TOGGLE_EDITOR_BUFFERED = new String[] {
+ "Component", "Editor", "Buffered mode" };
+ private static final String[] CANCEL_EDIT = new String[] { "Component",
+ "Editor", "Cancel edit" };
+
+ @Override
+ @Before
+ public void setUp() {
+ super.setUp();
+ selectMenuPath(TOGGLE_EDITOR_BUFFERED);
+ }
+
+ @Test
+ public void testEditorShowsNoButtons() {
+ selectMenuPath(EDIT_ITEM_5);
+
+ assertEditorOpen();
+
+ boolean saveButtonFound = true;
+ try {
+ getSaveButton();
+ } catch (NoSuchElementException e) {
+ saveButtonFound = false;
+ }
+ assertFalse("Save button should not be visible in unbuffered mode.",
+ saveButtonFound);
+
+ boolean cancelButtonFound = true;
+ try {
+ getCancelButton();
+ } catch (NoSuchElementException e) {
+ cancelButtonFound = false;
+ }
+ assertFalse("Cancel button should not be visible in unbuffered mode.",
+ cancelButtonFound);
+ }
+
+ @Test
+ public void testToggleEditorUnbufferedWhileOpen() {
+ selectMenuPath(EDIT_ITEM_5);
+ assertEditorOpen();
+ selectMenuPath(TOGGLE_EDITOR_BUFFERED);
+ boolean thrown = logContainsText("Exception occured, java.lang.IllegalStateException");
+ assertTrue("IllegalStateException thrown", thrown);
+ }
+
+ @Test
+ public void testEditorMove() {
+ selectMenuPath(EDIT_ITEM_5);
+
+ assertEditorOpen();
+
+ String firstFieldValue = getEditorWidgets().get(0)
+ .getAttribute("value");
+ assertTrue("Editor is not at correct row index (5)",
+ "(5, 0)".equals(firstFieldValue));
+
+ getGridElement().getCell(10, 0).click();
+ firstFieldValue = getEditorWidgets().get(0).getAttribute("value");
+
+ assertTrue("Editor is not at correct row index (10)",
+ "(10, 0)".equals(firstFieldValue));
+ }
+
+ @Test
+ public void testErrorMessageWrapperHidden() {
+ selectMenuPath(EDIT_ITEM_5);
+
+ assertEditorOpen();
+
+ WebElement editorFooter = getEditor().findElement(
+ By.className("v-grid-editor-footer"));
+
+ assertTrue("Editor footer should not be visible when there's no error",
+ editorFooter.getCssValue("display").equalsIgnoreCase("none"));
+ }
+
+ @Test
+ public void testScrollAfterEditByAPI() {
+ int originalScrollPos = getGridVerticalScrollPos();
+
+ selectMenuPath(EDIT_ITEM_5);
+
+ scrollGridVerticallyTo(100);
+ assertGreater(
+ "Grid should scroll vertically while editing in unbuffered mode",
+ getGridVerticalScrollPos(), originalScrollPos);
+ }
+
+ @Test
+ public void testScrollAfterEditByMouse() {
+ int originalScrollPos = getGridVerticalScrollPos();
+
+ GridCellElement cell_5_0 = getGridElement().getCell(5, 0);
+ new Actions(getDriver()).doubleClick(cell_5_0).perform();
+
+ scrollGridVerticallyTo(100);
+ assertGreater(
+ "Grid should scroll vertically while editing in unbuffered mode",
+ getGridVerticalScrollPos(), originalScrollPos);
+ }
+
+ @Test
+ public void testScrollAfterEditByKeyboard() {
+ int originalScrollPos = getGridVerticalScrollPos();
+
+ GridCellElement cell_5_0 = getGridElement().getCell(5, 0);
+ cell_5_0.click();
+ new Actions(getDriver()).sendKeys(Keys.ENTER).perform();
+
+ scrollGridVerticallyTo(100);
+ assertGreater(
+ "Grid should scroll vertically while editing in unbuffered mode",
+ getGridVerticalScrollPos(), originalScrollPos);
+ }
+
+ @Test
+ public void testEditorInDisabledGrid() {
+ selectMenuPath(EDIT_ITEM_5);
+
+ selectMenuPath("Component", "State", "Enabled");
+ assertEditorOpen();
+
+ assertTrue("Editor text field should be disabled",
+ null != getEditorWidgets().get(2).getAttribute("disabled"));
+
+ selectMenuPath("Component", "State", "Enabled");
+ assertEditorOpen();
+
+ assertFalse("Editor text field should not be disabled",
+ null != getEditorWidgets().get(2).getAttribute("disabled"));
+ }
+
+ @Test
+ public void testMouseOpeningClosing() {
+
+ getGridElement().getCell(4, 0).doubleClick();
+ assertEditorOpen();
+
+ selectMenuPath(CANCEL_EDIT);
+ selectMenuPath(TOGGLE_EDIT_ENABLED);
+
+ getGridElement().getCell(4, 0).doubleClick();
+ assertEditorClosed();
+ }
+} \ No newline at end of file
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");
+ }
+}