/**
* Copyright (c) 2003-2009, Xith3D Project Group all rights reserved.
*
* Portions based on the Java3D interface, Copyright by Sun Microsystems.
* Many thanks to the developers of Java3D and Sun Microsystems for their
* innovation and design.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the 'Xith3D Project Group' nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) A
* RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE
*/
package org.xith3d.utility.sgtree;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.util.Hashtable;
import java.util.Map;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeSelectionModel;
import org.xith3d.scenegraph.SceneGraph;
import org.xith3d.utility.sgtree.infoitems.SGTInfo_Object;
/**
* Xith3DTree
*
* Displays a Xith3D scenegraph in a Swing Tree control
*
* @author Daniel Selman (Java3D version)
* @author Hawkwind
* @author Amos Wenger (aka BlueSky)
* @author Marvin Froehlich (aka Qudus)
*/
public class SGTree extends JFrame implements TreeSelectionListener
{
private static final long serialVersionUID = -3374869095150421975L;
private JEditorPane m_TextPane = null;
private JSplitPane m_SplitPane = null;
private JTree m_Tree = null;
private static final String INFO_PACKAGE_NAME = org.xith3d.utility.sgtree.infoitems.SGTInfo_Object.class.getPackage().getName() + ".";
private Map< String, Object > m_ObjectInfoTable;
public SGTree()
{
super( "Xith3D Scenegraph Tree" );
m_ObjectInfoTable = new Hashtable< String, Object >( 64 );
buildObjectInfoTable();
}
private void buildObjectInfoTable()
{
m_ObjectInfoTable = new Hashtable< String, Object >( 64 );
addObjectInfoTableItem( org.xith3d.scenegraph.AmbientLight.class );
addObjectInfoTableItem( org.xith3d.scenegraph.Appearance.class );
//addObjectInfoTableItem(org.xith3d.scenegraph.Bounds.class);
addObjectInfoTableItem( org.xith3d.scenegraph.BoundingLeaf.class );
addObjectInfoTableItem( org.xith3d.scenegraph.BranchGroup.class );
addObjectInfoTableItem( org.xith3d.scenegraph.ColoringAttributes.class );
addObjectInfoTableItem( org.xith3d.scenegraph.Clip.class );
addObjectInfoTableItem( org.xith3d.scenegraph.DirectionalLight.class );
addObjectInfoTableItem( org.xith3d.scenegraph.Fog.class );
addObjectInfoTableItem( org.xith3d.scenegraph.Group.class );
addObjectInfoTableItem( org.xith3d.scenegraph.Leaf.class );
addObjectInfoTableItem( org.xith3d.scenegraph.Light.class );
addObjectInfoTableItem( org.xith3d.scenegraph.LineAttributes.class );
addObjectInfoTableItem( org.xith3d.scenegraph.Material.class );
addObjectInfoTableItem( org.xith3d.scenegraph.Morph.class );
addObjectInfoTableItem( org.xith3d.scenegraph.GroupNode.class );
addObjectInfoTableItem( org.xith3d.scenegraph.OrderedGroup.class );
addObjectInfoTableItem( org.xith3d.scenegraph.PointAttributes.class );
addObjectInfoTableItem( org.xith3d.scenegraph.PointLight.class );
addObjectInfoTableItem( org.xith3d.scenegraph.PolygonAttributes.class );
addObjectInfoTableItem( org.xith3d.scenegraph.RenderingAttributes.class );
addObjectInfoTableItem( org.xith3d.scenegraph.SceneGraphObject.class );
addObjectInfoTableItem( org.xith3d.scenegraph.Shape3D.class );
addObjectInfoTableItem( org.xith3d.scenegraph.Sound.class );
addObjectInfoTableItem( org.xith3d.scenegraph.SpotLight.class );
addObjectInfoTableItem( org.xith3d.scenegraph.Switch.class );
addObjectInfoTableItem( org.xith3d.scenegraph.TexCoordGeneration.class );
addObjectInfoTableItem( org.xith3d.scenegraph.Texture.class );
addObjectInfoTableItem( org.xith3d.scenegraph.TextureAttributes.class );
addObjectInfoTableItem( org.xith3d.scenegraph.Transform3D.class );
addObjectInfoTableItem( org.xith3d.scenegraph.TransformGroup.class );
addObjectInfoTableItem( org.xith3d.scenegraph.TransparencyAttributes.class );
}
private void addObjectInfoTableItem( Class< ? > sgClass )
{
final String className = sgClass.getName();
final String infoClassName = INFO_PACKAGE_NAME + "SGTInfo_" + sgClass.getSimpleName();
// System.out.println(className + "-->" + infoClassName);
Class< ? > classObject = getClass( infoClassName );
try
{
if ( classObject != null )
{
m_ObjectInfoTable.put( className, classObject.newInstance() );
return;
}
}
catch ( Exception e )
{
e.printStackTrace();
}
System.err.println( "Unable to create a new instance of info class for: " + className );
}
SGTInfo_Object getObjectInfo( String szClass )
{
// look it up, maybe we have a direct match...
// System.out.println( "Looking up: " + szClass );
SGTInfo_Object objReturn = (SGTInfo_Object)m_ObjectInfoTable.get( szClass );
// System.out.println( "Direct Match: " + szClass );
Class< ? > classObject = null;
try
{
classObject = Class.forName( szClass );
}
catch ( Exception e )
{
e.printStackTrace();
}
Class< ? > parentClass = null;
if ( classObject != null )
parentClass = classObject.getSuperclass();
while ( objReturn == null && parentClass != null )
{
// if we did not get a match we should walk
// up the inheritance tree and look for a match on a base classe
objReturn = (SGTInfo_Object)m_ObjectInfoTable.get( parentClass.getName() );
parentClass = parentClass.getSuperclass();
// System.out.println( "Parent Class: " + parentClass );
}
// System.out.println( "Returning: " + objReturn );
return objReturn;
}
private Class< ? > getClass( String infoClass )
{
Class< ? > classObject = null;
try
{
classObject = Class.forName( infoClass );
}
catch ( Exception e )
{
try
{
classObject = Class.forName( INFO_PACKAGE_NAME + "SGTInfo_Object" );
}
catch ( Exception e2 )
{
classObject = null;
}
}
return classObject;
}
public void recurseObject( Object obj, DefaultMutableTreeNode parent )
{
if ( obj != null )
{
SGTInfo_Object objInfo = getObjectInfo( obj.getClass().getName() );
if ( objInfo != null )
{
objInfo.addToTree( this, parent, obj );
}
}
else
{
System.err.println( "Warning: ignored null object in recurseObject." );
}
}
public void valueChanged( TreeSelectionEvent e )
{
DefaultMutableTreeNode node = (DefaultMutableTreeNode)m_Tree.getLastSelectedPathComponent();
if ( node == null )
return;
Object sceneGraphObject = node.getUserObject();
// get the _Info object for the node type
SGTInfo_Object objInfo = getObjectInfo( sceneGraphObject.getClass().getName() );
try
{
if ( objInfo != null )
{
String szText = objInfo.getInfo( sceneGraphObject );
// System.out.println( szText );
displayText( szText );
}
else
displayText( "No Info Handler for:" + sceneGraphObject );
}
catch ( Exception ex )
{
ex.printStackTrace();
displayText( ex.toString() );
}
}
private void displayText( String szText )
{
m_TextPane.setText( szText );
}
public void updateNodes( SceneGraph sceneGraph )
{
// Create the top level parent node.
DefaultMutableTreeNode top = new DefaultMutableTreeNode( "Scenegraph" );
final int n = sceneGraph.getNumberOfBranchGroups();
for ( int i = 0; i < n; i++ )
recurseObject( sceneGraph.getBranchGroup( i ), top );
// Create a tree that allows one selection at a time.
m_Tree = new JTree( top );
m_Tree.getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION );
// Listen for when the selection changes.
m_Tree.addTreeSelectionListener( this );
// Create the scroll pane and add the tree to it.
JScrollPane treeView = new JScrollPane( m_Tree );
Dimension minimumSize = new Dimension( 100, 50 );
treeView.setMinimumSize( minimumSize );
// Add the scroll panes to a split pane.
if ( m_SplitPane == null )
{
// Create the viewing pane.
m_TextPane = new JEditorPane();
m_TextPane.setEditable( false );
JScrollPane htmlView = new JScrollPane( m_TextPane );
m_SplitPane = new JSplitPane( JSplitPane.VERTICAL_SPLIT );
m_SplitPane.setTopComponent( treeView );
m_SplitPane.setBottomComponent( htmlView );
htmlView.setMinimumSize( minimumSize );
m_SplitPane.setDividerLocation( 100 );
m_SplitPane.setPreferredSize( new Dimension( 500, 300 ) );
// Add the split pane to this frame.
getContentPane().add( m_SplitPane, BorderLayout.CENTER );
pack();
setVisible( true );
}
else
{
m_SplitPane.setTopComponent( treeView );
}
}
}