blob: 808e6e51d66952a91a4c118d65855156caa8d5b7 [file] [log] [blame]
package org.eclipse.swt.widgets;
/*
* Copyright (c) 2000, 2002 IBM Corp. All rights reserved.
* This file is 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
*/
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
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;
}
}