Modifications to Protege - nononing2014/repoProtege GitHub Wiki
In this section I will explain modifications to Protege. First lets see at directory structure of protege:
-
protege/org.protege.common
Contains some common source code used by other applications. We don't need to modify it. -
protege/org.protege.editor.core.application
Contains source code for core application. It provides all necessary functionality like supporting new plugin, providing apis to external plugins and interacting with OWLAPI. -
protege/org.protege.editor.owl
All UI for editing ontology objects like introducing new classes and etc are provided by this API.
There are excellent sources in web to understand how to create plugin for protege. My explanation will be no where near them but I will try to explain as much as I can. There are various kinds of extension points provided by Protege to allow plugins to extend functionality of protege. Every plugin must have a plugin.xml file which declares what kind of functionality that plugin is extending. Every plugin must have something like this:
<extension id="ExampleWorkspaceTab" point="org.protege.editor.core.application.WorkspaceTab">
<label value="Example Tab"/>
<class value="org.protege.editor.owl.ui.OWLWorkspaceViewsTab"/>
<index value="X"/>
<editorKitId value="OWLEditorKit"/>
<defaultViewConfigFileName value="viewconfig-exampletab.xml"/>
</extension>
These lines are conveying that id of this plugin is "ExampleWorkspaceTab", it is implementing extension point "org.protege.editor.core.application.WorkspaceTab" that is used for creating a new tab in protege. By line <class value="org.protege.editor.owl.ui.OWLWorkspaceViewsTab"/>
it conveys where you can find source code of this extension. Other common extension points are org.protege.editor.core.application.ViewComponent
for view component and org.protege.editor.core.application.EditorKitMenuAction
for creating a new menu item. If you want to understand more about creating plugin look here for example implementations and here for wiki provided by protege for plugin development.
We created view components inside entity and class tabs. Fist take a look at modifications to xml files done by us:
Updates plugin xml can be found here
<extension id="OWLRelationList" point="org.protege.editor.core.application.ViewComponent">
<label value="Relation"/>
<class value="org.protege.editor.owl.ui.view.relation.OWLRelationViewComponent"/>
<headerColor value="@org.protege.datatypecolor"/>
<category value="@org.protege.datatypecategory"/>
<navigates value="@org.protege.datatypecategory"/>
</extension>
<extension id="OWLRelatedList" point="org.protege.editor.core.application.ViewComponent">
<label value="Related To"/>
<class value="org.protege.editor.owl.ui.view.relation.OWLRelatedViewComponent"/>
<headerColor value="@org.protege.classcolor"/>
<category value="@org.protege.classcategory"/>
<navigates value="@org.protege.classcategory"/>
</extension>
<extension id="OWLRelationCharacteristics" point="org.protege.editor.core.application.ViewComponent">
<label value="Characteristics"/>
<class value="org.protege.editor.owl.ui.view.relation.OWLRelationCharacteristicsViewComponent"/>
<headerColor value="@org.protege.objectpropertycolor"/>
<category value="@org.protege.objectpropertycategory"/>
</extension>
Basically we declared three view components:
OWLRelationList
OWLRelatedList
OWLRelationCharacteristics
We also declared where can you find our java implementation of those view component.
This configuration file explains alignment of different views inside class tab of protege. Modified source code can be found here. Our modification are:
<Component label="Related To">
<Property id="pluginId" value="org.protege.editor.owl.OWLRelatedList"/>
</Component>
Basically we are telling protege to include out OWLRelatedList view component in classes tab at a particular position.
This configuration file explains alignment of different views inside entities tab of protege. Modified source code can be found here. Our modification are:
<Component label="Relations">
<Property id="pluginId" value="org.protege.editor.owl.OWLRelationList"/>
</Component>
Basically we are telling protege to include out OWLRelationList view component in entities tab at a particular position.
Our main modification are included in folder protege/org.protege.editor.owl/src/main/java/org/protege/editor/owl/ui/view/relation
we created this folder to create new views that will be used for UI supporting our proposed syntax. As you can see this folder contains java files mentioned in plugin.xml
earlier. I will try to explain UI modification to the best of my ability. Protege uses java swing to create its UI so some basic knowledge on creating ui using swing will improve understanding of my modification. That being said lets see each of the ui component created by us:
This component create this UI:
We modified and created several files to support our UI. I will explain each of the files and I will explain each line in comment please read comments for more clear understanding.
This file implements entry point for our UI. This is pointed in plugin.xml so protege can load this view. Complete source code can be found here. A view component in Protege is extension to view class of swing in java.
//Package on which this file is included
package org.protege.editor.owl.ui.view.relation;
//Some imports. I don't want to clutter this documentation with all imports so I have include only one import. For complete set of imports see original file.
import org.protege.editor.owl.ui.list.OWLAxiomList;
// Every view component in Protege must extend AbstractOWLViewComponent. As it provides necessary APIs for proper working of view component in question.
public class OWLRelationViewComponent extends AbstractOWLViewComponent {
// Version ID
private static final long serialVersionUID = -4515710047558710080L;
// java logger for debugging and outputting error messages.
private static final Logger log = Logger.getLogger(OWLRelationViewComponent.class);
// OWLRelationList is extension to JList of swing library created by us display a list of relations.
private OWLRelationList list;
// Holds current ontology.
private OWLOntology actOnt;
// Declares a relation change listener which will be called when a relation is changed. This is explained in section concerning OWLAPI.
private OWLRelationChangeListener relListner = new OWLRelationChangeListener(){
public void relationChanged(String changeType, OWLRelation rel){
reload();
}
};
// Listener that will be called when selection in a list will be changed. This is standard listener provided by swing library of java.
private ListSelectionListener relSelListener = new ListSelectionListener(){
// Function that is called when a selection is changed
public void valueChanged(ListSelectionEvent e) {
// Selection Model in protege stores which entity is selected in UI. I have made some modifications to selection model also I will explain it later. In this line I am telling selection model to store selected relation in it's memory.
getOWLWorkspace().getOWLSelectionModel().setSelectedRelation(list.getSelectedValue());
}
};
// Called when initializing this view.
@Override
protected void initialiseOWLView() throws Exception {
// See swing documentation for this line.
setLayout(new BorderLayout());
// Create a new OWLRelationList that is extension to JList of swing. It is created by us and I will explain it later.
list = new OWLRelationList(getOWLEditorKit());
// Get active ontology from protege editor kit.
actOnt = getOWLEditorKit().getOWLModelManager().getActiveOntology();
// Add relation chnage listener in current ontology. I explained this in explanation of OWLAPI.
actOnt.addRelationChangeListner(relListner);
// Function declared later int this file to reload our UI.
reload();
// Our UI has two buttons in top they are to delete a relation and add a relation setup both buttons.
setupActions();
// Create a scroll pane from list of relation. See documentation of swing library.
add(ComponentFactory.createScrollPane(list));
// Add selection listener to given list. It is API provided by JList of swing. It will be triggered when a selcetion is changed
list.addListSelectionListener(relSelListener);
}
// Called when this view is being deleted.
@Override
protected void disposeOWLView() {
//Remove all selection listener
list.removeListSelectionListener(relSelListener);
actOnt.removeRelationChangeListner(relListner);
}
// Reload our UI
private void reload(){
// Get active ontology
actOnt = getOWLModelManager().getActiveOntology();
// Get set of relations from active ontology.
java.util.List<OWLRelation> relationList = actOnt.getAllRelations();
// Include all these relations in our list thereby displaying all relations in active ontology.
list.setListData(relationList.toArray(new OWLRelation[relationList.size()]));
}
private void setupActions() {
// Add new relation button. Provided by swing in java.
final DisposableAction addDatatypeAction = new DisposableAction("Add relation", OWLIcons.getIcon("datarange.add.png")) {
private static final long serialVersionUID = 7152977701137488187L;
// Create a new relation.
public void actionPerformed(ActionEvent event) {
createNewRelation();
}
public void dispose() {
// do nothing
}
};
// Create a delete button.
final OWLSelectionViewAction deleteDatatypeAction = new OWLSelectionViewAction("Delete relation", OWLIcons.getIcon("datarange.remove.png")) {
/**
*
*/
private static final long serialVersionUID = 5359788681251086828L;
// Delete selected relation
public void actionPerformed(ActionEvent event) {
deleteRelation();
}
// Don't activate this button unless something is selected/highlighted
public void updateState() {
// @@TODO should check if this is a built in datatype
setEnabled(list.getSelectedIndex() != -1);
}
public void dispose() {
// do nothing
}
};
// Add both buttons in our view
addAction(addDatatypeAction, "A", "A");
addAction(deleteDatatypeAction, "B", "A");
}
// Called when a new relation button is pressed.
public void createNewRelation(){
// Invoke newRelationCreationPanel. I will explain this later.
newRelationCreationPanel.showDialog(getOWLEditorKit(), "Please enter a datatype name");
}
// Delete all selected relations.
public void deleteRelation(){
for(OWLRelation rel : list.getSelectedOWLObjects())
// Remove relation is explained in OWLAPI documentation.
actOnt.removeRelation(rel.toString());
}
}
OWLRelationList is extension to JList used for crating a list of relation. It is used in above view. Complete source code after modification can be found here:
//Package on which this file is included.
package org.protege.editor.owl.ui.view.relation;
//Some imports. I don't want to clutter this documentation with all imports so I have include only one import. For complete set of imports see original file.
import org.protege.editor.owl.OWLEditorKit;
// Extends JList of swing library.
public class OWLRelationList extends JList<OWLRelation> {
private static final long serialVersionUID = -817749022854204056L;
public OWLRelationList(OWLEditorKit owlEditorKit) {
// Get simple cell renderer. This function is provided by protege to create a renderer for JList. We slightly modified it to render our relations, we will explain this later.
setCellRenderer(new OWLCellRendererSimple(owlEditorKit));
}
//Get tool tip message for a relation in a list.
public String getToolTipText(MouseEvent event) {
int index = locationToIndex(event.getPoint());
if (index >= 0){
Object element = getModel().getElementAt(index);
if (element != null && element instanceof OWLRelation){
return ((OWLRelation)element).getName();
}
}
return null;
}
// Set selected values in given list
public void setSelectedValues(Set<OWLRelation> owlRelations, boolean shouldScroll) {
getSelectionModel().clearSelection();
if (getSelectionMode() == ListSelectionModel.MULTIPLE_INTERVAL_SELECTION){
int firstIndex = -1;
for (int i=0; i<getModel().getSize(); i++){
if (owlRelations.contains(getModel().getElementAt(i))){
getSelectionModel().addSelectionInterval(i, i);
if (firstIndex == -1){
firstIndex = i;
}
}
}
if (shouldScroll && firstIndex != -1){
scrollRectToVisible(new Rectangle(getCellBounds(firstIndex, firstIndex)));
}
}
}
// Get selected objects in given list
@SuppressWarnings("unchecked")
public java.util.List<OWLRelation> getSelectedOWLObjects(){
List<OWLRelation> sel = new ArrayList<OWLRelation>();
for (Object o : getSelectedValues()){
sel.add((OWLRelation) o);
}
return sel;
}
}
Popup that will be displayed when new relation button is pressed. Complete source code can be found [here](https://github.com/khageshpatel/repoProtege/blob/master/protege-master/org.protege.editor.owl/src/main/java/org/protege/editor/owl/ui/view/relation/newRelationCreationPanel.java newRelationCreationPanel). We only use swing library to create this popup. I have not included source code for this file in our documentation because you can understand it easily after some internet browsing.
This view component is used for declaring various attributes of a relation. Complete source code can be found [here](https://github.com/khageshpatel/repoProtege/blob/master/protege-master/org.protege.editor.owl/src/main/java/org/protege/editor/owl/ui/view/relation/OWLRelationCharacteristicsViewComponent.java OWLRelationCharacteristicsViewComponent). Again only thing new in this file from previous files is use of swing library. It can be understood by going through swing documentation.
This file is responsible for changing the view in right panel of entities tab. We wanted to modify it such that when a relation is changed it shows OWLRelationCharacteristicsViewComponent. Complete source can be found here. Our modifications are:
// Import this as it is required.
import org.protege.editor.owl.model.selection.OWLRelationSelectionListener;
// Panel name for relations
private static final String RELATIONS_PANEL = "Relations";
//Create a listener that will be called when a selection is changed in relation panel.
private OWLRelationSelectionListener RelSelListener = new OWLRelationSelectionListener() {
public void selectionChanged() throws Exception {
processRelationSelection();
}
};
protected void initialiseOWLView() throws Exception {
::
// Add our relation selection listener
getOWLWorkspace().getOWLSelectionModel().addListener(RelSelListener);
::
// Add characteristic view component that we created earlier to list of panels.
addPane(RELATIONS_PANEL,
"/selected-entity-view-relation-panel.xml",
"org.protege.editor.owl.ui.view.selectedentityview.relations",
reset);
}
// Whenever a relation selection change occur select our relation panel
private void processRelationSelection(){
selectPanel(RELATIONS_PANEL);
}
// When this view is deleted remove out list selection change listener
protected void disposeOWLView() {
::
getOWLWorkspace().getOWLSelectionModel().removeListener(RelSelListener);
}
As mentioned earlier we used simple cell renderer to render list of relations. So we need to modify simple cell renderer to render our relations. Complete source code can be found here. Our modifications are:
// Import these libraries as we will use it later
import org.protege.editor.owl.ui.OWLIcons;
import org.semanticweb.owlapi.model.OWLRelation;
private void setText(Object value, JLabel renderer) {
::
// If entity you are rendering is a OWLRelation display its name as text
else if(value instanceof OWLRelation){
OWLRelation obj = (OWLRelation) value;
renderer.setText(obj.getName());
}
}
private void setIcon(Object value, JLabel renderer) {
::
// If entity you are rendering is OWLRelation put "datarange.png" as its icon.
else if(value instanceof OWLRelation){
renderer.setIcon(OWLIcons.getIcon("datarange.png"));
}
}
Selection model is responsible for managing selection of various entities in Protege UI.
We defined a interface of a selection listener that will be triggered when a change relation selection has occurred. Complete source code can be found here.
This file includes set of APIs provided by OWL selection model. Complete source code can be found here. We introduced four new methods in OWL selection model:
getLastSelectedRelation()
: returns last selected listener.
setSelectedRelation(OWLRelation rel)
: Set selected relation
addListener(OWLRelationSelectionListener listener)
: Add a selection listener
removeListener(OWLRelationSelectionListener listener)
: Remove a selection listener
This file includes implementation of APIs declared in OWLSelectionModel.java. Complete source code can be found here. Our modification are:
// A list maintaining listeners that need to be triggered when a selection is changed
private List<OWLRelationSelectionListener> relListeners;
//Last selected relation
private OWLRelation lastRelation;
public OWLSelectionModelImpl() {
::
// Initialize list of selection listeners.
relListeners = new ArrayList<OWLRelationSelectionListener>();
::
}
// Add a listener to list of listener
public void addListener(OWLRelationSelectionListener listener) {
if (listener == null) {
throw new IllegalArgumentException("Listener must not be null!");
}
relListeners.add(listener);
}
// Remove a listener
public void removeListener(OWLRelationSelectionListener listener) {
relListeners.remove(listener);
}
// Set last selected relation
public void setSelectedRelation(OWLRelation rel){
if (rel == null) {
if (lastRelation != null) {
updateSelectedRelation(null);
}
}
else {
if (lastRelation == null) {
updateSelectedRelation(rel);
}
else if (!rel.toString().equals(lastRelation.toString())) {
updateSelectedRelation(rel);
}
}
}
// Set last selected relation and fire all change listeners
private void updateSelectedRelation(OWLRelation rel){
lastRelation = rel;
fireRelationSelectionChanged();
}
// Fire all relation selection listeners added in this model
private void fireRelationSelectionChanged(){
for (OWLRelationSelectionListener listener : new ArrayList<OWLRelationSelectionListener>(relListeners)) {
try {
listener.selectionChanged();
}
catch (Exception e) {
logger.warn("BAD LISTENER: (" + listener.getClass().getSimpleName() + ") ");
ProtegeApplication.getErrorLog().handleError(Thread.currentThread(), e);
}
}
}
Here we will introduce view created for introducing relations between two concepts.
This is main java file used fo creating this panel: . Complete source code can be found [here] (https://github.com/khageshpatel/repoProtege/blob/master/protege-master/org.protege.editor.owl/src/main/java/org/protege/editor/owl/ui/view/relation/OWLRelatedViewComponent.java "Related View component"). All the line in this file are either introduced earlier or can be found in swing library documentation therefore I believe reader can go through this file on his/her own.
This declares popup that will be triggered when you press new button in this view. Here is complete source code of this file. Here we use split pane of swing library to create our popup. All APIs in this file come from swing library therefore not much explanation is required.