package yuku.atree; import android.view.*; import android.widget.*; public class TreeAdapter extends BaseAdapter { public static final String TAG = TreeAdapter.class.getSimpleName(); private TreeNode root; private boolean rootVisible = true; private TreeListener listener; @Override public int getCount() { if (root == null) { return 0; } else { return root.getRowCount() - (rootVisible? 0: 1); } } @Override public TreeNode getItem(int position) { if (rootVisible && position == 0) return root; return searchItem(root, rootVisible? 0: -1, position); } private static TreeNode searchItem(TreeNode cur, int base, int target) { if (base == target) return cur; int pos = base + 1; // first child is always one row after for (int i = 0, len = cur.getChildCount(); i < len; i++) { TreeNode child = cur.getChildAt(i); int max = pos + child.getRowCount(); // range covered is pos..<max if (target >= pos && target < max) { return searchItem(child, pos, target); } pos = max; } throw new RuntimeException("invalid target: " + target); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { TreeNode node = getItem(position); return node.getView(position, convertView, parent, node.getLevel(), TreeNodeIconType.up, null); } public void setRoot(TreeNode root) { this.root = root; notifyDataSetChanged(); if (root != null) { dispatchNodeStructureChanged(root); } else { notifyRootChangedToNull(this); } } public boolean getRootVisible() { return rootVisible; } public void setRootVisible(boolean visible) { this.rootVisible = visible; notifyDataSetChanged(); } public void setTreeListener(final TreeListener l) { listener = l; } @SuppressWarnings("unchecked") public <T extends TreeNode> T getRoot() { return (T) root; } public int getIndexOfChild(TreeNode parent, TreeNode child) { if (parent == null || child == null) { return -1; } int numChildren = parent.getChildCount(); for (int i = 0; i < numChildren; i++) { if (child.equals(parent.getChildAt(i))) { return i; } } return -1; } public void reload() { reload(root); } public void reload(final TreeNode node) { dispatchNodeStructureChanged(node); } public void insertNodeInto(final MutableTreeNode newChild, final MutableTreeNode parent, final int index) { parent.insert(newChild, index); dispatchNodesWereInserted(parent, new int[] { index }); } public void removeNodeFromParent(final MutableTreeNode node) { MutableTreeNode parent = node.getParent(); int index = parent.getIndex(node); parent.remove(node); dispatchNodesWereRemoved(parent, new int[] { index }, new TreeNode[] { node }); } public void dispatchNodeChanged(final TreeNode node) { if (node == root) { dispatchNodesChanged(node, null); return; } if (node == null) { return; } final TreeNode parent = node.getParent(); if (parent == null) { return; } dispatchNodesChanged(parent, new int[] { getIndexOfChild(parent, node) }); } public void dispatchNodesChanged(final TreeNode node, final int[] childIndices) { if (node == null || node != root || childIndices == null || childIndices.length == 0) { return; } notifyTreeNodesChanged(getPathToRoot(node), childIndices, getNodeChildren(node, childIndices)); } public void dispatchNodesWereInserted(final TreeNode node, final int[] childIndices) { if (node == null || childIndices == null || childIndices.length == 0) { return; } notifyTreeNodesInserted(this, getPathToRoot(node), childIndices, getNodeChildren(node, childIndices)); } public void dispatchNodesWereRemoved(final TreeNode node, final int[] childIndices, final TreeNode[] removedChildren) { if (node == null || childIndices == null || childIndices.length == 0) { return; } notifyTreeNodesRemoved(this, getPathToRoot(node), childIndices, removedChildren); } public void dispatchNodeStructureChanged(final TreeNode node) { if (node == null) { return; } notifyTreeStructureChanged(this, getPathToRoot(node), null, null); } public TreeNode[] getPathToRoot(final TreeNode aNode) { if (aNode == null) { return new TreeNode[0]; } return getPathToRoot(aNode, 0); } protected TreeNode[] getPathToRoot(final TreeNode aNode, final int depth) { return TreeCommons.getPathToAncestor(aNode, root, depth); } protected void notifyTreeNodesChanged(final TreeNode[] path, final int[] childIndices, final TreeNode[] children) { if (listener == null) return; TreeEvent event = new TreeEvent(path, childIndices, children); listener.onTreeNodesChanged(event); } protected void notifyTreeNodesInserted(final Object source, final TreeNode[] path, final int[] childIndices, final TreeNode[] children) { if (listener == null) return; TreeEvent event = new TreeEvent(path, childIndices, children); listener.onTreeNodesInserted(event); } protected void notifyTreeNodesRemoved(final Object source, final TreeNode[] path, final int[] childIndices, final TreeNode[] children) { if (listener == null) return; TreeEvent event = new TreeEvent(path, childIndices, children); listener.onTreeNodesRemoved(event); } protected void notifyTreeStructureChanged(final Object source, final TreeNode[] path, final int[] childIndices, final TreeNode[] children) { if (listener == null) return; TreeEvent event = new TreeEvent(path, childIndices, children); listener.onTreeStructureChanged(event); } private void notifyRootChangedToNull(final Object source) { TreeEvent event = new TreeEvent((TreePath) null); listener.onTreeStructureChanged(event); } private TreeNode[] getNodeChildren(final TreeNode node, final int[] childIndices) { if (childIndices == null) { return null; } TreeNode[] result = new TreeNode[childIndices.length]; for (int i = 0; i < result.length; i++) { result[i] = node.getChildAt(childIndices[i]); } return result; } }