├── src └── main │ ├── resources │ ├── open.gif │ ├── save.gif │ ├── pinned.gif │ ├── icon_plus.gif │ ├── note_edit.png │ ├── page_edit.png │ ├── export_wiz.gif │ ├── icon_export.gif │ ├── image_edit.png │ ├── comment_edit.png │ ├── viewconfig-ontograf.xml │ └── readme.html │ └── java │ └── org │ └── protege │ └── ontograf │ ├── common │ ├── util │ │ ├── NodeOWLClassTooltipType.java │ │ ├── NodeOWLIndividualTooltipType.java │ │ ├── IconConstants.java │ │ └── OWLIconProviderImpl.java │ ├── ProtegeInputEventHandler.java │ ├── GraphController.java │ └── ProtegeGraphModel.java │ ├── actions │ ├── ConfigTooltipsAction.java │ ├── SaveGraphAction.java │ ├── ExportAsDotAction.java │ ├── PinTooltipsAction.java │ ├── OpenGraphAction.java │ └── ExportImageAction.java │ ├── OntoGrafImportView.java │ ├── ui │ ├── TooltipConfigurationDialog.java │ ├── OntoGrafFileFilter.java │ └── FrameTooltipNode.java │ └── OntoGrafView.java ├── .gitignore ├── update-info ├── protege-4 │ └── update.properties └── protege-5 │ └── update.properties ├── README.md ├── plugin.xml ├── META-INF └── MANIFEST.MF └── pom.xml /src/main/resources/open.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/protegeproject/ontograf/HEAD/src/main/resources/open.gif -------------------------------------------------------------------------------- /src/main/resources/save.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/protegeproject/ontograf/HEAD/src/main/resources/save.gif -------------------------------------------------------------------------------- /src/main/resources/pinned.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/protegeproject/ontograf/HEAD/src/main/resources/pinned.gif -------------------------------------------------------------------------------- /src/main/resources/icon_plus.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/protegeproject/ontograf/HEAD/src/main/resources/icon_plus.gif -------------------------------------------------------------------------------- /src/main/resources/note_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/protegeproject/ontograf/HEAD/src/main/resources/note_edit.png -------------------------------------------------------------------------------- /src/main/resources/page_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/protegeproject/ontograf/HEAD/src/main/resources/page_edit.png -------------------------------------------------------------------------------- /src/main/resources/export_wiz.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/protegeproject/ontograf/HEAD/src/main/resources/export_wiz.gif -------------------------------------------------------------------------------- /src/main/resources/icon_export.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/protegeproject/ontograf/HEAD/src/main/resources/icon_export.gif -------------------------------------------------------------------------------- /src/main/resources/image_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/protegeproject/ontograf/HEAD/src/main/resources/image_edit.png -------------------------------------------------------------------------------- /src/main/resources/comment_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/protegeproject/ontograf/HEAD/src/main/resources/comment_edit.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Maven 2 | target/ 3 | 4 | # Eclipse 5 | .classpath 6 | .project 7 | .settings/ 8 | META-INF/ 9 | 10 | #intelliJ 11 | *.iws 12 | *.ipr 13 | .idea 14 | *.iml 15 | build/ 16 | -------------------------------------------------------------------------------- /update-info/protege-4/update.properties: -------------------------------------------------------------------------------- 1 | name=OntoGraf 2 | id=org.protege.ontograf 3 | version=1.0.3 4 | download=https://github.com/protegeproject/ontograf/releases/download/ontograf-1.0.3/org.protege.ontograf.jar 5 | readme=https://raw.githubusercontent.com/protegeproject/ontograf/master/src/main/resources/readme.html 6 | license=http://www.gnu.org/licenses/lgpl.html 7 | author=CO-ODE, The University of Manchester -------------------------------------------------------------------------------- /update-info/protege-5/update.properties: -------------------------------------------------------------------------------- 1 | name=OntoGraf 2 | id=org.protege.ontograf 3 | version=2.0.3 4 | download=https://github.com/protegeproject/ontograf/releases/download/ontograf-2.0.3/ontograf-2.0.3.jar 5 | readme=https://raw.githubusercontent.com/protegeproject/ontograf/master/src/main/resources/readme.html 6 | license=http://www.gnu.org/licenses/lgpl.html 7 | author=CO-ODE, The University of Manchester 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | OntoGraf 2 | ==================== 3 | 4 | Protege Desktop plug-in that allows visual, interactive navigation of the relationships in OWL ontologies. 5 | 6 | OntoGraf is bundled with the default installation of Protege Desktop. There are no additional installation steps required. Enable OntoGraf from the Window | Tabs menu. More user documentation is available on the Protege wiki: 7 | 8 | http://protegewiki.stanford.edu/wiki/OntoGraf 9 | -------------------------------------------------------------------------------- /src/main/resources/viewconfig-ontograf.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/java/org/protege/ontograf/common/util/NodeOWLClassTooltipType.java: -------------------------------------------------------------------------------- 1 | package org.protege.ontograf.common.util; 2 | 3 | public enum NodeOWLClassTooltipType { 4 | TITLE("Title"), URI("URI"), SUPERCLASSES("Superclasses"), EQUIVALENT_CLASSES("Equivalent classes"), 5 | DISJOINT_CLASSES("Disjoint classes"), ANNOTATIONS("Annotations"); 6 | 7 | private final String value; 8 | private boolean enabled; 9 | 10 | NodeOWLClassTooltipType(String value) { 11 | this.value = value; 12 | this.enabled = true; 13 | } 14 | 15 | public boolean isEnabled() { 16 | return enabled; 17 | } 18 | 19 | public void setEnabled(boolean enabled) { 20 | this.enabled = enabled; 21 | } 22 | 23 | public String toString() { 24 | return value; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/resources/readme.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

OntoGraf

9 |

by Sean Falconer

10 |

11 | OntoGraf gives support for interactively navigating the relationships 12 | of your OWL ontologies. Various layouts are supported for 13 | automatically organizing the structure of your ontology. Different 14 | relationships are supported: subclass, individual, domain/range object 15 | properties, and equivalence. Relationships and node types can be 16 | filtered to help you create the view you desire. For more infomration 17 | look on the 18 | the wiki page. 19 |

20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/main/java/org/protege/ontograf/common/util/NodeOWLIndividualTooltipType.java: -------------------------------------------------------------------------------- 1 | package org.protege.ontograf.common.util; 2 | 3 | public enum NodeOWLIndividualTooltipType { 4 | TITLE("Title"), URI("URI"), SAME_INDIVIDUALS("Same individuals"), DIFFERENT_INDIVIDUALS("Different individuals"), 5 | OBJECT_PROPERTY_ASSERTIONS("Object property assertions"), DATA_PROPERTY_ASSERTIONS("Data property assertions"), 6 | NEGATIVE_OBJECT_PROPERTY_ASSERTIONS("Negative object property assertions"), NEGATIVE_DATA_PROPERTY_ASSERTIONS("Negative data property assertions"), ANNOTATIONS("Annotations"); 7 | 8 | private final String value; 9 | private boolean enabled; 10 | 11 | NodeOWLIndividualTooltipType(String value) { 12 | this.value = value; 13 | this.enabled = true; 14 | } 15 | 16 | public boolean isEnabled() { 17 | return enabled; 18 | } 19 | 20 | public void setEnabled(boolean enabled) { 21 | this.enabled = enabled; 22 | } 23 | 24 | public String toString() { 25 | return value; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/protege/ontograf/actions/ConfigTooltipsAction.java: -------------------------------------------------------------------------------- 1 | package org.protege.ontograf.actions; 2 | 3 | import java.awt.Component; 4 | 5 | import javax.swing.Action; 6 | 7 | import org.protege.ontograf.common.util.IconConstants; 8 | import org.protege.ontograf.ui.TooltipConfigurationDialog; 9 | 10 | import ca.uvic.cs.chisel.cajun.actions.CajunAction; 11 | import edu.umd.cs.piccolo.PCanvas; 12 | 13 | public class ConfigTooltipsAction extends CajunAction { 14 | private static final long serialVersionUID = 7241297162054742885L; 15 | 16 | private static final String ACTION_NAME = "Configure Node Tooltips"; 17 | 18 | private TooltipConfigurationDialog tooltipDialog; 19 | 20 | public ConfigTooltipsAction(Component parent, PCanvas canvas) { 21 | super(ACTION_NAME, IconConstants.ICON_EDIT_NODE_TOOLTIP); 22 | 23 | putValue(Action.SHORT_DESCRIPTION, ACTION_NAME); 24 | 25 | tooltipDialog = new TooltipConfigurationDialog(); 26 | } 27 | 28 | @Override 29 | public void doAction() { 30 | tooltipDialog.setVisible(true); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 12 | 13 | 15 | 20 | 21 | 23 | 29 | 30 | -------------------------------------------------------------------------------- /META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Bundle-ManifestVersion: 2 3 | Bundle-Name: OntoGraf Plug-in 4 | Bundle-SymbolicName: org.protege.ontograf;singleton:=true 5 | Bundle-Category: protege 6 | Bundle-Description: A plugin for visualizing ontologies 7 | Bundle-Vendor: The Protege Team 8 | Bundle-DocURL: http://protege.stanford.edu/ 9 | Bundle-ClassPath: ., 10 | lib/layouts.jar, 11 | lib/org.eclipse.draw2d_3.2.100.v20070522.jar, 12 | lib/piccolo.jar, 13 | lib/piccolox.jar 14 | Import-Package: javax.imageio, 15 | javax.swing, 16 | javax.swing.border, 17 | javax.swing.colorchooser, 18 | javax.swing.event, 19 | javax.swing.filechooser, 20 | javax.swing.plaf, 21 | javax.swing.plaf.basic, 22 | javax.swing.plaf.metal, 23 | javax.swing.plaf.multi, 24 | javax.swing.plaf.synth, 25 | javax.swing.table, 26 | javax.swing.text, 27 | javax.swing.text.html, 28 | javax.swing.text.html.parser, 29 | javax.swing.text.rtf, 30 | javax.swing.tree, 31 | javax.swing.undo, 32 | javax.xml.parsers, 33 | org.apache.log4j, 34 | org.osgi.framework, 35 | org.w3c.dom, 36 | org.w3c.dom.bootstrap, 37 | org.w3c.dom.events, 38 | org.w3c.dom.ls, 39 | org.xml.sax, 40 | org.xml.sax.ext, 41 | org.xml.sax.helpers 42 | Bundle-Version: 1.0.3 43 | Bundle-Activator: org.protege.editor.core.plugin.DefaultPluginActivator 44 | Require-Bundle: org.protege.common, 45 | org.protege.editor.core.application, 46 | org.protege.editor.owl, 47 | org.semanticweb.owl.owlapi, 48 | ca.uvic.cs.chisel.cajun 49 | -------------------------------------------------------------------------------- /src/main/java/org/protege/ontograf/common/util/IconConstants.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1998-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada. 3 | * All rights reserved. 4 | */ 5 | package org.protege.ontograf.common.util; 6 | 7 | import java.net.URL; 8 | 9 | import javax.swing.Icon; 10 | import javax.swing.ImageIcon; 11 | 12 | import org.protege.ontograf.common.GraphController; 13 | 14 | 15 | /** 16 | * Interface for storing icons used by this tool. 17 | * 18 | * @author Sean Falconer 19 | */ 20 | public abstract class IconConstants { 21 | public static final Icon ICON_PLUS = loadImageIcon(GraphController.class, "/icon_plus.gif"); 22 | 23 | public static final Icon ICON_EXPORT_IMAGE = loadImageIcon(GraphController.class, "/icon_export.gif"); 24 | public static final Icon ICON_EDIT_NODE_TOOLTIP = loadImageIcon(GraphController.class, "/image_edit.png"); 25 | public static final Icon ICON_SAVE_GRAPH = loadImageIcon(GraphController.class, "/save.gif"); 26 | public static final Icon ICON_EXPORT_DOT_GRAPH = loadImageIcon(GraphController.class, "/export_wiz.gif"); 27 | public static final Icon ICON_OPEN_GRAPH = loadImageIcon(GraphController.class, "/open.gif"); 28 | public static final Icon ICON_PIN_TOOLTIPS = loadImageIcon(GraphController.class, "/pinned.gif"); 29 | 30 | @SuppressWarnings("unchecked") 31 | public static ImageIcon loadImageIcon(Class clas, String iconPath) { 32 | ImageIcon icon = null; 33 | URL url = clas.getResource(iconPath); 34 | if (url != null) { 35 | icon = new ImageIcon(url); 36 | } 37 | else { 38 | icon = new ImageIcon(iconPath); 39 | } 40 | return icon; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/org/protege/ontograf/actions/SaveGraphAction.java: -------------------------------------------------------------------------------- 1 | package org.protege.ontograf.actions; 2 | 3 | import java.awt.Component; 4 | import java.io.File; 5 | import java.io.FileNotFoundException; 6 | import java.io.PrintStream; 7 | 8 | import javax.swing.Action; 9 | import javax.swing.JFileChooser; 10 | import javax.swing.JOptionPane; 11 | 12 | import org.protege.editor.owl.model.OWLModelManager; 13 | import org.protege.ontograf.common.GraphController; 14 | import org.protege.ontograf.common.util.IconConstants; 15 | import org.protege.ontograf.ui.OntoGrafFileFilter; 16 | import org.semanticweb.owlapi.model.OWLEntity; 17 | 18 | import ca.uvic.cs.chisel.cajun.actions.CajunAction; 19 | import ca.uvic.cs.chisel.cajun.graph.GraphModel; 20 | import ca.uvic.cs.chisel.cajun.graph.node.DefaultGraphNode; 21 | import ca.uvic.cs.chisel.cajun.graph.node.GraphNode; 22 | 23 | public class SaveGraphAction extends CajunAction { 24 | private static final long serialVersionUID = 7241297162054742885L; 25 | 26 | private static final String ACTION_NAME = "Save Current Graph"; 27 | 28 | private JFileChooser fileChooser; 29 | 30 | private Component parent; 31 | private GraphController controller; 32 | 33 | public SaveGraphAction(Component parent, GraphController controller) { 34 | super(ACTION_NAME, IconConstants.ICON_SAVE_GRAPH); 35 | 36 | putValue(Action.SHORT_DESCRIPTION, ACTION_NAME); 37 | 38 | this.parent = parent; 39 | this.controller = controller; 40 | 41 | fileChooser = new JFileChooser(); 42 | fileChooser.setDialogTitle("Save graph configuration to a file"); 43 | fileChooser.addChoosableFileFilter(new OntoGrafFileFilter(new String[] { "graph" }, "OntoGraf File")); 44 | } 45 | 46 | @Override 47 | public void doAction() { 48 | int result = fileChooser.showSaveDialog(parent); 49 | 50 | if(result == JFileChooser.CANCEL_OPTION) return; 51 | 52 | String filePath = fileChooser.getSelectedFile().getPath(); 53 | if(!filePath.contains(".graph")) { 54 | filePath += ".graph"; 55 | } 56 | File file = new File(filePath); 57 | 58 | if(file.exists()) { 59 | String msg = "The file " + file.toString() + " already exists.\nDo you want to overwrite this existing file?"; 60 | int opt = JOptionPane.showConfirmDialog(parent, msg, 61 | "Export Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); 62 | 63 | if(opt == JOptionPane.NO_OPTION) return; 64 | } 65 | 66 | try { 67 | PrintStream out = new PrintStream(file); 68 | 69 | GraphModel model = controller.getGraph().getModel(); 70 | OWLModelManager owlModelManager = controller.getModel().getOwlModelManager(); 71 | 72 | out.println(owlModelManager.getActiveOntology().getOntologyID().getOntologyIRI().toString()); 73 | 74 | for(GraphNode node : model.getAllNodes()) { 75 | if(node instanceof DefaultGraphNode) { 76 | DefaultGraphNode graphNode = (DefaultGraphNode)node; 77 | OWLEntity entity = (OWLEntity)graphNode.getUserObject(); 78 | 79 | out.println(entity.getIRI().toString() + "," + graphNode.getX() + "," + graphNode.getY()); 80 | } 81 | } 82 | out.close(); 83 | } catch (FileNotFoundException e) { 84 | // TODO Auto-generated catch block 85 | e.printStackTrace(); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/org/protege/ontograf/actions/ExportAsDotAction.java: -------------------------------------------------------------------------------- 1 | package org.protege.ontograf.actions; 2 | 3 | import java.awt.Component; 4 | import java.io.File; 5 | import java.io.FileNotFoundException; 6 | import java.io.PrintStream; 7 | 8 | import javax.swing.Action; 9 | import javax.swing.JFileChooser; 10 | import javax.swing.JOptionPane; 11 | 12 | import org.protege.ontograf.common.GraphController; 13 | import org.protege.ontograf.common.util.IconConstants; 14 | import org.protege.ontograf.ui.OntoGrafFileFilter; 15 | 16 | import ca.uvic.cs.chisel.cajun.actions.CajunAction; 17 | import ca.uvic.cs.chisel.cajun.graph.GraphModel; 18 | import ca.uvic.cs.chisel.cajun.graph.arc.DefaultGraphArc; 19 | import ca.uvic.cs.chisel.cajun.graph.arc.GraphArc; 20 | 21 | public class ExportAsDotAction extends CajunAction { 22 | private static final long serialVersionUID = 7241297162054742885L; 23 | 24 | private static final String ACTION_NAME = "Export Graph to DOT"; 25 | 26 | private JFileChooser fileChooser; 27 | 28 | private Component parent; 29 | private GraphController controller; 30 | 31 | public ExportAsDotAction(Component parent, GraphController controller) { 32 | super(ACTION_NAME, IconConstants.ICON_EXPORT_DOT_GRAPH); 33 | 34 | putValue(Action.SHORT_DESCRIPTION, ACTION_NAME); 35 | 36 | this.parent = parent; 37 | this.controller = controller; 38 | 39 | fileChooser = new JFileChooser(); 40 | fileChooser.setDialogTitle("Save graph as DOT file"); 41 | fileChooser.addChoosableFileFilter(new OntoGrafFileFilter(new String[] { "dot" }, "DOT File")); 42 | } 43 | 44 | @Override 45 | public void doAction() { 46 | int result = fileChooser.showSaveDialog(parent); 47 | 48 | if(result == JFileChooser.CANCEL_OPTION) return; 49 | 50 | String filePath = fileChooser.getSelectedFile().getPath(); 51 | if(!filePath.contains(".dot")) { 52 | filePath += ".dot"; 53 | } 54 | File file = new File(filePath); 55 | 56 | if(file.exists()) { 57 | String msg = "The file " + file.toString() + " already exists.\nDo you want to overwrite this existing file?"; 58 | int opt = JOptionPane.showConfirmDialog(parent, msg, 59 | "Export Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); 60 | 61 | if(opt == JOptionPane.NO_OPTION) return; 62 | } 63 | 64 | try { 65 | PrintStream out = new PrintStream(file); 66 | 67 | GraphModel model = controller.getGraph().getModel(); 68 | 69 | out.println("digraph g {"); 70 | //out.println("\tnode [shape="); 71 | 72 | for(GraphArc arc : model.getAllArcs()) { 73 | if(arc instanceof DefaultGraphArc) { 74 | DefaultGraphArc graphArc = (DefaultGraphArc)arc; 75 | out.println("\t\"" + graphArc.getSource().getText() + "\" -> \"" + graphArc.getDestination().getText() 76 | + "\" [label=\"" + graphArc.getType() + "\"]"); 77 | } 78 | } 79 | 80 | // for(GraphNode node : model.getAllNodes()) { 81 | // if(node instanceof DefaultGraphNode) { 82 | // DefaultGraphNode graphNode = (DefaultGraphNode)node; 83 | // graphNode. 84 | // 85 | // //OWLEntity entity = (OWLEntity)graphNode.getUserObject(); 86 | // 87 | // //out.println(entity.getIRI().toString() + "," + graphNode.getX() + "," + graphNode.getY()); 88 | // } 89 | // } 90 | out.println("}"); 91 | out.close(); 92 | } catch (FileNotFoundException e) { 93 | // TODO Auto-generated catch block 94 | e.printStackTrace(); 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/org/protege/ontograf/common/ProtegeInputEventHandler.java: -------------------------------------------------------------------------------- 1 | package org.protege.ontograf.common; 2 | 3 | import org.protege.ontograf.ui.FrameTooltipNode; 4 | import org.semanticweb.owlapi.model.OWLEntity; 5 | 6 | import ca.uvic.cs.chisel.cajun.graph.AbstractGraph; 7 | import ca.uvic.cs.chisel.cajun.graph.node.DefaultGraphNode; 8 | import ca.uvic.cs.chisel.cajun.graph.node.GraphNode; 9 | import edu.umd.cs.piccolo.PCamera; 10 | import edu.umd.cs.piccolo.event.PBasicInputEventHandler; 11 | import edu.umd.cs.piccolo.event.PInputEvent; 12 | import edu.umd.cs.piccolo.event.PInputEventFilter; 13 | 14 | /** 15 | * Handles input events on the graph. 16 | * 17 | * @author seanf 18 | */ 19 | public class ProtegeInputEventHandler extends PBasicInputEventHandler { 20 | private static final int DOUBLE_CLICK = 2; 21 | 22 | private ProtegeGraphModel graphModel; 23 | private AbstractGraph graph; 24 | 25 | private FrameTooltipNode toolTip; 26 | private DefaultGraphNode currentNode; 27 | 28 | public ProtegeInputEventHandler(ProtegeGraphModel graphModel, AbstractGraph graph) { 29 | this.graphModel = graphModel; 30 | this.graph = graph; 31 | 32 | PInputEventFilter filter = new PInputEventFilter(); 33 | filter.rejectAllEventTypes(); 34 | filter.setAcceptsMousePressed(true); 35 | filter.setAcceptsMouseMoved(true); 36 | 37 | this.setEventFilter(filter); 38 | } 39 | 40 | public void mouseMoved(PInputEvent event) { 41 | if(event.getPickedNode() instanceof GraphNode) { 42 | if(!event.getPickedNode().equals(currentNode)) { 43 | showToolTip((DefaultGraphNode)event.getPickedNode()); 44 | } 45 | } 46 | else if(currentNode != null) { 47 | hideToolTip(currentNode); 48 | currentNode = null; 49 | } 50 | } 51 | 52 | public void mousePressed(PInputEvent event) { 53 | hideToolTip(currentNode); 54 | 55 | if (event.isLeftMouseButton()) { 56 | if (event.getClickCount() == DOUBLE_CLICK) { 57 | if (event.getPickedNode() instanceof GraphNode) { 58 | expandCollapseNode((GraphNode) event.getPickedNode()); 59 | //((FlatGraph) graph).getAnimationHandler().moveViewToCenterBounds(graph.getBounds(), false, 1000, true); 60 | } 61 | } 62 | else if(event.getClickCount() == 1 && event.isControlDown()) { 63 | showToolTip((DefaultGraphNode)event.getPickedNode()); 64 | currentNode = null; 65 | } 66 | } 67 | } 68 | 69 | private void hideToolTip(DefaultGraphNode node) { 70 | PCamera camera = graph.getCanvas().getCamera(); 71 | if(toolTip != null) { 72 | camera.removeChild(toolTip); 73 | camera.repaint(); 74 | toolTip = null; 75 | } 76 | } 77 | 78 | private void showToolTip(DefaultGraphNode node) { 79 | PCamera camera = graph.getCanvas().getCamera(); 80 | hideToolTip(node); 81 | 82 | toolTip = new FrameTooltipNode(graphModel.getOwlModelManager(), graph, node, (OWLEntity)node.getUserObject()); 83 | camera.addChild(toolTip); 84 | camera.repaint(); 85 | 86 | currentNode = node; 87 | } 88 | 89 | /** 90 | * Expands a node if it is not already expanded, otherwise it collapses it. 91 | * 92 | * @param graphNode The node to expand or collapse. 93 | */ 94 | private void expandCollapseNode(GraphNode graphNode) { 95 | graphNode.setHighlighted(false); 96 | graphNode.moveToFront(); 97 | 98 | if (graphModel.isExpanded(graphNode)) { 99 | graphModel.collapseNode(graphNode); 100 | } else { 101 | graphModel.expandNode(graphNode); 102 | } 103 | 104 | graph.performLayout(); 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/org/protege/ontograf/actions/PinTooltipsAction.java: -------------------------------------------------------------------------------- 1 | package org.protege.ontograf.actions; 2 | 3 | import java.awt.Component; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | import java.util.Map.Entry; 7 | 8 | import javax.swing.Action; 9 | import javax.swing.event.ChangeEvent; 10 | import javax.swing.event.ChangeListener; 11 | 12 | import org.protege.ontograf.common.GraphController; 13 | import org.protege.ontograf.common.util.IconConstants; 14 | import org.protege.ontograf.ui.FrameTooltipNode; 15 | import org.semanticweb.owlapi.model.OWLEntity; 16 | 17 | import ca.uvic.cs.chisel.cajun.actions.CajunAction; 18 | import ca.uvic.cs.chisel.cajun.graph.AbstractGraph; 19 | import ca.uvic.cs.chisel.cajun.graph.GraphModelAdapter; 20 | import ca.uvic.cs.chisel.cajun.graph.node.DefaultGraphNode; 21 | import ca.uvic.cs.chisel.cajun.graph.node.GraphNode; 22 | import edu.umd.cs.piccolo.PNode; 23 | 24 | public class PinTooltipsAction extends CajunAction { 25 | private static final long serialVersionUID = 7241297162054742885L; 26 | 27 | private static final String ACTION_NAME = "Pin Node Tooltips"; 28 | 29 | private GraphController graphController; 30 | 31 | private boolean show = true; 32 | 33 | private Map existingTooltipsMap; 34 | private Map changeListenerMap; 35 | 36 | public PinTooltipsAction(Component parent, GraphController graphController) { 37 | super(ACTION_NAME, IconConstants.ICON_PIN_TOOLTIPS); 38 | 39 | putValue(Action.SHORT_DESCRIPTION, ACTION_NAME); 40 | 41 | this.existingTooltipsMap = new HashMap(); 42 | this.changeListenerMap = new HashMap(); 43 | 44 | this.graphController = graphController; 45 | 46 | graphController.getModel().addGraphModelListener(new GraphModelAdapter() { 47 | @Override 48 | public void graphNodeAdded(GraphNode arg0) { 49 | if(!show) { 50 | showAllTooltips(); 51 | } 52 | } 53 | }); 54 | } 55 | 56 | public void doAction() { 57 | if(show) { 58 | showAllTooltips(); 59 | show = false; 60 | } 61 | else { 62 | hideAllTooltips(); 63 | show = true; 64 | } 65 | } 66 | 67 | private void hideAllTooltips() { 68 | for(Entry entry : existingTooltipsMap.entrySet()) { 69 | entry.getKey().removeChild(entry.getValue()); 70 | 71 | ChangeListener changeListener = changeListenerMap.get(entry.getValue()); 72 | ((DefaultGraphNode)entry.getKey()).removeChangeListener(changeListener); 73 | 74 | entry.getKey().repaint(); 75 | } 76 | 77 | existingTooltipsMap.clear(); 78 | changeListenerMap.clear(); 79 | } 80 | 81 | private void showAllTooltips() { 82 | for(GraphNode node : graphController.getModel().getAllNodes()) { 83 | // make sure there isn't already a tooltip showing 84 | if(existingTooltipsMap.get((PNode)node) == null) { 85 | FrameTooltipNode toolTip = new FrameTooltipNode(graphController.getModel().getOwlModelManager(), (AbstractGraph)graphController.getGraph(), (PNode)node, (OWLEntity)node.getUserObject()); 86 | ((PNode)node).addChild(toolTip); 87 | 88 | existingTooltipsMap.put((PNode)node, toolTip); 89 | 90 | ChangeListener changeListener = new ChangeListener() { 91 | public void stateChanged(ChangeEvent e) { 92 | PNode targetNode = existingTooltipsMap.get((PNode)e.getSource()); 93 | if(targetNode != null) { 94 | FrameTooltipNode toolTip = (FrameTooltipNode)targetNode; 95 | toolTip.updateLocation((AbstractGraph)graphController.getGraph(), toolTip.getParent()); 96 | } 97 | } 98 | }; 99 | 100 | ((DefaultGraphNode)node).addChangeListener(changeListener); 101 | changeListenerMap.put(toolTip, changeListener); 102 | } 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/org/protege/ontograf/actions/OpenGraphAction.java: -------------------------------------------------------------------------------- 1 | package org.protege.ontograf.actions; 2 | 3 | import java.awt.Component; 4 | import java.io.File; 5 | import java.io.FileNotFoundException; 6 | import java.util.Scanner; 7 | import java.util.Set; 8 | 9 | import javax.swing.Action; 10 | import javax.swing.JFileChooser; 11 | import javax.swing.JOptionPane; 12 | 13 | import org.protege.editor.owl.model.OWLModelManager; 14 | import org.protege.ontograf.common.GraphController; 15 | import org.protege.ontograf.common.ProtegeGraphModel; 16 | import org.protege.ontograf.common.util.IconConstants; 17 | import org.protege.ontograf.ui.OntoGrafFileFilter; 18 | import org.semanticweb.owlapi.model.IRI; 19 | import org.semanticweb.owlapi.model.OWLEntity; 20 | 21 | import ca.uvic.cs.chisel.cajun.actions.CajunAction; 22 | import ca.uvic.cs.chisel.cajun.graph.FlatGraph; 23 | import ca.uvic.cs.chisel.cajun.graph.node.GraphNode; 24 | 25 | public class OpenGraphAction extends CajunAction { 26 | private static final long serialVersionUID = 7241297162054742885L; 27 | 28 | private static final String ACTION_NAME = "Open Saved Graph"; 29 | 30 | private JFileChooser fileChooser; 31 | 32 | private Component parent; 33 | private GraphController controller; 34 | 35 | public OpenGraphAction(Component parent, GraphController controller) { 36 | super(ACTION_NAME, IconConstants.ICON_OPEN_GRAPH); 37 | 38 | putValue(Action.SHORT_DESCRIPTION, ACTION_NAME); 39 | 40 | this.parent = parent; 41 | this.controller = controller; 42 | 43 | fileChooser = new JFileChooser(); 44 | fileChooser.setDialogTitle("Open graph configuration file"); 45 | fileChooser.addChoosableFileFilter(new OntoGrafFileFilter(new String[] { "graph" }, "OntoGraf File")); 46 | } 47 | 48 | @Override 49 | public void doAction() { 50 | int result = fileChooser.showOpenDialog(parent); 51 | 52 | if(result == JFileChooser.CANCEL_OPTION) return; 53 | 54 | File file = fileChooser.getSelectedFile(); 55 | loadFromFile(file); 56 | } 57 | 58 | public void loadFromFile(File file) { 59 | controller.clear(); 60 | 61 | ProtegeGraphModel model = controller.getModel(); 62 | FlatGraph graph = (FlatGraph)controller.getGraph(); 63 | OWLModelManager owlModelManager = controller.getModel().getOwlModelManager(); 64 | boolean found = true; 65 | 66 | try (Scanner scanner = new Scanner(file)) { 67 | 68 | // make sure the stored graph is for the active ontology 69 | if(scanner.hasNextLine()) { 70 | String ontologyUri = scanner.nextLine(); 71 | String activeOntologyUri = owlModelManager.getActiveOntology().getOntologyID().getOntologyIRI().toString(); 72 | 73 | if(!ontologyUri.equals(activeOntologyUri)) { 74 | JOptionPane.showMessageDialog(parent, "Sorry, but the graph description does not correspond to your active ontology."); 75 | return; 76 | } 77 | } 78 | 79 | // attempt to read the csv file and display the elements 80 | while(scanner.hasNextLine()) { 81 | String line = scanner.nextLine(); 82 | String items[] = line.split(","); 83 | if(items.length == 3) { 84 | String uri = items[0]; 85 | double x = Double.parseDouble(items[1]); 86 | double y = Double.parseDouble(items[2]); 87 | 88 | Set entities = owlModelManager.getOWLEntityFinder().getEntities(IRI.create(uri)); 89 | if(entities != null && entities.size() > 0) { 90 | for(OWLEntity owlEntity : entities) { 91 | model.show(owlEntity, graph.getFilterManager()); 92 | 93 | GraphNode node = model.getNode(owlEntity); 94 | node.setLocation(x, y); 95 | } 96 | } 97 | else { 98 | found = false; 99 | } 100 | } 101 | } 102 | } catch (FileNotFoundException e) { 103 | e.printStackTrace(); 104 | } 105 | 106 | if(!found) { 107 | JOptionPane.showMessageDialog(parent, "Some of the graph entities in the file could not be found within your currenlty loaded ontology.\nPlease make sure this saved graph corresponds to your active ontology."); 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/main/java/org/protege/ontograf/OntoGrafImportView.java: -------------------------------------------------------------------------------- 1 | package org.protege.ontograf; 2 | 3 | import java.awt.BorderLayout; 4 | import java.awt.Dimension; 5 | import java.awt.event.ComponentAdapter; 6 | import java.awt.event.ComponentEvent; 7 | import java.util.ArrayList; 8 | import java.util.Collection; 9 | 10 | import javax.swing.Icon; 11 | 12 | import org.eclipse.zest.layouts.algorithms.HorizontalDirectedGraphLayoutAlgorithm; 13 | import org.protege.editor.owl.OWLEditorKit; 14 | import org.protege.editor.owl.model.OWLModelManager; 15 | import org.protege.editor.owl.ui.view.cls.AbstractOWLClassViewComponent; 16 | import org.protege.ontograf.common.util.OWLIconProviderImpl; 17 | import org.semanticweb.owlapi.model.OWLClass; 18 | import org.semanticweb.owlapi.model.OWLOntology; 19 | 20 | import ca.uvic.cs.chisel.cajun.actions.LayoutAction; 21 | import ca.uvic.cs.chisel.cajun.constants.LayoutConstants; 22 | import ca.uvic.cs.chisel.cajun.graph.DefaultGraphModel; 23 | import ca.uvic.cs.chisel.cajun.graph.FlatGraph; 24 | import ca.uvic.cs.chisel.cajun.graph.arc.DefaultGraphArc; 25 | import ca.uvic.cs.chisel.cajun.graph.arc.GraphArc; 26 | import ca.uvic.cs.chisel.cajun.graph.node.GraphNode; 27 | import ca.uvic.cs.chisel.cajun.graph.ui.DefaultFlatGraphView; 28 | 29 | /** 30 | * Plugin extension point for the OntoGraf imports view. 31 | * 32 | * @author seanf 33 | */ 34 | public class OntoGrafImportView extends AbstractOWLClassViewComponent { 35 | private static final long serialVersionUID = -6969495880634875570L; 36 | 37 | /** the graph object, performs layouts and renders the model */ 38 | private FlatGraph graph; 39 | 40 | private ImportsGraphModel model; 41 | 42 | /** the panel that renders the graph view */ 43 | private DefaultFlatGraphView view; 44 | 45 | @Override 46 | public void initialiseClassView() throws Exception { 47 | setLayout(new BorderLayout()); 48 | 49 | this.addComponentListener(new ComponentAdapter() { 50 | @Override 51 | public void componentResized(ComponentEvent e) { 52 | // TODO Auto-generated method stub 53 | super.componentResized(e); 54 | 55 | } 56 | }); 57 | 58 | this.model = new ImportsGraphModel(this.getOWLEditorKit()); 59 | this.graph = new FlatGraph(model); 60 | this.view = new DefaultFlatGraphView(graph); 61 | 62 | this.add(this.view, BorderLayout.CENTER); 63 | 64 | Dimension d = new Dimension(800, 600); 65 | setPreferredSize(d); 66 | setSize(d); 67 | setLocation(100, 50); 68 | 69 | setVisible(true); 70 | 71 | for (LayoutAction layoutAction : graph.getLayouts()) { 72 | if (layoutAction.getName().equals(LayoutConstants.LAYOUT_SPRING)) { 73 | layoutAction.setLayout(new HorizontalDirectedGraphLayoutAlgorithm()); 74 | this.graph.setLastLayout(layoutAction); 75 | } 76 | } 77 | 78 | this.graph.performLayout(); 79 | } 80 | 81 | @Override 82 | protected OWLClass updateView(OWLClass owlClass) { 83 | return null; 84 | } 85 | 86 | @Override 87 | public void disposeView() { 88 | // TODO Auto-generated method stub 89 | 90 | } 91 | } 92 | 93 | class ImportsGraphModel extends DefaultGraphModel { 94 | private static final String IMPORTS = "imports"; 95 | private static final String ONTOLOGY = "ontology"; 96 | 97 | private OWLEditorKit owlEditorKit; 98 | 99 | public ImportsGraphModel(OWLEditorKit owlEditorKit) { 100 | super(); 101 | 102 | this.owlEditorKit = owlEditorKit; 103 | 104 | loadData(owlEditorKit.getOWLWorkspace().getOWLModelManager().getActiveOntology()); 105 | } 106 | 107 | private void loadData(OWLOntology owlOntology) { 108 | GraphNode parentNode = addNode(owlEditorKit.getOWLWorkspace().getOWLModelManager().getRendering(owlOntology)); 109 | 110 | for(OWLOntology importedOntology : owlOntology.getDirectImports()) { 111 | GraphNode childNode = addNode(owlEditorKit.getOWLWorkspace().getOWLModelManager().getRendering(importedOntology)); 112 | addArc(parentNode, childNode); 113 | 114 | loadData(importedOntology); 115 | } 116 | } 117 | 118 | private GraphNode addNode(String name) { 119 | OWLModelManager modelManager = owlEditorKit.getOWLWorkspace().getOWLModelManager(); 120 | OWLIconProviderImpl iconProvider = new OWLIconProviderImpl(modelManager); 121 | Icon icon = iconProvider.getIcon(modelManager.getActiveOntology()); 122 | return addNode(name, name, icon, ONTOLOGY); 123 | } 124 | 125 | public Collection getNodeTypes() { 126 | ArrayList types = new ArrayList(2); 127 | types.add(ONTOLOGY); 128 | 129 | return types; 130 | } 131 | 132 | private GraphArc addArc(GraphNode src, GraphNode dest) { 133 | String arcId = src.getText() + "->" + dest.getText(); 134 | 135 | DefaultGraphArc arc = (DefaultGraphArc) addArc(arcId, src, dest, IMPORTS); 136 | 137 | arc.setInverted(false); 138 | return arc; 139 | } 140 | 141 | public Collection getArcTypes() { 142 | ArrayList types = new ArrayList(3); 143 | types.add(IMPORTS); 144 | 145 | return types; 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/org/protege/ontograf/ui/TooltipConfigurationDialog.java: -------------------------------------------------------------------------------- 1 | package org.protege.ontograf.ui; 2 | 3 | import java.awt.BorderLayout; 4 | import java.awt.Color; 5 | import java.awt.GridLayout; 6 | import java.awt.event.ActionEvent; 7 | import java.awt.event.ActionListener; 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | import java.util.TreeSet; 11 | 12 | import javax.swing.BorderFactory; 13 | import javax.swing.JButton; 14 | import javax.swing.JDialog; 15 | import javax.swing.JPanel; 16 | import javax.swing.JScrollPane; 17 | import javax.swing.JSplitPane; 18 | import javax.swing.border.TitledBorder; 19 | 20 | import org.protege.ontograf.common.util.NodeOWLClassTooltipType; 21 | import org.protege.ontograf.common.util.NodeOWLIndividualTooltipType; 22 | 23 | import ca.uvic.cs.chisel.cajun.graph.ui.FilterCheckBox; 24 | 25 | public class TooltipConfigurationDialog extends JDialog { 26 | private static final long serialVersionUID = -5081919405096749260L; 27 | 28 | private Map owlClassTooltipTypes; 29 | private Map owlIndividualTooltipTypes; 30 | 31 | public TooltipConfigurationDialog() { 32 | setSize(600, 300); 33 | 34 | owlClassTooltipTypes = new HashMap(); 35 | for(NodeOWLClassTooltipType tooltipType : NodeOWLClassTooltipType.values()) { 36 | owlClassTooltipTypes.put(tooltipType.toString(), tooltipType.isEnabled()); 37 | } 38 | 39 | owlIndividualTooltipTypes = new HashMap(); 40 | for(NodeOWLIndividualTooltipType tooltipType : NodeOWLIndividualTooltipType.values()) { 41 | owlIndividualTooltipTypes.put(tooltipType.toString(), tooltipType.isEnabled()); 42 | } 43 | 44 | init(); 45 | } 46 | 47 | private void init() { 48 | setLayout(new BorderLayout()); 49 | setTitle("Node tooltip configuration"); 50 | 51 | JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); 52 | 53 | splitPane.add(getTypeScrollPanel(getTypesPanel("Class Tooltip Options:"), owlClassTooltipTypes)); 54 | splitPane.add(getTypeScrollPanel(getTypesPanel("Individual Tooltip Options:"), owlIndividualTooltipTypes)); 55 | 56 | splitPane.setDividerLocation(300); 57 | 58 | add(splitPane, BorderLayout.CENTER); 59 | add(getButtonPanel(), BorderLayout.SOUTH); 60 | } 61 | 62 | private JScrollPane getTypeScrollPanel(JPanel typesPanel, Map types) { 63 | JPanel holder = new JPanel(new BorderLayout()); 64 | holder.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2)); 65 | holder.add(typesPanel, BorderLayout.NORTH); 66 | holder.setBackground(Color.white); 67 | //add(getHeaderPanel(), BorderLayout.NORTH); 68 | 69 | JScrollPane scroll = new JScrollPane(holder, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); 70 | 71 | loadTypes(typesPanel, types); 72 | 73 | return scroll; 74 | } 75 | 76 | private JPanel getButtonPanel() { 77 | JPanel panel = new JPanel(new BorderLayout()); 78 | JButton closeButton = new JButton("Close"); 79 | closeButton.addActionListener(new ActionListener() { 80 | public void actionPerformed(ActionEvent e) { 81 | TooltipConfigurationDialog.this.setVisible(false); 82 | } 83 | }); 84 | 85 | JPanel buttonContainerPanel = new JPanel(); 86 | buttonContainerPanel.add(closeButton); 87 | 88 | panel.add(buttonContainerPanel, BorderLayout.EAST); 89 | 90 | return panel; 91 | } 92 | 93 | private void typeVisibilityChanged(Object type, boolean visible) { 94 | for(NodeOWLClassTooltipType tooltipType : NodeOWLClassTooltipType.values()) { 95 | if(tooltipType.toString().equals(type.toString())) { 96 | tooltipType.setEnabled(visible); 97 | break; 98 | } 99 | } 100 | } 101 | 102 | private void typeIndividualVisibilityChanged(Object type, boolean visible) { 103 | for(NodeOWLIndividualTooltipType tooltipType : NodeOWLIndividualTooltipType.values()) { 104 | if(tooltipType.toString().equals(type.toString())) { 105 | tooltipType.setEnabled(visible); 106 | break; 107 | } 108 | } 109 | } 110 | 111 | public void loadTypes(final JPanel panel, Map items) { 112 | panel.removeAll(); 113 | if (items.size() > 0) { 114 | // sort the types alphabetically 115 | TreeSet sortedTypes = new TreeSet(); 116 | sortedTypes.addAll(items.keySet()); 117 | for (Object type : sortedTypes) { 118 | boolean selected = items.get(type); 119 | FilterCheckBox checkbox = new FilterCheckBox(type, null, selected){ 120 | private static final long serialVersionUID = -861175558062891232L; 121 | 122 | public void typeVisibilityChanged(Object type, boolean visible) { 123 | String title = ((TitledBorder)panel.getBorder()).getTitle(); 124 | if(title.equals("Class Tooltip Options:")) { 125 | TooltipConfigurationDialog.this.typeVisibilityChanged(type, visible); 126 | } 127 | else { 128 | typeIndividualVisibilityChanged(type, visible); 129 | } 130 | } 131 | }; 132 | 133 | panel.add(checkbox); 134 | } 135 | } 136 | this.invalidate(); 137 | this.validate(); 138 | this.repaint(); 139 | } 140 | 141 | private JPanel getTypesPanel(String title) { 142 | //if (typesPanel == null) { 143 | 144 | JPanel typesPanel = new JPanel(new GridLayout(0, 1, 0, 1)); 145 | typesPanel.setBorder(BorderFactory.createTitledBorder(title)); 146 | typesPanel.setOpaque(false); 147 | //} 148 | return typesPanel; 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/main/java/org/protege/ontograf/ui/OntoGrafFileFilter.java: -------------------------------------------------------------------------------- 1 | package org.protege.ontograf.ui; 2 | 3 | import java.io.File; 4 | import java.util.Enumeration; 5 | import java.util.Hashtable; 6 | 7 | import javax.swing.filechooser.FileFilter; 8 | 9 | /** 10 | * This class was copied and slightly modified from the Shrimp code base from UVic. 11 | * 12 | * A convenience implementation of FileFilter that filters out 13 | * all files except for those type extensions that it knows about. 14 | * 15 | * Example - create a new filter that filters out all files 16 | * but gif and jpg image files: 17 | * 18 | * JFileChooser chooser = new JFileChooser(); 19 | * ShrimpFileFilter filter = new ShrimpFileFilter( 20 | * new String{"gif", "jpg"}, "JPEG and GIF Images") 21 | * chooser.addChoosableFileFilter(filter); 22 | * chooser.showOpenDialog(this); 23 | * 24 | * @version 1.8 08/26/98 25 | * @author Jeff Dinkins 26 | */ 27 | public class OntoGrafFileFilter extends FileFilter implements java.io.FileFilter { 28 | private Hashtable filters = null; 29 | private String description = null; 30 | private String fullDescription = null; 31 | private boolean useExtensionsInDescription = true; 32 | 33 | /** 34 | * Creates a file filter. If no filters are added, then all 35 | * files are accepted. 36 | * 37 | * @see #addExtension 38 | */ 39 | public OntoGrafFileFilter() { 40 | this.filters = new Hashtable(); 41 | } 42 | 43 | /** 44 | * Creates a file filter that accepts files with the given extension. 45 | * Example: new ShrimpFileFilter("jpg"); 46 | * 47 | * @see #addExtension 48 | */ 49 | public OntoGrafFileFilter(String extension) { 50 | this(extension, null); 51 | } 52 | 53 | /** 54 | * Creates a file filter that accepts the given file type. 55 | * Example: new ShrimpFileFilter("jpg", "JPEG Image Images"); 56 | * 57 | * Note that the "." before the extension is not needed. If 58 | * provided, it will be ignored. 59 | * 60 | * @see #addExtension 61 | */ 62 | public OntoGrafFileFilter(String extension, String description) { 63 | this(); 64 | if (extension != null) 65 | addExtension(extension); 66 | if (description != null) 67 | setDescription(description); 68 | } 69 | 70 | /** 71 | * Creates a file filter from the given string array. 72 | * Example: new ShrimpFileFilter(String {"gif", "jpg"}); 73 | * 74 | * Note that the "." before the extension is not needed adn 75 | * will be ignored. 76 | * 77 | * @see #addExtension 78 | */ 79 | public OntoGrafFileFilter(String[] filters) { 80 | this(filters, null); 81 | } 82 | 83 | /** 84 | * Creates a file filter from the given string array and description. 85 | * Example: new ShrimpFileFilter(String {"gif", "jpg"}, "Gif and JPG Images"); 86 | * 87 | * Note that the "." before the extension is not needed and will be ignored. 88 | * 89 | * @see #addExtension 90 | */ 91 | public OntoGrafFileFilter(String[] filters, String description) { 92 | this(); 93 | for (int i = 0; i < filters.length; i++) { 94 | // add filters one by one 95 | addExtension(filters[i]); 96 | } 97 | if (description != null) 98 | setDescription(description); 99 | } 100 | 101 | /** 102 | * Return true if this file should be shown in the directory pane, 103 | * false if it shouldn't. 104 | * 105 | * Files that begin with "." are ignored. 106 | * 107 | * @see #getExtension 108 | */ 109 | public boolean accept(File f) { 110 | if (f != null) { 111 | if (f.isDirectory()) { 112 | return true; 113 | } 114 | String extension = getExtension(f); 115 | if (extension != null && filters.get(getExtension(f)) != null) { 116 | return true; 117 | } 118 | } 119 | return false; 120 | } 121 | 122 | /** 123 | * Return the extension portion of the file's name . 124 | * 125 | * @see #getExtension 126 | * @see FileFilter#accept 127 | */ 128 | public String getExtension(File f) { 129 | if (f != null) { 130 | String filename = f.getName(); 131 | int i = filename.lastIndexOf('.'); 132 | if (i > 0 && i < filename.length() - 1) { 133 | return filename.substring(i + 1).toLowerCase(); 134 | } 135 | } 136 | return null; 137 | } 138 | 139 | /** 140 | * Adds a filetype "dot" extension to filter against. 141 | * 142 | * For example: the following code will create a filter that filters 143 | * out all files except those that end in ".jpg" and ".tif": 144 | * 145 | * ShrimpFileFilter filter = new ShrimpFileFilter(); 146 | * filter.addExtension("jpg"); 147 | * filter.addExtension("tif"); 148 | * 149 | * Note that the "." before the extension is not needed and will be ignored. 150 | */ 151 | public void addExtension(String extension) { 152 | if (filters == null) { 153 | filters = new Hashtable(5); 154 | } 155 | filters.put(extension.toLowerCase(), this); 156 | fullDescription = null; 157 | } 158 | 159 | /** 160 | * Returns the human readable description of this filter. For 161 | * example: "JPEG and GIF Image Files (*.jpg, *.gif)" 162 | * 163 | * @see #setDescription 164 | * @see #setExtensionListInDescription 165 | * @see #isExtensionListInDescription 166 | * @see FileFilter#getDescription 167 | */ 168 | public String getDescription() { 169 | if (fullDescription == null) { 170 | if (description == null || isExtensionListInDescription()) { 171 | fullDescription = description == null ? "(" : description + " ("; 172 | // build the description from the extension list 173 | Enumeration extensions = filters.keys(); 174 | if (extensions != null) { 175 | fullDescription += "." + (String) extensions.nextElement(); 176 | while (extensions.hasMoreElements()) { 177 | fullDescription += ", ." + extensions.nextElement(); 178 | } 179 | } 180 | fullDescription += ")"; 181 | } else { 182 | fullDescription = description; 183 | } 184 | } 185 | return fullDescription; 186 | } 187 | 188 | /** 189 | * Sets the human readable description of this filter. For 190 | * example: filter.setDescription("Gif and JPG Images"); 191 | * 192 | * @see #setDescription 193 | * @see #setExtensionListInDescription 194 | * @see #isExtensionListInDescription 195 | */ 196 | public void setDescription(String description) { 197 | this.description = description; 198 | fullDescription = null; 199 | } 200 | 201 | /** 202 | * Determines whether the extension list (.jpg, .gif, etc) should 203 | * show up in the human readable description. 204 | * 205 | * Only relevent if a description was provided in the constructor 206 | * or using setDescription(); 207 | * 208 | * @see #getDescription 209 | * @see #setDescription 210 | * @see #isExtensionListInDescription 211 | */ 212 | public void setExtensionListInDescription(boolean b) { 213 | useExtensionsInDescription = b; 214 | fullDescription = null; 215 | } 216 | 217 | /** 218 | * Returns whether the extension list (.jpg, .gif, etc) should 219 | * show up in the human readable description. 220 | * 221 | * Only relevent if a description was provided in the constructor 222 | * or using setDescription(); 223 | * 224 | * @see #getDescription 225 | * @see #setDescription 226 | * @see #setExtensionListInDescription 227 | */ 228 | public boolean isExtensionListInDescription() { 229 | return useExtensionsInDescription; 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /src/main/java/org/protege/ontograf/OntoGrafView.java: -------------------------------------------------------------------------------- 1 | package org.protege.ontograf; 2 | 3 | import java.awt.BorderLayout; 4 | import java.awt.Color; 5 | import java.awt.Cursor; 6 | import java.awt.Dimension; 7 | import java.awt.Font; 8 | import java.awt.event.ActionEvent; 9 | import java.awt.event.ActionListener; 10 | import java.awt.event.ComponentAdapter; 11 | import java.awt.event.ComponentEvent; 12 | import java.awt.event.KeyEvent; 13 | import java.awt.event.KeyListener; 14 | 15 | import javax.swing.Action; 16 | import javax.swing.JButton; 17 | import javax.swing.JComboBox; 18 | import javax.swing.JFrame; 19 | import javax.swing.JLabel; 20 | import javax.swing.JOptionPane; 21 | import javax.swing.JPanel; 22 | import javax.swing.JTextField; 23 | import javax.swing.JToggleButton; 24 | import javax.swing.JToolBar; 25 | import javax.swing.SwingUtilities; 26 | 27 | import org.protege.editor.owl.ui.view.cls.AbstractOWLClassViewComponent; 28 | import org.protege.ontograf.actions.ConfigTooltipsAction; 29 | import org.protege.ontograf.actions.ExportAsDotAction; 30 | import org.protege.ontograf.actions.ExportImageAction; 31 | import org.protege.ontograf.actions.OpenGraphAction; 32 | import org.protege.ontograf.actions.PinTooltipsAction; 33 | import org.protege.ontograf.actions.SaveGraphAction; 34 | import org.protege.ontograf.common.GraphController; 35 | import org.semanticweb.owlapi.model.OWLClass; 36 | import org.semanticweb.owlapi.model.OWLEntity; 37 | 38 | import ca.uvic.cs.chisel.cajun.graph.AbstractGraph; 39 | import ca.uvic.cs.chisel.cajun.graph.node.GraphNode; 40 | import ca.uvic.cs.chisel.cajun.graph.node.GraphNodeCollectionEvent; 41 | import ca.uvic.cs.chisel.cajun.graph.node.GraphNodeCollectionListener; 42 | import ca.uvic.cs.chisel.cajun.util.GradientPainter; 43 | import ca.uvic.cs.chisel.cajun.util.GradientPanel; 44 | 45 | /** 46 | * Plugin extension point for the OntoGraf view. 47 | * 48 | * @author seanf 49 | */ 50 | public class OntoGrafView extends AbstractOWLClassViewComponent { 51 | private static final long serialVersionUID = -6969495880634875570L; 52 | 53 | private static final Color BACKGROUND_COLOR = new Color(0, 46, 123); 54 | 55 | // search modes available 56 | private static final String[] MODES = { GraphController.CONTAINS, GraphController.STARTS_WITH, GraphController.ENDS_WITH, GraphController.EXACT_MATCH, GraphController.REGEXP }; 57 | 58 | // reference to the graph controller object, gives access to graph model and graph functions 59 | private GraphController graphController; 60 | 61 | // search related UI controls 62 | private JComboBox searchTypeBox; 63 | private JTextField searchField; 64 | private JLabel searchResults; 65 | 66 | // flag for cancelling updateView call, this is for managing synchronization between 67 | // the graph and the class tree 68 | private boolean cancelSelectionUpdate; 69 | 70 | private JPanel getSearchPanel() { 71 | JPanel searchPanel = new GradientPanel(GradientPanel.BG_START, BACKGROUND_COLOR.darker(), GradientPainter.TOP_TO_BOTTOM); 72 | 73 | JLabel searchLabel = new JLabel("Search:"); 74 | searchLabel.setFont(searchLabel.getFont().deriveFont(Font.BOLD)); 75 | searchLabel.setForeground(Color.white); 76 | 77 | searchField = new JTextField(); 78 | searchField.setMinimumSize(new Dimension(300, 22)); 79 | searchField.setSize(new Dimension(300, 22)); 80 | searchField.setPreferredSize(new Dimension(300, 22)); 81 | searchField.setFocusable(true); 82 | searchField.requestFocus(); 83 | 84 | searchTypeBox = new JComboBox(MODES); 85 | 86 | JButton searchButton = new JButton("Search"); 87 | searchButton.addActionListener(new ActionListener() { 88 | public void actionPerformed(ActionEvent e) { 89 | performSearch(); 90 | } 91 | }); 92 | searchButton.setMinimumSize(new Dimension(80, 22)); 93 | searchButton.setSize(new Dimension(80, 22)); 94 | searchButton.setPreferredSize(new Dimension(80, 22)); 95 | 96 | searchField.addKeyListener(new KeyListener() { 97 | public void keyTyped(KeyEvent e) {} 98 | public void keyPressed(KeyEvent e) {} 99 | 100 | public void keyReleased(KeyEvent e) { 101 | if (e.getKeyCode() == KeyEvent.VK_ENTER) { 102 | performSearch(); 103 | } 104 | } 105 | }); 106 | 107 | JButton clearButton = new JButton("Clear"); 108 | clearButton.addActionListener(new ActionListener() { 109 | public void actionPerformed(ActionEvent e) { 110 | graphController.clear(); 111 | searchResults.setText(""); 112 | } 113 | }); 114 | clearButton.setMinimumSize(new Dimension(80, 22)); 115 | clearButton.setSize(new Dimension(80, 22)); 116 | clearButton.setPreferredSize(new Dimension(80, 22)); 117 | 118 | searchResults = new JLabel(); 119 | searchResults.setFont(searchResults.getFont().deriveFont(Font.BOLD)); 120 | searchResults.setForeground(Color.white); 121 | searchResults.setOpaque(false); 122 | 123 | searchPanel.add(searchLabel); 124 | searchPanel.add(searchField); 125 | searchPanel.add(searchTypeBox); 126 | searchPanel.add(searchButton); 127 | searchPanel.add(clearButton); 128 | searchPanel.add(searchResults); 129 | 130 | return searchPanel; 131 | } 132 | 133 | private void performSearch() { 134 | if (searchField.getText().length() > 0) { 135 | this.setCursor(new Cursor(Cursor.WAIT_CURSOR)); 136 | int numOfResults = graphController.search(searchField.getText(), getSearchMode()); 137 | searchResults.setText(numOfResults + " result(s) found."); 138 | this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); 139 | 140 | syncNodeSelection(); 141 | } else { 142 | JOptionPane.showMessageDialog(this, "You must enter a valid search term", "Invalid search term", JOptionPane.INFORMATION_MESSAGE); 143 | } 144 | } 145 | 146 | /** 147 | * When a node gets selected in the graph, we want to update the global class selection for Protege. 148 | */ 149 | private void syncNodeSelection() { 150 | GraphNode node = ((AbstractGraph)graphController.getGraph()).getFirstSelectedNode(); 151 | if(node != null) { 152 | cancelSelectionUpdate = true; 153 | setGlobalSelection((OWLEntity)node.getUserObject()); 154 | } 155 | } 156 | 157 | private String getSearchMode() { 158 | return MODES[searchTypeBox.getSelectedIndex()]; 159 | } 160 | 161 | @Override 162 | public void initialiseClassView() throws Exception { 163 | setLayout(new BorderLayout()); 164 | 165 | this.addComponentListener(new ComponentAdapter() { 166 | @Override 167 | public void componentResized(ComponentEvent e) { 168 | // TODO Auto-generated method stub 169 | super.componentResized(e); 170 | 171 | } 172 | }); 173 | 174 | graphController = new GraphController(this, this.getOWLEditorKit()); 175 | 176 | graphController.getGraph().addNodeSelectionListener(new GraphNodeCollectionListener() { 177 | public void collectionChanged(GraphNodeCollectionEvent arg0) { 178 | syncNodeSelection(); 179 | } 180 | }); 181 | 182 | add(getSearchPanel(), BorderLayout.NORTH); 183 | 184 | initToolbar(); 185 | 186 | Dimension d = new Dimension(800, 600); 187 | setPreferredSize(d); 188 | setSize(d); 189 | setLocation(100, 50); 190 | 191 | setVisible(true); 192 | } 193 | 194 | private void initToolbar() { 195 | JToolBar toolBar = graphController.getToolBar(); 196 | 197 | JFrame mainWindow = (javax.swing.JFrame)SwingUtilities.windowForComponent(this); 198 | 199 | toolBar.addSeparator(); 200 | toolBar.add(new ExportImageAction(mainWindow, graphController.getGraph().getCanvas())); 201 | toolBar.add(new ConfigTooltipsAction(mainWindow, graphController.getGraph().getCanvas())); 202 | toolBar.addSeparator(); 203 | toolBar.add(new SaveGraphAction(mainWindow, graphController)); 204 | toolBar.add(new OpenGraphAction(mainWindow, graphController)); 205 | toolBar.addSeparator(); 206 | toolBar.add(new ExportAsDotAction(mainWindow, graphController)); 207 | 208 | Action action = new PinTooltipsAction(mainWindow, graphController); 209 | JToggleButton btn = new JToggleButton(action); 210 | btn.setText(null); 211 | btn.setToolTipText((String) action.getValue(Action.NAME)); 212 | 213 | toolBar.add(btn); 214 | } 215 | 216 | @Override 217 | protected OWLClass updateView(OWLClass owlClass) { 218 | if(owlClass != null && !cancelSelectionUpdate) { 219 | graphController.showOWLClass(owlClass); 220 | } 221 | 222 | cancelSelectionUpdate = false; 223 | 224 | return null; 225 | } 226 | 227 | @Override 228 | public void disposeView() { 229 | // TODO Auto-generated method stub 230 | 231 | } 232 | 233 | } 234 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | org.sonatype.oss 7 | oss-parent 8 | 7 9 | 10 | 11 | edu.stanford.protege 12 | ontograf 13 | 2.0.4-SNAPSHOT 14 | bundle 15 | 16 | OntoGraf 17 | A plug-in for the Protege Desktop ontology editor that allows visual, interactive navigation of the relationships in OWL ontologies. 18 | https://github.com/protegeproject/ontograf 19 | 20 | 21 | GNU Lesser General Public License 22 | http://www.gnu.org/copyleft/lesser.html 23 | 24 | 25 | 26 | 27 | 28 | Sean Falconer 29 | falconer.sean@gmail.com 30 | 31 | 32 | 33 | 34 | 35 | 36 | protege-user 37 | https://mailman.stanford.edu/mailman/listinfo/protege-user 38 | https://mailman.stanford.edu/mailman/listinfo/protege-user 39 | protege-user@lists.stanford.edu 40 | http://protege-project.136.n4.nabble.com/ 41 | 42 | https://mailman.stanford.edu/pipermail/protege-user/ 43 | 44 | 45 | 46 | 47 | 48 | protege-dev 49 | https://mailman.stanford.edu/mailman/listinfo/protege-dev 50 | https://mailman.stanford.edu/mailman/listinfo/protege-dev 51 | protege-dev@lists.stanford.edu 52 | http://protege-project.136.n4.nabble.com/ 53 | 54 | https://mailman.stanford.edu/pipermail/protege-dev/ 55 | 56 | 57 | 58 | 59 | 60 | scm:git:git@github.com:protegeproject/ontograf.git 61 | scm:git:git@github.com:protegeproject/ontograf.git 62 | https://github.com/protegeproject/ontograf 63 | HEAD 64 | 65 | 66 | 67 | 68 | edu.stanford.protege 69 | ca.uvic.cs.chisel.cajun 70 | 1.0.2 71 | 72 | 73 | edu.stanford.protege 74 | protege-editor-owl 75 | 5.0.0-RC1 76 | 77 | 78 | 79 | 80 | 81 | 82 | org.apache.maven.plugins 83 | maven-compiler-plugin 84 | 3.3 85 | 86 | 1.8 87 | 1.8 88 | 89 | 90 | 91 | org.apache.felix 92 | maven-bundle-plugin 93 | 2.5.3 94 | true 95 | 96 | 97 | org.protege.editor.owl.ProtegeOWL 98 | . 99 | org.protege.ontograf;singleton:=true 100 | The Protege Development Team 101 | 102 | ca.uvic.cs.chisel.cajun 103 | 104 | 105 | com.ibm.icu.*;resolution:=optional, 106 | org.eclipse.swt.*;resolution:=optional, 107 | org.eclipse.jface.*;resolution:=optional, 108 | org.protege.editor.core.*;version="5.0.0", 109 | org.protege.editor.owl.*;version="5.0.0", 110 | * 111 | 112 | plugin.xml, {maven-resources} 113 | 114 | 115 | 116 | bundle-manifest 117 | install 118 | 119 | manifest 120 | 121 | 122 | 123 | 124 | 125 | 126 | maven-eclipse-plugin 127 | 2.9 128 | 129 | true 130 | 131 | 132 | 133 | maven-release-plugin 134 | 2.5 135 | 136 | 137 | org.apache.maven.scm 138 | maven-scm-provider-gitexe 139 | 1.9 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | release 150 | 151 | false 152 | 153 | 154 | 155 | 156 | org.apache.maven.plugins 157 | maven-source-plugin 158 | 2.2.1 159 | 160 | 161 | attach-sources 162 | 163 | jar 164 | 165 | 166 | 167 | 168 | 169 | org.apache.maven.plugins 170 | maven-javadoc-plugin 171 | 2.10.3 172 | 173 | 174 | attach-javadocs 175 | 176 | jar 177 | 178 | 179 | false 180 | true 181 | 182 | 183 | 184 | 185 | 186 | org.apache.maven.plugins 187 | maven-gpg-plugin 188 | 1.6 189 | 190 | 191 | sign-artifacts 192 | verify 193 | 194 | sign 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | -------------------------------------------------------------------------------- /src/main/java/org/protege/ontograf/actions/ExportImageAction.java: -------------------------------------------------------------------------------- 1 | package org.protege.ontograf.actions; 2 | 3 | import java.awt.BorderLayout; 4 | import java.awt.Component; 5 | import java.awt.Dimension; 6 | import java.awt.Graphics; 7 | import java.awt.Point; 8 | import java.awt.Rectangle; 9 | import java.awt.image.BufferedImage; 10 | import java.io.File; 11 | import java.io.IOException; 12 | 13 | import javax.imageio.ImageIO; 14 | import javax.swing.Action; 15 | import javax.swing.JComponent; 16 | import javax.swing.JFileChooser; 17 | import javax.swing.JOptionPane; 18 | import javax.swing.JPanel; 19 | import javax.swing.JViewport; 20 | import javax.swing.filechooser.FileFilter; 21 | 22 | import org.protege.ontograf.common.util.IconConstants; 23 | import org.protege.ontograf.ui.OntoGrafFileFilter; 24 | 25 | import ca.uvic.cs.chisel.cajun.actions.CajunAction; 26 | import edu.umd.cs.piccolo.PCanvas; 27 | 28 | public class ExportImageAction extends CajunAction { 29 | private static final long serialVersionUID = 7241297162054742885L; 30 | 31 | private static final String ACTION_NAME = "Export Graph as Image"; 32 | 33 | private JFileChooser fileChooser; 34 | private Component parent; 35 | private PCanvas canvas; 36 | 37 | // booleans indicating whether the different formats are available 38 | private boolean jpegAvailable; 39 | private boolean pngAvailable; 40 | private boolean gifAvailable; 41 | 42 | // file filters for showing only a given type of file in the file dialog 43 | private OntoGrafFileFilter pngFileFilter; 44 | private OntoGrafFileFilter gifFileFilter; 45 | private OntoGrafFileFilter jpegFileFilter; 46 | 47 | public ExportImageAction(Component parent, PCanvas canvas) { 48 | super(ACTION_NAME, IconConstants.ICON_EXPORT_IMAGE); 49 | 50 | putValue(Action.SHORT_DESCRIPTION, ACTION_NAME); 51 | 52 | this.parent = parent; 53 | this.canvas = canvas; 54 | this.fileChooser = new JFileChooser(); 55 | 56 | String[] formats = ImageIO.getWriterFormatNames(); 57 | String allFormats = ""; 58 | for (int i = 0; i < formats.length; i++) { 59 | String format = formats[i]; 60 | if (!jpegAvailable && (format.toLowerCase().equals("jpeg") || format.toLowerCase().equals("jpg"))) { 61 | jpegAvailable = true; 62 | allFormats += "JPG "; 63 | } else if (!pngAvailable && format.toLowerCase().equals("png")) { 64 | pngAvailable = true; 65 | allFormats += "PNG "; 66 | } else if (!gifAvailable && format.toLowerCase().equals("gif")) { 67 | gifAvailable = true; 68 | allFormats += "GIF"; 69 | } 70 | } 71 | 72 | fileChooser.setDialogTitle("Export to Image File (" + allFormats + ")"); 73 | //File dir = (lastDirectory != null ? lastDirectory : new File(System.getProperty("user.dir"))); 74 | //chooser.setCurrentDirectory(dir); 75 | // chooser.setAcceptAllFileFilterUsed(true); 76 | 77 | if (pngAvailable) { 78 | pngFileFilter = new OntoGrafFileFilter(new String[] { "png" }, "PNG Images"); 79 | fileChooser.addChoosableFileFilter(pngFileFilter); 80 | } 81 | if (gifAvailable) { 82 | gifFileFilter = new OntoGrafFileFilter(new String[] { "gif" }, "GIF Images"); 83 | fileChooser.addChoosableFileFilter(gifFileFilter); 84 | } 85 | if (jpegAvailable) { 86 | jpegFileFilter = new OntoGrafFileFilter(new String[] { "jpg", "jpeg" }, "JPEG Images"); 87 | fileChooser.addChoosableFileFilter(jpegFileFilter); 88 | } 89 | } 90 | 91 | @Override 92 | public void doAction() { 93 | int result = fileChooser.showSaveDialog(parent); 94 | 95 | if(result == JFileChooser.CANCEL_OPTION) return; 96 | 97 | File file = fileChooser.getSelectedFile(); 98 | FileFilter fileFilter = fileChooser.getFileFilter(); 99 | String filePath = file.toString(); 100 | String formatName = ""; 101 | if (jpegFileFilter != null && jpegFileFilter.equals(fileFilter)) { 102 | formatName = "jpg"; 103 | if (!filePath.toLowerCase().endsWith(".jpg") && !filePath.toLowerCase().endsWith(".jpeg")) { 104 | filePath += ".jpg"; 105 | file = new File(filePath); 106 | } 107 | } 108 | if (pngFileFilter != null && pngFileFilter.equals(fileFilter)) { 109 | formatName = "png"; 110 | if (!filePath.toLowerCase().endsWith(".png")) { 111 | filePath += ".png"; 112 | file = new File(filePath); 113 | } 114 | } 115 | if (gifFileFilter != null && gifFileFilter.equals(fileFilter)) { 116 | formatName = "gif"; 117 | if (!filePath.toLowerCase().endsWith(".gif")) { 118 | filePath += ".gif"; 119 | file = new File(filePath); 120 | } 121 | } 122 | 123 | boolean saveImage = false; 124 | if (file.exists()) { 125 | String msg = "The file " + file.toString() + " already exists.\nDo you want to overwrite this existing file?"; 126 | int opt = JOptionPane.showConfirmDialog(parent, msg, 127 | "Export Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); 128 | saveImage = (opt == JOptionPane.YES_OPTION); 129 | } else { 130 | try { 131 | file.createNewFile(); 132 | saveImage = true; 133 | } catch (IOException e) { 134 | e.printStackTrace(); 135 | String msg = "There was a problem creating " + file.toString() + ". The image has not been exported."; 136 | JOptionPane.showMessageDialog(parent, msg, "Export Error", JOptionPane.ERROR_MESSAGE); 137 | } 138 | } 139 | 140 | if (saveImage) { 141 | exportGraphAsImage(file, formatName); 142 | } 143 | } 144 | 145 | private void exportGraphAsImage(File file, String formatName) { 146 | boolean saved = false; 147 | // if the parent is a viewport then save the entire canvas, not just the visible part 148 | if (canvas.getParent() instanceof JViewport) { 149 | saved = saveViewport(file, formatName, canvas, (JViewport)canvas.getParent()); 150 | } else { 151 | // save only the visible region of the canvas 152 | saved = paintComponent(canvas, file, formatName); 153 | } 154 | if (saved) { 155 | JOptionPane.showMessageDialog(parent, 156 | file.toString() + " has been saved successfully."); 157 | } 158 | } 159 | 160 | /** 161 | * Prompts the user to save the entire canvas or just the visible region. 162 | * If the entire canvas is selected then the canvas is removed from the viewport and resized, then 163 | * painted into the image and returned to the viewport. 164 | * 165 | * @return true if the image is saved 166 | */ 167 | private boolean saveViewport(File file, String formatName, PCanvas canvas, JViewport viewport) { 168 | boolean saved = false; 169 | 170 | Dimension fullSize = viewport.getViewSize(); 171 | Point viewPosition = viewport.getViewPosition(); 172 | 173 | // ask the user if they want an image of the whole canvas or just the visible area 174 | // check if the canvas is smaller than the viewport view size 175 | if ((fullSize.width > canvas.getWidth()) || (fullSize.height > canvas.getHeight())) { 176 | String msg = "Do you want to save the visible region of the canvas " + dimToString(canvas.getSize()) + 177 | " or the entire canvas " + dimToString(fullSize) + "?\n" + 178 | "Warning: saving the entire canvas can cause an out of memory error if it is too large."; 179 | String[] options = new String[] { " Just The Visible Region ", 180 | " The Entire Canvas ", " Cancel " }; 181 | int choice = JOptionPane.showOptionDialog(viewport, 182 | msg, "Confirm", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, 183 | null, options, options[0]); 184 | 185 | if (choice == JOptionPane.CANCEL_OPTION) { 186 | // do nothing, false will be returned 187 | } else if (choice == JOptionPane.YES_OPTION) { 188 | // just save the visible region of the canvas 189 | saved = paintComponent(canvas, file, formatName); 190 | } else if (choice == JOptionPane.NO_OPTION) { 191 | // save the entire canvas, need to start in the top left corner 192 | viewport.setViewPosition(new Point(0, 0)); 193 | 194 | JPanel fullPanel = new JPanel(new BorderLayout()); 195 | fullPanel.add(canvas, BorderLayout.CENTER); 196 | Rectangle oldBounds = canvas.getBounds(); 197 | // make this panel use the entire view 198 | fullPanel.setBounds(0, 0, fullSize.width, fullSize.height); 199 | // have to make the canvas use all the size 200 | canvas.setBounds(0, 0, fullSize.width, fullSize.height); 201 | 202 | saved = paintComponent(fullPanel, file, formatName); 203 | 204 | // restore the canvas as the original view with original position and bounds 205 | viewport.setView(canvas); 206 | viewport.setViewPosition(viewPosition); 207 | canvas.setBounds(oldBounds); 208 | } 209 | } else { 210 | // just save the visible region of the canvas 211 | saved = paintComponent(canvas, file, formatName); 212 | } 213 | return saved; 214 | } 215 | 216 | private boolean paintComponent(JComponent comp, File file, String formatName) { 217 | try { 218 | BufferedImage bufferedImage = new BufferedImage(comp.getWidth(), comp.getHeight(), BufferedImage.TYPE_INT_RGB); 219 | Graphics g = bufferedImage.getGraphics(); 220 | comp.paint(g); // paint the canvas to the image 221 | ImageIO.write(bufferedImage, formatName, file); 222 | } catch (Throwable t) { 223 | // sometimes an out of memory error will occur! 224 | JOptionPane.showMessageDialog(parent, 225 | "There was a problem saving " + file.toString() + 226 | ". The image has not been exported.\nReason: " + t.getMessage(), 227 | "Export Error", JOptionPane.ERROR_MESSAGE); 228 | t.printStackTrace(); 229 | return false; 230 | } 231 | return true; 232 | } 233 | 234 | private static String dimToString(Dimension d) { 235 | return "(" + d.width + "x" + d.height + ")"; 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /src/main/java/org/protege/ontograf/common/GraphController.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1998-2007, CHISEL Group, University of Victoria, Victoria, BC, Canada. 3 | * All rights reserved. 4 | */ 5 | package org.protege.ontograf.common; 6 | 7 | import java.awt.BasicStroke; 8 | import java.awt.BorderLayout; 9 | import java.awt.Container; 10 | import java.awt.Stroke; 11 | import java.awt.event.ActionEvent; 12 | import java.util.ArrayList; 13 | import java.util.Collection; 14 | import java.util.HashSet; 15 | import java.util.List; 16 | import java.util.Set; 17 | 18 | import javax.swing.Action; 19 | import javax.swing.Icon; 20 | import javax.swing.JMenu; 21 | import javax.swing.JPopupMenu; 22 | import javax.swing.JToolBar; 23 | import javax.swing.event.PopupMenuEvent; 24 | import javax.swing.event.PopupMenuListener; 25 | 26 | import org.eclipse.zest.layouts.algorithms.DirectedGraphLayoutAlgorithm; 27 | import org.eclipse.zest.layouts.algorithms.HorizontalDirectedGraphLayoutAlgorithm; 28 | import org.eclipse.zest.layouts.progress.ProgressEvent; 29 | import org.eclipse.zest.layouts.progress.ProgressListener; 30 | import org.protege.editor.owl.OWLEditorKit; 31 | import org.protege.ontograf.common.util.IconConstants; 32 | import org.semanticweb.owlapi.model.OWLClass; 33 | import org.semanticweb.owlapi.model.OWLEntity; 34 | 35 | import ca.uvic.cs.chisel.cajun.actions.CajunAction; 36 | import ca.uvic.cs.chisel.cajun.actions.LayoutAction; 37 | import ca.uvic.cs.chisel.cajun.constants.LayoutConstants; 38 | import ca.uvic.cs.chisel.cajun.filter.FilterChangedEvent; 39 | import ca.uvic.cs.chisel.cajun.filter.FilterChangedListener; 40 | import ca.uvic.cs.chisel.cajun.graph.FlatGraph; 41 | import ca.uvic.cs.chisel.cajun.graph.Graph; 42 | import ca.uvic.cs.chisel.cajun.graph.arc.DefaultGraphArcStyle; 43 | import ca.uvic.cs.chisel.cajun.graph.arc.GraphArc; 44 | import ca.uvic.cs.chisel.cajun.graph.node.DefaultGraphNode; 45 | import ca.uvic.cs.chisel.cajun.graph.node.DefaultGraphNodeStyle; 46 | import ca.uvic.cs.chisel.cajun.graph.node.GraphNode; 47 | import ca.uvic.cs.chisel.cajun.graph.ui.DefaultFlatGraphView; 48 | import edu.umd.cs.piccolo.util.PBounds; 49 | 50 | /** 51 | * Controller for the graph and model elements. This controller ties the appropriate graph model 52 | * representation (Protege OWL) to the graph. 53 | * 54 | * @author seanf 55 | */ 56 | public class GraphController { 57 | /** duration to animate the zoom in and zoom out */ 58 | private static final int ANIMATION_DURATION = 700; 59 | 60 | /** the graph object, performs layouts and renders the model */ 61 | private FlatGraph graph; 62 | 63 | /** the model representation of the graph, nodes and edges */ 64 | private ProtegeGraphModel model; 65 | 66 | /** the panel that renders the graph view */ 67 | private DefaultFlatGraphView view; 68 | 69 | private Action expandAction; 70 | private Action collapseAction; 71 | private Set expandBasedOnActions; 72 | public static final String REGEXP = "regexp"; 73 | public static final String EXACT_MATCH = "exact match"; 74 | public static final String ENDS_WITH = "ends with"; 75 | public static final String STARTS_WITH = "starts with"; 76 | public static final String CONTAINS = "contains"; 77 | 78 | private OWLEntity owlClass; 79 | 80 | public GraphController(Container parentContainer, OWLEditorKit owlEditorKit) { 81 | model = new ProtegeGraphModel(owlEditorKit); 82 | 83 | this.graph = new FlatGraph(model); 84 | this.graph.setShowNodeTooltips(false); 85 | 86 | // show the plus icon for expandable nodes 87 | DefaultGraphNodeStyle nodeStyle = new DefaultGraphNodeStyle() { 88 | public Collection getOverlayIcons(GraphNode graphNode) { 89 | if (model.isExpandable(graphNode) && !model.isExpanded(graphNode)) { 90 | Collection icons = new ArrayList(); 91 | icons.add(IconConstants.ICON_PLUS); 92 | 93 | return icons; 94 | } 95 | 96 | return null; 97 | } 98 | }; 99 | nodeStyle.setNodeTypes(model.getNodeTypes()); 100 | this.graph.setGraphNodeStyle(nodeStyle); 101 | 102 | // color the arcs based on arc type 103 | DefaultGraphArcStyle arcStyle = new DefaultGraphArcStyle() { 104 | public Stroke getStroke(GraphArc arc) { 105 | if (arc.getType().toString().contains(ProtegeGraphModel.DIRECT_SUBCLASS_SLOT_TYPE) || arc.getType().toString().contains(ProtegeGraphModel.DIRECT_INDIVIDUAL_SLOT_TYPE)) { 106 | setDashed(false); 107 | } else { 108 | setDashed(true); 109 | if (arc.getType().toString().contains("Equivalent")) { 110 | setDashedCapSquare(BasicStroke.CAP_ROUND); 111 | setDashWidth(2f); 112 | } 113 | else { 114 | setDashedCapSquare(BasicStroke.CAP_SQUARE); 115 | setDashWidth(10f); 116 | } 117 | } 118 | 119 | return super.getStroke(arc); 120 | } 121 | }; 122 | arcStyle.setArcTypes(model.getArcTypes()); 123 | this.graph.setGraphArcStyle(arcStyle); 124 | 125 | initialize(parentContainer); 126 | 127 | this.graph.addLayoutListener(new ProgressListener() { 128 | public void progressEnded(ProgressEvent arg0) { 129 | // make sure the node is visible 130 | DefaultGraphNode node = (DefaultGraphNode)model.getNode(owlClass); 131 | panTo(node); 132 | } 133 | 134 | public void progressStarted(ProgressEvent arg0) {} 135 | public void progressUpdated(ProgressEvent arg0) {} 136 | }); 137 | 138 | this.graph.getFilterManager().addFilterChangedListener(new FilterChangedListener() { 139 | public void filtersChanged(FilterChangedEvent fce) { 140 | // have to update the relationship counts when a filter is applied 141 | model.resetNodeToArcCount(); 142 | } 143 | }); 144 | } 145 | 146 | public ProtegeGraphModel getModel() { 147 | return model; 148 | } 149 | 150 | public Graph getGraph() { 151 | return graph; 152 | } 153 | 154 | public void refresh() { 155 | graph.repaint(); 156 | } 157 | 158 | public void clear() { 159 | graph.clear(); 160 | model.clear(); 161 | model.restrictToArcType = ""; 162 | } 163 | 164 | public void display(OWLClass cls) { 165 | model.showNeighborhood(cls, true); 166 | graph.performLayout(); 167 | } 168 | 169 | public void displayAsSingleNode(OWLEntity entity) { 170 | model.show(entity, graph.getFilterManager()); 171 | graph.performLayout(); 172 | } 173 | 174 | public JToolBar getToolBar() { 175 | return view.getToolBar(); 176 | } 177 | 178 | /** 179 | * Performs a search on the ontology with the given string. 180 | * 181 | * @param searchString The entered string to search on 182 | * @param searchMode The search type mode that determines how to match the searchString 183 | */ 184 | public int search(String searchString, String searchMode) { 185 | searchString = prepareSearchString(searchString, searchMode); 186 | 187 | for(GraphNode node : model.getAllNodes()) node.setSelected(false); 188 | 189 | Collection matchingNodes = new ArrayList(); 190 | Collection searchResults = model.search(searchString, graph.getFilterManager()); 191 | for (OWLEntity owlEntity : searchResults) { 192 | GraphNode node = model.getNode(owlEntity); 193 | if(node != null) { 194 | matchingNodes.add(model.getNode(owlEntity)); 195 | } 196 | } 197 | 198 | graph.setSelectedNodes(matchingNodes); 199 | graph.setMatchingNodes(matchingNodes); 200 | graph.performLayout(); 201 | 202 | //model.recalculateArcTypes(); 203 | 204 | return searchResults.size(); 205 | } 206 | 207 | /** 208 | * Shows the class as a node and any arcs that exist between this new node and the 209 | * existing nodes on the canvas. 210 | * 211 | * @param owlClass 212 | */ 213 | public void showOWLClass(OWLClass owlClass) { 214 | // set all the current nodes to a fixed location 215 | for(GraphNode node : model.getAllNodes()) { 216 | node.setFixedLocation(true); 217 | } 218 | 219 | boolean panToNode = true; 220 | if(model.getNode(owlClass) == null) { 221 | panToNode = false; 222 | } 223 | 224 | model.restrictToArcType = ""; 225 | model.show(owlClass, graph.getFilterManager()); 226 | 227 | Collection matchingNodes = new ArrayList(); 228 | matchingNodes.add(model.getNode(owlClass)); 229 | 230 | graph.setMatchingNodes(matchingNodes); 231 | graph.performLayout(); 232 | 233 | // unset the fixed location on all nodes 234 | for(GraphNode node : model.getAllNodes()) { 235 | node.setFixedLocation(false); 236 | } 237 | 238 | this.owlClass = owlClass; 239 | 240 | if(panToNode) { 241 | // make sure the node is visible 242 | DefaultGraphNode node = (DefaultGraphNode)model.getNode(owlClass); 243 | panTo(node); 244 | } 245 | } 246 | 247 | private void panTo(DefaultGraphNode node) { 248 | if(node != null) { 249 | double x = node.getFullBoundsReference().getX(); 250 | double y = node.getFullBoundsReference().getY(); 251 | double w = node.getFullBoundsReference().getWidth(); 252 | double h = node.getFullBoundsReference().getHeight(); 253 | PBounds bounds = new PBounds(x - w * .01, y - h * .02, w + w * .02, h + h * .04); 254 | // only pan to the bounds if the node is not already visible 255 | if(!graph.getCamera().getViewBounds().contains(bounds.getBounds2D())) { 256 | graph.getRoot().getActivityScheduler().addActivity( 257 | graph.getCamera().animateViewToCenterBounds(bounds.getBounds2D(), false, ANIMATION_DURATION) 258 | ); 259 | } 260 | } 261 | } 262 | 263 | /** 264 | * Adds appropriate query parameters to the searchString based on the selected searchMode. 265 | */ 266 | private String prepareSearchString(String searchString, String searchMode) { 267 | if (searchMode.equals(CONTAINS)) { 268 | return searchString; 269 | } else if (searchMode.equals(STARTS_WITH)) { 270 | return "^" + searchString; 271 | } else if (searchMode.equals(ENDS_WITH)) { 272 | return searchString + "$"; 273 | } else if(searchMode.equals(EXACT_MATCH)) { 274 | return "^" + searchString + "$"; 275 | } 276 | 277 | return searchString; 278 | } 279 | 280 | private void initialize(Container parentContainer) { 281 | // setup the layouts 282 | List layoutRelTypes = new ArrayList(); 283 | layoutRelTypes.add(ProtegeGraphModel.DIRECT_SUBCLASS_SLOT_TYPE); 284 | layoutRelTypes.add(ProtegeGraphModel.DIRECT_INDIVIDUAL_SLOT_TYPE); 285 | for (LayoutAction layoutAction : graph.getLayouts()) { 286 | if (layoutAction.getName().equals(LayoutConstants.LAYOUT_TREE_HORIZONTAL)) { 287 | layoutAction.setLayout(new HorizontalDirectedGraphLayoutAlgorithm()); 288 | this.graph.setLastLayout(layoutAction); 289 | layoutAction.setLayoutRelTypes(layoutRelTypes); 290 | } else if (layoutAction.getName().equals(LayoutConstants.LAYOUT_TREE_VERTICAL)) { 291 | layoutAction.setLayout(new DirectedGraphLayoutAlgorithm()); 292 | layoutAction.setLayoutRelTypes(layoutRelTypes); 293 | } 294 | } 295 | 296 | view = new DefaultFlatGraphView(graph); 297 | 298 | parentContainer.add(view, BorderLayout.CENTER); 299 | 300 | initNodeMenu(graph.getNodeContextMenu()); 301 | graph.addInputEventListener(new ProtegeInputEventHandler(model, graph)); 302 | } 303 | 304 | /** 305 | * Initializes the menu for the right-click operation on a graph node. 306 | * 307 | * @param graphMenu 308 | */ 309 | private void initNodeMenu(JPopupMenu graphMenu) { 310 | graphMenu.add(new CajunAction("Show neighborhood", "Show neighborhood") { 311 | private static final long serialVersionUID = 4234994986788687910L; 312 | 313 | public void actionPerformed(ActionEvent e) { 314 | owlClass = (OWLEntity) graph.getFirstSelectedNode().getUserObject(); 315 | model.showNeighborhood(owlClass, true); 316 | graph.performLayout(); 317 | } 318 | }); 319 | 320 | graphMenu.add(new CajunAction("Set as focus", "Set as focus") { 321 | private static final long serialVersionUID = -68720636770886830L; 322 | 323 | public void actionPerformed(ActionEvent e) { 324 | owlClass = (OWLEntity)graph.getFirstSelectedNode().getUserObject(); 325 | model.hideAscendants(graph.getFirstSelectedNode()); 326 | graph.performLayout(); 327 | } 328 | }); 329 | 330 | graphMenu.addSeparator(); 331 | 332 | expandAction = new CajunAction("Expand", "Expand") { 333 | private static final long serialVersionUID = -8044342001264176639L; 334 | 335 | public void actionPerformed(ActionEvent e) { 336 | owlClass = (OWLEntity)graph.getFirstSelectedNode().getUserObject(); 337 | model.expandNode(graph.getFirstSelectedNode()); 338 | graph.performLayout(); 339 | } 340 | }; 341 | 342 | collapseAction = new CajunAction("Collapse", "Collapse") { 343 | private static final long serialVersionUID = 815274665395852446L; 344 | 345 | public void actionPerformed(ActionEvent e) { 346 | owlClass = (OWLEntity)graph.getFirstSelectedNode().getUserObject(); 347 | model.collapseNode(graph.getFirstSelectedNode()); 348 | graph.performLayout(); 349 | } 350 | }; 351 | 352 | graphMenu.add(expandAction); 353 | graphMenu.add(collapseAction); 354 | graphMenu.addSeparator(); 355 | 356 | final JMenu expandBasedOnMenu = new JMenu("Expand on"); 357 | graphMenu.add(expandBasedOnMenu); 358 | 359 | expandBasedOnActions = new HashSet(); 360 | // initialize the actions with the defaults 361 | // for(Object o : model.getArcTypes()) { 362 | // Action action = getNodeExpansionAction(o.toString()); 363 | // expandBasedOnActions.add(action); 364 | // expandBasedOnMenu.add(action); 365 | // } 366 | 367 | // add any new arc types 368 | // model.addGraphModelListener(new GraphModelAdapter() { 369 | // public void graphArcTypeAdded(Object arcType) { 370 | // Action action = getNodeExpansionAction(arcType.toString()); 371 | // if(!expandBasedOnActions.contains(action)) { 372 | // expandBasedOnActions.add(action); 373 | // expandBasedOnMenu.add(action); 374 | // } 375 | // } 376 | // }); 377 | 378 | graphMenu.add(expandBasedOnMenu); 379 | 380 | graphMenu.addPopupMenuListener(new PopupMenuListener() { 381 | public void popupMenuCanceled(PopupMenuEvent e) {} 382 | public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {} 383 | 384 | public void popupMenuWillBecomeVisible(PopupMenuEvent e) { 385 | GraphNode node = graph.getFirstSelectedNode(); 386 | if (node != null) { 387 | prepareNodeSpecificActions(node, expandBasedOnMenu); 388 | initNodeActionConditions(node); 389 | } 390 | } 391 | 392 | }); 393 | } 394 | 395 | /** 396 | * Sets the expansion menu options enabled/disabled flag based on the current state of the 397 | * node. If the node has already been expanded, everything is disabled. Otherwise, all the 398 | * non-filtered arc types are enabled. 399 | * @param node 400 | */ 401 | private void initNodeActionConditions(GraphNode node) { 402 | if (model.isExpanded(node)) { 403 | expandAction.setEnabled(false); 404 | for (Action action : expandBasedOnActions) { 405 | action.setEnabled(false); 406 | } 407 | } else { 408 | expandAction.setEnabled(true); 409 | for (Action action : expandBasedOnActions) { 410 | if(graph.getFilterManager().isArcTypeVisible(((CajunAction)action).getName())) { 411 | action.setEnabled(true); 412 | } 413 | else { 414 | action.setEnabled(false); 415 | } 416 | } 417 | } 418 | } 419 | 420 | /** 421 | * Uses the arc cache to get all the unique arc types for the given node. 422 | */ 423 | private void prepareNodeSpecificActions(GraphNode node, JMenu expandBasedOnMenu) { 424 | expandBasedOnActions.clear(); 425 | expandBasedOnMenu.removeAll(); 426 | for(GraphArc arc : model.getCachedArcsForEntity((OWLEntity)node.getUserObject())) { 427 | Action action = getNodeExpansionAction(arc.getType().toString()); 428 | if(!expandBasedOnActions.contains(action)) { 429 | expandBasedOnActions.add(action); 430 | expandBasedOnMenu.add(action); 431 | } 432 | } 433 | } 434 | 435 | private CajunAction getNodeExpansionAction(String arcType) { 436 | return new CajunAction(arcType, arcType) { 437 | private static final long serialVersionUID = -4658385618425759291L; 438 | 439 | public void actionPerformed(ActionEvent e) { 440 | model.expandNode(graph.getFirstSelectedNode(), e.getActionCommand()); 441 | graph.performLayout(); 442 | } 443 | }; 444 | } 445 | } 446 | -------------------------------------------------------------------------------- /src/main/java/org/protege/ontograf/common/util/OWLIconProviderImpl.java: -------------------------------------------------------------------------------- 1 | package org.protege.ontograf.common.util; 2 | 3 | import javax.swing.Icon; 4 | 5 | import org.protege.editor.owl.model.OWLModelManager; 6 | import org.protege.editor.owl.ui.OWLIcons; 7 | import org.protege.editor.owl.ui.renderer.OWLIconProvider; 8 | import org.semanticweb.owlapi.model.OWLAnnotationAssertionAxiom; 9 | import org.semanticweb.owlapi.model.OWLAnnotationProperty; 10 | import org.semanticweb.owlapi.model.OWLAnnotationPropertyDomainAxiom; 11 | import org.semanticweb.owlapi.model.OWLAnnotationPropertyRangeAxiom; 12 | import org.semanticweb.owlapi.model.OWLAnonymousIndividual; 13 | import org.semanticweb.owlapi.model.OWLAsymmetricObjectPropertyAxiom; 14 | import org.semanticweb.owlapi.model.OWLClass; 15 | import org.semanticweb.owlapi.model.OWLClassAssertionAxiom; 16 | import org.semanticweb.owlapi.model.OWLDataAllValuesFrom; 17 | import org.semanticweb.owlapi.model.OWLDataExactCardinality; 18 | import org.semanticweb.owlapi.model.OWLDataHasValue; 19 | import org.semanticweb.owlapi.model.OWLDataMaxCardinality; 20 | import org.semanticweb.owlapi.model.OWLDataMinCardinality; 21 | import org.semanticweb.owlapi.model.OWLDataOneOf; 22 | import org.semanticweb.owlapi.model.OWLDataProperty; 23 | import org.semanticweb.owlapi.model.OWLDataPropertyAssertionAxiom; 24 | import org.semanticweb.owlapi.model.OWLDataPropertyDomainAxiom; 25 | import org.semanticweb.owlapi.model.OWLDataPropertyRangeAxiom; 26 | import org.semanticweb.owlapi.model.OWLDataSomeValuesFrom; 27 | import org.semanticweb.owlapi.model.OWLDatatype; 28 | import org.semanticweb.owlapi.model.OWLDatatypeDefinitionAxiom; 29 | import org.semanticweb.owlapi.model.OWLDeclarationAxiom; 30 | import org.semanticweb.owlapi.model.OWLDifferentIndividualsAxiom; 31 | import org.semanticweb.owlapi.model.OWLDisjointClassesAxiom; 32 | import org.semanticweb.owlapi.model.OWLDisjointDataPropertiesAxiom; 33 | import org.semanticweb.owlapi.model.OWLDisjointObjectPropertiesAxiom; 34 | import org.semanticweb.owlapi.model.OWLDisjointUnionAxiom; 35 | import org.semanticweb.owlapi.model.OWLEquivalentClassesAxiom; 36 | import org.semanticweb.owlapi.model.OWLEquivalentDataPropertiesAxiom; 37 | import org.semanticweb.owlapi.model.OWLEquivalentObjectPropertiesAxiom; 38 | import org.semanticweb.owlapi.model.OWLFunctionalDataPropertyAxiom; 39 | import org.semanticweb.owlapi.model.OWLFunctionalObjectPropertyAxiom; 40 | import org.semanticweb.owlapi.model.OWLHasKeyAxiom; 41 | import org.semanticweb.owlapi.model.OWLInverseFunctionalObjectPropertyAxiom; 42 | import org.semanticweb.owlapi.model.OWLInverseObjectPropertiesAxiom; 43 | import org.semanticweb.owlapi.model.OWLIrreflexiveObjectPropertyAxiom; 44 | import org.semanticweb.owlapi.model.OWLNamedIndividual; 45 | import org.semanticweb.owlapi.model.OWLNegativeDataPropertyAssertionAxiom; 46 | import org.semanticweb.owlapi.model.OWLNegativeObjectPropertyAssertionAxiom; 47 | import org.semanticweb.owlapi.model.OWLObject; 48 | import org.semanticweb.owlapi.model.OWLObjectAllValuesFrom; 49 | import org.semanticweb.owlapi.model.OWLObjectComplementOf; 50 | import org.semanticweb.owlapi.model.OWLObjectExactCardinality; 51 | import org.semanticweb.owlapi.model.OWLObjectHasSelf; 52 | import org.semanticweb.owlapi.model.OWLObjectHasValue; 53 | import org.semanticweb.owlapi.model.OWLObjectIntersectionOf; 54 | import org.semanticweb.owlapi.model.OWLObjectMaxCardinality; 55 | import org.semanticweb.owlapi.model.OWLObjectMinCardinality; 56 | import org.semanticweb.owlapi.model.OWLObjectOneOf; 57 | import org.semanticweb.owlapi.model.OWLObjectProperty; 58 | import org.semanticweb.owlapi.model.OWLObjectPropertyAssertionAxiom; 59 | import org.semanticweb.owlapi.model.OWLObjectPropertyDomainAxiom; 60 | import org.semanticweb.owlapi.model.OWLObjectPropertyRangeAxiom; 61 | import org.semanticweb.owlapi.model.OWLObjectSomeValuesFrom; 62 | import org.semanticweb.owlapi.model.OWLObjectUnionOf; 63 | import org.semanticweb.owlapi.model.OWLOntology; 64 | import org.semanticweb.owlapi.model.OWLReflexiveObjectPropertyAxiom; 65 | import org.semanticweb.owlapi.model.OWLSameIndividualAxiom; 66 | import org.semanticweb.owlapi.model.OWLSubAnnotationPropertyOfAxiom; 67 | import org.semanticweb.owlapi.model.OWLSubClassOfAxiom; 68 | import org.semanticweb.owlapi.model.OWLSubDataPropertyOfAxiom; 69 | import org.semanticweb.owlapi.model.OWLSubObjectPropertyOfAxiom; 70 | import org.semanticweb.owlapi.model.OWLSubPropertyChainOfAxiom; 71 | import org.semanticweb.owlapi.model.OWLSymmetricObjectPropertyAxiom; 72 | import org.semanticweb.owlapi.model.OWLTransitiveObjectPropertyAxiom; 73 | import org.semanticweb.owlapi.search.EntitySearcher; 74 | import org.semanticweb.owlapi.util.OWLObjectVisitorAdapter; 75 | 76 | public class OWLIconProviderImpl extends OWLObjectVisitorAdapter implements OWLIconProvider { 77 | 78 | private Icon icon; 79 | 80 | private final Icon primitiveClassIcon = OWLIcons.getIcon("class.primitive.png"); 81 | 82 | private final Icon definedClassIcon = OWLIcons.getIcon("class.defined.png"); 83 | 84 | private final Icon objectPropertyIcon = OWLIcons.getIcon("property.object.png"); 85 | 86 | private final Icon dataPropertyIcon = OWLIcons.getIcon("property.data.png"); 87 | 88 | private final Icon annotationPropertyIcon = OWLIcons.getIcon("property.annotation.png"); 89 | 90 | private final Icon individualIcon = OWLIcons.getIcon("individual.png"); 91 | 92 | private final Icon dataTypeIcon = OWLIcons.getIcon("datarange.png"); 93 | 94 | private final Icon ontologyIcon = OWLIcons.getIcon("ontology.png"); 95 | 96 | private OWLModelManager owlModelManager; 97 | 98 | public OWLIconProviderImpl(OWLModelManager owlModelManager) { 99 | this.owlModelManager = owlModelManager; 100 | } 101 | 102 | public Icon getIcon() { 103 | return icon; 104 | } 105 | 106 | @Override 107 | public Icon getIcon(OWLObject owlObject) { 108 | try { 109 | icon = null; 110 | owlObject.accept(this); 111 | return icon; 112 | } 113 | catch (Exception e) { 114 | return null; 115 | } 116 | } 117 | 118 | @Override 119 | public void visit(OWLObjectIntersectionOf owlAnd) { 120 | icon = primitiveClassIcon; 121 | } 122 | 123 | @Override 124 | public void visit(OWLDatatype owlDatatype) { 125 | icon = dataTypeIcon; 126 | } 127 | 128 | @Override 129 | public void visit(OWLDataOneOf owlDataEnumeration) { 130 | icon = dataTypeIcon; 131 | } 132 | 133 | 134 | @Override 135 | public void visit(OWLDataAllValuesFrom owlDataAllRestriction) { 136 | icon = primitiveClassIcon; 137 | } 138 | 139 | @Override 140 | public void visit(OWLDataProperty owlDataProperty) { 141 | icon = dataPropertyIcon; 142 | } 143 | 144 | @Override 145 | public void visit(OWLDataSomeValuesFrom owlDataSomeValuesFrom) { 146 | icon = primitiveClassIcon; 147 | } 148 | 149 | @Override 150 | public void visit(OWLDataHasValue owlDataValueRestriction) { 151 | icon = primitiveClassIcon; 152 | } 153 | 154 | @Override 155 | public void visit(OWLDifferentIndividualsAxiom owlDifferentIndividualsAxiom) { 156 | icon = individualIcon; 157 | } 158 | 159 | @Override 160 | public void visit(OWLDisjointDataPropertiesAxiom owlDisjointDataPropertiesAxiom) { 161 | icon = dataPropertyIcon; 162 | } 163 | 164 | @Override 165 | public void visit(OWLFunctionalObjectPropertyAxiom axiom) { 166 | icon = objectPropertyIcon; 167 | } 168 | 169 | @Override 170 | public void visit(OWLDisjointObjectPropertiesAxiom axiom) { 171 | icon = objectPropertyIcon; 172 | } 173 | 174 | @Override 175 | public void visit(OWLInverseObjectPropertiesAxiom axiom) { 176 | icon = objectPropertyIcon; 177 | } 178 | 179 | @Override 180 | public void visit(OWLHasKeyAxiom owlHasKeyAxiom) { 181 | icon = primitiveClassIcon; 182 | } 183 | 184 | @Override 185 | public void visit(OWLDatatypeDefinitionAxiom owlDatatypeDefinitionAxiom) { 186 | icon = dataTypeIcon; 187 | } 188 | 189 | @Override 190 | public void visit(OWLInverseFunctionalObjectPropertyAxiom axiom) { 191 | icon = objectPropertyIcon; 192 | } 193 | 194 | @Override 195 | public void visit(OWLObjectPropertyDomainAxiom axiom) { 196 | icon = objectPropertyIcon; 197 | } 198 | 199 | @Override 200 | public void visit(OWLEquivalentObjectPropertiesAxiom owlEquivalentObjectPropertiesAxiom) { 201 | icon = objectPropertyIcon; 202 | } 203 | 204 | @Override 205 | public void visit(OWLNegativeDataPropertyAssertionAxiom owlNegativeDataPropertyAssertionAxiom) { 206 | icon = individualIcon; 207 | } 208 | 209 | @Override 210 | public void visit(OWLObjectPropertyRangeAxiom axiom) { 211 | icon = objectPropertyIcon; 212 | } 213 | 214 | @Override 215 | public void visit(OWLObjectPropertyAssertionAxiom owlObjectPropertyAssertionAxiom) { 216 | icon = individualIcon; 217 | } 218 | 219 | @Override 220 | public void visit(OWLSubObjectPropertyOfAxiom axiom) { 221 | icon = objectPropertyIcon; 222 | } 223 | 224 | @Override 225 | public void visit(OWLNamedIndividual owlIndividual) { 226 | icon = individualIcon; 227 | } 228 | 229 | @Override 230 | public void visit(OWLAnonymousIndividual individual) { 231 | icon = individualIcon; 232 | } 233 | 234 | @Override 235 | public void visit(OWLObjectAllValuesFrom owlObjectAllRestriction) { 236 | icon = primitiveClassIcon; 237 | } 238 | 239 | @Override 240 | public void visit(OWLObjectMinCardinality desc) { 241 | icon = primitiveClassIcon; 242 | } 243 | 244 | @Override 245 | public void visit(OWLObjectExactCardinality desc) { 246 | icon = primitiveClassIcon; 247 | } 248 | 249 | @Override 250 | public void visit(OWLObjectMaxCardinality desc) { 251 | icon = primitiveClassIcon; 252 | } 253 | 254 | @Override 255 | public void visit(OWLObjectHasSelf desc) { 256 | icon = primitiveClassIcon; 257 | } 258 | 259 | @Override 260 | public void visit(OWLDataMinCardinality desc) { 261 | icon = primitiveClassIcon; 262 | } 263 | 264 | @Override 265 | public void visit(OWLDataExactCardinality desc) { 266 | icon = primitiveClassIcon; 267 | } 268 | 269 | @Override 270 | public void visit(OWLDataMaxCardinality desc) { 271 | icon = primitiveClassIcon; 272 | } 273 | 274 | @Override 275 | public void visit(OWLObjectProperty owlObjectProperty) { 276 | icon = objectPropertyIcon; 277 | } 278 | 279 | @Override 280 | public void visit(OWLObjectSomeValuesFrom owlObjectSomeValuesFrom) { 281 | icon = primitiveClassIcon; 282 | } 283 | 284 | @Override 285 | public void visit(OWLObjectHasValue owlObjectValueRestriction) { 286 | icon = primitiveClassIcon; 287 | } 288 | 289 | @Override 290 | public void visit(OWLObjectComplementOf owlNot) { 291 | icon = primitiveClassIcon; 292 | } 293 | 294 | @Override 295 | public void visit(OWLOntology owlOntology) { 296 | icon = ontologyIcon; 297 | } 298 | 299 | @Override 300 | public void visit(OWLObjectUnionOf owlOr) { 301 | icon = primitiveClassIcon; 302 | } 303 | 304 | @Override 305 | public void visit(OWLDeclarationAxiom owlDeclarationAxiom) { 306 | owlDeclarationAxiom.getEntity().accept(this); 307 | } 308 | 309 | @Override 310 | public void visit(OWLSubClassOfAxiom owlSubClassAxiom) { 311 | icon = primitiveClassIcon; 312 | } 313 | 314 | @Override 315 | public void visit(OWLNegativeObjectPropertyAssertionAxiom owlNegativeObjectPropertyAssertionAxiom) { 316 | icon = individualIcon; 317 | } 318 | 319 | @Override 320 | public void visit(OWLAsymmetricObjectPropertyAxiom owlAntiSymmetricObjectPropertyAxiom) { 321 | icon = objectPropertyIcon; 322 | } 323 | 324 | @Override 325 | public void visit(OWLReflexiveObjectPropertyAxiom owlReflexiveObjectPropertyAxiom) { 326 | icon = objectPropertyIcon; 327 | } 328 | 329 | @Override 330 | public void visit(OWLDisjointClassesAxiom owlDisjointClassesAxiom) { 331 | icon = primitiveClassIcon; 332 | } 333 | 334 | @Override 335 | public void visit(OWLDataPropertyDomainAxiom owlDataPropertyDomainAxiom) { 336 | icon = dataPropertyIcon; 337 | } 338 | 339 | @Override 340 | public void visit(OWLDisjointUnionAxiom owlDisjointUnionAxiom) { 341 | icon = primitiveClassIcon; 342 | } 343 | 344 | @Override 345 | public void visit(OWLSymmetricObjectPropertyAxiom owlSymmetricObjectPropertyAxiom) { 346 | icon = objectPropertyIcon; 347 | } 348 | 349 | @Override 350 | public void visit(OWLDataPropertyRangeAxiom owlDataPropertyRangeAxiom) { 351 | icon = dataPropertyIcon; 352 | } 353 | 354 | @Override 355 | public void visit(OWLFunctionalDataPropertyAxiom owlFunctionalDataPropertyAxiom) { 356 | icon = dataPropertyIcon; 357 | } 358 | 359 | @Override 360 | public void visit(OWLEquivalentDataPropertiesAxiom owlEquivalentDataPropertiesAxiom) { 361 | icon = dataPropertyIcon; 362 | } 363 | 364 | @Override 365 | public void visit(OWLEquivalentClassesAxiom owlEquivalentClassesAxiom) { 366 | icon = primitiveClassIcon; 367 | } 368 | 369 | @Override 370 | public void visit(OWLDataPropertyAssertionAxiom owlDataPropertyAssertionAxiom) { 371 | icon = individualIcon; 372 | } 373 | 374 | @Override 375 | public void visit(OWLTransitiveObjectPropertyAxiom owlTransitiveObjectPropertyAxiom) { 376 | icon = objectPropertyIcon; 377 | } 378 | 379 | @Override 380 | public void visit(OWLIrreflexiveObjectPropertyAxiom owlIrreflexiveObjectPropertyAxiom) { 381 | icon = objectPropertyIcon; 382 | } 383 | 384 | @Override 385 | public void visit(OWLSubDataPropertyOfAxiom owlDataSubPropertyAxiom) { 386 | icon = dataPropertyIcon; 387 | } 388 | 389 | @Override 390 | public void visit(OWLSameIndividualAxiom owlSameIndividualsAxiom) { 391 | icon = individualIcon; 392 | } 393 | 394 | @Override 395 | public void visit(OWLClassAssertionAxiom owlClassAssertionAxiom) { 396 | icon = individualIcon; 397 | } 398 | 399 | @Override 400 | public void visit(OWLSubPropertyChainOfAxiom axiom) { 401 | icon = objectPropertyIcon; 402 | } 403 | 404 | @Override 405 | public void visit(OWLClass owlClass) { 406 | for (OWLOntology ont : owlModelManager.getActiveOntologies()) { 407 | if (EntitySearcher.isDefined(owlClass, ont)) { 408 | icon = definedClassIcon; 409 | return; 410 | } 411 | } 412 | icon = primitiveClassIcon; 413 | } 414 | 415 | @Override 416 | public void visit(OWLObjectOneOf owlEnumeration) { 417 | icon = primitiveClassIcon; 418 | } 419 | 420 | @Override 421 | public void visit(OWLAnnotationProperty owlAnnotationProperty) { 422 | icon = annotationPropertyIcon; 423 | } 424 | 425 | @Override 426 | public void visit(OWLAnnotationAssertionAxiom owlAnnotationAssertionAxiom) { 427 | icon = annotationPropertyIcon; 428 | } 429 | 430 | @Override 431 | public void visit(OWLSubAnnotationPropertyOfAxiom owlSubAnnotationPropertyOfAxiom) { 432 | icon = annotationPropertyIcon; 433 | } 434 | 435 | @Override 436 | public void visit(OWLAnnotationPropertyDomainAxiom owlAnnotationPropertyDomainAxiom) { 437 | icon = annotationPropertyIcon; 438 | } 439 | 440 | @Override 441 | public void visit(OWLAnnotationPropertyRangeAxiom owlAnnotationPropertyRangeAxiom) { 442 | icon = annotationPropertyIcon; 443 | } 444 | } 445 | -------------------------------------------------------------------------------- /src/main/java/org/protege/ontograf/ui/FrameTooltipNode.java: -------------------------------------------------------------------------------- 1 | package org.protege.ontograf.ui; 2 | 3 | import java.awt.BasicStroke; 4 | import java.awt.Color; 5 | import java.awt.Font; 6 | import java.awt.Graphics2D; 7 | import java.awt.Paint; 8 | import java.awt.Rectangle; 9 | import java.awt.RenderingHints; 10 | import java.awt.Shape; 11 | import java.awt.Stroke; 12 | import java.awt.geom.Point2D; 13 | import java.awt.geom.Rectangle2D; 14 | import java.util.ArrayList; 15 | import java.util.Collection; 16 | import java.util.HashSet; 17 | import java.util.List; 18 | import java.util.Map; 19 | import java.util.Map.Entry; 20 | import java.util.Set; 21 | 22 | import org.protege.editor.owl.model.OWLModelManager; 23 | import org.protege.ontograf.common.util.NodeOWLClassTooltipType; 24 | import org.protege.ontograf.common.util.NodeOWLIndividualTooltipType; 25 | import org.semanticweb.owlapi.model.OWLAnnotation; 26 | import org.semanticweb.owlapi.model.OWLClass; 27 | import org.semanticweb.owlapi.model.OWLDataPropertyAssertionAxiom; 28 | import org.semanticweb.owlapi.model.OWLDataPropertyExpression; 29 | import org.semanticweb.owlapi.model.OWLDisjointClassesAxiom; 30 | import org.semanticweb.owlapi.model.OWLEntity; 31 | import org.semanticweb.owlapi.model.OWLEquivalentClassesAxiom; 32 | import org.semanticweb.owlapi.model.OWLIndividual; 33 | import org.semanticweb.owlapi.model.OWLLiteral; 34 | import org.semanticweb.owlapi.model.OWLObject; 35 | import org.semanticweb.owlapi.model.OWLObjectPropertyAssertionAxiom; 36 | import org.semanticweb.owlapi.model.OWLObjectPropertyExpression; 37 | import org.semanticweb.owlapi.model.OWLSubClassOfAxiom; 38 | import org.semanticweb.owlapi.search.EntitySearcher; 39 | 40 | import ca.uvic.cs.chisel.cajun.graph.AbstractGraph; 41 | import edu.umd.cs.piccolo.PCamera; 42 | import edu.umd.cs.piccolo.PNode; 43 | import edu.umd.cs.piccolo.nodes.PText; 44 | import edu.umd.cs.piccolo.util.PBounds; 45 | import edu.umd.cs.piccolo.util.PPaintContext; 46 | import edu.umd.cs.piccolox.util.PFixedWidthStroke; 47 | 48 | public class FrameTooltipNode extends PNode { 49 | private static final long serialVersionUID = 1171088034485980559L; 50 | 51 | private static final Color BACKGROUND_COLOR = new Color(255, 255, 203); 52 | 53 | private static final int PADDING_X = 12; 54 | private static final int PADDING_Y = 6; 55 | protected static final int MAX_TEXT_CHARS = 75; 56 | protected static final int MAX_LINES = 3; 57 | 58 | private List textNodes; 59 | 60 | protected Stroke borderStroke; 61 | 62 | private OWLModelManager owlModelManager; 63 | private OWLEntity owlEntity; 64 | 65 | private boolean isCameraNode; 66 | 67 | public FrameTooltipNode(OWLModelManager owlModelManager, AbstractGraph graph, PNode owner, OWLEntity owlEntity) { 68 | borderStroke = new PFixedWidthStroke(1f); 69 | 70 | this.owlModelManager = owlModelManager; 71 | this.owlEntity = owlEntity; 72 | 73 | isCameraNode = true; 74 | 75 | initLocation(graph, owner); 76 | initText(); 77 | adjustX(graph, owner); 78 | 79 | repaint(); 80 | } 81 | 82 | public void updateLocation(AbstractGraph graph, PNode owner) { 83 | removeAllChildren(); 84 | 85 | isCameraNode = false; 86 | 87 | initLocation(graph, owner); 88 | initText(); 89 | adjustX(graph, owner); 90 | 91 | repaint(); 92 | } 93 | 94 | public void setText(GraphTextNode textNode, String s) { 95 | if (s == null) { 96 | s = ""; 97 | } 98 | 99 | textNode.setText(splitTextIntoLines(s, MAX_LINES, MAX_TEXT_CHARS)); 100 | } 101 | 102 | /** 103 | * Moves the tooltip to the left if the owner is on the right hand side 104 | * of the screen. 105 | */ 106 | private void adjustX(AbstractGraph graph, PNode owner) { 107 | Rectangle2D rect = owner.getBounds(); 108 | if(isCameraNode) { 109 | rect = graph.getCamera().viewToLocal(owner.getBounds()); 110 | } 111 | 112 | double maxX = graph.getWidth() / 3; 113 | maxX *= 2; 114 | if(getX() > maxX) { 115 | translate(-1 * (getWidth() + rect.getWidth()), 0); 116 | } 117 | } 118 | 119 | private void initText() { 120 | double x = getX() + 5, y = getY() + 5; 121 | 122 | textNodes = new ArrayList(); 123 | 124 | Font font = PText.DEFAULT_FONT.deriveFont(10f); 125 | 126 | Point2D currentPos = new Point2D.Double(x, y); 127 | 128 | if(owlEntity instanceof OWLClass) { 129 | currentPos = initClassTooltips(currentPos, font); 130 | } 131 | else if(owlEntity instanceof OWLIndividual) { 132 | currentPos = initIndividualTooltips(currentPos, font); 133 | } 134 | 135 | updateBounds(); 136 | } 137 | 138 | private Point2D createTitleText(Point2D currentPos, Font font) { 139 | textNodes.add(createTextNode(currentPos.getX(), currentPos.getY(), owlModelManager.getRendering(owlEntity), font)); 140 | double y = currentPos.getY() + textNodes.get(textNodes.size()-1).getHeight() + 2; 141 | 142 | return new Point2D.Double(currentPos.getX(), y); 143 | } 144 | 145 | private Point2D createURIText(Point2D currentPos, Font font) { 146 | double x = currentPos.getX(); 147 | double y = currentPos.getY(); 148 | textNodes.add(createTextNode(x, y, "URI:", font.deriveFont(Font.BOLD))); 149 | x += textNodes.get(textNodes.size()-1).getWidth() + 5; 150 | textNodes.add(createTextNode(x, y, owlEntity.getIRI().toString(), font)); 151 | 152 | y += textNodes.get(textNodes.size()-1).getHeight() + 2; 153 | x = textNodes.get(0).getX(); 154 | 155 | return new Point2D.Double(x, y); 156 | } 157 | 158 | private Point2D initIndividualTooltips(Point2D currentPos, Font font) { 159 | OWLIndividual individual = (OWLIndividual)owlEntity; 160 | 161 | if(NodeOWLIndividualTooltipType.TITLE.isEnabled()) { 162 | currentPos = createTitleText(currentPos, font); 163 | } 164 | 165 | if(NodeOWLIndividualTooltipType.URI.isEnabled()) { 166 | currentPos = createURIText(currentPos, font); 167 | } 168 | 169 | if(NodeOWLIndividualTooltipType.DIFFERENT_INDIVIDUALS.isEnabled()) { 170 | Collection individuals = EntitySearcher 171 | .getDifferentIndividuals(individual, 172 | owlModelManager.getActiveOntology()); 173 | if(individuals.size() > 0) { 174 | currentPos = addCollectionTextValues(individuals, "Different individuals:", font, currentPos); 175 | } 176 | } 177 | 178 | if(NodeOWLIndividualTooltipType.SAME_INDIVIDUALS.isEnabled()) { 179 | Collection individuals = EntitySearcher 180 | .getSameIndividuals(individual, 181 | owlModelManager.getActiveOntology()); 182 | if(individuals.size() > 0) { 183 | currentPos = addCollectionTextValues(individuals, "Same individuals:", font, currentPos); 184 | } 185 | } 186 | 187 | if(NodeOWLIndividualTooltipType.OBJECT_PROPERTY_ASSERTIONS.isEnabled()) { 188 | Set properties = owlModelManager.getActiveOntology().getObjectPropertyAssertionAxioms(individual); 189 | if(properties.size() > 0) { 190 | currentPos = addCollectionTextValues(properties, "Object property assertions:", font, currentPos); 191 | } 192 | } 193 | 194 | if(NodeOWLIndividualTooltipType.DATA_PROPERTY_ASSERTIONS.isEnabled()) { 195 | Set dataProperties = owlModelManager.getActiveOntology().getDataPropertyAssertionAxioms(individual); 196 | if(dataProperties.size() > 0) { 197 | currentPos = addCollectionTextValues(dataProperties, "Data property assertions:", font, currentPos); 198 | } 199 | } 200 | 201 | if(NodeOWLIndividualTooltipType.NEGATIVE_DATA_PROPERTY_ASSERTIONS.isEnabled()) { 202 | Map> map = EntitySearcher 203 | .getNegativeDataPropertyValues(individual, 204 | owlModelManager.getActiveOntology()).asMap(); 205 | Set negativeDataProperties = new HashSet(); 206 | for (Entry> entry : map 207 | .entrySet()) { 208 | String property = owlModelManager.getRendering(entry.getKey()); 209 | for(OWLLiteral literal : entry.getValue()) { 210 | property += " " + owlModelManager.getRendering(literal); 211 | } 212 | negativeDataProperties.add(property); 213 | } 214 | 215 | if(negativeDataProperties.size() > 0) { 216 | currentPos = addStringValues(negativeDataProperties, "Negative data property assertions:", font, currentPos); 217 | } 218 | } 219 | 220 | 221 | if(NodeOWLIndividualTooltipType.NEGATIVE_OBJECT_PROPERTY_ASSERTIONS.isEnabled()) { 222 | Map> negativeObjectPropertiesMap = EntitySearcher 223 | .getNegativeObjectPropertyValues(individual, 224 | owlModelManager.getActiveOntology()).asMap(); 225 | Set negativeObjectProperties = new HashSet(); 226 | for (Entry> entry : negativeObjectPropertiesMap 227 | .entrySet()) { 228 | String property = owlModelManager.getRendering(entry.getKey()); 229 | for(OWLIndividual owlIndividual : entry.getValue()) { 230 | property += " " + owlModelManager.getRendering(owlIndividual); 231 | } 232 | negativeObjectProperties.add(property); 233 | } 234 | 235 | if(negativeObjectProperties.size() > 0) { 236 | currentPos = addStringValues(negativeObjectProperties, "Negative object property assertions:", font, currentPos); 237 | } 238 | } 239 | 240 | if(NodeOWLIndividualTooltipType.ANNOTATIONS.isEnabled()) { 241 | Collection annotations = EntitySearcher 242 | .getAnnotations(owlEntity, 243 | owlModelManager.getActiveOntology()); 244 | if(annotations.size() > 0) { 245 | currentPos = addCollectionTextValues(annotations, "Annotations:", font, currentPos); 246 | } 247 | } 248 | 249 | return currentPos; 250 | } 251 | 252 | private Point2D initClassTooltips(Point2D currentPos, Font font) { 253 | if(NodeOWLClassTooltipType.TITLE.isEnabled()) { 254 | currentPos = createTitleText(currentPos, font); 255 | } 256 | 257 | if(NodeOWLClassTooltipType.URI.isEnabled()) { 258 | currentPos = createURIText(currentPos, font); 259 | } 260 | 261 | if(NodeOWLClassTooltipType.SUPERCLASSES.isEnabled()) { 262 | Set superClasses = owlModelManager.getActiveOntology().getSubClassAxiomsForSubClass((OWLClass)owlEntity); 263 | if(superClasses.size() > 0) { 264 | currentPos = addCollectionTextValues(superClasses, "Superclasses:", font, currentPos); 265 | } 266 | } 267 | 268 | if(NodeOWLClassTooltipType.EQUIVALENT_CLASSES.isEnabled()) { 269 | Set equivalentAxioms = owlModelManager.getActiveOntology().getEquivalentClassesAxioms((OWLClass)owlEntity); 270 | if(equivalentAxioms.size() > 0) { 271 | currentPos = addCollectionTextValues(equivalentAxioms, "Equivalent classes:", font, currentPos); 272 | } 273 | } 274 | 275 | if(NodeOWLClassTooltipType.DISJOINT_CLASSES.isEnabled()) { 276 | Set disjointAxioms = owlModelManager.getActiveOntology().getDisjointClassesAxioms((OWLClass)owlEntity); 277 | if(disjointAxioms.size() > 0) { 278 | currentPos = addCollectionTextValues(disjointAxioms, "Disjoint classes:", font, currentPos); 279 | } 280 | } 281 | 282 | if(NodeOWLClassTooltipType.ANNOTATIONS.isEnabled()) { 283 | Collection annotations = EntitySearcher 284 | .getAnnotations(owlEntity, 285 | owlModelManager.getActiveOntology()); 286 | if(annotations.size() > 0) { 287 | currentPos = addCollectionTextValues(annotations, "Annotations:", font, currentPos); 288 | } 289 | } 290 | 291 | return currentPos; 292 | } 293 | 294 | private Point2D addStringValues(Set entities, String title, Font font, Point2D point) { 295 | double x = point.getX(); 296 | double y = point.getY(); 297 | textNodes.add(createTextNode(x, y, title, font.deriveFont(Font.BOLD))); 298 | y += textNodes.get(textNodes.size()-1).getHeight() + 2; 299 | x += 10; 300 | for(String entry : entities) { 301 | textNodes.add(createTextNode(x, y, entry, font)); 302 | y += textNodes.get(textNodes.size()-1).getHeight() + 2; 303 | } 304 | 305 | return new Point2D.Double(x-10, y); 306 | } 307 | 308 | private Point2D addCollectionTextValues( 309 | Collection entities, String title, Font font, 310 | Point2D point) { 311 | double x = point.getX(); 312 | double y = point.getY(); 313 | textNodes.add(createTextNode(x, y, title, font.deriveFont(Font.BOLD))); 314 | y += textNodes.get(textNodes.size()-1).getHeight() + 2; 315 | x += 10; 316 | for(OWLObject annotation : entities) { 317 | textNodes.add(createTextNode(x, y, owlModelManager.getRendering(annotation), font)); 318 | y += textNodes.get(textNodes.size()-1).getHeight() + 2; 319 | } 320 | 321 | return new Point2D.Double(x-10, y); 322 | } 323 | 324 | private GraphTextNode createTextNode(double x, double y, String text, Font font) { 325 | GraphTextNode textNode = new GraphTextNode(); 326 | // make this node match the text size 327 | textNode.setConstrainWidthToTextWidth(true); 328 | textNode.setConstrainHeightToTextHeight(true); 329 | textNode.setPickable(false); 330 | textNode.setFont(font); 331 | addChild(textNode); 332 | setText(textNode, text); 333 | textNode.setX(x); 334 | textNode.setY(y); 335 | 336 | return textNode; 337 | } 338 | 339 | /** 340 | * Sets the tooltip location relative the owner's position in the global coordinate system. 341 | */ 342 | private void initLocation(AbstractGraph graph, PNode owner) { 343 | PCamera camera = graph.getCanvas().getCamera(); 344 | Rectangle bounds = graph.getCanvas().getBounds(); 345 | 346 | Rectangle2D rect = owner.getBounds(); //camera.viewToLocal(owner.getBounds()); 347 | if(isCameraNode) { 348 | rect = camera.viewToLocal(owner.getBounds()); 349 | } 350 | 351 | double x = rect.getX(); 352 | double y = rect.getY(); 353 | 354 | x += rect.getWidth(); 355 | x = Math.min(x, bounds.getWidth() - getWidth()); 356 | 357 | y = Math.max(y, 0); 358 | 359 | setX(x); 360 | setY(y); 361 | } 362 | 363 | /** 364 | * Restricts the number of characters in the text node. If the string is too long it is chopped 365 | * and appended with "...". 366 | * 367 | * @param text the string to possibly elide 368 | * @return the elided string, or the original if text isn't longer than the max allowed chars 369 | */ 370 | protected String elideText(String text, int maxCharsPerLine) { 371 | if (text.length() > maxCharsPerLine) { 372 | return new String(text.substring(0, maxCharsPerLine).trim() + "..."); 373 | } 374 | return text; 375 | } 376 | 377 | /** 378 | * Splits the text into lines. Attempts to split at word breaks if possible. Also puts a cap on 379 | * the max number of lines. 380 | */ 381 | protected String splitTextIntoLines(String text, int maxLines, int maxCharsPerLine) { 382 | text = text.trim(); 383 | StringBuffer buffer = new StringBuffer(text.length() + 10); 384 | if (text.length() > maxCharsPerLine) { 385 | int lines = 0; 386 | while (text.length() > 0 && lines < maxLines) { 387 | // base case #1 - text is short 388 | if (text.length() < maxCharsPerLine) { 389 | buffer.append(text); 390 | break; 391 | } 392 | // base case #2 - added max lines 393 | if (lines + 1 == maxLines) { 394 | // elide the remaining text (s) instead of just the current line 395 | buffer.append(elideText(text, maxCharsPerLine)); 396 | break; 397 | } 398 | 399 | // find a space and break on it 400 | int end = findWhiteSpace(text, maxCharsPerLine); 401 | if (end == -1) { 402 | end = Math.min(text.length(), maxCharsPerLine); 403 | } 404 | String line = text.substring(0, end).trim(); 405 | if (line.length() == 0) { 406 | break; 407 | } 408 | 409 | buffer.append(line); 410 | buffer.append('\n'); 411 | lines++; 412 | text = text.substring(end).trim(); 413 | } 414 | return buffer.toString().trim(); 415 | } 416 | return text; 417 | } 418 | 419 | private int findWhiteSpace(String s, int end) { 420 | int ws = -1; 421 | // look 2 characters past the end for a space character 422 | // and work backwards 423 | for (int i = Math.min(s.length() - 1, end + 2); i >= 0; i--) { 424 | if (Character.isWhitespace(s.charAt(i))) { 425 | ws = i; 426 | break; 427 | } 428 | } 429 | return ws; 430 | } 431 | 432 | /** 433 | * Sets the bounds of this node based on the text size. Takes into consideration the 434 | * maximum node width too. 435 | */ 436 | private void updateBounds() { 437 | double w = 0, minY = Double.MAX_VALUE, maxY = 0; 438 | double h = 0; 439 | for(GraphTextNode textNode : textNodes) { 440 | PBounds textBounds = textNode.getBounds(); 441 | w = Math.max(w, 3 * PADDING_X + textBounds.getWidth()); 442 | minY = Math.min(minY, textBounds.getY()); 443 | if(maxY < textBounds.getY()) { 444 | maxY = textBounds.getY(); 445 | h = textBounds.getHeight(); 446 | } 447 | maxY = Math.max(maxY, textBounds.getY()); 448 | } 449 | 450 | h += maxY - minY + PADDING_Y; 451 | setBounds(getX(), getY(), w, h); 452 | } 453 | 454 | @Override 455 | public boolean setBounds(double x, double y, double width, double height) { 456 | // TODO handle maximum width? 457 | boolean changed = super.setBounds(x, y, width, height); 458 | 459 | if (changed) { 460 | invalidatePaint(); 461 | } 462 | return changed; 463 | } 464 | 465 | private static Color getMixedColor(Color c1, float pct1, Color c2, float pct2) { 466 | float[] clr1 = c1.getComponents(null); 467 | float[] clr2 = c2.getComponents(null); 468 | for (int i = 0; i < clr1.length; i++) { 469 | clr1[i] = clr1[i] * pct1 + clr2[i] * pct2; 470 | } 471 | return new Color(clr1[0], clr1[1], clr1[2], clr1[3]); 472 | } 473 | 474 | private void paintBorderShadow(Graphics2D g2, int shadowWidth, Shape shape) { 475 | g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 476 | RenderingHints.VALUE_ANTIALIAS_ON); 477 | int sw = shadowWidth*2; 478 | for (int i=sw; i >= 2; i-=2) { 479 | float pct = (float)(sw - i) / (sw - 1); 480 | g2.setColor(getMixedColor(Color.LIGHT_GRAY, pct, 481 | Color.WHITE, 1.0f-pct)); 482 | g2.setStroke(new BasicStroke(i)); 483 | g2.draw(shape); 484 | } 485 | } 486 | 487 | @Override 488 | protected void paint(PPaintContext paintContext) { 489 | Graphics2D g2 = paintContext.getGraphics(); 490 | 491 | Shape shape = getBounds(); 492 | 493 | g2.setPaint(BACKGROUND_COLOR); 494 | 495 | Rectangle r = shape.getBounds(); 496 | g2.fillRect(r.x, r.y, r.width, r.height); 497 | 498 | paintBorderShadow(g2, 2, shape); 499 | 500 | g2.setPaint(Color.black); 501 | g2.setStroke(borderStroke); 502 | g2.draw(shape); 503 | } 504 | 505 | class GraphTextNode extends PText { 506 | private static final long serialVersionUID = -871571524212274580L; 507 | 508 | private boolean ignoreInvalidatePaint = false; 509 | 510 | // @Override 511 | // public Font getFont() { 512 | // Font font = PText.DEFAULT_FONT; 513 | // if (font == null) { 514 | // font = DEFAULT_FONT; 515 | // } 516 | // return font; 517 | // } 518 | 519 | @Override 520 | public Paint getTextPaint() { 521 | Paint paint = Color.black; 522 | if (paint == null) { 523 | paint = Color.black; 524 | } 525 | return paint; 526 | } 527 | 528 | @Override 529 | protected void paint(PPaintContext paintContext) { 530 | // update the text paint - the super paint method doesn't call our getTextPaint() method 531 | Paint p = getTextPaint(); 532 | if (!p.equals(super.getTextPaint())) { 533 | ignoreInvalidatePaint = true; 534 | setTextPaint(getTextPaint()); 535 | ignoreInvalidatePaint = false; 536 | } 537 | // the font is never set in the super paint class? 538 | paintContext.getGraphics().setFont(getFont()); 539 | super.paint(paintContext); 540 | } 541 | 542 | @Override 543 | public void invalidatePaint() { 544 | if (!ignoreInvalidatePaint) { 545 | super.invalidatePaint(); 546 | } 547 | } 548 | } 549 | } 550 | -------------------------------------------------------------------------------- /src/main/java/org/protege/ontograf/common/ProtegeGraphModel.java: -------------------------------------------------------------------------------- 1 | package org.protege.ontograf.common; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | import java.util.HashMap; 6 | import java.util.HashSet; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.Map.Entry; 10 | import java.util.Set; 11 | import java.util.regex.Pattern; 12 | 13 | import javax.swing.Icon; 14 | 15 | import org.protege.editor.owl.OWLEditorKit; 16 | import org.protege.editor.owl.model.OWLModelManager; 17 | import org.protege.ontograf.common.util.OWLIconProviderImpl; 18 | import org.semanticweb.owlapi.model.AxiomType; 19 | import org.semanticweb.owlapi.model.ClassExpressionType; 20 | import org.semanticweb.owlapi.model.IRI; 21 | import org.semanticweb.owlapi.model.OWLAxiom; 22 | import org.semanticweb.owlapi.model.OWLClass; 23 | import org.semanticweb.owlapi.model.OWLClassExpression; 24 | import org.semanticweb.owlapi.model.OWLEntity; 25 | import org.semanticweb.owlapi.model.OWLIndividual; 26 | import org.semanticweb.owlapi.model.OWLNamedIndividual; 27 | import org.semanticweb.owlapi.model.OWLObjectProperty; 28 | import org.semanticweb.owlapi.model.OWLObjectPropertyExpression; 29 | import org.semanticweb.owlapi.model.OWLObjectSomeValuesFrom; 30 | import org.semanticweb.owlapi.model.OWLOntology; 31 | import org.semanticweb.owlapi.model.OWLQuantifiedRestriction; 32 | import org.semanticweb.owlapi.model.OWLSubClassOfAxiom; 33 | import org.semanticweb.owlapi.search.EntitySearcher; 34 | 35 | import ca.uvic.cs.chisel.cajun.filter.FilterManager; 36 | import ca.uvic.cs.chisel.cajun.graph.DefaultGraphModel; 37 | import ca.uvic.cs.chisel.cajun.graph.arc.DefaultGraphArc; 38 | import ca.uvic.cs.chisel.cajun.graph.arc.GraphArc; 39 | import ca.uvic.cs.chisel.cajun.graph.node.DefaultGraphNode; 40 | import ca.uvic.cs.chisel.cajun.graph.node.GraphNode; 41 | 42 | /** 43 | * Graph model representation of Protege OWL API. Converts OWL relationships and entities 44 | * into GraphArc's and GraphNode's. 45 | * 46 | * @author seanf 47 | */ 48 | public class ProtegeGraphModel extends DefaultGraphModel { 49 | /** Protege specific relationships */ 50 | protected static final String DIRECT_SUBCLASS_SLOT_TYPE = "has subclass"; 51 | protected static final String DIRECT_INDIVIDUAL_SLOT_TYPE = "has individual"; 52 | protected static final String SUFFIX_DOMAIN_RANGE = " (Domain>Range)"; 53 | protected static final String SUB_CLASS_SOME_VALUE_OF = "(Subclass some)"; 54 | protected static final String SUB_CLASS_ALL_VALUES = "(Subclass all)"; 55 | protected static final String EQUIVALENT_CLASS_SOME_VALUE_OF = "(Equivalent class some)"; 56 | protected static final String EQUIVALENT_CLASS_ALL_VALUES = "(Equivalent class all)"; 57 | 58 | /** Protege specific node types */ 59 | protected static final String UNKNOWN_ART_TYPE = "unknown"; 60 | protected static final String CLASS_ART_TYPE = "class"; 61 | protected static final String INDIVIDUAL_ART_TYPE = "individual"; 62 | 63 | /** used to restrict an expansion to a specific arc type */ 64 | protected String restrictToArcType; 65 | 66 | /** map to store the number of arcs associated with a given frame object */ 67 | private Map> frameToArcCount; 68 | 69 | /** collections for caching frame to arc relationships based on reified relationships */ 70 | private Map> artifactToUnreifiedRels; 71 | 72 | /** set of domain/range constraints for the OWL file */ 73 | private Set domainRangeRelsBuffer; 74 | 75 | /** current set of arc types available */ 76 | private Collection arcTypes; 77 | 78 | private Set owlOntologies; 79 | private OWLModelManager owlModelManager; 80 | private OWLEditorKit owlEditorKit; 81 | 82 | private FilterManager filterManager; 83 | 84 | public ProtegeGraphModel(OWLEditorKit owlEditorKit) { 85 | super(); 86 | 87 | owlModelManager = owlEditorKit.getModelManager(); 88 | this.owlEditorKit = owlEditorKit; 89 | owlOntologies = owlModelManager.getActiveOntologies(); 90 | 91 | frameToArcCount = new HashMap>(); 92 | } 93 | 94 | public OWLModelManager getOwlModelManager() { 95 | return owlModelManager; 96 | } 97 | 98 | /** 99 | * Adds the entity as a node and adds any arcs that exist between this new node and the 100 | * existing nodes on the canvas. 101 | * 102 | * @param entity 103 | */ 104 | public void show(OWLEntity entity, FilterManager filterManager) { 105 | this.filterManager = filterManager; 106 | 107 | List arcs = new ArrayList(); 108 | 109 | addNode(entity); 110 | 111 | arcs.addAll(createIncomingRelationships(entity, true)); 112 | arcs.addAll(createOutgoingRelationships(entity, true)); 113 | 114 | addArcsToModel(arcs, false); 115 | recalculateArcStyles(); 116 | } 117 | 118 | /** 119 | * Shows the neighborhood for a given Frame. 120 | * 121 | * @param entity The entity object to get the neighborhood for. 122 | * @param removeOldNodes True if current visible nodes should be removed. 123 | */ 124 | public void showNeighborhood(OWLEntity entity, boolean removeOldNodes) { 125 | List singleItemList = new ArrayList(1); 126 | singleItemList.add(entity); 127 | 128 | showNeighborhood(singleItemList, removeOldNodes); 129 | } 130 | 131 | /** 132 | * Shows the neighborhood for a collection of Frame objects. 133 | * 134 | * @param nodes The collection of OWLEntity objects to get the neighborhood for. 135 | * @param removeOldNodes True if current visible nodes should be removed. 136 | */ 137 | public void showNeighborhood(Collection nodes, boolean removeOldNodes) { 138 | List arcs = new ArrayList(); 139 | for (OWLEntity entity : nodes) { 140 | arcs.addAll(createIncomingRelationships(entity, false)); 141 | arcs.addAll(createOutgoingRelationships(entity, false)); 142 | } 143 | 144 | addArcsToModel(arcs, removeOldNodes); 145 | recalculateArcStyles(); 146 | } 147 | 148 | /** 149 | * Adds the list of arcs to the graph model. All nodes included in the arc relationships are 150 | * also added to the model if necessary. 151 | * 152 | * @param arcs 153 | */ 154 | private void addArcsToModel(Collection arcs, boolean removeOldNodes) { 155 | Set newGraphNodes = new HashSet(); 156 | 157 | for (GraphArc arc : arcs) { 158 | GraphArc createdArc = addArc((OWLEntity) arc.getSource().getUserObject(), (OWLEntity) arc.getDestination().getUserObject(), arc.getType().toString(), arc.getIcon()); 159 | if (createdArc != null) { 160 | newGraphNodes.add(createdArc.getSource()); 161 | newGraphNodes.add(createdArc.getDestination()); 162 | createdArc.setInverted(arc.isInverted()); 163 | 164 | //PNode n = (PNode)createdArc.getDestination(); 165 | //System.out.println(n.getRoot().getClass()); 166 | } 167 | } 168 | 169 | if (removeOldNodes) { 170 | // remove all old nodes 171 | GraphNode[] allNodes = getAllNodes().toArray(new GraphNode[getAllNodes().size()]); 172 | for (GraphNode node : allNodes) { 173 | if (!newGraphNodes.contains(node)) { 174 | removeNode(node.getUserObject()); 175 | } 176 | } 177 | } 178 | } 179 | 180 | /** 181 | * Adds an OWLEntity object as a GraphNode to the model. 182 | * 183 | * @return The newly created GraphNode. 184 | */ 185 | protected GraphNode addNode(OWLEntity entity) { 186 | OWLIconProviderImpl iconProvider = new OWLIconProviderImpl(owlModelManager); 187 | Icon icon = iconProvider.getIcon(entity); 188 | return addNode(entity, owlModelManager.getRendering(entity), icon, getNodeType(entity)); 189 | } 190 | 191 | /** 192 | * Gets the node type as a string based on the OWLEntity object. 193 | * 194 | * @return The node type as a string. 195 | */ 196 | protected String getNodeType(OWLEntity entity) { 197 | if(entity instanceof OWLClass) { 198 | return CLASS_ART_TYPE; 199 | } else if(entity instanceof OWLIndividual) { 200 | return INDIVIDUAL_ART_TYPE; 201 | } 202 | return UNKNOWN_ART_TYPE; 203 | } 204 | 205 | /** 206 | * Adds a GraphArc to the model if it doesn't already exist. 207 | * 208 | * @return The created or found GraphArc. 209 | */ 210 | protected GraphArc addArc(OWLEntity srcEntity, OWLEntity destEntity, String relType, Icon icon) { 211 | if (!relType.contains(restrictToArcType)) { 212 | return null; 213 | } 214 | 215 | boolean newNode = true; 216 | if (getNode(destEntity) != null) { 217 | newNode = false; 218 | } 219 | 220 | GraphNode srcNode = addNode(srcEntity); 221 | GraphNode destNode = addNode(destEntity); 222 | 223 | if (newNode) { 224 | destNode.setLocation(srcNode.getBounds().getX(), srcNode.getBounds().getY()); 225 | } 226 | 227 | String key = srcEntity.toString() + relType + destEntity.toString(); 228 | DefaultGraphArc arc = (DefaultGraphArc) addArc(key, srcNode, destNode, relType, icon); 229 | //arc.setType(relType); 230 | // for this sample the arc types work backworks (is_a, etc) 231 | arc.setInverted(true); 232 | return arc; 233 | } 234 | 235 | /** 236 | * Determines if the given node is displayable, meaning that it if mustBeVisible is true, then 237 | * the entity must exist in the graph model. 238 | * 239 | * @return True if this node should be displayed. 240 | */ 241 | protected boolean isDisplayableNode(OWLEntity entity, boolean mustBeVisible) { 242 | return !mustBeVisible || mustBeVisible && getNode(entity) != null; 243 | } 244 | 245 | /** 246 | * Creates all incoming relationships for the entityOfInterest. 247 | * 248 | * @param entityOfInterest 249 | * @param mustBeVisible True if we only want to create relationships between existing nodes. 250 | * @return The list of GraphArcs created. 251 | */ 252 | protected Set createIncomingRelationships(OWLEntity entityOfInterest, boolean mustBeVisible) { 253 | Set incomingArcs = new HashSet(); 254 | 255 | incomingArcs.addAll(loadParents(entityOfInterest, mustBeVisible)); 256 | incomingArcs.addAll(loadDomainRangeRels(entityOfInterest, false, mustBeVisible)); 257 | incomingArcs.addAll(findIncomingIndividualRelationships(entityOfInterest, mustBeVisible)); 258 | incomingArcs.addAll(loadUnreifiedRelations(entityOfInterest, mustBeVisible)); 259 | incomingArcs.addAll(findIncomingConditionsRelationships(entityOfInterest, mustBeVisible)); 260 | 261 | return incomingArcs; 262 | } 263 | 264 | /** 265 | * Creates all outgoing relationships for a given OWLEntity. 266 | * 267 | * @param entityOfInterest 268 | * @param mustBeVisible True if we only want to create relationships between existing nodes. 269 | * @return The list of GraphArcs created. 270 | */ 271 | protected Set createOutgoingRelationships(OWLEntity entityOfInterest, boolean mustBeVisible) { 272 | Set outgoingRels = new HashSet(); 273 | 274 | outgoingRels.addAll(loadChildren(entityOfInterest, mustBeVisible)); 275 | outgoingRels.addAll(loadDomainRangeRels(entityOfInterest, true, mustBeVisible)); 276 | outgoingRels.addAll(findOutgoingIndividualRelationships(entityOfInterest, mustBeVisible)); 277 | outgoingRels.addAll(findOutgoingConditionsRelationships(entityOfInterest, mustBeVisible)); 278 | 279 | return outgoingRels; 280 | } 281 | 282 | /** 283 | * Finds relationships between an artifact as a item in the domain, and the ranges of its 284 | * properties 285 | */ 286 | private Set loadDomainRangeRels(OWLEntity entityOfInterest, boolean outgoing, boolean mustBeVisible) { 287 | Set domainRangeArcs = new HashSet(); 288 | 289 | getDomainRangeRelationships(); // ensures that domain range rels are created 290 | for (GraphArc relationship : domainRangeRelsBuffer) { 291 | if(!filterManager.isArcTypeVisible(relationship.getType())) { 292 | continue; 293 | } 294 | 295 | OWLEntity sourceObject = (OWLEntity) relationship.getSource().getUserObject(); 296 | OWLEntity destObject = (OWLEntity) relationship.getDestination().getUserObject(); 297 | 298 | if (!isDisplayableNode(sourceObject, mustBeVisible) || !isDisplayableNode(destObject, mustBeVisible)) { 299 | continue; 300 | } 301 | if (outgoing && sourceObject.equals(entityOfInterest) || destObject.equals(entityOfInterest)) { 302 | if(outgoing) { 303 | relationship.setInverted(false); 304 | } 305 | 306 | domainRangeArcs.add(relationship); 307 | } 308 | 309 | } 310 | 311 | return domainRangeArcs; 312 | } 313 | 314 | private Set loadUnreifiedRelations(OWLEntity entityOfInterest, boolean mustBeVisible) { 315 | unreifyRelationInstances(); 316 | 317 | Set unreifiedRels = artifactToUnreifiedRels.get(entityOfInterest); 318 | if(unreifiedRels != null) { 319 | for(GraphArc arc : unreifiedRels) { 320 | if(!filterManager.isArcTypeVisible(arc.getType())) { 321 | unreifiedRels.remove(arc); 322 | } 323 | else { 324 | if(!isDisplayableNode((OWLEntity)arc.getDestination().getUserObject(), mustBeVisible)) { 325 | unreifiedRels.remove(arc); 326 | } 327 | } 328 | } 329 | } 330 | return unreifiedRels == null ? new HashSet() : unreifiedRels; 331 | } 332 | 333 | private void unreifyRelationInstances() { 334 | if (artifactToUnreifiedRels != null) { 335 | return; 336 | } 337 | 338 | artifactToUnreifiedRels = new HashMap>(); 339 | 340 | for (OWLOntology owlOntology : owlOntologies) { 341 | for(OWLNamedIndividual individual : owlOntology.getIndividualsInSignature()) { 342 | for (Entry> entry : EntitySearcher 343 | .getObjectPropertyValues(individual, owlOntology).asMap() 344 | .entrySet()) { 345 | for(OWLIndividual refIndividual : entry.getValue()) { 346 | GraphArc arc = createArc(individual, (OWLNamedIndividual)refIndividual, owlModelManager.getRendering(entry.getKey())); 347 | 348 | Set outgoingUnreifiedRels = artifactToUnreifiedRels.get(individual); 349 | if (outgoingUnreifiedRels == null) { 350 | outgoingUnreifiedRels = new HashSet(); 351 | artifactToUnreifiedRels.put(individual, outgoingUnreifiedRels); 352 | } 353 | outgoingUnreifiedRels.add(arc); 354 | 355 | Set incomingUnreifiedRels = artifactToUnreifiedRels.get(refIndividual); 356 | if (incomingUnreifiedRels == null) { 357 | incomingUnreifiedRels = new HashSet(); 358 | artifactToUnreifiedRels.put((OWLNamedIndividual)refIndividual, incomingUnreifiedRels); 359 | } 360 | incomingUnreifiedRels.add(arc); 361 | } 362 | } 363 | } 364 | } 365 | } 366 | 367 | private Set findIncomingIndividualRelationships(OWLEntity entityOfInterest, boolean mustBeVisible) { 368 | Set arcs = new HashSet(); 369 | 370 | if (!(entityOfInterest instanceof OWLNamedIndividual)) { 371 | return arcs; 372 | } 373 | if(!filterManager.isArcTypeVisible(DIRECT_INDIVIDUAL_SLOT_TYPE)) { 374 | return arcs; 375 | } 376 | 377 | OWLNamedIndividual destIndiv = (OWLNamedIndividual) entityOfInterest; 378 | for (OWLClassExpression refNode : EntitySearcher.getTypes(destIndiv, 379 | owlOntologies)) { 380 | if(refNode instanceof OWLClass) { 381 | OWLClass clsOwner = (OWLClass)refNode; 382 | if (isDisplayableNode(clsOwner, mustBeVisible)) { 383 | String relType = DIRECT_INDIVIDUAL_SLOT_TYPE; 384 | 385 | arcs.add(createArc(clsOwner, destIndiv, relType)); 386 | } 387 | } 388 | } 389 | 390 | return arcs; 391 | } 392 | 393 | private Set findIncomingConditionsRelationships(OWLEntity entityOfInterest, boolean mustBeVisible) { 394 | Set arcs = new HashSet(); 395 | 396 | if (!(entityOfInterest instanceof OWLClass)) { 397 | return arcs; 398 | } 399 | 400 | for (OWLOntology owlOntology : owlOntologies) { 401 | OWLClass owlClass = (OWLClass) entityOfInterest; 402 | Collection axioms = EntitySearcher.getReferencingAxioms( 403 | owlClass, owlOntology, true); 404 | for(OWLAxiom axiom : axioms) { 405 | if(axiom.getAxiomType().equals(AxiomType.SUBCLASS_OF)) { 406 | OWLSubClassOfAxiom subClassAxiom = (OWLSubClassOfAxiom)axiom; 407 | OWLClassExpression subClassExpression = subClassAxiom.getSubClass(); 408 | 409 | if(subClassExpression instanceof OWLClass) { 410 | OWLClassExpression superClassExpression = subClassAxiom.getSuperClass(); 411 | if(superClassExpression instanceof OWLQuantifiedRestriction) { 412 | OWLQuantifiedRestriction restriction = (OWLQuantifiedRestriction)superClassExpression; 413 | if(restriction.getFiller() instanceof OWLClass) { 414 | String relType = owlModelManager.getRendering(restriction.getProperty()); 415 | if(restriction instanceof OWLObjectSomeValuesFrom) { 416 | relType += SUB_CLASS_SOME_VALUE_OF; 417 | } else { 418 | relType += SUB_CLASS_ALL_VALUES; 419 | } 420 | 421 | if(!filterManager.isArcTypeVisible(relType)) { 422 | continue; 423 | } 424 | 425 | OWLEntity source = (OWLClass)subClassExpression; 426 | OWLEntity target = (OWLClass)restriction.getFiller(); 427 | 428 | if(isDisplayableNode(source, mustBeVisible) && isDisplayableNode(target, mustBeVisible)) { 429 | arcs.add(createArc(source, target, relType)); 430 | } 431 | } 432 | } 433 | } 434 | } 435 | } 436 | } 437 | 438 | return arcs; 439 | } 440 | 441 | private Set findOutgoingConditionsRelationships(OWLEntity entityOfInterest, boolean mustBeVisible) { 442 | Set arcs = new HashSet(); 443 | 444 | if (!(entityOfInterest instanceof OWLClass)) { 445 | return arcs; 446 | } 447 | 448 | OWLClass owlClass = (OWLClass) entityOfInterest; 449 | 450 | convertOWLClassExpressionsToArcs(owlClass, 451 | EntitySearcher.getSuperClasses(owlClass, owlOntologies), arcs, 452 | null, mustBeVisible); 453 | 454 | OWLIconProviderImpl iconProvider = new OWLIconProviderImpl(owlModelManager); 455 | Icon icon = iconProvider.getIcon(owlClass); 456 | convertOWLClassExpressionsToArcs(owlClass, 457 | EntitySearcher.getEquivalentClasses(owlClass, owlOntologies), 458 | arcs, icon, mustBeVisible); 459 | 460 | return arcs; 461 | } 462 | 463 | private void convertOWLClassExpressionsToArcs(OWLClass owlClass, 464 | Collection expressions, Set arcs, 465 | Icon icon, boolean mustBeVisible) { 466 | for(OWLClassExpression expression : expressions) { 467 | if(expression.getClassExpressionType().equals(ClassExpressionType.OBJECT_SOME_VALUES_FROM) 468 | || expression.getClassExpressionType().equals(ClassExpressionType.OBJECT_ALL_VALUES_FROM)) { 469 | convertOWLClassExpressionToArcs(owlClass, expression, arcs, icon, mustBeVisible); 470 | } 471 | else if(expression.getClassExpressionType().equals(ClassExpressionType.OBJECT_INTERSECTION_OF)) { 472 | for(OWLClassExpression e : expression.asConjunctSet()) { 473 | convertOWLClassExpressionToArcs(owlClass, e, arcs, icon, mustBeVisible); 474 | } 475 | } 476 | } 477 | } 478 | 479 | private void convertOWLClassExpressionToArcs(OWLClass owlClass, OWLClassExpression expression, Set arcs, Icon icon, boolean mustBeVisible) { 480 | boolean isSubClass = true; 481 | if(icon != null) { 482 | isSubClass = false; 483 | } 484 | 485 | for(OWLClassExpression e : expression.asConjunctSet()) { 486 | if(e instanceof OWLQuantifiedRestriction) { 487 | OWLQuantifiedRestriction restriction = (OWLQuantifiedRestriction)e; 488 | if(restriction.getFiller() instanceof OWLClass) { 489 | String relType = owlModelManager.getRendering(restriction.getProperty()); 490 | if(isSubClass) { 491 | if(restriction instanceof OWLObjectSomeValuesFrom) { 492 | relType += SUB_CLASS_SOME_VALUE_OF; 493 | } else { 494 | relType += SUB_CLASS_ALL_VALUES; 495 | } 496 | } 497 | else { 498 | if(restriction instanceof OWLObjectSomeValuesFrom) { 499 | relType += EQUIVALENT_CLASS_SOME_VALUE_OF; 500 | } else { 501 | relType += EQUIVALENT_CLASS_ALL_VALUES; 502 | } 503 | } 504 | 505 | if(!filterManager.isArcTypeVisible(relType)) { 506 | continue; 507 | } 508 | 509 | if(isDisplayableNode( (OWLClass)restriction.getFiller(), mustBeVisible)) { 510 | arcs.add(createArc(owlClass, (OWLClass)restriction.getFiller(), relType, icon)); 511 | } 512 | } 513 | } 514 | } 515 | } 516 | 517 | /** 518 | * Creates relationships between entityOfInterest and its' direct parents. 519 | * 520 | * @return A list of child to parent relationships. 521 | */ 522 | protected Set loadParents(OWLEntity entityOfInterest, boolean mustBeVisible) { 523 | Set parents = new HashSet(); 524 | 525 | if(!(entityOfInterest instanceof OWLClass)) { 526 | return parents; 527 | } 528 | if(!filterManager.isArcTypeVisible(DIRECT_SUBCLASS_SLOT_TYPE)) { 529 | return parents; 530 | } 531 | 532 | OWLClass clsOfInterest = (OWLClass)entityOfInterest; 533 | 534 | for(OWLClass parentCls : owlEditorKit.getOWLModelManager().getOWLHierarchyManager().getOWLClassHierarchyProvider().getParents(clsOfInterest)) { 535 | if (isDisplayableNode(parentCls, mustBeVisible)) { 536 | GraphArc arc = createArc(parentCls, clsOfInterest, DIRECT_SUBCLASS_SLOT_TYPE); 537 | arc.setInverted(false); 538 | parents.add(arc); 539 | } 540 | } 541 | 542 | return parents; 543 | } 544 | 545 | /** 546 | * Creates relationships between entityOfInterest and its' direct children. 547 | * 548 | * @return A list of parent to child relationships. 549 | */ 550 | protected Set loadChildren(OWLEntity entityOfInterest, boolean mustBeVisible) { 551 | Set children = new HashSet(); 552 | 553 | if(!(entityOfInterest instanceof OWLClass)) { 554 | return children; 555 | } 556 | if(!filterManager.isArcTypeVisible(DIRECT_SUBCLASS_SLOT_TYPE)) { 557 | return children; 558 | } 559 | 560 | OWLClass clsOfInterest = (OWLClass)entityOfInterest; 561 | 562 | for(OWLClass childCls : owlEditorKit.getOWLModelManager().getOWLHierarchyManager().getOWLClassHierarchyProvider().getChildren(clsOfInterest)) { 563 | if (isDisplayableNode(childCls, mustBeVisible)) { 564 | GraphArc arc = createArc(clsOfInterest, childCls, DIRECT_SUBCLASS_SLOT_TYPE); 565 | children.add(arc); 566 | } 567 | } 568 | 569 | return children; 570 | } 571 | 572 | private Set findOutgoingIndividualRelationships(OWLEntity entityOfInterest, boolean mustBeVisible) { 573 | Set incomingInstanceRels = new HashSet(); 574 | 575 | if (!(entityOfInterest instanceof OWLClass)) { 576 | return incomingInstanceRels; 577 | } 578 | if(!filterManager.isArcTypeVisible(DIRECT_INDIVIDUAL_SLOT_TYPE)) { 579 | return incomingInstanceRels; 580 | } 581 | 582 | OWLClass owlClass = (OWLClass) entityOfInterest; 583 | for (OWLIndividual individual : EntitySearcher.getIndividuals(owlClass, 584 | owlOntologies)) { 585 | if(individual instanceof OWLNamedIndividual) { 586 | OWLNamedIndividual namedIndividual = (OWLNamedIndividual)individual; 587 | if(isDisplayableNode(namedIndividual, mustBeVisible)) { 588 | String relType = DIRECT_INDIVIDUAL_SLOT_TYPE; 589 | GraphArc arc = createArc(owlClass, namedIndividual, relType); 590 | incomingInstanceRels.add(arc); 591 | } 592 | } 593 | } 594 | 595 | return incomingInstanceRels; 596 | } 597 | 598 | private Set getOWLClasses( 599 | Collection owlExpressions) { 600 | Set domains = new HashSet(); 601 | for(OWLClassExpression expression : owlExpressions) { 602 | if(expression instanceof OWLClass) { 603 | domains.add((OWLClass)expression); 604 | } 605 | } 606 | 607 | return domains; 608 | } 609 | 610 | private void createDomainRangeRels(Set domains, Set ranges, OWLObjectProperty property) { 611 | // make relationships between all named classes in the domain and all named classes in the range 612 | for(OWLEntity domainClass : domains) { 613 | GraphNode srcNode = new DefaultGraphNode(domainClass); 614 | for (OWLEntity rangeClass : ranges) { 615 | GraphNode destNode = new DefaultGraphNode(rangeClass); 616 | String relType = owlModelManager.getRendering(property) + SUFFIX_DOMAIN_RANGE; 617 | 618 | GraphArc arc = createArc(srcNode, destNode, relType, null); 619 | if(!domainRangeRelsBuffer.contains(arc)) { 620 | domainRangeRelsBuffer.add(arc); 621 | } 622 | } 623 | } 624 | } 625 | 626 | private void createDomainRangeRels() { 627 | domainRangeRelsBuffer = new HashSet(); 628 | 629 | for (OWLOntology owlOntology : owlOntologies) { 630 | Set properties = owlOntology.getObjectPropertiesInSignature(); 631 | 632 | for(OWLObjectProperty property : properties) { 633 | for(OWLObjectProperty owlObjectProperty : property.getObjectPropertiesInSignature()) { 634 | Collection domainVals = EntitySearcher 635 | .getDomains(owlObjectProperty, owlOntology); 636 | Collection rangeVals = EntitySearcher 637 | .getRanges(owlObjectProperty, owlOntology); 638 | 639 | if (domainVals.isEmpty() && !rangeVals.isEmpty()) { 640 | domainVals.add(owlModelManager.getOWLEntityFinder().getOWLClass("Thing")); 641 | } else if (rangeVals.isEmpty() && !domainVals.isEmpty()) { 642 | rangeVals.add(owlModelManager.getOWLEntityFinder().getOWLClass("Thing")); 643 | } 644 | 645 | Set domains = getOWLClasses(domainVals); 646 | Set ranges = getOWLClasses(rangeVals); 647 | 648 | createDomainRangeRels(domains, ranges, owlObjectProperty); 649 | } 650 | } 651 | } 652 | } 653 | 654 | private Collection getDomainRangeRelationships() { 655 | if (domainRangeRelsBuffer == null) { 656 | createDomainRangeRels(); 657 | } 658 | return domainRangeRelsBuffer; 659 | } 660 | 661 | /** 662 | * Creates a GraphArc with the given parameters without actually adding the GraphNodes or 663 | * GraphArc to the model. 664 | * 665 | * @return A GraphArc object. 666 | */ 667 | protected GraphArc createArc(OWLEntity srcCls, OWLEntity targetCls, String relType) { 668 | return createArc(srcCls, targetCls, relType, null); 669 | } 670 | 671 | protected GraphArc createArc(OWLEntity srcCls, OWLEntity targetCls, String relType, Icon icon) { 672 | GraphNode srcNode = new DefaultGraphNode(srcCls); 673 | GraphNode destNode = new DefaultGraphNode(targetCls); 674 | 675 | return createArc(srcNode, destNode, relType, icon); 676 | } 677 | 678 | /** 679 | * Creates a GraphArc with the given parameters without actually adding the GraphNodes or 680 | * GraphArc to the model. 681 | * 682 | * @return A GraphArc object. 683 | */ 684 | protected GraphArc createArc(GraphNode srcNode, GraphNode destNode, String relType, Icon icon) { 685 | String key = srcNode.getUserObject().toString() + relType + destNode.getUserObject().toString(); 686 | 687 | return new DefaultGraphArc(key, srcNode, destNode, icon, relType); 688 | } 689 | 690 | /** 691 | * Performs a search against the knowledge base and displays the neighborhood for the results. 692 | * 693 | * @param searchString 694 | */ 695 | public Collection search(String searchString, FilterManager filterManager) { 696 | restrictToArcType = ""; 697 | this.filterManager = filterManager; 698 | 699 | Set searchResults = new HashSet(); 700 | Set matchingClasses = owlModelManager.getOWLEntityFinder().getMatchingOWLClasses(searchString, true, Pattern.CASE_INSENSITIVE); 701 | Set matchingIndividuals = owlModelManager.getOWLEntityFinder().getMatchingOWLIndividuals(searchString, true, Pattern.CASE_INSENSITIVE); 702 | 703 | searchResults.addAll(matchingClasses); 704 | searchResults.addAll(matchingIndividuals); 705 | 706 | if (searchResults != null) { 707 | showNeighborhood(searchResults, true); 708 | } 709 | 710 | return searchResults; 711 | } 712 | 713 | /** 714 | * Hides all ascendants of the given node. 715 | */ 716 | public void hideAscendants(GraphNode graphNode) { 717 | Set seen = new HashSet(); 718 | 719 | hideAscendants(graphNode, seen); 720 | } 721 | 722 | /** 723 | * Hides all incoming arcs and attempts to hide any nodes and their arcs. 724 | * 725 | * @param graphNode 726 | * @param seen The list of recursively visited items, need this to avoid cycles 727 | */ 728 | private void hideAscendants(GraphNode graphNode, Set seen) { 729 | GraphArc[] arcs = graphNode.getArcs().toArray(new GraphArc[graphNode.getArcs().size()]); 730 | seen.add(((OWLEntity) graphNode.getUserObject()).getIRI()); 731 | 732 | for (GraphArc arc : arcs) { 733 | Object userObject = arc.getSource().getUserObject(); 734 | GraphNode node = getNode(userObject); 735 | 736 | // recursively collapse the child node, check our seen object in order to avoid cycles 737 | if (node != null && !node.equals(graphNode)) { 738 | removeArc(arc.getUserObject()); 739 | if (!seen.contains(((OWLEntity) userObject).getIRI())) { 740 | hideAll(node, seen); 741 | } 742 | 743 | if (isRemovable(node)) { 744 | removeNode(userObject); 745 | } 746 | } else { 747 | userObject = arc.getDestination().getUserObject(); 748 | seen.add(((OWLEntity) userObject).getIRI()); 749 | } 750 | } 751 | } 752 | 753 | /** 754 | * Hides all arcs recursively from the given graphNode. 755 | * 756 | * @param graphNode 757 | * @param seen Set of URIs that have already been recursed on 758 | */ 759 | private void hideAll(GraphNode graphNode, Set seen) { 760 | GraphArc[] arcs = graphNode.getArcs().toArray(new GraphArc[graphNode.getArcs().size()]); 761 | seen.add(((OWLEntity) graphNode.getUserObject()).getIRI()); 762 | 763 | for (GraphArc arc : arcs) { 764 | Object userObject = arc.getDestination().getUserObject(); 765 | GraphNode node = getNode(userObject); 766 | if (node == null || node.equals(graphNode)) { 767 | continue; 768 | } 769 | 770 | // recursively collapse the child node, check our seen object in order to avoid cycles 771 | removeArc(arc.getUserObject()); 772 | if (!seen.contains(((OWLEntity) userObject).getIRI())) { 773 | hideAll(node, seen); 774 | } 775 | 776 | if (node != null && isRemovable(node)) { 777 | removeNode(userObject); 778 | } 779 | } 780 | } 781 | 782 | private Collection generateArcTypes() { 783 | Set types = new HashSet(); 784 | types.add(ProtegeGraphModel.DIRECT_SUBCLASS_SLOT_TYPE); 785 | types.add(ProtegeGraphModel.DIRECT_INDIVIDUAL_SLOT_TYPE); 786 | types.addAll(super.getArcTypes()); 787 | 788 | return types; 789 | } 790 | 791 | @Override 792 | public Collection getArcTypes() { 793 | if(arcTypes == null) { 794 | arcTypes = generateArcTypes(); 795 | } 796 | else { 797 | Collection types = generateArcTypes(); 798 | if(types.size() != arcTypes.size()) { 799 | arcTypes.addAll(types); 800 | } 801 | } 802 | return arcTypes; 803 | } 804 | 805 | /** 806 | * Expands the given graphNode by showing it's neighborhood and keeping existing nodes. 807 | * 808 | * @param graphNode 809 | */ 810 | public void expandNode(GraphNode graphNode) { 811 | showNeighborhood((OWLEntity) graphNode.getUserObject(), false); 812 | } 813 | 814 | /** 815 | * Expands the given graphNode based on a specific arcType and keeping existing nodes. 816 | * 817 | * @param graphNode 818 | */ 819 | public void expandNode(GraphNode graphNode, String arcType) { 820 | graphNode.setHighlighted(false); 821 | 822 | restrictToArcType = arcType; 823 | showNeighborhood((OWLEntity) graphNode.getUserObject(), false); 824 | restrictToArcType = ""; 825 | } 826 | 827 | /** 828 | * Collapses the given graphNode. 829 | */ 830 | public void collapseNode(GraphNode graphNode) { 831 | Set seen = new HashSet(); 832 | 833 | graphNode.setHighlighted(false); 834 | 835 | collapseNode(graphNode, seen); 836 | } 837 | 838 | /** 839 | * Gets all the incoming and outgoing arcs for a given OWLEntity. 840 | * 841 | * @return All associated arcs for a given OWLEntity. 842 | */ 843 | private Collection getArcsForEntity(OWLEntity entity) { 844 | Set arcs = new HashSet(); 845 | 846 | arcs.addAll(createIncomingRelationships(entity, false)); 847 | arcs.addAll(createOutgoingRelationships(entity, false)); 848 | 849 | return arcs; 850 | } 851 | 852 | public void resetNodeToArcCount() { 853 | for(OWLEntity owlEntity : frameToArcCount.keySet()) { 854 | frameToArcCount.put(owlEntity, (Set)getArcsForEntity(owlEntity)); 855 | } 856 | } 857 | 858 | /** 859 | * Gets the number of relationships for a given OWLEntity. If the entity doesn't exist in the cache, 860 | * then it calculates the count. 861 | * 862 | * @return The number of incoming and outgoing relationships for the frame. 863 | */ 864 | private Integer getNodeToArcCount(OWLEntity entity) { 865 | Set arcs = getCachedArcsForEntity(entity); 866 | 867 | return arcs.size(); 868 | } 869 | 870 | public Set getCachedArcsForEntity(OWLEntity entity) { 871 | Set arcs = frameToArcCount.get(entity); 872 | if (arcs == null) { 873 | arcs = (Set)getArcsForEntity(entity); 874 | frameToArcCount.put(entity, arcs); 875 | } 876 | 877 | return arcs; 878 | } 879 | 880 | /** 881 | * Collapses the given graphNode by recursively removing all outgoing relationships and nodes 882 | * that become separate components. 883 | * 884 | * @param graphNode 885 | * @param seen The list of recursively visited items, need this to avoid cycles 886 | */ 887 | private void collapseNode(GraphNode graphNode, Set seen) { 888 | GraphArc[] arcs = graphNode.getArcs().toArray(new GraphArc[graphNode.getArcs().size()]); //createOutgoingRelationships((Frame) graphNode.getUserObject(), true); 889 | seen.add(((OWLEntity) graphNode.getUserObject()).getIRI()); 890 | 891 | for (GraphArc arc : arcs) { 892 | Object userObject = arc.getDestination().getUserObject(); 893 | GraphNode node = getNode(userObject); 894 | 895 | // recursively collapse the child node, check our seen object in order to avoid cycles 896 | if (node != null && !node.equals(graphNode)) { 897 | removeArc(arc.getUserObject()); 898 | if (isRecursableArc(seen, userObject, arc)) { 899 | collapseNode(node, seen); 900 | } 901 | 902 | if (isRemovable(node)) { 903 | removeNode(userObject); 904 | } 905 | } 906 | } 907 | } 908 | 909 | /** 910 | * Determines whether the given GraphNode is removable. It is removable if it does not have any 911 | * arcs or the only arcs it has are self loops. 912 | * 913 | * @param node 914 | * @return True if removable. 915 | */ 916 | private boolean isRemovable(GraphNode node) { 917 | for (GraphArc arc : node.getArcs()) { 918 | if (!arc.getDestination().equals(arc.getSource())) { 919 | return false; 920 | } 921 | } 922 | 923 | return true; 924 | } 925 | 926 | private boolean isRecursableArc(Set seen, Object userObject, GraphArc arc) { 927 | return !seen.contains(((OWLEntity) userObject).getIRI()) && (arc.getType().equals(DIRECT_SUBCLASS_SLOT_TYPE) || arc.getType().equals(DIRECT_INDIVIDUAL_SLOT_TYPE)); 928 | } 929 | 930 | /** 931 | * Checks if the given graphNode can be expanded, i.e. has relationships. 932 | * 933 | */ 934 | public boolean isExpandable(GraphNode graphNode) { 935 | return getNodeToArcCount((OWLEntity) graphNode.getUserObject()) > 0; 936 | } 937 | 938 | /** 939 | * Determines if the given graphNode is expanded. 940 | * 941 | * @return True if already expanded. 942 | */ 943 | public boolean isExpanded(GraphNode graphNode) { 944 | int modelArcsSize = graphNode.getArcs().size(); 945 | int frameArcsSize = getNodeToArcCount((OWLEntity) graphNode.getUserObject()); 946 | 947 | return modelArcsSize >= frameArcsSize; 948 | } 949 | } 950 | --------------------------------------------------------------------------------