OntologyInstanceView.java
001 /**
002  *  Copyright (c) 1995-2012, The University of Sheffield. See the file
003  *  COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
004  *
005  *  This file is part of GATE (see http://gate.ac.uk/), and is free
006  *  software, licenced under the GNU Library General Public License,
007  *  Version 2, June 1991 (in the distribution as file licence.html,
008  *  and also available at http://gate.ac.uk/gate/licence.html).
009  *
010  *  Thomas Heitz - 17/12/2009
011  *
012  *  $Id$
013  */
014 
015 package gate.gui.docview;
016 
017 import gate.Annotation;
018 import gate.AnnotationSet;
019 import gate.Factory;
020 import gate.gui.Handle;
021 import gate.gui.MainFrame;
022 import gate.gui.ontology.OntologyEditor;
023 import gate.swing.XJTable;
024 import gate.creole.ontology.*;
025 import gate.util.InvalidOffsetException;
026 import gate.util.LuckyException;
027 import gate.util.Out;
028 import gate.util.Strings;
029 
030 import javax.swing.*;
031 import javax.swing.event.DocumentEvent;
032 import javax.swing.event.DocumentListener;
033 import javax.swing.event.ListSelectionEvent;
034 import javax.swing.event.ListSelectionListener;
035 import javax.swing.table.DefaultTableCellRenderer;
036 import javax.swing.table.DefaultTableModel;
037 import javax.swing.table.TableCellEditor;
038 import java.awt.*;
039 import java.awt.event.*;
040 import java.text.Collator;
041 import java.util.*;
042 import java.util.List;
043 import java.util.Timer;
044 import java.util.regex.Matcher;
045 import java.util.regex.Pattern;
046 
047 /**
048  * Document view that shows two tables: one instances and one for properties.
049  * The instances table is linked with the OntologyClassView class selection
050  * and the properties table is linked with the instances view.
051  <br>
052  * Two buttons allow to add a new instance from the text selection in the
053  * document or as a new label for the selected instance.
054  <br>
055  * You can filter the instances table, delete instances and set properties
056  * that are defined in the ontology as object properties.
057  */
058 @SuppressWarnings("serial")
059 public class OntologyInstanceView extends AbstractDocumentView {
060 
061   public OntologyInstanceView() {
062 
063     instances = new HashSet<OInstance>();
064     setProperties = new HashSet<ObjectProperty>();
065     properties = new HashSet<ObjectProperty>();
066     classesByPropertyMap = new HashMap<String, Set<OClass>>();
067   }
068 
069   @Override
070   protected void initGUI() {
071 
072     // get a pointer to the text view used to display
073     // the selected annotations
074     Iterator<DocumentView> centralViewsIter = owner.getCentralViews().iterator();
075     while(textView == null && centralViewsIter.hasNext()){
076       DocumentView aView = centralViewsIter.next();
077       if(aView instanceof TextualDocumentView)
078         textView = (TextualDocumentViewaView;
079     }
080     // get a pointer to the class view
081     Iterator<DocumentView> verticalViewsIter = owner.getVerticalViews().iterator();
082     while(classView == null && verticalViewsIter.hasNext()){
083       DocumentView aView = verticalViewsIter.next();
084       if (aView instanceof OntologyClassView) {
085         classView = (OntologyClassViewaView;
086       }
087     }
088     classView.setOwner(owner);
089 
090     mainPanel = new JPanel(new BorderLayout());
091 
092     // filter and buttons at the top
093     JPanel filterPanel = new JPanel(new GridBagLayout());
094     GridBagConstraints gbc = new GridBagConstraints();
095     JLabel filterLabel = new JLabel("Filter: ");
096     filterPanel.add(filterLabel, gbc);
097     gbc.fill = GridBagConstraints.HORIZONTAL;
098     gbc.weightx = 1;
099     filterPanel.add(filterTextField = new JTextField(20), gbc);
100     gbc.fill = GridBagConstraints.NONE;
101     gbc.weightx = 0;
102     filterTextField.setToolTipText("Filter the instance table on labels");
103     clearFilterButton = new JButton();
104     clearFilterButton.setBorder(BorderFactory.createEmptyBorder());
105     filterPanel.add(clearFilterButton, gbc);
106     hiddenInstancesLabel = new JLabel(" 0 hidden ");
107     filterPanel.add(hiddenInstancesLabel, gbc);
108     JPanel filterButtonsPanel = new JPanel();
109     newInstanceButton = new JButton("New Inst.");
110     newInstanceButton.setEnabled(false);
111     newInstanceButton.setToolTipText("New instance from the selection");
112     newInstanceButton.setMnemonic(KeyEvent.VK_N);
113     filterButtonsPanel.add(newInstanceButton);
114     addLabelButton = new JButton("Add to Selected Inst.");
115     addLabelButton.setEnabled(false);
116     addLabelButton.setToolTipText(
117       "Add label from selection to the selected instance");
118     addLabelButton.setMnemonic(KeyEvent.VK_A);
119     filterButtonsPanel.add(addLabelButton);
120     filterPanel.add(filterButtonsPanel, gbc);
121 
122     mainPanel.add(filterPanel, BorderLayout.NORTH);
123 
124     // tables at the bottom
125     JPanel tablesPanel = new JPanel(new GridLayout(12));
126     instanceTable = new XJTable() {
127       @Override
128       public boolean isCellEditable(int row, int column) {
129         return false;
130       }
131     };
132     DefaultTableModel model = new DefaultTableModel();
133     model.addColumn("Instance");
134     model.addColumn("Labels");
135     instanceTable.setModel(model);
136     tablesPanel.add(new JScrollPane(instanceTable));
137     propertyTable = new XJTable(){
138       @Override
139       public boolean isCellEditable(int row, int column) {
140         // property values are editable
141         return convertColumnIndexToModel(column== 1;
142       }
143     };
144     model = new DefaultTableModel();
145     model.addColumn("Property");
146     model.addColumn("Value");
147     propertyTable.setModel(model);
148     tablesPanel.add(new JScrollPane(propertyTable));
149 
150     mainPanel.add(tablesPanel, BorderLayout.CENTER);
151 
152     initListeners();
153   }
154 
155   protected void initListeners() {
156 
157     clearFilterButton.setAction(
158       new AbstractAction("", MainFrame.getIcon("exit.gif")) {
159       this.putValue(MNEMONIC_KEY, KeyEvent.VK_BACK_SPACE);
160         this.putValue(SHORT_DESCRIPTION, "Clear text field")}
161       @Override
162       public void actionPerformed(ActionEvent e) {
163         filterTextField.setText("");
164         filterTextField.requestFocusInWindow();
165       }
166     });
167 
168     // when an instance is selected, update the property table
169     instanceTable.getSelectionModel().addListSelectionListener(
170       new ListSelectionListener() {
171         @Override
172         public void valueChanged(ListSelectionEvent e) {
173           if (e.getValueIsAdjusting()) { return}
174           updatePropertyTable();
175           addLabelButton.setEnabled(newInstanceButton.isEnabled()
176                                  && selectedInstance != null);
177         }
178       }
179     );
180 
181     // when typing a character in the instance table, use it for filtering
182     instanceTable.addKeyListener(new KeyAdapter() {
183       @Override
184       public void keyTyped(KeyEvent e) {
185         if (e.getKeyChar() != KeyEvent.VK_TAB
186          && e.getKeyChar() != KeyEvent.VK_SPACE
187          && e.getKeyChar() != KeyEvent.VK_BACK_SPACE
188          && e.getKeyChar() != KeyEvent.VK_DELETE) {
189           filterTextField.requestFocusInWindow();
190           filterTextField.setText(String.valueOf(e.getKeyChar()));
191         }
192       }
193     });
194 
195     // context menu to delete instances
196     instanceTable.addMouseListener(new MouseAdapter() {
197       @Override
198       public void mouseClicked(MouseEvent evt) {
199         processMouseEvent(evt);
200       }
201       @Override
202       public void mousePressed(MouseEvent evt) {
203         JTable table = (JTableevt.getSource();
204         int row =  table.rowAtPoint(evt.getPoint());
205         if (evt.isPopupTrigger()
206         && !table.isRowSelected(row)) {
207           // if right click outside the selection then reset selection
208           table.getSelectionModel().setSelectionInterval(row, row);
209         }
210         processMouseEvent(evt);
211       }
212       @Override
213       public void mouseReleased(MouseEvent evt) {
214         processMouseEvent(evt);
215       }
216       protected void processMouseEvent(MouseEvent evt) {
217         final JTable table = (JTableevt.getSource();
218         int row = table.rowAtPoint(evt.getPoint());
219         if (row >= 0) {
220           if (evt.isPopupTrigger()) {
221             // context menu
222             JPopupMenu popup = new JPopupMenu();
223             if (table.getSelectedRowCount() == 1) {
224               popup.add(new ShowInstanceInOntologyEditorAction());
225               popup.addSeparator();
226             }
227             if (table.getSelectedRowCount() 0) {
228               popup.add(new DeleteSelectedInstanceAction());
229             }
230             if (popup.getComponentCount() 0) {
231               popup.show(table, evt.getX(), evt.getY());
232             }
233           }
234         }
235       }
236     });
237 
238     // context menu to delete properties
239     propertyTable.addMouseListener(new MouseAdapter() {
240       @Override
241       public void mouseClicked(MouseEvent evt) {
242         processMouseEvent(evt);
243       }
244       @Override
245       public void mousePressed(MouseEvent evt) {
246         JTable table = (JTableevt.getSource();
247         int row =  table.rowAtPoint(evt.getPoint());
248         if (evt.isPopupTrigger()
249         && !table.isRowSelected(row)) {
250           // if right click outside the selection then reset selection
251           table.getSelectionModel().setSelectionInterval(row, row);
252         }
253         processMouseEvent(evt);
254       }
255       @Override
256       public void mouseReleased(MouseEvent evt) {
257         processMouseEvent(evt);
258       }
259       protected void processMouseEvent(MouseEvent evt) {
260         final JTable table = (JTableevt.getSource();
261         int row = table.rowAtPoint(evt.getPoint());
262         if (row >= 0) {
263           if (evt.isPopupTrigger()) {
264             // context menu
265             JPopupMenu popup = new JPopupMenu();
266             if (table.getSelectedRowCount() 0) {
267               popup.add(new DeleteSelectedPropertyAction());
268             }
269             if (popup.getComponentCount() 0) {
270               popup.show(table, evt.getX(), evt.getY());
271             }
272           }
273         }
274       }
275     });
276 
277     // show only the rows containing the text from filterTextField
278     filterTextField.getDocument().addDocumentListener(new DocumentListener() {
279       private Timer timer = new Timer("Instance view table rows filter"true);
280       private TimerTask timerTask;
281       @Override
282       public void changedUpdate(DocumentEvent e) { /* do nothing */ }
283       @Override
284       public void insertUpdate(DocumentEvent e) { update()}
285       @Override
286       public void removeUpdate(DocumentEvent e) { update()}
287       private void update() {
288         if (timerTask != null) { timerTask.cancel()}
289         Date timeToRun = new Date(System.currentTimeMillis() 300);
290         timerTask = new TimerTask() { @Override
291         public void run() {
292           updateInstanceTable(selectedClass);
293         }};
294         // add a delay
295         timer.schedule(timerTask, timeToRun);
296       }
297     });
298 
299     // Up/Down key events in filterTextField are transferred to the table
300     filterTextField.addKeyListener(new KeyAdapter() {
301       @Override
302       public void keyPressed(KeyEvent e) {
303         if (e.getKeyCode() == KeyEvent.VK_UP
304          || e.getKeyCode() == KeyEvent.VK_DOWN
305          || e.getKeyCode() == KeyEvent.VK_PAGE_UP
306          || e.getKeyCode() == KeyEvent.VK_PAGE_DOWN) {
307           instanceTable.dispatchEvent(e);
308         }
309       }
310     });
311   }
312 
313   @Override
314   protected void registerHooks() {
315     // show the class view at the right
316     if (!classView.isActive()) {
317       owner.setRightView(owner.verticalViews.indexOf(classView));
318     }
319   }
320 
321   @Override
322   protected void unregisterHooks() {
323     // hide the class view at the right
324     if (classView.isActive()) {
325       owner.setRightView(-1);
326     }
327   }
328 
329   @Override
330   public Component getGUI() {
331     return mainPanel;
332   }
333 
334   @Override
335   public int getType() {
336     return HORIZONTAL;
337   }
338 
339   /**
340    * Update the instance table for the class and ontology selected.
341    @param selectedClass class selected
342    */
343   public void updateInstanceTable(OClass selectedClass) {
344     this.selectedClass = selectedClass;
345     instances.clear();
346     Set<OInstance> allInstances = new HashSet<OInstance>();
347     final DefaultTableModel tableModel = new DefaultTableModel();
348     tableModel.addColumn("Instance");
349     tableModel.addColumn("Labels");
350     if (selectedClass != null) {
351       selectedOntology = selectedClass.getOntology();
352       allInstances.addAll(selectedOntology.getOInstances(
353         selectedClass, OConstants.Closure.TRANSITIVE_CLOSURE));
354       String filter = filterTextField.getText()
355         .trim().toLowerCase(Locale.ENGLISH);
356       for (OInstance instance : allInstances) {
357         Set<AnnotationProperty> properties =
358           instance.getSetAnnotationProperties();
359         boolean hasLabelProperty = false;
360         instances.add(instance);
361         for (AnnotationProperty property : properties) {
362           if (property.getName().equals("label")) {
363             hasLabelProperty = true;
364             List<Literal> values =
365               instance.getAnnotationPropertyValues(property);
366             Set<String> labels = new HashSet<String>();
367             boolean matchFilter = false;
368             for (Literal value : values) {
369               labels.add(value.getValue());
370               if (value.getValue().toLowerCase().indexOf(filter!= -1) {
371                 matchFilter = true;
372               }
373             }
374             if (matchFilter) {
375               tableModel.addRow(new Object[]{instance.getName(),
376                 Strings.toString(labels)});
377             else {
378               instances.remove(instance);
379             }
380           }
381         }
382         if (!hasLabelProperty) {
383           // add instance row without label property
384           tableModel.addRow(new Object[]{instance.getName()""});
385         }
386       }
387     }
388     final int hiddenInstances = allInstances.size() - instances.size();
389     SwingUtilities.invokeLater(new Runnable() { @Override
390     public void run() {
391       hiddenInstancesLabel.setText(" " + hiddenInstances + " hidden ");
392       instanceTable.setModel(tableModel);
393       if (instanceTable.getRowCount() 0) {
394         instanceTable.setRowSelectionInterval(00);
395       }
396     }});
397   }
398 
399   protected void updatePropertyTable() {
400     selectedInstance = null;
401     final DefaultTableModel tableModel = new DefaultTableModel();
402     tableModel.addColumn("Property");
403     tableModel.addColumn("Value");
404     if (instanceTable.getSelectedRow() != -1) {
405       String selectedValue = (StringinstanceTable.getValueAt(
406         instanceTable.getSelectedRow(),
407         instanceTable.convertColumnIndexToView(0));
408       for (OInstance instance : instances) {
409         if (instance.getName().equals(selectedValue)) {
410           // found the instance matching the name in the table
411           selectedInstance = instance;
412           setProperties.clear();
413           properties.clear();
414           // get all object properties that can be set for this instance
415           Set<OClass> classes =
416             instance.getOClasses(OConstants.Closure.DIRECT_CLOSURE);
417           for (OClass oClass : classes) {
418             for (RDFProperty property :
419                  oClass.getPropertiesWithResourceAsDomain()) {
420               if (property instanceof ObjectProperty) {
421                 properties.add((ObjectPropertyproperty);
422                 Set<String> ranges = new HashSet<String>();
423                 Set<OClass> rangeClasses = new HashSet<OClass>();
424                 for (OResource range :
425                     ((ObjectPropertyproperty).getRange()) {
426                   ranges.add(range.getName());
427                   rangeClasses.add((OClassrange);
428                 }
429                 if (ranges.isEmpty()) {
430                   ranges.add("All classes");
431                 }
432                 classesByPropertyMap.put(property.getName(), rangeClasses);
433                 tableModel.addRow(new Object[]{property.getName(),
434                   Strings.toString(ranges)});
435               }
436             }
437           }
438           // get all set object properties and values for this instance
439           for (ObjectProperty objectProperty :
440                instance.getSetObjectProperties()) {
441             setProperties.add(objectProperty);
442             for (OInstance oInstance :
443                  instance.getObjectPropertyValues(objectProperty)) {
444                   tableModel.addRow(new Object[]{objectProperty.getName(),
445                     oInstance.getONodeID().getResourceName()});
446             }
447           }
448           break;
449         }
450       }
451     }
452     SwingUtilities.invokeLater(new Runnable() { @Override
453     public void run() {
454       propertyTable.setModel(tableModel);
455       propertyTable.getColumnModel().getColumn(1)
456         .setCellEditor(new PropertyValueCellEditor());
457       propertyTable.getColumnModel().getColumn(0)
458         .setCellRenderer(new DefaultTableCellRenderer() {
459           @Override
460           public Component getTableCellRendererComponent(JTable table, Object
461             value, boolean isSelected, boolean hasFocus, int row, int column) {
462             super.getTableCellRendererComponent(
463               table, value, isSelected, hasFocus, row, column);
464             setBackground(table.getBackground());
465             Object nextValue = table.getModel().getValueAt(row, 1);
466             if (nextValue != null && ((String)nextValue).startsWith("[")) {
467               // change color for rows that have no values set
468               setBackground(new Color(252252176));
469             }
470             return this;
471           }
472         });
473       propertyTable.getColumnModel().getColumn(1)
474         .setCellRenderer(new DefaultTableCellRenderer() {
475           @Override
476           public Component getTableCellRendererComponent(JTable table, Object
477             value, boolean isSelected, boolean hasFocus, int row, int column) {
478             super.getTableCellRendererComponent(
479               table, value, isSelected, hasFocus, row, column);
480             setBackground(table.getBackground());
481             if (value != null && ((String)value).startsWith("[")) {
482               // change color for rows that have no values set
483               setBackground(new Color(252252176));
484             }
485             return this;
486           }
487         });
488     }});
489   }
490 
491   /**
492    * Create a new annotation and instance from a text selection.
493    * Use the text selected as the instance property label.
494    *
495    @param selectedSet name of the selected annotation set
496    @param selectedText selection
497    @param start selection start offset
498    @param end selection end offset
499    */
500   protected void addSelectionToFilter(final String selectedSet,
501       final String selectedText, final int start, final int end) {
502     newInstanceButton.setAction(
503       new AbstractAction(newInstanceButton.getText()) {
504       this.putValue(MNEMONIC_KEY, KeyEvent.VK_N);
505         this.putValue(SHORT_DESCRIPTION, newInstanceButton.getToolTipText())}
506       @Override
507       public void actionPerformed(ActionEvent e) {
508         createFromSelection(selectedSet, selectedText, start, end, true);
509         filterTextField.setText("");
510 //        filterTextField.setBackground(
511 //          UIManager.getColor("TextField.background"));
512       }
513     });
514     newInstanceButton.setEnabled(true);
515     addLabelButton.setAction(
516       new AbstractAction(addLabelButton.getText()) {
517       this.putValue(MNEMONIC_KEY, KeyEvent.VK_A);
518         this.putValue(SHORT_DESCRIPTION, addLabelButton.getToolTipText())}
519       @Override
520       public void actionPerformed(ActionEvent e) {
521         createFromSelection(selectedSet, selectedText, start, end, false);
522         filterTextField.setText("");
523 //        filterTextField.setBackground(
524 //          UIManager.getColor("TextField.background"));
525       }
526     });
527     filterTextField.setText(selectedText);
528     filterTextField.selectAll();
529     filterTextField.requestFocusInWindow();
530     addLabelButton.setEnabled(selectedInstance != null);
531 //    filterTextField.setBackground(new Color(252, 255, 194));
532 //    filterTextField.setBackground(
533 //      UIManager.getColor("TextField.background"));
534   }
535 
536   /**
537    * Create a new annotation and instance or label from a text selection.
538    * Use the text selected as the instance property label.
539    *
540    @param selectedSet name of the selected annotation set
541    @param selectedText selection
542    @param start selection start offset
543    @param end selection end offset
544    @param newInstance true if it will create a new instance otherwise
545    * it will add a new label to the selected instance
546    */
547   protected void createFromSelection(String selectedSet, String selectedText,
548                                      int start, int end, boolean newInstance) {
549     newInstanceButton.setEnabled(false);
550     addLabelButton.setEnabled(false);
551     AnnotationProperty annotationProperty;
552     RDFProperty property = selectedOntology.getProperty(
553       selectedOntology.createOURIForName("label"));
554     if (property == null) {
555       // create a property 'label' if it doesn't exist
556       annotationProperty = selectedOntology.addAnnotationProperty(
557         selectedOntology.createOURIForName("label"));
558     else if (property instanceof AnnotationProperty) {
559       // get the existing property 'label'
560       annotationProperty = (AnnotationPropertyproperty;
561     else {
562       Out.prln("There is already a property 'label' " +
563         "that is not an annotation property!");
564       return;
565     }
566     OInstance instance = selectedInstance;
567     if (newInstance) {
568       // squeeze spaces, replace spaces and HTML characters with underscores
569       String instanceName = selectedText.replaceAll("\\s+""_");
570       instanceName = instanceName.replaceAll("<>\"&""_");
571       // take only the first 20 characters of the selection
572       if (instanceName.length() 100) {
573         instanceName = instanceName.substring(0100);
574       }
575       OURI instanceOURI = selectedOntology.createOURIForName(instanceName);
576       for (int i = 0; selectedOntology.containsOInstance(instanceOURI)
577           && i < Integer.MAX_VALUE; i++) {
578         // instance name already existing so suffix with a number
579         instanceOURI = selectedOntology.createOURIForName(instanceName+'_'+i);
580       }
581       // create a new instance from the text selected
582       instance = selectedOntology.addOInstance(instanceOURI, selectedClass);
583     }
584     // add a property 'label' with the selected text as value
585     instance.addAnnotationPropertyValue(annotationProperty,
586       new Literal(selectedText));
587     AnnotationSet set = document.getAnnotations(selectedSet);
588 
589     try {
590       String ontology = selectedOntology.getDefaultNameSpace();
591       // to be compatible with KIM and OAT which have
592       // ontology feature without ending #
593       ontology = ontology.substring(0, ontology.length()-1);
594       features = Factory.newFeatureMap();
595       features.put(ONTOLOGY, ontology);
596       features.put(CLASS, selectedClass.getONodeID().toString());
597       features.put(INSTANCE, instance.getONodeID().toString());
598       // create a new annotation from the text selected
599       set.add((longstart, (longend, ANNOTATION_TYPE, features);
600     catch(InvalidOffsetException e) {
601       throw new LuckyException(e);
602     }
603     classView.setClassHighlighted(selectedClass, false);
604     classView.setClassHighlighted(selectedClass, true);
605 //    classView.selectInstance(set, set.get(id), selectedClass);
606     updateInstanceTable(selectedClass);
607   }
608 
609   /**
610    * Select an instance in the instance table if it exists..
611    @param oInstance instance to be selected
612    */
613   public void selectInstance(OInstance oInstance) {
614     for (int row = 0; row < instanceTable.getRowCount(); row++) {
615       if (oInstance.getONodeID().toString().endsWith(
616         (StringinstanceTable.getValueAt(row, 0))) {
617         int rowModel = instanceTable.rowViewToModel(row);
618         instanceTable.getSelectionModel()
619           .setSelectionInterval(rowModel, rowModel);
620         break;
621       }
622     }
623   }
624 
625   protected class PropertyValueCellEditor extends AbstractCellEditor
626       implements TableCellEditor, ActionListener {
627     private JComboBox<String> valueComboBox;
628     private Collator comparator;
629     private String oldValue;
630     private Map<String, OInstance> nameInstanceMap;
631     private Pattern instanceLabelsPattern;
632 
633     private PropertyValueCellEditor() {
634       valueComboBox = new JComboBox<String>();
635       valueComboBox.setMaximumRowCount(10);
636       valueComboBox.addActionListener(this);
637       comparator = Collator.getInstance();
638       comparator.setStrength(java.text.Collator.TERTIARY);
639       nameInstanceMap = new HashMap<String, OInstance>();
640       instanceLabelsPattern = Pattern.compile("^(.+) \\[.*\\]$");
641     }
642 
643     @Override
644     public Component getTableCellEditorComponent(JTable table, Object value,
645         boolean isSelected, int row, int column) {
646       oldValue = (Stringvalue;
647       TreeSet<String> ts = new TreeSet<String>(comparator);
648       Set<OClass> classes = classesByPropertyMap.get(propertyTable.getModel().getValueAt(row, 0));
649       if (classes.isEmpty()) { classes = selectedOntology.getOClasses(false)}
650       for (OClass oClass : classes) {
651         // get all the classes that belong to the property domain
652         Set<OInstance> instances = selectedOntology.getOInstances(
653           oClass, OConstants.Closure.TRANSITIVE_CLOSURE);
654         for (OInstance instance : instances) {
655           Set<String> labelSet = new HashSet<String>();
656           Set<AnnotationProperty> properties =
657             instance.getSetAnnotationProperties();
658           for (AnnotationProperty property : properties) {
659             if (property.getName().equals("label")) {
660               List<Literal> labels =
661                 instance.getAnnotationPropertyValues(property);
662               for (Literal label : labels) {
663                 labelSet.add(label.getValue());
664               }
665             }
666           }
667           // for each class add their instance names and labels list
668           ts.add(instance.getName() " " + Strings.toString(labelSet));
669           nameInstanceMap.put(instance.getName(), instance);
670         }
671       }
672       DefaultComboBoxModel<String> dcbm = new DefaultComboBoxModel<String>(ts.toArray(new String[ts.size()]));
673       valueComboBox.setModel(dcbm);
674       valueComboBox.setSelectedItem(propertyTable.getValueAt(row, column));
675       return valueComboBox;
676     }
677 
678     @Override
679     public Object getCellEditorValue() {
680       return valueComboBox.getSelectedItem();
681     }
682 
683     @Override
684     protected void fireEditingStopped() {
685       String newValue = (StringgetCellEditorValue();
686       if (newValue == null) {
687         fireEditingCanceled();
688         return;
689       }
690       Matcher matcher = instanceLabelsPattern.matcher(newValue);
691       // remove the list of labels from the selected instance value
692       if (matcher.matches()) { newValue = matcher.group(1)}
693       super.fireEditingStopped();
694       String selectedProperty = (StringpropertyTable.getModel().getValueAt(
695         propertyTable.getSelectedRow()0);
696       // search the object property to set
697       for (ObjectProperty objectProperty : setProperties) {
698         // verify that the property value correspond
699         if (objectProperty.getName().equals(selectedProperty)) {
700           for (OInstance oInstance :
701                selectedInstance.getObjectPropertyValues(objectProperty)) {
702             String value = oInstance.getONodeID().getResourceName();
703             if (value.equals(oldValue)) {
704               // property already existing, remove it first
705               selectedInstance.removeObjectPropertyValue(
706                 objectProperty, oInstance);
707                 try {
708                   // set the new value for the selected object property
709                   selectedInstance.addObjectPropertyValue(
710                     objectProperty, nameInstanceMap.get(newValue));
711                 catch (InvalidValueException e) {
712                   e.printStackTrace();
713                 }
714               updatePropertyTable();
715               return;
716             }
717           }
718         }
719       }
720       for (ObjectProperty objectProperty : properties) {
721         if (objectProperty.getName().equals(selectedProperty)) {
722           try {
723             // set the new value for the selected object property
724               selectedInstance.addObjectPropertyValue(
725                 objectProperty, nameInstanceMap.get(newValue));
726           catch (InvalidValueException e) {
727             e.printStackTrace();
728           }
729           updatePropertyTable();
730           return;
731         }
732       }
733     }
734 
735     // TODO: itemlistener may be better
736     @Override
737     public void actionPerformed(ActionEvent e) {
738       if (getCellEditorValue() == null) {
739         fireEditingCanceled();
740       else {
741         fireEditingStopped();
742       }
743     }
744   }
745 
746   protected class ShowInstanceInOntologyEditorAction extends AbstractAction {
747     public ShowInstanceInOntologyEditorAction() {
748       super("Show In Ontology Editor");
749     }
750 
751     @Override
752     public void actionPerformed(ActionEvent event) {
753       // show the ontology editor if not already displayed
754       SwingUtilities.invokeLater(new Runnable() { @Override
755       public void run() {
756         final Handle handle = MainFrame.getInstance().select(selectedOntology);
757         if (handle == null) { return}
758         // wait some time for the ontology editor to be displayed
759         Date timeToRun = new Date(System.currentTimeMillis() 1000);
760         Timer timer = new Timer("Ontology Instance View Timer"true);
761         timer.schedule(new TimerTask() { @Override
762         public void run() {
763           String instanceName = (StringinstanceTable.getModel()
764             .getValueAt(instanceTable.getSelectedRow()0);
765           for (OInstance oInstance : instances) {
766             if (oInstance.getName().equals(instanceName)) {
767               // found the corresponding instance in the ontology
768               JComponent largeView = handle.getLargeView();
769               if (largeView != null
770               && largeView instanceof JTabbedPane
771               && ((JTabbedPane)largeView).getSelectedComponent() != null) {
772                   ((OntologyEditor) ((JTabbedPanelargeView)
773                     .getSelectedComponent())
774                       .selectResourceInClassTree(oInstance);
775               }
776               break;
777             }
778           }
779         }}, timeToRun);
780       }});
781     }
782   }
783 
784   protected class DeleteSelectedInstanceAction extends AbstractAction {
785     public DeleteSelectedInstanceAction() {
786       super(instanceTable.getSelectedRowCount() ?
787         "Delete instances" "Delete instance");
788       putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("shift DELETE"));
789     }
790 
791     @Override
792     public void actionPerformed(ActionEvent e) {
793       String ontology = selectedOntology.getDefaultNameSpace();
794       ontology = ontology.substring(0, ontology.length()-1);
795       for (OInstance oInstance : instances) {
796         for (int selectedRow : instanceTable.getSelectedRows()) {
797           if (oInstance.getName().equals(
798               instanceTable.getModel().getValueAt(selectedRow, 0))) {
799             selectedOntology.removeOInstance(oInstance);
800             // find annotations related to this instance
801             AnnotationSet annotationSet =
802               document.getAnnotations(classView.getSelectedSet());
803             for (Annotation annotation :
804               annotationSet.get(ANNOTATION_TYPE)) {
805               if (annotation.getFeatures().containsKey(ONTOLOGY)
806               && annotation.getFeatures().get(ONTOLOGY)
807                 .equals(ontology)
808               && annotation.getFeatures().containsKey(CLASS)
809               && annotation.getFeatures().get(CLASS)
810                 .equals(selectedClass.getONodeID().toString())
811               && annotation.getFeatures().containsKey(INSTANCE)
812               && annotation.getFeatures().get(INSTANCE)
813                 .equals(oInstance.getONodeID().toString())) {
814                 // delete the annotation
815                 annotationSet.remove(annotation);
816               }
817             }
818           }
819         }
820       }
821       classView.setClassHighlighted(selectedClass, false);
822       classView.setClassHighlighted(selectedClass, true);
823       updateInstanceTable(selectedClass);
824     }
825   }
826 
827   protected class DeleteSelectedPropertyAction extends AbstractAction {
828     public DeleteSelectedPropertyAction() {
829       super(propertyTable.getSelectedRowCount() ?
830         "Delete properties" "Delete property");
831       putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("shift DELETE"));
832     }
833 
834     @Override
835     public void actionPerformed(ActionEvent e) {
836       for (ObjectProperty objectProperty : setProperties) {
837         for (int selectedRow : propertyTable.getSelectedRows()) {
838           // find the property that matches the first column value
839           if (objectProperty.getName().equals(
840               propertyTable.getModel().getValueAt(selectedRow, 0))) {
841             for (OInstance oInstance : selectedInstance
842                 .getObjectPropertyValues(objectProperty)) {
843               String value = oInstance.getONodeID()
844                 .getResourceName();
845               // find the value that matches the second column value
846               if (value.equals(propertyTable.getModel()
847                   .getValueAt(selectedRow, 1))) {
848                 // delete the property
849                 selectedInstance.removeObjectPropertyValue(
850                   objectProperty, oInstance);
851                 break;
852               }
853             }
854           }
855         }
856       }
857       updatePropertyTable();
858     }
859   }
860 
861   // external resources
862   protected Ontology selectedOntology;
863   protected TextualDocumentView textView;
864   protected OntologyClassView classView;
865 
866   // UI components
867   protected JPanel mainPanel;
868   protected JTextField filterTextField;
869   protected JButton clearFilterButton;
870   protected JLabel hiddenInstancesLabel;
871   protected JButton newInstanceButton;
872   protected JButton addLabelButton;
873   protected XJTable instanceTable;
874   protected XJTable propertyTable;
875 
876   // local objects
877   /** Class that has the lead selection in the focused tree. */
878   protected OClass selectedClass;
879   /** Instance selected in the instance table. */
880   protected OInstance selectedInstance;
881   /** Instances in the instance table for the selected class and filter. */
882   protected Set<OInstance> instances;
883   /** Properties set in the property table for the selected class and filter. */
884   protected Set<ObjectProperty> setProperties;
885   /** Properties in the instance table for the selected class and filter. */
886   protected Set<ObjectProperty> properties;
887   protected Map<String, Set<OClass>> classesByPropertyMap;
888 
889   // constants for annotation feature, annotation type
890   protected static final String ONTOLOGY =
891     gate.creole.ANNIEConstants.LOOKUP_ONTOLOGY_FEATURE_NAME;
892   protected static final String CLASS =
893     gate.creole.ANNIEConstants.LOOKUP_CLASS_FEATURE_NAME;
894   protected static final String INSTANCE =
895     gate.creole.ANNIEConstants.LOOKUP_INSTANCE_FEATURE_NAME;
896   protected static final String ANNOTATION_TYPE = "Mention";
897 }