1
7 package gate.gui.docview;
8
9 import java.awt.*;
10 import java.awt.Color;
11 import java.awt.Component;
12 import java.awt.event.*;
13 import java.awt.event.ActionEvent;
14 import java.awt.event.ActionListener;
15 import java.util.*;
16 import java.util.List;
17 import java.util.prefs.Preferences;
18
19 import javax.swing.*;
20 import javax.swing.JScrollPane;
21 import javax.swing.JTable;
22 import javax.swing.border.Border;
23 import javax.swing.event.*;
24 import javax.swing.event.MouseInputListener;
25 import javax.swing.event.PopupMenuListener;
26 import javax.swing.table.*;
27 import javax.swing.table.AbstractTableModel;
28 import javax.swing.table.TableCellRenderer;
29 import javax.swing.text.*;
30 import javax.swing.text.BadLocationException;
31
32 import gate.*;
33 import gate.Annotation;
34 import gate.AnnotationSet;
35 import gate.event.AnnotationSetEvent;
36 import gate.event.AnnotationSetListener;
37 import gate.event.DocumentEvent;
38 import gate.event.DocumentListener;
39 import gate.gui.MainFrame;
40 import gate.swing.ColorGenerator;
41 import gate.swing.XJTable;
42 import gate.util.GateRuntimeException;
43 import gate.util.InvalidOffsetException;
44
45
51 public class AnnotationSetsView extends AbstractDocumentView
52 implements DocumentListener,
53 AnnotationSetListener{
54
55
56 public AnnotationSetsView(){
57 setHandlers = new ArrayList();
58 tableRows = new ArrayList();
59 colourGenerator = new ColorGenerator();
60 }
61
62
63
66 public int getType() {
67 return VERTICAL;
68 }
69
70 protected void initGUI() {
71 Iterator centralViewsIter = owner.getCentralViews().iterator();
73 while(textView == null && centralViewsIter.hasNext()){
74 DocumentView aView = (DocumentView)centralViewsIter.next();
75 if(aView instanceof TextualDocumentView)
76 textView = (TextualDocumentView)aView;
77 }
78 textPane = (JEditorPane)((JScrollPane)textView.getGUI())
79 .getViewport().getView();
80
81 setHandlers.add(new SetHandler(document.getAnnotations()));
82 List setNames = document.getNamedAnnotationSets() == null ?
83 new ArrayList() :
84 new ArrayList(document.getNamedAnnotationSets().keySet());
85 Collections.sort(setNames);
86 Iterator setsIter = setNames.iterator();
87 while(setsIter.hasNext()){
88 setHandlers.add(new SetHandler(document.
89 getAnnotations((String)setsIter.next())));
90 }
91 tableRows.addAll(setHandlers);
92 mainTable = new XJTable();
93 tableModel = new SetsTableModel();
94 ((XJTable)mainTable).setSortable(false);
95 mainTable.setModel(tableModel);
96 SetsTableCellRenderer cellRenderer = new SetsTableCellRenderer();
99 mainTable.getColumnModel().getColumn(NAME_COL).setCellRenderer(cellRenderer);
100 mainTable.getColumnModel().getColumn(SELECTED_COL).setCellRenderer(cellRenderer);
101 SetsTableCellEditor cellEditor = new SetsTableCellEditor();
102 mainTable.getColumnModel().getColumn(SELECTED_COL).setCellEditor(cellEditor);
103 mainTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
104 mainTable.setColumnSelectionAllowed(false);
105 mainTable.setRowSelectionAllowed(true);
106
107 mainTable.setTableHeader(null);
108 mainTable.setShowGrid(false);
109 mainTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
110
111 scroller = new JScrollPane(mainTable);
112 scroller.getViewport().setOpaque(true);
113 scroller.getViewport().setBackground(mainTable.getBackground());
114
115 annotationEditor = new AnnotationEditor(textView, this);
116
117 mainPanel = new JPanel();
118 mainPanel.setLayout(new GridBagLayout());
119 GridBagConstraints constraints = new GridBagConstraints();
120
121 constraints.gridy = 0;
122 constraints.gridx = GridBagConstraints.RELATIVE;
123 constraints.gridwidth = 2;
124 constraints.weighty = 1;
125 constraints.weightx = 1;
126 constraints.fill = GridBagConstraints.BOTH;
127 mainPanel.add(scroller, constraints);
128
129 constraints.gridy = 1;
130 constraints.gridwidth = 1;
131 constraints.weighty = 0;
132 newSetNameTextField = new JTextField();
133 mainPanel.add(newSetNameTextField, constraints);
134 constraints.weightx = 0;
135 newSetAction = new NewAnnotationSetAction();
136 mainPanel.add(new JButton(newSetAction), constraints);
137 initListeners();
138 }
139
140 public Component getGUI(){
141 return mainPanel;
142 }
143
144 protected Color getColor(String annotationType){
145 Preferences prefRoot = Preferences.userNodeForPackage(getClass());
146 int rgba = prefRoot.getInt(annotationType, -1);
147 Color colour;
148 if(rgba == -1){
149 float components[] = colourGenerator.getNextColor().getComponents(null);
151 colour = new Color(components[0],
152 components[1],
153 components[2],
154 0.5f);
155 int rgb = colour.getRGB();
156 int alpha = colour.getAlpha();
157 rgba = rgb | (alpha << 24);
158 prefRoot.putInt(annotationType, rgba);
159 }else{
160 colour = new Color(rgba, true);
161 }
162 return colour;
163 }
164
165 protected void saveColor(String annotationType, Color colour){
166 Preferences prefRoot = Preferences.userNodeForPackage(getClass());
167 int rgb = colour.getRGB();
168 int alpha = colour.getAlpha();
169 int rgba = rgb | (alpha << 24);
170 prefRoot.putInt(annotationType, rgba);
171 }
172
173
178 protected void registerHooks(){
179 textPane.addMouseListener(textMouseListener);
180 textPane.addMouseMotionListener(textMouseListener);
181 textPane.addAncestorListener(textAncestorListener);
182 }
183
184
190 protected void unregisterHooks(){
191 textPane.removeMouseListener(textMouseListener);
192 textPane.removeMouseMotionListener(textMouseListener);
193 textPane.removeAncestorListener(textAncestorListener);
194 }
195
196
197 protected void initListeners(){
198 document.addDocumentListener(this);
199 mainTable.addComponentListener(new ComponentAdapter(){
200 public void componentResized(ComponentEvent e){
201 mainTable.adjustSizes();
203 }
205 });
206
207 mainTable.addMouseListener(new MouseAdapter(){
208 public void mouseClicked(MouseEvent evt){
209 int row = mainTable.rowAtPoint(evt.getPoint());
210 int column = mainTable.columnAtPoint(evt.getPoint());
211 if(row >= 0 && column == NAME_COL){
212 Object handler = tableRows.get(row);
213 if(handler instanceof TypeHandler){
214 TypeHandler tHandler = (TypeHandler)handler;
215 if(evt.getClickCount() >= 2){
216 tHandler.changeColourAction.actionPerformed(null);
218 }
219 }
220 }
221 }
222 public void mousePressed(MouseEvent evt){
223 int row = mainTable.rowAtPoint(evt.getPoint());
224 int column = mainTable.columnAtPoint(evt.getPoint());
225 if(row >= 0 && column == NAME_COL){
226 Object handler = tableRows.get(row);
227 if(handler instanceof TypeHandler){
228 TypeHandler tHandler = (TypeHandler)handler;
229 if(evt.isPopupTrigger()){
230 JPopupMenu popup = new JPopupMenu();
232 popup.add(tHandler.changeColourAction);
233 popup.show(mainTable, evt.getX(), evt.getY());
234 }
235 }
236 }
237 }
238
239 public void mouseReleased(MouseEvent evt){
240 int row = mainTable.rowAtPoint(evt.getPoint());
241 int column = mainTable.columnAtPoint(evt.getPoint());
242 if(row >= 0 && column == NAME_COL){
243 Object handler = tableRows.get(row);
244 if(handler instanceof TypeHandler){
245 TypeHandler tHandler = (TypeHandler)handler;
246 if(evt.isPopupTrigger()){
247 JPopupMenu popup = new JPopupMenu();
249 popup.add(tHandler.changeColourAction);
250 popup.show(mainTable, evt.getX(), evt.getY());
251 }
252 }
253 }
254 }
255 });
256
257
258 mouseStoppedMovingAction = new MouseStoppedMovingAction();
259 mouseMovementTimer = new javax.swing.Timer(MOUSE_MOVEMENT_TIMER_DELAY,
260 mouseStoppedMovingAction);
261 mouseMovementTimer.setRepeats(false);
262 textMouseListener = new TextMouseListener();
263 textAncestorListener = new AncestorListener(){
264 public void ancestorAdded(AncestorEvent event){
265 if(wasShowing) annotationEditor.show(false);
266 wasShowing = false;
267 }
268
269 public void ancestorRemoved(AncestorEvent event){
270 if(annotationEditor.isShowing()){
271 wasShowing = true;
272 annotationEditor.hide();
273 }
274 }
275
276 public void ancestorMoved(AncestorEvent event){
277
278 }
279 private boolean wasShowing = false;
280 };
281
282 mainTable.getInputMap().put(
283 KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "deleteAll");
284 mainTable.getActionMap().put("deleteAll",
285 new DeleteSelectedAnnotationGroupAction());
286 newSetNameTextField.getInputMap().put(
287 KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "newSet");
288 newSetNameTextField.getActionMap().put("newSet", newSetAction);
289 }
290
291
292
295 public void cleanup() {
296 document.removeDocumentListener(this);
297 super.cleanup();
298 }
299
300 public void annotationSetAdded(DocumentEvent e) {
301 String newSetName = e.getAnnotationSetName();
302 SetHandler sHandler = new SetHandler(document.getAnnotations(newSetName));
303 int i = 1;
306 for(;
307 i < setHandlers.size() &&
308 ((SetHandler)setHandlers.get(i)).set.
309 getName().compareTo(newSetName) <= 0;
310 i++);
311 setHandlers.add(i, sHandler);
312 SetHandler previousHandler = (SetHandler)setHandlers.get(i -1);
314 int j = 0;
316 for(;
317 tableRows.get(j) != previousHandler;
318 j++);
319 if(previousHandler.isExpanded()){
320 j += previousHandler.typeHandlers.size();
321 }
322 j++;
323 tableRows.add(j, sHandler);
324 tableModel.fireTableRowsInserted(j, j);
326 }
328 public void annotationSetRemoved(DocumentEvent e) {
329 String setName = e.getAnnotationSetName();
330 SetHandler sHandler = getSetHandler(setName);
333 if(sHandler != null){
334 Iterator typeIter = sHandler.typeHandlers.iterator();
336 while(typeIter.hasNext()){
337 TypeHandler tHandler = (TypeHandler)typeIter.next();
338 tHandler.setSelected(false);
339 }
340 setHandlers.remove(sHandler);
341 int row = tableRows.indexOf(sHandler);
343 tableRows.remove(row);
344 int removed = 1;
345 if(sHandler.isExpanded())
347 for(int i = 0; i < sHandler.typeHandlers.size(); i++){
348 tableRows.remove(row);
349 removed++;
350 }
351 tableModel.fireTableRowsDeleted(row, row + removed -1);
352 sHandler.cleanup();
353 }
354 }
356
359 public void contentEdited(DocumentEvent e){
360 Iterator setIter = setHandlers.iterator();
362 while(setIter.hasNext()){
363 SetHandler sHandler = (SetHandler)setIter.next();
364 Iterator typeIter = sHandler.typeHandlers.iterator();
365 while(typeIter.hasNext()){
366 TypeHandler tHandler = (TypeHandler)typeIter.next();
367 if(tHandler.isSelected())
368 tHandler.repairHighlights(e.getEditStart().intValue(),
369 e.getEditEnd().intValue());
370 }
371 }
372 }
373
374
375 public void annotationAdded(AnnotationSetEvent e) {
376 AnnotationSet set = (AnnotationSet)e.getSource();
377 Annotation ann = e.getAnnotation();
378 TypeHandler tHandler = getTypeHandler(set.getName(), ann.getType());
379 if(tHandler == null){
380 SetHandler sHandler = getSetHandler(set.getName());
382 tHandler = sHandler.newType(ann.getType());
383 }
384 tHandler.annotationAdded(ann);
385 }
386
387 public void annotationRemoved(AnnotationSetEvent e) {
388 AnnotationSet set = (AnnotationSet)e.getSource();
389 Annotation ann = e.getAnnotation();
390 TypeHandler tHandler = getTypeHandler(set.getName(), ann.getType());
391 tHandler.annotationRemoved(ann);
392 }
393
394 protected SetHandler getSetHandler(String name){
395 Iterator shIter = setHandlers.iterator();
396 while(shIter.hasNext()){
397 SetHandler sHandler = (SetHandler)shIter.next();
398 if(name == null){
399 if(sHandler.set.getName() == null) return sHandler;
400 }else{
401 if(name.equals(sHandler.set.getName())) return sHandler;
402 }
403 }
404 return null;
405 }
406
407 protected TypeHandler getTypeHandler(String set, String type){
408 SetHandler sHandler = getSetHandler(set);
409 TypeHandler tHandler = null;
410 Iterator typeIter = sHandler.typeHandlers.iterator();
411 while(tHandler == null && typeIter.hasNext()){
412 TypeHandler aHandler = (TypeHandler)typeIter.next();
413 if(aHandler.name.equals(type)) tHandler = aHandler;
414 }
415 return tHandler;
416 }
417
418 public void setTypeSelected(final String setName,
419 final String typeName,
420 final boolean selected){
421
422 SwingUtilities.invokeLater(new Runnable(){
423 public void run(){
424 TypeHandler tHandler = getTypeHandler(setName, typeName);
425 tHandler.setSelected(selected);
426 int row = tableRows.indexOf(tHandler);
427 tableModel.fireTableRowsUpdated(row, row);
428 }
429 });
430 }
431
432
437 void setLastAnnotationType(String annType){
438 this.lastAnnotationType = annType;
439 }
440
441 protected class SetsTableModel extends AbstractTableModel{
442 public int getRowCount(){
443 return tableRows.size();
444 }
453
454 public int getColumnCount(){
455 return 2;
456 }
457
458 public Object getValueAt(int row, int column){
459 Object value = tableRows.get(row);
460 switch(column){
461 case NAME_COL:
462 return value;
463 case SELECTED_COL:
464 if(value instanceof SetHandler)
465 return new Boolean(((SetHandler)value).isExpanded());
466 if(value instanceof TypeHandler)
467 return new Boolean(((TypeHandler)value).isSelected());
468 default:
469 return null;
470 }
471 }
496
497 public boolean isCellEditable(int rowIndex, int columnIndex){
498 Object value = tableRows.get(rowIndex);
499 switch(columnIndex){
500 case NAME_COL: return false;
501 case SELECTED_COL:
502 if(value instanceof SetHandler)
503 return ((SetHandler)value).typeHandlers.size() > 0;
504 if(value instanceof TypeHandler) return true;
505 }
506 return columnIndex == SELECTED_COL;
507 }
508
509 public void setValueAt(Object aValue, int rowIndex, int columnIndex){
510 Object receiver = tableRows.get(rowIndex);
511 switch(columnIndex){
512 case SELECTED_COL:
513 if(receiver instanceof SetHandler){
514 ((SetHandler)receiver).setExpanded(((Boolean)aValue).booleanValue());
515 }else if(receiver instanceof TypeHandler){
516 ((TypeHandler)receiver).setSelected(((Boolean)aValue).booleanValue());
517 }
518
519 break;
520 default:
521 break;
522 }
523 }
524 }
526 protected class SetsTableCellRenderer implements TableCellRenderer{
527 public SetsTableCellRenderer(){
528 typeLabel = new JLabel(){
529 public void repaint(long tm, int x, int y, int width, int height){}
530 public void repaint(Rectangle r){}
531 public void validate(){}
532 public void revalidate(){}
533 protected void firePropertyChange(String propertyName,
534 Object oldValue,
535 Object newValue){}
536 };
537 typeLabel.setOpaque(true);
538 typeLabel.setBorder(BorderFactory.createCompoundBorder(
539 BorderFactory.createMatteBorder(0, 5, 0, 0,
540 mainTable.getBackground()),
541 BorderFactory.createEmptyBorder(0, 5, 0, 5)));
542
544
545 setLabel = new JLabel(){
546 public void repaint(long tm, int x, int y, int width, int height){}
547 public void repaint(Rectangle r){}
548 public void validate(){}
549 public void revalidate(){}
550 protected void firePropertyChange(String propertyName,
551 Object oldValue,
552 Object newValue){}
553 };
554 setLabel.setOpaque(true);
555 setLabel.setFont(setLabel.getFont().deriveFont(Font.BOLD));
556 setLabel.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
557
558
559 typeChk = new JCheckBox(){
560 public void repaint(long tm, int x, int y, int width, int height){}
561 public void repaint(Rectangle r){}
562 public void validate(){}
563 public void revalidate(){}
564 protected void firePropertyChange(String propertyName,
565 Object oldValue,
566 Object newValue){}
567 };
568 typeChk.setOpaque(true);
569
571 setChk = new JCheckBox(){
572 public void repaint(long tm, int x, int y, int width, int height){}
573 public void repaint(Rectangle r){}
574 public void validate(){}
575 public void revalidate(){}
576 protected void firePropertyChange(String propertyName,
577 Object oldValue,
578 Object newValue){}
579 };
580 setChk.setSelectedIcon(MainFrame.getIcon("expanded.gif"));
581 setChk.setIcon(MainFrame.getIcon("closed.gif"));
582 setChk.setMaximumSize(setChk.getMinimumSize());
583 setChk.setOpaque(true);
584
585 normalBorder = BorderFactory.createLineBorder(
586 mainTable.getBackground(), 2);
587 selectedBorder = BorderFactory.createLineBorder(
588 mainTable.getSelectionBackground(), 2);
589 }
590
591 public Component getTableCellRendererComponent(JTable table,
592 Object value,
593 boolean isSelected,
594 boolean hasFocus,
595 int row,
596 int column){
597
598 value = tableRows.get(row);
599 if(value instanceof SetHandler){
600 SetHandler sHandler = (SetHandler)value;
601 switch(column){
602 case NAME_COL:
603 setLabel.setText(sHandler.set.getName());
604 setLabel.setBackground(isSelected ?
605 table.getSelectionBackground() :
606 table.getBackground());
607 return setLabel;
608 case SELECTED_COL:
609 setChk.setSelected(sHandler.isExpanded());
610 setChk.setEnabled(sHandler.typeHandlers.size() > 0);
611 setChk.setBackground(isSelected ?
612 table.getSelectionBackground() :
613 table.getBackground());
614 return setChk;
615 }
616 }else if(value instanceof TypeHandler){
617 TypeHandler tHandler = (TypeHandler)value;
618 switch(column){
619 case NAME_COL:
620 typeLabel.setBackground(tHandler.colour);
621 typeLabel.setText(tHandler.name);
622 typeLabel.setBorder(isSelected ? selectedBorder : normalBorder);
623 return typeLabel;
624 case SELECTED_COL:
625 typeChk.setBackground(isSelected ?
626 table.getSelectionBackground() :
627 table.getBackground());
628 typeChk.setSelected(tHandler.isSelected());
629 return typeChk;
630 }
631 }
632 typeLabel.setText("?");
633 return typeLabel;
634 }
636
637 protected JLabel typeLabel;
638 protected JLabel setLabel;
639 protected JCheckBox setChk;
640 protected JCheckBox typeChk;
641 protected Border selectedBorder;
642 protected Border normalBorder;
643 }
644
645 protected class SetsTableCellEditor extends AbstractCellEditor
646 implements TableCellEditor{
647 public SetsTableCellEditor(){
648 setChk = new JCheckBox();
649 setChk.setSelectedIcon(MainFrame.getIcon("expanded.gif"));
650 setChk.setIcon(MainFrame.getIcon("closed.gif"));
651 setChk.setOpaque(true);
653 setChk.addActionListener(new ActionListener(){
654 public void actionPerformed(ActionEvent evt){
655 fireEditingStopped();
656 }
657 });
658 typeChk = new JCheckBox();
659 typeChk.setOpaque(false);
660 typeChk.addActionListener(new ActionListener(){
662 public void actionPerformed(ActionEvent evt){
663 fireEditingStopped();
664 }
665 });
666 }
667
668 public Component getTableCellEditorComponent(JTable table,
669 Object value,
670 boolean isSelected,
671 int row,
672 int column){
673 value = tableRows.get(row);
674 if(value instanceof SetHandler){
675 SetHandler sHandler = (SetHandler)value;
676 switch(column){
677 case NAME_COL: return null;
678 case SELECTED_COL:
679 setChk.setSelected(sHandler.isExpanded());
680 setChk.setEnabled(sHandler.typeHandlers.size() > 0);
681 setChk.setBackground(isSelected ?
682 table.getSelectionBackground() :
683 table.getBackground());
684 currentChk = setChk;
685 return setChk;
686 }
687 }else if(value instanceof TypeHandler){
688 TypeHandler tHandler = (TypeHandler)value;
689 switch(column){
690 case NAME_COL: return null;
691 case SELECTED_COL:
692 typeChk.setSelected(tHandler.isSelected());
694 currentChk = typeChk;
695 return typeChk;
696 }
697 }
698 return null;
699 }
700
701 public boolean stopCellEditing(){
702 return true;
703 }
704
705 public Object getCellEditorValue(){
706 return new Boolean(currentChk.isSelected());
707 }
708
709 public boolean shouldSelectCell(EventObject anEvent){
710 return true;
711 }
712
713 public boolean isCellEditable(EventObject anEvent){
714 return true;
715 }
716
717 JCheckBox currentChk;
718 JCheckBox setChk;
719 JCheckBox typeChk;
720 }
721
722
723
726 protected class SetHandler{
727 SetHandler(AnnotationSet set){
728 this.set = set;
729 typeHandlers = new ArrayList();
730 typeHandlersByType = new HashMap();
731 List typeNames = new ArrayList(set.getAllTypes());
732 Collections.sort(typeNames);
733 Iterator typIter = typeNames.iterator();
734 while(typIter.hasNext()){
735 String name = (String)typIter.next();
736 TypeHandler tHandler = new TypeHandler(this, name);
737 typeHandlers.add(tHandler);
738 typeHandlersByType.put(name, tHandler);
739 }
740 set.addAnnotationSetListener(AnnotationSetsView.this);
741 }
742
743 public void cleanup(){
744 set.removeAnnotationSetListener(AnnotationSetsView.this);
745 typeHandlers.clear();
746 }
747
748
753 public TypeHandler newType(String type){
754 TypeHandler tHandler = new TypeHandler(this, type);
756 int pos = 0;
758 for(;
759 pos < typeHandlers.size() &&
760 ((TypeHandler)typeHandlers.get(pos)).name.compareTo(type) <= 0;
761 pos++);
762 typeHandlers.add(pos, tHandler);
763 typeHandlersByType.put(type, tHandler);
764 int setRow = tableRows.indexOf(this);
765 if(typeHandlers.size() == 1)
766 tableModel.fireTableRowsUpdated(setRow, setRow);
767 if(expanded){
768 tableRows.add(setRow + pos + 1, tHandler);
769 tableModel.fireTableRowsInserted(setRow + pos + 1,
770 setRow + pos + 1);
771 }
772 return tHandler;
773 }
774
775 public void removeType(TypeHandler tHandler){
776 int setRow = tableRows.indexOf(this);
777 int pos = typeHandlers.indexOf(tHandler);
778 typeHandlers.remove(pos);
779 typeHandlersByType.remove(tHandler.name);
780 if(expanded){
781 tableRows.remove(setRow + pos + 1);
782 tableModel.fireTableRowsDeleted(setRow + pos + 1, setRow + pos + 1);
783 }
784 if(typeHandlers.isEmpty()){
785 setExpanded(false);
787 tableModel.fireTableRowsUpdated(setRow, setRow);
788 }
789 }
790
791 public void removeType(String type){
792 removeType((TypeHandler)typeHandlersByType.get(type));
793 }
794
795 public TypeHandler getTypeHandler(String type){
796 return (TypeHandler)typeHandlersByType.get(type);
797 }
798
799 public void setExpanded(boolean expanded){
800 if(this.expanded == expanded) return;
801 this.expanded = expanded;
802 int myPosition = tableRows.indexOf(this);
803 if(expanded){
804 tableRows.addAll(myPosition + 1, typeHandlers);
806 tableModel.fireTableRowsInserted(myPosition + 1,
807 myPosition + 1 + typeHandlers.size());
808 }else{
809 for(int i = 0; i < typeHandlers.size(); i++){
811 tableRows.remove(myPosition + 1);
812 }
813 tableModel.fireTableRowsDeleted(myPosition + 1,
814 myPosition + 1 + typeHandlers.size());
815 }
816 tableModel.fireTableRowsUpdated(myPosition, myPosition);
817 }
818
819 public boolean isExpanded(){
820 return expanded;
821 }
822
823
824 AnnotationSet set;
825 List typeHandlers;
826 Map typeHandlersByType;
827 private boolean expanded = false;
828 }
829
830 protected class TypeHandler{
831 TypeHandler (SetHandler setHandler, String name){
832 this.setHandler = setHandler;
833 this.name = name;
834 colour = getColor(name);
835 hghltTagsForAnn = new HashMap();
836 changeColourAction = new ChangeColourAction();
837 }
838
839 public void setColour(Color colour){
840 if(this.colour.equals(colour)) return;
841 this.colour = colour;
842 saveColor(name, colour);
843 if(isSelected()){
844 Runnable runnable = new Runnable(){
846 public void run(){
847 textView.removeHighlights(hghltTagsForAnn.values());
849 hghltTagsForAnn.clear();
850 List annots = new ArrayList(setHandler.set.get(name));
852 List tags = textView.addHighlights(annots, setHandler.set,
853 TypeHandler.this.colour);
854 for(int i = 0; i < annots.size(); i++){
855 hghltTagsForAnn.put(((Annotation)annots.get(i)).getId(), tags.get(i));
856 }
857 }
858 };
859 Thread thread = new Thread(runnable);
860 thread.setPriority(Thread.MIN_PRIORITY);
861 thread.start();
862 }
863 SwingUtilities.invokeLater(new Runnable(){
865 public void run(){
866 int row = tableRows.indexOf(this);
867 if(row >= 0) tableModel.fireTableRowsUpdated(row, row);
868 }
869 });
870 }
871
872 public void setSelected(boolean selected){
873 if(this.selected == selected) return;
874 this.selected = selected;
875 final List annots = new ArrayList(setHandler.set.get(name));
876 if(selected){
877 setHandler.setExpanded(true);
879 hghltTagsForAnn.clear();
881 Iterator annIter = annots.iterator();
882 Runnable runnable = new Runnable(){
884 public void run(){
885 List tags = textView.addHighlights(annots, setHandler.set, colour);
887 for(int i = 0; i < annots.size(); i++){
888 hghltTagsForAnn.put(((Annotation)annots.get(i)).getId(), tags.get(i));
889 }
890 }
891 };
892 Thread thread = new Thread(runnable);
893 thread.setPriority(Thread.MIN_PRIORITY);
894 thread.start();
895 }else{
896 Runnable runnable = new Runnable(){
898 public void run(){
899 textView.removeHighlights(hghltTagsForAnn.values());
901 hghltTagsForAnn.clear();
902 }
903 };
904 Thread thread = new Thread(runnable);
905 thread.setPriority(Thread.MIN_PRIORITY);
906 thread.start();
907 }
908 int row = tableRows.indexOf(this);
910 tableModel.fireTableRowsUpdated(row, row);
911 }
912
913 public boolean isSelected(){
914 return selected;
915 }
916
917
922 public void annotationAdded(Annotation ann){
923 if(selected) hghltTagsForAnn.put(ann.getId(),
925 textView.addHighlight(ann, setHandler.set, colour));
926 }
927
928
932 public void annotationRemoved(Annotation ann){
933 if(selected){
934 Object tag = hghltTagsForAnn.remove(ann.getId());
935 textView.removeHighlight(tag);
936 }
937 Set remainingAnns = setHandler.set.get(name);
940 if(remainingAnns == null || remainingAnns.isEmpty()){
941 setHandler.removeType(this);
942 }
943 }
944
945 protected void repairHighlights(int start, int end){
946 List tags = new ArrayList(hghltTagsForAnn.size());
948 List annots = new ArrayList(hghltTagsForAnn.size());
949 Iterator annIter = hghltTagsForAnn.keySet().iterator();
950 while(annIter.hasNext()){
951 Annotation ann = setHandler.set.get((Integer)annIter.next());
952 int annStart = ann.getStartNode().getOffset().intValue();
953 int annEnd = ann.getEndNode().getOffset().intValue();
954 if((annStart <= start && start <= annEnd) ||
955 (start <= annStart && annStart <= end)){
956 if(!hghltTagsForAnn.containsKey(ann.getId())){
957 System.out.println("Error!!!");
958 }
959 tags.add(hghltTagsForAnn.get(ann.getId()));
960 annots.add(ann);
961 }
962 }
963 for(int i = 0; i < tags.size(); i++){
964 Object tag = tags.get(i);
965 Annotation ann = (Annotation)annots.get(i);
966 try{
967 textView.moveHighlight(tag,
968 ann.getStartNode().getOffset().intValue(),
969 ann.getEndNode().getOffset().intValue());
970 }catch(BadLocationException ble){
971 }
973 }
974 }
975
976
977 protected class ChangeColourAction extends AbstractAction{
978 public ChangeColourAction(){
979 super("Change colour");
980 }
981
982 public void actionPerformed(ActionEvent evt){
983 Color col = JColorChooser.showDialog(mainTable,
984 "Select colour for \"" + name + "\"",
985 colour);
986 if(col != null){
987 Color colAlpha = new Color(col.getRed(), col.getGreen(),
988 col.getBlue(), 128);
989 setColour(colAlpha);
990 }
991 }
992 }
993
994 ChangeColourAction changeColourAction;
995 boolean selected;
996 Map hghltTagsForAnn;
998 String name;
999 SetHandler setHandler;
1000 Color colour;
1001 }
1002
1003 protected static class AnnotationHandler{
1004 public AnnotationHandler(AnnotationSet set, Annotation ann){
1005 this.ann = ann;
1006 this.set = set;
1007 }
1008 Annotation ann;
1009 AnnotationSet set;
1010 }
1011
1012
1015 protected class TextMouseListener implements MouseInputListener{
1016 public void mouseDragged(MouseEvent e){
1017 mouseStoppedMovingAction.setTextLocation(textPane.viewToModel(e.getPoint()));
1018 mouseMovementTimer.restart();
1019 }
1020
1021 public void mouseMoved(MouseEvent e){
1022 mouseStoppedMovingAction.setTextLocation(textPane.viewToModel(e.getPoint()));
1025 mouseMovementTimer.restart();
1026 }
1027
1028 public void mouseClicked(MouseEvent e){
1029 mouseStoppedMovingAction.setTextLocation(textPane.viewToModel(e.getPoint()));
1032 mouseMovementTimer.restart();
1033 }
1034
1035 public void mousePressed(MouseEvent e){
1036
1037 }
1038 public void mouseReleased(MouseEvent e){
1039
1040 }
1041
1042 public void mouseEntered(MouseEvent e){
1043
1044 }
1045
1046 public void mouseExited(MouseEvent e){
1047 mouseMovementTimer.stop();
1048 }
1049 }
1051
1052 protected class NewAnnotationSetAction extends AbstractAction{
1053 public NewAnnotationSetAction(){
1054 super("New");
1055 putValue(SHORT_DESCRIPTION, "Creates a new annotation set");
1056 }
1057
1058 public void actionPerformed(ActionEvent evt){
1059 String name = newSetNameTextField.getText();
1060 newSetNameTextField.setText("");
1061 if(name != null && name.length() > 0){
1062 document.getAnnotations(name);
1063 }
1064 }
1065 }
1066
1067 protected class NewAnnotationAction extends AbstractAction{
1068 public void actionPerformed(ActionEvent evt){
1069 int start = textPane.getSelectionStart();
1070 int end = textPane.getSelectionEnd();
1071 if(start != end){
1072 textPane.setSelectionStart(start);
1073 textPane.setSelectionEnd(start);
1074 int row = mainTable.getSelectedRow();
1077 if(row < 0) row = 0;
1079 while(!(tableRows.get(row) instanceof SetHandler)) row --;
1081 AnnotationSet set = ((SetHandler)tableRows.get(row)).set;
1082 try{
1083 Integer annId = set.add(new Long(start), new Long(end),
1084 lastAnnotationType, Factory.newFeatureMap());
1085 Annotation ann = set.get(annId);
1086 setTypeSelected(set.getName(), ann.getType(), true);
1088 annotationEditor.setAnnotation(ann, set);
1090 annotationEditor.show(true);
1091 }catch(InvalidOffsetException ioe){
1092 throw new GateRuntimeException(ioe);
1094 }
1095 }
1096 }
1097 }
1098
1099
1103 protected class MouseStoppedMovingAction extends AbstractAction{
1104
1105 public void actionPerformed(ActionEvent evt){
1106 if(textPane.getSelectionStart() <= textLocation &&
1109 textPane.getSelectionEnd() >= textLocation){
1110 new NewAnnotationAction().actionPerformed(evt);
1111 }else{
1112 List annotsAtPoint = new ArrayList();
1114 Iterator shIter = setHandlers.iterator();
1115 while(shIter.hasNext()){
1116 SetHandler sHandler = (SetHandler)shIter.next();
1117 Iterator annIter = sHandler.set.get(new Long(textLocation),
1118 new Long(textLocation)).iterator();
1119 while(annIter.hasNext()){
1120 Annotation ann = (Annotation)annIter.next();
1121 if(sHandler.getTypeHandler(ann.getType()).isSelected()){
1122 annotsAtPoint.add(new AnnotationHandler(sHandler.set, ann));
1123 }
1124 }
1125 }
1126 if(annotsAtPoint.size() > 0){
1127 if(annotsAtPoint.size() > 1){
1128 JPopupMenu popup = new JPopupMenu();
1129 Iterator annIter = annotsAtPoint.iterator();
1130 while(annIter.hasNext()){
1131 AnnotationHandler aHandler = (AnnotationHandler)annIter.next();
1132 popup.add(new HighlightMenuItem(
1133 new EditAnnotationAction(aHandler),
1134 aHandler.ann.getStartNode().getOffset().intValue(),
1135 aHandler.ann.getEndNode().getOffset().intValue(),
1136 popup));
1137 }
1138 try{
1139 Rectangle rect = textPane.modelToView(textLocation);
1140 popup.show(textPane, rect.x + 10, rect.y);
1141 }catch(BadLocationException ble){
1142 throw new GateRuntimeException(ble);
1143 }
1144 }else{
1145 new EditAnnotationAction((AnnotationHandler)annotsAtPoint.get(0)).
1147 actionPerformed(null);
1148 }
1149 }
1150 }
1151 }
1152
1153 public void setTextLocation(int textLocation){
1154 this.textLocation = textLocation;
1155 }
1156 int textLocation;
1157 }
1159
1160
1165 protected class HighlightMenuItem extends JMenuItem {
1166 public HighlightMenuItem(Action action, int startOffset, int endOffset,
1167 JPopupMenu popup) {
1168 super(action);
1169 this.start = startOffset;
1170 this.end = endOffset;
1171 this.addMouseListener(new MouseAdapter() {
1172 public void mouseEntered(MouseEvent e) {
1173 showHighlight();
1174 }
1175
1176 public void mouseExited(MouseEvent e) {
1177 removeHighlight();
1178 }
1179 });
1180 popup.addPopupMenuListener(new PopupMenuListener(){
1181 public void popupMenuWillBecomeVisible(PopupMenuEvent e){
1182
1183 }
1184 public void popupMenuCanceled(PopupMenuEvent e){
1185 removeHighlight();
1186 }
1187 public void popupMenuWillBecomeInvisible(PopupMenuEvent e){
1188 removeHighlight();
1189 }
1190
1191
1192 });
1193 }
1194
1195 protected void showHighlight(){
1196 try {
1197 highlight = textPane.getHighlighter().addHighlight(start, end,
1198 DefaultHighlighter.DefaultPainter);
1199 }catch(BadLocationException ble){
1200 throw new GateRuntimeException(ble.toString());
1201 }
1202
1203 }
1204
1205 protected void removeHighlight(){
1206 if(highlight != null){
1207 textPane.getHighlighter().removeHighlight(highlight);
1208 highlight = null;
1209 }
1210
1211 }
1212
1213 int start;
1214 int end;
1215 Action action;
1216 Object highlight;
1217 }
1218
1219
1220
1221 protected class EditAnnotationAction extends AbstractAction{
1222 public EditAnnotationAction(AnnotationHandler aHandler){
1223 super(aHandler.ann.getType() + " [" +
1224 (aHandler.set.getName() == null ? " " :
1225 aHandler.set.getName()) +
1226 "]");
1227 putValue(SHORT_DESCRIPTION, aHandler.ann.getFeatures().toString());
1228 this.aHandler = aHandler;
1229 }
1230
1231 public void actionPerformed(ActionEvent evt){
1232 annotationEditor.setAnnotation(aHandler.ann, aHandler.set);
1233 annotationEditor.show(true);
1234 }
1235
1236 AnnotationHandler aHandler;
1237 }
1238
1239 protected class DeleteSelectedAnnotationGroupAction extends AbstractAction{
1240 public DeleteSelectedAnnotationGroupAction(){
1241 }
1242 public void actionPerformed(ActionEvent evt){
1243 int row = mainTable.getSelectedRow();
1244 if(row >= 0){
1245 Object handler = tableRows.get(row);
1246 if(handler instanceof TypeHandler){
1247 TypeHandler tHandler = (TypeHandler)handler;
1248 AnnotationSet set = tHandler.setHandler.set;
1249 AnnotationSet toDeleteAS = set.get(tHandler.name);
1250 if(toDeleteAS != null){
1251 List toDelete = new ArrayList(toDeleteAS);
1252 set.removeAll(toDelete);
1253 }
1254 }else if(handler instanceof SetHandler){
1255 SetHandler sHandler = (SetHandler)handler;
1256 if(sHandler.set == document.getAnnotations()){
1257 sHandler.set.clear();
1259 }else{
1260 document.removeAnnotationSet(sHandler.set.getName());
1261 }
1262 }
1263 }
1264 }
1265 }
1266
1267 List setHandlers;
1268 List tableRows;
1269 XJTable mainTable;
1270 SetsTableModel tableModel;
1271 JScrollPane scroller;
1272 JPanel mainPanel;
1273 JTextField newSetNameTextField;
1274
1275 TextualDocumentView textView;
1276 JEditorPane textPane;
1277 AnnotationEditor annotationEditor;
1278 NewAnnotationSetAction newSetAction;
1279
1280
1283 protected TextMouseListener textMouseListener;
1284
1285 protected javax.swing.Timer mouseMovementTimer;
1286 private static final int MOUSE_MOVEMENT_TIMER_DELAY = 500;
1287 protected AncestorListener textAncestorListener;
1288 protected MouseStoppedMovingAction mouseStoppedMovingAction;
1289
1290 protected String lastAnnotationType = "_New_";
1291
1292 protected ColorGenerator colourGenerator;
1293 private static final int NAME_COL = 1;
1294 private static final int SELECTED_COL = 0;
1295
1296}
1297