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 = (DocumentView) centralViewsIter.next();
075 if(aView instanceof TextualDocumentView)
076 textView = (TextualDocumentView) aView;
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 = (OntologyClassView) aView;
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(1, 2));
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 = (JTable) evt.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 = (JTable) evt.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 = (JTable) evt.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 = (JTable) evt.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(0, 0);
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 = (String) instanceTable.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((ObjectProperty) property);
399 Set<String> ranges = new HashSet<String>();
400 Set<OClass> rangeClasses = new HashSet<OClass>();
401 for (OResource range :
402 ((ObjectProperty) property).getRange()) {
403 ranges.add(range.getName());
404 rangeClasses.add((OClass) range);
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(252, 252, 176));
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(252, 252, 176));
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 = (AnnotationProperty) property;
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(0, 100);
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((long) start, (long) end, 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 (String) instanceTable.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 = (String) value;
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 = (String) getCellEditorValue();
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 = (String) propertyTable.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 = (String) instanceTable.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) ((JTabbedPane) largeView)
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() > 1 ?
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() > 1 ?
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 }
|