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