summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--WebContent/VAADIN/themes/base/grid/grid.scss15
-rw-r--r--WebContent/VAADIN/themes/valo/components/_grid.scss11
-rw-r--r--client/src/com/vaadin/client/connectors/GridConnector.java28
-rw-r--r--client/src/com/vaadin/client/widget/grid/EditorHandler.java117
-rw-r--r--client/src/com/vaadin/client/widgets/Grid.java162
-rw-r--r--server/src/com/vaadin/ui/Grid.java76
-rw-r--r--shared/src/com/vaadin/shared/ui/grid/EditorClientRpc.java7
-rw-r--r--uitest/src/com/vaadin/testbench/elements/GridElement.java11
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorClientTest.java14
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java6
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java18
11 files changed, 333 insertions, 132 deletions
diff --git a/WebContent/VAADIN/themes/base/grid/grid.scss b/WebContent/VAADIN/themes/base/grid/grid.scss
index a79420f7a9..e4a4a1d920 100644
--- a/WebContent/VAADIN/themes/base/grid/grid.scss
+++ b/WebContent/VAADIN/themes/base/grid/grid.scss
@@ -266,6 +266,21 @@ $v-grid-editor-background-color: $v-grid-row-background-color !default;
max-width: 100%;
}
}
+
+ .error::before {
+ position: absolute;
+ display: block;
+ height: 0;
+ width: 0;
+ content: "";
+ border-top: 5px solid red;
+ border-right: 5px solid transparent;
+ }
+
+ .error,
+ .error > input {
+ background-color: #fee;
+ }
}
.#{$primaryStyleName}-editor-footer {
diff --git a/WebContent/VAADIN/themes/valo/components/_grid.scss b/WebContent/VAADIN/themes/valo/components/_grid.scss
index c481f127a8..4cac9c5e43 100644
--- a/WebContent/VAADIN/themes/valo/components/_grid.scss
+++ b/WebContent/VAADIN/themes/valo/components/_grid.scss
@@ -102,6 +102,17 @@ $v-grid-animations-enabled: $v-animations-enabled !default;
height: 100%;
vertical-align: middle;
}
+
+ .error::before {
+ border-top: round($v-unit-size / 4) solid $v-error-indicator-color;
+ border-right: round($v-unit-size / 4) solid transparent;
+ }
+
+ .error,
+ .error > input {
+ // taken from @mixin valo-textfield-error-style()
+ background-color: scale-color($v-error-indicator-color, $lightness: 98%);
+ }
.v-textfield,
.v-textfield-focus,
diff --git a/client/src/com/vaadin/client/connectors/GridConnector.java b/client/src/com/vaadin/client/connectors/GridConnector.java
index 8d383ab0ae..60a730c80e 100644
--- a/client/src/com/vaadin/client/connectors/GridConnector.java
+++ b/client/src/com/vaadin/client/connectors/GridConnector.java
@@ -18,6 +18,7 @@ package com.vaadin.client.connectors;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -202,7 +203,7 @@ public class GridConnector extends AbstractHasComponentsConnector implements
private EditorServerRpc rpc = getRpcProxy(EditorServerRpc.class);
- private EditorRequest<?> currentRequest = null;
+ private EditorRequest<JsonObject> currentRequest = null;
private boolean serverInitiated = false;
public CustomEditorHandler() {
@@ -227,12 +228,13 @@ public class GridConnector extends AbstractHasComponentsConnector implements
@Override
public void confirmBind(final boolean bindSucceeded) {
- endRequest(bindSucceeded);
+ endRequest(bindSucceeded, null);
}
@Override
- public void confirmSave(boolean saveSucceeded) {
- endRequest(saveSucceeded);
+ public void confirmSave(boolean saveSucceeded,
+ List<String> errorColumnsIds) {
+ endRequest(saveSucceeded, errorColumnsIds);
}
});
}
@@ -295,24 +297,34 @@ public class GridConnector extends AbstractHasComponentsConnector implements
}
}
- private void startRequest(EditorRequest<?> request) {
+ private void startRequest(EditorRequest<JsonObject> request) {
assert currentRequest == null : "Earlier request not yet finished";
currentRequest = request;
}
- private void endRequest(boolean succeeded) {
+ private void endRequest(boolean succeeded, List<String> errorColumnsIds) {
assert currentRequest != null : "Current request was null";
/*
* Clear current request first to ensure the state is valid if
* another request is made in the callback.
*/
- EditorRequest<?> request = currentRequest;
+ EditorRequest<JsonObject> request = currentRequest;
currentRequest = null;
if (succeeded) {
request.success();
} else {
- request.fail();
+ Collection<Column<?, JsonObject>> errorColumns;
+ if (errorColumnsIds != null) {
+ errorColumns = new ArrayList<Grid.Column<?, JsonObject>>();
+ for (String colId : errorColumnsIds) {
+ errorColumns.add(columnIdToColumn.get(colId));
+ }
+ } else {
+ errorColumns = null;
+ }
+
+ request.failure(errorColumns);
}
}
}
diff --git a/client/src/com/vaadin/client/widget/grid/EditorHandler.java b/client/src/com/vaadin/client/widget/grid/EditorHandler.java
index 07ec1b231c..1d152c708c 100644
--- a/client/src/com/vaadin/client/widget/grid/EditorHandler.java
+++ b/client/src/com/vaadin/client/widget/grid/EditorHandler.java
@@ -15,6 +15,8 @@
*/
package com.vaadin.client.widget.grid;
+import java.util.Collection;
+
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.widgets.Grid;
@@ -43,82 +45,27 @@ public interface EditorHandler<T> {
* @param <T>
* the row data type
*/
- public static class EditorRequest<T> {
-
- /**
- * A callback interface used to notify the invoker of the editor handler
- * of completed editor requests.
- *
- * @param <T>
- * the row data type
- */
- public interface RequestCallback<T> {
- /**
- * The method that must be called when the request has been
- * processed correctly.
- *
- * @param request
- * the original request object
- */
- public void onSuccess(EditorRequest<T> request);
-
- /**
- * The method that must be called when processing the request has
- * produced an aborting error.
- *
- * @param request
- * the original request object
- */
- public void onError(EditorRequest<T> request);
- }
-
- private Grid<T> grid;
- private int rowIndex;
- private RequestCallback<T> callback;
- private boolean completed = false;
-
- /**
- * Creates a new editor request.
- *
- * @param rowIndex
- * the index of the edited row
- * @param callback
- * the callback invoked when the request is ready, or null if
- * no need to call back
- */
- public EditorRequest(Grid<T> grid, int rowIndex,
- RequestCallback<T> callback) {
- this.grid = grid;
- this.rowIndex = rowIndex;
- this.callback = callback;
- }
-
+ public interface EditorRequest<T> {
/**
* Returns the index of the row being requested.
*
* @return the row index
*/
- public int getRowIndex() {
- return rowIndex;
- }
+ public int getRowIndex();
/**
* Returns the row data related to the row being requested.
*
* @return the row data
*/
- public T getRow() {
- return grid.getDataSource().getRow(rowIndex);
- }
+ public T getRow();
/**
* Returns the grid instance related to this editor request.
*
* @return the grid instance
*/
- public Grid<T> getGrid() {
- return grid;
- }
+ public Grid<T> getGrid();
/**
* Returns the editor widget used to edit the values of the given
@@ -128,59 +75,30 @@ public interface EditorHandler<T> {
* the column whose widget to get
* @return the widget related to the column
*/
- public Widget getWidget(Grid.Column<?, T> column) {
- Widget w = grid.getEditorWidget(column);
- assert w != null;
- return w;
- }
-
- /**
- * Completes this request. The request can only be completed once. This
- * method should only be called by an EditorHandler implementer if the
- * request handling is asynchronous in nature and {@link #startAsync()}
- * is previously invoked for this request. Synchronous requests are
- * completed automatically by the editor.
- *
- * @throws IllegalStateException
- * if the request is already completed
- */
- private void complete() {
- if (completed) {
- throw new IllegalStateException(
- "An EditorRequest must be completed exactly once");
- }
- completed = true;
- }
+ public Widget getWidget(Grid.Column<?, T> column);
/**
* Informs Grid that the editor request was a success.
*/
- public void success() {
- complete();
- if (callback != null) {
- callback.onSuccess(this);
- }
- }
+ public void success();
/**
* Informs Grid that an error occurred while trying to process the
* request.
+ *
+ * @param errorColumns
+ * a collection of columns for which an error indicator
+ * should be shown, or <code>null</code> if no columns should
+ * be marked as erroneous.
*/
- public void fail() {
- complete();
- if (callback != null) {
- callback.onError(this);
- }
- }
+ public void failure(Collection<Grid.Column<?, T>> errorColumns);
/**
* Checks whether the request is completed or not.
*
* @return <code>true</code> iff the request is completed
*/
- public boolean isCompleted() {
- return completed;
- }
+ public boolean isCompleted();
}
/**
@@ -188,8 +106,9 @@ public interface EditorHandler<T> {
* opened for editing.
* <p>
* The implementation <em>must</em> call either
- * {@link EditorRequest#success()} or {@link EditorRequest#fail()} to signal
- * a successful or a failed (respectively) bind action.
+ * {@link EditorRequest#success()} or
+ * {@link EditorRequest#failure(Collection)} to signal a successful or a
+ * failed (respectively) bind action.
*
* @param request
* the data binding request
diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java
index fb7ec3abb5..0f3ffc696a 100644
--- a/client/src/com/vaadin/client/widgets/Grid.java
+++ b/client/src/com/vaadin/client/widgets/Grid.java
@@ -83,7 +83,6 @@ import com.vaadin.client.widget.grid.DataAvailableEvent;
import com.vaadin.client.widget.grid.DataAvailableHandler;
import com.vaadin.client.widget.grid.EditorHandler;
import com.vaadin.client.widget.grid.EditorHandler.EditorRequest;
-import com.vaadin.client.widget.grid.EditorHandler.EditorRequest.RequestCallback;
import com.vaadin.client.widget.grid.EventCellReference;
import com.vaadin.client.widget.grid.RendererCellReference;
import com.vaadin.client.widget.grid.RowReference;
@@ -936,6 +935,106 @@ public class Grid<T> extends ResizeComposite implements
}
}
+ private static class EditorRequestImpl<T> implements EditorRequest<T> {
+
+ /**
+ * A callback interface used to notify the invoker of the editor handler
+ * of completed editor requests.
+ *
+ * @param <T>
+ * the row data type
+ */
+ public static interface RequestCallback<T> {
+ /**
+ * The method that must be called when the request has been
+ * processed correctly.
+ *
+ * @param request
+ * the original request object
+ */
+ public void onSuccess(EditorRequest<T> request);
+
+ /**
+ * The method that must be called when processing the request has
+ * produced an aborting error.
+ *
+ * @param request
+ * the original request object
+ */
+ public void onError(EditorRequest<T> request);
+ }
+
+ private Grid<T> grid;
+ private int rowIndex;
+ private RequestCallback<T> callback;
+ private boolean completed = false;
+
+ public EditorRequestImpl(Grid<T> grid, int rowIndex,
+ RequestCallback<T> callback) {
+ this.grid = grid;
+ this.rowIndex = rowIndex;
+ this.callback = callback;
+ }
+
+ @Override
+ public int getRowIndex() {
+ return rowIndex;
+ }
+
+ @Override
+ public T getRow() {
+ return grid.getDataSource().getRow(rowIndex);
+ }
+
+ @Override
+ public Grid<T> getGrid() {
+ return grid;
+ }
+
+ @Override
+ public Widget getWidget(Grid.Column<?, T> column) {
+ Widget w = grid.getEditorWidget(column);
+ assert w != null;
+ return w;
+ }
+
+ private void complete(Collection<Column<?, T>> errorColumns) {
+ if (completed) {
+ throw new IllegalStateException(
+ "An EditorRequest must be completed exactly once");
+ }
+ completed = true;
+
+ grid.getEditor().clearEditorColumnErrors();
+ if (errorColumns != null) {
+ for (Column<?, T> column : errorColumns) {
+ grid.getEditor().setEditorColumnError(column, true);
+ }
+ }
+ }
+
+ @Override
+ public void success() {
+ complete(null);
+ if (callback != null) {
+ callback.onSuccess(this);
+ }
+ }
+
+ @Override
+ public void failure(Collection<Grid.Column<?, T>> errorColumns) {
+ complete(errorColumns);
+ if (callback != null) {
+ callback.onError(this);
+ }
+ }
+
+ @Override
+ public boolean isCompleted() {
+ return completed;
+ }
+ }
+
/**
* An editor UI for Grid rows. A single Grid row at a time can be opened for
* editing.
@@ -945,6 +1044,8 @@ public class Grid<T> extends ResizeComposite implements
public static final int KEYCODE_SHOW = KeyCodes.KEY_ENTER;
public static final int KEYCODE_HIDE = KeyCodes.KEY_ESCAPE;
+ private static final String ERROR_CLASS_NAME = "error";
+
protected enum State {
INACTIVE, ACTIVATING, BINDING, ACTIVE, SAVING
}
@@ -988,7 +1089,7 @@ public class Grid<T> extends ResizeComposite implements
}
};
- private final RequestCallback<T> saveRequestCallback = new RequestCallback<T>() {
+ private final EditorRequestImpl.RequestCallback<T> saveRequestCallback = new EditorRequestImpl.RequestCallback<T>() {
@Override
public void onSuccess(EditorRequest<T> request) {
if (state == State.SAVING) {
@@ -1027,7 +1128,7 @@ public class Grid<T> extends ResizeComposite implements
+ " remember to call success() or fail()?");
}
};
- private final RequestCallback<T> bindRequestCallback = new RequestCallback<T>() {
+ private final EditorRequestImpl.RequestCallback<T> bindRequestCallback = new EditorRequestImpl.RequestCallback<T>() {
@Override
public void onSuccess(EditorRequest<T> request) {
if (state == State.BINDING) {
@@ -1055,6 +1156,9 @@ 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>>();
+
public Editor() {
saveButton = new Button();
saveButton.setText(GridConstants.DEFAULT_SAVE_CAPTION);
@@ -1132,7 +1236,7 @@ public class Grid<T> extends ResizeComposite implements
hideOverlay();
grid.getEscalator().setScrollLocked(Direction.VERTICAL, false);
- EditorRequest<T> request = new EditorRequest<T>(grid, rowIndex,
+ EditorRequest<T> request = new EditorRequestImpl<T>(grid, rowIndex,
null);
handler.cancel(request);
state = State.INACTIVE;
@@ -1159,7 +1263,7 @@ public class Grid<T> extends ResizeComposite implements
state = State.SAVING;
setButtonsEnabled(false);
saveTimeout.schedule(SAVE_TIMEOUT_MS);
- EditorRequest<T> request = new EditorRequest<T>(grid, rowIndex,
+ EditorRequest<T> request = new EditorRequestImpl<T>(grid, rowIndex,
saveRequestCallback);
handler.save(request);
}
@@ -1222,8 +1326,8 @@ public class Grid<T> extends ResizeComposite implements
if (state == State.ACTIVATING) {
state = State.BINDING;
bindTimeout.schedule(BIND_TIMEOUT_MS);
- EditorRequest<T> request = new EditorRequest<T>(grid, rowIndex,
- bindRequestCallback);
+ EditorRequest<T> request = new EditorRequestImpl<T>(grid,
+ rowIndex, bindRequestCallback);
handler.bind(request);
grid.getEscalator().setScrollLocked(Direction.VERTICAL, true);
}
@@ -1372,6 +1476,8 @@ public class Grid<T> extends ResizeComposite implements
editorOverlay.removeFromParent();
scrollHandler.removeHandler();
+
+ clearEditorColumnErrors();
}
protected void setStylePrimaryName(String primaryName) {
@@ -1480,6 +1586,46 @@ public class Grid<T> extends ResizeComposite implements
public String getCancelCaption() {
return cancelButton.getText();
}
+
+ public void setEditorColumnError(Column<?, T> column, boolean hasError) {
+ if (state != State.ACTIVE && state != State.SAVING) {
+ throw new IllegalStateException("Cannot set cell error "
+ + "status: editor is neither active nor saving.");
+ }
+
+ if (isEditorColumnError(column) == hasError) {
+ return;
+ }
+
+ Element editorCell = getWidget(column).getElement()
+ .getParentElement();
+ if (hasError) {
+ editorCell.addClassName(ERROR_CLASS_NAME);
+ columnErrors.add(column);
+ } else {
+ editorCell.removeClassName(ERROR_CLASS_NAME);
+ columnErrors.remove(column);
+ }
+ }
+
+ public void clearEditorColumnErrors() {
+
+ /*
+ * editorOverlay has no children if it's not active, effectively
+ * making this loop a NOOP.
+ */
+ Element e = editorOverlay.getFirstChildElement();
+ while (e != null) {
+ e.removeClassName(ERROR_CLASS_NAME);
+ e = e.getNextSiblingElement();
+ }
+
+ columnErrors.clear();
+ }
+
+ public boolean isEditorColumnError(Column<?, T> column) {
+ return columnErrors.contains(column);
+ }
}
public static abstract class AbstractGridKeyEvent<HANDLER extends AbstractGridKeyEventHandler>
@@ -3215,7 +3361,7 @@ public class Grid<T> extends ResizeComposite implements
*
* @return {@code true} if this column is editable, {@code false}
* otherwise
- *
+ *
* @see #setEditable(boolean)
*/
public boolean isEditable() {
diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java
index 69e23ecd92..ef97f9b336 100644
--- a/server/src/com/vaadin/ui/Grid.java
+++ b/server/src/com/vaadin/ui/Grid.java
@@ -260,6 +260,8 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
private CommitException cause;
+ private Set<Column> errorColumns = new HashSet<Column>();
+
public CommitErrorEvent(Grid grid, CommitException cause) {
super(grid);
this.cause = cause;
@@ -288,6 +290,26 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
return cause.getCause() instanceof InvalidValueException;
}
+ /**
+ * Marks that an error indicator should be shown for the editor of a
+ * column.
+ *
+ * @param column
+ * the column to show an error for
+ */
+ public void addErrorColumn(Column column) {
+ errorColumns.add(column);
+ }
+
+ /**
+ * Gets all the columns that have been marked as erroneous.
+ *
+ * @return an umodifiable collection of erroneous columns
+ */
+ public Collection<Column> getErrorColumns() {
+ return Collections.unmodifiableCollection(errorColumns);
+ }
+
}
/**
@@ -302,19 +324,36 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
.getCause().getInvalidFields();
if (!invalidFields.isEmpty()) {
- // Validation error, show first failure as
- // "<Column header>: <message>"
+ Object firstErrorPropertyId = null;
+ Field<?> firstErrorField = null;
+
FieldGroup fieldGroup = event.getCause().getFieldGroup();
- Object propertyId = getFirstPropertyId(fieldGroup,
- invalidFields.keySet());
- Field<?> field = fieldGroup.getField(propertyId);
- String caption = getColumn(propertyId).getHeaderCaption();
- // TODO This should be shown in the editor component once
- // there is a place for that. Optionally, all errors should be
- // shown
- Notification.show(caption + ": "
- + invalidFields.get(field).getLocalizedMessage(),
- Type.ERROR_MESSAGE);
+ for (Column column : getColumns()) {
+ Object propertyId = column.getPropertyId();
+ Field<?> field = fieldGroup.getField(propertyId);
+ if (invalidFields.keySet().contains(field)) {
+ event.addErrorColumn(column);
+
+ if (firstErrorPropertyId == null) {
+ firstErrorPropertyId = propertyId;
+ firstErrorField = field;
+ }
+ }
+ }
+
+ /*
+ * Validation error, show first failure as
+ * "<Column header>: <message>"
+ */
+ String caption = getColumn(firstErrorPropertyId)
+ .getHeaderCaption();
+ String message = invalidFields.get(firstErrorField)
+ .getLocalizedMessage();
+ /*
+ * TODO This should be shown in the editor component once there
+ * is a place for that. Optionally, all errors should be shown
+ */
+ Notification.show(caption + ": " + message, Type.ERROR_MESSAGE);
} else {
com.vaadin.server.ErrorEvent.findErrorHandler(Grid.this).error(
@@ -3016,14 +3055,21 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
@Override
public void save(int rowIndex) {
+ List<String> errorColumnIds = null;
boolean success = false;
try {
saveEditor();
success = true;
} catch (CommitException e) {
try {
- getEditorErrorHandler().commitError(
- new CommitErrorEvent(Grid.this, e));
+ CommitErrorEvent event = new CommitErrorEvent(
+ Grid.this, e);
+ getEditorErrorHandler().commitError(event);
+
+ errorColumnIds = new ArrayList<String>();
+ for (Column column : event.getErrorColumns()) {
+ errorColumnIds.add(column.state.id);
+ }
} catch (Exception ee) {
// A badly written error handler can throw an exception,
// which would lock up the Grid
@@ -3032,7 +3078,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
} catch (Exception e) {
handleError(e);
}
- getEditorRpc().confirmSave(success);
+ getEditorRpc().confirmSave(success, errorColumnIds);
}
private void handleError(Exception e) {
diff --git a/shared/src/com/vaadin/shared/ui/grid/EditorClientRpc.java b/shared/src/com/vaadin/shared/ui/grid/EditorClientRpc.java
index 82e08999b4..6fb0b7a069 100644
--- a/shared/src/com/vaadin/shared/ui/grid/EditorClientRpc.java
+++ b/shared/src/com/vaadin/shared/ui/grid/EditorClientRpc.java
@@ -15,6 +15,8 @@
*/
package com.vaadin.shared.ui.grid;
+import java.util.List;
+
import com.vaadin.shared.communication.ClientRpc;
/**
@@ -56,6 +58,9 @@ public interface EditorClientRpc extends ClientRpc {
*
* @param saveSucceeded
* <code>true</code> iff the save action was successful
+ * @param errorColumnsIds
+ * a list of column keys that should get error markers, or
+ * <code>null</code> if there should be no error markers
*/
- void confirmSave(boolean saveSucceeded);
+ void confirmSave(boolean saveSucceeded, List<String> errorColumnsIds);
}
diff --git a/uitest/src/com/vaadin/testbench/elements/GridElement.java b/uitest/src/com/vaadin/testbench/elements/GridElement.java
index 6b1279d2c2..5d85de4eb6 100644
--- a/uitest/src/com/vaadin/testbench/elements/GridElement.java
+++ b/uitest/src/com/vaadin/testbench/elements/GridElement.java
@@ -100,6 +100,17 @@ public class GridElement extends AbstractComponentElement {
}
/**
+ * Checks whether a field is marked with an error.
+ *
+ * @param colIndex
+ * column index
+ * @return <code>true</code> iff the field is marked with an error
+ */
+ public boolean isFieldErrorMarked(int colIndex) {
+ return getField(colIndex).getAttribute("class").contains("error");
+ }
+
+ /**
* Saves the fields of this editor.
* <p>
* <em>Note:</em> that this closes the editor making this element
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorClientTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorClientTest.java
index 30481ebc65..2d8c9eb763 100644
--- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorClientTest.java
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorClientTest.java
@@ -187,6 +187,7 @@ public class GridEditorClientTest extends GridBasicClientFeaturesTest {
.getText());
}
+ @Test
public void testUneditableColumn() {
selectMenuPath("Component", "Editor", "Edit row 5");
@@ -194,6 +195,19 @@ public class GridEditorClientTest extends GridBasicClientFeaturesTest {
getGridElement().getEditor().isEditable(3));
}
+ @Test
+ public void testErrorField() {
+ selectMenuPath(EDIT_ROW_5);
+
+ assertTrue("No errors should be present",
+ getEditor().findElements(By.className("error")).isEmpty());
+ selectMenuPath("Component", "Editor", "Toggle second editor error");
+ getSaveButton().click();
+
+ assertEquals("Unexpected amount of error fields", 1, getEditor()
+ .findElements(By.className("error")).size());
+ }
+
protected WebElement getSaveButton() {
return getEditor().findElement(By.className("v-grid-editor-save"));
}
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 5e11af1ca5..e1567b4286 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
@@ -212,6 +212,10 @@ public class GridEditorTest extends GridBasicFeaturesTest {
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");
@@ -220,6 +224,8 @@ public class GridEditorTest extends GridBasicFeaturesTest {
assertEquals("Column 7: Could not convert value to Integer",
n.getCaption());
n.close();
+ assertTrue("Field 7 should have been marked with an error after error",
+ editor.isFieldErrorMarked(7));
editor.cancel();
selectMenuPath(EDIT_ITEM_100);
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java
index 41d74a11a2..7509054957 100644
--- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java
+++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java
@@ -16,6 +16,7 @@
package com.vaadin.tests.widgetset.client.grid;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
@@ -67,6 +68,7 @@ import com.vaadin.client.widget.grid.events.ScrollEvent;
import com.vaadin.client.widget.grid.events.ScrollHandler;
import com.vaadin.client.widget.grid.selection.SelectionModel.None;
import com.vaadin.client.widgets.Grid;
+import com.vaadin.client.widgets.Grid.Column;
import com.vaadin.client.widgets.Grid.FooterRow;
import com.vaadin.client.widgets.Grid.HeaderRow;
import com.vaadin.client.widgets.Grid.SelectionMode;
@@ -122,6 +124,12 @@ public class GridBasicClientFeaturesWidget extends
@Override
public void save(EditorRequest<List<Data>> request) {
+ if (secondEditorError) {
+ log.setText("Syntethic fail of editor in column 2");
+ request.failure(Collections.<Column<?, List<Data>>> singleton(grid
+ .getColumn(2)));
+ return;
+ }
try {
log.setText("Row " + request.getRowIndex() + " edit committed");
List<Data> rowData = ds.getRow(request.getRowIndex());
@@ -145,7 +153,7 @@ public class GridBasicClientFeaturesWidget extends
request.success();
} catch (Exception e) {
Logger.getLogger(getClass().getName()).warning(e.toString());
- request.fail();
+ request.failure(null);
}
}
@@ -179,6 +187,8 @@ public class GridBasicClientFeaturesWidget extends
private final ListDataSource<List<Data>> ds;
private final ListSorter<List<Data>> sorter;
+ private boolean secondEditorError = false;
+
/**
* Our basic data object
*/
@@ -972,6 +982,12 @@ public class GridBasicClientFeaturesWidget extends
}
}, "Component", "Editor");
+ addMenuCommand("Toggle second editor error", new ScheduledCommand() {
+ @Override
+ public void execute() {
+ secondEditorError = !secondEditorError;
+ }
+ }, "Component", "Editor");
}
private void configureFooterRow(final FooterRow row) {