*/
package com.vaadin.client.connectors.data.typed;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.vaadin.client.ServerConnector;
import com.vaadin.client.data.HasDataSource;
import com.vaadin.client.extensions.AbstractExtensionConnector;
import com.vaadin.client.widget.grid.datasources.ListDataSource;
import com.vaadin.server.communication.data.typed.DataProvider;
import com.vaadin.shared.data.DataProviderClientRpc;
+import com.vaadin.shared.data.DataProviderConstants;
+import com.vaadin.shared.data.DataRequestRpc;
import com.vaadin.shared.ui.Connect;
+import elemental.json.Json;
import elemental.json.JsonArray;
import elemental.json.JsonObject;
/**
- * A simple connector for DataProvider class.
+ * A simple connector for DataProvider class. Based on {@link ListDataSource}
+ * and does not support lazy loading or paging.
*
* @since
*/
@Connect(DataProvider.class)
public class DataSourceConnector extends AbstractExtensionConnector {
- ListDataSource<JsonObject> ds = new ListDataSource<JsonObject>();
+ private Map<String, JsonObject> keyToJson = new HashMap<String, JsonObject>();
+ private Set<String> droppedKeys = new HashSet<String>();
+ private ListDataSource<JsonObject> ds = new ListDataSource<JsonObject>();
+ private boolean pendingDrop = false;
@Override
protected void extend(ServerConnector target) {
@Override
public void resetSize(long size) {
- // Server will provide the data we need.
ds.asList().clear();
+ // Inform the server-side that all keys are now dropped.
+ for (String key : keyToJson.keySet()) {
+ dropKey(key);
+ }
+ sendDroppedKeys();
}
@Override
assert firstIndex <= l.size() : "Gap in data. First Index: "
+ firstIndex + ", Size: " + l.size();
for (long i = 0; i < data.length(); ++i) {
+ JsonObject object = data.getObject((int) i);
if (i + firstIndex == l.size()) {
- l.add(data.getObject((int) i));
+ l.add(object);
} else if (i + firstIndex < l.size()) {
- l.set((int) (i + firstIndex), data.getObject((int) i));
+ int index = (int) (i + firstIndex);
+ dropKey(getKey(l.get(index)));
+ l.set(index, object);
}
+ keyToJson.put(getKey(object), object);
}
+ sendDroppedKeys();
}
@Override
}
@Override
- public void drop(JsonObject dataObject) {
- List<JsonObject> l = ds.asList();
- for (int i = 0; i < l.size(); ++i) {
- if (l.get(i).toJson().equals(dataObject.toJson())) {
- l.remove(i);
- return;
- }
+ public void drop(String key) {
+ if (keyToJson.containsKey(key)) {
+ ds.asList().remove(keyToJson.get(key));
+ dropKey(key);
+ sendDroppedKeys();
}
}
});
assert false : "Parent not implementing HasDataSource";
}
}
+
+ /**
+ * Marks a key as dropped. Call to
+ * {@link DataSourceConnector#sendDroppedKeys()} should be called to make
+ * sure the information is sent to the server-side.
+ *
+ * @param key
+ * dropped key
+ */
+ private void dropKey(String key) {
+ if (keyToJson.containsKey(key)) {
+ droppedKeys.add(key);
+ keyToJson.remove(key);
+ }
+ }
+
+ /**
+ * Sends dropped keys to the server-side with a deferred scheduled command.
+ * Multiple calls to this method will only result to one command being
+ * executed.
+ */
+ private void sendDroppedKeys() {
+ if (pendingDrop) {
+ return;
+ }
+
+ pendingDrop = true;
+ Scheduler.get().scheduleDeferred(new ScheduledCommand() {
+
+ @Override
+ public void execute() {
+ pendingDrop = false;
+ if (droppedKeys.isEmpty()) {
+ return;
+ }
+
+ JsonArray keyArray = Json.createArray();
+ int i = 0;
+ for (String key : droppedKeys) {
+ keyArray.set(i++, key);
+ }
+
+ getRpcProxy(DataRequestRpc.class).dropRows(keyArray);
+
+ // Force RPC since it's delayed.
+ getConnection().getServerRpcQueue().flush();
+
+ droppedKeys.clear();
+ }
+ });
+ }
+
+ /**
+ * Gets the mapping key from given {@link JsonObject}.
+ *
+ * @param jsonObject
+ * json object to get the key from
+ */
+ protected String getKey(JsonObject jsonObject) {
+ if (jsonObject.hasKey(DataProviderConstants.KEY)) {
+ return jsonObject.getString(DataProviderConstants.KEY);
+ }
+ return null;
+ }
}
}
@Override
- public void dropRows(JsonArray rowKeys) {
- // FIXME: What should I do with these?
+ public void dropRows(JsonArray keys) {
+ for (int i = 0; i < keys.length(); ++i) {
+ handler.dropActiveData(keys.getString(i));
+ }
+
+ // Use the whole data as the ones sent to the client.
+ handler.cleanUp(data);
}
}
}
/**
- * Informs the DataProvider that an item has been added. It is assumed to be
- * the last item in the collection.
+ * Informs the DataProvider that a data object has been added. It is assumed
+ * to be the last object in the collection.
*
- * @param item
- * item added to collection
+ * @param data
+ * data object added to collection
*/
- public void add(T item) {
- rpc.add(getDataObject(item));
+ public void add(T data) {
+ rpc.add(getDataObject(data));
}
/**
- * Informs the DataProvider that an item has been removed.
+ * Informs the DataProvider that a data object has been removed.
*
- * @param item
- * item removed from collection
+ * @param data
+ * data object removed from collection
*/
- public void remove(T item) {
- rpc.drop(getDataObject(item));
+ public void remove(T data) {
+ if (handler.getActiveData().contains(data)) {
+ rpc.drop(getKeyMapper().key(data));
+ }
}
}