Package jsynoptic.plugins.java3d.tree

Source Code of jsynoptic.plugins.java3d.tree.AbstractNode

/* ========================
* JSynoptic : a free Synoptic editor
* ========================
*
* Project Info:  http://jsynoptic.sourceforge.net/index.html
*
* This program 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 program 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
* program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* (C) Copyright 2001-2007, by :
*     Corporate:
*         EADS Astrium
*     Individual:
*         Claude Cazenave
*
* $Id: AbstractNode.java,v 1.8 2008/12/17 22:37:53 cazenave Exp $
*
* Changes
* -------
* 4 janv. 08  : Initial public release
*
*/
package jsynoptic.plugins.java3d.tree;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.MissingResourceException;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;

/**
* A tree node to hold a SceneGraph object
* and provide dedicated feature
*/
public abstract class AbstractNode extends DefaultMutableTreeNode {
    /**
     * Node resources : icons
     */
    final static HashMap<String,Icon> _icons=new HashMap<String,Icon>();
   
    /**
     * Node resources : descriptions
     */
    final static HashMap<String,String> _descriptions=new HashMap<String, String>();
   
    /**
     * Node class according to SceneGraphObject class
     */
    final static HashMap<String,Class<? extends AbstractNode>> _nodeClasses=new HashMap<String, Class<? extends AbstractNode>>();
   
    /**
     * Add a node class name to be used to display a scene graph object in the tree
     * @param className scene graph object class name
     * @param nodeClass the class of the node to use
     */
    public static void addNodeClass(String className, Class<? extends AbstractNode> nodeClass){
        _nodeClasses.put(className, nodeClass);
    }

    /**
     * Add resources to display in the tree a scene graph object
     * The loaded resources are the icon and the description
     * @param className scene graph object class name
     * @param id the key to look for the resources
     */
    public static void addResources(String className, String id){
        // icons are fixed wrt i18n
        // Tree.resources provides file URL only
        try{
            URL url=Tree.resources.getClass().getResource(id+".png");
            if(url!=null){
                ImageIcon ic=new ImageIcon(url);
                _icons.put(className, ic);
            }
        }
        catch(MissingResourceException e){
        }
        _descriptions.put(className, Tree.resources.getStringValue(id));
    }
   
    /**
     * Add resources to display in the tree a scene graph object
     * @param className scene graph object class name
     * @param icon the icon to display
     * @param description the description to display
     */
    public static void addResource(String className, Icon icon, String description){
        _icons.put(className, icon);
        _descriptions.put(className, description);
    }

    /**
     * Get a node description according to the class name
     */
    public static String getDescription(Object graphObject){
        if(graphObject==null) return null; // root node
        String res=_descriptions.get(graphObject.getClass().getName());
        if(res==null){
            // look for sub types
            Class<?> c=graphObject.getClass().getSuperclass();
            while(c!=Object.class){
                res=_descriptions.get(c.getName());
                if(res!=null){
                    // keep for next call
                    _descriptions.put(graphObject.getClass().getName(), res);
                    break;
                }
                c=c.getSuperclass();
            }
        }
        return res;
    }

    /**
     * Get a node icon according to the graph object class name
     */
    public static Icon getIcon(Object graphObject){
        if(graphObject==null) return null; // root node
        Icon res=_icons.get(graphObject.getClass().getName());
        if(res==null){
            // look for sub types
            Class<?> c=graphObject.getClass().getSuperclass();
            while(c!=Object.class){
                res=_icons.get(c.getName());
                if(res!=null){
                    // keep for next call
                    _icons.put(graphObject.getClass().getName(), res);
                    break;
                }
                c=c.getSuperclass();
            }
        }
        return res;
    }

    /**
     * The tree owner of this node
     */
    private final Tree _tree;
   
    /**
     * The related scene graph object or null if root
     */
    private Object _graphObject;
   
    /**
     * This node icon
     */
    Icon _icon;
   
    /**
     * This node name
     */
    protected String _name;
   
    /**
     * Latest rendered name used to detect changes
     */
    String _lastName;
   
    /**
     * This node description
     */
    String _description;
   
    /**<b>(boolean)</b> _knownChildren: determines whether the children of the current object can be displayed or not*/
    private boolean _knownChildren = false;
   
    /**
     * @param graphObject
     * @param getChildren
     */
    protected AbstractNode(Tree tree, Object graphObject, boolean getChildren) {
        _tree=tree;
        _graphObject=graphObject;
        _lastName=null;
       
        // by default name is equal to class name
        String n=(graphObject==null) ? "" : graphObject.getClass().getName();
        int k=n.lastIndexOf('.');
        _name=n.substring(k+1);
       
        _icon=getIcon(_graphObject);
        _description=getDescription(_graphObject);
       
        if(getChildren){
            refresh();
        }
    }

    public String getName(){
        return _name;
    }
   
    /**
     * Get the list of children of this scene graph object
     * @param list the list to fill with the scene graph children
     */
    protected abstract void getSceneGraphChildren(ArrayList<Object> list);
   
    /**
     * According to a child scene graph object, returns the class
     * of the Node to hold it in the Tree
     * @param sceneGraphObject a child object of this Node scene graph object
     * @return the class to use to create the Node
     * @see createNode
     */
    protected Class<? extends AbstractNode> getChildrenNodeClass(Object sceneGraphObject){
        return getChildrenNodeClass(sceneGraphObject.getClass());
    }
   
    /**
     * According to a child scene graph object class, returns the class
     * of the Node to hold it in the Tree
     * @param sceneGraphObjectClass a child object class of this Node scene graph object
     * @return the class to use to create the Node
     * @see createNode
     */
    @SuppressWarnings("unchecked")
    protected Class<? extends AbstractNode> getChildrenNodeClass(Class<?> sceneGraphObjectClass){
        String className=sceneGraphObjectClass.getName();
        Class<? extends AbstractNode> res=_nodeClasses.get(className);
        if(res==null){
            // look for a class with Node in this package
            int k=className.lastIndexOf('.');
            className="jsynoptic.plugins.java3d.tree."+className.substring(k+1)+"Node";
            Class<?> cf=null;
            try {
                cf=Class.forName(className);
            } catch (ClassNotFoundException e) {
            }
            if(cf!=null && AbstractNode.class.isAssignableFrom(cf)){
                res=(Class<? extends AbstractNode>) cf;
                _nodeClasses.put(sceneGraphObjectClass.getName(), res); // for next use
            }
        }
        if(res==null){
            // look for sub types
            Class<?> c=sceneGraphObjectClass.getSuperclass();
            if(c!=Object.class){
                res=getChildrenNodeClass(c);
            }
        }
        if(res==null){
            res=SceneGraphTreeNode.class;
            _nodeClasses.put(sceneGraphObjectClass.getName(), res); // for next use
        }
        return res;
    }

    public synchronized void refresh(){
        _knownChildren=true;
       
        // 1) get the list of children in the scene graph
        ArrayList<Object> sceneList=new ArrayList<Object>();
        getSceneGraphChildren(sceneList);
       
        // 2) get list of children in the tree
        HashMap<Object, AbstractNode> map=new HashMap<Object, AbstractNode>();
        ArrayList<Object> treeList=new ArrayList<Object>();
        int k=getChildCount();
        for(int i=0;i<k;i++){
            AbstractNode n=(AbstractNode)getChildAt(i);
            treeList.add(n._graphObject);
            map.put(n._graphObject, n);
        }
       
        // 3) check if some to be removed and do remove
        treeList.removeAll(sceneList);
        AbstractNode[] removedNodes=new AbstractNode[treeList.size()];
        int[] removedNodesIndex=new int[treeList.size()];
        int j=0;
        for(Object r : treeList){
            AbstractNode n=map.get(r);
            removedNodes[j]=n;
            removedNodesIndex[j]=getIndex(n);
            j++;
            remove(map.get(r));
        }
       
        // 4) check if some to be added and do add
        treeList=new ArrayList<Object>();
        k=getChildCount();
        for(int i=0;i<k;i++){
            AbstractNode n=(AbstractNode)getChildAt(i);
            treeList.add(n._graphObject);
        }
        sceneList.removeAll(treeList);
        int[] ci=new int[sceneList.size()];
        int i=0;
        for(Object r : sceneList){
            ci[i]=k+i;
            i++;
            add(createNode(r));
        }
       
        // 5) notify tree node changes
        // if some added and some removed node structure change
        // if only some removed or some added notify parent accordingly
        if(ci.length>0){
            if(removedNodes.length>0){
                _tree._treeModel.nodeStructureChanged(this);
            }
            else{
                if(getChildCount()==1){
                    // first node : expand it to force display
                    _tree.expandPath(new TreePath(this));
                }
                _tree._treeModel.nodesWereInserted(this, ci);
            }
        }
        else if(removedNodes.length>0){
            _tree._treeModel.nodesWereRemoved(this, removedNodesIndex, removedNodes);
        }
       
        // 6) get node changes i.e. name has changed
        if(_lastName!=null && _lastName.equals(getName())){
            _tree._treeModel.nodeChanged(this);
        }
    }
   
    protected AbstractNode createNode(Object graphObject){
        Class<?> c=getChildrenNodeClass(graphObject);
        if(c==null){
            throw new RuntimeException("Invalid child "+graphObject.getClass().getName() + " for Node "+getClass().getName());
        }
        AbstractNode res=null;
        Exception ex=null;
        try {
            Constructor<?> ctor=c.getConstructor(Tree.class, Object.class, boolean.class);
            Object o=ctor.newInstance(_tree, graphObject, false);
            if(o instanceof AbstractNode){
                res=(AbstractNode)o;
            }
        } catch (SecurityException e) {
            ex=e;
        } catch (NoSuchMethodException e) {
            ex=e;
        } catch (IllegalArgumentException e) {
            ex=e;
        } catch (InstantiationException e) {
            ex=e;
        } catch (IllegalAccessException e) {
            ex=e;
        } catch (InvocationTargetException e) {
            ex=e;
        }
        if(res==null){
            if(ex!=null){
                throw new RuntimeException("Invalid Node class "+c.getName(),ex);
            }else{
                throw new RuntimeException("Invalid Node class "+c.getName());
            }
        }
        return res;
    }
   
    public boolean getAllowsChildren() {
        if (!_knownChildren){
            refresh();
        }
        return super.getAllowsChildren();
    }
   
    public int getChildCount(){
        if (!_knownChildren){
            refresh();
        }
        return super.getChildCount();
    }

    /**
     * @return Returns the _tree.
     */
    public Tree getTree() {
        return _tree;
    }

    /**
     * @return Returns the _graphObject.
     */
    Object getGraphObject() {
        return _graphObject;
    }
   
}
TOP

Related Classes of jsynoptic.plugins.java3d.tree.AbstractNode

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.