001 /*
002 * Copyright (c) 2009-2010, Ontotext AD.
003 * Copyright (c) 1995-2010, The University of Sheffield. See the file
004 * COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
005 *
006 * This file is part of GATE (see http://gate.ac.uk/), and is free
007 * software, licenced under the GNU Library General Public License,
008 * Version 2, June 1991 (in the distribution as file licence.html,
009 * and also available at http://gate.ac.uk/gate/licence.html).
010 *
011 * AnnotatioListView.java
012 *
013 * Valentin Tablan, May 25, 2004
014 *
015 * $Id: AnnotationListView.java 13614 2011-04-05 14:24:31Z valyt $
016 */
017
018 package gate.gui.docview;
019
020 import gate.*;
021 import gate.creole.*;
022 import gate.event.AnnotationEvent;
023 import gate.event.AnnotationListener;
024 import gate.gui.MainFrame;
025 import gate.gui.annedit.*;
026 import gate.swing.XJTable;
027 import gate.util.*;
028 import java.awt.*;
029 import java.awt.event.*;
030 import java.util.*;
031 import java.util.List;
032 import java.util.Timer;
033 import javax.swing.*;
034 import javax.swing.event.*;
035 import javax.swing.table.AbstractTableModel;
036 import javax.swing.text.JTextComponent;
037
038 /**
039 * A tabular view for a list of annotations.
040 * Used as part of the document viewer to display all the annotation currently
041 * highlighted.
042 */
043 public class AnnotationListView extends AbstractDocumentView
044 implements AnnotationListener, AnnotationList, AnnotationEditorOwner{
045
046 public AnnotationListView(){
047 annDataList = new ArrayList<AnnotationData>();
048 editorsCache = new HashMap<String, AnnotationVisualResource>();
049 }
050
051
052 /**
053 * (non-Javadoc)
054 * @see gate.gui.docview.AnnotationList#getAnnotationAtRow(int)
055 */
056 public AnnotationData getAnnotationAtRow(int row) {
057 return annDataList == null ? null : annDataList.get(
058 table.rowViewToModel(row));
059 }
060
061
062 /* (non-Javadoc)
063 * @see gate.gui.docview.AnnotationList#getSelectionModel()
064 */
065 public ListSelectionModel getSelectionModel() {
066 return table == null ? null : table.getSelectionModel();
067 }
068
069
070 @Override
071 public void cleanup() {
072 super.cleanup();
073 for(AnnotationData aData : annDataList){
074 aData.getAnnotation().removeAnnotationListener(this);
075 }
076 annDataList.clear();
077 textView = null;
078 }
079
080 /* (non-Javadoc)
081 * @see gate.gui.docview.AbstractDocumentView#initGUI()
082 */
083 protected void initGUI() {
084 tableModel = new AnnotationTableModel();
085 table = new XJTable(tableModel);
086 table.setAutoResizeMode(XJTable.AUTO_RESIZE_LAST_COLUMN);
087 table.setSortable(true);
088 table.setSortedColumn(START_COL);
089 table.setIntercellSpacing(new Dimension(2, 0));
090 table.setEnableHidingColumns(true);
091 scroller = new JScrollPane(table);
092
093 mainPanel = new JPanel();
094 mainPanel.setLayout(new GridBagLayout());
095 GridBagConstraints constraints = new GridBagConstraints();
096
097 constraints.gridx = 0;
098 constraints.gridwidth = 4;
099 constraints.gridy = 0;
100 constraints.weightx = 1;
101 constraints.weighty = 1;
102 constraints.fill= GridBagConstraints.BOTH;
103 mainPanel.add(scroller, constraints);
104
105 constraints.gridx = GridBagConstraints.RELATIVE;
106 constraints.gridwidth = 1;
107 constraints.gridy = 1;
108 constraints.weightx = 0;
109 constraints.weighty = 0;
110 constraints.fill= GridBagConstraints.NONE;
111 constraints.anchor = GridBagConstraints.WEST;
112 statusLabel = new JLabel();
113 mainPanel.add(statusLabel, constraints);
114 constraints.fill= GridBagConstraints.HORIZONTAL;
115 constraints.anchor = GridBagConstraints.EAST;
116 mainPanel.add(Box.createHorizontalStrut(10), constraints);
117 mainPanel.add(new JLabel("Select: "), constraints);
118 filterTextField = new JTextField(20);
119 filterTextField.setToolTipText("Select the rows containing this text.");
120 mainPanel.add(filterTextField, constraints);
121
122 //get a pointer to the text view used to display
123 //the selected annotations
124 Iterator centralViewsIter = owner.getCentralViews().iterator();
125 while(textView == null && centralViewsIter.hasNext()){
126 DocumentView aView = (DocumentView)centralViewsIter.next();
127 if(aView instanceof TextualDocumentView)
128 textView = (TextualDocumentView)aView;
129 }
130
131 initListeners();
132 }
133
134 public Component getGUI(){
135 return mainPanel;
136 }
137
138 protected void initListeners(){
139
140 tableModel.addTableModelListener(new TableModelListener(){
141 public void tableChanged(TableModelEvent e){
142 statusLabel.setText(
143 Integer.toString(tableModel.getRowCount()) +
144 " Annotations (" +
145 Integer.toString(table.getSelectedRowCount()) +
146 " selected)");
147 }
148 });
149
150 table.getSelectionModel().
151 addListSelectionListener(new ListSelectionListener(){
152 public void valueChanged(ListSelectionEvent e){
153 if(!isActive())return;
154 if(e.getValueIsAdjusting()) return;
155 statusLabel.setText(
156 Integer.toString(tableModel.getRowCount()) +
157 " Annotations (" +
158 Integer.toString(table.getSelectedRowCount()) +
159 " selected)");
160 //if the new selection is already known about, no more work to do
161 if(localSelectionUpdating) return;
162 //update the list of selected annotations globally
163 int[] viewRows = table.getSelectedRows();
164 List<AnnotationData> selAnns = new ArrayList<AnnotationData>();
165 for(int i = 0; i < viewRows.length; i++){
166 int modelRow = table.rowViewToModel(viewRows[i]);
167 if(modelRow >= 0){
168 selAnns.add(annDataList.get(modelRow));
169 }
170 }
171 owner.setSelectedAnnotations(selAnns);
172
173 if(table.getSelectedRowCount() >= 1){
174 int viewRow = table.getSelectionModel().getLeadSelectionIndex();
175 if(table.getSelectionModel().isSelectedIndex(viewRow)){
176 int modelRow = table.rowViewToModel(viewRow);
177 AnnotationData aHandler = annDataList.get(modelRow);
178 //scroll to show the last highlight
179 if(aHandler != null && aHandler.getAnnotation() != null)
180 textView.scrollAnnotationToVisible(aHandler.getAnnotation());
181 }else{
182 //last operation was a remove selection
183 //do nothing
184 }
185 }
186 }
187 });
188
189 table.addMouseListener(new MouseAdapter() {
190 public void mouseClicked(MouseEvent me) {
191 processMouseEvent(me);
192 }
193 public void mouseReleased(MouseEvent me) {
194 processMouseEvent(me);
195 }
196 public void mousePressed(MouseEvent me) {
197 int row = table.rowAtPoint(me.getPoint());
198 if(me.isPopupTrigger()
199 && !table.isRowSelected(row)) {
200 // if right click outside the selection then reset selection
201 table.getSelectionModel().setSelectionInterval(row, row);
202 }
203 processMouseEvent(me);
204 }
205 protected void processMouseEvent(MouseEvent me){
206 int viewRow = table.rowAtPoint(me.getPoint());
207 final int modelRow = viewRow == -1 ?
208 viewRow :
209 table.rowViewToModel(viewRow);
210
211 // popup menu
212 if(me.isPopupTrigger()) {
213 JPopupMenu popup = new JPopupMenu();
214 popup.add(new DeleteAction());
215
216 //add the custom edit actions
217 if(modelRow != -1){
218 AnnotationData aHandler = annDataList.get(modelRow);
219 popup.addSeparator();
220 List<Action> specificEditorActions = getSpecificEditorActions(
221 aHandler.getAnnotationSet(), aHandler.getAnnotation());
222 for (Action action : specificEditorActions) {
223 popup.add(action);
224 }
225 if (!(popup.getComponent(popup.getComponentCount()-1)
226 instanceof JSeparator)) {
227 popup.addSeparator();
228 }
229 for (Action action : getGenericEditorActions(
230 aHandler.getAnnotationSet(), aHandler.getAnnotation())) {
231 if (specificEditorActions.contains(action)) { continue; }
232 popup.add(action);
233 }
234 if ((popup.getComponent(popup.getComponentCount()-1)
235 instanceof JSeparator)) {
236 popup.remove(popup.getComponentCount()-1);
237 }
238 }
239 popup.show(table, me.getX(), me.getY());
240 }
241 }
242 });
243
244 table.addAncestorListener(new AncestorListener() {
245 public void ancestorAdded(AncestorEvent event) {
246 // force the table to be sorted when the view is shown
247 tableModel.fireTableDataChanged();
248 }
249 public void ancestorMoved(AncestorEvent event) {
250 }
251 public void ancestorRemoved(AncestorEvent event) {
252 }
253 });
254
255 // select all the rows containing the text from filterTextField
256 filterTextField.getDocument().addDocumentListener( new DocumentListener() {
257 private Timer timer = new Timer("Annotation list selection timer", true);
258 private TimerTask timerTask;
259 public void changedUpdate(DocumentEvent e) { /* do nothing */ }
260 public void insertUpdate(DocumentEvent e) { update(); }
261 public void removeUpdate(DocumentEvent e) { update(); }
262 private void update() {
263 if (timerTask != null) { timerTask.cancel(); }
264 Date timeToRun = new Date(System.currentTimeMillis() + 300);
265 timerTask = new TimerTask() { public void run() {
266 selectRows();
267 }};
268 // add a delay
269 timer.schedule(timerTask, timeToRun);
270 }
271 private void selectRows() {
272 table.clearSelection();
273 if (filterTextField.getText().trim().length() < 2
274 || table.getRowCount() == 0) {
275 return;
276 }
277 // block upward events
278 localSelectionUpdating = true;
279 for (int row = 0; row < table.getRowCount(); row++) {
280 for (int col = 0; col < table.getColumnCount(); col++) {
281 if (table.getValueAt(row, col) != null
282 && table.getValueAt(row, col).toString()
283 .contains(filterTextField.getText().trim())) {
284 table.addRowSelectionInterval(row, row);
285 break;
286 }
287 }
288 }
289 localSelectionUpdating = false;
290 // update the highlights in the document
291 if (table.isCellSelected(0,0)) {
292 table.addRowSelectionInterval(0, 0);
293 } else {
294 table.removeRowSelectionInterval(0, 0);
295 }
296 }
297 });
298
299 // Delete key for deleting selected annotations
300 table.addKeyListener(new KeyAdapter() {
301 public void keyPressed(KeyEvent e) {
302 if (e.getKeyCode() == KeyEvent.VK_DELETE) {
303 new DeleteAction().actionPerformed(new ActionEvent(e.getSource(),
304 e.getID(), "", e.getWhen(), e.getModifiers()));
305 }
306 }
307 });
308 }
309
310 public List<Action> getSpecificEditorActions(AnnotationSet set,
311 Annotation annotation) {
312 List<Action> actions = new ArrayList<Action>();
313 //add the specific editors
314 List<String> specificEditorClasses =
315 Gate.getCreoleRegister().getAnnotationVRs(annotation.getType());
316 if (specificEditorClasses != null &&
317 specificEditorClasses.size() > 0) {
318 for (String editorClass : specificEditorClasses) {
319 AnnotationVisualResource editor =
320 editorsCache.get(editorClass);
321 if (editor == null) {
322 //create the new type of editor
323 try {
324 editor = (AnnotationVisualResource)
325 Factory.createResource(editorClass);
326 editorsCache.put(editorClass, editor);
327 } catch (ResourceInstantiationException rie) {
328 rie.printStackTrace(Err.getPrintWriter());
329 }
330 }
331 actions.add(new EditAnnotationAction(set, annotation, editor));
332 }
333 }
334 return actions;
335 }
336
337 public List<Action> getGenericEditorActions(AnnotationSet set,
338 Annotation annotation) {
339 List<Action> actions = new ArrayList<Action>();
340 //add generic editors
341 List<String> genericEditorClasses = Gate.getCreoleRegister().
342 getAnnotationVRs();
343 if (genericEditorClasses != null &&
344 genericEditorClasses.size() > 0) {
345 for (String editorClass : genericEditorClasses) {
346 AnnotationVisualResource editor = editorsCache.get(editorClass);
347 if (editor == null) {
348 //create the new type of editor
349 try {
350 ResourceData resData = Gate.getCreoleRegister().get(editorClass);
351 Class<?> resClass = resData.getResourceClass();
352 if (OwnedAnnotationEditor.class.isAssignableFrom(resClass)) {
353 OwnedAnnotationEditor newEditor =
354 (OwnedAnnotationEditor) resClass.newInstance();
355 newEditor.setOwner(AnnotationListView.this);
356 newEditor.init();
357 editor = newEditor;
358 } else {
359 editor = (AnnotationVisualResource)
360 Factory.createResource(editorClass);
361 }
362 editorsCache.put(editorClass, editor);
363 } catch (Exception rie) {
364 rie.printStackTrace(Err.getPrintWriter());
365 }
366 }
367 actions.add(new EditAnnotationAction(set, annotation, editor));
368 }
369 }
370 return actions;
371 }
372
373 protected class DeleteAction extends AbstractAction {
374 public DeleteAction() {
375 super("Delete Annotations");
376 putValue(SHORT_DESCRIPTION, "Delete selected annotations");
377 putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("DELETE"));
378 }
379 public void actionPerformed(ActionEvent event){
380 if ((event.getModifiers() & ActionEvent.SHIFT_MASK)
381 != ActionEvent.SHIFT_MASK
382 && (event.getModifiers() & InputEvent.BUTTON1_MASK)
383 != InputEvent.BUTTON1_MASK) {
384 // shows a confirm dialog before to delete annotations
385 int choice = JOptionPane.showOptionDialog(MainFrame.getInstance(), new
386 Object[]{"Are you sure you want to delete the "
387 + table.getSelectedRowCount() + " selected annotations?",
388 "<html><i>You can use Shift+Delete to bypass this dialog.</i>\n\n"},
389 "Delete annotations",
390 JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null,
391 new String[]{"Delete annotations", "Cancel"}, "Cancel");
392 if (choice == JOptionPane.CLOSED_OPTION || choice == 1) { return; }
393 }
394 List<AnnotationData> annotationsData = new ArrayList<AnnotationData>();
395 for (int selectedRow : table.getSelectedRows()) {
396 annotationsData.add(annDataList.get(table.rowViewToModel(selectedRow)));
397 }
398 for (AnnotationData annotationData : annotationsData) {
399 annotationData.getAnnotationSet().remove(annotationData.getAnnotation());
400 }
401 }
402 }
403
404 /* (non-Javadoc)
405 * @see gate.gui.docview.AbstractDocumentView#registerHooks()
406 */
407 protected void registerHooks() {
408 //this is called on activation
409 // showHighlights();
410 }
411
412 /* (non-Javadoc)
413 * @see gate.gui.docview.AbstractDocumentView#unregisterHooks()
414 */
415 protected void unregisterHooks() {
416 //this is called on de-activation
417 //remove highlights
418 // textView.removeAllBlinkingHighlights();
419 }
420
421 /* (non-Javadoc)
422 * @see gate.gui.docview.DocumentView#getType()
423 */
424 public int getType() {
425 return HORIZONTAL;
426 }
427
428 // protected void showHighlights(){
429 // int[] viewRows = table.getSelectedRows();
430 // AnnotationData aHandler = null;
431 // for(int i = 0; i < viewRows.length; i++){
432 // int modelRow = table.rowViewToModel(viewRows[i]);
433 // if(modelRow >= 0){
434 // aHandler = annDataList.get(modelRow);
435 // textView.addBlinkingHighlight(aHandler.getAnnotation());
436 // }
437 // }
438 // }
439
440
441 /**
442 * Adds an annotation to be displayed in the list.
443 * @param ann the annotation
444 * @param set the set containing the annotation
445 * @return a tag that can be used to refer to this annotation for future
446 * operations, e.g. when removing the annotation from display.
447 */
448 public AnnotationDataImpl addAnnotation(Annotation ann, AnnotationSet set){
449 AnnotationDataImpl aData = new AnnotationDataImpl(set, ann);
450 annDataList.add(aData);
451 int row = annDataList.size() -1;
452 try{
453 localSelectionUpdating = true;
454 if(tableModel != null) tableModel.fireTableRowsInserted(row, row);
455 }finally{
456 localSelectionUpdating = false;
457 }
458
459 //listen for the new annotation's events
460 aData.getAnnotation().addAnnotationListener(AnnotationListView.this);
461 return aData;
462 }
463
464 public void removeAnnotation(AnnotationData tag){
465 int row = annDataList.indexOf(tag);
466 if(row >= 0){
467 AnnotationData aHandler = annDataList.get(row);
468 //remove from selection, if the table is built
469 List<AnnotationData> selAnns = owner.getSelectedAnnotations();
470 if(selAnns.remove(tag)){
471 owner.setSelectedAnnotations(selAnns);
472 }
473 aHandler.getAnnotation().removeAnnotationListener(
474 AnnotationListView.this);
475 annDataList.remove(row);
476 //owner was already notified
477 try{
478 localSelectionUpdating = true;
479 if(tableModel != null) tableModel.fireTableRowsDeleted(row, row);
480 }finally{
481 localSelectionUpdating = false;
482 }
483 }
484 }
485
486 public void removeAnnotations(Collection<AnnotationData> tags){
487 //to speed-up things, first remove all blinking highlights
488 if(table != null){
489 table.getSelectionModel().clearSelection();
490 }
491 //cache the selected annotations
492 final List<AnnotationData> selAnns = owner.getSelectedAnnotations();
493 boolean selectionChanged = false;
494 //now do the actual removal, in batch mode
495 for(AnnotationData aData : tags){
496 annDataList.remove(aData);
497 if(selAnns.remove(aData)){
498 selectionChanged = true;
499 }
500 aData.getAnnotation().removeAnnotationListener(AnnotationListView.this);
501 }
502 //update the table display
503 if(tableModel != null) tableModel.fireTableDataChanged();
504 //restore selection
505 if(selectionChanged){
506 //this needs to happen after the table has caught up with all the changes
507 //hence we need to queue it to the GUI thread
508 SwingUtilities.invokeLater(new Runnable(){
509 public void run(){
510 owner.setSelectedAnnotations(selAnns);
511 }});
512 }
513 }
514
515 /**
516 * Adds a batch of annotations in one go.
517 * For each annotation, a tag object will be created. The return value is
518 * list that returns the tags in the same order as the collection used
519 * for the input annotations.
520 * This method does not assume it was called from the UI Thread.
521 * @return a collection of tags corresponding to the annotations.
522 * @param annotations a collection of annotations
523 * @param set the annotation set to which all the annotations belong.
524 */
525 public List<AnnotationData> addAnnotations(List<Annotation> annotations,
526 AnnotationSet set){
527 List<AnnotationData> tags = new ArrayList<AnnotationData>();
528 for(Annotation ann : annotations){
529 AnnotationData aTag = new AnnotationDataImpl(set, ann);
530 tags.add(aTag);
531 annDataList.add(aTag);
532 ann.addAnnotationListener(AnnotationListView.this);
533 }
534 try{
535 //this will cause the selection to change (the actual selection contents
536 //stay the same, but the row numbers may change)
537 //we want to avoid circular notifications.
538 localSelectionUpdating = true;
539 if(tableModel != null) tableModel.fireTableDataChanged();
540 }finally{
541 localSelectionUpdating = false;
542 }
543 return tags;
544 }
545
546 /**
547 * Returns the tags for all the annotations currently displayed
548 * @return a list of {@link AnnotationDataImpl}.
549 */
550 public List<AnnotationData> getAllAnnotations(){
551 return annDataList;
552 }
553
554 public void annotationUpdated(AnnotationEvent e){
555 //update all occurrences of this annotation
556 // if annotations tab has not been set to visible state
557 // table will be null.
558 if(table == null) return;
559 //save selection
560 int[] selection = table.getSelectedRows();
561 if(selection != null){
562 localSelectionUpdating = true;
563 }
564 Annotation ann = (Annotation)e.getSource();
565 if(tableModel != null){
566 for(int i = 0; i < annDataList.size(); i++){
567 AnnotationData aHandler = annDataList.get(i);
568 if(aHandler.getAnnotation() == ann)tableModel.fireTableRowsUpdated(i, i);
569 }
570 }
571 //restore selection
572 table.clearSelection();
573 if(selection != null){
574 localSelectionUpdating = true;
575 for(int i = 0; i < selection.length; i++){
576 table.addRowSelectionInterval(selection[i], selection[i]);
577 }
578 localSelectionUpdating = false;
579 }
580 }
581
582
583 /* (non-Javadoc)
584 * @see gate.gui.docview.AbstractDocumentView#setSelectedAnnotations(java.util.List)
585 */
586 @Override
587 public void setSelectedAnnotations(final List<AnnotationData> selectedAnnots) {
588 //if the list of selected annotations differs from the current selection,
589 //update the selection.
590 //otherwise do nothing (to break infinite looping)
591
592 //first get the local list of selected annotations
593 int[] viewRows = table.getSelectedRows();
594 List<AnnotationData> localSelAnns = new ArrayList<AnnotationData>();
595 for (int viewRow : viewRows) {
596 int modelRow = table.rowViewToModel(viewRow);
597 if (modelRow >= 0) {
598 localSelAnns.add(annDataList.get(modelRow));
599 }
600 }
601 //now compare with the new value
602 if(localSelAnns.size() == selectedAnnots.size()){
603 //same size, we need to actually compare contents
604 localSelAnns.removeAll(selectedAnnots);
605 if(localSelAnns.isEmpty()){
606 //lists are the same -> exit!
607 return;
608 }
609 }
610 //if we got this far, the selection lists were different
611 //we need to change the selection from the UI thread.
612 SwingUtilities.invokeLater(new Runnable(){
613 public void run(){
614 try{
615 //block upward events
616 localSelectionUpdating = true;
617 //update the local selection
618 table.getSelectionModel().clearSelection();
619 int rowToScrollTo = -1;
620 for(AnnotationData aData : selectedAnnots){
621 int modelRow = annDataList.indexOf(aData);
622 if(modelRow != -1){
623 int viewRow = table.rowModelToView(modelRow);
624 table.getSelectionModel().addSelectionInterval(viewRow, viewRow);
625 rowToScrollTo = viewRow;
626 }
627 }
628 if(rowToScrollTo >= 0){
629 table.scrollRectToVisible(table.getCellRect(rowToScrollTo, 0, true));
630 }
631 }finally{
632 //re-enable upward events
633 localSelectionUpdating = false;
634 }
635 }
636 });
637 }
638
639
640 /**
641 * Selects the annotation for the given tag.
642 * @param tag the tag of the annotation to be selected.
643 */
644 public void selectAnnotationForTag(Object tag){
645 int modelPosition = annDataList.indexOf(tag);
646 table.getSelectionModel().clearSelection();
647 if(modelPosition != -1){
648 int tablePosition = table.rowModelToView(modelPosition);
649 table.getSelectionModel().setSelectionInterval(tablePosition,
650 tablePosition);
651 table.scrollRectToVisible(table.getCellRect(tablePosition, 0, false));
652 }
653 }
654
655
656
657 /* (non-Javadoc)
658 * @see gate.gui.annedit.AnnotationEditorOwner#annotationChanged(gate.Annotation, gate.AnnotationSet, java.lang.String)
659 */
660 public void annotationChanged(Annotation ann, AnnotationSet set,
661 String oldType) {
662 //do nothing
663 }
664
665 /* (non-Javadoc)
666 * @see gate.gui.annedit.AnnotationEditorOwner#getNextAnnotation()
667 */
668 public Annotation getNextAnnotation() {
669 return null;
670 }
671
672
673 /* (non-Javadoc)
674 * @see gate.gui.annedit.AnnotationEditorOwner#getPreviousAnnotation()
675 */
676 public Annotation getPreviousAnnotation() {
677 return null;
678 }
679
680
681 /* (non-Javadoc)
682 * @see gate.gui.annedit.AnnotationEditorOwner#getTextComponent()
683 */
684 public JTextComponent getTextComponent() {
685 //get a pointer to the text view used to display
686 //the selected annotations
687 Iterator centralViewsIter = owner.getCentralViews().iterator();
688 while(textView == null && centralViewsIter.hasNext()){
689 DocumentView aView = (DocumentView)centralViewsIter.next();
690 if(aView instanceof TextualDocumentView)
691 textView = (TextualDocumentView)aView;
692 }
693 return (JTextArea)((JScrollPane)textView.getGUI()).getViewport().getView();
694 }
695
696 /* (non-Javadoc)
697 * @see gate.gui.annedit.AnnotationEditorOwner#selectAnnotation(gate.gui.annedit.AnnotationData)
698 */
699 public void selectAnnotation(AnnotationData data) {
700 }
701
702 /* (non-Javadoc)
703 * @see gate.gui.docview.AnnotationList#getRowForAnnotation(gate.gui.annedit.AnnotationData)
704 */
705 public int getRowForAnnotation(AnnotationData data) {
706 return annDataList.indexOf(data);
707 }
708
709 class AnnotationTableModel extends AbstractTableModel{
710 public int getRowCount(){
711 return annDataList.size();
712 }
713
714 public int getColumnCount(){
715 return 6;
716 }
717
718 public String getColumnName(int column){
719 switch(column){
720 case TYPE_COL: return "Type";
721 case SET_COL: return "Set";
722 case START_COL: return "Start";
723 case END_COL: return "End";
724 case ID_COL: return "Id";
725 case FEATURES_COL: return "Features";
726 default: return "?";
727 }
728 }
729
730 public Class getColumnClass(int column){
731 switch(column){
732 case TYPE_COL: return String.class;
733 case SET_COL: return String.class;
734 case START_COL: return Long.class;
735 case END_COL: return Long.class;
736 case ID_COL: return Integer.class;
737 case FEATURES_COL: return String.class;
738 default: return String.class;
739 }
740 }
741
742 public boolean isCellEditable(int rowIndex, int columnIndex){
743 return false;
744 }
745
746 public Object getValueAt(int row, int column){
747 if(row >= annDataList.size()) return null;
748 AnnotationData aData = annDataList.get(row);
749 switch(column){
750 case TYPE_COL: return aData.getAnnotation().getType();
751 case SET_COL: return aData.getAnnotationSet().getName();
752 case START_COL: return aData.getAnnotation().getStartNode().getOffset();
753 case END_COL: return aData.getAnnotation().getEndNode().getOffset();
754 case ID_COL: return aData.getAnnotation().getId();
755 case FEATURES_COL:
756 //sort the features by name
757 FeatureMap features = aData.getAnnotation().getFeatures();
758 List keyList = new ArrayList(features.keySet());
759 Collections.sort(keyList);
760 StringBuffer strBuf = new StringBuffer("{");
761 Iterator keyIter = keyList.iterator();
762 boolean first = true;
763 while(keyIter.hasNext()){
764 Object key = keyIter.next();
765 Object value = features.get(key);
766 if(first){
767 first = false;
768 }else{
769 strBuf.append(", ");
770 }
771 strBuf.append(key.toString());
772 strBuf.append("=");
773 strBuf.append(value == null ? "[null]" : value.toString());
774 }
775 strBuf.append("}");
776 return strBuf.toString();
777 default: return "?";
778 }
779 }
780
781 }
782
783
784 protected class EditAnnotationAction extends AbstractAction{
785 public EditAnnotationAction(AnnotationSet set, Annotation ann,
786 AnnotationVisualResource editor){
787 this.set = set;
788 this.ann = ann;
789 this.editor = editor;
790 ResourceData rData =
791 Gate.getCreoleRegister().get(editor.getClass().getName());
792 if(rData != null){
793 title = rData.getName();
794 putValue(NAME, "Edit with " + title);
795 putValue(SHORT_DESCRIPTION, rData.getComment());
796 }
797 }
798
799 public void actionPerformed(ActionEvent evt){
800 // editor.setTarget(set);
801 // editor.setAnnotation(ann);
802 if(editor instanceof OwnedAnnotationEditor){
803 //we need to unpin the editor so that it actually calculates the
804 //position
805 ((OwnedAnnotationEditor)editor).setPinnedMode(false);
806 ((OwnedAnnotationEditor)editor).placeDialog(
807 ann.getStartNode().getOffset().intValue(),
808 ann.getEndNode().getOffset().intValue());
809 //now we need to pin it so that it does not disappear automatically
810 ((OwnedAnnotationEditor)editor).setPinnedMode(true);
811 editor.editAnnotation(ann, set);
812 }else{
813 editor.editAnnotation(ann, set);
814 JScrollPane scroller = new JScrollPane((Component)editor);
815 JOptionPane optionPane = new JOptionPane(scroller,
816 JOptionPane.QUESTION_MESSAGE,
817 JOptionPane.OK_CANCEL_OPTION,
818 null, new String[]{"OK", "Cancel"});
819 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
820 scroller.setMaximumSize(new Dimension((int)(screenSize.width * .75),
821 (int)(screenSize.height * .75)));
822 JDialog dialog = optionPane.createDialog(AnnotationListView.this.getGUI(),
823 title);
824 dialog.setModal(true);
825 dialog.setResizable(true);
826 dialog.setVisible(true);
827 try{
828 if(optionPane.getValue().equals("OK")) editor.okAction();
829 else editor.cancelAction();
830 }catch(GateException ge){
831 throw new GateRuntimeException(ge);
832 }
833
834 }
835
836 }
837
838 String title;
839 Annotation ann;
840 AnnotationSet set;
841 AnnotationVisualResource editor;
842 }
843
844 protected XJTable table;
845 protected AnnotationTableModel tableModel;
846 protected JScrollPane scroller;
847
848 /**
849 * Stores the {@link AnnotationData} objects representing the annotations
850 * displayed by this view.
851 */
852 protected List<AnnotationData> annDataList;
853
854 /**
855 * Flag used to mark the fact that the table selection is currently being
856 * updated, to synchronise it with the global selection.
857 * This is used to block update events being sent to the owner, while the
858 * current selection is adjusted.
859 */
860 protected volatile boolean localSelectionUpdating = false;
861
862 protected JPanel mainPanel;
863 protected JLabel statusLabel;
864 protected JTextField filterTextField;
865 protected TextualDocumentView textView;
866 /**
867 * A map that stores instantiated annotations editors in order to avoid the
868 * delay of building them at each request;
869 */
870 protected Map<String, AnnotationVisualResource> editorsCache;
871
872 private static final int TYPE_COL = 0;
873 private static final int SET_COL = 1;
874 private static final int START_COL = 2;
875 private static final int END_COL = 3;
876 private static final int ID_COL = 4;
877 private static final int FEATURES_COL = 5;
878
879 }
|