numberOfItems);
fireEvent(new DataAvailableEvent(currentDataAvailable));
}
+
+ @Override
+ public void resetDataAndSize(int newSize) {
+ RowContainer body = escalator.getBody();
+
+ /*
+ * Because the data has simply changed and we don't really know
+ * what, we'll simply remove everything and redraw everything.
+ */
+
+ double prevScroll = escalator.getScrollTop();
+ body.removeRows(0, body.getRowCount());
+ body.insertRows(0, newSize);
+
+ /*
+ * If data was removed or inserted above the scroll top, the
+ * scroll position is kept locked, leading to data
+ * "sliding under us". But we can't do anything about that,
+ * since simply _something_ happened.
+ */
+ escalator.setScrollTop(prevScroll);
+ }
});
int previousRowCount = escalator.getBody().getRowCount();
private final ActiveRowHandler activeRowHandler = new ActiveRowHandler();
+ private DataProviderRpc rpc;
+
private final ItemSetChangeListener itemListener = new ItemSetChangeListener() {
@Override
public void containerItemSetChange(ItemSetChangeEvent event) {
}
else {
- Range visibleRows = activeRowHandler.activeRange;
- List<?> itemIds = container.getItemIds(visibleRows.getStart(),
- visibleRows.length());
- keyMapper.removeActiveRows(keyMapper.activeRange);
- keyMapper.addActiveRows(visibleRows, visibleRows.getStart(),
- itemIds);
+ /*
+ * Clear everything we have in view, and let the client
+ * re-request for whatever it needs.
+ *
+ * Why this shortcut? Well, since anything could've happened, we
+ * don't know what has happened. There are a lot of use-cases we
+ * can cover at once with this carte blanche operation:
+ *
+ * 1) Grid is scrolled somewhere in the middle and all the
+ * rows-inview are removed. We need a new pageful.
+ *
+ * 2) Grid is scrolled somewhere in the middle and none of the
+ * visible rows are removed. We need no new rows.
+ *
+ * 3) Grid is scrolled all the way to the bottom, and the last
+ * rows are being removed. Grid needs to scroll up and request
+ * for more rows at the top.
+ *
+ * 4) Grid is scrolled pretty much to the bottom, and the last
+ * rows are being removed. Grid needs to be aware that some
+ * scrolling is needed, but not to compensate for all the
+ * removed rows. And it also needs to request for some more rows
+ * to the top.
+ *
+ * 5) Some ranges of rows are removed from view. We need to
+ * collapse the gaps with existing rows and load the missing
+ * rows.
+ *
+ * 6) The ultimate use case! Grid has 1.5 pages of rows and
+ * scrolled a bit down. One page of rows is removed. We need to
+ * make sure that new rows are loaded, but not all old slots are
+ * occupied, since the page can't be filled with new row data.
+ * It also needs to be scrolled to the top.
+ *
+ * So, it's easier (and safer) to do the simple thing instead of
+ * taking all the corner cases into account.
+ */
- pushRows(visibleRows.getStart(), itemIds);
- activeRowHandler.setActiveRows(visibleRows.getStart(),
- visibleRows.length());
+ activeRowHandler.activeRange = Range.withLength(0, 0);
+ activeRowHandler.valueChangeListeners.clear();
+ rpc.resetDataAndSize(event.getContainer().size());
+ getState().containerSize = event.getContainer().size();
}
}
};
*/
public RpcDataProviderExtension(Indexed container) {
this.container = container;
+ rpc = getRpcProxy(DataProviderRpc.class);
registerRpc(new DataRequestRpc() {
private Collection<String> allTemporarilyPinnedKeys = new ArrayList<String>();
for (int i = 0; i < itemIds.size(); ++i) {
rows.set(i, getRowData(propertyIds, itemIds.get(i)));
}
- getRpcProxy(DataProviderRpc.class).setRowData(firstRow, rows.toJson());
+ rpc.setRowData(firstRow, rows.toJson());
}
private JsonValue getRowData(Collection<?> propertyIds, Object itemId) {
*/
private void insertRowData(int index, int count) {
getState().containerSize += count;
- getRpcProxy(DataProviderRpc.class).insertRowData(index, count);
+ rpc.insertRowData(index, count);
activeRowHandler.insertRows(index, count);
}
*/
private void removeRowData(int firstIndex, int count) {
getState().containerSize -= count;
- getRpcProxy(DataProviderRpc.class).removeRowData(firstIndex, count);
+ rpc.removeRowData(firstIndex, count);
for (int i = 0; i < count; i++) {
Object itemId = keyMapper.itemIdAtIndex(firstIndex + i);
JsonValue row = getRowData(container.getContainerPropertyIds(), itemId);
JsonArray rowArray = Json.createArray();
rowArray.set(0, row);
- getRpcProxy(DataProviderRpc.class).setRowData(index, rowArray.toJson());
+ rpc.setRowData(index, rowArray.toJson());
}
@Override
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import java.util.List;
import org.junit.Test;
import org.openqa.selenium.By;
+import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebElement;
import com.vaadin.testbench.TestBenchElement;
+import com.vaadin.tests.components.grid.GridElement.GridCellElement;
import com.vaadin.testbench.elements.NotificationElement;
import com.vaadin.tests.components.grid.GridElement;
import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeatures;
assertTrue(verticalScrollbarIsPresent());
}
+ @Test
+ public void testBareItemSetChange() throws Exception {
+ openTestURL();
+
+ selectMenuPath("Component", "Filter", "Column 1 starts with \"(23\"");
+
+ boolean foundElements = false;
+ for (int row = 0; row < 100; row++) {
+ try {
+ GridCellElement cell = getGridElement().getCell(row, 1);
+ foundElements = true;
+ assertTrue("Unexpected cell contents. "
+ + "Did the ItemSetChange work after all?", cell
+ .getText().startsWith("(23"));
+ } catch (NoSuchElementException e) {
+ assertTrue("No rows were found", foundElements);
+ return;
+ }
+ }
+ fail("unexpected amount of rows post-filter. Did the ItemSetChange work after all?");
+ }
+
+
@Test
public void testRemoveLastColumn() {
setDebug(true);