diff options
author | Teemu Suo-Anttila <tsuoanttila@users.noreply.github.com> | 2017-03-23 15:28:37 +0200 |
---|---|---|
committer | Henri Sara <henri.sara@gmail.com> | 2017-03-23 15:28:37 +0200 |
commit | 6384bc7dee5ccbaaafbbf569b758b3e6fd8a2c8b (patch) | |
tree | 419be55a19b6c4ef65876392b6e31091e1ff5c28 | |
parent | 17b3f23b0e526250dc134df1f7d2e6cd7f149ba5 (diff) | |
download | vaadin-framework-6384bc7dee5ccbaaafbbf569b758b3e6fd8a2c8b.tar.gz vaadin-framework-6384bc7dee5ccbaaafbbf569b758b3e6fd8a2c8b.zip |
Add feature to disable collapsing items in TreeGrid (#8879)
Fixes #8846
12 files changed, 346 insertions, 87 deletions
diff --git a/client/src/main/java/com/vaadin/client/connectors/treegrid/TreeGridConnector.java b/client/src/main/java/com/vaadin/client/connectors/treegrid/TreeGridConnector.java index e96bdffc06..32b5a63840 100644 --- a/client/src/main/java/com/vaadin/client/connectors/treegrid/TreeGridConnector.java +++ b/client/src/main/java/com/vaadin/client/connectors/treegrid/TreeGridConnector.java @@ -23,10 +23,8 @@ import com.google.gwt.dom.client.BrowserEvents; import com.google.gwt.dom.client.Element; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.user.client.Event; -import com.google.web.bindery.event.shared.HandlerRegistration; import com.vaadin.client.annotations.OnStateChange; import com.vaadin.client.connectors.grid.GridConnector; -import com.vaadin.client.renderers.ClickableRenderer; import com.vaadin.client.renderers.HierarchyRenderer; import com.vaadin.client.widget.grid.EventCellReference; import com.vaadin.client.widget.grid.GridEventHandler; @@ -54,9 +52,6 @@ public class TreeGridConnector extends GridConnector { private HierarchyRenderer hierarchyRenderer; - // Expander click event handling - private HandlerRegistration expanderClickHandlerRegistration; - @Override public TreeGrid getWidget() { return (TreeGrid) super.getWidget(); @@ -121,7 +116,7 @@ public class TreeGridConnector extends GridConnector { private HierarchyRenderer getHierarchyRenderer() { if (hierarchyRenderer == null) { - hierarchyRenderer = new HierarchyRenderer(); + hierarchyRenderer = new HierarchyRenderer(this::setCollapsed); } return hierarchyRenderer; } @@ -130,20 +125,6 @@ public class TreeGridConnector extends GridConnector { protected void init() { super.init(); - expanderClickHandlerRegistration = getHierarchyRenderer() - .addClickHandler( - new ClickableRenderer.RendererClickHandler<JsonObject>() { - @Override - public void onClick( - ClickableRenderer.RendererClickEvent<JsonObject> event) { - toggleCollapse(getRowKey(event.getRow()), - event.getCell().getRowIndex(), - !isCollapsed(event.getRow())); - event.stopPropagation(); - event.preventDefault(); - } - }); - // Swap Grid's CellFocusEventHandler to this custom one // The handler is identical to the original one except for the child // widget check @@ -158,13 +139,6 @@ public class TreeGridConnector extends GridConnector { new TreeGridClickEvent(getWidget(), getEventCell(getWidget()))); } - @Override - public void onUnregister() { - super.onUnregister(); - - expanderClickHandlerRegistration.removeHandler(); - } - private native void replaceCellFocusEventHandler(Grid<?> grid, GridEventHandler<?> eventHandler) /*-{ @@ -188,9 +162,10 @@ public class TreeGridConnector extends GridConnector { return cell.getColumn().getRenderer() instanceof HierarchyRenderer; } - private void toggleCollapse(String rowKey, int rowIndex, boolean collapse) { + private void setCollapsed(int rowIndex, boolean collapsed) { + String rowKey = getRowKey(getDataSource().getRow(rowIndex)); getRpcProxy(NodeCollapseRpc.class).setNodeCollapsed(rowKey, rowIndex, - collapse); + collapsed); } /** @@ -273,15 +248,15 @@ public class TreeGridConnector extends GridConnector { switch (domEvent.getKeyCode()) { case KeyCodes.KEY_RIGHT: if (!leaf && collapsed) { - toggleCollapse(getRowKey(rowData), - event.getCell().getRowIndex(), true); + setCollapsed(event.getCell().getRowIndex(), + !collapsed); } break; case KeyCodes.KEY_LEFT: if (!collapsed) { // collapse node - toggleCollapse(getRowKey(rowData), - event.getCell().getRowIndex(), false); + setCollapsed(event.getCell().getRowIndex(), + !collapsed); } break; } diff --git a/client/src/main/java/com/vaadin/client/renderers/HierarchyRenderer.java b/client/src/main/java/com/vaadin/client/renderers/HierarchyRenderer.java index 205f7929e4..206491f75b 100644 --- a/client/src/main/java/com/vaadin/client/renderers/HierarchyRenderer.java +++ b/client/src/main/java/com/vaadin/client/renderers/HierarchyRenderer.java @@ -15,6 +15,8 @@ */ package com.vaadin.client.renderers; +import java.util.function.BiConsumer; + import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Element; import com.google.gwt.event.dom.client.ClickEvent; @@ -35,21 +37,55 @@ import elemental.json.JsonObject; /** * A renderer for displaying hierarchical columns in TreeGrid. - * + * * @author Vaadin Ltd * @since 8.1 */ public class HierarchyRenderer extends ClickableRenderer<Object, Widget> { - + private static final String CLASS_TREE_GRID_NODE = "v-tree-grid-node"; private static final String CLASS_TREE_GRID_EXPANDER = "v-tree-grid-expander"; private static final String CLASS_TREE_GRID_CELL_CONTENT = "v-tree-grid-cell-content"; private static final String CLASS_COLLAPSED = "collapsed"; + private static final String CLASS_COLLAPSE_DISABLED = "collapse-disabled"; private static final String CLASS_EXPANDED = "expanded"; private static final String CLASS_DEPTH = "depth-"; private Renderer innerRenderer; + /** + * Constructs a HierarchyRenderer with given collapse callback. Callback is + * called when user clicks on the expander of a row. Callback is given the + * row index and the target collapsed state. + * + * @param collapseCallback + * the callback for collapsing nodes with row index + */ + public HierarchyRenderer(BiConsumer<Integer, Boolean> collapseCallback) { + addClickHandler(event -> { + try { + JsonObject row = (JsonObject) event.getRow(); + // Row needs to have hierarchy description + if (!hasHierarchyData(row)) { + return; + } + + JsonObject hierarchyData = getHierarchyData(row); + if ((!isCollapsed(hierarchyData) + && !isCollapseAllowed(hierarchyData)) + || isLeaf(hierarchyData)) { + return; + } + + collapseCallback.accept(event.getCell().getRowIndex(), + !isCollapsed(hierarchyData)); + } finally { + event.stopPropagation(); + event.preventDefault(); + } + }); + } + @Override public Widget createWidget() { return new HierarchyItem(CLASS_TREE_GRID_NODE); @@ -63,18 +99,15 @@ public class HierarchyRenderer extends ClickableRenderer<Object, Widget> { int depth = 0; boolean leaf = false; boolean collapsed = false; - if (row.hasKey( - TreeGridCommunicationConstants.ROW_HIERARCHY_DESCRIPTION)) { - JsonObject rowDescription = row.getObject( - TreeGridCommunicationConstants.ROW_HIERARCHY_DESCRIPTION); - - depth = (int) rowDescription - .getNumber(TreeGridCommunicationConstants.ROW_DEPTH); - leaf = rowDescription - .getBoolean(TreeGridCommunicationConstants.ROW_LEAF); + boolean collapseAllowed = true; + if (hasHierarchyData(row)) { + JsonObject rowDescription = getHierarchyData(row); + + depth = getDepth(rowDescription); + leaf = isLeaf(rowDescription); if (!leaf) { - collapsed = rowDescription.getBoolean( - TreeGridCommunicationConstants.ROW_COLLAPSED); + collapsed = isCollapsed(rowDescription); + collapseAllowed = isCollapseAllowed(rowDescription); } } @@ -89,22 +122,64 @@ public class HierarchyRenderer extends ClickableRenderer<Object, Widget> { cellWidget.setExpanderState(ExpanderState.EXPANDED); } - // Render the contents of the inner renderer. For non widget renderers - // the cell reference needs to be wrapped so that its getElement method + cellWidget.setCollapseAllowed(collapseAllowed); + + // Render the contents of the inner renderer. For non widget + // renderers + // the cell reference needs to be wrapped so that its getElement + // method // returns the correct element we want to render. if (innerRenderer instanceof WidgetRenderer) { - ((WidgetRenderer) innerRenderer).render(cell, data, ((HierarchyItem) widget).content); + ((WidgetRenderer) innerRenderer).render(cell, data, + ((HierarchyItem) widget).content); } else { - innerRenderer.render(new HierarchyRendererCellReferenceWrapper(cell, - ((HierarchyItem) widget).content.getElement()), data); + innerRenderer.render( + new HierarchyRendererCellReferenceWrapper(cell, + ((HierarchyItem) widget).content.getElement()), + data); } } + private int getDepth(JsonObject rowDescription) { + return (int) rowDescription + .getNumber(TreeGridCommunicationConstants.ROW_DEPTH); + } + + private JsonObject getHierarchyData(JsonObject row) { + return row.getObject( + TreeGridCommunicationConstants.ROW_HIERARCHY_DESCRIPTION); + } + + private boolean hasHierarchyData(JsonObject row) { + return row.hasKey( + TreeGridCommunicationConstants.ROW_HIERARCHY_DESCRIPTION); + } + + private boolean isLeaf(JsonObject rowDescription) { + boolean leaf; + leaf = rowDescription + .getBoolean(TreeGridCommunicationConstants.ROW_LEAF); + return leaf; + } + + private boolean isCollapseAllowed(JsonObject row) { + return row.getBoolean( + TreeGridCommunicationConstants.ROW_COLLAPSE_ALLOWED); + } + + private boolean isCollapsed(JsonObject rowDescription) { + boolean collapsed; + collapsed = rowDescription + .getBoolean(TreeGridCommunicationConstants.ROW_COLLAPSED); + return collapsed; + } + /** - * Sets the renderer to be wrapped. This is the original renderer before hierarchy is applied. + * Sets the renderer to be wrapped. This is the original renderer before + * hierarchy is applied. * * @param innerRenderer - * Renderer to be wrapped. + * Renderer to be wrapped. */ public void setInnerRenderer(Renderer innerRenderer) { this.innerRenderer = innerRenderer; @@ -166,11 +241,13 @@ public class HierarchyRenderer extends ClickableRenderer<Object, Widget> { } private void setDepth(int depth) { - String classNameToBeReplaced = getFullClassName(CLASS_DEPTH, panel.getElement().getClassName()); + String classNameToBeReplaced = getFullClassName(CLASS_DEPTH, + panel.getElement().getClassName()); if (classNameToBeReplaced == null) { panel.getElement().addClassName(CLASS_DEPTH + depth); } else { - panel.getElement().replaceClassName(classNameToBeReplaced, CLASS_DEPTH + depth); + panel.getElement().replaceClassName(classNameToBeReplaced, + CLASS_DEPTH + depth); } } @@ -178,7 +255,8 @@ public class HierarchyRenderer extends ClickableRenderer<Object, Widget> { int start = classNameList.indexOf(prefix); int end = start + prefix.length(); if (start > -1) { - while (end < classNameList.length() && classNameList.charAt(end) != ' ') { + while (end < classNameList.length() + && classNameList.charAt(end) != ' ') { end++; } return classNameList.substring(start, end); @@ -203,6 +281,15 @@ public class HierarchyRenderer extends ClickableRenderer<Object, Widget> { } } + private void setCollapseAllowed(boolean collapseAllowed) { + if (expander.getElement().hasClassName(CLASS_EXPANDED) + && !collapseAllowed) { + expander.getElement().addClassName(CLASS_COLLAPSE_DISABLED); + } else { + expander.getElement().removeClassName(CLASS_COLLAPSE_DISABLED); + } + } + private class Expander extends Widget implements HasClickHandlers { private Expander() { diff --git a/documentation/components/components-treegrid.asciidoc b/documentation/components/components-treegrid.asciidoc index d3a431c3e9..f3c2058f03 100644 --- a/documentation/components/components-treegrid.asciidoc +++ b/documentation/components/components-treegrid.asciidoc @@ -93,6 +93,22 @@ treeGrid.addColumn(Project::getHoursDone).setCaption("Hours Done"); treeGrid.setHierarchyColumn("name"); ---- +== Prevent Node Collapsing + +[classname]#TreeGrid# supports setting a callback method that can allow or prevent the user from collapsing an expanded node. +It can be set with [methodname]#setItemCollapseAllowedProvider# method, that takes a [interfacename]#SerializablePredicate#. +For nodes that cannot be collapsed, the [literal]#++collapse-disabled++# class name is applied to the expansion element + +Avoid doing any heavy operations in the method, since it is called for each item when it is being sent to the client. + +Example using a predefined set of persons that can not be collapsed: +[source, java] +---- +Set<Person> alwaysExpanded; +personTreeGrid.setItemCollapseAllowedProvider(person -> + !alwaysExpanded.contains(person)); +---- + == Listening to Events In addition to supporting all the listeners of the standard [classname]#Grid#, [classname]#TreeGrid# supports listening to the expansion and collapsing of items in its hierarchy. 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 159dfbe1d4..5bb1335ed0 100644 --- a/server/src/main/java/com/vaadin/data/provider/HierarchicalDataCommunicator.java +++ b/server/src/main/java/com/vaadin/data/provider/HierarchicalDataCommunicator.java @@ -28,6 +28,7 @@ import java.util.stream.Stream; import com.vaadin.data.HierarchyData; import com.vaadin.data.provider.HierarchyMapper.TreeLevelQuery; import com.vaadin.server.SerializableConsumer; +import com.vaadin.server.SerializablePredicate; import com.vaadin.shared.Range; import com.vaadin.shared.extension.datacommunicator.HierarchicalDataCommunicatorState; import com.vaadin.shared.ui.treegrid.TreeGridCommunicationConstants; @@ -58,6 +59,11 @@ public class HierarchicalDataCommunicator<T> extends DataCommunicator<T> { private HierarchyMapper mapper = new HierarchyMapper(); /** + * Collapse allowed provider used to allow/disallow collapsing nodes. + */ + private SerializablePredicate<T> itemCollapseAllowedProvider = t -> true; + + /** * The captured client side cache size. */ private int latestCacheSize = INITIAL_FETCH_SIZE; @@ -209,6 +215,9 @@ public class HierarchicalDataCommunicator<T> extends DataCommunicator<T> { hierarchyData.put(TreeGridCommunicationConstants.ROW_COLLAPSED, mapper.isCollapsed(key)); hierarchyData.put(TreeGridCommunicationConstants.ROW_LEAF, false); + hierarchyData.put( + TreeGridCommunicationConstants.ROW_COLLAPSE_ALLOWED, + itemCollapseAllowedProvider.test(item)); } // add hierarchy information to row as metadata @@ -386,4 +395,23 @@ public class HierarchicalDataCommunicator<T> extends DataCommunicator<T> { refresh(expandedItem); } + /** + * Sets the item collapse allowed provider for this + * HierarchicalDataCommunicator. The provider should return {@code true} for + * any item that the user can collapse. + * <p> + * <strong>Note:</strong> This callback will be accessed often when sending + * data to the client. The callback should not do any costly operations. + * + * @param provider + * the item collapse allowed provider, not {@code null} + */ + public void setItemCollapseAllowedProvider( + SerializablePredicate<T> provider) { + Objects.requireNonNull(provider, "Provider can't be null"); + itemCollapseAllowedProvider = provider; + + getActiveDataHandler().getActiveData().forEach(this::refresh); + } + } diff --git a/server/src/main/java/com/vaadin/ui/TreeGrid.java b/server/src/main/java/com/vaadin/ui/TreeGrid.java index 2378ff3f2b..6f961990de 100644 --- a/server/src/main/java/com/vaadin/ui/TreeGrid.java +++ b/server/src/main/java/com/vaadin/ui/TreeGrid.java @@ -35,6 +35,7 @@ import com.vaadin.data.provider.HierarchicalDataCommunicator; import com.vaadin.data.provider.HierarchicalDataProvider; 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.NodeCollapseRpc; import com.vaadin.shared.ui.treegrid.TreeGridState; @@ -58,7 +59,7 @@ public class TreeGrid<T> extends Grid<T> { /** * Item expand event listener. - * + * * @author Vaadin Ltd * @since 8.1 * @param <T> @@ -72,7 +73,7 @@ public class TreeGrid<T> extends Grid<T> { /** * Callback method for when an item has been expanded. - * + * * @param event * the expand event */ @@ -81,7 +82,7 @@ public class TreeGrid<T> extends Grid<T> { /** * Item collapse event listener. - * + * * @author Vaadin Ltd * @since 8.1 * @param <T> @@ -95,7 +96,7 @@ public class TreeGrid<T> extends Grid<T> { /** * Callback method for when an item has been collapsed. - * + * * @param event * the collapse event */ @@ -104,7 +105,7 @@ public class TreeGrid<T> extends Grid<T> { /** * An event that is fired when an item is expanded. - * + * * @author Vaadin Ltd * @since 8.1 * @param <T> @@ -116,7 +117,7 @@ public class TreeGrid<T> extends Grid<T> { /** * Construct an expand event. - * + * * @param source * the tree grid this event originated from * @param item @@ -129,7 +130,7 @@ public class TreeGrid<T> extends Grid<T> { /** * Get the expanded item that triggered this event. - * + * * @return the expanded item */ public T getExpandedItem() { @@ -140,7 +141,7 @@ public class TreeGrid<T> extends Grid<T> { /** * An event that is fired when an item is collapsed. Note that expanded * subtrees of the collapsed item will not trigger collapse events. - * + * * @author Vaadin Ltd * @since 8.1 * @param <T> @@ -152,7 +153,7 @@ public class TreeGrid<T> extends Grid<T> { /** * Construct a collapse event. - * + * * @param source * the tree grid this event originated from * @param item @@ -165,7 +166,7 @@ public class TreeGrid<T> extends Grid<T> { /** * Get the collapsed item that triggered this event. - * + * * @return the collapsed item */ public T getCollapsedItem() { @@ -195,9 +196,9 @@ public class TreeGrid<T> extends Grid<T> { /** * Adds an ExpandListener to this TreeGrid. - * + * * @see ExpandEvent - * + * * @param listener * the listener to add * @return a registration for the listener @@ -209,9 +210,9 @@ public class TreeGrid<T> extends Grid<T> { /** * Adds a CollapseListener to this TreeGrid. - * + * * @see CollapseEvent - * + * * @param listener * the listener to add * @return a registration for the listener @@ -366,6 +367,26 @@ public class TreeGrid<T> extends Grid<T> { getState().hierarchyColumnId = getInternalIdForColumn(getColumn(id)); } + /** + * Sets the item collapse allowed provider for this TreeGrid. The provider + * should return {@code true} for any item that the user can collapse. + * <p> + * <strong>Note:</strong> This callback will be accessed often when sending + * data to the client. The callback should not do any costly operations. + * <p> + * This method is a shortcut to method with the same name in + * {@link HierarchicalDataCommunicator}. + * + * @param provider + * the item collapse allowed provider, not {@code null} + * + * @see HierarchicalDataCommunicator#setItemCollapseAllowedProvider(SerializablePredicate) + */ + public void setItemCollapseAllowedProvider( + SerializablePredicate<T> provider) { + getDataCommunicator().setItemCollapseAllowedProvider(provider); + } + @Override protected TreeGridState getState() { return (TreeGridState) super.getState(); @@ -464,9 +485,8 @@ public class TreeGrid<T> extends Grid<T> { .map(DesignFormatter::encodeForTextNode) .orElse("")); } - getDataProvider().fetch(new HierarchicalQuery<>(null, item)) - .forEach(childItem -> writeRow(container, childItem, item, - context)); + getDataProvider().fetch(new HierarchicalQuery<>(null, item)).forEach( + childItem -> writeRow(container, childItem, item, context)); } @Override @@ -491,7 +511,7 @@ public class TreeGrid<T> extends Grid<T> { /** * Emit an expand event. - * + * * @param item * the item that was expanded */ @@ -501,7 +521,7 @@ public class TreeGrid<T> extends Grid<T> { /** * Emit a collapse event. - * + * * @param item * the item that was collapsed */ diff --git a/shared/src/main/java/com/vaadin/shared/ui/treegrid/TreeGridCommunicationConstants.java b/shared/src/main/java/com/vaadin/shared/ui/treegrid/TreeGridCommunicationConstants.java index c3bd0bbd91..0e678aeb3a 100644 --- a/shared/src/main/java/com/vaadin/shared/ui/treegrid/TreeGridCommunicationConstants.java +++ b/shared/src/main/java/com/vaadin/shared/ui/treegrid/TreeGridCommunicationConstants.java @@ -20,7 +20,7 @@ import java.io.Serializable; /** * Set of contants used by TreeGrid. These are commonly used JsonObject keys * which are considered to be reserved for internal use. - * + * * @author Vaadin Ltd * @since 8.1 */ @@ -29,4 +29,5 @@ public class TreeGridCommunicationConstants implements Serializable { public static final String ROW_DEPTH = "d"; public static final String ROW_COLLAPSED = "c"; public static final String ROW_LEAF = "l"; + public static final String ROW_COLLAPSE_ALLOWED = "ca"; } diff --git a/testbench-api/src/main/java/com/vaadin/testbench/elements/TreeGridElement.java b/testbench-api/src/main/java/com/vaadin/testbench/elements/TreeGridElement.java index 0ca81a56ef..ed02041e06 100644 --- a/testbench-api/src/main/java/com/vaadin/testbench/elements/TreeGridElement.java +++ b/testbench-api/src/main/java/com/vaadin/testbench/elements/TreeGridElement.java @@ -15,6 +15,9 @@ */ package com.vaadin.testbench.elements; +import java.util.Arrays; +import java.util.List; + import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.WebElement; @@ -97,8 +100,9 @@ public class TreeGridElement extends GridElement { public boolean isRowExpanded(int rowIndex, int hierarchyColumnIndex) { WebElement expandElement = getExpandElement(rowIndex, hierarchyColumnIndex); - return expandElement.getAttribute("expanded") != null - && expandElement.getAttribute("collapsed") == null; + List<String> classes = Arrays + .asList(expandElement.getAttribute("class").split(" ")); + return classes.contains("expanded") && !classes.contains("collapsed"); } /** @@ -111,10 +115,7 @@ public class TreeGridElement extends GridElement { * @return {@code true} if collapsed, {@code false} if expanded */ public boolean isRowCollapsed(int rowIndex, int hierarchyColumnIndex) { - WebElement expandElement = getExpandElement(rowIndex, - hierarchyColumnIndex); - return expandElement.getAttribute("collapsed") != null - && expandElement.getAttribute("expanded") == null; + return !isRowExpanded(rowIndex, hierarchyColumnIndex); } /** diff --git a/themes/src/main/themes/VAADIN/themes/valo/components/_treegrid.scss b/themes/src/main/themes/VAADIN/themes/valo/components/_treegrid.scss index 15c53f8cc9..8255d830eb 100644 --- a/themes/src/main/themes/VAADIN/themes/valo/components/_treegrid.scss +++ b/themes/src/main/themes/VAADIN/themes/valo/components/_treegrid.scss @@ -42,6 +42,11 @@ $tg-expander-padding: 10px !default; content: $tg-expander-char-collapsed; } } + + &.collapse-disabled { + @include opacity($v-disabled-opacity); + cursor: default; + } } // Hierarchy depth styling diff --git a/uitest/src/main/java/com/vaadin/tests/components/treegrid/TreeGridBasicFeatures.java b/uitest/src/main/java/com/vaadin/tests/components/treegrid/TreeGridBasicFeatures.java index 3b58e6c75e..9b07cc106e 100644 --- a/uitest/src/main/java/com/vaadin/tests/components/treegrid/TreeGridBasicFeatures.java +++ b/uitest/src/main/java/com/vaadin/tests/components/treegrid/TreeGridBasicFeatures.java @@ -9,6 +9,7 @@ import com.vaadin.annotations.Widgetset; import com.vaadin.data.HierarchyData; import com.vaadin.data.provider.DataProvider; import com.vaadin.data.provider.InMemoryHierarchicalDataProvider; +import com.vaadin.server.SerializablePredicate; import com.vaadin.tests.components.AbstractComponentTest; import com.vaadin.ui.TreeGrid; @@ -38,7 +39,8 @@ public class TreeGridBasicFeatures extends AbstractComponentTest<TreeGrid> { grid.addColumn(HierarchicalTestBean::toString).setCaption("String") .setId("string"); grid.addColumn(HierarchicalTestBean::getDepth).setCaption("Depth") - .setId("depth"); + .setId("depth").setDescriptionGenerator( + t -> "Hierarchy depth: " + t.getDepth()); grid.addColumn(HierarchicalTestBean::getIndex) .setCaption("Index on this depth").setId("index"); grid.setHierarchyColumn("string"); @@ -54,6 +56,7 @@ public class TreeGridBasicFeatures extends AbstractComponentTest<TreeGrid> { createDataProviderSelect(); createHierarchyColumnSelect(); + createCollapseAllowedSelect(); createListenerMenu(); } @@ -103,6 +106,18 @@ public class TreeGridBasicFeatures extends AbstractComponentTest<TreeGrid> { (treeGrid, value, data) -> treeGrid.setHierarchyColumn(value)); } + private void createCollapseAllowedSelect() { + LinkedHashMap<String, SerializablePredicate<HierarchicalTestBean>> options = new LinkedHashMap<>(); + options.put("all allowed", t -> true); + options.put("all disabled", t -> false); + options.put("depth 0 disabled", t -> t.getDepth() != 0); + options.put("depth 1 disabled", t -> t.getDepth() != 1); + + createSelectAction("Collapse allowed", CATEGORY_FEATURES, options, + "all allowed", (treeGrid, value, data) -> treeGrid + .setItemCollapseAllowedProvider(value)); + } + @SuppressWarnings("unchecked") private void createListenerMenu() { createListenerAction("Collapse listener", "State", diff --git a/uitest/src/test/java/com/vaadin/tests/components/treegrid/TreeGridBasicFeaturesTest.java b/uitest/src/test/java/com/vaadin/tests/components/treegrid/TreeGridBasicFeaturesTest.java index 215bef95d2..cda2ba5966 100644 --- a/uitest/src/test/java/com/vaadin/tests/components/treegrid/TreeGridBasicFeaturesTest.java +++ b/uitest/src/test/java/com/vaadin/tests/components/treegrid/TreeGridBasicFeaturesTest.java @@ -127,7 +127,7 @@ public class TreeGridBasicFeaturesTest extends MultiBrowserTest { Assert.assertFalse(logContainsText("Item expanded: 0 | 0")); Assert.assertFalse(logContainsText("Item collapsed: 0 | 0")); - grid.collapseWithClick(0); + grid.expandWithClick(0); Assert.assertTrue(logContainsText("Item expanded: 0 | 0")); Assert.assertFalse(logContainsText("Item collapsed: 0 | 0")); @@ -140,7 +140,7 @@ public class TreeGridBasicFeaturesTest extends MultiBrowserTest { selectMenuPath("Component", "State", "Expand listener"); selectMenuPath("Component", "State", "Collapse listener"); - grid.collapseWithClick(1); + grid.expandWithClick(1); grid.collapseWithClick(1); Assert.assertFalse(logContainsText("Item expanded: 0 | 1")); diff --git a/uitest/src/test/java/com/vaadin/tests/components/treegrid/TreeGridCollapseDisabledTest.java b/uitest/src/test/java/com/vaadin/tests/components/treegrid/TreeGridCollapseDisabledTest.java new file mode 100644 index 0000000000..dbb8e38b2a --- /dev/null +++ b/uitest/src/test/java/com/vaadin/tests/components/treegrid/TreeGridCollapseDisabledTest.java @@ -0,0 +1,111 @@ +package com.vaadin.tests.components.treegrid; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.vaadin.testbench.elements.TreeGridElement; +import com.vaadin.tests.tb3.SingleBrowserTest; + +public class TreeGridCollapseDisabledTest extends SingleBrowserTest { + + private TreeGridElement grid; + + @Override + protected Class<?> getUIClass() { + return TreeGridBasicFeatures.class; + } + + @Before + public void before() { + openTestURL(); + grid = $(TreeGridElement.class).first(); + } + + @Test + public void collapse_disabled_for_all() { + selectMenuPath("Component", "Features", "Collapse allowed", + "all disabled"); + + // Assert first and second row can be expanded, but not collapsed + assertExpandRow(0); + assertCollapseRowDisabled(0); + + assertExpandRow(1); + assertCollapseRowDisabled(1); + } + + @Test + public void collapse_disabled_for_depth0() { + selectMenuPath("Component", "Features", "Collapse allowed", + "depth 0 disabled"); + + // Assert first row expands + assertExpandRow(0); + + // Assert second row expands and collapses + assertExpandRow(1); + assertCollapseRow(1); + + // Assert first row does not collapse + assertCollapseRowDisabled(0); + } + + @Test + public void collapse_disabled_for_depth1() { + selectMenuPath("Component", "Features", "Collapse allowed", + "depth 1 disabled"); + + // Assert first row expands + assertExpandRow(0); + + // Assert second row expands but does not collapse + assertExpandRow(1); + assertCollapseRowDisabled(1); + + // Assert first row still collapses + assertCollapseRow(0); + } + + @Test + public void collapse_disabled_mode_change_with_expanded_rows() { + // Assert first row expands + assertExpandRow(0); + + // Assert second row expands and collapses + assertExpandRow(1); + assertCollapseRow(1); + + selectMenuPath("Component", "Features", "Collapse allowed", + "depth 1 disabled"); + + Assert.assertTrue("First row should still be expanded", + grid.isRowExpanded(0, 0)); + + // Assert second row expands but does not collapse + assertExpandRow(1); + assertCollapseRowDisabled(1); + + // Assert first row still collapses + assertCollapseRow(0); + } + + private void assertExpandRow(int row) { + Assert.assertFalse(grid.isRowExpanded(row, 0)); + grid.expandWithClick(row); + Assert.assertTrue(grid.isRowExpanded(row, 0)); + } + + private void assertCollapseRow(int row) { + Assert.assertTrue("Row not expanded", grid.isRowExpanded(row, 0)); + grid.collapseWithClick(row); + Assert.assertFalse("Row did not collapse", grid.isRowExpanded(row, 0)); + } + + private void assertCollapseRowDisabled(int row) { + Assert.assertTrue("Row not expanded", grid.isRowExpanded(row, 0)); + grid.collapseWithClick(row); + Assert.assertTrue("Row should not collapse", + grid.isRowExpanded(row, 0)); + } +} diff --git a/uitest/src/test/java/com/vaadin/tests/components/treegrid/TreeGridScrollingTest.java b/uitest/src/test/java/com/vaadin/tests/components/treegrid/TreeGridScrollingTest.java index be7953ba35..b4bc65e1ce 100644 --- a/uitest/src/test/java/com/vaadin/tests/components/treegrid/TreeGridScrollingTest.java +++ b/uitest/src/test/java/com/vaadin/tests/components/treegrid/TreeGridScrollingTest.java @@ -129,7 +129,7 @@ public class TreeGridScrollingTest extends SingleBrowserTest { verifyRow(1, 1, 0); verifyRow(0, 0, 0); - grid.expandWithClick(3); + grid.collapseWithClick(3); verifyRow(0, 0, 0); verifyRow(1, 1, 0); @@ -144,7 +144,7 @@ public class TreeGridScrollingTest extends SingleBrowserTest { verifyRow(1, 1, 0); verifyRow(0, 0, 0); - grid.expandWithClick(0); + grid.collapseWithClick(0); verifyRow(0, 0, 0); verifyRow(10, 0, 10); |