| /******************************************************************************* |
| * Copyright (c) 2000, 2003 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.swt.widgets; |
| |
| |
| import org.eclipse.swt.*; |
| import java.util.Enumeration; |
| import java.util.Vector; |
| |
| /** |
| * This class stores and manages child items of a tree item. |
| * It provides protocol to query the index of an item relative |
| * to the root and to retrieve items by index. |
| * The TreeItem class implements this protocol for general |
| * tree items. |
| * TreeRoots provides a special implementation that allows the |
| * Tree class to treat trees with one root and with multiple |
| * roots equally. |
| */ |
| abstract class AbstractTreeItem extends SelectableItem { |
| private Vector children; |
| private boolean isExpanded = false; |
| // number of children. |
| // includes all expanded items down to the leafs. |
| private int visibleItemCount = 0; |
| |
| /** |
| * Create a new instance of the receiver. |
| * @param parent - widget the receiver belongs to |
| * @param swtStyle - widget style. see Widget class for details |
| */ |
| AbstractTreeItem(Tree parent, int swtStyle) { |
| super(parent, swtStyle); |
| } |
| /** |
| * Insert 'item' in the list of child items. Notify the |
| * parent about the new item. |
| * @param 'item' - the item that should be added to the |
| * receiver's children. |
| * @param index - position that 'item' will be inserted at |
| * in the receiver. |
| */ |
| void add(TreeItem item, int index) { |
| Vector items = getChildren(); |
| int visibleIndex = getVisibleIndex(); |
| |
| if (index < 0 || index > items.size()) { |
| error(SWT.ERROR_INVALID_RANGE); |
| } |
| if (item.isRoot()) { |
| visibleIndex = index; |
| } |
| else |
| if (isExpanded == false) { |
| visibleIndex = -1; |
| } |
| if (visibleIndex != -1) { |
| if (index > 0) { |
| TreeItem previousChild = (TreeItem) getChildren().elementAt(index - 1); |
| visibleIndex = previousChild.getVisibleIndex() + previousChild.getVisibleItemCount() + 1; |
| } |
| else { |
| visibleIndex = getVisibleIndex() + 1; |
| } |
| } |
| getSelectableParent().addingItem(item, visibleIndex); |
| item.setIndex(index); |
| resetChildIndices(index, true); |
| items.insertElementAt(item, index); |
| if (isExpanded == true) { |
| visibleItemCount++; |
| calculateVisibleItemCountParent(); |
| } |
| getSelectableParent().addedItem(item, visibleIndex); |
| } |
| /** |
| * Set whether the receiver is expanded or not. |
| * If the receiver is expanded its child items are visible. |
| * @param expanded - |
| * true=the receiver is expanded, making its child items visible. |
| * false=the receiver is collapsed, making its child items invisible |
| */ |
| void internalSetExpanded(boolean expanded) { |
| isExpanded = expanded; |
| calculateVisibleItemCount(); |
| } |
| /** |
| * Calculate the number of expanded children. |
| * Recurse up in the tree to the root item. |
| */ |
| abstract void calculateVisibleItemCount(); |
| /** |
| * Calculate the number of expanded children for the parent item |
| * of this item. |
| */ |
| abstract void calculateVisibleItemCountParent(); |
| /** |
| * Deselect the receiver and all children |
| */ |
| void deselectAll() { |
| Enumeration children = getChildren().elements(); |
| AbstractTreeItem treeItem; |
| |
| setSelected(false); |
| while (children.hasMoreElements() == true) { |
| treeItem = (AbstractTreeItem) children.nextElement(); |
| treeItem.deselectAll(); |
| } |
| } |
| public void dispose() { |
| if (isDisposed()) return; |
| Vector children = getChildren(); |
| AbstractTreeItem child; |
| while (children.size() > 0) { // TreeItem objects are removed from vector during dispose |
| child = (AbstractTreeItem) children.firstElement(); |
| child.dispose(); |
| } |
| super.dispose(); |
| } |
| void doDispose() { |
| setChildren(null); |
| visibleItemCount = 0; |
| super.doDispose(); |
| } |
| /** |
| * Answer the Vector containing the child items of the receiver. |
| */ |
| Vector getChildren() { |
| if (children == null) { |
| children = new Vector(4); |
| } |
| return children; |
| } |
| /** |
| * Answer whether the receiver is expanded or not. |
| * If the receiver is expanded its children are visible. |
| * @return |
| * true - the receiver is expanded, making its children visible |
| * false - the receiver is collapsed, making its children invisible |
| */ |
| public boolean getExpanded() { |
| checkWidget(); |
| |
| return isExpanded; |
| } |
| /** |
| * Answer the number of children. |
| */ |
| public int getItemCount() { |
| checkWidget(); |
| |
| return getChildren().size(); |
| } |
| /** |
| * Answer the index of the receiver relative to the first root |
| * item. |
| * If 'anIndex' is the global index of the expanded item 'anItem' |
| * then the following expressions are true: |
| * 'anItem == theRoot.getVisibleItem(anIndex)' and |
| * 'anIndex == anItem.getVisibleIndex()' |
| * @return |
| * The index of the receiver relative to the first root item. |
| * Answer -1 if the receiver is not visible (because the parent |
| * is collapsed). |
| */ |
| abstract int getVisibleIndex(); |
| /** |
| * Answer the index of the child item identified by 'childIndex' |
| * relative to the first root item. |
| */ |
| abstract int getVisibleIndex(int childIndex); |
| /** |
| * Answer the item at 'searchIndex' relativ to the receiver. |
| * When this method is called for the root item, 'searchIndex' |
| * represents the global index into all items of the tree. |
| * searchIndex=0 returns the receiver. |
| * searchIndex=1 returns the first visible child. |
| * Note: searchIndex must be >= 0 |
| * |
| * Note: |
| * Visible in this context does not neccessarily mean that the |
| * item is displayed on the screen. Visible here means that all |
| * the parents of the item are expanded. An item is only |
| * visible on screen if it is within the receiver's parent's |
| * client area. |
| */ |
| abstract TreeItem getVisibleItem(int searchIndex); |
| /** |
| * Answer the number of expanded children, direct and indirect. |
| */ |
| int getVisibleItemCount() { |
| return visibleItemCount; |
| } |
| /** |
| * Returns the expanded state. Circumvent widget/thread check |
| * for performance. For non-API callers only. |
| */ |
| boolean internalGetExpanded() { |
| return isExpanded; |
| } |
| /** |
| * Answer whether the receiver is a leaf item. |
| * An item is a leaf when it has no child items. |
| * @return |
| * true - receiver is a leaf item |
| * false - receiver is not a leaf item. |
| */ |
| boolean isLeaf() { |
| return (getChildren().size() == 0); |
| } |
| /** |
| * Answer whether the receiver is a root item. |
| * The receiver is a root item when it doesn't have a parent item. |
| * @return |
| * true - the receiver is a root item. |
| * false - the receiver is not a root item. |
| */ |
| boolean isRoot() { |
| return false; |
| } |
| /** |
| * Remove 'child' from the receiver. |
| * Notify the parent widget only if it is not being disposed itself. |
| */ |
| void removeItem(SelectableItem child) { |
| Vector children = getChildren(); |
| SelectableItemWidget parent = getSelectableParent(); |
| int childIndex = children.indexOf(child); |
| |
| if (childIndex != -1) { |
| if (((Tree) parent).isRemovingAll() == true) { |
| children.removeElementAt(childIndex); // just remove the item from the list if the whole tree is being disposed |
| if (isExpanded == true) { |
| visibleItemCount--; |
| calculateVisibleItemCountParent(); |
| } |
| } |
| else { |
| parent.removingItem(child); |
| children.removeElementAt(childIndex); |
| if (isExpanded == true) { |
| visibleItemCount--; |
| calculateVisibleItemCountParent(); |
| } |
| resetChildIndices(childIndex, false); // mark child index dirty |
| parent.removedItem(child); |
| } |
| } |
| } |
| /** |
| * Allow subclasses to reset any cached data. |
| * Called for all children of the receiver. |
| */ |
| void reset() { |
| Enumeration children = getChildren().elements(); |
| AbstractTreeItem treeItem; |
| |
| while (children.hasMoreElements() == true) { |
| treeItem = (AbstractTreeItem) children.nextElement(); |
| treeItem.reset(); |
| } |
| } |
| /** |
| * Mark all child indices dirty starting with the child at |
| * 'startIndex'. This causes getIndex to recalculate the index. |
| * @param startIndex - index in the list of children at which |
| * and after which the indices are reset. |
| */ |
| void resetChildIndices(int startIndex, boolean addItem) { |
| Vector children = getChildren(); |
| TreeItem child; |
| int increment = addItem ? 1 : 0; |
| |
| for (int i = startIndex; i < children.size(); i++) { |
| child = (TreeItem) children.elementAt(i); |
| child.setIndex(i + increment); // mark child index dirty |
| } |
| } |
| /** |
| * Select the receiver and all children. |
| * Return a Vector containing all the items that have been selected |
| * (and that have not been selected before). |
| */ |
| Vector selectAll(Vector selectedItems) { |
| Enumeration children = getChildren().elements(); |
| AbstractTreeItem treeItem; |
| |
| if (isSelected() == false) { |
| selectedItems.addElement(this); |
| setSelected(true); |
| getSelectableParent().redrawSelection(this); |
| } |
| while (children.hasMoreElements() == true) { |
| treeItem = (AbstractTreeItem) children.nextElement(); |
| selectedItems = treeItem.selectAll(selectedItems); |
| } |
| return selectedItems; |
| } |
| /** |
| * Set the Array containing the receiver's child items to 'children'. |
| */ |
| void setChildren(Vector children) { |
| this.children = children; |
| } |
| |
| void setVisibleItemCount(int count) { |
| visibleItemCount = count; |
| } |
| } |