aboutsummaryrefslogtreecommitdiffstats
path: root/server/src/com/vaadin/ui/Tree.java
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/com/vaadin/ui/Tree.java')
-rw-r--r--server/src/com/vaadin/ui/Tree.java1981
1 files changed, 0 insertions, 1981 deletions
diff --git a/server/src/com/vaadin/ui/Tree.java b/server/src/com/vaadin/ui/Tree.java
deleted file mode 100644
index 5e6ac55027..0000000000
--- a/server/src/com/vaadin/ui/Tree.java
+++ /dev/null
@@ -1,1981 +0,0 @@
-/*
- * Copyright 2000-2014 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.ui;
-
-import java.io.Serializable;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
-import java.util.Map;
-import java.util.Set;
-import java.util.Stack;
-import java.util.StringTokenizer;
-
-import org.jsoup.nodes.Element;
-
-import com.vaadin.data.Container;
-import com.vaadin.data.Item;
-import com.vaadin.data.util.ContainerHierarchicalWrapper;
-import com.vaadin.data.util.HierarchicalContainer;
-import com.vaadin.event.Action;
-import com.vaadin.event.Action.Handler;
-import com.vaadin.event.ContextClickEvent;
-import com.vaadin.event.DataBoundTransferable;
-import com.vaadin.event.ItemClickEvent;
-import com.vaadin.event.ItemClickEvent.ItemClickListener;
-import com.vaadin.event.ItemClickEvent.ItemClickNotifier;
-import com.vaadin.event.Transferable;
-import com.vaadin.event.dd.DragAndDropEvent;
-import com.vaadin.event.dd.DragSource;
-import com.vaadin.event.dd.DropHandler;
-import com.vaadin.event.dd.DropTarget;
-import com.vaadin.event.dd.TargetDetails;
-import com.vaadin.event.dd.acceptcriteria.ClientSideCriterion;
-import com.vaadin.event.dd.acceptcriteria.ServerSideCriterion;
-import com.vaadin.event.dd.acceptcriteria.TargetDetailIs;
-import com.vaadin.server.KeyMapper;
-import com.vaadin.server.PaintException;
-import com.vaadin.server.PaintTarget;
-import com.vaadin.server.Resource;
-import com.vaadin.shared.MouseEventDetails;
-import com.vaadin.shared.ui.MultiSelectMode;
-import com.vaadin.shared.ui.dd.VerticalDropLocation;
-import com.vaadin.shared.ui.tree.TreeConstants;
-import com.vaadin.shared.ui.tree.TreeServerRpc;
-import com.vaadin.shared.ui.tree.TreeState;
-import com.vaadin.ui.declarative.DesignAttributeHandler;
-import com.vaadin.ui.declarative.DesignContext;
-import com.vaadin.ui.declarative.DesignException;
-import com.vaadin.util.ReflectTools;
-
-/**
- * Tree component. A Tree can be used to select an item (or multiple items) from
- * a hierarchical set of items.
- *
- * @author Vaadin Ltd.
- * @since 3.0
- */
-@SuppressWarnings({ "serial", "deprecation" })
-public class Tree extends AbstractSelect implements Container.Hierarchical,
- Action.Container, ItemClickNotifier, DragSource, DropTarget {
-
- /**
- * ContextClickEvent for the Tree Component.
- *
- * @since 7.6
- */
- public static class TreeContextClickEvent extends ContextClickEvent {
-
- private final Object itemId;
-
- public TreeContextClickEvent(Tree source, Object itemId,
- MouseEventDetails mouseEventDetails) {
- super(source, mouseEventDetails);
- this.itemId = itemId;
- }
-
- @Override
- public Tree getComponent() {
- return (Tree) super.getComponent();
- }
-
- /**
- * Returns the item id of context clicked row.
- *
- * @return item id of clicked row; <code>null</code> if no row is
- * present at the location
- */
- public Object getItemId() {
- return itemId;
- }
- }
-
- /* Private members */
-
- private static final String NULL_ALT_EXCEPTION_MESSAGE = "Parameter 'altText' needs to be non null";
-
- /**
- * Item icons alt texts.
- */
- private final HashMap<Object, String> itemIconAlts = new HashMap<Object, String>();
-
- /**
- * Set of expanded nodes.
- */
- private HashSet<Object> expanded = new HashSet<Object>();
-
- /**
- * List of action handlers.
- */
- private LinkedList<Action.Handler> actionHandlers = null;
-
- /**
- * Action mapper.
- */
- private KeyMapper<Action> actionMapper = null;
-
- /**
- * Is the tree selectable on the client side.
- */
- private boolean selectable = true;
-
- /**
- * Flag to indicate sub-tree loading
- */
- private boolean partialUpdate = false;
-
- /**
- * Holds a itemId which was recently expanded
- */
- private Object expandedItemId;
-
- /**
- * a flag which indicates initial paint. After this flag set true partial
- * updates are allowed.
- */
- private boolean initialPaint = true;
-
- /**
- * Item tooltip generator
- */
- private ItemDescriptionGenerator itemDescriptionGenerator;
-
- /**
- * Supported drag modes for Tree.
- */
- public enum TreeDragMode {
- /**
- * When drag mode is NONE, dragging from Tree is not supported. Browsers
- * may still support selecting text/icons from Tree which can initiate
- * HTML 5 style drag and drop operation.
- */
- NONE,
- /**
- * When drag mode is NODE, users can initiate drag from Tree nodes that
- * represent {@link Item}s in from the backed {@link Container}.
- */
- NODE
- // , SUBTREE
- }
-
- private TreeDragMode dragMode = TreeDragMode.NONE;
-
- private MultiSelectMode multiSelectMode = MultiSelectMode.DEFAULT;
-
- /* Tree constructors */
-
- /**
- * Creates a new empty tree.
- */
- public Tree() {
- this(null);
-
- registerRpc(new TreeServerRpc() {
- @Override
- public void contextClick(String rowKey, MouseEventDetails details) {
- fireEvent(new TreeContextClickEvent(Tree.this,
- itemIdMapper.get(rowKey), details));
- }
- });
- }
-
- /**
- * Creates a new empty tree with caption.
- *
- * @param caption
- */
- public Tree(String caption) {
- this(caption, new HierarchicalContainer());
- }
-
- /**
- * Creates a new tree with caption and connect it to a Container.
- *
- * @param caption
- * @param dataSource
- */
- public Tree(String caption, Container dataSource) {
- super(caption, dataSource);
- }
-
- @Override
- public void setItemIcon(Object itemId, Resource icon) {
- setItemIcon(itemId, icon, "");
- }
-
- /**
- * Sets the icon for an item.
- *
- * @param itemId
- * the id of the item to be assigned an icon.
- * @param icon
- * the icon to use or null.
- *
- * @param altText
- * the alternative text for the icon
- */
- public void setItemIcon(Object itemId, Resource icon, String altText) {
- if (itemId != null) {
- super.setItemIcon(itemId, icon);
-
- if (icon == null) {
- itemIconAlts.remove(itemId);
- } else if (altText == null) {
- throw new IllegalArgumentException(NULL_ALT_EXCEPTION_MESSAGE);
- } else {
- itemIconAlts.put(itemId, altText);
- }
- markAsDirty();
- }
- }
-
- /**
- * Set the alternate text for an item.
- *
- * Used when the item has an icon.
- *
- * @param itemId
- * the id of the item to be assigned an icon.
- * @param altText
- * the alternative text for the icon
- */
- public void setItemIconAlternateText(Object itemId, String altText) {
- if (itemId != null) {
- if (altText == null) {
- throw new IllegalArgumentException(NULL_ALT_EXCEPTION_MESSAGE);
- } else {
- itemIconAlts.put(itemId, altText);
- }
- }
- }
-
- /**
- * Return the alternate text of an icon in a tree item.
- *
- * @param itemId
- * Object with the ID of the item
- * @return String with the alternate text of the icon, or null when no icon
- * was set
- */
- public String getItemIconAlternateText(Object itemId) {
- String storedAlt = itemIconAlts.get(itemId);
- return storedAlt == null ? "" : storedAlt;
- }
-
- /* Expanding and collapsing */
-
- /**
- * Check is an item is expanded
- *
- * @param itemId
- * the item id.
- * @return true iff the item is expanded.
- */
- public boolean isExpanded(Object itemId) {
- return expanded.contains(itemId);
- }
-
- /**
- * Expands an item.
- *
- * @param itemId
- * the item id.
- * @return True iff the expand operation succeeded
- */
- public boolean expandItem(Object itemId) {
- boolean success = expandItem(itemId, true);
- markAsDirty();
- return success;
- }
-
- /**
- * Expands an item.
- *
- * @param itemId
- * the item id.
- * @param sendChildTree
- * flag to indicate if client needs subtree or not (may be
- * cached)
- * @return True if the expand operation succeeded
- */
- private boolean expandItem(Object itemId, boolean sendChildTree) {
-
- // Succeeds if the node is already expanded
- if (isExpanded(itemId)) {
- return true;
- }
-
- // Nodes that can not have children are not expandable
- if (!areChildrenAllowed(itemId)) {
- return false;
- }
-
- // Expands
- expanded.add(itemId);
-
- expandedItemId = itemId;
- if (initialPaint) {
- markAsDirty();
- } else if (sendChildTree) {
- requestPartialRepaint();
- }
- fireExpandEvent(itemId);
-
- return true;
- }
-
- @Override
- public void markAsDirty() {
- super.markAsDirty();
- partialUpdate = false;
- }
-
- private void requestPartialRepaint() {
- super.markAsDirty();
- partialUpdate = true;
- }
-
- /**
- * Expands the items recursively
- *
- * Expands all the children recursively starting from an item. Operation
- * succeeds only if all expandable items are expanded.
- *
- * @param startItemId
- * @return True iff the expand operation succeeded
- */
- public boolean expandItemsRecursively(Object startItemId) {
-
- boolean result = true;
-
- // Initial stack
- final Stack<Object> todo = new Stack<Object>();
- todo.add(startItemId);
-
- // Expands recursively
- while (!todo.isEmpty()) {
- final Object id = todo.pop();
- if (areChildrenAllowed(id) && !expandItem(id, false)) {
- result = false;
- }
- if (hasChildren(id)) {
- todo.addAll(getChildren(id));
- }
- }
- markAsDirty();
- return result;
- }
-
- /**
- * Collapses an item.
- *
- * @param itemId
- * the item id.
- * @return True iff the collapse operation succeeded
- */
- public boolean collapseItem(Object itemId) {
-
- // Succeeds if the node is already collapsed
- if (!isExpanded(itemId)) {
- return true;
- }
-
- // Collapse
- expanded.remove(itemId);
- markAsDirty();
- fireCollapseEvent(itemId);
-
- return true;
- }
-
- /**
- * Collapses the items recursively.
- *
- * Collapse all the children recursively starting from an item. Operation
- * succeeds only if all expandable items are collapsed.
- *
- * @param startItemId
- * @return True iff the collapse operation succeeded
- */
- public boolean collapseItemsRecursively(Object startItemId) {
-
- boolean result = true;
-
- // Initial stack
- final Stack<Object> todo = new Stack<Object>();
- todo.add(startItemId);
-
- // Collapse recursively
- while (!todo.isEmpty()) {
- final Object id = todo.pop();
- if (areChildrenAllowed(id) && !collapseItem(id)) {
- result = false;
- }
- if (hasChildren(id)) {
- todo.addAll(getChildren(id));
- }
- }
-
- return result;
- }
-
- /**
- * Returns the current selectable state. Selectable determines if the a node
- * can be selected on the client side. Selectable does not affect
- * {@link #setValue(Object)} or {@link #select(Object)}.
- *
- * <p>
- * The tree is selectable by default.
- * </p>
- *
- * @return the current selectable state.
- */
- public boolean isSelectable() {
- return selectable;
- }
-
- /**
- * Sets the selectable state. Selectable determines if the a node can be
- * selected on the client side. Selectable does not affect
- * {@link #setValue(Object)} or {@link #select(Object)}.
- *
- * <p>
- * The tree is selectable by default.
- * </p>
- *
- * @param selectable
- * The new selectable state.
- */
- public void setSelectable(boolean selectable) {
- if (this.selectable != selectable) {
- this.selectable = selectable;
- markAsDirty();
- }
- }
-
- /**
- * Sets the behavior of the multiselect mode
- *
- * @param mode
- * The mode to set
- */
- public void setMultiselectMode(MultiSelectMode mode) {
- if (multiSelectMode != mode && mode != null) {
- multiSelectMode = mode;
- markAsDirty();
- }
- }
-
- /**
- * Returns the mode the multiselect is in. The mode controls how
- * multiselection can be done.
- *
- * @return The mode
- */
- public MultiSelectMode getMultiselectMode() {
- return multiSelectMode;
- }
-
- /* Component API */
-
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.ui.AbstractSelect#changeVariables(java.lang.Object,
- * java.util.Map)
- */
- @Override
- public void changeVariables(Object source, Map<String, Object> variables) {
-
- if (variables.containsKey("clickedKey")) {
- String key = (String) variables.get("clickedKey");
-
- Object id = itemIdMapper.get(key);
- MouseEventDetails details = MouseEventDetails
- .deSerialize((String) variables.get("clickEvent"));
- Item item = getItem(id);
- if (item != null) {
- fireEvent(new ItemClickEvent(this, item, id, null, details));
- }
- }
-
- if (!isSelectable() && variables.containsKey("selected")) {
- // Not-selectable is a special case, AbstractSelect does not support
- // TODO could be optimized.
- variables = new HashMap<String, Object>(variables);
- variables.remove("selected");
- }
-
- // Collapses the nodes
- if (variables.containsKey("collapse")) {
- final String[] keys = (String[]) variables.get("collapse");
- for (int i = 0; i < keys.length; i++) {
- final Object id = itemIdMapper.get(keys[i]);
- if (id != null && isExpanded(id)) {
- expanded.remove(id);
- if (expandedItemId == id) {
- expandedItemId = null;
- }
- fireCollapseEvent(id);
- }
- }
- }
-
- // Expands the nodes
- if (variables.containsKey("expand")) {
- boolean sendChildTree = false;
- if (variables.containsKey("requestChildTree")) {
- sendChildTree = true;
- }
- final String[] keys = (String[]) variables.get("expand");
- for (int i = 0; i < keys.length; i++) {
- final Object id = itemIdMapper.get(keys[i]);
- if (id != null) {
- expandItem(id, sendChildTree);
- }
- }
- }
-
- // AbstractSelect cannot handle multiselection so we handle
- // it ourself
- if (variables.containsKey("selected") && isMultiSelect()
- && multiSelectMode == MultiSelectMode.DEFAULT) {
- handleSelectedItems(variables);
- variables = new HashMap<String, Object>(variables);
- variables.remove("selected");
- }
-
- // Selections are handled by the select component
- super.changeVariables(source, variables);
-
- // Actions
- if (variables.containsKey("action")) {
- final StringTokenizer st = new StringTokenizer(
- (String) variables.get("action"), ",");
- if (st.countTokens() == 2) {
- final Object itemId = itemIdMapper.get(st.nextToken());
- final Action action = actionMapper.get(st.nextToken());
- if (action != null && (itemId == null || containsId(itemId))
- && actionHandlers != null) {
- for (Handler ah : actionHandlers) {
- ah.handleAction(action, this, itemId);
- }
- }
- }
- }
- }
-
- /**
- * Handles the selection
- *
- * @param variables
- * The variables sent to the server from the client
- */
- private void handleSelectedItems(Map<String, Object> variables) {
- final String[] ka = (String[]) variables.get("selected");
-
- // Converts the key-array to id-set
- final LinkedList<Object> s = new LinkedList<Object>();
- for (int i = 0; i < ka.length; i++) {
- final Object id = itemIdMapper.get(ka[i]);
- if (!isNullSelectionAllowed()
- && (id == null || id == getNullSelectionItemId())) {
- // skip empty selection if nullselection is not allowed
- markAsDirty();
- } else if (id != null && containsId(id)) {
- s.add(id);
- }
- }
-
- if (!isNullSelectionAllowed() && s.size() < 1) {
- // empty selection not allowed, keep old value
- markAsDirty();
- return;
- }
-
- setValue(s, true);
- }
-
- /**
- * Paints any needed component-specific things to the given UIDL stream.
- *
- * @see com.vaadin.ui.AbstractComponent#paintContent(PaintTarget)
- */
- @Override
- public void paintContent(PaintTarget target) throws PaintException {
- initialPaint = false;
-
- if (partialUpdate) {
- target.addAttribute("partialUpdate", true);
- target.addAttribute("rootKey", itemIdMapper.key(expandedItemId));
- } else {
- getCaptionChangeListener().clear();
-
- // The tab ordering number
- if (getTabIndex() > 0) {
- target.addAttribute("tabindex", getTabIndex());
- }
-
- // Paint tree attributes
- if (isSelectable()) {
- target.addAttribute("selectmode", (isMultiSelect() ? "multi"
- : "single"));
- if (isMultiSelect()) {
- target.addAttribute("multiselectmode",
- multiSelectMode.toString());
- }
- } else {
- target.addAttribute("selectmode", "none");
- }
- if (isNewItemsAllowed()) {
- target.addAttribute("allownewitem", true);
- }
-
- if (isNullSelectionAllowed()) {
- target.addAttribute("nullselect", true);
- }
-
- if (dragMode != TreeDragMode.NONE) {
- target.addAttribute("dragMode", dragMode.ordinal());
- }
-
- if (isHtmlContentAllowed()) {
- target.addAttribute(TreeConstants.ATTRIBUTE_HTML_ALLOWED, true);
- }
-
- }
-
- // Initialize variables
- final Set<Action> actionSet = new LinkedHashSet<Action>();
-
- // rendered selectedKeys
- LinkedList<String> selectedKeys = new LinkedList<String>();
-
- final LinkedList<String> expandedKeys = new LinkedList<String>();
-
- // Iterates through hierarchical tree using a stack of iterators
- final Stack<Iterator<?>> iteratorStack = new Stack<Iterator<?>>();
- Collection<?> ids;
- if (partialUpdate) {
- ids = getChildren(expandedItemId);
- } else {
- ids = rootItemIds();
- }
-
- if (ids != null) {
- iteratorStack.push(ids.iterator());
- }
-
- /*
- * Body actions - Actions which has the target null and can be invoked
- * by right clicking on the Tree body
- */
- if (actionHandlers != null) {
- final ArrayList<String> keys = new ArrayList<String>();
- for (Handler ah : actionHandlers) {
-
- // Getting action for the null item, which in this case
- // means the body item
- final Action[] aa = ah.getActions(null, this);
- if (aa != null) {
- for (int ai = 0; ai < aa.length; ai++) {
- final String akey = actionMapper.key(aa[ai]);
- actionSet.add(aa[ai]);
- keys.add(akey);
- }
- }
- }
- target.addAttribute("alb", keys.toArray());
- }
-
- while (!iteratorStack.isEmpty()) {
-
- // Gets the iterator for current tree level
- final Iterator<?> i = iteratorStack.peek();
-
- // If the level is finished, back to previous tree level
- if (!i.hasNext()) {
-
- // Removes used iterator from the stack
- iteratorStack.pop();
-
- // Closes node
- if (!iteratorStack.isEmpty()) {
- target.endTag("node");
- }
- }
-
- // Adds the item on current level
- else {
- final Object itemId = i.next();
-
- // Starts the item / node
- final boolean isNode = areChildrenAllowed(itemId);
- if (isNode) {
- target.startTag("node");
- } else {
- target.startTag("leaf");
- }
-
- if (itemStyleGenerator != null) {
- String stylename = itemStyleGenerator
- .getStyle(this, itemId);
- if (stylename != null) {
- target.addAttribute(TreeConstants.ATTRIBUTE_NODE_STYLE,
- stylename);
- }
- }
-
- if (itemDescriptionGenerator != null) {
- String description = itemDescriptionGenerator
- .generateDescription(this, itemId, null);
- if (description != null && !description.equals("")) {
- target.addAttribute("descr", description);
- }
- }
-
- // Adds the attributes
- target.addAttribute(TreeConstants.ATTRIBUTE_NODE_CAPTION,
- getItemCaption(itemId));
- final Resource icon = getItemIcon(itemId);
- if (icon != null) {
- target.addAttribute(TreeConstants.ATTRIBUTE_NODE_ICON,
- getItemIcon(itemId));
- target.addAttribute(TreeConstants.ATTRIBUTE_NODE_ICON_ALT,
- getItemIconAlternateText(itemId));
- }
- final String key = itemIdMapper.key(itemId);
- target.addAttribute("key", key);
- if (isSelected(itemId)) {
- target.addAttribute("selected", true);
- selectedKeys.add(key);
- }
- if (areChildrenAllowed(itemId) && isExpanded(itemId)) {
- target.addAttribute("expanded", true);
- expandedKeys.add(key);
- }
-
- // Add caption change listener
- getCaptionChangeListener().addNotifierForItem(itemId);
-
- // Actions
- if (actionHandlers != null) {
- final ArrayList<String> keys = new ArrayList<String>();
- final Iterator<Action.Handler> ahi = actionHandlers
- .iterator();
- while (ahi.hasNext()) {
- final Action[] aa = ahi.next().getActions(itemId, this);
- if (aa != null) {
- for (int ai = 0; ai < aa.length; ai++) {
- final String akey = actionMapper.key(aa[ai]);
- actionSet.add(aa[ai]);
- keys.add(akey);
- }
- }
- }
- target.addAttribute("al", keys.toArray());
- }
-
- // Adds the children if expanded, or close the tag
- if (isExpanded(itemId) && hasChildren(itemId)
- && areChildrenAllowed(itemId)) {
- iteratorStack.push(getChildren(itemId).iterator());
- } else {
- if (isNode) {
- target.endTag("node");
- } else {
- target.endTag("leaf");
- }
- }
- }
- }
-
- // Actions
- if (!actionSet.isEmpty()) {
- target.addVariable(this, "action", "");
- target.startTag("actions");
- final Iterator<Action> i = actionSet.iterator();
- while (i.hasNext()) {
- final Action a = i.next();
- target.startTag("action");
- if (a.getCaption() != null) {
- target.addAttribute(TreeConstants.ATTRIBUTE_ACTION_CAPTION,
- a.getCaption());
- }
- if (a.getIcon() != null) {
- target.addAttribute(TreeConstants.ATTRIBUTE_ACTION_ICON,
- a.getIcon());
- }
- target.addAttribute("key", actionMapper.key(a));
- target.endTag("action");
- }
- target.endTag("actions");
- }
-
- if (partialUpdate) {
- partialUpdate = false;
- } else {
- // Selected
- target.addVariable(this, "selected",
- selectedKeys.toArray(new String[selectedKeys.size()]));
-
- // Expand and collapse
- target.addVariable(this, "expand", new String[] {});
- target.addVariable(this, "collapse", new String[] {});
-
- // New items
- target.addVariable(this, "newitem", new String[] {});
-
- if (dropHandler != null) {
- dropHandler.getAcceptCriterion().paint(target);
- }
-
- }
- }
-
- /* Container.Hierarchical API */
-
- /**
- * Tests if the Item with given ID can have any children.
- *
- * @see com.vaadin.data.Container.Hierarchical#areChildrenAllowed(Object)
- */
- @Override
- public boolean areChildrenAllowed(Object itemId) {
- return ((Container.Hierarchical) items).areChildrenAllowed(itemId);
- }
-
- /**
- * Gets the IDs of all Items that are children of the specified Item.
- *
- * @see com.vaadin.data.Container.Hierarchical#getChildren(Object)
- */
- @Override
- public Collection<?> getChildren(Object itemId) {
- return ((Container.Hierarchical) items).getChildren(itemId);
- }
-
- /**
- * Gets the ID of the parent Item of the specified Item.
- *
- * @see com.vaadin.data.Container.Hierarchical#getParent(Object)
- */
- @Override
- public Object getParent(Object itemId) {
- return ((Container.Hierarchical) items).getParent(itemId);
- }
-
- /**
- * Tests if the Item specified with <code>itemId</code> has child Items.
- *
- * @see com.vaadin.data.Container.Hierarchical#hasChildren(Object)
- */
- @Override
- public boolean hasChildren(Object itemId) {
- return ((Container.Hierarchical) items).hasChildren(itemId);
- }
-
- /**
- * Tests if the Item specified with <code>itemId</code> is a root Item.
- *
- * @see com.vaadin.data.Container.Hierarchical#isRoot(Object)
- */
- @Override
- public boolean isRoot(Object itemId) {
- return ((Container.Hierarchical) items).isRoot(itemId);
- }
-
- /**
- * Gets the IDs of all Items in the container that don't have a parent.
- *
- * @see com.vaadin.data.Container.Hierarchical#rootItemIds()
- */
- @Override
- public Collection<?> rootItemIds() {
- return ((Container.Hierarchical) items).rootItemIds();
- }
-
- /**
- * Sets the given Item's capability to have children.
- *
- * @see com.vaadin.data.Container.Hierarchical#setChildrenAllowed(Object,
- * boolean)
- */
- @Override
- public boolean setChildrenAllowed(Object itemId, boolean areChildrenAllowed) {
- final boolean success = ((Container.Hierarchical) items)
- .setChildrenAllowed(itemId, areChildrenAllowed);
- if (success) {
- markAsDirty();
- }
- return success;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.data.Container.Hierarchical#setParent(java.lang.Object ,
- * java.lang.Object)
- */
- @Override
- public boolean setParent(Object itemId, Object newParentId) {
- final boolean success = ((Container.Hierarchical) items).setParent(
- itemId, newParentId);
- if (success) {
- markAsDirty();
- }
- return success;
- }
-
- /* Overriding select behavior */
-
- /**
- * Sets the Container that serves as the data source of the viewer.
- *
- * @see com.vaadin.data.Container.Viewer#setContainerDataSource(Container)
- */
- @Override
- public void setContainerDataSource(Container newDataSource) {
- if (newDataSource == null) {
- newDataSource = new HierarchicalContainer();
- }
-
- // Assure that the data source is ordered by making unordered
- // containers ordered by wrapping them
- if (Container.Hierarchical.class.isAssignableFrom(newDataSource
- .getClass())) {
- super.setContainerDataSource(newDataSource);
- } else {
- super.setContainerDataSource(new ContainerHierarchicalWrapper(
- newDataSource));
- }
-
- /*
- * Ensure previous expanded items are cleaned up if they don't exist in
- * the new container
- */
- if (expanded != null) {
- /*
- * We need to check that the expanded-field is not null since
- * setContainerDataSource() is called from the parent constructor
- * (AbstractSelect()) and at that time the expanded field is not yet
- * initialized.
- */
- cleanupExpandedItems();
- }
-
- }
-
- @Override
- public void containerItemSetChange(
- com.vaadin.data.Container.ItemSetChangeEvent event) {
- super.containerItemSetChange(event);
- if (getContainerDataSource() instanceof Filterable) {
- boolean hasFilters = !((Filterable) getContainerDataSource())
- .getContainerFilters().isEmpty();
- if (!hasFilters) {
- /*
- * If Container is not filtered then the itemsetchange is caused
- * by either adding or removing items to the container. To
- * prevent a memory leak we should cleanup the expanded list
- * from items which was removed.
- *
- * However, there will still be a leak if the container is
- * filtered to show only a subset of the items in the tree and
- * later unfiltered items are removed from the container. In
- * that case references to the unfiltered item ids will remain
- * in the expanded list until the Tree instance is removed and
- * the list is destroyed, or the container data source is
- * replaced/updated. To force the removal of the removed items
- * the application developer needs to a) remove the container
- * filters temporarly or b) re-apply the container datasource
- * using setContainerDataSource(getContainerDataSource())
- */
- cleanupExpandedItems();
- }
- }
-
- }
-
- /* Expand event and listener */
-
- /**
- * Event to fired when a node is expanded. ExapandEvent is fired when a node
- * is to be expanded. it can me used to dynamically fill the sub-nodes of
- * the node.
- *
- * @author Vaadin Ltd.
- * @since 3.0
- */
- public static class ExpandEvent extends Component.Event {
-
- private final Object expandedItemId;
-
- /**
- * New instance of options change event
- *
- * @param source
- * the Source of the event.
- * @param expandedItemId
- */
- public ExpandEvent(Component source, Object expandedItemId) {
- super(source);
- this.expandedItemId = expandedItemId;
- }
-
- /**
- * Node where the event occurred.
- *
- * @return the Source of the event.
- */
- public Object getItemId() {
- return expandedItemId;
- }
- }
-
- /**
- * Expand event listener.
- *
- * @author Vaadin Ltd.
- * @since 3.0
- */
- public interface ExpandListener extends Serializable {
-
- public static final Method EXPAND_METHOD = ReflectTools.findMethod(
- ExpandListener.class, "nodeExpand", ExpandEvent.class);
-
- /**
- * A node has been expanded.
- *
- * @param event
- * the Expand event.
- */
- public void nodeExpand(ExpandEvent event);
- }
-
- /**
- * Adds the expand listener.
- *
- * @param listener
- * the Listener to be added.
- */
- public void addExpandListener(ExpandListener listener) {
- addListener(ExpandEvent.class, listener, ExpandListener.EXPAND_METHOD);
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #addExpandListener(ExpandListener)}
- **/
- @Deprecated
- public void addListener(ExpandListener listener) {
- addExpandListener(listener);
- }
-
- /**
- * Removes the expand listener.
- *
- * @param listener
- * the Listener to be removed.
- */
- public void removeExpandListener(ExpandListener listener) {
- removeListener(ExpandEvent.class, listener,
- ExpandListener.EXPAND_METHOD);
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #removeExpandListener(ExpandListener)}
- **/
- @Deprecated
- public void removeListener(ExpandListener listener) {
- removeExpandListener(listener);
- }
-
- /**
- * Emits the expand event.
- *
- * @param itemId
- * the item id.
- */
- protected void fireExpandEvent(Object itemId) {
- fireEvent(new ExpandEvent(this, itemId));
- }
-
- /* Collapse event */
-
- /**
- * Collapse event
- *
- * @author Vaadin Ltd.
- * @since 3.0
- */
- public static class CollapseEvent extends Component.Event {
-
- private final Object collapsedItemId;
-
- /**
- * New instance of options change event.
- *
- * @param source
- * the Source of the event.
- * @param collapsedItemId
- */
- public CollapseEvent(Component source, Object collapsedItemId) {
- super(source);
- this.collapsedItemId = collapsedItemId;
- }
-
- /**
- * Gets tge Collapsed Item id.
- *
- * @return the collapsed item id.
- */
- public Object getItemId() {
- return collapsedItemId;
- }
- }
-
- /**
- * Collapse event listener.
- *
- * @author Vaadin Ltd.
- * @since 3.0
- */
- public interface CollapseListener extends Serializable {
-
- public static final Method COLLAPSE_METHOD = ReflectTools.findMethod(
- CollapseListener.class, "nodeCollapse", CollapseEvent.class);
-
- /**
- * A node has been collapsed.
- *
- * @param event
- * the Collapse event.
- */
- public void nodeCollapse(CollapseEvent event);
- }
-
- /**
- * Adds the collapse listener.
- *
- * @param listener
- * the Listener to be added.
- */
- public void addCollapseListener(CollapseListener listener) {
- addListener(CollapseEvent.class, listener,
- CollapseListener.COLLAPSE_METHOD);
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #addCollapseListener(CollapseListener)}
- **/
- @Deprecated
- public void addListener(CollapseListener listener) {
- addCollapseListener(listener);
- }
-
- /**
- * Removes the collapse listener.
- *
- * @param listener
- * the Listener to be removed.
- */
- public void removeCollapseListener(CollapseListener listener) {
- removeListener(CollapseEvent.class, listener,
- CollapseListener.COLLAPSE_METHOD);
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #removeCollapseListener(CollapseListener)}
- **/
- @Deprecated
- public void removeListener(CollapseListener listener) {
- removeCollapseListener(listener);
- }
-
- /**
- * Emits collapse event.
- *
- * @param itemId
- * the item id.
- */
- protected void fireCollapseEvent(Object itemId) {
- fireEvent(new CollapseEvent(this, itemId));
- }
-
- /* Action container */
-
- /**
- * Adds an action handler.
- *
- * @see com.vaadin.event.Action.Container#addActionHandler(Action.Handler)
- */
- @Override
- public void addActionHandler(Action.Handler actionHandler) {
-
- if (actionHandler != null) {
-
- if (actionHandlers == null) {
- actionHandlers = new LinkedList<Action.Handler>();
- actionMapper = new KeyMapper<Action>();
- }
-
- if (!actionHandlers.contains(actionHandler)) {
- actionHandlers.add(actionHandler);
- markAsDirty();
- }
- }
- }
-
- /**
- * Removes an action handler.
- *
- * @see com.vaadin.event.Action.Container#removeActionHandler(Action.Handler)
- */
- @Override
- public void removeActionHandler(Action.Handler actionHandler) {
-
- if (actionHandlers != null && actionHandlers.contains(actionHandler)) {
-
- actionHandlers.remove(actionHandler);
-
- if (actionHandlers.isEmpty()) {
- actionHandlers = null;
- actionMapper = null;
- }
-
- markAsDirty();
- }
- }
-
- /**
- * Removes all action handlers
- */
- public void removeAllActionHandlers() {
- actionHandlers = null;
- actionMapper = null;
- markAsDirty();
- }
-
- /**
- * Gets the visible item ids.
- *
- * @see com.vaadin.ui.Select#getVisibleItemIds()
- */
- @Override
- public Collection<?> getVisibleItemIds() {
-
- final LinkedList<Object> visible = new LinkedList<Object>();
-
- // Iterates trough hierarchical tree using a stack of iterators
- final Stack<Iterator<?>> iteratorStack = new Stack<Iterator<?>>();
- final Collection<?> ids = rootItemIds();
- if (ids != null) {
- iteratorStack.push(ids.iterator());
- }
- while (!iteratorStack.isEmpty()) {
-
- // Gets the iterator for current tree level
- final Iterator<?> i = iteratorStack.peek();
-
- // If the level is finished, back to previous tree level
- if (!i.hasNext()) {
-
- // Removes used iterator from the stack
- iteratorStack.pop();
- }
-
- // Adds the item on current level
- else {
- final Object itemId = i.next();
-
- visible.add(itemId);
-
- // Adds children if expanded, or close the tag
- if (isExpanded(itemId) && hasChildren(itemId)) {
- iteratorStack.push(getChildren(itemId).iterator());
- }
- }
- }
-
- return visible;
- }
-
- /**
- * Tree does not support <code>setNullSelectionItemId</code>.
- *
- * @see com.vaadin.ui.AbstractSelect#setNullSelectionItemId(java.lang.Object)
- */
- @Override
- public void setNullSelectionItemId(Object nullSelectionItemId)
- throws UnsupportedOperationException {
- if (nullSelectionItemId != null) {
- throw new UnsupportedOperationException();
- }
-
- }
-
- /**
- * Adding new items is not supported.
- *
- * @throws UnsupportedOperationException
- * if set to true.
- * @see com.vaadin.ui.Select#setNewItemsAllowed(boolean)
- */
- @Override
- public void setNewItemsAllowed(boolean allowNewOptions)
- throws UnsupportedOperationException {
- if (allowNewOptions) {
- throw new UnsupportedOperationException();
- }
- }
-
- private ItemStyleGenerator itemStyleGenerator;
-
- private DropHandler dropHandler;
-
- private boolean htmlContentAllowed;
-
- @Override
- public void addItemClickListener(ItemClickListener listener) {
- addListener(TreeConstants.ITEM_CLICK_EVENT_ID, ItemClickEvent.class,
- listener, ItemClickEvent.ITEM_CLICK_METHOD);
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #addItemClickListener(ItemClickListener)}
- **/
- @Override
- @Deprecated
- public void addListener(ItemClickListener listener) {
- addItemClickListener(listener);
- }
-
- @Override
- public void removeItemClickListener(ItemClickListener listener) {
- removeListener(TreeConstants.ITEM_CLICK_EVENT_ID, ItemClickEvent.class,
- listener);
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #removeItemClickListener(ItemClickListener)}
- **/
- @Override
- @Deprecated
- public void removeListener(ItemClickListener listener) {
- removeItemClickListener(listener);
- }
-
- /**
- * Sets the {@link ItemStyleGenerator} to be used with this tree.
- *
- * @param itemStyleGenerator
- * item style generator or null to remove generator
- */
- public void setItemStyleGenerator(ItemStyleGenerator itemStyleGenerator) {
- if (this.itemStyleGenerator != itemStyleGenerator) {
- this.itemStyleGenerator = itemStyleGenerator;
- markAsDirty();
- }
- }
-
- /**
- * @return the current {@link ItemStyleGenerator} for this tree. Null if
- * {@link ItemStyleGenerator} is not set.
- */
- public ItemStyleGenerator getItemStyleGenerator() {
- return itemStyleGenerator;
- }
-
- /**
- * ItemStyleGenerator can be used to add custom styles to tree items. The
- * CSS class name that will be added to the item content is
- * <tt>v-tree-node-[style name]</tt>.
- */
- public interface ItemStyleGenerator extends Serializable {
-
- /**
- * Called by Tree when an item is painted.
- *
- * @param source
- * the source Tree
- * @param itemId
- * The itemId of the item to be painted
- * @return The style name to add to this item. (the CSS class name will
- * be v-tree-node-[style name]
- */
- public abstract String getStyle(Tree source, Object itemId);
- }
-
- // Overriden so javadoc comes from Container.Hierarchical
- @Override
- public boolean removeItem(Object itemId)
- throws UnsupportedOperationException {
- return super.removeItem(itemId);
- }
-
- @Override
- public DropHandler getDropHandler() {
- return dropHandler;
- }
-
- public void setDropHandler(DropHandler dropHandler) {
- this.dropHandler = dropHandler;
- }
-
- /**
- * A {@link TargetDetails} implementation with Tree specific api.
- *
- * @since 6.3
- */
- public class TreeTargetDetails extends AbstractSelectTargetDetails {
-
- TreeTargetDetails(Map<String, Object> rawVariables) {
- super(rawVariables);
- }
-
- @Override
- public Tree getTarget() {
- return (Tree) super.getTarget();
- }
-
- /**
- * If the event is on a node that can not have children (see
- * {@link Tree#areChildrenAllowed(Object)}), this method returns the
- * parent item id of the target item (see {@link #getItemIdOver()} ).
- * The identifier of the parent node is also returned if the cursor is
- * on the top part of node. Else this method returns the same as
- * {@link #getItemIdOver()}.
- * <p>
- * In other words this method returns the identifier of the "folder"
- * into the drag operation is targeted.
- * <p>
- * If the method returns null, the current target is on a root node or
- * on other undefined area over the tree component.
- * <p>
- * The default Tree implementation marks the targetted tree node with
- * CSS classnames v-tree-node-dragfolder and
- * v-tree-node-caption-dragfolder (for the caption element).
- */
- public Object getItemIdInto() {
-
- Object itemIdOver = getItemIdOver();
- if (areChildrenAllowed(itemIdOver)
- && getDropLocation() == VerticalDropLocation.MIDDLE) {
- return itemIdOver;
- }
- return getParent(itemIdOver);
- }
-
- /**
- * If drop is targeted into "folder node" (see {@link #getItemIdInto()}
- * ), this method returns the item id of the node after the drag was
- * targeted. This method is useful when implementing drop into specific
- * location (between specific nodes) in tree.
- *
- * @return the id of the item after the user targets the drop or null if
- * "target" is a first item in node list (or the first in root
- * node list)
- */
- public Object getItemIdAfter() {
- Object itemIdOver = getItemIdOver();
- Object itemIdInto2 = getItemIdInto();
- if (itemIdOver.equals(itemIdInto2)) {
- return null;
- }
- VerticalDropLocation dropLocation = getDropLocation();
- if (VerticalDropLocation.TOP == dropLocation) {
- // if on top of the caption area, add before
- Collection<?> children;
- Object itemIdInto = getItemIdInto();
- if (itemIdInto != null) {
- // seek the previous from child list
- children = getChildren(itemIdInto);
- } else {
- children = rootItemIds();
- }
- Object ref = null;
- for (Object object : children) {
- if (object.equals(itemIdOver)) {
- return ref;
- }
- ref = object;
- }
- }
- return itemIdOver;
- }
-
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
- * com.vaadin.event.dd.DropTarget#translateDropTargetDetails(java.util.Map)
- */
- @Override
- public TreeTargetDetails translateDropTargetDetails(
- Map<String, Object> clientVariables) {
- return new TreeTargetDetails(clientVariables);
- }
-
- /**
- * Helper API for {@link TreeDropCriterion}
- *
- * @param itemId
- * @return
- */
- private String key(Object itemId) {
- return itemIdMapper.key(itemId);
- }
-
- /**
- * Sets the drag mode that controls how Tree behaves as a {@link DragSource}
- * .
- *
- * @param dragMode
- */
- public void setDragMode(TreeDragMode dragMode) {
- this.dragMode = dragMode;
- markAsDirty();
- }
-
- /**
- * @return the drag mode that controls how Tree behaves as a
- * {@link DragSource}.
- *
- * @see TreeDragMode
- */
- public TreeDragMode getDragMode() {
- return dragMode;
- }
-
- /**
- * Concrete implementation of {@link DataBoundTransferable} for data
- * transferred from a tree.
- *
- * @see {@link DataBoundTransferable}.
- *
- * @since 6.3
- */
- protected class TreeTransferable extends DataBoundTransferable {
-
- public TreeTransferable(Component sourceComponent,
- Map<String, Object> rawVariables) {
- super(sourceComponent, rawVariables);
- }
-
- @Override
- public Object getItemId() {
- return getData("itemId");
- }
-
- @Override
- public Object getPropertyId() {
- return getItemCaptionPropertyId();
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.event.dd.DragSource#getTransferable(java.util.Map)
- */
- @Override
- public Transferable getTransferable(Map<String, Object> payload) {
- TreeTransferable transferable = new TreeTransferable(this, payload);
- // updating drag source variables
- Object object = payload.get("itemId");
- if (object != null) {
- transferable.setData("itemId", itemIdMapper.get((String) object));
- }
-
- return transferable;
- }
-
- /**
- * Lazy loading accept criterion for Tree. Accepted target nodes are loaded
- * from server once per drag and drop operation. Developer must override one
- * method that decides accepted tree nodes for the whole Tree.
- *
- * <p>
- * Initially pretty much no data is sent to client. On first required
- * criterion check (per drag request) the client side data structure is
- * initialized from server and no subsequent requests requests are needed
- * during that drag and drop operation.
- */
- public static abstract class TreeDropCriterion extends ServerSideCriterion {
-
- private Tree tree;
-
- private Set<Object> allowedItemIds;
-
- /*
- * (non-Javadoc)
- *
- * @see
- * com.vaadin.event.dd.acceptCriteria.ServerSideCriterion#getIdentifier
- * ()
- */
- @Override
- protected String getIdentifier() {
- return TreeDropCriterion.class.getCanonicalName();
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
- * com.vaadin.event.dd.acceptCriteria.AcceptCriterion#accepts(com.vaadin
- * .event.dd.DragAndDropEvent)
- */
- @Override
- public boolean accept(DragAndDropEvent dragEvent) {
- AbstractSelectTargetDetails dropTargetData = (AbstractSelectTargetDetails) dragEvent
- .getTargetDetails();
- tree = (Tree) dragEvent.getTargetDetails().getTarget();
- allowedItemIds = getAllowedItemIds(dragEvent, tree);
-
- return allowedItemIds.contains(dropTargetData.getItemIdOver());
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
- * com.vaadin.event.dd.acceptCriteria.AcceptCriterion#paintResponse(
- * com.vaadin.server.PaintTarget)
- */
- @Override
- public void paintResponse(PaintTarget target) throws PaintException {
- /*
- * send allowed nodes to client so subsequent requests can be
- * avoided
- */
- Object[] array = allowedItemIds.toArray();
- for (int i = 0; i < array.length; i++) {
- String key = tree.key(array[i]);
- array[i] = key;
- }
- target.addAttribute("allowedIds", array);
- }
-
- protected abstract Set<Object> getAllowedItemIds(
- DragAndDropEvent dragEvent, Tree tree);
-
- }
-
- /**
- * A criterion that accepts {@link Transferable} only directly on a tree
- * node that can have children.
- * <p>
- * Class is singleton, use {@link TargetItemAllowsChildren#get()} to get the
- * instance.
- *
- * @see Tree#setChildrenAllowed(Object, boolean)
- *
- * @since 6.3
- */
- public static class TargetItemAllowsChildren extends TargetDetailIs {
-
- private static TargetItemAllowsChildren instance = new TargetItemAllowsChildren();
-
- public static TargetItemAllowsChildren get() {
- return instance;
- }
-
- private TargetItemAllowsChildren() {
- super("itemIdOverIsNode", Boolean.TRUE);
- }
-
- /*
- * Uses enhanced server side check
- */
- @Override
- public boolean accept(DragAndDropEvent dragEvent) {
- try {
- // must be over tree node and in the middle of it (not top or
- // bottom
- // part)
- TreeTargetDetails eventDetails = (TreeTargetDetails) dragEvent
- .getTargetDetails();
-
- Object itemIdOver = eventDetails.getItemIdOver();
- if (!eventDetails.getTarget().areChildrenAllowed(itemIdOver)) {
- return false;
- }
- // return true if directly over
- return eventDetails.getDropLocation() == VerticalDropLocation.MIDDLE;
- } catch (Exception e) {
- return false;
- }
- }
-
- }
-
- /**
- * An accept criterion that checks the parent node (or parent hierarchy) for
- * the item identifier given in constructor. If the parent is found, content
- * is accepted. Criterion can be used to accepts drags on a specific sub
- * tree only.
- * <p>
- * The root items is also consider to be valid target.
- */
- public class TargetInSubtree extends ClientSideCriterion {
-
- private Object rootId;
- private int depthToCheck = -1;
-
- /**
- * Constructs a criteria that accepts the drag if the targeted Item is a
- * descendant of Item identified by given id
- *
- * @param parentItemId
- * the item identifier of the parent node
- */
- public TargetInSubtree(Object parentItemId) {
- rootId = parentItemId;
- }
-
- /**
- * Constructs a criteria that accepts drops within given level below the
- * subtree root identified by given id.
- *
- * @param rootId
- * the item identifier to be sought for
- * @param depthToCheck
- * the depth that tree is traversed upwards to seek for the
- * parent, -1 means that the whole structure should be
- * checked
- */
- public TargetInSubtree(Object rootId, int depthToCheck) {
- this.rootId = rootId;
- this.depthToCheck = depthToCheck;
- }
-
- @Override
- public boolean accept(DragAndDropEvent dragEvent) {
- try {
- TreeTargetDetails eventDetails = (TreeTargetDetails) dragEvent
- .getTargetDetails();
-
- if (eventDetails.getItemIdOver() != null) {
- Object itemId = eventDetails.getItemIdOver();
- int i = 0;
- while (itemId != null
- && (depthToCheck == -1 || i <= depthToCheck)) {
- if (itemId.equals(rootId)) {
- return true;
- }
- itemId = getParent(itemId);
- i++;
- }
- }
- return false;
- } catch (Exception e) {
- return false;
- }
- }
-
- @Override
- public void paintContent(PaintTarget target) throws PaintException {
- super.paintContent(target);
- target.addAttribute("depth", depthToCheck);
- target.addAttribute("key", key(rootId));
- }
- }
-
- /**
- * Set the item description generator which generates tooltips for the tree
- * items
- *
- * @param generator
- * The generator to use or null to disable
- */
- public void setItemDescriptionGenerator(ItemDescriptionGenerator generator) {
- if (generator != itemDescriptionGenerator) {
- itemDescriptionGenerator = generator;
- markAsDirty();
- }
- }
-
- /**
- * Get the item description generator which generates tooltips for tree
- * items
- */
- public ItemDescriptionGenerator getItemDescriptionGenerator() {
- return itemDescriptionGenerator;
- }
-
- private void cleanupExpandedItems() {
- Set<Object> removedItemIds = new HashSet<Object>();
- for (Object expandedItemId : expanded) {
- if (getItem(expandedItemId) == null) {
- removedItemIds.add(expandedItemId);
- if (this.expandedItemId == expandedItemId) {
- this.expandedItemId = null;
- }
- }
- }
- expanded.removeAll(removedItemIds);
- }
-
- /**
- * Reads an Item from a design and inserts it into the data source.
- * Recursively handles any children of the item as well.
- *
- * @since 7.5.0
- * @param node
- * an element representing the item (tree node).
- * @param selected
- * A set accumulating selected items. If the item that is read is
- * marked as selected, its item id should be added to this set.
- * @param context
- * the DesignContext instance used in parsing
- * @return the item id of the new item
- *
- * @throws DesignException
- * if the tag name of the {@code node} element is not
- * {@code node}.
- */
- @Override
- protected String readItem(Element node, Set<String> selected,
- DesignContext context) {
-
- if (!"node".equals(node.tagName())) {
- throw new DesignException("Unrecognized child element in "
- + getClass().getSimpleName() + ": " + node.tagName());
- }
-
- String itemId = node.attr("text");
- addItem(itemId);
- if (node.hasAttr("icon")) {
- Resource icon = DesignAttributeHandler.readAttribute("icon",
- node.attributes(), Resource.class);
- setItemIcon(itemId, icon);
- }
- if (node.hasAttr("selected")) {
- selected.add(itemId);
- }
-
- for (Element child : node.children()) {
- String childItemId = readItem(child, selected, context);
- setParent(childItemId, itemId);
- }
- return itemId;
- }
-
- /**
- * Recursively writes the root items and their children to a design.
- *
- * @since 7.5.0
- * @param design
- * the element into which to insert the items
- * @param context
- * the DesignContext instance used in writing
- */
- @Override
- protected void writeItems(Element design, DesignContext context) {
- for (Object itemId : rootItemIds()) {
- writeItem(design, itemId, context);
- }
- }
-
- /**
- * Recursively writes a data source Item and its children to a design.
- *
- * @since 7.5.0
- * @param design
- * the element into which to insert the item
- * @param itemId
- * the id of the item to write
- * @param context
- * the DesignContext instance used in writing
- * @return
- */
- @Override
- protected Element writeItem(Element design, Object itemId,
- DesignContext context) {
- Element element = design.appendElement("node");
-
- element.attr("text", itemId.toString());
-
- Resource icon = getItemIcon(itemId);
- if (icon != null) {
- DesignAttributeHandler.writeAttribute("icon", element.attributes(),
- icon, null, Resource.class);
- }
-
- if (isSelected(itemId)) {
- element.attr("selected", "");
- }
-
- Collection<?> children = getChildren(itemId);
- if (children != null) {
- // Yeah... see #5864
- for (Object childItemId : children) {
- writeItem(element, childItemId, context);
- }
- }
-
- return element;
- }
-
- /**
- * Sets whether html is allowed in the item captions. If set to
- * <code>true</code>, the captions are passed to the browser as html and the
- * developer is responsible for ensuring no harmful html is used. If set to
- * <code>false</code>, the content is passed to the browser as plain text.
- * The default setting is <code>false</code>
- *
- * @since 7.6
- * @param htmlContentAllowed
- * <code>true</code> if the captions are used as html,
- * <code>false</code> if used as plain text
- */
- public void setHtmlContentAllowed(boolean htmlContentAllowed) {
- this.htmlContentAllowed = htmlContentAllowed;
- markAsDirty();
- }
-
- /**
- * Checks whether captions are interpreted as html or plain text.
- *
- * @since 7.6
- * @return <code>true</code> if the captions are displayed as html,
- * <code>false</code> if displayed as plain text
- * @see #setHtmlContentAllowed(boolean)
- */
- public boolean isHtmlContentAllowed() {
- return htmlContentAllowed;
- }
-
- @Override
- protected TreeState getState() {
- return (TreeState) super.getState();
- }
-}