Skip to content

Commit

Permalink
Hierarchical data (#8842)
Browse files Browse the repository at this point in the history
* Initial HierarchicalDataProvider for TreeGrid
* Initial in-memory hierarchical data implementation
* TreeGrid declarative support

Fixes #8611, Fixes #8620
  • Loading branch information
ahie authored and pleku committed Mar 16, 2017
1 parent e5488df commit 71679df
Show file tree
Hide file tree
Showing 29 changed files with 3,165 additions and 344 deletions.
Expand Up @@ -78,14 +78,25 @@ public void updateData(JsonArray data) {
updateRowData(data.getObject(i));
}
}

@Override
public void insertRows(int firstRowIndex, int count) {
insertRowData(firstRowIndex, count);
}

@Override
public void removeRows(int firstRowIndex, int count) {
removeRowData(firstRowIndex, count);
}
});
}

@Override
protected void requestRows(int firstRowIndex, int numberOfRows,
RequestRowsCallback<JsonObject> callback) {
getRpcProxy(DataRequestRpc.class).requestRows(firstRowIndex,
numberOfRows, 0, 0);
numberOfRows, getCachedRange().getStart(),
getCachedRange().length());

JsonArray dropped = Json.createArray();
int i = 0;
Expand All @@ -112,13 +123,16 @@ protected void onDropFromCache(int rowIndex, JsonObject removed) {
/**
* Updates row data based on row key.
*
* @param row
* @param rowData
* new row object
*/
protected void updateRowData(JsonObject row) {
int index = indexOfKey(getRowKey(row));
protected void updateRowData(JsonObject rowData) {
int index = indexOfKey(getRowKey(rowData));
if (index >= 0) {
setRowData(index, Collections.singletonList(row));
JsonObject oldRowData = getRow(index);
onRowDataUpdate(rowData, oldRowData);

setRowData(index, Collections.singletonList(rowData));
}
}
}
Expand All @@ -135,6 +149,25 @@ protected void extend(ServerConnector target) {
}
}

/**
* Called row updates from server side.
* <p>
* This method exists for making it possible to copy data from the old
* object to the new one, if e.g. some data is not available in the server
* side when doing updates and would be missed otherwise.
*
* @param newRowData
* the new row data
* @param oldRowData
* the previous row data
*
* @since 8.1
*/
protected void onRowDataUpdate(JsonObject newRowData,
JsonObject oldRowData) {
// NOOP, see overrides for concrete use cases
}

@Override
public DataCommunicatorState getState() {
return (DataCommunicatorState) super.getState();
Expand Down
@@ -0,0 +1,59 @@
/*
* Copyright 2000-2016 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.connectors.data;

import com.vaadin.data.provider.HierarchicalDataCommunicator;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.treegrid.TreeGridCommunicationConstants;

import elemental.json.JsonObject;

/**
* A connector for HierarchicalDataCommunicator class.
*
* @author Vaadin Ltd
* @since
*/
@Connect(HierarchicalDataCommunicator.class)
public class HierarchicalDataCommunicatorConnector
extends DataCommunicatorConnector {

@Override
protected void onRowDataUpdate(JsonObject newRowData,
JsonObject oldRowData) {
assert newRowData.hasKey(
TreeGridCommunicationConstants.ROW_HIERARCHY_DESCRIPTION);
assert oldRowData.hasKey(
TreeGridCommunicationConstants.ROW_HIERARCHY_DESCRIPTION);

/*
* Since server side can't know the index of a random item, any
* refreshItem(..) cannot know the depth. Thus need to copy it from
* previous item.
*/
JsonObject hierarchyData = newRowData.getObject(
TreeGridCommunicationConstants.ROW_HIERARCHY_DESCRIPTION);
if (!hierarchyData.hasKey(TreeGridCommunicationConstants.ROW_DEPTH)) {
hierarchyData.put(TreeGridCommunicationConstants.ROW_DEPTH,
oldRowData
.getObject(
TreeGridCommunicationConstants.ROW_HIERARCHY_DESCRIPTION)
.getNumber(
TreeGridCommunicationConstants.ROW_DEPTH));
}
}

}
Expand Up @@ -34,7 +34,6 @@
import com.vaadin.client.widget.treegrid.TreeGrid;
import com.vaadin.client.widget.treegrid.events.TreeGridClickEvent;
import com.vaadin.client.widgets.Grid;
import com.vaadin.shared.data.DataCommunicatorConstants;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.treegrid.NodeCollapseRpc;
import com.vaadin.shared.ui.treegrid.TreeGridCommunicationConstants;
Expand Down Expand Up @@ -81,7 +80,7 @@ public TreeGridState getState() {
void updateHierarchyColumn() {
Scheduler.get().scheduleFinally(() -> {
// Id of old hierarchy column
String oldHierarchyColumnId = this.hierarchyColumnId;
String oldHierarchyColumnId = hierarchyColumnId;

// Id of new hierarchy column. Choose first when nothing explicitly
// set
Expand Down Expand Up @@ -112,7 +111,7 @@ void updateHierarchyColumn() {
// setRenderer() replaces DOM elements
getWidget().setFrozenColumnCount(getState().frozenColumnCount);

this.hierarchyColumnId = newHierarchyColumnId;
hierarchyColumnId = newHierarchyColumnId;
} else {
Logger.getLogger(TreeGridConnector.class.getName()).warning(
"Couldn't find column: " + newHierarchyColumnId);
Expand All @@ -137,7 +136,9 @@ protected void init() {
@Override
public void onClick(
ClickableRenderer.RendererClickEvent<JsonObject> event) {
toggleCollapse(getRowKey(event.getRow()));
toggleCollapse(getRowKey(event.getRow()),
event.getCell().getRowIndex(),
!isCollapsed(event.getRow()));
event.stopPropagation();
event.preventDefault();
}
Expand Down Expand Up @@ -187,8 +188,9 @@ private boolean isHierarchyColumn(EventCellReference<JsonObject> cell) {
return cell.getColumn().getRenderer() instanceof HierarchyRenderer;
}

private void toggleCollapse(String rowKey) {
getRpcProxy(NodeCollapseRpc.class).toggleCollapse(rowKey);
private void toggleCollapse(String rowKey, int rowIndex, boolean collapse) {
getRpcProxy(NodeCollapseRpc.class).setNodeCollapsed(rowKey, rowIndex,
collapse);
}

/**
Expand Down Expand Up @@ -260,31 +262,26 @@ public void onEvent(Grid.GridEvent<JsonObject> event) {

// Hierarchy metadata
boolean collapsed, leaf;
if (event.getCell().getRow().hasKey(
JsonObject rowData = event.getCell().getRow();
if (rowData.hasKey(
TreeGridCommunicationConstants.ROW_HIERARCHY_DESCRIPTION)) {
JsonObject rowDescription = event.getCell().getRow()
.getObject(
TreeGridCommunicationConstants.ROW_HIERARCHY_DESCRIPTION);
collapsed = rowDescription.getBoolean(
TreeGridCommunicationConstants.ROW_COLLAPSED);
collapsed = isCollapsed(rowData);
JsonObject rowDescription = rowData.getObject(
TreeGridCommunicationConstants.ROW_HIERARCHY_DESCRIPTION);
leaf = rowDescription.getBoolean(
TreeGridCommunicationConstants.ROW_LEAF);

switch (domEvent.getKeyCode()) {
case KeyCodes.KEY_RIGHT:
if (!leaf) {
if (collapsed) {
toggleCollapse(
event.getCell().getRow().getString(
DataCommunicatorConstants.KEY));
}
if (!leaf && collapsed) {
toggleCollapse(getRowKey(rowData),
event.getCell().getRowIndex(), true);
}
break;
case KeyCodes.KEY_LEFT:
if (!collapsed) {
// collapse node
toggleCollapse(event.getCell().getRow()
.getString(DataCommunicatorConstants.KEY));
toggleCollapse(getRowKey(rowData),
event.getCell().getRowIndex(), false);
}
break;
}
Expand All @@ -294,4 +291,24 @@ public void onEvent(Grid.GridEvent<JsonObject> event) {
}
}
}

private static boolean isCollapsed(JsonObject rowData) {
assert rowData
.hasKey(TreeGridCommunicationConstants.ROW_HIERARCHY_DESCRIPTION) : "missing hierarchy data for row "
+ rowData.asString();
return rowData
.getObject(
TreeGridCommunicationConstants.ROW_HIERARCHY_DESCRIPTION)
.getBoolean(TreeGridCommunicationConstants.ROW_COLLAPSED);
}

private static int getDepth(JsonObject rowData) {
assert rowData
.hasKey(TreeGridCommunicationConstants.ROW_HIERARCHY_DESCRIPTION) : "missing hierarchy data for row "
+ rowData.asString();
return (int) rowData
.getObject(
TreeGridCommunicationConstants.ROW_HIERARCHY_DESCRIPTION)
.getNumber(TreeGridCommunicationConstants.ROW_DEPTH);
}
}
4 changes: 2 additions & 2 deletions server/src/main/java/com/vaadin/data/HasItems.java
Expand Up @@ -87,7 +87,7 @@ public interface HasItems<T> extends Component, Serializable {
* <pre>
* <code>
* HasDataProvider<String> listing = new CheckBoxGroup<>();
* listing.setItems(Arrays.asList("a","b"));
* listing.setItems("a","b");
* ...
*
* Collection<String> collection = ((ListDataProvider<String>)listing.getDataProvider()).getItems();
Expand Down Expand Up @@ -122,7 +122,7 @@ public default void setItems(@SuppressWarnings("unchecked") T... items) {
* <pre>
* <code>
* HasDataProvider<String> listing = new CheckBoxGroup<>();
* listing.setItems(Arrays.asList("a","b"));
* listing.setItems(Stream.of("a","b"));
* ...
*
* Collection<String> collection = ((ListDataProvider<String>)listing.getDataProvider()).getItems();
Expand Down

0 comments on commit 71679df

Please sign in to comment.