1
15
16 package gate.gui.docview;
17
18 import gate.*;
19 import gate.Annotation;
20 import gate.AnnotationSet;
21 import gate.creole.*;
22 import gate.creole.AnnotationVisualResource;
23 import gate.event.AnnotationEvent;
24 import gate.event.AnnotationListener;
25 import gate.gui.ResizableVisualResource;
26 import gate.swing.XJTable;
27 import gate.util.*;
28 import gate.util.Err;
29 import gate.util.GateRuntimeException;
30 import java.awt.*;
31 import java.awt.Component;
32 import java.awt.GridBagLayout;
33 import java.awt.event.*;
34 import java.util.*;
35 import java.util.List;
36 import java.util.Map;
37 import javax.swing.*;
38 import javax.swing.JScrollPane;
39 import javax.swing.SwingUtilities;
40 import javax.swing.event.*;
41 import javax.swing.event.TableModelEvent;
42 import javax.swing.event.TableModelListener;
43 import javax.swing.table.AbstractTableModel;
44
45
50 public class AnnotationListView extends AbstractDocumentView
51 implements AnnotationListener{
52 public AnnotationListView(){
53 tagList = new ArrayList();
54 annotationHandlerByTag = new HashMap();
55 }
56
57
60 protected void initGUI() {
61 editorsCache = new HashMap();
62 tableModel = new AnnotationTableModel();
63 table = new XJTable(tableModel);
64 table.setAutoResizeMode(XJTable.AUTO_RESIZE_OFF);
65 table.setSortable(true);
66 table.setSortedColumn(START_COL);
67 table.setIntercellSpacing(new Dimension(2, 0));
68 scroller = new JScrollPane(table);
69
70 mainPanel = new JPanel();
71 mainPanel.setLayout(new GridBagLayout());
72 GridBagConstraints constraints = new GridBagConstraints();
73
74 constraints.gridx = 0;
75 constraints.gridy = 0;
76 constraints.weightx = 1;
77 constraints.weighty = 1;
78 constraints.fill= GridBagConstraints.BOTH;
79 mainPanel.add(scroller, constraints);
80
81 constraints.gridy = 1;
82 constraints.weightx = 0;
83 constraints.weighty = 0;
84 constraints.fill= GridBagConstraints.NONE;
85 constraints.anchor = GridBagConstraints.WEST;
86 statusLabel = new JLabel();
87 mainPanel.add(statusLabel, constraints);
88
89 Iterator centralViewsIter = owner.getCentralViews().iterator();
92 while(textView == null && centralViewsIter.hasNext()){
93 DocumentView aView = (DocumentView)centralViewsIter.next();
94 if(aView instanceof TextualDocumentView)
95 textView = (TextualDocumentView)aView;
96 }
97
98 initListeners();
99 }
100
101 public Component getGUI(){
102 return mainPanel;
103 }
104 protected void initListeners(){
105
112 tableModel.addTableModelListener(new TableModelListener(){
113 public void tableChanged(TableModelEvent e){
114 statusLabel.setText(
115 Integer.toString(tableModel.getRowCount()) +
116 " Annotations (" +
117 Integer.toString(table.getSelectedRowCount()) +
118 " selected)");
119 }
120 });
121
122
123 table.getSelectionModel().
124 addListSelectionListener(new ListSelectionListener(){
125 public void valueChanged(ListSelectionEvent e){
126 if(!isActive())return;
127 statusLabel.setText(
128 Integer.toString(tableModel.getRowCount()) +
129 " Annotations (" +
130 Integer.toString(table.getSelectedRowCount()) +
131 "selected)");
132 textView.removeAllBlinkingHighlights();
134 showHighlights();
135 }
136 });
137
138 table.addMouseListener(new MouseListener() {
139 public void mouseClicked(final MouseEvent me) {
140 int viewRow = table.rowAtPoint(me.getPoint());
141 final int modelRow = viewRow == -1 ?
142 viewRow :
143 table.rowViewToModel(viewRow);
144
145 if(javax.swing.SwingUtilities.isRightMouseButton(me)) {
147 JPopupMenu popup = new JPopupMenu();
148
149 Action deleteAction = new AbstractAction("Delete"){
150 public void actionPerformed(ActionEvent evt){
151 int[] rows = table.getSelectedRows();
152 if(rows == null || rows.length == 0){
153 if(modelRow == -1) return;
155 rows = new int[]{modelRow};
156 }
157
158 ArrayList handlers = new ArrayList();
159
160 for(int i = 0; i < rows.length; i++){
161 Object tag = tagList.get(table.rowViewToModel(rows[i]));
162 handlers.add(tag);
163 }
164
165 for(int i=0;i<handlers.size();i++) {
166 Object tag = handlers.get(i);
167 AnnotationHandler aHandler = (AnnotationHandler)
168 annotationHandlerByTag.get(tag);
169 aHandler.set.remove(aHandler.ann);
170 removeAnnotation(tag);
171 }
172 }
173 };
174 popup.add(deleteAction);
175
176 if(modelRow != -1){
178 AnnotationHandler aHandler = (AnnotationHandler)
179 annotationHandlerByTag.get(tagList.get(modelRow));
180 List editorClasses = Gate.getCreoleRegister().
181 getAnnotationVRs(aHandler.ann.getType());
182 if(editorClasses != null && editorClasses.size() > 0){
183 popup.addSeparator();
184 Iterator editorIter = editorClasses.iterator();
185 while(editorIter.hasNext()){
186 String editorClass = (String) editorIter.next();
187 AnnotationVisualResource editor = (AnnotationVisualResource)
188 editorsCache.get(editorClass);
189 if(editor == null){
190 try{
192 editor = (AnnotationVisualResource)
193 Factory.createResource(editorClass);
194 editorsCache.put(editorClass, editor);
195 }catch(ResourceInstantiationException rie){
196 rie.printStackTrace(Err.getPrintWriter());
197 }
198 }
199 popup.add(new EditAnnotationAction(aHandler.set,
200 aHandler.ann, editor));
201 }
202 }
203 }
204
205
206
207 popup.show(table, me.getX(), me.getY());
208 }
209 }
210 public void mouseReleased(MouseEvent me) { }
211 public void mouseEntered(MouseEvent me) { }
212 public void mouseExited(MouseEvent me) { }
213 public void mousePressed(MouseEvent me) { }
214 });
215
216
217 }
218
221 protected void registerHooks() {
222 showHighlights();
224 }
225
226
229 protected void unregisterHooks() {
230 textView.removeAllBlinkingHighlights();
233 }
234
235
238 public int getType() {
239 return HORIZONTAL;
240 }
241 protected void guiShown(){
242 tableModel.fireTableDataChanged();
243 }
244
245 protected void showHighlights(){
246 int[] rows = table.getSelectedRows();
247 for(int i = 0; i < rows.length; i++){
248 Object tag = tagList.get(table.rowViewToModel(rows[i]));
249 AnnotationHandler aHandler = (AnnotationHandler)
250 annotationHandlerByTag.get(tag);
251 textView.addBlinkingHighlight(aHandler.ann);
252 textView.scrollAnnotationToVisible(aHandler.ann);
253 }
254 }
255
256 public void addAnnotation(Object tag, Annotation ann, AnnotationSet set){
257 AnnotationHandler aHandler = new AnnotationHandler(set, ann);
258 Object oldValue = annotationHandlerByTag.put(tag, aHandler);
259 if(oldValue == null){
260 tagList.add(tag);
262 int row = tagList.size() -1;
263 if(tableModel != null) tableModel.fireTableRowsInserted(row, row);
264 }else{
265 int row = tagList.indexOf(tag);
267 if(tableModel != null) tableModel.fireTableRowsUpdated(row,row);
268 }
269 ann.addAnnotationListener(this);
271 }
272
273 public void removeAnnotation(Object tag){
274 int row = tagList.indexOf(tag);
275 if(row >= 0){
276 tagList.remove(row);
277 AnnotationHandler aHandler = (AnnotationHandler)
278 annotationHandlerByTag.remove(tag);
279 if(aHandler != null)aHandler.ann.removeAnnotationListener(this);
280 if(tableModel != null) tableModel.fireTableRowsDeleted(row, row);
281 }
282 }
283
284
293 public void addAnnotations(Collection tags, Collection annotations,
294 AnnotationSet set){
295 if(tags.size() != annotations.size()) throw new GateRuntimeException(
296 "Invalid invocation - different numbers of annotations and tags!");
297 Iterator tagIter = tags.iterator();
298 Iterator annIter = annotations.iterator();
299 while(tagIter.hasNext()){
300 Object tag = tagIter.next();
301 Annotation ann = (Annotation)annIter.next();
302 AnnotationHandler aHandler = new AnnotationHandler(set, ann);
303 Object oldValue = annotationHandlerByTag.put(tag, aHandler);
304 if(oldValue == null){
305 tagList.add(tag);
307 int row = tagList.size() -1;
308 }else{
309 int row = tagList.indexOf(tag);
311 }
312 ann.addAnnotationListener(this);
314 }
315 SwingUtilities.invokeLater(new Runnable(){
316 public void run(){
317 if(tableModel != null) tableModel.fireTableDataChanged();
318 }
319 });
320 }
321
322 public void removeAnnotations(Collection tags){
323 Iterator tagIter = tags.iterator();
324 while(tagIter.hasNext()){
325 Object tag = tagIter.next();
326 int row = tagList.indexOf(tag);
327 if(row >= 0){
328 tagList.remove(row);
329 AnnotationHandler aHandler = (AnnotationHandler)
330 annotationHandlerByTag.remove(tag);
331 if(aHandler != null)aHandler.ann.removeAnnotationListener(this);
332 }
333 }
334 SwingUtilities.invokeLater(new Runnable(){
335 public void run(){
336 if(tableModel != null) tableModel.fireTableDataChanged();
337 }
338 });
339 }
340
341 public void annotationUpdated(AnnotationEvent e){
342
345 if(table == null) {
348 return;
349 }
350
351 int[] selection = table.getSelectedRows();
352 Annotation ann = (Annotation)e.getSource();
353 for(int i = 0; i < tagList.size(); i++){
354 Object tag = tagList.get(i);
355 if(((AnnotationHandler)annotationHandlerByTag.get(tag)).ann == ann){
356 if(tableModel != null)tableModel.fireTableRowsUpdated(i, i);
357 }
358 }
359 table.clearSelection();
361 if(selection != null){
362 for(int i = 0; i < selection.length; i++){
363 table.getSelectionModel().addSelectionInterval(selection[i],
364 selection[i]);
365 }
366 }
367 }
368
369
373 public void selectAnnotationForTag(Object tag){
374 int modelPosition = tagList.indexOf(tag);
375 if(modelPosition != -1){
376 int tablePosition = table.rowModelToView(modelPosition);
377 table.getSelectionModel().setSelectionInterval(tablePosition,
378 tablePosition);
379 table.scrollRectToVisible(table.getCellRect(tablePosition, 0, false));
380 }
381 }
382
383 class AnnotationTableModel extends AbstractTableModel{
384 public int getRowCount(){
385 return tagList.size();
386 }
387
388 public int getColumnCount(){
389 return 5;
390 }
391
392 public String getColumnName(int column){
393 switch(column){
394 case TYPE_COL: return "Type";
395 case SET_COL: return "Set";
396 case START_COL: return "Start";
397 case END_COL: return "End";
398 case FEATURES_COL: return "Features";
399 default: return "?";
400 }
401 }
402
403 public Class getColumnClass(int column){
404 switch(column){
405 case TYPE_COL: return String.class;
406 case SET_COL: return String.class;
407 case START_COL: return Long.class;
408 case END_COL: return Long.class;
409 case FEATURES_COL: return String.class;
410 default: return String.class;
411 }
412 }
413
414 public boolean isCellEditable(int rowIndex, int columnIndex){
415 return false;
416 }
417
418 public Object getValueAt(int row, int column){
419 AnnotationHandler aHandler = (AnnotationHandler)annotationHandlerByTag.
420 get(tagList.get(row));
421 switch(column){
422 case TYPE_COL: return aHandler.ann.getType();
423 case SET_COL: return aHandler.set.getName();
424 case START_COL: return aHandler.ann.getStartNode().getOffset();
425 case END_COL: return aHandler.ann.getEndNode().getOffset();
426 case FEATURES_COL:
427 FeatureMap features = aHandler.ann.getFeatures();
429 List keyList = new ArrayList(features.keySet());
430 Collections.sort(keyList);
431 StringBuffer strBuf = new StringBuffer("{");
432 Iterator keyIter = keyList.iterator();
433 boolean first = true;
434 while(keyIter.hasNext()){
435 Object key = keyIter.next();
436 Object value = features.get(key);
437 if(first){
438 first = false;
439 }else{
440 strBuf.append(", ");
441 }
442 strBuf.append(key.toString());
443 strBuf.append("=");
444 strBuf.append(value == null ? "[null]" : value.toString());
445 }
446 strBuf.append("}");
447 return strBuf.toString();
448 default: return "?";
449 }
450 }
451
452 }
453
454 protected static class AnnotationHandler{
455 public AnnotationHandler(AnnotationSet set, Annotation ann){
456 this.ann = ann;
457 this.set = set;
458 }
459 Annotation ann;
460 AnnotationSet set;
461 }
462
463 protected class EditAnnotationAction extends AbstractAction{
464 public EditAnnotationAction(AnnotationSet set, Annotation ann,
465 AnnotationVisualResource editor){
466 this.set = set;
467 this.ann = ann;
468 this.editor = editor;
469 ResourceData rData =(ResourceData)Gate.getCreoleRegister().
470 get(editor.getClass().getName());
471 if(rData != null){
472 title = rData.getName();
473 putValue(NAME, "Edit with " + title);
474 putValue(SHORT_DESCRIPTION, rData.getComment());
475 }
476 }
477
478 public void actionPerformed(ActionEvent evt){
479 JScrollPane scroller = new JScrollPane((Component)editor);
480 editor.setTarget(set);
481 editor.setAnnotation(ann);
482 JOptionPane optionPane = new JOptionPane(scroller,
483 JOptionPane.QUESTION_MESSAGE,
484 JOptionPane.OK_CANCEL_OPTION,
485 null, new String[]{"OK", "Cancel"});
486 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
487 scroller.setMaximumSize(new Dimension((int)(screenSize.width * .75),
488 (int)(screenSize.height * .75)));
489 JDialog dialog = optionPane.createDialog(AnnotationListView.this.getGUI(),
490 title);
491 dialog.setModal(true);
492 dialog.setResizable(true);
493 dialog.setVisible(true);
494 try{
495 if(optionPane.getValue().equals("OK")) editor.okAction();
496 else editor.cancelAction();
497 }catch(GateException ge){
498 throw new GateRuntimeException(ge);
499 }
500 }
501
502 String title;
503 Annotation ann;
504 AnnotationSet set;
505 AnnotationVisualResource editor;
506 }
507
508 protected XJTable table;
509 protected AnnotationTableModel tableModel;
510 protected JScrollPane scroller;
511 protected Map annotationHandlerByTag;
512 protected List tagList;
513 protected JPanel mainPanel;
514 protected JLabel statusLabel;
515 protected TextualDocumentView textView;
516
520 protected Map editorsCache;
521
522 private static final int TYPE_COL = 0;
523 private static final int SET_COL = 1;
524 private static final int START_COL = 2;
525 private static final int END_COL = 3;
526 private static final int FEATURES_COL = 4;
527
528 }
529