1 package gate.gui;
2
3 import gate.Resource;
4 import gate.creole.AbstractVisualResource;
5 import gate.creole.ResourceInstantiationException;
6 import gate.creole.ontology.*;
7 import gate.event.*;
8 import gate.swing.XJTable;
9 import gate.util.Err;
10 import gate.util.GateRuntimeException;
11 import java.awt.*;
12 import java.awt.event.ComponentEvent;
13 import java.awt.event.ComponentListener;
14 import java.util.*;
15 import java.util.List;
16 import javax.swing.*;
17 import javax.swing.event.TreeSelectionEvent;
18 import javax.swing.event.TreeSelectionListener;
19 import javax.swing.table.AbstractTableModel;
20 import javax.swing.table.DefaultTableCellRenderer;
21 import javax.swing.tree.*;
22 import com.ontotext.gate.ontology.TaxonomyImpl;
23
24 public class OntologyEditor extends AbstractVisualResource
25 implements ResizableVisualResource,
26 ObjectModificationListener{
27
28
31 public void setTarget(Object target){
32 this.taxonomy = (Taxonomy)target;
33 if(target instanceof Ontology){
34 this.ontology = (Ontology)target;
35 ontologyMode = true;
36 }else{
37 ontologyMode = false;
38 }
39 rebuildModel();
40 if(taxonomy instanceof TaxonomyImpl){
41 ((TaxonomyImpl)taxonomy).addObjectModificationListener(this);
42 }
43 }
44
45 public Resource init() throws ResourceInstantiationException{
46 super.init();
47 initLocalData();
48 initGUIComponents();
49 initListeners();
50 return this;
51 }
52
53
54 protected void initLocalData(){
55 itemComparator = new OntologyItemComparator();
56 }
57
58 protected void initGUIComponents(){
59 this.setLayout(new BorderLayout());
60
61 mainSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
62 this.add(mainSplit, BorderLayout.CENTER);
63
64
65 rootNode = new DefaultMutableTreeNode(null, true);
66 treeModel = new DefaultTreeModel(rootNode);
67 tree = new JTree(treeModel);
68 tree.setRootVisible(false);
69 tree.setShowsRootHandles(true);
70 tree.setCellRenderer(new OntoTreeCellRenderer());
71 tree.getSelectionModel().setSelectionMode(
72 TreeSelectionModel.SINGLE_TREE_SELECTION);
73 JScrollPane scroller = new JScrollPane(tree);
74 ToolTipManager.sharedInstance().registerComponent(tree);
76 mainSplit.setLeftComponent(scroller);
77
78 detailsTableModel = new DetailsTableModel();
79 detailsTable = new XJTable(detailsTableModel);
80 ((XJTable)detailsTable).setSortable(false);
81 DetailsTableCellRenderer renderer = new DetailsTableCellRenderer();
82 detailsTable.getColumnModel().getColumn(DetailsTableModel.EXPANDED_COLUMN).
83 setCellRenderer(renderer);
84 detailsTable.getColumnModel().getColumn(DetailsTableModel.LABEL_COLUMN).
85 setCellRenderer(renderer);
86 detailsTable.setShowGrid(false);
87 detailsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
88 detailsTable.setColumnSelectionAllowed(false);
89 detailsTable.setRowSelectionAllowed(true);
90
91 detailsTable.setTableHeader(null);
92 detailsTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
93
94 scroller = new JScrollPane(detailsTable);
95 scroller.getViewport().setOpaque(true);
96 scroller.getViewport().setBackground(detailsTable.getBackground());
97
98 mainSplit.setRightComponent(scroller);
99
100 }
101
102 protected void initListeners(){
103 tree.getSelectionModel().addTreeSelectionListener(
104 new TreeSelectionListener(){
105 public void valueChanged(TreeSelectionEvent e){
106 int[] selectedRows = tree.getSelectionRows();
107 if(selectedRows != null && selectedRows.length > 0){
108 DefaultMutableTreeNode node = (DefaultMutableTreeNode)
109 tree.getPathForRow(selectedRows[0]).
110 getLastPathComponent();
111 detailsTableModel.setItem(node.getUserObject());
112 }
113 }
114 });
115
116 mainSplit.addComponentListener(new ComponentListener(){
117 public void componentHidden(ComponentEvent e){
118 }
119
120 public void componentMoved(ComponentEvent e){
121 }
122
123 public void componentResized(ComponentEvent e){
124 mainSplit.setDividerLocation(0.7);
125 }
126
127 public void componentShown(ComponentEvent e){
128
129 }
130
131 });
132 }
133
134
137 protected void rebuildModel(){
138 rootNode.removeAllChildren();
139 List rootClasses = new ArrayList(taxonomy.getTopClasses());
140 Collections.sort(rootClasses, itemComparator);
141
142 addChidrenRec(rootNode, rootClasses, itemComparator);
143
144 SwingUtilities.invokeLater(new Runnable(){
145 public void run(){
146 treeModel.nodeStructureChanged(rootNode);
147 tree.setSelectionInterval(0, 0);
148 tree.expandPath(new TreePath(rootNode));
150 for(int i = 0; i < tree.getRowCount(); i++) tree.expandRow(i);
152 }
153 });
154 }
155
156
163 protected void addChidrenRec(DefaultMutableTreeNode parent, List children,
164 Comparator comparator){
165 Iterator childIter = children.iterator();
166 while(childIter.hasNext()){
167 Object aChild = childIter.next();
168 DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(aChild);
169 parent.add(childNode);
170 if(aChild instanceof TClass){
171 childNode.setAllowsChildren(true);
172 TClass aClass = (TClass)aChild;
174 List childList =
175 new ArrayList(aClass.getSubClasses(TClass.DIRECT_CLOSURE));
176 Collections.sort(childList, comparator);
177 addChidrenRec(childNode, childList, comparator);
178
179 if(ontologyMode){
181 childList = new ArrayList(ontology.getDirectInstances((OClass)aClass));
182 Collections.sort(childList, comparator);
183 addChidrenRec(childNode, childList, comparator);
184 }
185 }else if(aChild instanceof OInstance){
186 childNode.setAllowsChildren(false);
187 }else{
188 throw new GateRuntimeException("Unknown ontology item: " +
189 aChild.getClass().getName() + "!");
190 }
191
192 }
193 }
194
195 public void processGateEvent(GateEvent e){
196 }
198
199 public void objectCreated(ObjectModificationEvent e){
200 }
202
203 public void objectDeleted(ObjectModificationEvent e){
204 }
206
207 public void objectModified(ObjectModificationEvent e){
208 rebuildModel();
210 }
211
212
213 protected static class OntologyItemComparator implements Comparator{
214
215 public int compare(Object o1, Object o2){
216 if(o1 == null) return o2 == null ? 0 : -1;
217 if(o2 == null) return o1 == null ? 0 : 1;
218 if(o1 instanceof OntologyResource && o2 instanceof OntologyResource) {
219 String s1 = ((OntologyResource)o1).getName();
220 String s2 = ((OntologyResource)o2).getName();
221 if(s1 == null) return s2 == null ? 0 : -1;
222 if(s2 == null) return s1 == null ? 0 : 1;
223 return s1.compareTo(s2);
224 }else return 0;
225 }
226 }
227
228 protected static class OntoTreeCellRenderer extends DefaultTreeCellRenderer{
229 public Component getTreeCellRendererComponent(JTree tree,
230 Object value,
231 boolean sel,
232 boolean expanded,
233 boolean leaf,
234 int row,
235 boolean hasFocus){
236
237
238 if(value != null && value instanceof DefaultMutableTreeNode){
239 Icon icon = null;
240 String itemName = null;
241 Object nodeObject = ((DefaultMutableTreeNode)value).getUserObject();
242 if(nodeObject instanceof TClass){
243 icon = MainFrame.getIcon("Class.gif");
244 itemName = ((TClass)nodeObject).getName();
245 setToolTipText(((TClass)nodeObject).getURI());
246 }else if(nodeObject instanceof OInstance){
247 icon = MainFrame.getIcon("Instance.gif");
248 itemName = ((OInstance)nodeObject).getName();
249 setToolTipText(((OInstance)nodeObject).getURI());
250 }
251 if(icon != null){
252 if(expanded) setOpenIcon(icon);
253 else setClosedIcon(icon);
254 if(leaf) setLeafIcon(icon);
255 }
256 super.getTreeCellRendererComponent(tree,
257 itemName, sel, expanded, leaf, row,
258 hasFocus);
259 }else{
260 super.getTreeCellRendererComponent(tree,
261 value, sel, expanded, leaf, row,
262 hasFocus);
263 }
264 return this;
265 }
266
267 }
268
269
272 protected class DetailsTableModel extends AbstractTableModel{
273
274 public DetailsTableModel(){
275 directSuperClasses = new DetailsGroup("Direct Super Classes", true, null);
276 allSuperClasses = new DetailsGroup("All Super Classes", true, null);
277 directSubClasses = new DetailsGroup("Direct Sub Classes", true, null);
278 allSubClasses = new DetailsGroup("All Sub Classes", true, null);
279 instances = new DetailsGroup("Instances", true, null);
280 properties = new DetailsGroup("Properties", true, null);
281 directTypes = new DetailsGroup("Direct Types", true, null);
282 allTypes = new DetailsGroup("All Types", true, null);
283 detailGroups = new DetailsGroup[]{};
284
285 }
286
287
288 public int getColumnCount(){
289 return COLUMN_COUNT;
290 }
291
292 public int getRowCount(){
293 int size = detailGroups.length;
294 for(int i = 0; i < detailGroups.length; i++)
295 if(detailGroups[i].isExpanded()) size += detailGroups[i].getSize();
296 return size;
297 }
298
299
300 public String getColumnName(int column){
301 switch(column){
302 case EXPANDED_COLUMN : return "";
303 case LABEL_COLUMN: return "";
304 default: return "";
305 }
306 }
307
308 public Class getColumnClass(int columnIndex){
309 switch(columnIndex){
310 case EXPANDED_COLUMN : return Boolean.class;
311 case LABEL_COLUMN: return Object.class;
312 default: return Object.class;
313 }
314 }
315
316
317
320 public boolean isCellEditable(int rowIndex, int columnIndex){
321 Object value = getItemForRow(rowIndex);
322 return columnIndex == EXPANDED_COLUMN && value instanceof DetailsGroup;
323 }
324
325
326
329 public void setValueAt(Object aValue, int rowIndex, int columnIndex){
330 Object oldValue = getItemForRow(rowIndex);
331 if(columnIndex == EXPANDED_COLUMN && oldValue instanceof DetailsGroup){
332 DetailsGroup aGroup = (DetailsGroup)oldValue;
334 aGroup.setExpanded(((Boolean)aValue).booleanValue());
335 }
336 fireTableDataChanged();
337 }
338
339
340 protected Object getItemForRow(int rowIndex){
341 int currentIndex = 0;
342 int groupIndex = 0;
343 while(currentIndex <= rowIndex){
344 if(currentIndex == rowIndex) {
345 return detailGroups[groupIndex];
347 }
348 int increment = 1 +
350 (detailGroups[groupIndex].isExpanded() ?
351 detailGroups[groupIndex].getSize() : 0);
352 if(currentIndex + increment > rowIndex){
353 return detailGroups[groupIndex].getValueAt(rowIndex - currentIndex -1);
355 }else{
356 currentIndex += increment;
357 groupIndex++;
358 }
359 }
360 return null;
361 }
362
363 public Object getValueAt(int rowIndex, int columnIndex){
364 Object value = getItemForRow(rowIndex);
365 switch(columnIndex){
366 case EXPANDED_COLUMN:
367 return value instanceof DetailsGroup ?
368 new Boolean(((DetailsGroup)value).isExpanded()) :
369 null;
370 case LABEL_COLUMN:
371 return value;
372 default:
373 return null;
374 }
375 }
376
377
378
382 public void setItem(Object item){
383 if(item instanceof TClass){
384 detailGroups = ontologyMode ?
385 new DetailsGroup[]{
386 directSuperClasses, allSuperClasses,
387 directSubClasses, allSubClasses,
388 properties, instances} :
389 new DetailsGroup[]{
390 directSuperClasses, allSuperClasses,
391 directSubClasses, allSubClasses};
392
393 TClass aClass = (TClass)item;
395 Set classes = aClass. getSuperClasses(TClass.DIRECT_CLOSURE);
397 directSuperClasses.getValues().clear();
398 if(classes != null){
399 directSuperClasses.getValues().addAll(classes);
400 Collections.sort(directSuperClasses.getValues(), itemComparator);
401 }
402
403 classes = aClass. getSuperClasses(TClass.TRANSITIVE_CLOSURE);
405 allSuperClasses.getValues().clear();
406 if(classes != null){
407 allSuperClasses.getValues().addAll(classes);
408 Collections.sort(allSuperClasses.getValues(), itemComparator);
409 }
410
411 classes = aClass. getSubClasses(TClass.DIRECT_CLOSURE);
413 directSubClasses.getValues().clear();
414 if(classes != null){
415 directSubClasses.getValues().addAll(classes);
416 Collections.sort(directSubClasses.getValues(), itemComparator);
417 }
418
419 classes = aClass. getSubClasses(TClass.TRANSITIVE_CLOSURE);
421 allSubClasses.getValues().clear();
422 if(classes != null){
423 allSubClasses.getValues().addAll(classes);
424 Collections.sort(allSubClasses.getValues(), itemComparator);
425 }
426
427 if(ontologyMode) {
428 properties.getValues().clear();
430 Iterator propIter = new HashSet(ontology.getPropertyDefinitions())
431 .iterator();
432 OInstanceImpl aFakeInstance = new OInstanceImpl("", "",
434 (OClass)aClass, ontology);
435
436 while(propIter.hasNext()) {
437 Property prop = (Property)propIter.next();
438 if(prop.isValidDomain(aFakeInstance))
439 properties.getValues().add(prop);
440 }
444
445 Set setPropNames = aClass.getSetPropertiesNames();
448 if (setPropNames != null) {
449 Iterator setPropNamesIter = setPropNames.iterator();
450 while (setPropNamesIter.hasNext()) {
451 String propName = (String) setPropNamesIter.next();
452 List propValues = aClass.getPropertyValues(propName);
453 if (propValues != null) {
454 Iterator propValIter = propValues.iterator();
455 while (propValIter.hasNext()) {
456 StringBuffer propText = new StringBuffer(propName);
457 propText.append("(");
458 Object propValue = propValIter.next();
459 if (propValue != null)
460 propText.append(propValue instanceof OInstance ?
461 ( (OInstance) propValue).getName() :
462 propValue.toString());
463 propText.append(")");
464 properties.getValues().add(propText.toString());
465 } }
468 } } Collections.sort(properties.getValues(), itemComparator);
471
472 if(ontologyMode){
474 Set instanceSet = ontology.getDirectInstances((OClass)aClass);
475 instances.getValues().clear();
476 if(instanceSet != null){
477 instances.getValues().addAll(instanceSet);
478 Collections.sort(instances.getValues(), itemComparator);
479 }
480 }
481 }
482 }else if(item instanceof OInstance){
483 OInstance anInstance = (OInstance)item;
485 detailGroups = new DetailsGroup[]{directTypes, allTypes, properties};
486
487 Set classes = anInstance.getOClasses();
489 directTypes.getValues().clear();
490 if(classes != null){
491 directTypes.getValues().addAll(classes);
492 Collections.sort(directTypes.getValues(), itemComparator);
493 }
494
495 Set allClasses = new HashSet();
497 classes = anInstance.getOClasses();
498 allClasses.addAll(classes);
499 for(Iterator classIter = classes.iterator(); classIter.hasNext();) {
500 OClass aClass = (OClass)classIter.next();
501 allClasses.addAll(
502 aClass.getSuperClasses(OntologyConstants.TRANSITIVE_CLOSURE));
503 }
504 allTypes.getValues().clear();
505 if(allClasses != null){
506 allTypes.getValues().addAll(allClasses);
507 Collections.sort(allTypes.getValues(), itemComparator);
508 }
509
510 properties.getValues().clear();
511 Set propNames = anInstance.getSetPropertiesNames();
512 if(propNames != null){
513 Iterator propIter = propNames.iterator();
514 while(propIter.hasNext()){
515 String propertyName = (String)propIter.next();
516 List propValues = anInstance.getPropertyValues(propertyName);
517 if(propValues != null){
518 Iterator propValIter = propValues.iterator();
519 while(propValIter.hasNext()){
520 StringBuffer propText = new StringBuffer(propertyName);
521 propText.append("(");
522 Object propValue = propValIter.next();
523 if(propValue != null)
524 propText.append(propValue instanceof OInstance ?
525 ((OInstance)propValue).getName() :
526 propValue.toString());
527 propText.append(")");
528 properties.getValues().add(propText.toString());
529 }
530 }
531 }
532 Collections.sort(properties.getValues());
533 }
534 }
535
536 fireTableDataChanged();
537 }
538
539
540
548 protected boolean mightPropertyApplyToClass(Property property, OClass aClass) {
549 Set domainClasses = new HashSet(property.getDomain());
550 Iterator superPropIter = property.
551 getSuperProperties(OntologyConstants.TRANSITIVE_CLOSURE).iterator();
552 while(superPropIter.hasNext()) {
553 Property aProp = (Property)superPropIter.next();
554 if(aProp == null)Err.prln("Null superProp for " + property.getName());
555 if(aProp.getDomain() == null) Err.prln("Null domain for " + aProp.getName());
556 else domainClasses.addAll(aProp.getDomain());
557 }
558
559 return domainClasses.contains(aClass);
560 }
561
562 protected DetailsGroup directSuperClasses;
563 protected DetailsGroup allSuperClasses;
564 protected DetailsGroup directSubClasses;
565 protected DetailsGroup allSubClasses;
566 protected DetailsGroup instances;
567 protected DetailsGroup properties;
568 protected DetailsGroup directTypes;
569 protected DetailsGroup allTypes;
570 protected DetailsGroup[] detailGroups;
571
572 public static final int COLUMN_COUNT = 2;
573 public static final int EXPANDED_COLUMN = 0;
574 public static final int LABEL_COLUMN = 1;
575 }
576
577
578 protected class DetailsTableCellRenderer extends DefaultTableCellRenderer{
579
580 public Component getTableCellRendererComponent(JTable table,
581 Object value, boolean isSelected, boolean hasFocus,
582 int row, int column){
583 Component res = super.getTableCellRendererComponent(table, "",
585 isSelected,hasFocus, row, column);
586
587 if(column == DetailsTableModel.EXPANDED_COLUMN){
589 setText(null);
590 if(value == null) setIcon(null);
591 else{
592 Object actualValue = detailsTableModel.
593 getValueAt(row, DetailsTableModel.LABEL_COLUMN);
594 setIcon(MainFrame.getIcon(
595 ((Boolean)value).booleanValue() ?
596 "expanded.gif" :
597 "closed.gif"));
598 setEnabled(((DetailsGroup)actualValue).getSize() > 0);
599 }
600 }else if(column == DetailsTableModel.LABEL_COLUMN){
601 if(value instanceof DetailsGroup){
602 DetailsGroup aGroup = (DetailsGroup)value;
603 setIcon(null);
604 setFont(getFont().deriveFont(Font.BOLD));
605 setText(aGroup.getName());
606 setEnabled(aGroup.getSize() > 0);
607 }else if(value instanceof TClass){
608 TClass aClass = (TClass)value;
609 setIcon(MainFrame.getIcon("Class.gif"));
610 setFont(getFont().deriveFont(Font.PLAIN));
611 setText(aClass.getName());
612 setToolTipText(aClass.getURI());
613 setEnabled(true);
614 }else if(value instanceof OInstance){
615 OInstance anInstance = (OInstance)value;
616 setIcon(MainFrame.getIcon("Instance.gif"));
617 setFont(getFont().deriveFont(Font.PLAIN));
618 setText(anInstance.getName());
619 setToolTipText(anInstance.getURI());
620 setEnabled(true);
621 }else if(value instanceof Property){
622 Property aProperty = (Property)value;
623 setIcon(MainFrame.getIcon("param.gif"));
624 setFont(getFont().deriveFont(Font.PLAIN));
625 String text = aProperty.getName() + " -> ";
626 Set range = aProperty.getRange();
627 text += range.toString();
628 setText(text);
629 setToolTipText("<HTML><b>Object Property</b><br>" +
630 aProperty.getURI() + "</html>");
631 setEnabled(true);
632 }else{
633 setIcon(null);
634 setFont(getFont().deriveFont(Font.PLAIN));
635 setText(value.toString());
636 setEnabled(true);
637 }
638 }
639
640 return res;
641 }
642
643 }
644
649 protected static class DetailsGroup{
650 public DetailsGroup(String name, boolean expanded, Collection values){
651 this.name = name;
652 this.expanded = expanded;
653 this.values = values == null ? new ArrayList() : new ArrayList(values);
654 }
655
656 public String getName(){
657 return name;
658 }
659
660
663 public boolean isExpanded(){
664 return expanded;
665 }
666
669 public void setExpanded(boolean expanded){
670 this.expanded = expanded;
671 }
672
675 public void setName(String name){
676 this.name = name;
677 }
678
679 public int getSize(){
680 return values.size();
681 }
682
683 public Object getValueAt(int index){
684 return values.get(index);
685 }
686
687
690 public List getValues(){
691 return values;
692 }
693
694
697 public void setValues(List values){
698 this.values = values;
699 }
700
701 boolean expanded;
702 String name;
703 List values;
704 }
705
708 protected Taxonomy taxonomy;
709
710
714 protected Ontology ontology;
715
716
719 protected boolean ontologyMode;
720
721
722 protected OntologyItemComparator itemComparator;
723
726 protected JTree tree;
727
728
731 protected DefaultTreeModel treeModel;
732
733
734
737 protected JTable detailsTable;
738
739 DetailsTableModel detailsTableModel;
740
741
744 protected JSplitPane mainSplit;
745
746
749 protected DefaultMutableTreeNode rootNode;
750
751 }
752