summaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
authorHenrik Paul <henrik@vaadin.com>2015-02-05 23:50:31 +0200
committerLeif Åstrand <leif@vaadin.com>2015-02-06 11:19:17 +0200
commit0e141e31bb30a0ab6726129f3c9fa892c92573e4 (patch)
tree672975bd0671b06d1498e5ce5f984e7d30179ef7 /client
parent0c82dad0ab225aeb9920b2e5c6f061da871bea66 (diff)
downloadvaadin-framework-0e141e31bb30a0ab6726129f3c9fa892c92573e4.tar.gz
vaadin-framework-0e141e31bb30a0ab6726129f3c9fa892c92573e4.zip
Highlights erroneous cells in Grid editor (#16575)
Change-Id: Ie1f9d738db7a03ddb01b968782ad5e4877af1d7e
Diffstat (limited to 'client')
-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
3 files changed, 192 insertions, 115 deletions
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() {