//Copyright (c)2005 Holobloc Inc.
//Contributed to the OOONEIDA FBench project under the Common Public License.
package fbench.tree;
import java.util.Enumeration;
import java.util.Vector;
import javax.swing.Icon;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreeNode;
import fbench.FBench;
import fbench.IconFactory;
import fbench.dom.ElementModel;
import org.apache.xerces.dom.events.MutationEventImpl;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.events.Event;
import org.w3c.dom.events.EventListener;
import org.w3c.dom.events.MutationEvent;
/**
* A TreeNode encapsulating an Element of the DOM tree of an IEC 61499 XML
* document that has been "scrubbed" of all but Element nodes.
*
* @author JHC
* @version 20051027/JHC - Redefined default icon.
* @version 20050801/JHC - Modified from DOMTreeElement.
* @version 20050419/JHC
*/
public class DOMTreeNode extends ElementModel implements TreeNode, EventListener {
private Vector<DOMTreeNode> children;
private DOMTreeNode parent = null;
public void setElement(Element el)
{
children = null;
if( getElement() != null )
((org.w3c.dom.events.EventTarget) getElement()).removeEventListener(MutationEventImpl.DOM_ATTR_MODIFIED, this, false);
super.setElement(el);
((org.w3c.dom.events.EventTarget) getElement()).addEventListener(MutationEventImpl.DOM_ATTR_MODIFIED, this, false);
// DONT NEED MutationEventImpl.DOM_CHARACTER_DATA_MODIFIED
}
/** Returns the count of displayable children. */
public int getChildCount() {
return getChildren().size();
}
/**
* Returns the string to be used to display the tree node. Default is the
* result of the ElementModel getName() method.
*/
public String getText() {
return getName();
}
/**
* Returns the icon to be used for display of this element. Default is the
* icon identified by the element's tag name in lower case, or <B>null </B>
* if no icon is to be used.
*/
public Icon getIcon() {
return IconFactory.getIcon(element.getTagName().toLowerCase());
}
/**
* Returns <b>true </b> if the given string is the name of an IEC 61499
* LibraryElement with an interface.
*/
public static boolean hasInterface(String nname) {
return nname.endsWith("Type");
}
public DOMTreeNode getChildAt(int childIndex) {
Object ans = getChildren().get(childIndex);
return (ans instanceof DOMTreeNode) ? (DOMTreeNode) ans : null;
}
public void setParent(DOMTreeNode p)
{
parent = p;
}
public TreeNode getParent() {
return parent;
}
public int getIndex(TreeNode node) {
return getChildren().indexOf(node);
}
/**
* Returns <TT> true </TT> if the receiver allows children. Default return
* value is <TT> false </TT> .
* Extending classes may choose to return true
*/
public boolean getAllowsChildren() {
return false;
}
public boolean isLeaf() {
if ( getChildren() == null ) return true;
return getChildren().isEmpty();
}
public Enumeration children() {
return getChildren().elements();
}
/**
* Returns a DOMTreeNode encapsulating the given DOM Element, or <TT>null
* </TT> if no such DOMTreeNode exists.
*/
public static DOMTreeNode forElement(Element el) {
// try FBench Static list
String classname = FBench.getTreeNode(el.getTagName());
if ( classname != null )
{
try {
Class geclass = Class.forName(classname);
Object obj = geclass.newInstance();
if (obj instanceof DOMTreeNode) {
DOMTreeNode em = (DOMTreeNode) obj;
em.setElement(el);
return em;
}
} catch (ClassNotFoundException CX){
//Somewhat expected
} catch (Exception ex) {
ex.printStackTrace();
}
}
else
{
String packageName = "fbench.tree.";
classname = packageName + el.getTagName();
try {
Class geclass = Class.forName(classname);
Object obj = geclass.newInstance();
if (obj instanceof DOMTreeNode) {
DOMTreeNode em = (DOMTreeNode) obj;
em.setElement(el);
// Add to FBench List
FBench.putTreeNode(el.getTagName(),classname);
return em;
}
} catch (ClassNotFoundException CX){
//Somewhat expected
} catch (Exception ex) {
ex.printStackTrace();
}
}
return null;
}
public void add(TreeNode newNode)
{
}
/**
* Returns a Vector of the receiver's children. Default is a Vector of
* TreeNodes encapsulating the Elements in the DOM element's list of
* children.
*/
public Vector<DOMTreeNode> getChildren() {
// FIXED: STORE this... then if MutationEvent THEN change
if ( children == null )
{
java.lang.System.out.println("[DOMTreeNode] " + getText() + " getChildren() " + this.hashCode());
children = new Vector<DOMTreeNode>();
if (!getAllowsChildren())
return children;
NodeList subNodes = getElement().getChildNodes();
//Node for containing list of VersionInfo
Vector<DOMTreeNode> versionList = new Vector<DOMTreeNode>();
DOMTreeNode versionListNode = null;
boolean isVersionInfoAdded = false;
for (int i = 0; i < subNodes.getLength(); i++) {
DOMTreeNode childNode = forElement((Element) subNodes.item(i));
if( childNode == null )
continue;
try{
if(childNode.getElement().getNodeName().equals("VersionInfo")){
if(!isVersionInfoAdded){
Element verInfoElem =
getElement().getOwnerDocument().createElement("VersionList");
versionListNode = forElement(verInfoElem);
versionListNode.setParent(this);
((VersionList) versionListNode).setVersionList(versionList);
children.add(versionListNode);
isVersionInfoAdded = true;
}
childNode.setParent(versionListNode);
versionList.add(childNode);
}
else if (childNode != null)
{
childNode.setParent(this);
children.addElement(childNode);
}
}
catch(NullPointerException e){
e.printStackTrace();
}
}
}
return children;
}
public void handleEvent(Event evt) {
// TODO Auto-generated method stub
try
{
// If the event is from THIS NODE.. and not a child...
MutationEvent mevt = (MutationEvent)evt;
if( ((Node)getElement()) == mevt.getRelatedNode() )
{
//java.lang.System.out.println("[DOMTreeNode] " + getText() + "got event... " + this.hashCode());
if( mevt.getAttrName().equals("Name") )
{
//java.lang.System.out.println("[DOMTreeNode] " + mevt.getPrevValue()+ "got Name Changed..." + mevt.getNewValue());
}
//setText
// ONLY listening to attr_modified
setElement(getElement());
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
/*
* Needed for tree refresh...
* Remove all children... (first removing their children)... etc
*/
public void removeAllChildren()
{
if (getChildren() == null)
return;
for (DOMTreeNode child : getChildren())
{
if( child.getAllowsChildren() )
{
// Remove child's children
child.removeAllChildren();
}
child.setParent(null);
}
this.children = null;
java.lang.System.out.println("[DTN] " + this.getName() + " no longer has children");
}
}