diff options
6 files changed, 217 insertions, 9 deletions
diff --git a/WebContent/VAADIN/themes/base/grid/grid.scss b/WebContent/VAADIN/themes/base/grid/grid.scss index de38b8c1ff..69b293e26e 100644 --- a/WebContent/VAADIN/themes/base/grid/grid.scss +++ b/WebContent/VAADIN/themes/base/grid/grid.scss @@ -39,12 +39,19 @@ .#{$primaryStyleName}-editor-row { position: absolute; + overflow-y: visible; background: #EEE; box-shadow: 0 0 5px; & > div { position: absolute; + box-sizing: border-box; border: 1px solid #CCC; } + + .v-editor-row-save, + .v-editor-row-cancel { + position: absolute; + } } } diff --git a/client/src/com/vaadin/client/ui/grid/EditorRow.java b/client/src/com/vaadin/client/ui/grid/EditorRow.java index ddef7c3dc7..a748af172f 100644 --- a/client/src/com/vaadin/client/ui/grid/EditorRow.java +++ b/client/src/com/vaadin/client/ui/grid/EditorRow.java @@ -24,9 +24,12 @@ import com.google.gwt.dom.client.Style; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.dom.client.TableCellElement; import com.google.gwt.dom.client.TableRowElement; +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.ui.Button; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ui.grid.EditorRowHandler.EditorRowRequest; import com.vaadin.client.ui.grid.EditorRowHandler.EditorRowRequest.RequestCallback; @@ -79,8 +82,9 @@ public class EditorRow<T> { * the index of the row to be edited * * @throws IllegalStateException - * if this editor row is not enabled or if it is already in edit - * mode + * if this editor row is not enabled + * @throws IllegalStateException + * if this editor row is already in edit mode */ public void editRow(int rowIndex) { if (!enabled) { @@ -104,9 +108,12 @@ public class EditorRow<T> { } /** - * Cancels the currently active edit and hides the editor. + * Cancels the currently active edit and hides the editor. Any changes that + * are not {@link #commit() committed} are lost. * * @throws IllegalStateException + * if this editor row is not enabled + * @throws IllegalStateException * if this editor row is not in edit mode */ public void cancel() { @@ -125,6 +132,56 @@ public class EditorRow<T> { } /** + * Commits any unsaved changes to the data source. + * + * @throws IllegalStateException + * if this editor row is not enabled + * @throws IllegalStateException + * if this editor row is not in edit mode + */ + public void commit() { + if (!enabled) { + throw new IllegalStateException( + "Cannot commit: EditorRow is not enabled"); + } + if (state != State.ACTIVE) { + throw new IllegalStateException( + "Cannot commit: EditorRow is not in edit mode"); + } + + state = State.COMMITTING; + + handler.commit(new EditorRowRequest(rowIndex, new RequestCallback() { + @Override + public void onResponse(EditorRowRequest request) { + if (state == State.COMMITTING) { + state = State.ACTIVE; + } + } + })); + } + + /** + * Reloads row values from the data source, discarding any unsaved changes. + * + * @throws IllegalStateException + * if this editor row is not enabled + * @throws IllegalStateException + * if this editor row is not in edit mode + */ + public void discard() { + if (!enabled) { + throw new IllegalStateException( + "Cannot discard: EditorRow is not enabled"); + } + if (state != State.ACTIVE) { + throw new IllegalStateException( + "Cannot discard: EditorRow is not in edit mode"); + } + handler.discard(new EditorRowRequest(rowIndex, null)); + } + + /** * Returns the handler responsible for binding data and editor widgets to * this editor row. * @@ -263,10 +320,35 @@ public class EditorRow<T> { Widget editor = getHandler().getWidget(column); if (editor != null) { editorWidgets.add(editor); - cell.appendChild(editor.getElement()); - Grid.setParent(editor, grid); + attachWidget(editor, cell); } } + + Button save = new Button(); + save.setText("Save"); + save.setStyleName("v-editor-row-save"); + save.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + // TODO should have a mechanism for handling failed commits + commit(); + cancel(); + } + }); + setBounds(save.getElement(), 0, tr.getOffsetHeight() + 5, 50, 25); + attachWidget(save, editorOverlay); + + Button cancel = new Button(); + cancel.setText("Cancel"); + cancel.setStyleName("v-editor-row-cancel"); + cancel.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + cancel(); + } + }); + setBounds(cancel.getElement(), 55, tr.getOffsetHeight() + 5, 50, 25); + attachWidget(cancel, editorOverlay); } protected void hideOverlay() { @@ -305,6 +387,11 @@ public class EditorRow<T> { return cell; } + private void attachWidget(Widget w, Element parent) { + parent.appendChild(w.getElement()); + Grid.setParent(w, grid); + } + private static void setBounds(Element e, int left, int top, int width, int height) { Style style = e.getStyle(); diff --git a/client/src/com/vaadin/client/ui/grid/EditorRowHandler.java b/client/src/com/vaadin/client/ui/grid/EditorRowHandler.java index ba3d0b9cd2..d2d1e61efb 100644 --- a/client/src/com/vaadin/client/ui/grid/EditorRowHandler.java +++ b/client/src/com/vaadin/client/ui/grid/EditorRowHandler.java @@ -34,6 +34,8 @@ public interface EditorRowHandler<T> { * A request class for handling asynchronous data binding. The request is * callback-based to facilitate usage with remote or otherwise asynchronous * data sources. + * <p> + * TODO Should have a mechanism for signaling a failed request to the caller */ public static class EditorRowRequest { @@ -112,6 +114,28 @@ public interface EditorRowHandler<T> { public void cancel(EditorRowRequest request); /** + * Commits changes in the currently active edit to the data source. Called + * by the editor row when changes are saved. + * + * @param request + * the commit request + */ + public void commit(EditorRowRequest request); + + /** + * Discards any unsaved changes and reloads editor content from the data + * source. + * <p> + * Implementation note: This method may simply call + * {@link #bind(EditorRowRequest) bind} if no other processing needs to be + * done. + * + * @param request + * the discard request + */ + public void discard(EditorRowRequest request); + + /** * Returns a widget instance that is used to edit the values in the given * column. A null return value means the column is not editable. * diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index 7c0a2da96d..050f312d7e 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -233,6 +233,18 @@ public class GridConnector extends AbstractHasComponentsConnector { currentRequest.invokeCallback(); currentRequest = null; } + + @Override + public void commit(EditorRowRequest request) { + // TODO no-op until Vaadin comms implemented + request.invokeCallback(); + } + + @Override + public void discard(EditorRowRequest request) { + // TODO no-op until Vaadin comms implemented + request.invokeCallback(); + } } /** diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowClientTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowClientTest.java index a37bf41072..4c64eac6e5 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowClientTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorRowClientTest.java @@ -89,7 +89,7 @@ public class GridEditorRowClientTest extends GridBasicClientFeaturesTest { @Test public void testWidgetBinding() throws Exception { - selectMenuPath("Component", "State", "Editor row", "Edit row 100"); + selectMenuPath("Component", "Editor row", "Edit row 100"); WebElement editorRow = getEditorRow(); List<WebElement> widgets = editorRow.findElements(By @@ -119,4 +119,36 @@ public class GridEditorRowClientTest extends GridBasicClientFeaturesTest { assertFalse("normal column cell shoul've had contents", selectorDivs .get(1).getAttribute("innerHTML").isEmpty()); } + + @Test + public void testCommit() { + selectMenuPath("Component", "Editor row", "Edit row 100"); + + List<WebElement> widgets = getEditorRow().findElements( + By.className("gwt-TextBox")); + + widgets.get(0).sendKeys(" changed"); + + WebElement saveButton = getEditorRow().findElement( + By.className("v-editor-row-save")); + + saveButton.click(); + + assertEquals("(100, 0) changed", getGridElement().getCell(100, 0) + .getText()); + } + + @Test + public void testDiscard() { + selectMenuPath("Component", "Editor row", "Edit row 100"); + + List<WebElement> widgets = getEditorRow().findElements( + By.className("gwt-TextBox")); + + widgets.get(0).sendKeys(" changed"); + + selectMenuPath("Component", "Editor row", "Discard"); + + assertEquals("(100, 0)", getGridElement().getCell(100, 0).getText()); + } } 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 5b69df1fb7..d5d276c7db 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java @@ -23,6 +23,7 @@ import java.util.Map; import java.util.Random; import com.google.gwt.core.client.Scheduler.ScheduledCommand; +import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.shared.HandlerRegistration; @@ -96,9 +97,8 @@ public class GridBasicClientFeaturesWidget extends boolean hasSelectionColumn = !(grid.getSelectionModel() instanceof None); for (int i = 0; i < rowData.size(); i++) { - int gridColumnIndex = hasSelectionColumn ? i + 1 : i; - GridColumn<?, List<Data>> col = grid.getColumn(gridColumnIndex); - getWidget(col).setText(rowData.get(i).value.toString()); + int columnIndex = hasSelectionColumn ? i + 1 : i; + getWidget(columnIndex).setText(rowData.get(i).value.toString()); } request.invokeCallback(); @@ -111,6 +111,33 @@ public class GridBasicClientFeaturesWidget extends } @Override + public void commit(EditorRowRequest request) { + log.setText("Row " + request.getRowIndex() + " edit committed"); + List<Data> rowData = ds.getRow(request.getRowIndex()); + + int i = 0; + for (; i < COLUMNS - MANUALLY_FORMATTED_COLUMNS; i++) { + rowData.get(i).value = getWidget(i).getText(); + } + + rowData.get(i).value = Integer.valueOf(getWidget(i++).getText()); + rowData.get(i).value = new Date(getWidget(i++).getText()); + rowData.get(i).value = getWidget(i++).getText(); + rowData.get(i).value = Integer.valueOf(getWidget(i++).getText()); + rowData.get(i).value = Integer.valueOf(getWidget(i++).getText()); + + // notify data source of changes + ds.asList().set(request.getRowIndex(), rowData); + + request.invokeCallback(); + } + + @Override + public void discard(EditorRowRequest request) { + bind(request); + } + + @Override public TextBox getWidget(GridColumn<?, List<Data>> column) { if (grid.getColumns().indexOf(column) == 0 && !(grid.getSelectionModel() instanceof None)) { @@ -120,10 +147,15 @@ public class GridBasicClientFeaturesWidget extends TextBox w = widgets.get(column); if (w == null) { w = new TextBox(); + w.getElement().getStyle().setMargin(0, Unit.PX); widgets.put(column, w); } return w; } + + private TextBox getWidget(int i) { + return getWidget(grid.getColumn(i)); + } } private static final int MANUALLY_FORMATTED_COLUMNS = 5; @@ -704,6 +736,20 @@ public class GridBasicClientFeaturesWidget extends } }, "Component", "Editor row"); + addMenuCommand("Commit", new ScheduledCommand() { + @Override + public void execute() { + grid.getEditorRow().commit(); + } + }, "Component", "Editor row"); + + addMenuCommand("Discard", new ScheduledCommand() { + @Override + public void execute() { + grid.getEditorRow().discard(); + } + }, "Component", "Editor row"); + addMenuCommand("Cancel edit", new ScheduledCommand() { @Override public void execute() { |