summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java26
-rw-r--r--client/src/com/vaadin/client/data/AbstractRemoteDataSource.java136
-rw-r--r--client/src/com/vaadin/client/ui/grid/Escalator.java10
-rw-r--r--client/src/com/vaadin/client/ui/grid/Grid.java22
-rw-r--r--server/src/com/vaadin/data/RpcDataProviderExtension.java65
-rw-r--r--shared/src/com/vaadin/shared/data/DataProviderState.java32
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorRowTest.java4
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStaticSectionComponentTest.java4
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientDataSourcesWidget.java52
9 files changed, 219 insertions, 132 deletions
diff --git a/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java b/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java
index c9a01c0c5e..5f8a06ca10 100644
--- a/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java
+++ b/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java
@@ -27,7 +27,6 @@ import com.vaadin.client.ServerConnector;
import com.vaadin.client.data.AbstractRemoteDataSource;
import com.vaadin.client.extensions.AbstractExtensionConnector;
import com.vaadin.shared.data.DataProviderRpc;
-import com.vaadin.shared.data.DataProviderState;
import com.vaadin.shared.data.DataRequestRpc;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.grid.GridState;
@@ -89,7 +88,20 @@ public class RpcDataSourceConnector extends AbstractExtensionConnector {
private DataRequestRpc rpcProxy = getRpcProxy(DataRequestRpc.class);
@Override
- protected void requestRows(int firstRowIndex, int numberOfRows) {
+ protected void requestRows(int firstRowIndex, int numberOfRows,
+ RequestRowsCallback<JSONObject> callback) {
+ /*
+ * If you're looking at this code because you want to learn how to
+ * use AbstactRemoteDataSource, please look somewhere else instead.
+ *
+ * We're not doing things in the conventional way with the callback
+ * here since Vaadin doesn't directly support RPC with return
+ * values. We're instead asking the server to push us some data, and
+ * when we receive pushed data, we just push it along to the
+ * underlying cache in the same way no matter if it was a genuine
+ * push or just a result of us requesting rows.
+ */
+
Range cached = getCachedRange();
rpcProxy.requestRows(firstRowIndex, numberOfRows,
@@ -113,11 +125,6 @@ public class RpcDataSourceConnector extends AbstractExtensionConnector {
}
@Override
- public int size() {
- return getState().containerSize;
- }
-
- @Override
protected void pinHandle(RowHandleImpl handle) {
// Server only knows if something is pinned or not. No need to pin
// multiple times.
@@ -146,9 +153,4 @@ public class RpcDataSourceConnector extends AbstractExtensionConnector {
protected void extend(ServerConnector target) {
((GridConnector) target).setDataSource(dataSource);
}
-
- @Override
- public DataProviderState getState() {
- return (DataProviderState) super.getState();
- }
}
diff --git a/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java b/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java
index 7546ac6054..26b60bd2ae 100644
--- a/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java
+++ b/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java
@@ -32,10 +32,8 @@ import com.vaadin.shared.ui.grid.Range;
* Base implementation for data sources that fetch data from a remote system.
* This class takes care of caching data and communicating with the data source
* user. An implementation of this class should override
- * {@link #requestRows(int, int)} to trigger asynchronously loading of data.
- * When data is received from the server, new row data should be passed to
- * {@link #setRowData(int, List)}. {@link #setEstimatedSize(int)} should be used
- * based on estimations of how many rows are available.
+ * {@link #requestRows(int, int, RequestRowsCallback)} to trigger asynchronously
+ * loading of data and then pass the loaded data into the provided callback.
*
* @since
* @author Vaadin Ltd
@@ -44,6 +42,60 @@ import com.vaadin.shared.ui.grid.Range;
*/
public abstract class AbstractRemoteDataSource<T> implements DataSource<T> {
+ /**
+ * Callback used by
+ * {@link AbstractRemoteDataSource#requestRows(int, int, RequestRowsCallback)}
+ * to pass data to the underlying implementation when data has been fetched.
+ */
+ public static class RequestRowsCallback<T> {
+ private final Range requestedRange;
+ private final double requestStart;
+ private final AbstractRemoteDataSource<T> source;
+
+ /**
+ * Creates a new callback
+ *
+ * @param source
+ * the data source for which the request is made
+ * @param requestedRange
+ * the requested row range
+ */
+ protected RequestRowsCallback(AbstractRemoteDataSource<T> source,
+ Range requestedRange) {
+ this.source = source;
+ this.requestedRange = requestedRange;
+
+ requestStart = Duration.currentTimeMillis();
+ }
+
+ /**
+ * Called by the
+ * {@link AbstractRemoteDataSource#requestRows(int, int, RequestRowsCallback)}
+ * implementation when data has been received.
+ *
+ * @param rowData
+ * a list of row objects starting at the requested offset
+ * @param totalSize
+ * the total number of rows available at the remote end
+ */
+ public void onResponse(List<T> rowData, int totalSize) {
+ if (source.size != totalSize) {
+ source.resetDataAndSize(totalSize);
+ }
+ source.setRowData(requestedRange.getStart(), rowData);
+ }
+
+ /**
+ * Gets the range of rows that was requested.
+ *
+ * @return the requsted row range
+ */
+ public Range getRequestedRange() {
+ return requestedRange;
+ }
+
+ }
+
protected class RowHandleImpl extends RowHandle<T> {
private T row;
private final Object key;
@@ -120,13 +172,7 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> {
}
}
- /**
- * Records the start of the previously requested range. This is used when
- * tracking request timings to distinguish between explicit responses and
- * arbitrary updates pushed from the server.
- */
- private int lastRequestStart = -1;
- private double pendingRequestTime;
+ private RequestRowsCallback<T> currentRequestCallback;
private boolean coverageCheckPending = false;
@@ -153,6 +199,9 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> {
private Map<Object, RowHandleImpl> pinnedRows = new HashMap<Object, RowHandleImpl>();
protected Collection<T> temporarilyPinnedRows = Collections.emptySet();
+ // Size not yet known
+ private int size = -1;
+
private void ensureCoverageCheck() {
if (!coverageCheckPending) {
coverageCheckPending = true;
@@ -214,8 +263,9 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> {
}
private void checkCacheCoverage() {
- if (lastRequestStart != -1) {
- // Anyone clearing lastRequestStart should run this method again
+ if (currentRequestCallback != null) {
+ // Anyone clearing currentRequestCallback should run this method
+ // again
return;
}
@@ -269,22 +319,23 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> {
if (range.isEmpty()) {
return;
}
- lastRequestStart = range.getStart();
- pendingRequestTime = Duration.currentTimeMillis();
- requestRows(range.getStart(), range.length());
+ currentRequestCallback = new RequestRowsCallback<T>(this, range);
+ requestRows(range.getStart(), range.length(), currentRequestCallback);
}
/**
- * Triggers fetching rows from the remote data source.
- * {@link #setRowData(int, List)} should be invoked with data for the
- * requested rows when they have been received.
+ * Triggers fetching rows from the remote data source. The provided callback
+ * should be informed when the requested rows have been received.
*
* @param firstRowIndex
* the index of the first row to fetch
* @param numberOfRows
* the number of rows to fetch
+ * @param callback
+ * callback to inform when the requested rows are available
*/
- protected abstract void requestRows(int firstRowIndex, int numberOfRows);
+ protected abstract void requestRows(int firstRowIndex, int numberOfRows,
+ RequestRowsCallback<T> callback);
@Override
public T getRow(int rowIndex) {
@@ -321,16 +372,18 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> {
*/
protected void setRowData(int firstRowIndex, List<T> rowData) {
+ assert firstRowIndex + rowData.size() <= size();
+
Profiler.enter("AbstractRemoteDataSource.setRowData");
Range received = Range.withLength(firstRowIndex, rowData.size());
- if (firstRowIndex == lastRequestStart) {
- // Provide timing information if we know when we asked for this data
+ if (currentRequestCallback != null) {
cacheStrategy.onDataArrive(Duration.currentTimeMillis()
- - pendingRequestTime, received.length());
+ - currentRequestCallback.requestStart, received.length());
+
+ currentRequestCallback = null;
}
- lastRequestStart = -1;
Range maxCacheRange = getMaxCacheRange();
@@ -411,6 +464,8 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> {
protected void removeRowData(int firstRowIndex, int count) {
Profiler.enter("AbstractRemoteDataSource.removeRowData");
+ size -= count;
+
// shift indices to fill the cache correctly
for (int i = firstRowIndex + count; i < cached.getEnd(); i++) {
moveRowFromIndexToIndex(i, i - count);
@@ -445,6 +500,8 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> {
protected void insertRowData(int firstRowIndex, int count) {
Profiler.enter("AbstractRemoteDataSource.insertRowData");
+ size += count;
+
if (cached.contains(firstRowIndex)) {
int oldCacheEnd = cached.getEnd();
/*
@@ -523,7 +580,7 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> {
}
private Range getMinCacheRange() {
- Range availableDataRange = Range.withLength(0, size());
+ Range availableDataRange = getAvailableRangeForCache();
Range minCacheRange = cacheStrategy.getMinCacheRange(
requestedAvailability, cached, availableDataRange);
@@ -533,7 +590,7 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> {
}
private Range getMaxCacheRange() {
- Range availableDataRange = Range.withLength(0, size());
+ Range availableDataRange = getAvailableRangeForCache();
Range maxCacheRange = cacheStrategy.getMaxCacheRange(
requestedAvailability, cached, availableDataRange);
@@ -542,6 +599,14 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> {
return maxCacheRange;
}
+ private Range getAvailableRangeForCache() {
+ int upperBound = size();
+ if (upperBound == -1) {
+ upperBound = requestedAvailability.length();
+ }
+ return Range.withLength(0, upperBound);
+ }
+
@Override
public RowHandle<T> getHandle(T row) throws IllegalStateException {
Object key = getRowKey(row);
@@ -584,7 +649,26 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> {
*/
abstract public Object getRowKey(T row);
+ @Override
+ public int size() {
+ return size;
+ }
+
+ /**
+ * Updates the size, discarding all cached data. This method is used when
+ * the size of the container is changed without any information about the
+ * structure of the change. In this case, all cached data is discarded to
+ * avoid cache offset issues.
+ * <p>
+ * If you have information about the structure of the change, use
+ * {@link #insertRowData(int, int)} or {@link #removeRowData(int, int)} to
+ * indicate where the inserted or removed rows are located.
+ *
+ * @param newSize
+ * the new size of the container
+ */
protected void resetDataAndSize(int newSize) {
+ size = newSize;
dropFromCache(getCachedRange());
cached = Range.withLength(0, 0);
assertDataChangeHandlerIsInjected();
diff --git a/client/src/com/vaadin/client/ui/grid/Escalator.java b/client/src/com/vaadin/client/ui/grid/Escalator.java
index deb80b9e00..1bbcaaf166 100644
--- a/client/src/com/vaadin/client/ui/grid/Escalator.java
+++ b/client/src/com/vaadin/client/ui/grid/Escalator.java
@@ -5047,4 +5047,14 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
Scheduler.get().scheduleDeferred(layoutCommand);
}
}
+
+ /**
+ * Gets the maximum number of body rows that can be visible on the screen at
+ * once.
+ *
+ * @return the maximum capacity
+ */
+ public int getMaxVisibleRowCount() {
+ return body.getMaxEscalatorRowCapacity();
+ }
}
diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java
index 2ebe1b62a3..91d796692c 100644
--- a/client/src/com/vaadin/client/ui/grid/Grid.java
+++ b/client/src/com/vaadin/client/ui/grid/Grid.java
@@ -2934,7 +2934,7 @@ public class Grid<T> extends ResizeComposite implements
@Override
public void onRowVisibilityChange(
RowVisibilityChangeEvent event) {
- if (dataSource != null && dataSource.size() > 0) {
+ if (dataSource != null && dataSource.size() != 0) {
dataIsBeingFetched = true;
dataSource.ensureAvailability(
event.getFirstVisibleRow(),
@@ -3661,7 +3661,18 @@ public class Grid<T> extends ResizeComposite implements
escalator.getBody().removeRows(0, previousRowCount);
}
+ setEscalatorSizeFromDataSource();
+ }
+
+ private void setEscalatorSizeFromDataSource() {
+ assert escalator.getBody().getRowCount() == 0;
+
int size = dataSource.size();
+ if (size == -1 && isAttached()) {
+ // Exact size is not yet known, start with some reasonable guess
+ // just to get an initial backend request going
+ size = getEscalator().getMaxVisibleRowCount();
+ }
if (size > 0) {
escalator.getBody().insertRows(0, size);
}
@@ -5075,4 +5086,13 @@ public class Grid<T> extends ResizeComposite implements
public Widget getEditorRowWidget(GridColumn<?, T> column) {
return editorRow.getWidget(column);
}
+
+ @Override
+ protected void onAttach() {
+ super.onAttach();
+
+ if (getEscalator().getBody().getRowCount() == 0 && dataSource != null) {
+ setEscalatorSizeFromDataSource();
+ }
+ }
}
diff --git a/server/src/com/vaadin/data/RpcDataProviderExtension.java b/server/src/com/vaadin/data/RpcDataProviderExtension.java
index 9f7c783537..f28d95f610 100644
--- a/server/src/com/vaadin/data/RpcDataProviderExtension.java
+++ b/server/src/com/vaadin/data/RpcDataProviderExtension.java
@@ -45,7 +45,6 @@ import com.vaadin.server.AbstractExtension;
import com.vaadin.server.ClientConnector;
import com.vaadin.server.KeyMapper;
import com.vaadin.shared.data.DataProviderRpc;
-import com.vaadin.shared.data.DataProviderState;
import com.vaadin.shared.data.DataRequestRpc;
import com.vaadin.shared.ui.grid.GridState;
import com.vaadin.shared.ui.grid.Range;
@@ -638,7 +637,6 @@ public class RpcDataProviderExtension extends AbstractExtension {
activeRowHandler.activeRange = Range.withLength(0, 0);
activeRowHandler.valueChangeListeners.clear();
rpc.resetDataAndSize(event.getContainer().size());
- getState().containerSize = event.getContainer().size();
}
}
};
@@ -665,20 +663,8 @@ public class RpcDataProviderExtension extends AbstractExtension {
public void requestRows(int firstRow, int numberOfRows,
int firstCachedRowIndex, int cacheSize) {
- Range active = Range.withLength(firstRow, numberOfRows);
- if (cacheSize != 0) {
- Range cached = Range.withLength(firstCachedRowIndex,
- cacheSize);
- active = active.combineWith(cached);
- }
-
- List<?> itemIds = RpcDataProviderExtension.this.container
- .getItemIds(firstRow, numberOfRows);
- keyMapper.preActiveRowsChange(active, firstRow, itemIds);
- pushRows(firstRow, itemIds);
-
- activeRowHandler.setActiveRows(active.getStart(),
- active.length());
+ pushRowData(firstRow, numberOfRows, firstCachedRowIndex,
+ cacheSize);
}
@Override
@@ -696,8 +682,6 @@ public class RpcDataProviderExtension extends AbstractExtension {
}
});
- getState().containerSize = container.size();
-
if (container instanceof ItemSetChangeNotifier) {
((ItemSetChangeNotifier) container)
.addItemSetChangeListener(itemListener);
@@ -708,15 +692,43 @@ public class RpcDataProviderExtension extends AbstractExtension {
@Override
public void beforeClientResponse(boolean initial) {
super.beforeClientResponse(initial);
- clientInitialized = true;
+ if (!clientInitialized) {
+ clientInitialized = true;
+
+ /*
+ * Push initial set of rows, assuming Grid will initially be
+ * rendered scrolled to the top and with a decent amount of rows
+ * visible. If this guess is right, initial data can be shown
+ * without a round-trip and if it's wrong, the data will simply be
+ * discarded.
+ */
+ int size = container.size();
+ rpc.resetDataAndSize(size);
+
+ int numberOfRows = Math.min(40, size);
+ pushRowData(0, numberOfRows, 0, 0);
+ }
}
- private void pushRows(int firstRow, List<?> itemIds) {
+ private void pushRowData(int firstRowToPush, int numberOfRows,
+ int firstCachedRowIndex, int cacheSize) {
+ Range active = Range.withLength(firstRowToPush, numberOfRows);
+ if (cacheSize != 0) {
+ Range cached = Range.withLength(firstCachedRowIndex, cacheSize);
+ active = active.combineWith(cached);
+ }
+
+ List<?> itemIds = RpcDataProviderExtension.this.container.getItemIds(
+ firstRowToPush, numberOfRows);
+ keyMapper.preActiveRowsChange(active, firstRowToPush, itemIds);
+
JsonArray rows = Json.createArray();
for (int i = 0; i < itemIds.size(); ++i) {
rows.set(i, getRowData(getGrid().getColumns(), itemIds.get(i)));
}
- rpc.setRowData(firstRow, rows.toJson());
+ rpc.setRowData(firstRowToPush, rows.toJson());
+
+ activeRowHandler.setActiveRows(active.getStart(), active.length());
}
private JsonValue getRowData(Collection<Column> columns, Object itemId) {
@@ -776,11 +788,6 @@ public class RpcDataProviderExtension extends AbstractExtension {
}
}
- @Override
- protected DataProviderState getState() {
- return (DataProviderState) super.getState();
- }
-
/**
* Makes the data source available to the given {@link Grid} component.
*
@@ -802,7 +809,6 @@ public class RpcDataProviderExtension extends AbstractExtension {
* the number of rows inserted at <code>index</code>
*/
private void insertRowData(int index, int count) {
- getState().containerSize += count;
if (clientInitialized) {
rpc.insertRowData(index, count);
}
@@ -821,7 +827,6 @@ public class RpcDataProviderExtension extends AbstractExtension {
* the item id of the first removed item
*/
private void removeRowData(int firstIndex, int count) {
- getState().containerSize -= count;
if (clientInitialized) {
rpc.removeRowData(firstIndex, count);
}
@@ -864,9 +869,7 @@ public class RpcDataProviderExtension extends AbstractExtension {
int firstRow = activeRowHandler.activeRange.getStart();
int numberOfRows = activeRowHandler.activeRange.length();
- List<?> itemIds = RpcDataProviderExtension.this.container.getItemIds(
- firstRow, numberOfRows);
- pushRows(firstRow, itemIds);
+ pushRowData(firstRow, numberOfRows, firstRow, numberOfRows);
}
@Override
diff --git a/shared/src/com/vaadin/shared/data/DataProviderState.java b/shared/src/com/vaadin/shared/data/DataProviderState.java
deleted file mode 100644
index 76d68e8352..0000000000
--- a/shared/src/com/vaadin/shared/data/DataProviderState.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2000-2014 Vaadin Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.vaadin.shared.data;
-
-import com.vaadin.shared.communication.SharedState;
-
-/**
- * Shared state used by client-side data sources.
- *
- * @since
- * @author Vaadin Ltd
- */
-public class DataProviderState extends SharedState {
- /**
- * The size of the container.
- */
- public int containerSize;
-}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorRowTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorRowTest.java
index 7f3d4ff325..d649e4a97c 100644
--- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorRowTest.java
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorRowTest.java
@@ -55,7 +55,7 @@ public class GridEditorRowTest extends GridBasicFeaturesTest {
selectMenuPath("Component", "Editor row", "Edit item 5");
assertNull(getEditorRow());
assertEquals(
- "4. Exception occured, java.lang.IllegalStateExceptionEditor row is not enabled",
+ "5. Exception occured, java.lang.IllegalStateExceptionEditor row is not enabled",
getLogRow(0));
}
@@ -65,7 +65,7 @@ public class GridEditorRowTest extends GridBasicFeaturesTest {
selectMenuPath("Component", "Editor row", "Enabled");
assertNotNull(getEditorRow());
assertEquals(
- "4. Exception occured, java.lang.IllegalStateExceptionCannot disable the editor row while an item (5) is being edited.",
+ "5. Exception occured, java.lang.IllegalStateExceptionCannot disable the editor row while an item (5) is being edited.",
getLogRow(0));
}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStaticSectionComponentTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStaticSectionComponentTest.java
index 21bf667bae..76382da035 100644
--- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStaticSectionComponentTest.java
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStaticSectionComponentTest.java
@@ -35,7 +35,7 @@ public class GridStaticSectionComponentTest extends GridBasicFeaturesTest {
getGridElement().$(ButtonElement.class).first().click();
- assertEquals("2. Button clicked!", getLogRow(0));
+ assertEquals("3. Button clicked!", getLogRow(0));
}
@Test
@@ -49,6 +49,6 @@ public class GridStaticSectionComponentTest extends GridBasicFeaturesTest {
getGridElement().$(ButtonElement.class).first().click();
- assertEquals("4. Button clicked!", getLogRow(0));
+ assertEquals("5. Button clicked!", getLogRow(0));
}
}
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientDataSourcesWidget.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientDataSourcesWidget.java
index 76a146bfd2..aca11cfab3 100644
--- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientDataSourcesWidget.java
+++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientDataSourcesWidget.java
@@ -18,6 +18,7 @@ package com.vaadin.tests.widgetset.client.grid;
import java.util.ArrayList;
import java.util.List;
+import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.vaadin.client.data.AbstractRemoteDataSource;
import com.vaadin.client.ui.grid.Grid;
@@ -28,6 +29,10 @@ import com.vaadin.client.ui.grid.renderers.TextRenderer;
public class GridClientDataSourcesWidget extends
PureGWTTestApplication<Grid<String[]>> {
+ private interface RestCallback {
+ void onResponse(RestishDataSource.Backend.Result result);
+ }
+
/**
* This is an emulated datasource that has a back-end that changes size
* constantly. The back-end is unable to actively push data to Grid.
@@ -66,8 +71,6 @@ public class GridClientDataSourcesWidget extends
* </ol>
*/
private class RestishDataSource extends AbstractRemoteDataSource<String[]> {
- private int currentSize = 0;
-
/**
* Pretend like this class doesn't exist. It just simulates a backend
* somewhere.
@@ -83,14 +86,22 @@ public class GridClientDataSourcesWidget extends
private int size = 200;
private int modCount = 0;
- public Result query(int firstRowIndex, int numberOfRows) {
- Result result = new Result();
+ public void query(int firstRowIndex, int numberOfRows,
+ final RestCallback callback) {
+ final Result result = new Result();
result.size = size;
- result.rows = getRows(firstRowIndex, numberOfRows);
- return result;
+ result.rows = fetchRows(firstRowIndex, numberOfRows);
+
+ Scheduler.get().scheduleDeferred(new ScheduledCommand() {
+ @Override
+ public void execute() {
+ callback.onResponse(result);
+ }
+ });
+
}
- private List<String[]> getRows(int firstRowIndex, int numberOfRows) {
+ private List<String[]> fetchRows(int firstRowIndex, int numberOfRows) {
List<String[]> rows = new ArrayList<String[]>();
for (int i = 0; i < numberOfRows; i++) {
String id = String.valueOf(firstRowIndex + i);
@@ -121,29 +132,18 @@ public class GridClientDataSourcesWidget extends
public RestishDataSource() {
backend = new Backend();
- currentSize = backend.size;
- }
-
- @Override
- public int size() {
- return currentSize;
}
@Override
- protected void requestRows(int firstRowIndex, int numberOfRows) {
- Backend.Result result = backend.query(firstRowIndex, numberOfRows);
- final List<String[]> newRows = result.rows;
-
- // order matters: first set row data, only then modify size.
+ protected void requestRows(int firstRowIndex, int numberOfRows,
+ final RequestRowsCallback<String[]> callback) {
- /* Here's the requested data. Process it, please. */
- setRowData(firstRowIndex, newRows);
-
- /* Let's check whether the backend size changed. */
- if (currentSize != result.size) {
- currentSize = result.size;
- resetDataAndSize(currentSize);
- }
+ backend.query(firstRowIndex, numberOfRows, new RestCallback() {
+ @Override
+ public void onResponse(Backend.Result result) {
+ callback.onResponse(result.rows, result.size);
+ }
+ });
}
@Override