summaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorIlia Motornyi <elmot@vaadin.com>2017-04-05 14:14:03 +0200
committerGitHub <noreply@github.com>2017-04-05 14:14:03 +0200
commit535b879cb8180983c2da6444ec275e588fb4125f (patch)
treeb92535ccbc9bd9f43b1000a73fcf2d5bf9223a30 /server
parent1a30320913e8b9ea851af3ed4a659f969aa92ee6 (diff)
downloadvaadin-framework-535b879cb8180983c2da6444ec275e588fb4125f.tar.gz
vaadin-framework-535b879cb8180983c2da6444ec275e588fb4125f.zip
TreeGrid keyboard navigation
Fixes #8758
Diffstat (limited to 'server')
-rw-r--r--server/src/main/java/com/vaadin/data/provider/HierarchicalDataCommunicator.java40
-rw-r--r--server/src/main/java/com/vaadin/data/provider/HierarchyMapper.java16
-rw-r--r--server/src/main/java/com/vaadin/ui/TreeGrid.java29
3 files changed, 68 insertions, 17 deletions
diff --git a/server/src/main/java/com/vaadin/data/provider/HierarchicalDataCommunicator.java b/server/src/main/java/com/vaadin/data/provider/HierarchicalDataCommunicator.java
index b93d0c3952..b986f74ea3 100644
--- a/server/src/main/java/com/vaadin/data/provider/HierarchicalDataCommunicator.java
+++ b/server/src/main/java/com/vaadin/data/provider/HierarchicalDataCommunicator.java
@@ -335,14 +335,16 @@ public class HierarchicalDataCommunicator<T> extends DataCommunicator<T> {
}
/**
- * Collapses given row, removing all its subtrees.
+ * Collapses given row, removing all its subtrees. Calling this method will
+ * have no effect if the row is already collapsed.
*
* @param collapsedRowKey
* the key of the row, not {@code null}
* @param collapsedRowIndex
* the index of row to collapse
+ * @return {@code true} if the row was collapsed, {@code false} otherwise
*/
- public void doCollapse(String collapsedRowKey, int collapsedRowIndex) {
+ public boolean doCollapse(String collapsedRowKey, int collapsedRowIndex) {
if (collapsedRowIndex < 0 | collapsedRowIndex >= mapper.getTreeSize()) {
throw new IllegalArgumentException("Invalid row index "
+ collapsedRowIndex + " when tree grid size of "
@@ -353,24 +355,30 @@ public class HierarchicalDataCommunicator<T> extends DataCommunicator<T> {
Objects.requireNonNull(collapsedItem,
"Cannot find item for given key " + collapsedItem);
+ if (mapper.isCollapsed(collapsedRowKey)) {
+ return false;
+ }
int collapsedSubTreeSize = mapper.collapse(collapsedRowKey,
collapsedRowIndex);
-
- getClientRpc().removeRows(collapsedRowIndex + 1, collapsedSubTreeSize);
+ getClientRpc().removeRows(collapsedRowIndex + 1,
+ collapsedSubTreeSize);
// FIXME seems like a slight overkill to do this just for refreshing
// expanded status
refresh(collapsedItem);
+ return true;
}
/**
- * Expands the given row.
+ * Expands the given row. Calling this method will have no effect if the row
+ * is already expanded.
*
* @param expandedRowKey
* the key of the row, not {@code null}
* @param expandedRowIndex
* the index of the row to expand
+ * @return {@code true} if the row was expanded, {@code false} otherwise
*/
- public void doExpand(String expandedRowKey, final int expandedRowIndex) {
+ public boolean doExpand(String expandedRowKey, final int expandedRowIndex) {
if (expandedRowIndex < 0 | expandedRowIndex >= mapper.getTreeSize()) {
throw new IllegalArgumentException("Invalid row index "
+ expandedRowIndex + " when tree grid size of "
@@ -388,16 +396,21 @@ public class HierarchicalDataCommunicator<T> extends DataCommunicator<T> {
+ " returned no child nodes.");
}
+ if (!mapper.isCollapsed(expandedRowKey)) {
+ return false;
+ }
mapper.expand(expandedRowKey, expandedRowIndex, expandedNodeSize);
-
getClientRpc().insertRows(expandedRowIndex + 1, expandedNodeSize);
- // TODO optimize by sending "just enough" of the expanded items directly
- doPushRows(Range.withLength(expandedRowIndex + 1, expandedNodeSize));
+ // TODO optimize by sending "just enough" of the expanded items
+ // directly
+ doPushRows(
+ Range.withLength(expandedRowIndex + 1, expandedNodeSize));
// expanded node needs to be updated to be marked as expanded
// FIXME seems like a slight overkill to do this just for refreshing
// expanded status
refresh(expandedItem);
+ return true;
}
/**
@@ -419,4 +432,13 @@ public class HierarchicalDataCommunicator<T> extends DataCommunicator<T> {
getActiveDataHandler().getActiveData().forEach(this::refresh);
}
+ /**
+ * Returns parent index for the row or {@code null}
+ *
+ * @param rowIndex the row index
+ * @return the parent index or {@code null} for top-level items
+ */
+ public Integer getParentIndex(int rowIndex) {
+ return mapper.getParentIndex(rowIndex);
+ }
}
diff --git a/server/src/main/java/com/vaadin/data/provider/HierarchyMapper.java b/server/src/main/java/com/vaadin/data/provider/HierarchyMapper.java
index 040be6cf2f..6c6f8fdaef 100644
--- a/server/src/main/java/com/vaadin/data/provider/HierarchyMapper.java
+++ b/server/src/main/java/com/vaadin/data/provider/HierarchyMapper.java
@@ -442,4 +442,20 @@ class HierarchyMapper implements Serializable {
}
}
+ /**
+ * Returns parent index for the row or {@code null}
+ *
+ * @param rowIndex the row index
+ * @return the parent index or {@code null} for top-level items
+ */
+ public Integer getParentIndex(int rowIndex) {
+ return nodes.stream()
+ .filter(treeNode -> treeNode.getParentKey() != null
+ && treeNode.getStartIndex() <= rowIndex
+ && treeNode.getEndIndex() >= rowIndex)
+ .min((a, b) -> Math.min(a.getEndIndex() - a.getStartIndex(),
+ b.getEndIndex() - b.getStartIndex()))
+ .map(treeNode -> treeNode.getStartIndex() - 1)
+ .orElse(null);
+ }
}
diff --git a/server/src/main/java/com/vaadin/ui/TreeGrid.java b/server/src/main/java/com/vaadin/ui/TreeGrid.java
index 6f961990de..d91a0f9af1 100644
--- a/server/src/main/java/com/vaadin/ui/TreeGrid.java
+++ b/server/src/main/java/com/vaadin/ui/TreeGrid.java
@@ -37,6 +37,8 @@ import com.vaadin.data.provider.HierarchicalQuery;
import com.vaadin.data.provider.InMemoryHierarchicalDataProvider;
import com.vaadin.server.SerializablePredicate;
import com.vaadin.shared.Registration;
+import com.vaadin.shared.ui.treegrid.FocusParentRpc;
+import com.vaadin.shared.ui.treegrid.FocusRpc;
import com.vaadin.shared.ui.treegrid.NodeCollapseRpc;
import com.vaadin.shared.ui.treegrid.TreeGridState;
import com.vaadin.ui.declarative.DesignAttributeHandler;
@@ -120,7 +122,7 @@ public class TreeGrid<T> extends Grid<T> {
*
* @param source
* the tree grid this event originated from
- * @param item
+ * @param expandedItem
* the item that was expanded
*/
public ExpandEvent(TreeGrid<T> source, T expandedItem) {
@@ -156,7 +158,7 @@ public class TreeGrid<T> extends Grid<T> {
*
* @param source
* the tree grid this event originated from
- * @param item
+ * @param collapsedItem
* the item that was collapsed
*/
public CollapseEvent(TreeGrid<T> source, T collapsedItem) {
@@ -182,13 +184,24 @@ public class TreeGrid<T> extends Grid<T> {
public void setNodeCollapsed(String rowKey, int rowIndex,
boolean collapse) {
if (collapse) {
- getDataCommunicator().doCollapse(rowKey, rowIndex);
- fireCollapseEvent(
- getDataCommunicator().getKeyMapper().get(rowKey));
+ if (getDataCommunicator().doCollapse(rowKey, rowIndex)) {
+ fireCollapseEvent(getDataCommunicator().getKeyMapper()
+ .get(rowKey));
+ }
} else {
- getDataCommunicator().doExpand(rowKey, rowIndex);
- fireExpandEvent(
- getDataCommunicator().getKeyMapper().get(rowKey));
+ if (getDataCommunicator().doExpand(rowKey, rowIndex)) {
+ fireExpandEvent(getDataCommunicator().getKeyMapper()
+ .get(rowKey));
+ }
+ }
+ }
+ });
+ registerRpc(new FocusParentRpc() {
+ @Override
+ public void focusParent(int rowIndex, int cellIndex) {
+ Integer parentIndex = getDataCommunicator().getParentIndex(rowIndex);
+ if (parentIndex != null) {
+ getRpcProxy(FocusRpc.class).focusCell(parentIndex, cellIndex);
}
}
});