Fixes #8846tags/8.1.0.alpha3
@@ -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; | |||
} |
@@ -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() { |
@@ -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. |
@@ -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; | |||
@@ -57,6 +58,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. | |||
*/ | |||
@@ -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); | |||
} | |||
} |
@@ -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 | |||
*/ |
@@ -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"; | |||
} |
@@ -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); | |||
} | |||
/** |
@@ -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 |
@@ -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", |
@@ -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")); |
@@ -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)); | |||
} | |||
} |
@@ -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); |