/******************************************************************************* * Copyright (c) 2012, 2013, 2014 Original authors and others. * 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: * Original authors and others - initial API and implementation * Dirk Fauth <dirk.fauth@googlemail.com> - Deprecated expand/collapse methods since they should reside in ITreeRowModel * Dirk Fauth <dirk.fauth@googlemail.com> - Bug 455364 ******************************************************************************/ package org.eclipse.nebula.widgets.nattable.extension.glazedlists.tree; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.eclipse.nebula.widgets.nattable.tree.ITreeData; import org.eclipse.nebula.widgets.nattable.tree.ITreeRowModel; import ca.odell.glazedlists.TreeList; import ca.odell.glazedlists.TreeList.Node; /** * Implementation of ITreeData that operates on a GlazedLists TreeList. * * @param <T> * The type of objects that are contained in the TreeList. */ public class GlazedListTreeData<T> implements ITreeData<T> { private final TreeList<T> treeList; public GlazedListTreeData(TreeList<T> treeList) { this.treeList = treeList; } @Override @Deprecated public String formatDataForDepth(int depth, int index) { return formatDataForDepth(depth, getDataAtIndex(index)); } @Override @Deprecated public String formatDataForDepth(int depth, T object) { if (object != null) { return object.toString(); } else { return ""; //$NON-NLS-1$ } } @Override public T getDataAtIndex(int index) { if (!isValidIndex(index)) { return null; } return this.treeList.get(index); } @Override public int getDepthOfData(T object) { return getDepthOfData(indexOf(object)); } @Override public int getDepthOfData(int index) { if (!isValidIndex(index)) { return 0; } return this.treeList.depth(index); } @Override public int indexOf(T object) { return this.treeList.indexOf(object); } @Override public boolean hasChildren(T object) { return hasChildren(indexOf(object)); } @Override public boolean hasChildren(int index) { if (!isValidIndex(index)) { return false; } return this.treeList.hasChildren(index); } @Override public List<T> getChildren(T object) { return getChildren(indexOf(object)); } private List<T> getNodeChildren(Node<T> treeNode) { List<T> children = new ArrayList<T>(); for (Node<T> child : treeNode.getChildren()) { children.add(child.getElement()); children.addAll(getNodeChildren(child)); } return children; } @Override public List<T> getChildren(T object, boolean fullDepth) { if (fullDepth == false) { return getChildren(object); } int index = indexOf(object); if (index >= 0) { Node<T> treeNode = this.treeList.getTreeNode(index); return getNodeChildren(treeNode); } return Collections.emptyList(); } @Override public List<T> getChildren(int index) { if (!isValidIndex(index)) { return null; } List<T> children = new ArrayList<T>(); if (index >= 0) { Node<T> treeNode = this.treeList.getTreeNode(index); if (treeNode != null) { List<Node<T>> childrenNodes = treeNode.getChildren(); for (Node<T> node : childrenNodes) { children.add(node.getElement()); } } } return children; } @Override public int getElementCount() { return this.treeList.size(); } /** * Collapse the tree node that represent the given object. * * @param object * The object that represents the tree node to collapse. * @deprecated expand/collapse operations should be performed on * {@link ITreeRowModel}! */ @Deprecated public void collapse(T object) { collapse(indexOf(object)); }; /** * Expand the tree node that represent the given object. * * @param object * The object that represents the tree node to expand. * @deprecated expand/collapse operations should be performed on * {@link ITreeRowModel}! */ @Deprecated public void expand(T object) { expand(indexOf(object)); }; /** * Collapse the tree node at the given visible index. * * @param index * The index of the tree node to collapse. * @deprecated expand/collapse operations should be performed on * {@link ITreeRowModel}! */ @Deprecated public void collapse(int index) { if (!isValidIndex(index)) { return; } this.treeList.setExpanded(index, false); }; /** * Expand the tree node at the given visible index. * * @param index * The index of the tree node to expand. * @deprecated expand/collapse operations should be performed on * {@link ITreeRowModel}! */ @Deprecated public void expand(int index) { if (!isValidIndex(index)) { return; } this.treeList.setExpanded(index, true); }; /** * Will check the whole TreeList for its nodes and collapses them if they * are expanded. After executing this method, all nodes in the TreeList will * be collapsed. * * @deprecated expand/collapse operations should be performed on * {@link ITreeRowModel}! */ @Deprecated public void collapseAll() { this.treeList.getReadWriteLock().writeLock().lock(); try { // iterating directly over the TreeList is a lot faster than // checking the nodes // which is related that on collapsing we only need to iterate once // from bottom to top for (int i = (this.treeList.size() - 1); i >= 0; i--) { /* * Checks if the node at the given visible index has children * and is collapsible. If it is it will be collapsed otherwise * skipped. This backwards searching and collapsing mechanism is * necessary to ensure to really get every collapsible node in * the whole tree structure. */ if (hasChildren(i) && isExpanded(i)) { this.treeList.setExpanded(i, false); } } } finally { this.treeList.getReadWriteLock().writeLock().unlock(); } } /** * Will check the whole TreeList for its nodes and expands them if they are * collapsed. After executing this method, all nodes in the TreeList will be * expanded. * * @deprecated expand/collapse operations should be performed on * {@link ITreeRowModel}! */ @Deprecated public void expandAll() { boolean expandPerformed = false; this.treeList.getReadWriteLock().writeLock().lock(); try { // iterating directly over the TreeList is a lot faster than // checking the nodes for (int i = (this.treeList.size() - 1); i >= 0; i--) { /* * Checks if the node at the given visible index has children * and is expandable. If it is it will be expanded otherwise * skipped. This backwards searching and expanding mechanism is * necessary to ensure to really get every expandable node in * the whole tree structure. */ if (hasChildren(i) && !isExpanded(i)) { this.treeList.setExpanded(i, true); expandPerformed = true; } } } finally { this.treeList.getReadWriteLock().writeLock().unlock(); } // if at least one element was expanded we need to perform the step // again as we are only able to retrieve the visible nodes if (expandPerformed) { expandAll(); } } /** * Checks if the given element is expanded or not. * <p> * Note: The check only works for visible elements, therefore a check for an * element that is below an collapsed element does not work. * * @param object * The element that should be checked. * @return <code>true</code> if the children of the given element are * visible, <code>false</code> if not * @deprecated expand/collapse operations should be performed on * {@link ITreeRowModel}! */ @Deprecated public boolean isExpanded(T object) { return isExpanded(indexOf(object)); } /** * Checks if the element at the given visual index is expanded or not. * * @param index * The visual index of the element to check. * @return <code>true</code> if the children of the element at given index * are visible, <code>false</code> if not * @deprecated expand/collapse operations should be performed on * {@link ITreeRowModel}! */ @Deprecated public boolean isExpanded(int index) { if (!isValidIndex(index)) { return false; } return this.treeList.isExpanded(index); } @Override public boolean isValidIndex(int index) { return (!(index < 0) && index < this.treeList.size()); } /** * @return The underlying {@link TreeList} this {@link GlazedListTreeData} * is operating on. */ public TreeList<T> getTreeList() { return this.treeList; } }