package org.mindswap.swoop.utils.graph.hierarchy; import java.awt.Color; import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; import java.net.URI; import java.util.Collections; import java.util.Comparator; import java.util.Vector; import org.mindswap.swoop.SwoopModel; import org.mindswap.swoop.utils.graph.hierarchy.colors.GraphColorScheme; import org.semanticweb.owl.model.OWLClass; import org.semanticweb.owl.model.OWLException; /* * Created on Jul 15, 2005 * * TODO To change the template for this generated file go to * Window - Preferences - Java - Code Style - Code Templates */ /** * @author Dave Wang * * TODO To change the template for this generated type comment go to * Window - Preferences - Java - Code Style - Code Templates */ public class ClassTreeNode { class DescendingClassTreeNodeComparator implements Comparator { public int compare(Object o1, Object o2) { ClassTreeNode t1 = (ClassTreeNode)o1; ClassTreeNode t2 = (ClassTreeNode)o2; int t1_size = t1.getSubTreeSize(); int t2_size = t2.getSubTreeSize(); if ( t1_size > t2_size) return -1; else if (t1_size == t2_size) return 0; else return 1; } public boolean equals(Object o2) { return false; } } public static final int UNASSIGNED_SIZE = -1423; private URI myURI; private ClassTreeNode myParent = null; private Vector myChildren = new Vector(); private int mySubTreeSize = UNASSIGNED_SIZE; private TreeNodeSizeInfo myChildNodeSizeInfo = null; private double localX = -1; private double localY = -1; private double globalX = -1; private double globalY = -1; private double myRotationAngle = 0; private boolean isSelected = false; // whether selected by user via mouse private boolean isHighlighted = false; // whether highlighted via search private boolean isListBrowsed = false; // whether viewed by user via list private boolean isOverlayed = false; // whether this class node is overlayed private boolean hasRelations = false; // whether related to other classes via some restrictions private SwoopModel myModel = null; private OntologyGraphNode myOntologyGraphNode = null; // init in sortChildren(....) private GraphColorScheme myColorScheme = null; // init in sortChildren(....) private AffineTransform myLocalXForm; private AffineTransform myGlobalXform; private int myDepth = 0; private int mySubtreeDepth = 0; public ClassTreeNode(SwoopModel model, URI uri, int depth ) { myURI = uri; myModel = model; myDepth = depth; // myOntologyNode, myColorSchem are set by // call to sortChildren by OntologyGraphNode constructor } public int getNumChildren() { return myChildren.size(); } public int getDepth() { return myDepth; } public int getSubtreeDepth() { return mySubtreeDepth; } public void setSubtreeDepth( int subtreeDepth ) { mySubtreeDepth = subtreeDepth; } public OWLClass getOWLClass() { try { return myOntologyGraphNode.getOntology().getClass( myURI); } catch( OWLException e) { e.printStackTrace(); } return null; } public ClassTreeNode getChild(int index) { if ( (index < 0) || (index > (myChildren.size() -1) ) ) return null; return (ClassTreeNode)myChildren.elementAt( index ); } public ClassTreeNode addChild( ClassTreeNode node ) { node.setParent( this ); myChildren.add( node ); return node; } public void setParent( ClassTreeNode parent ) { myParent = parent; } public void removeChild( ClassTreeNode node) { myChildren.remove( node ); } public ClassTreeNode findNode( String id ) { for (int i = 0; i < myChildren.size(); i++) { ClassTreeNode node = (ClassTreeNode)myChildren.elementAt(i); if (node.getURI().toString().equals(id)) return node; } return null; } // returns size of subtree rooted at THIS node. Includes itself public int getSubTreeSize() { // if already assigned, return that value if (mySubTreeSize != UNASSIGNED_SIZE) return mySubTreeSize; // leaf case if ( myChildren.size() == 0 ) { mySubTreeSize = 1; return mySubTreeSize; } int size = 0; for (int i = 0; i < myChildren.size(); i ++) { ClassTreeNode node = (ClassTreeNode)myChildren.elementAt( i ); size = size + node.getSubTreeSize(); } mySubTreeSize = size + 1; return mySubTreeSize; } public TreeNodeSizeInfo getChildNodeSizeInfo() { if (myChildNodeSizeInfo != null ) return myChildNodeSizeInfo; int numChildren = this.getNumChildren(); if (numChildren == 0) { myChildNodeSizeInfo = TreeNodeSizeInfo.getNullInfo(); return myChildNodeSizeInfo; } int maxChildRadius = Integer.MIN_VALUE; ClassTreeNode largestNode = null; boolean isFirstTime = true; boolean areSameSize = true; boolean isFirstChildLarge = false; for (int i = 0; i < numChildren; i++ ) { ClassTreeNode child = this.getChild( i ); if ( i == 0 ) //largest node { if ( (2 * child.getRadius()) > (this.getRadius() * 0.75) ) isFirstChildLarge = true; } int childsize = child.getRadius(); if ((!isFirstTime) && ( maxChildRadius != childsize)) areSameSize = false; if ( maxChildRadius < childsize) { maxChildRadius = childsize; largestNode = child; } if ( isFirstTime ) isFirstTime = !isFirstTime; } TreeNodeSizeInfo info = new TreeNodeSizeInfo(); info.areSameSize = areSameSize; info.maxRadius = maxChildRadius; info.myLargestNode = largestNode; info.isFirstChildBig = isFirstChildLarge; myChildNodeSizeInfo = info; return myChildNodeSizeInfo; } public int getRadius() { return getSubTreeSize() * SizeConstants.unitSize; } public URI getURI() { return myURI; } public ClassTreeNode getParent() { return myParent; } public Vector getChildren() { return myChildren; } // guarantees for the current Colorscheme public GraphColorScheme getColorScheme() { return myOntologyGraphNode.getColorScheme(); } public Color getFillColor() { return myOntologyGraphNode.getColorScheme().getTreeNodeFillColor( this ); } public Color getOutlineColor() { return myOntologyGraphNode.getColorScheme().getTreeNodeOutlineColor( this ); } // sets the center for this treenode. It is local coordinate (from its parent's center) public void setLocalCenterPoint( double newx, double newy) { ClassTreeNode parentNode = this.getParent(); // this node is root, so set global = center = (newx, newy) if ( parentNode == null ) { this.localX = newx; this.localY = newy; return; } localX = newx; localY = newy; } public Point2D.Double getLocalCenter() { return new Point2D.Double(this.localX, this.localY); } public Point2D.Double computeGlobalCenter() { Point2D point = new Point2D.Double(0,0); Point2D.Double destPoint = new Point2D.Double(); destPoint = (Point2D.Double)myGlobalXform.transform( point, destPoint ); return destPoint; } public Point2D.Double getGlobalCenter() { return new Point2D.Double( globalX, globalY); } public double getLocalX() { return this.localX; } public double getLocalY() { return this.localY; } public double getGlobalX() { return this.globalX; } public double getGlobalY() { return this.globalY; } // in radians public double getRotationAngle() { return myRotationAngle; } public void setRotationAngle( double angle) { myRotationAngle = angle; } public void setLocalXForm( AffineTransform form ) { myLocalXForm = form; } public AffineTransform getLocalXForm() { return myLocalXForm; } // set global transform (which transforms (0,0) to this node's center) // and also set the global center public void setGlobalTransform( AffineTransform form ) { myGlobalXform = form; Point2D gPoint = computeGlobalCenter(); globalX = gPoint.getX(); globalY = gPoint.getY(); } // recursively sorts current tree node's child by (subtree)size ( largest first ) // invoked by constructor of OntologyGraphNode. myOntologyGraphNode is guaranteed // to set. myColorScheme is guaranteed to set. public void sortChildren( OntologyGraphNode motherNode) { motherNode.indexNode( this.getURI(), this ); Collections.sort( myChildren, new DescendingClassTreeNodeComparator()); myOntologyGraphNode = motherNode; myColorScheme = myOntologyGraphNode.getColorScheme(); for (int i = 0; i < getNumChildren(); i++) { ClassTreeNode child = getChild(i); child.sortChildren( motherNode ); } } public OntologyGraphNode getOntologyNode() { return myOntologyGraphNode; } public boolean getIsSelected() { return isSelected; } public void setIsSelected( boolean flag ) { isSelected = flag; } public boolean getIsHighlighted() { return isHighlighted; } public void setIsHighlighted( boolean flag ) { isHighlighted = flag; } public boolean getIsListBrowsed() { return isListBrowsed; } public void setIsListBrowsed( boolean flag ) { isListBrowsed = flag; } public boolean gethasRelations() { return hasRelations; } public void sethasRelations( boolean flag) { hasRelations = flag; } public boolean getIsOverlayed() { return isOverlayed; } public void setIsOverlayed( boolean flag) { isOverlayed = flag; } /* * * Returns the node that's selected by the point passed in. * If this node is selected, then it recursively finds if any child is selected (more * precisely selected node). * If true, then that child is returned * else this node is returned * * Invoked by GraphMouseImpl in TestVisualizationViewer */ public ClassTreeNode getSelectedChild( Point2D p) { ClassTreeNode selectedNode = null; Point2D.Double myCenter = this.getLocalCenter(); // find xform that translate p to local space AffineTransform xform = AffineTransform.getTranslateInstance( -myCenter.x, -myCenter.y ); Point2D localPoint = null; localPoint = xform.transform( p, localPoint ); for (int i = 0; i < getNumChildren(); i++) { ClassTreeNode child = getChild( i ); ClassTreeNode selectedChild = child.getSelectedNode( localPoint ); if (selectedChild != null) selectedNode = selectedChild; } return selectedNode; } // // localPoint is in the same local space as this node // however, it has not been rotated correctly, since this node's parent may have rotated // public ClassTreeNode getSelectedNode( Point2D localPoint ) { ClassTreeNode selectedNode = null; if ( isWithinMe( localPoint ) ) { selectedNode = this; // set return value to self. Point2D result= null; AffineTransform xform = null; try { xform = myLocalXForm.createInverse(); } catch( Exception e) { e.printStackTrace(); } Point2D newLocal = null; newLocal = xform.transform( localPoint, newLocal ); for (int i = 0; i < getNumChildren(); i++) { ClassTreeNode child = getChild( i ); ClassTreeNode selectedChild = child.getSelectedNode( newLocal ); if (selectedChild != null) selectedNode = selectedChild; } } return selectedNode; } // // point p is in local space, same space as this node's parent // private boolean isWithinMe( Point2D p ) { if (Math.sqrt( (Math.pow(p.getX() - this.localX , 2) ) + Math.pow(p.getY() - this.localY , 2) ) <= this.getRadius()) return true; return false; } public String toString() { return myModel.shortForm( this.getURI() ); } // differs from toString() in that this method only returns // the name of the class (no qnames when qname toggle is on in swoop) public String getName() { String name = myModel.shortForm( this.getURI() ); int index = name.indexOf(":"); if (index == -1) return name; else return name.substring( index ); } }