package bibliothek.help.view; import java.awt.BorderLayout; import java.awt.Component; import java.util.List; import javax.swing.JScrollPane; import javax.swing.JTree; import javax.swing.tree.*; import bibliothek.gui.Dockable; import bibliothek.gui.dock.DefaultDockable; import bibliothek.help.control.LinkManager; import bibliothek.help.control.Linking; import bibliothek.help.control.Undoable; import bibliothek.help.model.Entry; import bibliothek.help.model.HierarchyNode; import bibliothek.help.util.ResourceSet; /** * A {@link Dockable} that shows the type-hierarchy of a class or interface. The * hierarchy is encoded in an {@link Entry} and the method {@link Entry#toSubHierarchy()} * is used to decode it.<br> * This class implements {@link Linking} and can update its content automatically * using a {@link LinkManager}. * @author Benjamin Sigg * */ public class TypeHierarchyView extends DefaultDockable implements Linking, Undoable{ /** the visual representation of the hierarchy-tree */ private JTree tree; /** the tree */ private Entry entry; /** * Creates a new view. * @param manager A manager to which this view will add a listener. This * view will update its content whenever that listener is called. */ public TypeHierarchyView( LinkManager manager ){ setTitleText( "Hierarchy" ); setTitleIcon( ResourceSet.ICONS.get( "hierarchy" ) ); manager.add( this ); manager.getUR().register( this ); tree = new JTree(){ @Override public void updateUI(){ super.updateUI(); setCellRenderer( new Renderer() ); } }; setLayout( new BorderLayout() ); add( new JScrollPane( tree ), BorderLayout.CENTER ); tree.setModel( new DefaultTreeModel( new DefaultMutableTreeNode()) ); } public Entry getCurrent(){ return entry; } public void setCurrent( Entry entry ){ if( this.entry != entry ){ this.entry = entry; HierarchyNode node = entry.toSubHierarchy(); if( node == null ){ tree.setModel( new DefaultTreeModel( new DefaultMutableTreeNode( "< empty >" )) ); } else{ MutableTreeNode model = toModel( node ); tree.setModel( new DefaultTreeModel( model ) ); expandAll( model, new TreePath( model ) ); } } } public void selected( List<Entry> list ) { for( Entry entry : list ){ if( entry.getType().equals( "hierarchy-class" ) || entry.getType().equals( "empty" )){ setCurrent( entry ); break; } } } /** * Wraps <code>node</code> into a {@link TreeNode} such that it can * be shown in a {@link JTree}. * @param node a node in a tree * @return a wrapper around <code>node</code> and all its children */ private MutableTreeNode toModel( HierarchyNode node ){ DefaultMutableTreeNode model = new DefaultMutableTreeNode( node ); for( int i = 0, n = node.getChildrenCount(); i<n; i++ ) model.add( toModel( node.getChild( i )) ); return model; } /** * Ensures that <code>node</code> and all children of <code>node</code> * are expanded. * @param node a node * @param path the path to <code>node</code> */ private void expandAll( TreeNode node, TreePath path ){ tree.expandPath( path ); for( int i = 0, n = node.getChildCount(); i<n; i++ ){ TreeNode child = node.getChildAt( i ); TreePath next = path.pathByAddingChild( child ); expandAll( child, next ); } } /** * A {@link TreeCellRenderer} that shows an icon for nodes which * represent classes or interfaces. * @author Benjamin Sigg * */ private class Renderer extends DefaultTreeCellRenderer{ @Override public Component getTreeCellRendererComponent( JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus ) { Object user = ((DefaultMutableTreeNode)value).getUserObject(); if( user instanceof HierarchyNode ){ HierarchyNode node = (HierarchyNode)user; super.getTreeCellRendererComponent( tree, node.getName(), sel, expanded, leaf, row, hasFocus ); if( node.getType().equals( "c" )) setIcon( ResourceSet.ICONS.get( "class" ) ); else if( node.getType().equals( "i" )) setIcon( ResourceSet.ICONS.get( "interface" ) ); else setIcon( null ); } else super.getTreeCellRendererComponent( tree, value, sel, expanded, leaf, row, hasFocus ); return this; } } }