diff options
9 files changed, 118 insertions, 5 deletions
diff --git a/all/src/main/templates/release-notes.html b/all/src/main/templates/release-notes.html index fda12e0a2d..20a7346182 100644 --- a/all/src/main/templates/release-notes.html +++ b/all/src/main/templates/release-notes.html @@ -113,7 +113,7 @@ <li>Row height in <tt>Grid</tt> is replaced with separate header, body and footer row heights</li> <li><tt>GridState</tt> variable <tt>rowHeight</tt> has been replaced by three variables.</li> <li><tt>Button</tt> has a new constructor that may cause constructor calls with null as first parameter to be ambiguous.</li> - <li><tt>DataCommunicator</tt> method <tt>getDataProviderSize</tt> is now <tt>public</tt>, not <tt>protected</tt>.</li> + <li><tt>DataCommunicator</tt> methods <tt>getDataProviderSize</tt> and <tt>fetchItemsWithRange</tt> are now <tt>public</tt>, not <tt>protected</tt>.</li> <li><tt>Binder</tt> method <tt>getBindings</tt> now returns a Collection, not a Set.</li> <li><tt>BindingBuilder</tt> now works like a proper builder. Adding a converter will not mark Binding as <tt>bound</tt> allowing chaining to the same object.</li> <li><tt>ErrorLevel</tt> is removed from <tt>ErrorMessage</tt> and now <tt>com.vaadin.shared.ui.ErrorLevel</tt> should be used.</li> diff --git a/client/src/main/java/com/vaadin/client/connectors/grid/EditorConnector.java b/client/src/main/java/com/vaadin/client/connectors/grid/EditorConnector.java index 50704c4262..c8c60c9620 100644 --- a/client/src/main/java/com/vaadin/client/connectors/grid/EditorConnector.java +++ b/client/src/main/java/com/vaadin/client/connectors/grid/EditorConnector.java @@ -19,6 +19,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import com.google.gwt.core.client.Scheduler; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ComponentConnector; import com.vaadin.client.ConnectorMap; @@ -28,6 +29,7 @@ import com.vaadin.client.extensions.AbstractExtensionConnector; import com.vaadin.client.widget.grid.EditorHandler; import com.vaadin.client.widgets.Grid; import com.vaadin.client.widgets.Grid.Column; +import com.vaadin.shared.Range; import com.vaadin.shared.data.DataCommunicatorConstants; import com.vaadin.shared.ui.Connect; import com.vaadin.shared.ui.grid.editor.EditorClientRpc; @@ -46,6 +48,9 @@ import elemental.json.JsonObject; @Connect(EditorImpl.class) public class EditorConnector extends AbstractExtensionConnector { + private Integer currentEditedRow = null; + private boolean waitingForAvailableData = false; + /** * EditorHandler for communicating with the server-side implementation. */ @@ -56,6 +61,20 @@ public class EditorConnector extends AbstractExtensionConnector { public CustomEditorHandler() { registerRpc(EditorClientRpc.class, new EditorClientRpc() { + + @Override + public void bind(final int rowIndex) { + // call this deferred to avoid issues with editing on init + Scheduler.get().scheduleDeferred(() -> { + currentEditedRow = rowIndex; + // might need to wait for available data, + // if data is available, ensureAvailability will immediately trigger the handler anyway, + // so no need for alternative "immediately available" logic + waitingForAvailableData = true; + getParent().getDataSource().ensureAvailability(rowIndex, 1); + }); + } + @Override public void cancel() { serverInitiated = true; @@ -110,6 +129,7 @@ public class EditorConnector extends AbstractExtensionConnector { // a confirmation from the server rpc.cancel(afterBeingSaved); } + currentEditedRow = null; } @Override @@ -198,6 +218,13 @@ public class EditorConnector extends AbstractExtensionConnector { protected void extend(ServerConnector target) { Grid<JsonObject> grid = getParent().getWidget(); grid.getEditor().setHandler(new CustomEditorHandler()); + grid.addDataAvailableHandler((event) -> { + Range range = event.getAvailableRows(); + if (waitingForAvailableData && currentEditedRow != null && range.contains(currentEditedRow)) { + getParent().getWidget().editRow(currentEditedRow); + waitingForAvailableData = false; + } + }); } @Override diff --git a/server/src/main/java/com/vaadin/data/provider/DataCommunicator.java b/server/src/main/java/com/vaadin/data/provider/DataCommunicator.java index 9996d8d1aa..66bf758efe 100644 --- a/server/src/main/java/com/vaadin/data/provider/DataCommunicator.java +++ b/server/src/main/java/com/vaadin/data/provider/DataCommunicator.java @@ -370,7 +370,7 @@ public class DataCommunicator<T> extends AbstractExtension { * @since 8.1 */ @SuppressWarnings({ "rawtypes", "unchecked" }) - protected List<T> fetchItemsWithRange(int offset, int limit) { + public List<T> fetchItemsWithRange(int offset, int limit) { return (List<T>) getDataProvider().fetch(new Query(offset, limit, backEndSorting, inMemorySorting, filter)) .collect(Collectors.toList()); diff --git a/server/src/main/java/com/vaadin/data/provider/HierarchicalDataCommunicator.java b/server/src/main/java/com/vaadin/data/provider/HierarchicalDataCommunicator.java index 627cc28651..b0397ffcc7 100644 --- a/server/src/main/java/com/vaadin/data/provider/HierarchicalDataCommunicator.java +++ b/server/src/main/java/com/vaadin/data/provider/HierarchicalDataCommunicator.java @@ -66,7 +66,7 @@ public class HierarchicalDataCommunicator<T> extends DataCommunicator<T> { } @Override - protected List<T> fetchItemsWithRange(int offset, int limit) { + public List<T> fetchItemsWithRange(int offset, int limit) { // Instead of adding logic to this class, delegate request to the // separate object handling hierarchies. return mapper.fetchItems(Range.withLength(offset, limit)) diff --git a/server/src/main/java/com/vaadin/ui/components/grid/Editor.java b/server/src/main/java/com/vaadin/ui/components/grid/Editor.java index 26ef8101ab..8c34fbdf64 100644 --- a/server/src/main/java/com/vaadin/ui/components/grid/Editor.java +++ b/server/src/main/java/com/vaadin/ui/components/grid/Editor.java @@ -104,6 +104,16 @@ public interface Editor<T> extends Serializable { public void cancel(); /** + * Edits the selected row + * + * @param rowNumber + * the row to edit + * + * @since 8.2 + */ + public void editRow(int rowNumber); + + /** * Sets the caption of the save button in buffered mode. * * @param saveCaption diff --git a/server/src/main/java/com/vaadin/ui/components/grid/EditorImpl.java b/server/src/main/java/com/vaadin/ui/components/grid/EditorImpl.java index 4d5e91b671..7329677ca3 100644 --- a/server/src/main/java/com/vaadin/ui/components/grid/EditorImpl.java +++ b/server/src/main/java/com/vaadin/ui/components/grid/EditorImpl.java @@ -267,6 +267,43 @@ public class EditorImpl<T> extends AbstractGridExtension<T> rpc.cancel(); } + /** + * Opens the editor interface for the provided row. Scrolls the Grid to + * bring the row to view if it is not already visible. + * + * Note that any cell content rendered by a WidgetRenderer will not be + * visible in the editor row. + * + * @param rowNumber + * the row number of the edited item + * @throws IllegalStateException + * if the editor is not enabled or already editing a different item + * in buffered mode + * @throws IllegalArgumentException + * if the {@code rowNumber} is not in the backing data provider + * @see #setEnabled(boolean) + */ + public void editRow(int rowNumber) + throws IllegalStateException, IllegalArgumentException { + if (!isEnabled()) { + throw new IllegalStateException("Item editor is not enabled"); + } + T beanToEdit = getParent().getDataCommunicator(). + fetchItemsWithRange(rowNumber, 1). + stream().findFirst().orElseThrow(() -> new IllegalArgumentException( + "Row number " + rowNumber+ "did not yield any item from data provider")); + if (!beanToEdit.equals(edited)) { + if (isBuffered() && edited != null) { + throw new IllegalStateException("Editing item " + beanToEdit + + " failed. Item editor is already editing item " + + edited); + } else { + rpc.bind(rowNumber); + } + } + + } + private void doCancel(boolean afterBeingSaved) { T editedBean = edited; doClose(); diff --git a/shared/src/main/java/com/vaadin/shared/ui/grid/editor/EditorClientRpc.java b/shared/src/main/java/com/vaadin/shared/ui/grid/editor/EditorClientRpc.java index ff4ca4c614..e278e7716b 100644 --- a/shared/src/main/java/com/vaadin/shared/ui/grid/editor/EditorClientRpc.java +++ b/shared/src/main/java/com/vaadin/shared/ui/grid/editor/EditorClientRpc.java @@ -28,6 +28,15 @@ import com.vaadin.shared.communication.ClientRpc; public interface EditorClientRpc extends ClientRpc { /** + * Tells the client to open the editor and bind data to it. + * + * @param rowIndex + * the index of the edited row + * + */ + void bind(int rowIndex); + + /** * Tells the client to cancel editing and hide the editor. */ void cancel(); diff --git a/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java b/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java index 56d970308d..c9144e52f0 100644 --- a/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java +++ b/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java @@ -763,6 +763,11 @@ public class GridBasics extends AbstractTestUIWithLog { editorMenu.addItem("Save", i -> grid.getEditor().save()); editorMenu.addItem("Cancel edit", i -> grid.getEditor().cancel()); + Stream.of(0, 5, 100).forEach(i -> editorMenu.addItem("Edit row " + i, + menuItem -> grid.getEditor().editRow(i))); + editorMenu.addItem("Edit last row", menuItem -> grid.getEditor() + .editRow(grid.getDataCommunicator().getDataProviderSize() - 1)); + editorMenu.addItem("Change save caption", e -> grid.getEditor().setSaveCaption("ǝʌɐS")); editorMenu.addItem("Change cancel caption", diff --git a/uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridEditorTest.java b/uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridEditorTest.java index d8a49a5938..832e5e6651 100644 --- a/uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridEditorTest.java +++ b/uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridEditorTest.java @@ -19,6 +19,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import org.junit.Assert; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; @@ -37,8 +38,8 @@ public abstract class GridEditorTest extends GridBasicsTest { .className("v-grid-editor-cancel"); protected static final org.openqa.selenium.By BY_EDITOR_SAVE = By .className("v-grid-editor-save"); - protected static final String[] TOGGLE_EDIT_ENABLED = { - "Component", "Editor", "Enabled" }; + protected static final String[] TOGGLE_EDIT_ENABLED = { "Component", + "Editor", "Enabled" }; @Override @Before @@ -216,6 +217,30 @@ public abstract class GridEditorTest extends GridBasicsTest { assertEditorClosed(); } + @Test + public void testEditorOpeningFromServer() { + selectMenuPath("Component", "Editor", "Edit row 5"); + assertEditorOpen(); + + Assert.assertEquals("Unexpected editor field content", "5", + getEditor().getField(3).getAttribute("value")); + Assert.assertEquals("Unexpected not-editable column content", "(5, 1)", + getEditor().findElement(By.className("not-editable")) + .getText()); + } + + @Test + public void testEditorOpenWithScrollFromServer() { + selectMenuPath("Component", "Editor", "Edit last row"); + assertEditorOpen(); + + Assert.assertEquals("Unexpected editor field content", "999", + getEditor().getField(3).getAttribute("value")); + Assert.assertEquals("Unexpected not-editable column content", + "(999, 1)", getEditor() + .findElement(By.className("not-editable")).getText()); + } + protected WebElement getSaveButton() { return getDriver().findElement(BY_EDITOR_SAVE); } |