//The MIT License
//
// Copyright (c) 2004 Mindswap Research Group, University of Maryland, College Park
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
package org.mindswap.swoop;
import java.awt.Component;
import java.awt.Font;
import java.io.File;
import java.net.URI;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreePath;
import org.mindswap.swoop.reasoner.SwoopReasoner;
import org.mindswap.swoop.utils.SwoopCache;
import org.mindswap.swoop.utils.owlapi.DefaultShortFormProvider;
import org.mindswap.swoop.utils.treeexport.TreeSerializer;
import org.mindswap.swoop.utils.ui.EntityComparator;
import org.mindswap.swoop.utils.ui.SwoopIcons;
import org.semanticweb.owl.io.ShortFormProvider;
import org.semanticweb.owl.io.vocabulary.OWLVocabularyAdapter;
import org.semanticweb.owl.model.OWLClass;
import org.semanticweb.owl.model.OWLDescription;
import org.semanticweb.owl.model.OWLEntity;
import org.semanticweb.owl.model.OWLException;
import org.semanticweb.owl.model.OWLOntology;
import org.semanticweb.owl.model.OWLProperty;
import org.semanticweb.owl.model.helper.OntologyHelper;
/**
* @author Evren Sirin
*/
public class TreeRenderer {
private static OWLVocabularyAdapter OWL = OWLVocabularyAdapter.INSTANCE;
private SwoopModel swoopModel;
private SwoopFrame swoopHandler;
private ShortFormProvider shortFormProvider = new DefaultShortFormProvider();
private OWLClass owlThing;
private OWLClass owlNothing;
public boolean useOldClassTreeReferenceforExpansion = false;
public boolean useOldPropertyTreeReferenceforExpansion = false;
TreeCellRenderer treeCellRenderer = new DefaultTreeCellRenderer() {
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean sel, boolean expanded, boolean leaf, int row,
boolean hasFocus) {
super.getTreeCellRendererComponent(tree, value, sel, expanded,
leaf, row, hasFocus);
DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
try {
SwoopReasoner reasoner = swoopModel.getReasoner();
Set set = (Set) node.getUserObject();
String label = "";
boolean changed = false;
boolean annoteated = false;
boolean isCycle = false;
//*********************************************
//Added for Econnections
//**********************************************
boolean econnected = false;
//**********************************************
// check to see if this node is at the end of a cycle
// and initialize possible cycle head
SwoopTreeNode stn = (SwoopTreeNode)node;
OWLEntity cycleHead = null;
if ( ((Boolean)stn.getUserObject( SwoopTreeNode.IS_IN_CYCLE )).booleanValue() )
{
isCycle = true;
cycleHead = (OWLEntity)stn.getUserObject( SwoopTreeNode.CYCLE_HEAD );
}
if (set.size() > 1)
label += "[";
Iterator i = set.iterator();
while (i.hasNext()) {
OWLEntity entity = (OWLEntity) i.next();
// check if entity is dirty (has changes associated with it)
// if (swoopModel.getDirtyEntities().contains(entity))
if (swoopModel.getChangesCache().getChangeList(entity.getURI()).size()>0)
changed = true;
// mark entities that have annotations with superscript A
try {
if (swoopModel.getAnnotatedObjectURIs().contains(
entity.getURI()))
annoteated = true;
} catch (Exception e1) {
e1.printStackTrace();
}
//*************************************************
// Changed for Econnections
//*************************************************
//Iterator iter =
// swoopModel.getSelectedOntology().getObjectProperties().iterator();
//while(iter.hasNext()){
//OWLObjectProperty prop = (OWLObjectProperty)iter.next();
// if(prop.isLink()){
// if(entity instanceof OWLClass &&
// OntologyHelper.entityUsage(swoopModel.getSelectedOntology(),
// prop).contains(entity)){
//econnected = true;
// econnected=false;
//break;
//}
//}
//}
//*************************************************
SwoopIcons swoopIcons = new SwoopIcons();
if (swoopIcons.getIcon(entity, swoopModel) != null)
setIcon(swoopIcons.getIcon(entity, swoopModel));
label += getShortForm(entity.getURI());
if (i.hasNext())
label += ", ";
}
if (set.size() > 1)
label += "]";
if (changed)
label = label + "*";
if (swoopModel.getUseLabels() || annoteated || econnected || isCycle) {
String htmlLabel = "<html>";
//if (econnected) htmlLabel += "<sup> <font
// size=\"2\">ECONN </font></sup>" ;
if (econnected)
htmlLabel += "<b> <font color=\"#CC6600\">";
htmlLabel += label;
if (annoteated)
htmlLabel += "<sup>A</sup>";
if (econnected)
htmlLabel += "</font> </b>";
if (isCycle)
{
String cycleHeadName = swoopModel.shortForm( cycleHead.getURI());
htmlLabel += "<sup>" + cycleHeadName + "</sup>";
}
htmlLabel += "</html>";
label = htmlLabel;
}
setText(label);
//setPreferredSize(new Dimension(label.length()+200, 32));
} catch (OWLException e) {
e.printStackTrace();
}
return this;
}
};
/**
* Constructor
*/
public TreeRenderer(SwoopModel swoopModel, SwoopFrame swoopHandler) {
this.swoopModel = swoopModel;
this.swoopHandler = swoopHandler;
}
public JTree getClassTree(JTree currentTree) throws OWLException {
System.out.println("Create class tree");
SwoopReasoner reasoner = swoopModel.getReasoner();
OWLOntology ontology = reasoner.getOntology();
Font newFont = swoopModel.getFont();
if (ontology == null)
return null;
if (!ontology.equals(swoopModel.getSelectedOntology())) {
System.out
.println("ontology mismatch in swoopReasoner and swoopModel!");
}
JTree classTree = null;
if (ontology == null)
return classTree;
classTree = swoopModel.getClassTreeCache().getTree(ontology, reasoner);
// check if ontology is in cache -> get property tree from cache
if (classTree != null) {
classTree.setFont(newFont);
System.out.println("loading class tree from cache");
return classTree;
}
SwoopTreeNode thing = null;
SwoopTreeNode nothing = null;
owlThing = ontology.getOWLDataFactory().getOWLThing();
owlNothing = ontology.getOWLDataFactory().getOWLNothing();
Set set = reasoner.equivalentClassesOf(owlThing);
set.add(owlThing);
thing = createClassTree(set, new HashSet() );
Set eqs = reasoner.equivalentClassesOf(owlNothing);
Iterator i = eqs.iterator();
if (i.hasNext()) {
nothing = createNode(owlNothing);
while (i.hasNext()) {
OWLClass sub = (OWLClass) i.next();
SwoopTreeNode node = createNode(sub);
if (node != null)
nothing.add(node);
}
thing.add(nothing);
}
classTree = new JTree(new DefaultTreeModel(thing));
classTree.setFont(newFont);
classTree.setCellRenderer(treeCellRenderer);
classTree.setLargeModel(true); // resize qname toggle node labels
if (this.getEntityCount(ontology, 0) < Integer.parseInt(swoopModel
.getTreeThreshold())) {
// expand each node, if class count < threshold
for (int row = 1;; row++) {
if (classTree.getPathForRow(row) != null)
classTree.expandRow(row);
else
break;
}
} else {
// dont expand each node in tree
// check for current open nodes and expand only those
if (currentTree != null
&& this.useOldClassTreeReferenceforExpansion) {
this.useOldClassTreeReferenceforExpansion = false;
Enumeration enu = currentTree
.getExpandedDescendants(currentTree.getPathForRow(0));
if (enu != null) {
while (enu.hasMoreElements()) {
TreePath path = (TreePath) enu.nextElement();
int row = currentTree.getRowForPath(path);
classTree.expandRow(row);
}
}
}
}
// put class tree in cache
swoopModel.getClassTreeCache().putTree(ontology, reasoner, classTree);
System.out.println(ontology.getURI() + " class tree put in cache");
return classTree;
}
SwoopTreeNode createClassTree( Set concepts, Set ancestors ) throws OWLException {
if (concepts.contains(owlNothing))
return null;
SwoopTreeNode root = createNode(concepts);
if (concepts.isEmpty())
return root;
SwoopReasoner reasoner = swoopModel.getReasoner();
Object obj = concepts.iterator().next();
if (obj instanceof OWLClass)
{
OWLClass c = (OWLClass) obj;
// filter rules classes Impl, ClassAtom, IndividualPropertyAtom,
// etc.
if (c.getURI().getPath().equals("/2003/11/swrl"))
return null;
Set subs = reasoner.subClassesOf(c);
Iterator i = subs.iterator();
ancestors.add( concepts );
while (i.hasNext())
{
Set set = (Set) i.next();
if (set.contains(c))
continue;
SortedSet sortedSet = orderedEntities(set);
// if ancestors set contains the subclass set then we have a cycle
if ( ancestors.contains( set ) )
{
root.addUserObject( SwoopTreeNode.IS_IN_CYCLE, SwoopTreeNode.TRUE );
OWLClass cycleHead = (OWLClass)set.iterator().next();
root.addUserObject( SwoopTreeNode.CYCLE_HEAD, cycleHead );
continue;
}
SwoopTreeNode node = createClassTree(sortedSet, ancestors);
// do not add owl:Nothing to the tree
if (node != null) {
int index = 0;
for (; index < root.getChildCount(); index++) {
DefaultMutableTreeNode child = (DefaultMutableTreeNode) root
.getChildAt(index);
SortedSet otherSet = (SortedSet) child.getUserObject();
OWLEntity c1 = (OWLEntity) sortedSet.first();
OWLEntity c2 = (OWLEntity) otherSet.first();
if (EntityComparator.INSTANCE.compare(
sortedSet.first(), otherSet.first()) < 0)
break;
}
root.insert(node, index);
}
}
ancestors.remove( concepts );
}
return root;
}
/**
* Count the number of entities of a given type.
* @param ontology The ontology to be inspected. If swoopModel.getShowImports(),
* use the import closure.
* @param entityType '0' for classes, '1' for properties (excluding Annotation
* properties).
* @return The number of entities.
*/
private int getEntityCount(OWLOntology ontology, int entityType) {
int count = 0;
try {
Set ontologies = Collections.singleton(ontology);
if (swoopModel.getShowImports()) {
ontologies = OntologyHelper.importClosure(ontology);
}
for (Iterator iter = ontologies.iterator(); iter.hasNext();) {
OWLOntology ont = (OWLOntology) iter.next();
switch (entityType) {
case 0:// class count
count += ont.getClasses().size();
break;
case 1:// prop count
count += ont.getDataProperties().size();
count += ont.getObjectProperties().size();
break;
}
}
} catch (OWLException ex) {
ex.printStackTrace();
}
return count;
}
SwoopTreeNode createNode(OWLEntity entity) {
return new SwoopTreeNode(Collections.singleton(entity));
}
SwoopTreeNode createNode(Set set) {
return new SwoopTreeNode(set);
}
private SortedSet orderedEntities(Set entities) {
SortedSet ss = new TreeSet(EntityComparator.INSTANCE);
ss.addAll(entities);
return ss;
}
public JTree getPropertyTree(JTree currentTree) throws Exception {
System.out.println("Create prop tree");
SwoopReasoner reasoner = swoopModel.getReasoner();
OWLOntology ontology = reasoner.getOntology();
JTree propTree = null;
Font newFont = swoopModel.getFont();
if (ontology == null)
return propTree;
propTree = swoopModel.getPropTreeCache().getTree(ontology, reasoner);
// check if ontology is in cache -> get property tree from cache
if (propTree != null) {
propTree.setFont(newFont);
System.out.println("loading prop tree from cache");
return propTree;
}
OWLClass owlThing = ontology.getOWLDataFactory().getOWLThing();
SwoopTreeNode root = createNode(owlThing);
propTree = new JTree(new DefaultTreeModel(root));
propTree.setFont(newFont);
propTree.setCellRenderer(treeCellRenderer);
propTree.setLargeModel(true); // resize qname toggle node labels
SortedSet set = orderedEntities(reasoner.getProperties());
// filter rules properties argument1, argument2, body, classPredicate,
// etc.
for (Iterator it = set.iterator(); it.hasNext();) {
OWLEntity entity = (OWLEntity) it.next();
if (entity.getURI().getPath().equals("/2003/11/swrl") )
it.remove();
}
Iterator i = set.iterator();
while (i.hasNext()) {
OWLProperty prop = (OWLProperty) i.next();
Set eqProps = reasoner.equivalentPropertiesOf(prop);
Set superProps = reasoner.superPropertiesOf(prop);
if (superProps.size() > 0)
continue;
eqProps.add(prop);
root.add(createPropertyTree(eqProps));
}
propTree.setModel(new DefaultTreeModel(root));
if (this.getEntityCount(ontology, 1) < Integer.parseInt(swoopModel
.getTreeThreshold())) {
// expand each node, if property count < threshold
for (int row = 1;; row++) {
if (propTree.getPathForRow(row) != null)
propTree.expandRow(row);
else
break;
}
} else {
// dont expand each node in tree
// check for current open nodes and expand only those
if (currentTree != null
&& this.useOldPropertyTreeReferenceforExpansion) {
this.useOldPropertyTreeReferenceforExpansion = false;
Enumeration enu = currentTree
.getExpandedDescendants(currentTree.getPathForRow(0));
if (enu != null) {
while (enu.hasMoreElements()) {
TreePath path = (TreePath) enu.nextElement();
int row = currentTree.getRowForPath(path);
propTree.expandRow(row);
}
}
}
}
propTree.setRootVisible(false);
propTree.setShowsRootHandles(true);
propTree.setFont(newFont);
// put property tree in cache
swoopModel.getPropTreeCache().putTree(ontology, reasoner, propTree);
System.out.println(ontology.getURI() + " prop tree put in cache");
return propTree;
}
SwoopTreeNode createPropertyTree(Set props) throws OWLException {
SwoopTreeNode root = createNode(props);
Object obj = props.iterator().next();
if (obj instanceof OWLProperty) {
OWLProperty prop = (OWLProperty) obj;
SwoopReasoner reasoner = swoopModel.getReasoner();
Set subs = reasoner.subPropertiesOf(prop);
Iterator i = subs.iterator();
while (i.hasNext()) {
SortedSet set = orderedEntities((Set) i.next());
if (set.contains(prop))
continue;
SwoopTreeNode node = createPropertyTree(set);
int index = 0;
for (; index < root.getChildCount(); index++) {
DefaultMutableTreeNode child = (DefaultMutableTreeNode) root
.getChildAt(index);
SortedSet otherSet = (SortedSet) child.getUserObject();
OWLEntity c1 = (OWLEntity) set.first();
OWLEntity c2 = (OWLEntity) otherSet.first();
if (EntityComparator.INSTANCE.compare(set.first(), otherSet
.first()) < 0)
break;
}
root.insert(node, index);
}
}
return root;
}
private String getShortForm(URI uri) {
return shortFormProvider.shortForm(uri);
}
/**
* @return Returns the shortFormProvider.
*/
public ShortFormProvider getShortFormProvider() {
return shortFormProvider;
}
/**
* @param shortFormProvider
* The shortFormProvider to set.
*/
public void setShortFormProvider(ShortFormProvider shortFormProvider) {
this.shortFormProvider = shortFormProvider;
}
public void setSwoopModel(SwoopModel swoopModel) {
this.swoopModel = swoopModel;
}
public void removeClassTreeCacheEntry(OWLOntology ont) {
swoopModel.getClassTreeCache().removeOntology(ont);
}
public void removeClassTreeCacheEntry(OWLOntology ont,
SwoopReasoner reasoner) {
swoopModel.getClassTreeCache().putTree(ont, reasoner, null);
}
public void removePropTreeCacheEntry(OWLOntology ont) {
swoopModel.getPropTreeCache().removeOntology(ont);
}
public void removePropTreeCacheEntry(OWLOntology ont, SwoopReasoner reasoner) {
swoopModel.getPropTreeCache().putTree(ont, reasoner, null);
}
public void export( JTree tree, String type, File file, SwoopModel model)
{ TreeSerializer.export( tree, type, file, model); }
}