com.vaadin.v7.client.ui.tree.TreeConnector Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vaadin-compatibility-client Show documentation
Show all versions of vaadin-compatibility-client Show documentation
Vaadin 7 compatibility package for Vaadin 8
/*
* Copyright (C) 2000-2024 Vaadin Ltd
*
* This program is available under Vaadin Commercial License and Service Terms.
*
* See for the full
* license.
*/
package com.vaadin.v7.client.ui.tree;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.google.gwt.aria.client.Roles;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.EventTarget;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.BrowserInfo;
import com.vaadin.client.Paintable;
import com.vaadin.client.TooltipInfo;
import com.vaadin.client.UIDL;
import com.vaadin.client.WidgetUtil;
import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.MultiSelectMode;
import com.vaadin.v7.client.ui.AbstractLegacyComponentConnector;
import com.vaadin.v7.client.ui.VTree;
import com.vaadin.v7.client.ui.VTree.TreeNode;
import com.vaadin.v7.shared.ui.tree.TreeConstants;
import com.vaadin.v7.shared.ui.tree.TreeServerRpc;
import com.vaadin.v7.shared.ui.tree.TreeState;
import com.vaadin.v7.ui.Tree;
@Connect(Tree.class)
public class TreeConnector extends AbstractLegacyComponentConnector
implements Paintable {
protected final Map tooltipMap = new HashMap();
@Override
protected void init() {
getWidget().connector = this;
}
@Override
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
if (!isRealUpdate(uidl)) {
return;
}
getWidget().rendering = true;
getWidget().client = client;
if (uidl.hasAttribute("partialUpdate")) {
handleUpdate(uidl);
// IE8 is no longer supported with Vaadin 8
getWidget().rendering = false;
return;
}
getWidget().paintableId = uidl.getId();
getWidget().immediate = getState().immediate;
getWidget().disabled = !isEnabled();
getWidget().readonly = isReadOnly();
getWidget().dragMode = uidl.hasAttribute("dragMode")
? uidl.getIntAttribute("dragMode")
: 0;
getWidget().isNullSelectionAllowed = uidl
.getBooleanAttribute("nullselect");
getWidget().isHtmlContentAllowed = uidl
.getBooleanAttribute(TreeConstants.ATTRIBUTE_HTML_ALLOWED);
if (uidl.hasAttribute("alb")) {
getWidget().bodyActionKeys = uidl.getStringArrayAttribute("alb");
}
getWidget().body.clear();
// clear out any references to nodes that no longer are attached
getWidget().clearNodeToKeyMap();
tooltipMap.clear();
TreeNode childTree = null;
UIDL childUidl = null;
for (final Object child : uidl) {
childUidl = (UIDL) child;
if ("actions".equals(childUidl.getTag())) {
updateActionMap(childUidl);
continue;
} else if ("-ac".equals(childUidl.getTag())) {
getWidget().updateDropHandler(childUidl);
continue;
}
childTree = getWidget().new TreeNode();
getConnection().getVTooltip().connectHandlersToWidget(childTree);
updateNodeFromUIDL(childTree, childUidl, 1);
getWidget().body.add(childTree);
childTree.addStyleDependentName("root");
childTree.childNodeContainer.addStyleDependentName("root");
}
if (childTree != null && childUidl != null) {
boolean leaf = !childUidl.getTag().equals("node");
childTree.addStyleDependentName(leaf ? "leaf-last" : "last");
childTree.childNodeContainer.addStyleDependentName("last");
}
final String selectMode = uidl.getStringAttribute("selectmode");
getWidget().selectable = !"none".equals(selectMode);
getWidget().isMultiselect = "multi".equals(selectMode);
if (getWidget().isMultiselect) {
Roles.getTreeRole().setAriaMultiselectableProperty(
getWidget().getElement(), true);
if (BrowserInfo.get().isTouchDevice()) {
// Always use the simple mode for touch devices that do not have
// shift/ctrl keys (#8595)
getWidget().multiSelectMode = MultiSelectMode.SIMPLE;
} else {
getWidget().multiSelectMode = MultiSelectMode
.valueOf(uidl.getStringAttribute("multiselectmode"));
}
} else {
Roles.getTreeRole().setAriaMultiselectableProperty(
getWidget().getElement(), false);
}
getWidget().selectedIds = uidl.getStringArrayVariableAsSet("selected");
// Update lastSelection and focusedNode to point to *actual* nodes again
// after the old ones have been cleared from the body. This fixes focus
// and keyboard navigation issues as described in #7057 and other
// tickets.
if (getWidget().lastSelection != null) {
getWidget().lastSelection = getWidget()
.getNodeByKey(getWidget().lastSelection.key);
}
if (getWidget().focusedNode != null) {
Set selectedIds = getWidget().selectedIds;
// If the focused node is not between the selected nodes, we need to
// refresh the focused node to prevent an undesired scroll. #12618.
if (!selectedIds.isEmpty()
&& !selectedIds.contains(getWidget().focusedNode.key)) {
String keySelectedId = selectedIds.iterator().next();
TreeNode nodeToSelect = getWidget().getNodeByKey(keySelectedId);
getWidget().setFocusedNode(nodeToSelect);
} else {
getWidget().setFocusedNode(
getWidget().getNodeByKey(getWidget().focusedNode.key));
}
}
if (getWidget().lastSelection == null && getWidget().focusedNode == null
&& !getWidget().selectedIds.isEmpty()) {
getWidget().setFocusedNode(getWidget()
.getNodeByKey(getWidget().selectedIds.iterator().next()));
getWidget().focusedNode.setFocused(false);
}
// IE8 is no longer supported with Vaadin 8
getWidget().rendering = false;
}
@Override
public void onStateChanged(StateChangeEvent stateChangeEvent) {
super.onStateChanged(stateChangeEvent);
// VTree does not implement Focusable
getWidget().setTabIndex(getState().tabIndex);
}
@Override
public VTree getWidget() {
return (VTree) super.getWidget();
}
private void handleUpdate(UIDL uidl) {
final TreeNode rootNode = getWidget()
.getNodeByKey(uidl.getStringAttribute("rootKey"));
if (rootNode != null) {
if (!rootNode.getState()) {
// expanding node happened server side
rootNode.setState(true, false);
}
String levelPropertyString = Roles.getTreeitemRole()
.getAriaLevelProperty(rootNode.getElement());
int levelProperty;
try {
levelProperty = Integer.valueOf(levelPropertyString);
} catch (NumberFormatException e) {
levelProperty = 1;
getLogger().log(Level.SEVERE,
e.getMessage() == null ? "" : e.getMessage(), e);
}
renderChildNodes(rootNode, (Iterator) uidl.iterator(),
levelProperty + 1);
}
}
/**
* Registers action for the root and also for individual nodes
*
* @param uidl
*/
private void updateActionMap(UIDL uidl) {
for (final Object child : uidl) {
final UIDL action = (UIDL) child;
final String key = action.getStringAttribute("key");
final String caption = action
.getStringAttribute(TreeConstants.ATTRIBUTE_ACTION_CAPTION);
String iconUrl = null;
if (action.hasAttribute(TreeConstants.ATTRIBUTE_ACTION_ICON)) {
iconUrl = getConnection()
.translateVaadinUri(action.getStringAttribute(
TreeConstants.ATTRIBUTE_ACTION_ICON));
}
getWidget().registerAction(key, caption, iconUrl);
}
}
public void updateNodeFromUIDL(TreeNode treeNode, UIDL uidl, int level) {
Roles.getTreeitemRole().setAriaLevelProperty(treeNode.getElement(),
level);
String nodeKey = uidl.getStringAttribute("key");
String caption = uidl
.getStringAttribute(TreeConstants.ATTRIBUTE_NODE_CAPTION);
if (getWidget().isHtmlContentAllowed) {
treeNode.setHtml(caption);
} else {
treeNode.setText(caption);
}
treeNode.key = nodeKey;
getWidget().registerNode(treeNode);
if (uidl.hasAttribute("al")) {
treeNode.actionKeys = uidl.getStringArrayAttribute("al");
}
if (uidl.getTag().equals("node")) {
if (uidl.getChildCount() == 0) {
treeNode.childNodeContainer.setVisible(false);
} else {
renderChildNodes(treeNode, (Iterator) uidl.iterator(),
level + 1);
treeNode.childrenLoaded = true;
}
} else {
treeNode.addStyleName(TreeNode.CLASSNAME + "-leaf");
}
if (uidl.hasAttribute(TreeConstants.ATTRIBUTE_NODE_STYLE)) {
treeNode.setNodeStyleName(uidl
.getStringAttribute(TreeConstants.ATTRIBUTE_NODE_STYLE));
}
String description = uidl.getStringAttribute("descr");
if (description != null) {
tooltipMap.put(treeNode,
new TooltipInfo(description, null, treeNode));
}
if (uidl.getBooleanAttribute("expanded") && !treeNode.getState()) {
treeNode.setState(true, false);
}
if (uidl.getBooleanAttribute("selected")) {
treeNode.setSelected(true);
// ensure that identifier is in selectedIds array (this may be a
// partial update)
getWidget().selectedIds.add(nodeKey);
}
String iconUrl = uidl
.getStringAttribute(TreeConstants.ATTRIBUTE_NODE_ICON);
String iconAltText = uidl
.getStringAttribute(TreeConstants.ATTRIBUTE_NODE_ICON_ALT);
treeNode.setIcon(iconUrl, iconAltText);
}
void renderChildNodes(TreeNode containerNode, Iterator i, int level) {
containerNode.childNodeContainer.clear();
containerNode.childNodeContainer.setVisible(true);
while (i.hasNext()) {
final UIDL childUidl = i.next();
// actions are in bit weird place, don't mix them with children,
// but current node's actions
if ("actions".equals(childUidl.getTag())) {
updateActionMap(childUidl);
continue;
}
final TreeNode childTree = getWidget().new TreeNode();
getConnection().getVTooltip().connectHandlersToWidget(childTree);
updateNodeFromUIDL(childTree, childUidl, level);
containerNode.childNodeContainer.add(childTree);
if (!i.hasNext()) {
childTree.addStyleDependentName(
childTree.isLeaf() ? "leaf-last" : "last");
childTree.childNodeContainer.addStyleDependentName("last");
}
}
containerNode.childrenLoaded = true;
}
@Override
public boolean isReadOnly() {
return super.isReadOnly() || getState().propertyReadOnly;
}
@Override
public TreeState getState() {
return (TreeState) super.getState();
}
@Override
public TooltipInfo getTooltipInfo(Element element) {
TooltipInfo info = null;
// Try to find a tooltip for a node
if (element != getWidget().getElement()) {
Object node = WidgetUtil.findWidget(element, TreeNode.class);
if (node != null) {
TreeNode tnode = (TreeNode) node;
if (tnode.isCaptionElement(element)) {
info = tooltipMap.get(tnode);
}
}
}
// If no tooltip found for the node or if the target was not a node, use
// the default tooltip
if (info == null) {
info = super.getTooltipInfo(element);
}
return info;
}
@Override
public boolean hasTooltip() {
/*
* Item tooltips are not processed until updateFromUIDL, so we can't be
* sure that there are no tooltips during onStateChange when this method
* is used.
*/
return true;
}
@Override
protected void sendContextClickEvent(MouseEventDetails details,
EventTarget eventTarget) {
if (!Element.is(eventTarget)) {
return;
}
Element e = Element.as(eventTarget);
String key = null;
if (getWidget().body.getElement().isOrHasChild(e)) {
TreeNode t = WidgetUtil.findWidget(e, TreeNode.class);
if (t != null) {
key = t.key;
}
}
getRpcProxy(TreeServerRpc.class).contextClick(key, details);
WidgetUtil.clearTextSelection();
}
private static Logger getLogger() {
return Logger.getLogger(TreeConnector.class.getName());
}
}