Browse Source

Make RpcDataProviderExtension more generic (#19266)

Change-Id: I3099f2568b70670248983f735aa6cbac46238b34
feature/combobox-communication
Teemu Suo-Anttila 8 years ago
parent
commit
7ffdbe0139

+ 14
- 6
client/src/com/vaadin/client/connectors/GridConnector.java View File

@@ -47,6 +47,8 @@ import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.communication.StateChangeEvent.StateChangeHandler;
import com.vaadin.client.connectors.RpcDataSourceConnector.DetailsListener;
import com.vaadin.client.connectors.RpcDataSourceConnector.RpcDataSource;
import com.vaadin.client.data.DataSource;
import com.vaadin.client.data.HasDataSource;
import com.vaadin.client.ui.AbstractFieldConnector;
import com.vaadin.client.ui.AbstractHasComponentsConnector;
import com.vaadin.client.ui.ConnectorFocusAndBlurHandler;
@@ -109,7 +111,7 @@ import elemental.json.JsonValue;
*/
@Connect(com.vaadin.ui.Grid.class)
public class GridConnector extends AbstractHasComponentsConnector implements
SimpleManagedLayout, DeferredWorker {
SimpleManagedLayout, DeferredWorker, HasDataSource<JsonObject> {

private static final class CustomStyleGenerator implements
CellStyleGenerator<JsonObject>, RowStyleGenerator<JsonObject> {
@@ -1061,11 +1063,6 @@ public class GridConnector extends AbstractHasComponentsConnector implements
}
}

public void setDataSource(RpcDataSource dataSource) {
this.dataSource = dataSource;
getWidget().setDataSource(this.dataSource);
}

private void onSortStateChange() {
List<SortOrder> sortOrder = new ArrayList<SortOrder>();

@@ -1230,4 +1227,15 @@ public class GridConnector extends AbstractHasComponentsConnector implements
return result.isEmpty() ? null : result;
}

@Override
public void setDataSource(DataSource<JsonObject> ds) {
if (ds instanceof RpcDataSource) {
dataSource = (RpcDataSource) ds;
getWidget().setDataSource(dataSource);
} else {
throw new IllegalArgumentException(
"Given DataSource is not RpcDataSource");
}
}

}

+ 12
- 3
client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java View File

@@ -22,6 +22,7 @@ import java.util.List;

import com.vaadin.client.ServerConnector;
import com.vaadin.client.data.AbstractRemoteDataSource;
import com.vaadin.client.data.HasDataSource;
import com.vaadin.client.extensions.AbstractExtensionConnector;
import com.vaadin.shared.data.DataProviderRpc;
import com.vaadin.shared.data.DataRequestRpc;
@@ -246,8 +247,16 @@ public class RpcDataSourceConnector extends AbstractExtensionConnector {

@Override
protected void extend(ServerConnector target) {
GridConnector gridConnector = (GridConnector) target;
dataSource.setDetailsListener(gridConnector.getDetailsListener());
gridConnector.setDataSource(dataSource);
if (target instanceof HasDataSource) {
((HasDataSource<JsonObject>) target).setDataSource(dataSource);
} else {
throw new IllegalArgumentException(
"Parent connector does not implement HasDataSource");
}

if (target instanceof GridConnector) {
dataSource.setDetailsListener(((GridConnector) target)
.getDetailsListener());
}
}
}

+ 26
- 0
client/src/com/vaadin/client/data/HasDataSource.java View File

@@ -0,0 +1,26 @@
/*
* 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.client.data;

/**
* Interface describing a class that supports setting a {@link DataSource}.
*
* @since
*/
public interface HasDataSource<T> {

public void setDataSource(DataSource<T> ds);
}

+ 37
- 86
server/src/com/vaadin/server/communication/data/RpcDataProviderExtension.java View File

@@ -26,7 +26,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;

import com.vaadin.data.Container;
import com.vaadin.data.Container.Indexed;
import com.vaadin.data.Container.Indexed.ItemAddEvent;
import com.vaadin.data.Container.Indexed.ItemRemoveEvent;
@@ -53,11 +52,8 @@ import elemental.json.JsonArray;
import elemental.json.JsonObject;

/**
* Provides Vaadin server-side container data source to a
* {@link com.vaadin.client.ui.grid.GridConnector}. This is currently
* implemented as an Extension hardcoded to support a specific connector type.
* This will be changed once framework support for something more flexible has
* been implemented.
* Provides Vaadin server-side container data source to a connector implementing
* {@link com.vaadin.client.data.HasDataSource}.
*
* @since 7.4
* @author Vaadin Ltd
@@ -71,7 +67,7 @@ public class RpcDataProviderExtension extends AbstractExtension {
*/
private class ActiveItemHandler implements Serializable, DataGenerator {

private final Map<Object, GridValueChangeListener> activeItemMap = new HashMap<Object, GridValueChangeListener>();
private final Map<Object, DataProviderValueChangeListener> activeItemMap = new HashMap<Object, DataProviderValueChangeListener>();
private final KeyMapper<Object> keyMapper = new KeyMapper<Object>();
private final Set<Object> droppedItems = new HashSet<Object>();

@@ -87,8 +83,9 @@ public class RpcDataProviderExtension extends AbstractExtension {
public void addActiveItems(Collection<?> itemIds) {
for (Object itemId : itemIds) {
if (!activeItemMap.containsKey(itemId)) {
activeItemMap.put(itemId, new GridValueChangeListener(
itemId, container.getItem(itemId)));
activeItemMap.put(itemId,
new DataProviderValueChangeListener(itemId,
container.getItem(itemId)));
}
}

@@ -125,8 +122,9 @@ public class RpcDataProviderExtension extends AbstractExtension {
*
* @return collection of value change listeners
*/
public Collection<GridValueChangeListener> getValueChangeListeners() {
return new HashSet<GridValueChangeListener>(activeItemMap.values());
public Collection<DataProviderValueChangeListener> getValueChangeListeners() {
return new HashSet<DataProviderValueChangeListener>(
activeItemMap.values());
}

@Override
@@ -137,7 +135,8 @@ public class RpcDataProviderExtension extends AbstractExtension {
@Override
public void destroyData(Object itemId) {
keyMapper.remove(itemId);
GridValueChangeListener removed = activeItemMap.remove(itemId);
DataProviderValueChangeListener removed = activeItemMap
.remove(itemId);

if (removed != null) {
removed.removeListener();
@@ -146,10 +145,9 @@ public class RpcDataProviderExtension extends AbstractExtension {
}

/**
* A class to listen to changes in property values in the Container added
* with {@link Grid#setContainerDatasource(Container.Indexed)}, and notifies
* the data source to update the client-side representation of the modified
* item.
* A class to listen to changes in property values in the Container, and
* notifies the data source to update the client-side representation of the
* modified item.
* <p>
* One instance of this class can (and should) be reused for all the
* properties in an item, since this class will inform that the entire row
@@ -159,15 +157,13 @@ public class RpcDataProviderExtension extends AbstractExtension {
* Since there's no Container-wide possibility to listen to any kind of
* value changes, an instance of this class needs to be attached to each and
* every Item's Property in the container.
*
* @see Grid#addValueChangeListener(Container, Object, Object)
* @see Grid#valueChangeListeners
*/
private class GridValueChangeListener implements ValueChangeListener {
private class DataProviderValueChangeListener implements
ValueChangeListener {
private final Object itemId;
private final Item item;

public GridValueChangeListener(Object itemId, Item item) {
public DataProviderValueChangeListener(Object itemId, Item item) {
/*
* Using an assert instead of an exception throw, just to optimize
* prematurely
@@ -176,7 +172,7 @@ public class RpcDataProviderExtension extends AbstractExtension {
this.itemId = itemId;
this.item = item;

internalAddColumns(getGrid().getColumns());
internalAddProperties();
}

@Override
@@ -185,18 +181,22 @@ public class RpcDataProviderExtension extends AbstractExtension {
}

public void removeListener() {
removeColumns(getGrid().getColumns());
for (final Object propertyId : item.getItemPropertyIds()) {
Property<?> property = item.getItemProperty(propertyId);
if (property instanceof ValueChangeNotifier) {
((ValueChangeNotifier) property)
.removeValueChangeListener(this);
}
}
}

public void addColumns(Collection<Column> addedColumns) {
internalAddColumns(addedColumns);
updateRowData(itemId);
}

private void internalAddColumns(Collection<Column> addedColumns) {
for (final Column column : addedColumns) {
final Property<?> property = item.getItemProperty(column
.getPropertyId());
private void internalAddProperties() {
for (final Object propertyId : item.getItemPropertyIds()) {
Property<?> property = item.getItemProperty(propertyId);
if (property instanceof ValueChangeNotifier) {
((ValueChangeNotifier) property)
.addValueChangeListener(this);
@@ -205,14 +205,7 @@ public class RpcDataProviderExtension extends AbstractExtension {
}

public void removeColumns(Collection<Column> removedColumns) {
for (final Column column : removedColumns) {
final Property<?> property = item.getItemProperty(column
.getPropertyId());
if (property instanceof ValueChangeNotifier) {
((ValueChangeNotifier) property)
.removeValueChangeListener(this);
}
}

}
}

@@ -310,11 +303,10 @@ public class RpcDataProviderExtension extends AbstractExtension {
public void beforeClientResponse(boolean initial) {
if (initial || bareItemSetTriggeredSizeChange) {
/*
* 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.
* Push initial set of rows, assuming the component will initially
* be rendering the first items in DataSource. 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);
@@ -369,15 +361,14 @@ public class RpcDataProviderExtension extends AbstractExtension {

Item item = container.getItem(itemId);

rows.set(i, getRowData(getGrid().getColumns(), itemId, item));
rows.set(i, getRowData(itemId, item));
}
rpc.setRowData(firstRowToPush, rows);

activeItemHandler.addActiveItems(itemIds);
}

private JsonObject getRowData(Collection<Column> columns, Object itemId,
Item item) {
private JsonObject getRowData(Object itemId, Item item) {

final JsonObject rowObject = Json.createObject();
for (DataGenerator dg : dataGenerators) {
@@ -499,14 +490,13 @@ public class RpcDataProviderExtension extends AbstractExtension {
return;
}

List<Column> columns = getGrid().getColumns();
JsonArray rowData = Json.createArray();
int i = 0;
for (Object itemId : itemIds) {
if (activeItemHandler.getActiveItemIds().contains(itemId)) {
Item item = container.getItem(itemId);
if (item != null) {
JsonObject row = getRowData(columns, itemId, item);
JsonObject row = getRowData(itemId, item);
rowData.set(i++, row);
}
}
@@ -535,10 +525,8 @@ public class RpcDataProviderExtension extends AbstractExtension {
.removeItemSetChangeListener(itemListener);
}

} else if (!(parent instanceof Grid)) {
throw new IllegalStateException(
"Grid is the only accepted parent type");
}

super.setParent(parent);
}

@@ -556,44 +544,7 @@ public class RpcDataProviderExtension extends AbstractExtension {
}
}

/**
* Informs this data provider that given columns have been removed from
* grid.
*
* @param removedColumns
* a list of removed columns
*/
public void columnsRemoved(List<Column> removedColumns) {
for (GridValueChangeListener l : activeItemHandler
.getValueChangeListeners()) {
l.removeColumns(removedColumns);
}

// No need to resend unchanged data. Client will remember the old
// columns until next set of rows is sent.
}

/**
* Informs this data provider that given columns have been added to grid.
*
* @param addedColumns
* a list of added columns
*/
public void columnsAdded(List<Column> addedColumns) {
for (GridValueChangeListener l : activeItemHandler
.getValueChangeListeners()) {
l.addColumns(addedColumns);
}

// Resend all rows to contain new data.
refreshCache();
}

public KeyMapper<Object> getKeyMapper() {
return activeItemHandler.keyMapper;
}

protected Grid getGrid() {
return (Grid) getParent();
}
}

+ 11
- 25
server/src/com/vaadin/ui/Grid.java View File

@@ -4405,29 +4405,22 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
.getContainerPropertyIds());

// Find columns that need to be removed.
List<Column> removedColumns = new LinkedList<Column>();
for (Object propertyId : columns.keySet()) {
if (!properties.contains(propertyId)) {
removedColumns.add(getColumn(propertyId));
}
}
List<Object> removedProperties = new LinkedList<Object>(
columns.keySet());
removedProperties.removeAll(properties);

// Actually remove columns.
for (Column column : removedColumns) {
Object propertyId = column.getPropertyId();
for (Object propertyId : removedProperties) {
internalRemoveColumn(propertyId);
columnKeys.remove(propertyId);
}
datasourceExtension.columnsRemoved(removedColumns);

// Add new columns
List<Column> addedColumns = new LinkedList<Column>();
for (Object propertyId : properties) {
if (!columns.containsKey(propertyId)) {
addedColumns.add(appendColumn(propertyId));
appendColumn(propertyId);
}
}
datasourceExtension.columnsAdded(addedColumns);

if (getFrozenColumnCount() > columns.size()) {
setFrozenColumnCount(columns.size());
@@ -4444,6 +4437,9 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
}
}
}

// Update all rows.
datasourceExtension.refreshCache();
}
};

@@ -4462,13 +4458,6 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
*/
private SelectionModel selectionModel;

/**
* Used to know whether selection change events originate from the server or
* the client so the selection change handler knows whether the changes
* should be sent to the client.
*/
private boolean applyingSelectionFromClient;

private final Header header = new Header(this);
private final Footer footer = new Footer(this);

@@ -5018,7 +5007,8 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
Column column = getColumn(propertyId);
List<Column> addedColumns = new ArrayList<Column>();
addedColumns.add(column);
datasourceExtension.columnsAdded(addedColumns);

datasourceExtension.refreshCache();

return column;
}
@@ -5082,12 +5072,10 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
* Removes all columns from this Grid.
*/
public void removeAllColumns() {
List<Column> removed = new ArrayList<Column>(columns.values());
Set<Object> properties = new HashSet<Object>(columns.keySet());
for (Object propertyId : properties) {
removeColumn(propertyId);
}
datasourceExtension.columnsRemoved(removed);
}

/**
@@ -5208,7 +5196,6 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
List<Column> removed = new ArrayList<Column>();
removed.add(getColumn(propertyId));
internalRemoveColumn(propertyId);
datasourceExtension.columnsRemoved(removed);
}

private void internalRemoveColumn(Object propertyId) {
@@ -5826,8 +5813,7 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
}

/**
* Gets the
* {@link KeyMapper } being used by the data source.
* Gets the {@link KeyMapper } being used by the data source.
*
* @return the key mapper being used by the data source
*/

Loading…
Cancel
Save