This patch reverts the fix #10557 and replaces it with a proper solution from Grid perspective. Fixes #10987 Fixes #10985tags/8.5.0.alpha2
@Override | @Override | ||||
public void cancel() { | public void cancel() { | ||||
serverInitiated = true; | |||||
getParent().getWidget().cancelEditor(); | |||||
// Canceling an editor that is not open is a no-op. | |||||
if (getParent().getWidget().isEditorActive()) { | |||||
serverInitiated = true; | |||||
getParent().getWidget().cancelEditor(); | |||||
} | |||||
} | } | ||||
@Override | @Override |
public void attach() { | public void attach() { | ||||
super.attach(); | super.attach(); | ||||
attachDataProviderListener(); | attachDataProviderListener(); | ||||
if (getPushRows().isEmpty()) { | |||||
// Make sure rows are pushed when component is attached. | |||||
setPushRows(Range.withLength(0, getMinPushSize())); | |||||
} | |||||
} | } | ||||
@Override | @Override | ||||
public void beforeClientResponse(boolean initial) { | public void beforeClientResponse(boolean initial) { | ||||
super.beforeClientResponse(initial); | super.beforeClientResponse(initial); | ||||
if (initial && getPushRows().isEmpty()) { | |||||
// Make sure rows are pushed when component is attached. | |||||
setPushRows(Range.withLength(0, getMinPushSize())); | |||||
} | |||||
sendDataToClient(initial); | sendDataToClient(initial); | ||||
} | } | ||||
.forEach(this::addColumn); | .forEach(this::addColumn); | ||||
} | } | ||||
@Override | |||||
public void beforeClientResponse(boolean initial) { | |||||
super.beforeClientResponse(initial); | |||||
if (initial && editor.isOpen()) { | |||||
// Re-attaching grid. Any old editor should be closed. | |||||
editor.cancel(); | |||||
} | |||||
} | |||||
/** | /** | ||||
* Sets the property set to use for this grid. Does not create or update | * Sets the property set to use for this grid. Does not create or update | ||||
* columns in any way but will delete and re-create the editor. | * columns in any way but will delete and re-create the editor. | ||||
column.updateSortable(); | column.updateSortable(); | ||||
} | } | ||||
} | } | ||||
@Override | |||||
public void setVisible(boolean visible) { | |||||
if (getEditor().isOpen() && !visible) { | |||||
getEditor().cancel(); | |||||
} | |||||
super.setVisible(visible); | |||||
} | |||||
@Override | |||||
public void detach() { | |||||
if (getEditor().isOpen()) { | |||||
getEditor().cancel(); | |||||
} | |||||
super.detach(); | |||||
} | |||||
} | } |
*/ | */ | ||||
private void setSelected(Component component) { | private void setSelected(Component component) { | ||||
Tab tab = tabs.get(selected); | Tab tab = tabs.get(selected); | ||||
if (tab != null && !Objects.equals(tab.getComponent(), component) | |||||
&& tab.getComponent() != null | |||||
&& tab.getComponent().isAttached()) { | |||||
tab.getComponent().detach(); | |||||
tab.getComponent().attach(); // ugly hack | |||||
} | |||||
selected = component; | selected = component; | ||||
// Repaint of the selected component is needed as only the selected | // Repaint of the selected component is needed as only the selected |
/** | /** | ||||
* Used to execute data generation | * Used to execute data generation | ||||
* | |||||
* @param initial | |||||
* {@code true} to mock initial data request; {@code false} | |||||
* for follow-up request. | |||||
*/ | */ | ||||
public void runDataGeneration() { | |||||
super.getDataCommunicator().beforeClientResponse(true); | |||||
public void runDataGeneration(boolean initial) { | |||||
super.getDataCommunicator().beforeClientResponse(initial); | |||||
} | } | ||||
@Override | @Override | ||||
CountGenerator generator = new CountGenerator(); | CountGenerator generator = new CountGenerator(); | ||||
generator.extend(listing); | generator.extend(listing); | ||||
listing.setItems("Foo"); | listing.setItems("Foo"); | ||||
listing.runDataGeneration(); | |||||
listing.runDataGeneration(true); | |||||
assertEquals("Generator should have been called once", 1, | assertEquals("Generator should have been called once", 1, | ||||
generator.callCount); | generator.callCount); | ||||
} | } | ||||
CountGenerator generator = new CountGenerator(); | CountGenerator generator = new CountGenerator(); | ||||
listing.setItems("Foo"); | listing.setItems("Foo"); | ||||
generator.extend(listing); | generator.extend(listing); | ||||
listing.runDataGeneration(); | |||||
listing.runDataGeneration(true); | |||||
assertEquals("Generator should have been called once", 1, | assertEquals("Generator should have been called once", 1, | ||||
generator.callCount); | generator.callCount); | ||||
} | } | ||||
listing.setItems("Foo"); | listing.setItems("Foo"); | ||||
CountGenerator generator = new CountGenerator(); | CountGenerator generator = new CountGenerator(); | ||||
generator.extend(listing); | generator.extend(listing); | ||||
listing.runDataGeneration(); | |||||
listing.runDataGeneration(true); | |||||
assertEquals("Generator should have been called once", 1, | assertEquals("Generator should have been called once", 1, | ||||
generator.callCount); | generator.callCount); | ||||
listing.runDataGeneration(); | |||||
listing.runDataGeneration(false); | |||||
assertEquals("Generator should not have been called again", 1, | assertEquals("Generator should not have been called again", 1, | ||||
generator.callCount); | generator.callCount); | ||||
} | } | ||||
CountGenerator generator = new CountGenerator(); | CountGenerator generator = new CountGenerator(); | ||||
generator.extend(listing); | generator.extend(listing); | ||||
generator.remove(); | generator.remove(); | ||||
listing.runDataGeneration(); | |||||
listing.runDataGeneration(true); | |||||
assertEquals("Generator should not have been called", 0, | assertEquals("Generator should not have been called", 0, | ||||
generator.callCount); | generator.callCount); | ||||
} | } | ||||
listing.setItems("Foo"); | listing.setItems("Foo"); | ||||
CountGenerator generator = new CountGenerator(); | CountGenerator generator = new CountGenerator(); | ||||
generator.extend(listing); | generator.extend(listing); | ||||
listing.runDataGeneration(); | |||||
listing.runDataGeneration(true); | |||||
assertEquals("Generator should have been called once", 1, | assertEquals("Generator should have been called once", 1, | ||||
generator.callCount); | generator.callCount); | ||||
generator.refresh("Foo"); | generator.refresh("Foo"); | ||||
listing.runDataGeneration(); | |||||
listing.runDataGeneration(false); | |||||
assertEquals("Generator should have been called again", 2, | assertEquals("Generator should have been called again", 2, | ||||
generator.callCount); | generator.callCount); | ||||
} | } |
import com.vaadin.annotations.Widgetset; | import com.vaadin.annotations.Widgetset; | ||||
import com.vaadin.data.ValueProvider; | import com.vaadin.data.ValueProvider; | ||||
import com.vaadin.data.converter.StringToIntegerConverter; | |||||
import com.vaadin.data.provider.DataProvider; | import com.vaadin.data.provider.DataProvider; | ||||
import com.vaadin.data.provider.ListDataProvider; | import com.vaadin.data.provider.ListDataProvider; | ||||
import com.vaadin.server.VaadinRequest; | import com.vaadin.server.VaadinRequest; | ||||
import com.vaadin.ui.Grid.SelectionMode; | import com.vaadin.ui.Grid.SelectionMode; | ||||
import com.vaadin.ui.Label; | import com.vaadin.ui.Label; | ||||
import com.vaadin.ui.TabSheet; | import com.vaadin.ui.TabSheet; | ||||
import com.vaadin.ui.TextField; | |||||
import com.vaadin.ui.renderers.NumberRenderer; | import com.vaadin.ui.renderers.NumberRenderer; | ||||
@Widgetset("com.vaadin.DefaultWidgetSet") | @Widgetset("com.vaadin.DefaultWidgetSet") | ||||
final Grid<Integer> grid = new Grid<>(); | final Grid<Integer> grid = new Grid<>(); | ||||
grid.setSelectionMode(SelectionMode.MULTI); | grid.setSelectionMode(SelectionMode.MULTI); | ||||
grid.addColumn(ValueProvider.identity(), new NumberRenderer()) | grid.addColumn(ValueProvider.identity(), new NumberRenderer()) | ||||
.setId("count"); | |||||
.setId("count").setEditorBinding( | |||||
grid.getEditor().getBinder().forField(new TextField()) | |||||
.withConverter(new StringToIntegerConverter("")) | |||||
.bind(i -> i, (i, v) -> { | |||||
})); | |||||
grid.getEditor().setEnabled(true); | |||||
LinkedList<Integer> items = IntStream.range(0, 3).boxed() | LinkedList<Integer> items = IntStream.range(0, 3).boxed() | ||||
.collect(Collectors.toCollection(LinkedList::new)); | .collect(Collectors.toCollection(LinkedList::new)); |
import static org.junit.Assert.assertEquals; | import static org.junit.Assert.assertEquals; | ||||
import static org.junit.Assert.assertFalse; | import static org.junit.Assert.assertFalse; | ||||
import static org.junit.Assert.assertNotEquals; | |||||
import static org.junit.Assert.assertTrue; | import static org.junit.Assert.assertTrue; | ||||
import org.junit.Test; | import org.junit.Test; | ||||
import org.openqa.selenium.Keys; | |||||
import com.vaadin.testbench.By; | |||||
import com.vaadin.testbench.elements.ButtonElement; | import com.vaadin.testbench.elements.ButtonElement; | ||||
import com.vaadin.testbench.elements.GridElement; | import com.vaadin.testbench.elements.GridElement; | ||||
import com.vaadin.testbench.elements.NotificationElement; | import com.vaadin.testbench.elements.NotificationElement; | ||||
assertNoNotification(); | assertNoNotification(); | ||||
} | } | ||||
@Test | |||||
public void testEditorOpenWhenSwitchingTab() { | |||||
setDebug(true); | |||||
openTestURL(); | |||||
GridElement grid = $(GridElement.class).first(); | |||||
grid.getCell(0, 1).doubleClick(); | |||||
assertEquals("Editor should be open", "0", | |||||
grid.getEditor().getField(1).getAttribute("value")); | |||||
TabSheetElement tabsheet = $(TabSheetElement.class).first(); | |||||
tabsheet.openTab("Label"); | |||||
tabsheet.openTab("Grid"); | |||||
grid = $(GridElement.class).first(); | |||||
assertFalse("Editor should be closed.", | |||||
grid.isElementPresent(By.vaadin("#editor"))); | |||||
grid.getCell(1, 1).doubleClick(); | |||||
assertEquals("Editor should open after tab switch", "1", | |||||
grid.getEditor().getField(1).getAttribute("value")); | |||||
// Close the current editor and reopen on a different row | |||||
grid.sendKeys(Keys.ESCAPE); | |||||
grid.getCell(0, 1).doubleClick(); | |||||
assertEquals("Editor should move", "0", | |||||
grid.getEditor().getField(1).getAttribute("value")); | |||||
assertNoErrorNotifications(); | |||||
} | |||||
private void removeGridRow() { | private void removeGridRow() { | ||||
$(ButtonElement.class).caption("Remove row from Grid").first().click(); | $(ButtonElement.class).caption("Remove row from Grid").first().click(); | ||||
} | } |