package org.eclipse.jface.viewers;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.jface.util.SafeRunnable;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.events.TreeEvent;
import org.eclipse.swt.events.TreeListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Widget;
public abstract class AbstractTreeViewer extends ColumnViewer {
public static final int ALL_LEVELS = -1;
private ListenerList treeListeners = new ListenerList();
private int expandToLevel = 0;
class UpdateItemSafeRunnable extends SafeRunnable {
private Object element;
private Item item;
UpdateItemSafeRunnable(Item item, Object element) {
this.item = item;
this.element = element;
}
public void run() {
doUpdateItem(item, element);
}
}
protected AbstractTreeViewer() {
}
public void add(Object parentElementOrTreePath, Object[] childElements) {
Assert.isNotNull(parentElementOrTreePath);
assertElementsNotNull(childElements);
if (checkBusy())
return;
Widget[] widgets = internalFindItems(parentElementOrTreePath);
if (widgets.length == 0) {
return;
}
for (int i = 0; i < widgets.length; i++) {
internalAdd(widgets[i], parentElementOrTreePath, childElements);
}
}
final protected Widget[] internalFindItems(Object parentElementOrTreePath) {
Widget[] widgets;
if (parentElementOrTreePath instanceof TreePath) {
TreePath path = (TreePath) parentElementOrTreePath;
Widget w = internalFindItem(path);
if (w == null) {
widgets = new Widget[] {};
} else {
widgets = new Widget[] { w };
}
} else {
widgets = findItems(parentElementOrTreePath);
}
return widgets;
}
private Widget internalFindItem(TreePath path) {
Widget[] widgets = findItems(path.getLastSegment());
for (int i = 0; i < widgets.length; i++) {
Widget widget = widgets[i];
if (widget instanceof Item) {
Item item = (Item) widget;
TreePath p = getTreePathFromItem(item);
if (p.equals(path)) {
return widget;
}
}
}
return null;
}
protected void internalAdd(Widget widget, Object parentElementOrTreePath,
Object[] childElements) {
Object parent;
TreePath path;
if (parentElementOrTreePath instanceof TreePath) {
path = (TreePath) parentElementOrTreePath;
parent = path.getLastSegment();
} else {
parent = parentElementOrTreePath;
path = null;
}
if (widget instanceof Item) {
Item ti = (Item) widget;
if (!getExpanded(ti)) {
boolean needDummy = isExpandable(ti, path, parent);
boolean haveDummy = false;
Item[] items = getItems(ti);
for (int i = 0; i < items.length; i++) {
if (items[i].getData() != null) {
disassociate(items[i]);
items[i].dispose();
} else {
if (needDummy && !haveDummy) {
haveDummy = true;
} else {
items[i].dispose();
}
}
}
if (needDummy && !haveDummy) {
newItem(ti, SWT.NULL, -1);
}
return;
}
}
if (childElements.length > 0) {
Object[] filtered = filter(parentElementOrTreePath, childElements);
ViewerComparator comparator = getComparator();
if (comparator != null) {
if (comparator instanceof TreePathViewerSorter) {
TreePathViewerSorter tpvs = (TreePathViewerSorter) comparator;
if (path == null) {
path = internalGetSorterParentPath(widget, comparator);
}
tpvs.sort(this, path, filtered);
} else {
comparator.sort(this, filtered);
}
}
createAddedElements(widget, filtered);
}
}
private Object[] filter(Object parentElementOrTreePath, Object[] elements) {
ViewerFilter[] filters = getFilters();
if (filters != null) {
ArrayList filtered = new ArrayList(elements.length);
for (int i = 0; i < elements.length; i++) {
boolean add = true;
for (int j = 0; j < filters.length; j++) {
add = filters[j].select(this, parentElementOrTreePath,
elements[i]);
if (!add) {
break;
}
}
if (add) {
filtered.add(elements[i]);
}
}
return filtered.toArray();
}
return elements;
}
private void createAddedElements(Widget widget, Object[] elements) {
if (elements.length == 1) {
if (equals(elements[0], widget.getData())) {
return;
}
}
ViewerComparator comparator = getComparator();
TreePath parentPath = internalGetSorterParentPath(widget, comparator);
Item[] items = getChildren(widget);
if (items.length == 0) {
for (int i = 0; i < elements.length; i++) {
createTreeItem(widget, elements[i], -1);
}
return;
}
if (comparator == null) {
for (int i = 0; i < elements.length; i++) {
Object element = elements[i];
if (itemExists(items, element)) {
internalRefresh(element);
} else {
createTreeItem(widget, element, -1);
}
}
return;
}
int indexInItems = 0;
int newItems = 0;
elementloop: for (int i = 0; i < elements.length; i++) {
Object element = elements[i];
indexInItems = insertionPosition(items, comparator,
indexInItems, element, parentPath);
if (indexInItems == items.length) {
createTreeItem(widget, element, -1);
newItems++;
} else {
int insertionIndexInItems = indexInItems;
while( insertionIndexInItems < items.length
&& internalCompare(comparator, parentPath, element,
items[insertionIndexInItems].getData()) == 0) {
if (items[insertionIndexInItems].getData().equals(element)) {
internalRefresh(element);
continue elementloop;
}
insertionIndexInItems++;
}
if (insertionIndexInItems == items.length) {
createTreeItem(widget, element, -1);
newItems++;
} else {
createTreeItem(widget, element, insertionIndexInItems + newItems);
newItems++;
}
}
}
}
private boolean itemExists(Item[] items, Object element) {
if (usingElementMap()) {
Widget[] existingItems = findItems(element);
if (existingItems.length == 0) {
return false;
} else if (existingItems.length == 1) {
if (items.length > 0 && existingItems[0] instanceof Item) {
Item existingItem = (Item) existingItems[0];
return getParentItem(existingItem) == getParentItem(items[0]);
}
}
}
for (int i = 0; i < items.length; i++) {
if (items[i].getData().equals(element)) {
return true;
}
}
return false;
}
private int insertionPosition(Item[] items, ViewerComparator comparator,
int lastInsertion, Object element, TreePath parentPath) {
int size = items.length;
if (comparator == null) {
return size;
}
int min = lastInsertion, max = size - 1;
while (min <= max) {
int mid = (min + max) / 2;
Object data = items[mid].getData();
int compare = internalCompare(comparator, parentPath, data, element);
if (compare == 0) {
return mid; }
if (compare < 0) {
min = mid + 1;
} else {
max = mid - 1;
}
}
return min;
}
protected int indexForElement(Widget parent, Object element) {
ViewerComparator comparator = getComparator();
TreePath parentPath = internalGetSorterParentPath(parent, comparator);
Item[] items = getChildren(parent);
int count = items.length;
if (comparator == null) {
return count;
}
int min = 0, max = count - 1;
while (min <= max) {
int mid = (min + max) / 2;
Object data = items[mid].getData();
int compare = internalCompare(comparator, parentPath, data, element);
if (compare == 0) {
while (compare == 0) {
++mid;
if (mid >= count) {
break;
}
data = items[mid].getData();
compare = internalCompare(comparator, parentPath, data,
element);
}
return mid;
}
if (compare < 0) {
min = mid + 1;
} else {
max = mid - 1;
}
}
return min;
}
private TreePath internalGetSorterParentPath(Widget parent,
ViewerComparator comparator) {
TreePath path;
if (comparator instanceof TreePathViewerSorter
&& parent instanceof Item) {
Item item = (Item) parent;
path = getTreePathFromItem(item);
} else {
path = null;
}
return path;
}
private int internalCompare(ViewerComparator comparator,
TreePath parentPath, Object e1, Object e2) {
if (comparator instanceof TreePathViewerSorter) {
TreePathViewerSorter tpvs = (TreePathViewerSorter) comparator;
return tpvs.compare(this, parentPath, e1, e2);
}
return comparator.compare(this, e1, e2);
}
protected Object[] getSortedChildren(Object parentElementOrTreePath) {
Object[] result = getFilteredChildren(parentElementOrTreePath);
ViewerComparator comparator = getComparator();
if (parentElementOrTreePath != null
&& comparator instanceof TreePathViewerSorter) {
TreePathViewerSorter tpvs = (TreePathViewerSorter) comparator;
result = (Object[]) result.clone();
TreePath path = null;
if (parentElementOrTreePath instanceof TreePath) {
path = (TreePath) parentElementOrTreePath;
} else {
Object parent = parentElementOrTreePath;
Widget w = internalGetWidgetToSelect(parent);
if (w != null) {
path = internalGetSorterParentPath(w, comparator);
}
}
tpvs.sort(this, path, result);
} else if (comparator != null) {
result = (Object[]) result.clone();
comparator.sort(this, result);
}
return result;
}
protected Object[] getFilteredChildren(Object parentElementOrTreePath) {
Object[] result = getRawChildren(parentElementOrTreePath);
ViewerFilter[] filters = getFilters();
for (int i = 0; i < filters.length; i++) {
ViewerFilter filter = filters[i];
result = filter.filter(this, parentElementOrTreePath, result);
}
return result;
}
public void add(Object parentElementOrTreePath, Object childElement) {
add(parentElementOrTreePath, new Object[] { childElement });
}
protected void addSelectionListener(Control control,
SelectionListener listener) {
}
public void addTreeListener(ITreeViewerListener listener) {
treeListeners.add(listener);
}
protected abstract void addTreeListener(Control control,
TreeListener listener);
protected void associate(Object element, Item item) {
Object data = item.getData();
if (data != null && data != element && equals(data, element)) {
unmapElement(data, item);
item.setData(element);
mapElement(element, item);
} else {
super.associate(element, item);
}
}
public void collapseAll() {
Object root = getRoot();
if (root != null) {
collapseToLevel(root, ALL_LEVELS);
}
}
public void collapseToLevel(Object elementOrTreePath, int level) {
Assert.isNotNull(elementOrTreePath);
Widget w = internalGetWidgetToSelect(elementOrTreePath);
if (w != null) {
internalCollapseToLevel(w, level);
}
}
protected void createChildren(final Widget widget) {
boolean oldBusy = isBusy();
setBusy(true);
try {
final Item[] tis = getChildren(widget);
if (tis != null && tis.length > 0) {
Object data = tis[0].getData();
if (data != null) {
return; }
}
BusyIndicator.showWhile(widget.getDisplay(), new Runnable() {
public void run() {
if (tis != null) {
for (int i = 0; i < tis.length; i++) {
if (tis[i].getData() != null) {
disassociate(tis[i]);
Assert.isTrue(tis[i].getData() == null,
"Second or later child is non -null");
}
tis[i].dispose();
}
}
Object d = widget.getData();
if (d != null) {
Object parentElement = d;
Object[] children;
if (isTreePathContentProvider() && widget instanceof Item) {
TreePath path = getTreePathFromItem((Item) widget);
children = getSortedChildren(path);
} else {
children = getSortedChildren(parentElement);
}
for (int i = 0; i < children.length; i++) {
createTreeItem(widget, children[i], -1);
}
}
}
});
} finally {
setBusy(oldBusy);
}
}
protected void createTreeItem(Widget parent, Object element, int index) {
Item item = newItem(parent, SWT.NULL, index);
updateItem(item, element);
updatePlus(item, element);
}
protected void disassociate(Item item) {
super.disassociate(item);
if (usingElementMap()) {
disassociateChildren(item);
}
}
private void disassociateChildren(Item item) {
Item[] items = getChildren(item);
for (int i = 0; i < items.length; i++) {
if (items[i].getData() != null) {
disassociate(items[i]);
}
}
}
protected Widget doFindInputItem(Object element) {
Object root = getRoot();
if (root == null) {
return null;
}
if (equals(root, element)) {
return getControl();
}
return null;
}
protected Widget doFindItem(Object element) {
Object root = getRoot();
if (root == null) {
return null;
}
Item[] items = getChildren(getControl());
if (items != null) {
for (int i = 0; i < items.length; i++) {
Widget o = internalFindItem(items[i], element);
if (o != null) {
return o;
}
}
}
return null;
}
protected void doUpdateItem(final Item item, Object element) {
if (item.isDisposed()) {
unmapElement(element, item);
return;
}
int columnCount = doGetColumnCount();
if (columnCount == 0) columnCount = 1;
ViewerRow viewerRowFromItem = getViewerRowFromItem(item);
boolean isVirtual = (getControl().getStyle() & SWT.VIRTUAL) != 0;
if (isVirtual) {
viewerRowFromItem = (ViewerRow) viewerRowFromItem.clone();
}
for (int column = 0; column < columnCount; column++) {
ViewerColumn columnViewer = getViewerColumn(column);
ViewerCell cellToUpdate = updateCell(viewerRowFromItem, column,
element);
if (isVirtual) {
cellToUpdate = new ViewerCell(cellToUpdate.getViewerRow(), cellToUpdate.getColumnIndex(), element);
}
columnViewer.refresh(cellToUpdate);
updateCell(null, 0, null);
if (item.isDisposed()) {
unmapElement(element, item);
return;
}
}
}
protected boolean isSameSelection(List items, Item[] current) {
int n = items.size();
if (n != current.length) {
return false;
}
CustomHashtable itemSet = newHashtable(n * 2 + 1);
for (Iterator i = items.iterator(); i.hasNext();) {
Item item = (Item) i.next();
Object element = item.getData();
itemSet.put(element, element);
}
for (int i = 0; i < current.length; i++) {
if (current[i].getData() == null
|| !itemSet.containsKey(current[i].getData())) {
return false;
}
}
return true;
}
protected void doUpdateItem(Widget widget, Object element, boolean fullMap) {
boolean oldBusy = isBusy();
setBusy(true);
try {
if (widget instanceof Item) {
Item item = (Item) widget;
if (fullMap) {
associate(element, item);
} else {
Object data = item.getData();
if (data != null) {
unmapElement(data, item);
}
item.setData(element);
mapElement(element, item);
}
SafeRunnable.run(new UpdateItemSafeRunnable(item, element));
}
} finally {
setBusy(oldBusy);
}
}
public void expandAll() {
expandToLevel(ALL_LEVELS);
}
public void expandToLevel(int level) {
expandToLevel(getRoot(), level);
}
public void expandToLevel(Object elementOrTreePath, int level) {
if (checkBusy())
return;
Widget w = internalExpand(elementOrTreePath, true);
if (w != null) {
internalExpandToLevel(w, level);
}
}
protected void fireTreeCollapsed(final TreeExpansionEvent event) {
Object[] listeners = treeListeners.getListeners();
boolean oldBusy = isBusy();
setBusy(true);
try {
for (int i = 0; i < listeners.length; ++i) {
final ITreeViewerListener l = (ITreeViewerListener) listeners[i];
SafeRunnable.run(new SafeRunnable() {
public void run() {
l.treeCollapsed(event);
}
});
}
} finally {
setBusy(oldBusy);
}
}
protected void fireTreeExpanded(final TreeExpansionEvent event) {
Object[] listeners = treeListeners.getListeners();
boolean oldBusy = isBusy();
setBusy(true);
try {
for (int i = 0; i < listeners.length; ++i) {
final ITreeViewerListener l = (ITreeViewerListener) listeners[i];
SafeRunnable.run(new SafeRunnable() {
public void run() {
l.treeExpanded(event);
}
});
}
} finally {
setBusy(oldBusy);
}
}
public int getAutoExpandLevel() {
return expandToLevel;
}
protected abstract Item[] getChildren(Widget widget);
protected Item getChild(Widget widget, int index) {
return getChildren(widget)[index];
}
protected abstract boolean getExpanded(Item item);
public Object[] getExpandedElements() {
ArrayList items = new ArrayList();
internalCollectExpandedItems(items, getControl());
ArrayList result = new ArrayList(items.size());
for (Iterator it = items.iterator(); it.hasNext();) {
Item item = (Item) it.next();
Object data = item.getData();
if (data != null) {
result.add(data);
}
}
return result.toArray();
}
public boolean getExpandedState(Object elementOrTreePath) {
Assert.isNotNull(elementOrTreePath);
Widget item = internalGetWidgetToSelect(elementOrTreePath);
if (item instanceof Item) {
return getExpanded((Item) item);
}
return false;
}
protected abstract int getItemCount(Control control);
protected abstract int getItemCount(Item item);
protected abstract Item[] getItems(Item item);
protected Item getNextItem(Item item, boolean includeChildren) {
if (item == null) {
return null;
}
if (includeChildren && getExpanded(item)) {
Item[] children = getItems(item);
if (children != null && children.length > 0) {
return children[0];
}
}
Item parent = getParentItem(item);
if (parent == null) {
return null;
}
Item[] siblings = getItems(parent);
if (siblings != null) {
if (siblings.length <= 1) {
return getNextItem(parent, false);
}
for (int i = 0; i < siblings.length; i++) {
if (siblings[i] == item && i < (siblings.length - 1)) {
return siblings[i + 1];
}
}
}
return getNextItem(parent, false);
}
protected abstract Item getParentItem(Item item);
protected Item getPreviousItem(Item item) {
Item parent = getParentItem(item);
if (parent == null) {
return null;
}
Item[] siblings = getItems(parent);
if (siblings.length == 0 || siblings[0] == item) {
return parent;
}
Item previous = siblings[0];
for (int i = 1; i < siblings.length; i++) {
if (siblings[i] == item) {
return rightMostVisibleDescendent(previous);
}
previous = siblings[i];
}
return null;
}
protected Object[] getRawChildren(Object parentElementOrTreePath) {
boolean oldBusy = isBusy();
setBusy(true);
try {
Object parent;
TreePath path;
if (parentElementOrTreePath instanceof TreePath) {
path = (TreePath) parentElementOrTreePath;
parent = path.getLastSegment();
} else {
parent = parentElementOrTreePath;
path = null;
}
if (parent != null) {
if (equals(parent, getRoot())) {
return super.getRawChildren(parent);
}
IContentProvider cp = getContentProvider();
if (cp instanceof ITreePathContentProvider) {
ITreePathContentProvider tpcp = (ITreePathContentProvider) cp;
if (path == null) {
Widget w = findItem(parent);
if (w instanceof Item) {
Item item = (Item) w;
path = getTreePathFromItem(item);
}
if (path == null) {
path = new TreePath(new Object[] { parent });
}
}
Object[] result = tpcp.getChildren(path);
if (result != null) {
return result;
}
} else if (cp instanceof ITreeContentProvider) {
ITreeContentProvider tcp = (ITreeContentProvider) cp;
Object[] result = tcp.getChildren(parent);
if (result != null) {
return result;
}
}
}
return new Object[0];
} finally {
setBusy(oldBusy);
}
}
protected abstract Item[] getSelection(Control control);
protected List getSelectionFromWidget() {
Widget[] items = getSelection(getControl());
ArrayList list = new ArrayList(items.length);
for (int i = 0; i < items.length; i++) {
Widget item = items[i];
Object e = item.getData();
if (e != null) {
list.add(e);
}
}
return list;
}
protected void handleDoubleSelect(SelectionEvent event) {
Control control = getControl();
if (control != null && !control.isDisposed()) {
ISelection selection;
if (event.item != null && event.item.getData() != null) {
TreePath treePath = getTreePathFromItem((Item) event.item);
selection = new TreeSelection(treePath);
} else {
selection = getSelection();
updateSelection(selection);
}
fireDoubleClick(new DoubleClickEvent(this, selection));
}
}
protected void handleTreeCollapse(TreeEvent event) {
if (event.item.getData() != null) {
fireTreeCollapsed(new TreeExpansionEvent(this, event.item.getData()));
}
}
protected void handleTreeExpand(TreeEvent event) {
createChildren(event.item);
if (event.item.getData() != null) {
fireTreeExpanded(new TreeExpansionEvent(this, event.item.getData()));
}
}
protected void hookControl(Control control) {
super.hookControl(control);
addTreeListener(control, new TreeListener() {
public void treeExpanded(TreeEvent event) {
handleTreeExpand(event);
}
public void treeCollapsed(TreeEvent event) {
handleTreeCollapse(event);
}
});
}
protected void inputChanged(Object input, Object oldInput) {
preservingSelection(new Runnable() {
public void run() {
Control tree = getControl();
tree.setRedraw(false);
try {
removeAll(tree);
tree.setData(getRoot());
internalInitializeTree(tree);
} finally {
tree.setRedraw(true);
}
}
});
}
protected void internalInitializeTree(Control tree) {
createChildren(tree);
internalExpandToLevel(tree, expandToLevel);
}
protected void internalCollapseToLevel(Widget widget, int level) {
if (level == ALL_LEVELS || level > 0) {
if (widget instanceof Item) {
Item item = (Item) widget;
setExpanded(item, false);
Object element = item.getData();
if (element != null && level == ALL_LEVELS) {
if (optionallyPruneChildren(item, element)) {
return;
}
}
}
if (level == ALL_LEVELS || level > 1) {
Item[] children = getChildren(widget);
if (children != null) {
int nextLevel = (level == ALL_LEVELS ? ALL_LEVELS
: level - 1);
for (int i = 0; i < children.length; i++) {
internalCollapseToLevel(children[i], nextLevel);
}
}
}
}
}
private void internalCollectExpandedItems(List result, Widget widget) {
Item[] items = getChildren(widget);
for (int i = 0; i < items.length; i++) {
Item item = items[i];
if (getExpanded(item)) {
result.add(item);
}
internalCollectExpandedItems(result, item);
}
}
protected Widget internalExpand(Object elementOrPath, boolean expand) {
if (elementOrPath == null) {
return null;
}
Widget w = internalGetWidgetToSelect(elementOrPath);
if (w == null) {
if (equals(elementOrPath, getRoot())) { return null;
}
Object parent = getParentElement(elementOrPath);
if (parent != null) {
Widget pw = internalExpand(parent, false);
if (pw != null) {
createChildren(pw);
Object element = internalToElement(elementOrPath);
w = internalFindChild(pw, element);
if (expand && pw instanceof Item) {
Item item = (Item) pw;
LinkedList toExpandList = new LinkedList();
while (item != null && !getExpanded(item)) {
toExpandList.addFirst(item);
item = getParentItem(item);
}
for (Iterator it = toExpandList.iterator(); it
.hasNext();) {
Item toExpand = (Item) it.next();
setExpanded(toExpand, true);
}
}
}
}
}
return w;
}
private Object internalToElement(Object elementOrPath) {
if (elementOrPath instanceof TreePath) {
return ((TreePath) elementOrPath).getLastSegment();
}
return elementOrPath;
}
protected Object getParentElement(Object elementOrTreePath) {
if (elementOrTreePath instanceof TreePath) {
TreePath treePath = (TreePath) elementOrTreePath;
return (treePath).getParentPath();
}
IContentProvider cp = getContentProvider();
if (cp instanceof ITreePathContentProvider) {
ITreePathContentProvider tpcp = (ITreePathContentProvider) cp;
TreePath[] paths = tpcp.getParents(elementOrTreePath);
if (paths.length > 0) {
if (paths[0].getSegmentCount() == 0) {
return getRoot();
}
return paths[0].getLastSegment();
}
}
if (cp instanceof ITreeContentProvider) {
ITreeContentProvider tcp = (ITreeContentProvider) cp;
return tcp.getParent(elementOrTreePath);
}
return null;
}
protected Widget internalGetWidgetToSelect(Object elementOrTreePath) {
if (elementOrTreePath instanceof TreePath) {
TreePath treePath = (TreePath) elementOrTreePath;
if (treePath.getSegmentCount() == 0) {
return getControl();
}
Widget[] candidates = findItems(treePath.getLastSegment());
for (int i = 0; i < candidates.length; i++) {
Widget candidate = candidates[i];
if (!(candidate instanceof Item)) {
continue;
}
if (treePath.equals(getTreePathFromItem((Item) candidate),
getComparer())) {
return candidate;
}
}
return null;
}
return findItem(elementOrTreePath);
}
protected void internalExpandToLevel(Widget widget, int level) {
if (level == ALL_LEVELS || level > 0) {
if (widget instanceof Item && widget.getData() != null
&& !isExpandable((Item) widget, null, widget.getData())) {
return;
}
createChildren(widget);
if (widget instanceof Item) {
setExpanded((Item) widget, true);
}
if (level == ALL_LEVELS || level > 1) {
Item[] children = getChildren(widget);
if (children != null) {
int newLevel = (level == ALL_LEVELS ? ALL_LEVELS
: level - 1);
for (int i = 0; i < children.length; i++) {
internalExpandToLevel(children[i], newLevel);
}
}
}
}
}
private Widget internalFindChild(Widget parent, Object element) {
Item[] items = getChildren(parent);
for (int i = 0; i < items.length; i++) {
Item item = items[i];
Object data = item.getData();
if (data != null && equals(data, element)) {
return item;
}
}
return null;
}
private Widget internalFindItem(Item parent, Object element) {
Object data = parent.getData();
if (data != null) {
if (equals(data, element)) {
return parent;
}
}
Item[] items = getChildren(parent);
for (int i = 0; i < items.length; i++) {
Item item = items[i];
Widget o = internalFindItem(item, element);
if (o != null) {
return o;
}
}
return null;
}
protected void internalRefresh(Object element) {
internalRefresh(element, true);
}
protected void internalRefresh(Object element, boolean updateLabels) {
if (element == null) {
internalRefresh(getControl(), getRoot(), true, updateLabels);
return;
}
Widget[] items = findItems(element);
if (items.length != 0) {
for (int i = 0; i < items.length; i++) {
internalRefresh(items[i], element, true, updateLabels);
}
}
}
protected void internalRefresh(Widget widget, Object element,
boolean doStruct, boolean updateLabels) {
if (widget instanceof Item) {
if (doStruct) {
updatePlus((Item) widget, element);
}
if (updateLabels || !equals(element, widget.getData())) {
doUpdateItem(widget, element, true);
} else {
associate(element, (Item) widget);
}
}
if (doStruct) {
internalRefreshStruct(widget, element, updateLabels);
} else {
Item[] children = getChildren(widget);
if (children != null) {
for (int i = 0; i < children.length; i++) {
Widget item = children[i];
Object data = item.getData();
if (data != null) {
internalRefresh(item, data, doStruct, updateLabels);
}
}
}
}
}
void internalRefreshStruct(Widget widget, Object element,
boolean updateLabels) {
updateChildren(widget, element, null, updateLabels);
Item[] children = getChildren(widget);
if (children != null) {
for (int i = 0; i < children.length; i++) {
Widget item = children[i];
Object data = item.getData();
if (data != null) {
internalRefreshStruct(item, data, updateLabels);
}
}
}
}
protected void internalRemove(Object[] elementsOrPaths) {
Object input = getInput();
for (int i = 0; i < elementsOrPaths.length; ++i) {
Object element = elementsOrPaths[i];
if (equals(element, input)) {
setInput(null);
return;
}
Widget[] childItems = internalFindItems(element);
if (childItems.length > 0) {
for (int j = 0; j < childItems.length; j++) {
Widget childItem = childItems[j];
if (childItem instanceof Item) {
disassociate((Item) childItem);
childItem.dispose();
}
}
} else {
Object parent = getParentElement(element);
if (parent != null
&& !equals(parent, getRoot())
&& !(parent instanceof TreePath && ((TreePath) parent)
.getSegmentCount() == 0)) {
Widget[] parentItems = internalFindItems(parent);
for (int j = 0; j < parentItems.length; j++) {
Widget parentItem = parentItems[j];
if (parentItem instanceof Item) {
updatePlus((Item) parentItem, parent);
}
}
}
}
}
}
protected void internalRemove(Object parent, Object[] elements) {
CustomHashtable toRemove = new CustomHashtable(getComparer());
for (int i = 0; i < elements.length; i++) {
toRemove.put(elements[i], elements[i]);
}
Widget[] parentItemArray = findItems(parent);
for (int i = 0; i < parentItemArray.length; i++) {
Widget parentItem = parentItemArray[i];
if (parentItem.isDisposed())
continue;
Item[] children = getChildren(parentItem);
if (children.length == 1 && children[0].getData() == null &&
parentItem instanceof Item) { updatePlus((Item) parentItem, parent);
} else {
for (int j = 0; j < children.length; j++) {
Item child = children[j];
Object data = child.getData();
if (data != null && toRemove.containsKey(data)) {
disassociate(child);
child.dispose();
}
}
}
}
}
private void internalSetExpanded(CustomHashtable expandedElements,
Widget widget) {
Item[] items = getChildren(widget);
for (int i = 0; i < items.length; i++) {
Item item = items[i];
Object data = item.getData();
if (data != null) {
boolean expanded = expandedElements.remove(data) != null;
if (expanded != getExpanded(item)) {
if (expanded) {
createChildren(item);
}
setExpanded(item, expanded);
}
}
if (expandedElements.size() > 0) {
internalSetExpanded(expandedElements, item);
}
}
}
private void internalSetExpandedTreePaths(
CustomHashtable expandedTreePaths, Widget widget,
TreePath currentPath) {
Item[] items = getChildren(widget);
for (int i = 0; i < items.length; i++) {
Item item = items[i];
Object data = item.getData();
TreePath childPath = data == null ? null : currentPath
.createChildPath(data);
if (data != null && childPath != null) {
boolean expanded = expandedTreePaths.remove(childPath) != null;
if (expanded != getExpanded(item)) {
if (expanded) {
createChildren(item);
}
setExpanded(item, expanded);
}
}
internalSetExpandedTreePaths(expandedTreePaths, item, childPath);
}
}
public boolean isExpandable(Object elementOrTreePath) {
Object element;
TreePath path;
if (elementOrTreePath instanceof TreePath) {
path = (TreePath) elementOrTreePath;
element = path.getLastSegment();
} else {
element = elementOrTreePath;
path = null;
}
IContentProvider cp = getContentProvider();
if (cp instanceof ITreePathContentProvider) {
ITreePathContentProvider tpcp = (ITreePathContentProvider) cp;
if (path == null) {
Widget w = findItem(element);
if (w instanceof Item) {
Item item = (Item) w;
path = getTreePathFromItem(item);
}
if (path == null) {
path = new TreePath(new Object[] { element });
}
}
return tpcp.hasChildren(path);
}
if (cp instanceof ITreeContentProvider) {
ITreeContentProvider tcp = (ITreeContentProvider) cp;
return tcp.hasChildren(element);
}
return false;
}
private boolean isExpandable(Item item, TreePath parentPath, Object element) {
Object elementOrTreePath = element;
if (isTreePathContentProvider()) {
if (parentPath != null) {
elementOrTreePath = parentPath.createChildPath(element);
} else {
elementOrTreePath = getTreePathFromItem(item);
}
}
return isExpandable(elementOrTreePath);
}
protected void labelProviderChanged() {
Control tree = getControl();
tree.setRedraw(false);
internalRefresh(tree, getRoot(), false, true);
tree.setRedraw(true);
}
protected abstract Item newItem(Widget parent, int style, int index);
public void remove(final Object[] elementsOrTreePaths) {
assertElementsNotNull(elementsOrTreePaths);
if (elementsOrTreePaths.length == 0) {
return;
}
if (checkBusy())
return;
preservingSelection(new Runnable() {
public void run() {
internalRemove(elementsOrTreePaths);
}
});
}
public void remove(final Object parent, final Object[] elements) {
assertElementsNotNull(elements);
if (elements.length == 0) {
return;
}
if (checkBusy())
return;
preservingSelection(new Runnable() {
public void run() {
internalRemove(parent, elements);
}
});
}
public void remove(Object elementsOrTreePaths) {
remove(new Object[] { elementsOrTreePaths });
}
protected abstract void removeAll(Control control);
public void removeTreeListener(ITreeViewerListener listener) {
treeListeners.remove(listener);
}
public void reveal(Object elementOrTreePath) {
Assert.isNotNull(elementOrTreePath);
Widget w = internalExpand(elementOrTreePath, true);
if (w instanceof Item) {
showItem((Item) w);
}
}
private Item rightMostVisibleDescendent(Item item) {
Item[] children = getItems(item);
if (getExpanded(item) && children != null && children.length > 0) {
return rightMostVisibleDescendent(children[children.length - 1]);
}
return item;
}
public Item scrollDown(int x, int y) {
Item current = getItem(x, y);
if (current != null) {
Item next = getNextItem(current, true);
showItem(next == null ? current : next);
return next;
}
return null;
}
public Item scrollUp(int x, int y) {
Item current = getItem(x, y);
if (current != null) {
Item previous = getPreviousItem(current);
showItem(previous == null ? current : previous);
return previous;
}
return null;
}
public void setAutoExpandLevel(int level) {
expandToLevel = level;
}
public void setContentProvider(IContentProvider provider) {
super.setContentProvider(provider);
}
protected void assertContentProviderType(IContentProvider provider) {
Assert.isTrue(provider instanceof ITreeContentProvider
|| provider instanceof ITreePathContentProvider);
}
protected abstract void setExpanded(Item item, boolean expand);
public void setExpandedElements(Object[] elements) {
assertElementsNotNull(elements);
if (checkBusy()) {
return;
}
CustomHashtable expandedElements = newHashtable(elements.length * 2 + 1);
for (int i = 0; i < elements.length; ++i) {
Object element = elements[i];
internalExpand(element, false);
expandedElements.put(element, element);
}
internalSetExpanded(expandedElements, getControl());
}
public void setExpandedTreePaths(TreePath[] treePaths) {
assertElementsNotNull(treePaths);
if (checkBusy())
return;
final IElementComparer comparer = getComparer();
IElementComparer treePathComparer = new IElementComparer() {
public boolean equals(Object a, Object b) {
return ((TreePath) a).equals(((TreePath) b), comparer);
}
public int hashCode(Object element) {
return ((TreePath) element).hashCode(comparer);
}
};
CustomHashtable expandedTreePaths = new CustomHashtable(
treePaths.length * 2 + 1, treePathComparer);
for (int i = 0; i < treePaths.length; ++i) {
TreePath treePath = treePaths[i];
internalExpand(treePath, false);
expandedTreePaths.put(treePath, treePath);
}
internalSetExpandedTreePaths(expandedTreePaths, getControl(),
new TreePath(new Object[0]));
}
public void setExpandedState(Object elementOrTreePath, boolean expanded) {
Assert.isNotNull(elementOrTreePath);
if (checkBusy())
return;
Widget item = internalExpand(elementOrTreePath, false);
if (item instanceof Item) {
if (expanded) {
createChildren(item);
}
setExpanded((Item) item, expanded);
}
}
protected abstract void setSelection(List items);
protected void setSelectionToWidget(List v, boolean reveal) {
if (v == null) {
setSelection(new ArrayList(0));
return;
}
int size = v.size();
List newSelection = new ArrayList(size);
for (int i = 0; i < size; ++i) {
Object elementOrTreePath = v.get(i);
Widget w = internalExpand(elementOrTreePath, false);
if (w instanceof Item) {
newSelection.add(w);
} else if (w == null && elementOrTreePath instanceof TreePath) {
TreePath treePath = (TreePath) elementOrTreePath;
Object element = treePath.getLastSegment();
if (element != null) {
w = internalExpand(element, false);
if (w instanceof Item) {
newSelection.add(w);
}
}
}
}
setSelection(newSelection);
if (reveal && newSelection.size() > 0) {
for (int i = (newSelection.size()-1); i >= 0; i--) {
showItem((Item) newSelection.get(i));
}
}
}
protected abstract void showItem(Item item);
protected void updateChildren(Widget widget, Object parent,
Object[] elementChildren) {
updateChildren(widget, parent, elementChildren, true);
}
private void updateChildren(Widget widget, Object parent,
Object[] elementChildren, boolean updateLabels) {
if (widget instanceof Item) {
Item ti = (Item) widget;
if (!getExpanded(ti)) {
if (optionallyPruneChildren(ti, parent)) {
return;
}
Item[] its = getItems(ti);
if (isExpandable(ti, null, parent)) {
if (its.length == 0) {
newItem(ti, SWT.NULL, -1);
return;
} else if (its.length == 1 && its[0].getData() == null) {
return;
}
} else {
for (int i = 0; i < its.length; i++) {
if (its[i].getData() != null) {
disassociate(its[i]);
}
its[i].dispose();
}
return;
}
}
}
if (elementChildren == null) {
if (isTreePathContentProvider() && widget instanceof Item) {
TreePath path = getTreePathFromItem((Item) widget);
elementChildren = getSortedChildren(path);
} else {
elementChildren = getSortedChildren(parent);
}
}
Control tree = getControl();
int oldCnt = -1;
if (widget == tree) {
oldCnt = getItemCount(tree);
}
Item[] items = getChildren(widget);
CustomHashtable expanded = newHashtable(CustomHashtable.DEFAULT_CAPACITY); for (int i = 0; i < items.length; ++i) {
if (getExpanded(items[i])) {
Object element = items[i].getData();
if (element != null) {
expanded.put(element, element);
}
}
}
int min = Math.min(elementChildren.length, items.length);
int numItemsToDispose = items.length - min;
if (numItemsToDispose > 0) {
CustomHashtable children = newHashtable(elementChildren.length * 2);
for (int i = 0; i < elementChildren.length; i++) {
Object elementChild = elementChildren[i];
children.put(elementChild, elementChild);
}
int i = 0;
while (numItemsToDispose > 0 && i < items.length) {
Object data = items[i].getData();
if (data == null || items.length - i <= numItemsToDispose || !children.containsKey(data)) {
if (data != null) {
disassociate(items[i]);
}
items[i].dispose();
if (i + 1 < items.length) {
System.arraycopy(items, i + 1, items, i, items.length - (i+1));
}
numItemsToDispose--;
} else {
i++;
}
}
}
for (int i = 0; i < min; ++i) {
Item item = items[i];
Object oldElement = item.getData();
if (oldElement != null) {
Object newElement = elementChildren[i];
if (newElement != oldElement) {
if (equals(newElement, oldElement)) {
Object data = item.getData();
if (data != null) {
unmapElement(data, item);
}
item.setData(newElement);
mapElement(newElement, item);
} else {
disassociate(item);
item.setImage(null);
item.setText("");
}
}
}
}
for (int i = 0; i < min; ++i) {
Item item = items[i];
Object newElement = elementChildren[i];
if (item.getData() == null) {
associate(newElement, item);
updatePlus(item, newElement);
updateItem(item, newElement);
} else {
updatePlus(item, newElement);
if (updateLabels) {
updateItem(item, newElement);
}
}
}
for (int i = 0; i < min; ++i) {
Item item = items[i];
Object newElement = elementChildren[i];
setExpanded(item, expanded.containsKey(newElement));
}
if (min < elementChildren.length) {
for (int i = min; i < elementChildren.length; ++i) {
createTreeItem(widget, elementChildren[i], i);
}
if (expanded.size() > 0) {
items = getChildren(widget);
for (int i = min; i < elementChildren.length; ++i) {
if (expanded.containsKey(elementChildren[i])) {
setExpanded(items[i], true);
}
}
}
}
if (widget == tree && oldCnt == 0 && getItemCount(tree) != 0) {
tree.setRedraw(false);
tree.setRedraw(true);
}
}
boolean optionallyPruneChildren(Item item, Object element) {
boolean needDummy = isExpandable(item, null, element);
boolean haveDummy = false;
Item[] items = getItems(item);
for (int i = 0; i < items.length; i++) {
if (items[i].getData() != null) {
disassociate(items[i]);
items[i].dispose();
} else {
if (needDummy && !haveDummy) {
haveDummy = true;
} else {
items[i].dispose();
}
}
}
if (needDummy && !haveDummy) {
newItem(item, SWT.NULL, -1);
}
return true;
}
public Item[] getChildren(Widget widget, Object[] elementChildren) {
return getChildren(widget);
}
protected void updatePlus(Item item, Object element) {
boolean hasPlus = getItemCount(item) > 0;
boolean needsPlus = isExpandable(item, null, element);
boolean removeAll = false;
boolean addDummy = false;
Object data = item.getData();
if (data != null && equals(element, data)) {
if (hasPlus != needsPlus) {
if (needsPlus) {
addDummy = true;
} else {
removeAll = true;
}
}
} else {
removeAll = true;
addDummy = needsPlus;
setExpanded(item, false);
}
if (removeAll) {
Item[] items = getItems(item);
for (int i = 0; i < items.length; i++) {
if (items[i].getData() != null) {
disassociate(items[i]);
}
items[i].dispose();
}
}
if (addDummy) {
newItem(item, SWT.NULL, -1); }
}
public Object[] getVisibleExpandedElements() {
ArrayList v = new ArrayList();
internalCollectVisibleExpanded(v, getControl());
return v.toArray();
}
private void internalCollectVisibleExpanded(ArrayList result, Widget widget) {
Item[] items = getChildren(widget);
for (int i = 0; i < items.length; i++) {
Item item = items[i];
if (getExpanded(item)) {
Object data = item.getData();
if (data != null) {
result.add(data);
}
internalCollectVisibleExpanded(result, item);
}
}
}
protected TreePath getTreePathFromItem(Item item) {
LinkedList segments = new LinkedList();
while (item != null) {
Object segment = item.getData();
Assert.isNotNull(segment);
segments.addFirst(segment);
item = getParentItem(item);
}
return new TreePath(segments.toArray());
}
public ISelection getSelection() {
Control control = getControl();
if (control == null || control.isDisposed()) {
return TreeSelection.EMPTY;
}
Widget[] items = getSelection(getControl());
ArrayList list = new ArrayList(items.length);
for (int i = 0; i < items.length; i++) {
Widget item = items[i];
if (item.getData() != null) {
list.add(getTreePathFromItem((Item) item));
}
}
return new TreeSelection((TreePath[]) list.toArray(new TreePath[list
.size()]), getComparer());
}
protected void setSelectionToWidget(ISelection selection, boolean reveal) {
if (selection instanceof ITreeSelection) {
ITreeSelection treeSelection = (ITreeSelection) selection;
setSelectionToWidget(Arrays.asList(treeSelection.getPaths()),
reveal);
} else {
super.setSelectionToWidget(selection, reveal);
}
}
public TreePath[] getExpandedTreePaths() {
ArrayList items = new ArrayList();
internalCollectExpandedItems(items, getControl());
ArrayList result = new ArrayList(items.size());
for (Iterator it = items.iterator(); it.hasNext();) {
Item item = (Item) it.next();
TreePath treePath = getTreePathFromItem(item);
if (treePath != null) {
result.add(treePath);
}
}
return (TreePath[]) result.toArray(new TreePath[items.size()]);
}
private boolean isTreePathContentProvider() {
return getContentProvider() instanceof ITreePathContentProvider;
}
public void insert(Object parentElementOrTreePath, Object element,
int position) {
Assert.isNotNull(parentElementOrTreePath);
Assert.isNotNull(element);
if (checkBusy())
return;
if (getComparator() != null || hasFilters()) {
add(parentElementOrTreePath, new Object[] { element });
return;
}
Widget[] items;
if (internalIsInputOrEmptyPath(parentElementOrTreePath)) {
items = new Widget[] { getControl() };
} else {
items = internalFindItems(parentElementOrTreePath);
}
for (int i = 0; i < items.length; i++) {
Widget widget = items[i];
if (widget instanceof Item) {
Item item = (Item) widget;
Item[] childItems = getChildren(item);
if (getExpanded(item)
|| (childItems.length > 0 && childItems[0].getData() != null)) {
int insertionPosition = position;
if (insertionPosition == -1) {
insertionPosition = getItemCount(item);
}
createTreeItem(item, element, insertionPosition);
} else {
Object parentElement = parentElementOrTreePath;
if (element instanceof TreePath)
parentElement = ((TreePath) parentElement).getLastSegment();
updatePlus(item, parentElement);
}
} else {
int insertionPosition = position;
if (insertionPosition == -1) {
insertionPosition = getItemCount((Control) widget);
}
createTreeItem(widget, element, insertionPosition);
}
}
}
protected Widget getColumnViewerOwner(int columnIndex) {
return null;
}
protected Item getItemAt(Point point) {
return null;
}
protected ColumnViewerEditor createViewerEditor() {
return null;
}
protected int doGetColumnCount() {
return 0;
}
protected void buildLabel(ViewerLabel updateLabel, Object elementOrPath) {
Object element;
if (elementOrPath instanceof TreePath) {
TreePath path = (TreePath) elementOrPath;
IBaseLabelProvider provider = getLabelProvider();
if (provider instanceof ITreePathLabelProvider) {
ITreePathLabelProvider pprov = (ITreePathLabelProvider) provider;
buildLabel(updateLabel, path, pprov);
return;
}
element = path.getLastSegment();
} else {
element = elementOrPath;
}
super.buildLabel(updateLabel, element);
}
final protected boolean internalIsInputOrEmptyPath(final Object elementOrTreePath) {
if (elementOrTreePath.equals(getRoot()))
return true;
if (!(elementOrTreePath instanceof TreePath))
return false;
return ((TreePath) elementOrTreePath).getSegmentCount() == 0;
}
protected ViewerRow getViewerRowFromItem(Widget item) {
return null;
}
}