@Override public void mouseClicked(MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() % 2 == 0) { int row = jTable.rowAtPoint(e.getPoint()); int depth = treeList.depth(row); final int min = INDENT + (depth * WIDTH); final int max = min + WIDTH; if (e.getPoint().x < min || e.getPoint().x > max) { treeList.setExpanded(row, !treeList.isExpanded(row)); } } }
public DefaultExternalExpansionModel() { this(TreeList.<E>nodesStartExpanded()); }
private Node<E> deleteVirtualAncestryRootDown(Node<E> previous, Node<E> parent) { Node<E> replacementLastSibling = previous.ancestorWithPathLength(parent.pathLength() + 1); assert(replacementLastSibling.siblingAfter == null); Node<E> replacement = replacementLastSibling.parent; // merge expand/collapse state first if(replacement.expanded && !parent.expanded) { setExpanded(parent, true); } else if(parent.expanded && !replacement.expanded) { setExpanded(replacement, true); } // link the children of the two parents as siblings Node<E> parentFirstChild = parent.firstChild(); assert(parentFirstChild == null || parentFirstChild.siblingBefore == null); replacementLastSibling.siblingAfter = parentFirstChild; if(parentFirstChild != null) parentFirstChild.siblingBefore = replacementLastSibling; // point all children at the new parent for(Node<E> child = parentFirstChild; child != null; child = child.siblingAfter) { child.parent = replacement; } // remove the parent itself deleteNode(parent); // next up for potential deletion is the child of this parent return parentFirstChild; }
/** * A convenience method to expand the row if it is currently collapsed or * vice versa. */ public void toggleExpanded(int visibleIndex) { setExpanded(visibleIndex, !isExpanded(visibleIndex)); }
/** * Return a decorated form of the component returned by the data * {@link TableCellRenderer}. */ @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { treeList.getReadWriteLock().readLock().lock(); try { // read information about the tree node from the TreeList treeNodeData.setDepth(treeList.depth(row)); treeNodeData.setExpanded(treeList.isExpanded(row)); treeNodeData.setHasChildren(treeList.hasChildren(row)); treeNodeData.setAllowsChildren(treeList.getAllowsChildren(row)); } finally { treeList.getReadWriteLock().readLock().unlock(); } // if the delegate renderer accepts TreeNodeData, give it if (delegate instanceof TreeTableNodeDataRenderer) ((TreeTableNodeDataRenderer) delegate).setTreeNodeData(treeNodeData); // ask the delegate renderer to produce the data component final Component c = delegate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); // fetch the number of pixels to indent final int indent = getIndent(treeNodeData, showExpanderForEmptyParent); // fetch the number of pixels to space over final int spacer = getSpacer(treeNodeData, showExpanderForEmptyParent); // ask our special component to configure itself for this tree node component.configure(treeNodeData, showExpanderForEmptyParent, c, hasFocus, indent, spacer); return component; }
replaceAndDetachNode( sourceIndex, nodesToVerify ); Node<E> updated = finderInserter.findOrInsertNode(sourceIndex); nodeAttacher.nodesToAttach.queueNewNodeForInserting(updated); deleteAndDetachNode(sourceIndex, nodesToVerify); deleteObsoleteVirtualLeaves(nodesToVerify); deleteObsoleteVirtualParents(nodesToVerify); assert(isValid());
return; treeList.getReadWriteLock().writeLock().lock(); try { if (treeList.getAllowsChildren(row)) { final boolean expanded = treeList.isExpanded(row); if ((expanded && isLeftArrowKey) || (!expanded && isRightArrowKey)) TreeTableUtilities.toggleExpansion(table, treeList, row).run(); treeList.getReadWriteLock().writeLock().unlock();
/** * Control whether the child elements of the specified node are visible. * * @param expanded <code>true</code> to expand the node, <code>false</code> * to collapse it. */ public void setExpanded(int visibleIndex, boolean expanded) { Node<E> toExpand = data.get(visibleIndex, VISIBLE_NODES).get(); expansionModel.setExpanded(toExpand.getElement(), toExpand.path, expanded); setExpanded(toExpand, expanded); assert(isValid()); }
/** master Constructor */ private TreeList(InitializationData<E> initializationData) { super(initializationData.getSource()); this.format = initializationData.format; this.nodeComparator = initializationData.nodeComparator; this.expansionModel = initializationData.expansionModel; this.initializationData = initializationData; // insert the new elements like they were adds NodeAttacher nodeAttacher = new NodeAttacher(false); for(int i = 0; i < super.source.size(); i++) { Node<E> node = super.source.get(i); node.expanded = expansionModel.isExpanded(node.getElement(), node.path); addNode(node, HIDDEN_REAL, i); nodeAttacher.nodesToAttach.queueNewNodeForInserting(node); } // attach siblings and parent nodes nodeAttacher.attachAll(); assert(isValid()); source.addListEventListener(this); }
/** * Remove the node at the specified index, firing all the required * notifications. */ private void deleteAndDetachNode(int sourceIndex, List<Node<E>> nodesToVerify) { Node<E> node = data.get(sourceIndex, REAL_NODES).get(); // if it has children, replace it with a virtual copy and schedule that for verification if(!node.isLeaf()) { Node<E> replacement = new Node<E>(node.virtual, new ArrayList<E>(node.path())); replaceNode(node, replacement, true); nodesToVerify.add(replacement); // otherwise delete it directly } else { Node<E> follower = node.next(); deleteNode(node); // remove the parent if necessary in the next iteration nodesToVerify.add(node.parent); // also remove the follower - it may have become redundant as well if(follower != null && follower.virtual) nodesToVerify.add(follower); } }
TreeList<CheckBoxNode> treeList = new TreeList<>(EventModels.createSwingThreadProxyList(filterList), new CheckBoxNodeFormat(), TreeList.nodesStartExpanded()); eventList.getReadWriteLock().readLock().unlock();
/** * Delete all virtual parents that no longer have child nodes attached. * This method does not depend upon child nodes being properly configured. */ private void deleteObsoleteVirtualLeaves(List<Node<E>> nodesToVerify) { deleteObsoleteLeaves: for(Iterator<Node<E>> i = nodesToVerify.iterator(); i.hasNext(); ) { Node<E> node = i.next(); // walk up the tree, deleting nodes while(node != null) { // we've reached a real parent, don't delete it! if(!node.virtual) continue deleteObsoleteLeaves; // we've already deleted this parent, we're done if(node.element == null) continue deleteObsoleteLeaves; // this node now has children, don't delete it if(!node.isLeaf()) continue deleteObsoleteLeaves; // if this virtual node has no children, then it's obsolete and // we can delete it right away. Afterwards, we might need to // delete that node's parent deleteNode(node); node = node.parent; } } }
this.treeList.addListEventListener(SWING_THREAD_CHECKER);
/** * Return a decorated form of the component returned by the data * {@link TableCellRenderer}. */ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { treeList.getReadWriteLock().readLock().lock(); try { // read information about the tree node from the TreeList treeNodeData.setDepth(treeList.depth(row)); treeNodeData.setExpanded(treeList.isExpanded(row)); treeNodeData.setHasChildren(treeList.hasChildren(row)); treeNodeData.setAllowsChildren(treeList.getAllowsChildren(row)); } finally { treeList.getReadWriteLock().readLock().unlock(); } // if the delegate renderer accepts TreeNodeData, give it if (delegate instanceof TreeTableNodeDataRenderer) ((TreeTableNodeDataRenderer) delegate).setTreeNodeData(treeNodeData); // ask the delegate renderer to produce the data component final Component c = delegate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); // fetch the number of pixels to indent final int indent = getIndent(treeNodeData, showExpanderForEmptyParent); // fetch the number of pixels to space over final int spacer = getSpacer(treeNodeData, showExpanderForEmptyParent); // ask our special component to configure itself for this tree node component.configure(treeNodeData, showExpanderForEmptyParent, c, hasFocus, indent, spacer); return component; }
deleteAndDetachNode(sourceIndex, nodesToVerify); Node<E> updated = finderInserter.findOrInsertNode(sourceIndex); nodeAttacher.nodesToAttach.queueNewNodeForInserting(updated); deleteAndDetachNode(sourceIndex, nodesToVerify); deleteObsoleteVirtualLeaves(nodesToVerify); deleteObsoleteVirtualParents(nodesToVerify); assert(isValid());
return; treeList.getReadWriteLock().writeLock().lock(); try { if (treeList.getAllowsChildren(row)) { final boolean expanded = treeList.isExpanded(row); if ((expanded && isLeftArrowKey) || (!expanded && isRightArrowKey)) TreeTableUtilities.toggleExpansion(table, treeList, row).run(); treeList.getReadWriteLock().writeLock().unlock();
/** * A convenience method to expand the row if it is currently collapsed or * vice versa. */ public void toggleExpanded(int visibleIndex) { setExpanded(visibleIndex, !isExpanded(visibleIndex)); }
/** * Control whether the child elements of the specified node are visible. * * @param expanded <code>true</code> to expand the node, <code>false</code> * to collapse it. */ public void setExpanded(int visibleIndex, boolean expanded) { Node<E> toExpand = data.get(visibleIndex, VISIBLE_NODES).get(); expansionModel.setExpanded(toExpand.getElement(), toExpand.path, expanded); setExpanded(toExpand, expanded); assert(isValid()); }
/** master Constructor */ private TreeList(InitializationData<E> initializationData) { super(initializationData.getSource()); this.format = initializationData.format; this.nodeComparator = initializationData.nodeComparator; this.expansionModel = initializationData.expansionModel; this.initializationData = initializationData; // insert the new elements like they were adds NodeAttacher nodeAttacher = new NodeAttacher(false); for(int i = 0; i < super.source.size(); i++) { Node<E> node = super.source.get(i); node.expanded = expansionModel.isExpanded(node.getElement(), node.path); addNode(node, HIDDEN_REAL, i); nodeAttacher.nodesToAttach.queueNewNodeForInserting(node); } // attach siblings and parent nodes nodeAttacher.attachAll(); assert(isValid()); source.addListEventListener(this); }
/** * Remove the node at the specified index, firing all the required * notifications. */ private void deleteAndDetachNode(int sourceIndex, List<Node<E>> nodesToVerify) { Node<E> node = data.get(sourceIndex, REAL_NODES).get(); // if it has children, replace it with a virtual copy and schedule that for verification if(!node.isLeaf()) { Node<E> replacement = new Node<E>(node.virtual, new ArrayList<E>(node.path())); replaceNode(node, replacement, true); nodesToVerify.add(replacement); // otherwise delete it directly } else { Node<E> follower = node.next(); deleteNode(node); // remove the parent if necessary in the next iteration nodesToVerify.add(node.parent); // also remove the follower - it may have become redundant as well if(follower != null && follower.virtual) nodesToVerify.add(follower); } }