/* * Bibliothek - DockingFrames * Library built on Java/Swing, allows the user to "drag and drop" * panels containing any Swing-Component the developer likes to add. * * Copyright (C) 2010 Benjamin Sigg * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Benjamin Sigg * benjamin_sigg@gmx.ch * CH - Switzerland */ package bibliothek.test; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.swing.event.TreeModelEvent; import javax.swing.event.TreeModelListener; import javax.swing.tree.TreeModel; import javax.swing.tree.TreePath; public class InspectionTree implements TreeModel { private List<TreeModelListener> listeners = new ArrayList<TreeModelListener>(); private InspectionGraph graph; private Node root; public InspectionTree( InspectionNode root, InspectionGraph graph ){ this.root = new Node( null, root ); this.graph = graph; } public void addTreeModelListener( TreeModelListener l ){ listeners.add( l ); } public void removeTreeModelListener( TreeModelListener l ){ listeners.remove( l ); } protected TreeModelListener[] listeners(){ return listeners.toArray( new TreeModelListener[ listeners.size() ] ); } protected void fireNodesChanged( TreeModelEvent event ){ for( TreeModelListener listener : listeners() ){ listener.treeNodesChanged( event ); } } protected void fireNodesRemoved( TreeModelEvent event ){ for( TreeModelListener listener : listeners() ){ listener.treeNodesRemoved( event ); } } protected void fireNodesInserted( TreeModelEvent event ){ for( TreeModelListener listener : listeners() ){ listener.treeNodesInserted( event ); } } public Object getChild( Object parent, int index ){ return ((Node)parent).getChild( index ); } public int getChildCount( Object parent ){ return ((Node)parent).getChildrenCount(); } public int getIndexOfChild( Object parent, Object child ){ return ((Node)parent).indexOf( (Node)child ); } public Object getRoot(){ return root; } public boolean isLeaf( Object node ){ return getChildCount( node ) == 0; } public void valueForPathChanged( TreePath path, Object newValue ){ // ignore } public void update( boolean cleanse ){ graph.updateAll(); if( cleanse ){ Set<InspectionNode> set = new HashSet<InspectionNode>(); root.collect( set ); graph.retainAll( set ); } } public String toString( Object node ){ Object value = ((Node)node).content.getInspect().getValue(); return graph.toString( value ); } private class Node implements InspectionNodeListener{ private Node parent; private Node[] children; private InspectionNode content; public Node( Node parent, InspectionNode content ){ this.parent = parent; this.content = content; content.addListener( this ); } @Override public String toString(){ return content.toString(); } public void collect( Set<InspectionNode> nodes ){ if( nodes.add( content )){ if( children != null ){ for( Node child : children ){ child.collect( nodes ); } } } } public void destroy(){ content.removeListener( this ); if( children != null ){ for( Node child : children ){ child.destroy(); } } } public TreePath getPath(){ Node current = this; int count = 0; while( current != null ){ count++; current = current.parent; } Object[] path = new Object[count]; current = this; int index = count-1; while( current != null ){ path[index--] = current; current = current.parent; } return new TreePath( path ); } public void updated(){ TreeModelEvent event = new TreeModelEvent( this, getPath() ); fireNodesChanged( event ); } public void updated( InspectionNode[] oldChildren, InspectionNode[] newChildren ){ if( children == null ){ updated(); } else{ updated(); if( oldChildren == null ){ oldChildren = new InspectionNode[]{}; } if( newChildren == null ){ newChildren = new InspectionNode[]{}; } handleRemoved( oldChildren, newChildren ); handleAdded( oldChildren, newChildren ); } } private void handleRemoved( InspectionNode[] oldChildren, InspectionNode[] newChildren ){ boolean[] removed = new boolean[oldChildren.length]; int offset = 0; int count = 0; for( int i = 0; i < oldChildren.length; i++ ){ int index = indexOf( newChildren, oldChildren[i], offset ); if( index == -1 ){ removed[i] = true; count++; } else{ removed[i] = false; offset = index+1; } } if( count > 0 ){ int[] indices = new int[count]; Object[] selection = new Object[count]; Node[] updated = new Node[ children.length - count ]; offset = 0; int index = 0; for( int i = 0; i < children.length; i++ ){ if( removed[ i ] ){ indices[ offset ] = i; selection[ offset ] = children[i]; children[i].destroy(); offset++; } else{ updated[index++] = children[i]; } } children = updated; TreeModelEvent event = new TreeModelEvent( InspectionTree.this, getPath(), indices, selection ); fireNodesRemoved( event ); } } private void handleAdded( InspectionNode[] oldChildren, InspectionNode[] newChildren ){ boolean[] added = new boolean[ newChildren.length ]; int count = 0; int offset = 0; for( int i = 0; i < newChildren.length; i++ ){ int index = indexOf( oldChildren, newChildren[i], offset ); if( index == -1 ){ added[i] = true; count++; } else{ added[i] = false; offset = index+1; } } if( count > 0 ){ int[] indices = new int[count]; Object[] selection = new Object[count]; Node[] updated = new Node[ children.length + count ]; offset = 0; int index = 0; for( int i = 0; i < newChildren.length; i++ ){ if( added[ i ] ){ indices[ offset ] = i; updated[i] = new Node( this, newChildren[i] ); selection[ offset ] = updated[i]; offset++; } else{ updated[i] = children[index++]; } } children = updated; TreeModelEvent event = new TreeModelEvent( InspectionTree.this, getPath(), indices, selection ); fireNodesInserted( event ); } } private int indexOf( InspectionNode[] nodes, InspectionNode search, int offset ){ for( int i = offset; i < nodes.length; i++ ){ if( nodes[i] == search ){ return i; } } return -1; } private void children(){ if( children == null ){ InspectionNode[] contentChildren = content.getChildren(); children = new Node[ contentChildren.length ]; for( int i = 0; i < children.length; i++ ){ children[i] = new Node( this ,contentChildren[i] ); } } } public int getChildrenCount(){ children(); return children.length; } public Node getChild( int index ){ children(); return children[index]; } public int indexOf( Node child ){ for( int i = 0; i < children.length; i++ ){ if( children[i] == child ){ return i; } } return -1; } } }