import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
+ import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
-import java.util.Locale;
import java.util.Map;
import java.util.Set;
-import java.util.logging.Level;
-import java.util.logging.Logger;
import com.google.gwt.thirdparty.guava.common.collect.BiMap;
import com.google.gwt.thirdparty.guava.common.collect.HashBiMap;
import elemental.json.Json;
import elemental.json.JsonArray;
import elemental.json.JsonObject;
--import elemental.json.JsonValue;
/**
* Provides Vaadin server-side container data source to a
return pinnedItemIds.contains(itemId);
}
- }
-
- /**
- * A helper class that handles the client-side Escalator logic relating to
- * making sure that whatever is currently visible to the user, is properly
- * initialized and otherwise handled on the server side (as far as
- * required).
- * <p>
- * This bookeeping includes, but is not limited to:
- * <ul>
- * <li>listening to the currently visible {@link com.vaadin.data.Property
- * Properties'} value changes on the server side and sending those back to
- * the client; and
- * <li>attaching and detaching {@link com.vaadin.ui.Component Components}
- * from the Vaadin Component hierarchy.
- * </ul>
- */
- private class ActiveRowHandler implements Serializable {
- /**
- * A map from index to the value change listener used for all of column
- * properties
- */
- private final Map<Integer, GridValueChangeListener> valueChangeListeners = new HashMap<Integer, GridValueChangeListener>();
-
- /**
- * The currently active range. Practically, it's the range of row
- * indices being cached currently.
- */
- private Range activeRange = Range.withLength(0, 0);
+ /**
+ * {@inheritDoc}
+ *
+ * @since
+ */
+ @Override
+ public void generateData(Object itemId, Item item, JsonObject rowData) {
+ rowData.put(GridState.JSONKEY_ROWKEY, getKey(itemId));
+ }
+
/**
- * A hook for making sure that appropriate data is "active". All other
- * rows should be "inactive".
- * <p>
- * "Active" can mean different things in different contexts. For
- * example, only the Properties in the active range need
- * ValueChangeListeners. Also, whenever a row with a Component becomes
- * active, it needs to be attached (and conversely, when inactive, it
- * needs to be detached).
+ * Removes all inactive item id to key mapping from the key mapper.
*
- * @param firstActiveRow
- * the first active row
- * @param activeRowCount
- * the number of active rows
+ * @since
*/
- public void setActiveRows(Range newActiveRange) {
-
- // TODO [[Components]] attach and detach components
-
- /*-
- * Example
- *
- * New Range: [3, 4, 5, 6, 7]
- * Old Range: [1, 2, 3, 4, 5]
- * Result: [1, 2][3, 4, 5] []
- */
- final Range[] depractionPartition = activeRange
- .partitionWith(newActiveRange);
- removeValueChangeListeners(depractionPartition[0]);
- removeValueChangeListeners(depractionPartition[2]);
-
- /*-
- * Example
- *
- * Old Range: [1, 2, 3, 4, 5]
- * New Range: [3, 4, 5, 6, 7]
- * Result: [] [3, 4, 5][6, 7]
- */
- final Range[] activationPartition = newActiveRange
- .partitionWith(activeRange);
- addValueChangeListeners(activationPartition[0]);
- addValueChangeListeners(activationPartition[2]);
-
- activeRange = newActiveRange;
-
- assert valueChangeListeners.size() == newActiveRange.length() : "Value change listeners not set up correctly!";
- }
-
- private void addValueChangeListeners(Range range) {
- for (Integer i = range.getStart(); i < range.getEnd(); i++) {
-
- final Object itemId = container.getIdByIndex(i);
- final Item item = container.getItem(itemId);
-
- assert valueChangeListeners.get(i) == null : "Overwriting existing listener";
-
- GridValueChangeListener listener = new GridValueChangeListener(
- itemId, item);
- valueChangeListeners.put(i, listener);
+ public void dropInactiveItems() {
+ Collection<Object> active = activeItemHandler.getActiveItemIds();
+ Iterator<Object> itemIter = itemIdToKey.keySet().iterator();
+ while (itemIter.hasNext()) {
+ Object itemId = itemIter.next();
+ if (!active.contains(itemId) && !isPinned(itemId)) {
+ itemIter.remove();
+ }
}
}
+ }
- private void removeValueChangeListeners(Range range) {
- for (Integer i = range.getStart(); i < range.getEnd(); i++) {
- final GridValueChangeListener listener = valueChangeListeners
- .remove(i);
-
- assert listener != null : "Trying to remove nonexisting listener";
+ /**
+ * Class for keeping track of current items and ValueChangeListeners.
+ *
+ * @since
+ */
+ private class ActiveItemHandler implements Serializable {
- listener.removeListener();
- }
- }
+ private final Map<Object, GridValueChangeListener> activeItemMap = new HashMap<Object, GridValueChangeListener>();
+ private final Set<Object> droppedItems = new HashSet<Object>();
/**
- * Manages removed columns in active rows.
- * <p>
- * This method does <em>not</em> send data again to the client.
+ * Registers ValueChangeListeners for given items ids.
*
- * @param removedColumns
- * the columns that have been removed from the grid
+ * @param itemIds
+ * collection of new active item ids
*/
- public void columnsRemoved(Collection<Column> removedColumns) {
- if (removedColumns.isEmpty()) {
- return;
+ public void addActiveItems(Collection<?> itemIds) {
+ for (Object itemId : itemIds) {
+ if (!activeItemMap.containsKey(itemId)) {
+ activeItemMap.put(itemId, new GridValueChangeListener(
+ itemId, container.getItem(itemId)));
+ }
}
- for (GridValueChangeListener listener : valueChangeListeners
- .values()) {
- listener.removeColumns(removedColumns);
- }
+ // Remove still active rows that were "dropped"
+ droppedItems.removeAll(itemIds);
+ dropListeners(droppedItems);
+ droppedItems.clear();
}
/**
}
this.grid = grid;
}
- rowData.put(GridState.JSONKEY_DETAILS_VISIBLE, true);
+
+ /**
+ * {@inheritDoc}
+ *
+ * @since
+ */
+ @Override
+ public void generateData(Object itemId, Item item, JsonObject rowData) {
+ if (visibleDetails.contains(itemId)) {
++ // Double check to be sure details component exists.
++ detailComponentManager.createDetails(itemId);
++ Component detailsComponent = visibleDetailsComponents
++ .get(itemId);
++ rowData.put(
++ GridState.JSONKEY_DETAILS_VISIBLE,
++ (detailsComponent != null ? detailsComponent
++ .getConnectorId() : ""));
+ }
+ }
}
private final Indexed container;
* This map represents all the details that are user-defined as visible.
* This does not reflect the status in the DOM.
*/
- private Set<Object> visibleDetails = new HashSet<Object>();
+ // TODO this should probably be inside DetailComponentManager
- private Set<Object> visibleDetails = new HashSet<Object>();
++ private final Set<Object> visibleDetails = new HashSet<Object>();
private final DetailComponentManager detailComponentManager = new DetailComponentManager();
- private Set<DataGenerator> dataGenerators = new LinkedHashSet<DataGenerator>();
+
++ private final Set<DataGenerator> dataGenerators = new LinkedHashSet<DataGenerator>();
++
+ private final ActiveItemHandler activeItemHandler = new ActiveItemHandler();
/**
* Creates a new data provider using the given container.
}
rpc.setRowData(firstRowToPush, rows);
- activeRowHandler.setActiveRows(fullRange);
+ activeItemHandler.addActiveItems(itemIds);
+ keyMapper.dropInactiveItems();
}
- private JsonValue getRowData(Collection<Column> columns, Object itemId) {
+ private JsonObject getRowData(Collection<Column> columns, Object itemId) {
Item item = container.getItem(itemId);
- JsonObject rowData = Json.createObject();
-
- Grid grid = getGrid();
-
- for (Column column : columns) {
- Object propertyId = column.getPropertyId();
-
- Object propertyValue = item.getItemProperty(propertyId).getValue();
- JsonValue encodedValue = encodeValue(propertyValue,
- column.getRenderer(), column.getConverter(),
- grid.getLocale());
-
- rowData.put(columnKeys.key(propertyId), encodedValue);
- }
-
final JsonObject rowObject = Json.createObject();
- rowObject.put(GridState.JSONKEY_DATA, rowData);
- rowObject.put(GridState.JSONKEY_ROWKEY, keyMapper.getKey(itemId));
-
- if (visibleDetails.contains(itemId)) {
- // Double check to be sure details component exists.
- detailComponentManager.createDetails(itemId);
- Component detailsComponent = detailComponentManager.visibleDetailsComponents
- .get(itemId);
- rowObject.put(
- GridState.JSONKEY_DETAILS_VISIBLE,
- (detailsComponent != null ? detailsComponent
- .getConnectorId() : ""));
- }
-
- rowReference.set(itemId);
-
- CellStyleGenerator cellStyleGenerator = grid.getCellStyleGenerator();
- if (cellStyleGenerator != null) {
- setGeneratedCellStyles(cellStyleGenerator, rowObject, columns);
- }
- RowStyleGenerator rowStyleGenerator = grid.getRowStyleGenerator();
- if (rowStyleGenerator != null) {
- setGeneratedRowStyles(rowStyleGenerator, rowObject);
+ for (DataGenerator dg : dataGenerators) {
+ dg.generateData(itemId, item, rowObject);
}
return rowObject;