/******************************************************************************* * Copyright (c) 2012 xored software, Inc. All rights reserved. This program and the accompanying * materials are made available under the terms of the Eclipse Public License v1.0 which accompanies * this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html Contributors: * xored software, Inc. - initial API and implementation (Yuri Strot) ******************************************************************************/ package com.xored.glance.ui.controls.tree; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.widgets.TreeItem; import java.util.ArrayList; import java.util.List; public class TreeNode implements DisposeListener { public static final TreeNode[] EMPTY = new TreeNode[0]; List<TreeNode> kids = new ArrayList<TreeNode>(); List<TreeItemContent> items = new ArrayList<TreeItemContent>(); TreeNode parent; int[] index; TreeItem item; public TreeNode(TreeItem item) { this.item = item; if (item != null) { item.addDisposeListener(this); } } public void add(TreeNode[] nodes) { for (TreeNode node : nodes) { doAdd(node); } notifyRoot(TreeNode.EMPTY, nodes); } public int compareTo(TreeNode that) { int[] index = that.index; for (int i = 0; i < index.length && i < this.index.length; i++) { int diff = this.index[i] - index[i]; if (diff != 0) { return diff; } } return this.index.length - index.length; } public TreeNode[] getChildren() { return kids.toArray(new TreeNode[0]); } public void remove(TreeNode[] nodes) { doRemove(nodes); notifyRoot(nodes, TreeNode.EMPTY); } @Override public String toString() { int iMax = items.size() - 1; if (iMax == -1) { return "[]"; } StringBuilder b = new StringBuilder(); b.append('['); for (int i = 0;; i++) { b.append(items.get(i)); if (i == iMax) { return b.append(']').toString(); } b.append(", "); } } @Override public void widgetDisposed(DisposeEvent e) { close(); } protected void close() { if (item != null) { if (!item.isDisposed()) { item.removeDisposeListener(this); } for (TreeNode node : kids) { node.close(); } notifyRoot(new TreeNode[] {this}, TreeNode.EMPTY); item = null; } } void collect(TreeNode item, List<TreeNode> items) { items.add(item); for (TreeNode kid : item.kids) { collect(kid, items); } } TreeNode[] collect(TreeNode[] items) { List<TreeNode> result = new ArrayList<TreeNode>(); for (TreeNode item : items) { collect(item, result); } return result.toArray(new TreeNode[0]); } void doAdd(TreeNode node) { node.recalc(index, kids.size()); kids.add(node); node.parent = this; } void doRemove(TreeNode[] nodes) { int minPos = Integer.MAX_VALUE; for (TreeNode node : nodes) { int pos = kids.indexOf(node); if (pos >= 0) { kids.remove(pos); minPos = Math.min(minPos, pos); } } for (int i = minPos; i < kids.size(); i++) { kids.get(i).recalc(index, i); } } TreeItemContent[] getContent(TreeNode[] nodes) { List<TreeItemContent> content = new ArrayList<TreeItemContent>(); nodes = collect(nodes); for (TreeNode node : nodes) { content.addAll(node.items); } return content.toArray(new TreeItemContent[0]); } TreeContent getRoot() { TreeNode node = this; while (node != null) { if (node instanceof TreeContent) { return (TreeContent) node; } node = node.parent; } return null; } void notifyRoot(TreeNode[] removed, TreeNode[] added) { TreeContent root = getRoot(); if (root != null) { root.changed(getContent(removed), getContent(added)); } } void recalc(int[] parent, int cur) { if (parent != null) { index = new int[parent.length + 1]; System.arraycopy(parent, 0, index, 0, parent.length); index[parent.length] = cur; for (int i = 0; i < kids.size(); i++) { kids.get(i).recalc(index, i); } } } }