diff options
Diffstat (limited to 'src/com/vaadin/data/util/HierarchicalContainer.java')
-rw-r--r-- | src/com/vaadin/data/util/HierarchicalContainer.java | 814 |
1 files changed, 0 insertions, 814 deletions
diff --git a/src/com/vaadin/data/util/HierarchicalContainer.java b/src/com/vaadin/data/util/HierarchicalContainer.java deleted file mode 100644 index 06ab77c0e7..0000000000 --- a/src/com/vaadin/data/util/HierarchicalContainer.java +++ /dev/null @@ -1,814 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.util; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.Set; - -import com.vaadin.data.Container; -import com.vaadin.data.Item; - -/** - * A specialized Container whose contents can be accessed like it was a - * tree-like structure. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class HierarchicalContainer extends IndexedContainer implements - Container.Hierarchical { - - /** - * Set of IDs of those contained Items that can't have children. - */ - private final HashSet<Object> noChildrenAllowed = new HashSet<Object>(); - - /** - * Mapping from Item ID to parent Item ID. - */ - private final HashMap<Object, Object> parent = new HashMap<Object, Object>(); - - /** - * Mapping from Item ID to parent Item ID for items included in the filtered - * container. - */ - private HashMap<Object, Object> filteredParent = null; - - /** - * Mapping from Item ID to a list of child IDs. - */ - private final HashMap<Object, LinkedList<Object>> children = new HashMap<Object, LinkedList<Object>>(); - - /** - * Mapping from Item ID to a list of child IDs when filtered - */ - private HashMap<Object, LinkedList<Object>> filteredChildren = null; - - /** - * List that contains all root elements of the container. - */ - private final LinkedList<Object> roots = new LinkedList<Object>(); - - /** - * List that contains all filtered root elements of the container. - */ - private LinkedList<Object> filteredRoots = null; - - /** - * Determines how filtering of the container is done. - */ - private boolean includeParentsWhenFiltering = true; - - private boolean contentChangedEventsDisabled = false; - - private boolean contentsChangedEventPending; - - /* - * Can the specified Item have any children? Don't add a JavaDoc comment - * here, we use the default documentation from implemented interface. - */ - @Override - public boolean areChildrenAllowed(Object itemId) { - if (noChildrenAllowed.contains(itemId)) { - return false; - } - return containsId(itemId); - } - - /* - * Gets the IDs of the children of the specified Item. Don't add a JavaDoc - * comment here, we use the default documentation from implemented - * interface. - */ - @Override - public Collection<?> getChildren(Object itemId) { - LinkedList<Object> c; - - if (filteredChildren != null) { - c = filteredChildren.get(itemId); - } else { - c = children.get(itemId); - } - - if (c == null) { - return null; - } - return Collections.unmodifiableCollection(c); - } - - /* - * Gets the ID of the parent of the specified Item. Don't add a JavaDoc - * comment here, we use the default documentation from implemented - * interface. - */ - @Override - public Object getParent(Object itemId) { - if (filteredParent != null) { - return filteredParent.get(itemId); - } - return parent.get(itemId); - } - - /* - * Is the Item corresponding to the given ID a leaf node? Don't add a - * JavaDoc comment here, we use the default documentation from implemented - * interface. - */ - @Override - public boolean hasChildren(Object itemId) { - if (filteredChildren != null) { - return filteredChildren.containsKey(itemId); - } else { - return children.containsKey(itemId); - } - } - - /* - * Is the Item corresponding to the given ID a root node? Don't add a - * JavaDoc comment here, we use the default documentation from implemented - * interface. - */ - @Override - public boolean isRoot(Object itemId) { - // If the container is filtered the itemId must be among filteredRoots - // to be a root. - if (filteredRoots != null) { - if (!filteredRoots.contains(itemId)) { - return false; - } - } else { - // Container is not filtered - if (parent.containsKey(itemId)) { - return false; - } - } - - return containsId(itemId); - } - - /* - * Gets the IDs of the root elements in the container. Don't add a JavaDoc - * comment here, we use the default documentation from implemented - * interface. - */ - @Override - public Collection<?> rootItemIds() { - if (filteredRoots != null) { - return Collections.unmodifiableCollection(filteredRoots); - } else { - return Collections.unmodifiableCollection(roots); - } - } - - /** - * <p> - * Sets the given Item's capability to have children. If the Item identified - * with the itemId already has children and the areChildrenAllowed is false - * this method fails and <code>false</code> is returned; the children must - * be first explicitly removed with - * {@link #setParent(Object itemId, Object newParentId)} or - * {@link com.vaadin.data.Container#removeItem(Object itemId)}. - * </p> - * - * @param itemId - * the ID of the Item in the container whose child capability is - * to be set. - * @param childrenAllowed - * the boolean value specifying if the Item can have children or - * not. - * @return <code>true</code> if the operation succeeded, <code>false</code> - * if not - */ - @Override - public boolean setChildrenAllowed(Object itemId, boolean childrenAllowed) { - - // Checks that the item is in the container - if (!containsId(itemId)) { - return false; - } - - // Updates status - if (childrenAllowed) { - noChildrenAllowed.remove(itemId); - } else { - noChildrenAllowed.add(itemId); - } - - return true; - } - - /** - * <p> - * Sets the parent of an Item. The new parent item must exist and be able to - * have children. (<code>canHaveChildren(newParentId) == true</code>). It is - * also possible to detach a node from the hierarchy (and thus make it root) - * by setting the parent <code>null</code>. - * </p> - * - * @param itemId - * the ID of the item to be set as the child of the Item - * identified with newParentId. - * @param newParentId - * the ID of the Item that's to be the new parent of the Item - * identified with itemId. - * @return <code>true</code> if the operation succeeded, <code>false</code> - * if not - */ - @Override - public boolean setParent(Object itemId, Object newParentId) { - - // Checks that the item is in the container - if (!containsId(itemId)) { - return false; - } - - // Gets the old parent - final Object oldParentId = parent.get(itemId); - - // Checks if no change is necessary - if ((newParentId == null && oldParentId == null) - || ((newParentId != null) && newParentId.equals(oldParentId))) { - return true; - } - - // Making root? - if (newParentId == null) { - // The itemId should become a root so we need to - // - Remove it from the old parent's children list - // - Add it as a root - // - Remove it from the item -> parent list (parent is null for - // roots) - - // Removes from old parents children list - final LinkedList<Object> l = children.get(oldParentId); - if (l != null) { - l.remove(itemId); - if (l.isEmpty()) { - children.remove(oldParentId); - } - - } - - // Add to be a root - roots.add(itemId); - - // Updates parent - parent.remove(itemId); - - if (hasFilters()) { - // Refilter the container if setParent is called when filters - // are applied. Changing parent can change what is included in - // the filtered version (if includeParentsWhenFiltering==true). - doFilterContainer(hasFilters()); - } - - fireItemSetChange(); - - return true; - } - - // We get here when the item should not become a root and we need to - // - Verify the new parent exists and can have children - // - Check that the new parent is not a child of the selected itemId - // - Updated the item -> parent mapping to point to the new parent - // - Remove the item from the roots list if it was a root - // - Remove the item from the old parent's children list if it was not a - // root - - // Checks that the new parent exists in container and can have - // children - if (!containsId(newParentId) || noChildrenAllowed.contains(newParentId)) { - return false; - } - - // Checks that setting parent doesn't result to a loop - Object o = newParentId; - while (o != null && !o.equals(itemId)) { - o = parent.get(o); - } - if (o != null) { - return false; - } - - // Updates parent - parent.put(itemId, newParentId); - LinkedList<Object> pcl = children.get(newParentId); - if (pcl == null) { - // Create an empty list for holding children if one were not - // previously created - pcl = new LinkedList<Object>(); - children.put(newParentId, pcl); - } - pcl.add(itemId); - - // Removes from old parent or root - if (oldParentId == null) { - roots.remove(itemId); - } else { - final LinkedList<Object> l = children.get(oldParentId); - if (l != null) { - l.remove(itemId); - if (l.isEmpty()) { - children.remove(oldParentId); - } - } - } - - if (hasFilters()) { - // Refilter the container if setParent is called when filters - // are applied. Changing parent can change what is included in - // the filtered version (if includeParentsWhenFiltering==true). - doFilterContainer(hasFilters()); - } - - fireItemSetChange(); - - return true; - } - - private boolean hasFilters() { - return (filteredRoots != null); - } - - /** - * Moves a node (an Item) in the container immediately after a sibling node. - * The two nodes must have the same parent in the container. - * - * @param itemId - * the identifier of the moved node (Item) - * @param siblingId - * the identifier of the reference node (Item), after which the - * other node will be located - */ - public void moveAfterSibling(Object itemId, Object siblingId) { - Object parent2 = getParent(itemId); - LinkedList<Object> childrenList; - if (parent2 == null) { - childrenList = roots; - } else { - childrenList = children.get(parent2); - } - if (siblingId == null) { - childrenList.remove(itemId); - childrenList.addFirst(itemId); - - } else { - int oldIndex = childrenList.indexOf(itemId); - int indexOfSibling = childrenList.indexOf(siblingId); - if (indexOfSibling != -1 && oldIndex != -1) { - int newIndex; - if (oldIndex > indexOfSibling) { - newIndex = indexOfSibling + 1; - } else { - newIndex = indexOfSibling; - } - childrenList.remove(oldIndex); - childrenList.add(newIndex, itemId); - } else { - throw new IllegalArgumentException( - "Given identifiers no not have the same parent."); - } - } - fireItemSetChange(); - - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.IndexedContainer#addItem() - */ - @Override - public Object addItem() { - disableContentsChangeEvents(); - final Object itemId = super.addItem(); - if (itemId == null) { - return null; - } - - if (!roots.contains(itemId)) { - roots.add(itemId); - if (filteredRoots != null) { - if (passesFilters(itemId)) { - filteredRoots.add(itemId); - } - } - } - enableAndFireContentsChangeEvents(); - return itemId; - } - - @Override - protected void fireItemSetChange( - com.vaadin.data.Container.ItemSetChangeEvent event) { - if (contentsChangeEventsOn()) { - super.fireItemSetChange(event); - } else { - contentsChangedEventPending = true; - } - } - - private boolean contentsChangeEventsOn() { - return !contentChangedEventsDisabled; - } - - private void disableContentsChangeEvents() { - contentChangedEventsDisabled = true; - } - - private void enableAndFireContentsChangeEvents() { - contentChangedEventsDisabled = false; - if (contentsChangedEventPending) { - fireItemSetChange(); - } - contentsChangedEventPending = false; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.IndexedContainer#addItem(java.lang.Object) - */ - @Override - public Item addItem(Object itemId) { - disableContentsChangeEvents(); - final Item item = super.addItem(itemId); - if (item == null) { - return null; - } - - roots.add(itemId); - - if (filteredRoots != null) { - if (passesFilters(itemId)) { - filteredRoots.add(itemId); - } - } - enableAndFireContentsChangeEvents(); - return item; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.IndexedContainer#removeAllItems() - */ - @Override - public boolean removeAllItems() { - disableContentsChangeEvents(); - final boolean success = super.removeAllItems(); - - if (success) { - roots.clear(); - parent.clear(); - children.clear(); - noChildrenAllowed.clear(); - if (filteredRoots != null) { - filteredRoots = null; - } - if (filteredChildren != null) { - filteredChildren = null; - } - if (filteredParent != null) { - filteredParent = null; - } - } - enableAndFireContentsChangeEvents(); - return success; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.IndexedContainer#removeItem(java.lang.Object ) - */ - @Override - public boolean removeItem(Object itemId) { - disableContentsChangeEvents(); - final boolean success = super.removeItem(itemId); - - if (success) { - // Remove from roots if this was a root - if (roots.remove(itemId)) { - - // If filtering is enabled we might need to remove it from the - // filtered list also - if (filteredRoots != null) { - filteredRoots.remove(itemId); - } - } - - // Clear the children list. Old children will now become root nodes - LinkedList<Object> childNodeIds = children.remove(itemId); - if (childNodeIds != null) { - if (filteredChildren != null) { - filteredChildren.remove(itemId); - } - for (Object childId : childNodeIds) { - setParent(childId, null); - } - } - - // Parent of the item that we are removing will contain the item id - // in its children list - final Object parentItemId = parent.get(itemId); - if (parentItemId != null) { - final LinkedList<Object> c = children.get(parentItemId); - if (c != null) { - c.remove(itemId); - - if (c.isEmpty()) { - children.remove(parentItemId); - } - - // Found in the children list so might also be in the - // filteredChildren list - if (filteredChildren != null) { - LinkedList<Object> f = filteredChildren - .get(parentItemId); - if (f != null) { - f.remove(itemId); - if (f.isEmpty()) { - filteredChildren.remove(parentItemId); - } - } - } - } - } - parent.remove(itemId); - if (filteredParent != null) { - // Item id no longer has a parent as the item id is not in the - // container. - filteredParent.remove(itemId); - } - noChildrenAllowed.remove(itemId); - } - - enableAndFireContentsChangeEvents(); - - return success; - } - - /** - * Removes the Item identified by given itemId and all its children. - * - * @see #removeItem(Object) - * @param itemId - * the identifier of the Item to be removed - * @return true if the operation succeeded - */ - public boolean removeItemRecursively(Object itemId) { - disableContentsChangeEvents(); - boolean removeItemRecursively = removeItemRecursively(this, itemId); - enableAndFireContentsChangeEvents(); - return removeItemRecursively; - } - - /** - * Removes the Item identified by given itemId and all its children from the - * given Container. - * - * @param container - * the container where the item is to be removed - * @param itemId - * the identifier of the Item to be removed - * @return true if the operation succeeded - */ - public static boolean removeItemRecursively( - Container.Hierarchical container, Object itemId) { - boolean success = true; - Collection<?> children2 = container.getChildren(itemId); - if (children2 != null) { - Object[] array = children2.toArray(); - for (int i = 0; i < array.length; i++) { - boolean removeItemRecursively = removeItemRecursively( - container, array[i]); - if (!removeItemRecursively) { - success = false; - } - } - } - // remove the root of subtree if children where succesfully removed - if (success) { - success = container.removeItem(itemId); - } - return success; - - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.IndexedContainer#doSort() - */ - @Override - protected void doSort() { - super.doSort(); - - Collections.sort(roots, getItemSorter()); - for (LinkedList<Object> childList : children.values()) { - Collections.sort(childList, getItemSorter()); - } - } - - /** - * Used to control how filtering works. @see - * {@link #setIncludeParentsWhenFiltering(boolean)} for more information. - * - * @return true if all parents for items that match the filter are included - * when filtering, false if only the matching items are included - */ - public boolean isIncludeParentsWhenFiltering() { - return includeParentsWhenFiltering; - } - - /** - * Controls how the filtering of the container works. Set this to true to - * make filtering include parents for all matched items in addition to the - * items themselves. Setting this to false causes the filtering to only - * include the matching items and make items with excluded parents into root - * items. - * - * @param includeParentsWhenFiltering - * true to include all parents for items that match the filter, - * false to only include the matching items - */ - public void setIncludeParentsWhenFiltering( - boolean includeParentsWhenFiltering) { - this.includeParentsWhenFiltering = includeParentsWhenFiltering; - if (filteredRoots != null) { - // Currently filtered so needs to be re-filtered - doFilterContainer(true); - } - } - - /* - * Overridden to provide filtering for root & children items. - * - * (non-Javadoc) - * - * @see com.vaadin.data.util.IndexedContainer#updateContainerFiltering() - */ - @Override - protected boolean doFilterContainer(boolean hasFilters) { - if (!hasFilters) { - // All filters removed - filteredRoots = null; - filteredChildren = null; - filteredParent = null; - - return super.doFilterContainer(hasFilters); - } - - // Reset data structures - filteredRoots = new LinkedList<Object>(); - filteredChildren = new HashMap<Object, LinkedList<Object>>(); - filteredParent = new HashMap<Object, Object>(); - - if (includeParentsWhenFiltering) { - // Filter so that parents for items that match the filter are also - // included - HashSet<Object> includedItems = new HashSet<Object>(); - for (Object rootId : roots) { - if (filterIncludingParents(rootId, includedItems)) { - filteredRoots.add(rootId); - addFilteredChildrenRecursively(rootId, includedItems); - } - } - // includedItemIds now contains all the item ids that should be - // included. Filter IndexedContainer based on this - filterOverride = includedItems; - super.doFilterContainer(hasFilters); - filterOverride = null; - - return true; - } else { - // Filter by including all items that pass the filter and make items - // with no parent new root items - - // Filter IndexedContainer first so getItemIds return the items that - // match - super.doFilterContainer(hasFilters); - - LinkedHashSet<Object> filteredItemIds = new LinkedHashSet<Object>( - getItemIds()); - - for (Object itemId : filteredItemIds) { - Object itemParent = parent.get(itemId); - if (itemParent == null || !filteredItemIds.contains(itemParent)) { - // Parent is not included or this was a root, in both cases - // this should be a filtered root - filteredRoots.add(itemId); - } else { - // Parent is included. Add this to the children list (create - // it first if necessary) - addFilteredChild(itemParent, itemId); - } - } - - return true; - } - } - - /** - * Adds the given childItemId as a filteredChildren for the parentItemId and - * sets it filteredParent. - * - * @param parentItemId - * @param childItemId - */ - private void addFilteredChild(Object parentItemId, Object childItemId) { - LinkedList<Object> parentToChildrenList = filteredChildren - .get(parentItemId); - if (parentToChildrenList == null) { - parentToChildrenList = new LinkedList<Object>(); - filteredChildren.put(parentItemId, parentToChildrenList); - } - filteredParent.put(childItemId, parentItemId); - parentToChildrenList.add(childItemId); - - } - - /** - * Recursively adds all items in the includedItems list to the - * filteredChildren map in the same order as they are in the children map. - * Starts from parentItemId and recurses down as long as child items that - * should be included are found. - * - * @param parentItemId - * The item id to start recurse from. Not added to a - * filteredChildren list - * @param includedItems - * Set containing the item ids for the items that should be - * included in the filteredChildren map - */ - private void addFilteredChildrenRecursively(Object parentItemId, - HashSet<Object> includedItems) { - LinkedList<Object> childList = children.get(parentItemId); - if (childList == null) { - return; - } - - for (Object childItemId : childList) { - if (includedItems.contains(childItemId)) { - addFilteredChild(parentItemId, childItemId); - addFilteredChildrenRecursively(childItemId, includedItems); - } - } - } - - /** - * Scans the itemId and all its children for which items should be included - * when filtering. All items which passes the filters are included. - * Additionally all items that have a child node that should be included are - * also themselves included. - * - * @param itemId - * @param includedItems - * @return true if the itemId should be included in the filtered container. - */ - private boolean filterIncludingParents(Object itemId, - HashSet<Object> includedItems) { - boolean toBeIncluded = passesFilters(itemId); - - LinkedList<Object> childList = children.get(itemId); - if (childList != null) { - for (Object childItemId : children.get(itemId)) { - toBeIncluded |= filterIncludingParents(childItemId, - includedItems); - } - } - - if (toBeIncluded) { - includedItems.add(itemId); - } - return toBeIncluded; - } - - private Set<Object> filterOverride = null; - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.util.IndexedContainer#passesFilters(java.lang.Object) - */ - @Override - protected boolean passesFilters(Object itemId) { - if (filterOverride != null) { - return filterOverride.contains(itemId); - } else { - return super.passesFilters(itemId); - } - } -} |