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.io.*;
16 import java.util.*;
17 import java.util.List;
18 import java.util.prefs.Preferences;
19
20 import javax.swing.*;
21 import javax.swing.JScrollPane;
22 import javax.swing.JTable;
23 import javax.swing.border.Border;
24 import javax.swing.event.*;
25 import javax.swing.event.MouseInputListener;
26 import javax.swing.event.PopupMenuListener;
27 import javax.swing.table.*;
28 import javax.swing.table.AbstractTableModel;
29 import javax.swing.table.TableCellRenderer;
30 import javax.swing.text.*;
31 import javax.swing.text.BadLocationException;
32
33 import gate.*;
34 import gate.Annotation;
35 import gate.AnnotationSet;
36 import gate.event.*;
37 import gate.event.AnnotationSetEvent;
38 import gate.event.AnnotationSetListener;
39 import gate.event.DocumentEvent;
40 import gate.event.DocumentListener;
41 import gate.gui.*;
42 import gate.gui.MainFrame;
43 import gate.swing.ColorGenerator;
44 import gate.swing.XJTable;
45 import gate.util.*;
46 import gate.util.GateRuntimeException;
47 import gate.util.InvalidOffsetException;
48
49
55 public class AnnotationSetsView extends AbstractDocumentView
56 implements DocumentListener,
57 AnnotationSetListener{
58
59
60 public AnnotationSetsView(){
61 setHandlers = new ArrayList();
62 tableRows = new ArrayList();
63 colourGenerator = new ColorGenerator();
64 actions = new ArrayList();
65 actions.add(new SavePreserveFormatAction());
66 }
67
68 public List getActions() {
69 return actions;
70 }
71
72
75 public int getType() {
76 return VERTICAL;
77 }
78
79 protected void initGUI() {
80 Iterator centralViewsIter = owner.getCentralViews().iterator();
82 while(textView == null && centralViewsIter.hasNext()){
83 DocumentView aView = (DocumentView)centralViewsIter.next();
84 if(aView instanceof TextualDocumentView)
85 textView = (TextualDocumentView)aView;
86 }
87 textPane = (JEditorPane)((JScrollPane)textView.getGUI())
88 .getViewport().getView();
89
90 Iterator horizontalViewsIter = owner.getHorizontalViews().iterator();
92 while(listView == null && horizontalViewsIter.hasNext()){
93 DocumentView aView = (DocumentView)horizontalViewsIter.next();
94 if(aView instanceof AnnotationListView)
95 listView = (AnnotationListView)aView;
96 }
97
98
99 setHandlers.add(new SetHandler(document.getAnnotations()));
100 List setNames = document.getNamedAnnotationSets() == null ?
101 new ArrayList() :
102 new ArrayList(document.getNamedAnnotationSets().keySet());
103 Collections.sort(setNames);
104 Iterator setsIter = setNames.iterator();
105 while(setsIter.hasNext()){
106 setHandlers.add(new SetHandler(document.
107 getAnnotations((String)setsIter.next())));
108 }
109 tableRows.addAll(setHandlers);
110 mainTable = new XJTable();
111 tableModel = new SetsTableModel();
112 ((XJTable)mainTable).setSortable(false);
113 mainTable.setModel(tableModel);
114 SetsTableCellRenderer cellRenderer = new SetsTableCellRenderer();
117 mainTable.getColumnModel().getColumn(NAME_COL).setCellRenderer(cellRenderer);
118 mainTable.getColumnModel().getColumn(SELECTED_COL).setCellRenderer(cellRenderer);
119 SetsTableCellEditor cellEditor = new SetsTableCellEditor();
120 mainTable.getColumnModel().getColumn(SELECTED_COL).setCellEditor(cellEditor);
121 mainTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
122 mainTable.setColumnSelectionAllowed(false);
123 mainTable.setRowSelectionAllowed(true);
124
125 mainTable.setTableHeader(null);
126 mainTable.setShowGrid(false);
127 mainTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
128
129 scroller = new JScrollPane(mainTable);
130 scroller.getViewport().setOpaque(true);
131 scroller.getViewport().setBackground(mainTable.getBackground());
132
133 annotationEditor = new AnnotationEditor(textView, this);
134
135 mainPanel = new JPanel();
136 mainPanel.setLayout(new GridBagLayout());
137 GridBagConstraints constraints = new GridBagConstraints();
138
139 constraints.gridy = 0;
140 constraints.gridx = GridBagConstraints.RELATIVE;
141 constraints.gridwidth = 2;
142 constraints.weighty = 1;
143 constraints.weightx = 1;
144 constraints.fill = GridBagConstraints.BOTH;
145 mainPanel.add(scroller, constraints);
146
147 constraints.gridy = 1;
148 constraints.gridwidth = 1;
149 constraints.weighty = 0;
150 newSetNameTextField = new JTextField();
151 mainPanel.add(newSetNameTextField, constraints);
152 constraints.weightx = 0;
153 newSetAction = new NewAnnotationSetAction();
154 mainPanel.add(new JButton(newSetAction), constraints);
155 initListeners();
156 }
157
158 public Component getGUI(){
159 return mainPanel;
160 }
161
162 protected Color getColor(String annotationType){
163 Preferences prefRoot = Preferences.userNodeForPackage(getClass());
164 int rgba = prefRoot.getInt(annotationType, -1);
165 Color colour;
166 if(rgba == -1){
167 float components[] = colourGenerator.getNextColor().getComponents(null);
169 colour = new Color(components[0],
170 components[1],
171 components[2],
172 0.5f);
173 int rgb = colour.getRGB();
174 int alpha = colour.getAlpha();
175 rgba = rgb | (alpha << 24);
176 prefRoot.putInt(annotationType, rgba);
177 }else{
178 colour = new Color(rgba, true);
179 }
180 return colour;
181 }
182
183 protected void saveColor(String annotationType, Color colour){
184 Preferences prefRoot = Preferences.userNodeForPackage(getClass());
185 int rgb = colour.getRGB();
186 int alpha = colour.getAlpha();
187 int rgba = rgb | (alpha << 24);
188 prefRoot.putInt(annotationType, rgba);
189 }
190
191
196 protected void registerHooks(){
197 textPane.addMouseListener(textMouseListener);
198 textPane.addMouseMotionListener(textMouseListener);
199 textPane.addAncestorListener(textAncestorListener);
200 }
201
202
208 protected void unregisterHooks(){
209 textPane.removeMouseListener(textMouseListener);
210 textPane.removeMouseMotionListener(textMouseListener);
211 textPane.removeAncestorListener(textAncestorListener);
212 }
213
214
215 protected void initListeners(){
216 document.addDocumentListener(this);
217 mainTable.addComponentListener(new ComponentAdapter(){
218 public void componentResized(ComponentEvent e){
219 mainTable.adjustSizes();
221 }
223 });
224
225 mainTable.addMouseListener(new MouseAdapter(){
226 public void mouseClicked(MouseEvent evt){
227 int row = mainTable.rowAtPoint(evt.getPoint());
228 int column = mainTable.columnAtPoint(evt.getPoint());
229 if(row >= 0 && column == NAME_COL){
230 Object handler = tableRows.get(row);
231 if(handler instanceof TypeHandler){
232 TypeHandler tHandler = (TypeHandler)handler;
233 if(evt.getClickCount() >= 2){
234 tHandler.changeColourAction.actionPerformed(null);
236 }
237 }
238 }
239 }
240 public void mousePressed(MouseEvent evt){
241 int row = mainTable.rowAtPoint(evt.getPoint());
242 int column = mainTable.columnAtPoint(evt.getPoint());
243 if(row >= 0 && column == NAME_COL){
244 Object handler = tableRows.get(row);
245 if(handler instanceof TypeHandler){
246 TypeHandler tHandler = (TypeHandler)handler;
247 if(evt.isPopupTrigger()){
248 JPopupMenu popup = new JPopupMenu();
250 popup.add(tHandler.changeColourAction);
251 popup.show(mainTable, evt.getX(), evt.getY());
252 }
253 }
254 }
255 }
256
257 public void mouseReleased(MouseEvent evt){
258 int row = mainTable.rowAtPoint(evt.getPoint());
259 int column = mainTable.columnAtPoint(evt.getPoint());
260 if(row >= 0 && column == NAME_COL){
261 Object handler = tableRows.get(row);
262 if(handler instanceof TypeHandler){
263 TypeHandler tHandler = (TypeHandler)handler;
264 if(evt.isPopupTrigger()){
265 JPopupMenu popup = new JPopupMenu();
267 popup.add(tHandler.changeColourAction);
268 popup.show(mainTable, evt.getX(), evt.getY());
269 }
270 }
271 }
272 }
273 });
274
275
276 mouseStoppedMovingAction = new MouseStoppedMovingAction();
277 mouseMovementTimer = new javax.swing.Timer(MOUSE_MOVEMENT_TIMER_DELAY,
278 mouseStoppedMovingAction);
279 mouseMovementTimer.setRepeats(false);
280 textMouseListener = new TextMouseListener();
281 textAncestorListener = new AncestorListener(){
282 public void ancestorAdded(AncestorEvent event){
283 if(wasShowing) annotationEditor.show(false);
284 wasShowing = false;
285 }
286
287 public void ancestorRemoved(AncestorEvent event){
288 if(annotationEditor.isShowing()){
289 wasShowing = true;
290 annotationEditor.hide();
291 }
292 }
293
294 public void ancestorMoved(AncestorEvent event){
295
296 }
297 private boolean wasShowing = false;
298 };
299
300 mainTable.getInputMap().put(
301 KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "deleteAll");
302 mainTable.getActionMap().put("deleteAll",
303 new DeleteSelectedAnnotationGroupAction());
304 newSetNameTextField.getInputMap().put(
305 KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "newSet");
306 newSetNameTextField.getActionMap().put("newSet", newSetAction);
307 }
308
309
310
313 public void cleanup() {
314 document.removeDocumentListener(this);
315 super.cleanup();
316 }
317
318 public void annotationSetAdded(DocumentEvent e) {
319 String newSetName = e.getAnnotationSetName();
320 SetHandler sHandler = new SetHandler(document.getAnnotations(newSetName));
321 int i = 1;
324 for(;
325 i < setHandlers.size() &&
326 ((SetHandler)setHandlers.get(i)).set.
327 getName().compareTo(newSetName) <= 0;
328 i++);
329 setHandlers.add(i, sHandler);
330 SetHandler previousHandler = (SetHandler)setHandlers.get(i -1);
332 int j = 0;
334 for(;
335 tableRows.get(j) != previousHandler;
336 j++);
337 if(previousHandler.isExpanded()){
338 j += previousHandler.typeHandlers.size();
339 }
340 j++;
341 tableRows.add(j, sHandler);
342 tableModel.fireTableRowsInserted(j, j);
344 }
346 public void annotationSetRemoved(DocumentEvent e) {
347 String setName = e.getAnnotationSetName();
348 SetHandler sHandler = getSetHandler(setName);
351 if(sHandler != null){
352 Iterator typeIter = sHandler.typeHandlers.iterator();
354 while(typeIter.hasNext()){
355 TypeHandler tHandler = (TypeHandler)typeIter.next();
356 tHandler.setSelected(false);
357 }
358 setHandlers.remove(sHandler);
359 int row = tableRows.indexOf(sHandler);
361 tableRows.remove(row);
362 int removed = 1;
363 if(sHandler.isExpanded())
365 for(int i = 0; i < sHandler.typeHandlers.size(); i++){
366 tableRows.remove(row);
367 removed++;
368 }
369 tableModel.fireTableRowsDeleted(row, row + removed -1);
370 sHandler.cleanup();
371 }
372 }
374
377 public void contentEdited(DocumentEvent e){
378 Iterator setIter = setHandlers.iterator();
380 while(setIter.hasNext()){
381 SetHandler sHandler = (SetHandler)setIter.next();
382 Iterator typeIter = sHandler.typeHandlers.iterator();
383 while(typeIter.hasNext()){
384 TypeHandler tHandler = (TypeHandler)typeIter.next();
385 if(tHandler.isSelected())
386 tHandler.repairHighlights(e.getEditStart().intValue(),
387 e.getEditEnd().intValue());
388 }
389 }
390 }
391
392
393 public void annotationAdded(AnnotationSetEvent e) {
394 AnnotationSet set = (AnnotationSet)e.getSource();
395 Annotation ann = e.getAnnotation();
396 TypeHandler tHandler = getTypeHandler(set.getName(), ann.getType());
397 if(tHandler == null){
398 SetHandler sHandler = getSetHandler(set.getName());
400 tHandler = sHandler.newType(ann.getType());
401 }
402 tHandler.annotationAdded(ann);
403 }
404
405 public void annotationRemoved(AnnotationSetEvent e) {
406 AnnotationSet set = (AnnotationSet)e.getSource();
407 Annotation ann = e.getAnnotation();
408 TypeHandler tHandler = getTypeHandler(set.getName(), ann.getType());
409 tHandler.annotationRemoved(ann);
410 }
411
412 protected SetHandler getSetHandler(String name){
413 Iterator shIter = setHandlers.iterator();
414 while(shIter.hasNext()){
415 SetHandler sHandler = (SetHandler)shIter.next();
416 if(name == null){
417 if(sHandler.set.getName() == null) return sHandler;
418 }else{
419 if(name.equals(sHandler.set.getName())) return sHandler;
420 }
421 }
422 return null;
423 }
424
425 protected TypeHandler getTypeHandler(String set, String type){
426 SetHandler sHandler = getSetHandler(set);
427 TypeHandler tHandler = null;
428 Iterator typeIter = sHandler.typeHandlers.iterator();
429 while(tHandler == null && typeIter.hasNext()){
430 TypeHandler aHandler = (TypeHandler)typeIter.next();
431 if(aHandler.name.equals(type)) tHandler = aHandler;
432 }
433 return tHandler;
434 }
435
436 public void setTypeSelected(final String setName,
437 final String typeName,
438 final boolean selected){
439
440 SwingUtilities.invokeLater(new Runnable(){
441 public void run(){
442 TypeHandler tHandler = getTypeHandler(setName, typeName);
443 tHandler.setSelected(selected);
444 int row = tableRows.indexOf(tHandler);
445 tableModel.fireTableRowsUpdated(row, row);
446 mainTable.getSelectionModel().setSelectionInterval(row, row);
447 }
448 });
449 }
450
451
456 void setLastAnnotationType(String annType){
457 this.lastAnnotationType = annType;
458 }
459
460 protected class SetsTableModel extends AbstractTableModel{
461 public int getRowCount(){
462 return tableRows.size();
463 }
472
473 public int getColumnCount(){
474 return 2;
475 }
476
477 public Object getValueAt(int row, int column){
478 Object value = tableRows.get(row);
479 switch(column){
480 case NAME_COL:
481 return value;
482 case SELECTED_COL:
483 if(value instanceof SetHandler)
484 return new Boolean(((SetHandler)value).isExpanded());
485 if(value instanceof TypeHandler)
486 return new Boolean(((TypeHandler)value).isSelected());
487 default:
488 return null;
489 }
490 }
515
516 public boolean isCellEditable(int rowIndex, int columnIndex){
517 Object value = tableRows.get(rowIndex);
518 switch(columnIndex){
519 case NAME_COL: return false;
520 case SELECTED_COL:
521 if(value instanceof SetHandler)
522 return ((SetHandler)value).typeHandlers.size() > 0;
523 if(value instanceof TypeHandler) return true;
524 }
525 return columnIndex == SELECTED_COL;
526 }
527
528 public void setValueAt(Object aValue, int rowIndex, int columnIndex){
529 Object receiver = tableRows.get(rowIndex);
530 switch(columnIndex){
531 case SELECTED_COL:
532 if(receiver instanceof SetHandler){
533 ((SetHandler)receiver).setExpanded(((Boolean)aValue).booleanValue());
534 }else if(receiver instanceof TypeHandler){
535 ((TypeHandler)receiver).setSelected(((Boolean)aValue).booleanValue());
536 }
537
538 break;
539 default:
540 break;
541 }
542 }
543 }
545 protected class SetsTableCellRenderer implements TableCellRenderer{
546 public SetsTableCellRenderer(){
547 typeLabel = new JLabel(){
548 public void repaint(long tm, int x, int y, int width, int height){}
549 public void repaint(Rectangle r){}
550 public void validate(){}
551 public void revalidate(){}
552 protected void firePropertyChange(String propertyName,
553 Object oldValue,
554 Object newValue){}
555 };
556 typeLabel.setOpaque(true);
557 typeLabel.setBorder(BorderFactory.createCompoundBorder(
558 BorderFactory.createMatteBorder(0, 5, 0, 0,
559 mainTable.getBackground()),
560 BorderFactory.createEmptyBorder(0, 5, 0, 5)));
561
563
564 setLabel = new JLabel(){
565 public void repaint(long tm, int x, int y, int width, int height){}
566 public void repaint(Rectangle r){}
567 public void validate(){}
568 public void revalidate(){}
569 protected void firePropertyChange(String propertyName,
570 Object oldValue,
571 Object newValue){}
572 };
573 setLabel.setOpaque(true);
574 setLabel.setFont(setLabel.getFont().deriveFont(Font.BOLD));
575 setLabel.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
576
577
578 typeChk = new JCheckBox(){
579 public void repaint(long tm, int x, int y, int width, int height){}
580 public void repaint(Rectangle r){}
581 public void validate(){}
582 public void revalidate(){}
583 protected void firePropertyChange(String propertyName,
584 Object oldValue,
585 Object newValue){}
586 };
587 typeChk.setOpaque(true);
588
590 setChk = new JCheckBox(){
591 public void repaint(long tm, int x, int y, int width, int height){}
592 public void repaint(Rectangle r){}
593 public void validate(){}
594 public void revalidate(){}
595 protected void firePropertyChange(String propertyName,
596 Object oldValue,
597 Object newValue){}
598 };
599 setChk.setSelectedIcon(MainFrame.getIcon("expanded.gif"));
600 setChk.setIcon(MainFrame.getIcon("closed.gif"));
601 setChk.setMaximumSize(setChk.getMinimumSize());
602 setChk.setOpaque(true);
603
604 normalBorder = BorderFactory.createLineBorder(
605 mainTable.getBackground(), 2);
606 selectedBorder = BorderFactory.createLineBorder(
607 mainTable.getSelectionBackground(), 2);
608 }
609
610 public Component getTableCellRendererComponent(JTable table,
611 Object value,
612 boolean isSelected,
613 boolean hasFocus,
614 int row,
615 int column){
616
617 value = tableRows.get(row);
618 if(value instanceof SetHandler){
619 SetHandler sHandler = (SetHandler)value;
620 switch(column){
621 case NAME_COL:
622 setLabel.setText(sHandler.set.getName());
623 setLabel.setBackground(isSelected ?
624 table.getSelectionBackground() :
625 table.getBackground());
626 return setLabel;
627 case SELECTED_COL:
628 setChk.setSelected(sHandler.isExpanded());
629 setChk.setEnabled(sHandler.typeHandlers.size() > 0);
630 setChk.setBackground(isSelected ?
631 table.getSelectionBackground() :
632 table.getBackground());
633 return setChk;
634 }
635 }else if(value instanceof TypeHandler){
636 TypeHandler tHandler = (TypeHandler)value;
637 switch(column){
638 case NAME_COL:
639 typeLabel.setBackground(tHandler.colour);
640 typeLabel.setText(tHandler.name);
641 typeLabel.setBorder(isSelected ? selectedBorder : normalBorder);
642 return typeLabel;
643 case SELECTED_COL:
644 typeChk.setBackground(isSelected ?
645 table.getSelectionBackground() :
646 table.getBackground());
647 typeChk.setSelected(tHandler.isSelected());
648 return typeChk;
649 }
650 }
651 typeLabel.setText("?");
652 return typeLabel;
653 }
655
656 protected JLabel typeLabel;
657 protected JLabel setLabel;
658 protected JCheckBox setChk;
659 protected JCheckBox typeChk;
660 protected Border selectedBorder;
661 protected Border normalBorder;
662 }
663
664 protected class SetsTableCellEditor extends AbstractCellEditor
665 implements TableCellEditor{
666 public SetsTableCellEditor(){
667 setChk = new JCheckBox();
668 setChk.setSelectedIcon(MainFrame.getIcon("expanded.gif"));
669 setChk.setIcon(MainFrame.getIcon("closed.gif"));
670 setChk.setOpaque(true);
672 setChk.addActionListener(new ActionListener(){
673 public void actionPerformed(ActionEvent evt){
674 fireEditingStopped();
675 }
676 });
677 typeChk = new JCheckBox();
678 typeChk.setOpaque(false);
679 typeChk.addActionListener(new ActionListener(){
681 public void actionPerformed(ActionEvent evt){
682 fireEditingStopped();
683 }
684 });
685 }
686
687 public Component getTableCellEditorComponent(JTable table,
688 Object value,
689 boolean isSelected,
690 int row,
691 int column){
692 value = tableRows.get(row);
693 if(value instanceof SetHandler){
694 SetHandler sHandler = (SetHandler)value;
695 switch(column){
696 case NAME_COL: return null;
697 case SELECTED_COL:
698 setChk.setSelected(sHandler.isExpanded());
699 setChk.setEnabled(sHandler.typeHandlers.size() > 0);
700 setChk.setBackground(isSelected ?
701 table.getSelectionBackground() :
702 table.getBackground());
703 currentChk = setChk;
704 return setChk;
705 }
706 }else if(value instanceof TypeHandler){
707 TypeHandler tHandler = (TypeHandler)value;
708 switch(column){
709 case NAME_COL: return null;
710 case SELECTED_COL:
711 typeChk.setSelected(tHandler.isSelected());
713 currentChk = typeChk;
714 return typeChk;
715 }
716 }
717 return null;
718 }
719
720 public boolean stopCellEditing(){
721 return true;
722 }
723
724 public Object getCellEditorValue(){
725 return new Boolean(currentChk.isSelected());
726 }
727
728 public boolean shouldSelectCell(EventObject anEvent){
729 return true;
730 }
731
732 public boolean isCellEditable(EventObject anEvent){
733 return true;
734 }
735
736 JCheckBox currentChk;
737 JCheckBox setChk;
738 JCheckBox typeChk;
739 }
740
741
742
745 protected class SetHandler{
746 SetHandler(AnnotationSet set){
747 this.set = set;
748 typeHandlers = new ArrayList();
749 typeHandlersByType = new HashMap();
750 List typeNames = new ArrayList(set.getAllTypes());
751 Collections.sort(typeNames);
752 Iterator typIter = typeNames.iterator();
753 while(typIter.hasNext()){
754 String name = (String)typIter.next();
755 TypeHandler tHandler = new TypeHandler(this, name);
756 typeHandlers.add(tHandler);
757 typeHandlersByType.put(name, tHandler);
758 }
759 set.addAnnotationSetListener(AnnotationSetsView.this);
760 }
761
762 public void cleanup(){
763 set.removeAnnotationSetListener(AnnotationSetsView.this);
764 typeHandlers.clear();
765 }
766
767
772 public TypeHandler newType(String type){
773 TypeHandler tHandler = new TypeHandler(this, type);
775 int pos = 0;
777 for(;
778 pos < typeHandlers.size() &&
779 ((TypeHandler)typeHandlers.get(pos)).name.compareTo(type) <= 0;
780 pos++);
781 typeHandlers.add(pos, tHandler);
782 typeHandlersByType.put(type, tHandler);
783 int row = mainTable.getSelectedRow();
785 int setRow = tableRows.indexOf(this);
786 if(typeHandlers.size() == 1)
787 tableModel.fireTableRowsUpdated(setRow, setRow);
788 if(expanded){
789 tableRows.add(setRow + pos + 1, tHandler);
790 tableModel.fireTableRowsInserted(setRow + pos + 1,
791 setRow + pos + 1);
792 }
793 if(row != -1) mainTable.getSelectionModel().setSelectionInterval(row, row);
795 return tHandler;
796 }
797
798 public void removeType(TypeHandler tHandler){
799 int setRow = tableRows.indexOf(this);
800 int pos = typeHandlers.indexOf(tHandler);
801 typeHandlers.remove(pos);
802 typeHandlersByType.remove(tHandler.name);
803 int row = mainTable.getSelectedRow();
805 if(expanded){
806 tableRows.remove(setRow + pos + 1);
807 tableModel.fireTableRowsDeleted(setRow + pos + 1, setRow + pos + 1);
808 if(row >= (setRow + pos + 1)) row--;
809 }
810 if(typeHandlers.isEmpty()){
811 setExpanded(false);
813 tableModel.fireTableRowsUpdated(setRow, setRow);
814 }
815 if(row != -1) mainTable.getSelectionModel().setSelectionInterval(row, row);
817 }
818
819 public void removeType(String type){
820 removeType((TypeHandler)typeHandlersByType.get(type));
821 }
822
823 public TypeHandler getTypeHandler(String type){
824 return (TypeHandler)typeHandlersByType.get(type);
825 }
826
827 public void setExpanded(boolean expanded){
828 if(this.expanded == expanded) return;
829 this.expanded = expanded;
830 int myPosition = tableRows.indexOf(this);
831 if(expanded){
832 tableRows.addAll(myPosition + 1, typeHandlers);
834 tableModel.fireTableRowsInserted(myPosition + 1,
835 myPosition + 1 + typeHandlers.size());
836 }else{
837 for(int i = 0; i < typeHandlers.size(); i++){
839 tableRows.remove(myPosition + 1);
840 }
841 tableModel.fireTableRowsDeleted(myPosition + 1,
842 myPosition + 1 + typeHandlers.size());
843 }
844 tableModel.fireTableRowsUpdated(myPosition, myPosition);
845 }
846
847 public boolean isExpanded(){
848 return expanded;
849 }
850
851
852 AnnotationSet set;
853 List typeHandlers;
854 Map typeHandlersByType;
855 private boolean expanded = false;
856 }
857
858 protected class TypeHandler{
859 TypeHandler (SetHandler setHandler, String name){
860 this.setHandler = setHandler;
861 this.name = name;
862 colour = getColor(name);
863 hghltTagsForAnn = new HashMap();
864 changeColourAction = new ChangeColourAction();
865 }
866
867 public void setColour(Color colour){
868 if(this.colour.equals(colour)) return;
869 this.colour = colour;
870 saveColor(name, colour);
871 if(isSelected()){
872 Runnable runnable = new Runnable(){
874 public void run(){
875 textView.removeHighlights(hghltTagsForAnn.values());
877 hghltTagsForAnn.clear();
878 List annots = new ArrayList(setHandler.set.get(name));
880 List tags = textView.addHighlights(annots, setHandler.set,
881 TypeHandler.this.colour);
882 for(int i = 0; i < annots.size(); i++){
883 hghltTagsForAnn.put(((Annotation)annots.get(i)).getId(), tags.get(i));
884 }
885 }
886 };
887 Thread thread = new Thread(runnable);
888 thread.setPriority(Thread.MIN_PRIORITY);
889 thread.start();
890 }
891 SwingUtilities.invokeLater(new Runnable(){
893 public void run(){
894 int row = tableRows.indexOf(this);
895 if(row >= 0) tableModel.fireTableRowsUpdated(row, row);
896 }
897 });
898 }
899
900 public void setSelected(boolean selected){
901 if(this.selected == selected) return;
902 this.selected = selected;
903 final List annots = new ArrayList(setHandler.set.get(name));
904 if(selected){
905 setHandler.setExpanded(true);
907 hghltTagsForAnn.clear();
909 Iterator annIter = annots.iterator();
910 Runnable runnable = new Runnable(){
912 public void run(){
913 List tags = textView.addHighlights(annots, setHandler.set, colour);
915 for(int i = 0; i < annots.size(); i++){
916 hghltTagsForAnn.put(((Annotation)annots.get(i)).getId(), tags.get(i));
917 }
918 }
919 };
920 Thread thread = new Thread(runnable);
921 thread.setPriority(Thread.MIN_PRIORITY);
922 thread.start();
923 }else{
924 Runnable runnable = new Runnable(){
926 public void run(){
927 textView.removeHighlights(hghltTagsForAnn.values());
929 hghltTagsForAnn.clear();
930 }
931 };
932 Thread thread = new Thread(runnable);
933 thread.setPriority(Thread.MIN_PRIORITY);
934 thread.start();
935 }
936 int row = tableRows.indexOf(this);
938 tableModel.fireTableRowsUpdated(row, row);
939 }
940
941 public boolean isSelected(){
942 return selected;
943 }
944
945
950 public void annotationAdded(Annotation ann){
951 if(selected) hghltTagsForAnn.put(ann.getId(),
953 textView.addHighlight(ann, setHandler.set, colour));
954 }
955
956
960 public void annotationRemoved(Annotation ann){
961 if(selected){
962 Object tag = hghltTagsForAnn.remove(ann.getId());
963 textView.removeHighlight(tag);
964 }
965 Set remainingAnns = setHandler.set.get(name);
968 if(remainingAnns == null || remainingAnns.isEmpty()){
969 setHandler.removeType(this);
970 }
971 }
972
973 protected void repairHighlights(int start, int end){
974 List tags = new ArrayList(hghltTagsForAnn.size());
976 List annots = new ArrayList(hghltTagsForAnn.size());
977 Iterator annIter = hghltTagsForAnn.keySet().iterator();
978 while(annIter.hasNext()){
979 Annotation ann = setHandler.set.get((Integer)annIter.next());
980 int annStart = ann.getStartNode().getOffset().intValue();
981 int annEnd = ann.getEndNode().getOffset().intValue();
982 if((annStart <= start && start <= annEnd) ||
983 (start <= annStart && annStart <= end)){
984 if(!hghltTagsForAnn.containsKey(ann.getId())){
985 System.out.println("Error!!!");
986 }
987 tags.add(hghltTagsForAnn.get(ann.getId()));
988 annots.add(ann);
989 }
990 }
991 for(int i = 0; i < tags.size(); i++){
992 Object tag = tags.get(i);
993 Annotation ann = (Annotation)annots.get(i);
994 try{
995 textView.moveHighlight(tag,
996 ann.getStartNode().getOffset().intValue(),
997 ann.getEndNode().getOffset().intValue());
998 }catch(BadLocationException ble){
999 }
1001 }
1002 }
1003
1004
1005 protected class ChangeColourAction extends AbstractAction{
1006 public ChangeColourAction(){
1007 super("Change colour");
1008 }
1009
1010 public void actionPerformed(ActionEvent evt){
1011 Color col = JColorChooser.showDialog(mainTable,
1012 "Select colour for \"" + name + "\"",
1013 colour);
1014 if(col != null){
1015 Color colAlpha = new Color(col.getRed(), col.getGreen(),
1016 col.getBlue(), 128);
1017 setColour(colAlpha);
1018 }
1019 }
1020 }
1021
1022 ChangeColourAction changeColourAction;
1023 boolean selected;
1024 Map hghltTagsForAnn;
1026 String name;
1027 SetHandler setHandler;
1028 Color colour;
1029 }
1030
1031 protected static class AnnotationHandler{
1032 public AnnotationHandler(AnnotationSet set, Annotation ann){
1033 this.ann = ann;
1034 this.set = set;
1035 }
1036 Annotation ann;
1037 AnnotationSet set;
1038 }
1039
1040
1043 protected class TextMouseListener implements MouseInputListener{
1044 public void mouseDragged(MouseEvent e){
1045 mouseMovementTimer.stop();
1047 }
1048
1049 public void mouseMoved(MouseEvent e){
1050 int modEx = e.getModifiersEx();
1054 if((modEx & MouseEvent.CTRL_DOWN_MASK) != 0){
1055 mouseMovementTimer.stop();
1056 return;
1057 }
1058 if((modEx & MouseEvent.BUTTON1_DOWN_MASK) != 0){
1059 mouseMovementTimer.stop();
1060 return;
1061 }
1062 mouseStoppedMovingAction.setTextLocation(textPane.viewToModel(e.getPoint()));
1063 mouseMovementTimer.restart();
1064 }
1065
1066 public void mouseClicked(MouseEvent e){
1067 }
1068
1069 public void mousePressed(MouseEvent e){
1070
1071 }
1072 public void mouseReleased(MouseEvent e){
1073
1074 }
1075
1076 public void mouseEntered(MouseEvent e){
1077
1078 }
1079
1080 public void mouseExited(MouseEvent e){
1081 mouseMovementTimer.stop();
1082 }
1083 }
1085
1086 protected class NewAnnotationSetAction extends AbstractAction{
1087 public NewAnnotationSetAction(){
1088 super("New");
1089 putValue(SHORT_DESCRIPTION, "Creates a new annotation set");
1090 }
1091
1092 public void actionPerformed(ActionEvent evt){
1093 String name = newSetNameTextField.getText();
1094 newSetNameTextField.setText("");
1095 if(name != null && name.length() > 0){
1096 AnnotationSet set = document.getAnnotations(name);
1097 Iterator rowsIter = tableRows.iterator();
1099 int row = -1;
1100 for(int i = 0; i < tableRows.size() && row < 0; i++){
1101 if(tableRows.get(i) instanceof SetHandler &&
1102 ((SetHandler)tableRows.get(i)).set == set) row = i;
1103 }
1104 if(row >= 0) mainTable.getSelectionModel().setSelectionInterval(row, row);
1105 }
1106 }
1107 }
1108
1109 protected class NewAnnotationAction extends AbstractAction{
1110 public void actionPerformed(ActionEvent evt){
1111 int start = textPane.getSelectionStart();
1112 int end = textPane.getSelectionEnd();
1113 if(start != end){
1114 textPane.setSelectionStart(start);
1115 textPane.setSelectionEnd(start);
1116 int row = mainTable.getSelectedRow();
1119 if(row < 0) row = 0;
1121 while(!(tableRows.get(row) instanceof SetHandler)) row --;
1123 AnnotationSet set = ((SetHandler)tableRows.get(row)).set;
1124 try{
1125 Integer annId = set.add(new Long(start), new Long(end),
1126 lastAnnotationType, Factory.newFeatureMap());
1127 Annotation ann = set.get(annId);
1128 setTypeSelected(set.getName(), ann.getType(), true);
1130 annotationEditor.setAnnotation(ann, set);
1132 annotationEditor.show(true);
1133 }catch(InvalidOffsetException ioe){
1134 throw new GateRuntimeException(ioe);
1136 }
1137 }
1138 }
1139 }
1140
1141 protected class SavePreserveFormatAction extends AbstractAction{
1142 public SavePreserveFormatAction(){
1143 super("Save preserving document format");
1144 }
1145
1146 public void actionPerformed(ActionEvent evt){
1147 Runnable runableAction = new Runnable(){
1148 public void run(){
1149 JFileChooser fileChooser = MainFrame.getFileChooser();
1150 File selectedFile = null;
1151
1152 fileChooser.setMultiSelectionEnabled(false);
1153 fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
1154 fileChooser.setDialogTitle("Select document to save ...");
1155 fileChooser.setSelectedFiles(null);
1156
1157 int res = fileChooser.showDialog(owner, "Save");
1158 if(res == JFileChooser.APPROVE_OPTION){
1159 selectedFile = fileChooser.getSelectedFile();
1160 fileChooser.setCurrentDirectory(fileChooser.getCurrentDirectory());
1161 if(selectedFile == null) return;
1162 StatusListener sListener = (StatusListener)MainFrame.getListeners().
1163 get("gate.event.StatusListener");
1164 if (sListener != null)
1165 sListener.statusChanged("Please wait while dumping annotations"+
1166 "in the original format to " + selectedFile.toString() + " ...");
1167 Set annotationsToDump = new HashSet();
1171 Iterator setIter = setHandlers.iterator();
1172 while(setIter.hasNext()){
1173 SetHandler sHandler = (SetHandler)setIter.next();
1174 Iterator typeIter = sHandler.typeHandlers.iterator();
1175 while(typeIter.hasNext()){
1176 TypeHandler tHandler = (TypeHandler)typeIter.next();
1177 if(tHandler.isSelected()){
1178 annotationsToDump.addAll(sHandler.set.get(tHandler.name));
1179 }
1180 }
1181 }
1182
1183 try{
1184 String encoding = ((TextualDocument)document).getEncoding();
1186
1187 OutputStreamWriter writer = new OutputStreamWriter(
1188 new FileOutputStream(selectedFile),
1189 encoding);
1190
1191 Boolean featuresSaved =
1193 Gate.getUserConfig().getBoolean(
1194 GateConstants.SAVE_FEATURES_WHEN_PRESERVING_FORMAT);
1195 boolean saveFeatures = true;
1196 if (featuresSaved != null)
1197 saveFeatures = featuresSaved.booleanValue();
1198 writer.write(
1200 document.toXml(annotationsToDump, saveFeatures));
1201 writer.flush();
1202 writer.close();
1203 } catch (Exception ex){
1204 ex.printStackTrace(Out.getPrintWriter());
1205 } if (sListener != null)
1207 sListener.statusChanged("Finished dumping into the "+
1208 "file : " + selectedFile.toString());
1209 } } }; Thread thread = new Thread(runableAction, "");
1213 thread.setPriority(Thread.MIN_PRIORITY);
1214 thread.start();
1215 }
1216 }
1217
1218
1222 protected class MouseStoppedMovingAction extends AbstractAction{
1223
1224 public void actionPerformed(ActionEvent evt){
1225 if(textPane.getSelectionStart() <= textLocation &&
1228 textPane.getSelectionEnd() >= textLocation){
1229 new NewAnnotationAction().actionPerformed(evt);
1230 }else{
1231 List annotsAtPoint = new ArrayList();
1233 Iterator shIter = setHandlers.iterator();
1234 while(shIter.hasNext()){
1235 SetHandler sHandler = (SetHandler)shIter.next();
1236 Iterator annIter = sHandler.set.get(new Long(textLocation),
1237 new Long(textLocation)).iterator();
1238 while(annIter.hasNext()){
1239 Annotation ann = (Annotation)annIter.next();
1240 if(sHandler.getTypeHandler(ann.getType()).isSelected()){
1241 annotsAtPoint.add(new AnnotationHandler(sHandler.set, ann));
1242 }
1243 }
1244 }
1245 if(annotsAtPoint.size() > 0){
1246 if(annotsAtPoint.size() > 1){
1247 JPopupMenu popup = new JPopupMenu();
1248 Iterator annIter = annotsAtPoint.iterator();
1249 while(annIter.hasNext()){
1250 AnnotationHandler aHandler = (AnnotationHandler)annIter.next();
1251 popup.add(new HighlightMenuItem(
1252 new EditAnnotationAction(aHandler),
1253 aHandler.ann.getStartNode().getOffset().intValue(),
1254 aHandler.ann.getEndNode().getOffset().intValue(),
1255 popup));
1256 }
1257 try{
1258 Rectangle rect = textPane.modelToView(textLocation);
1259 popup.show(textPane, rect.x + 10, rect.y);
1260 }catch(BadLocationException ble){
1261 throw new GateRuntimeException(ble);
1262 }
1263 }else{
1264 new EditAnnotationAction((AnnotationHandler)annotsAtPoint.get(0)).
1266 actionPerformed(null);
1267 }
1268 }
1269 }
1270 }
1271
1272 public void setTextLocation(int textLocation){
1273 this.textLocation = textLocation;
1274 }
1275 int textLocation;
1276 }
1278
1279
1284 protected class HighlightMenuItem extends JMenuItem {
1285 public HighlightMenuItem(Action action, int startOffset, int endOffset,
1286 JPopupMenu popup) {
1287 super(action);
1288 this.start = startOffset;
1289 this.end = endOffset;
1290 this.addMouseListener(new MouseAdapter() {
1291 public void mouseEntered(MouseEvent e) {
1292 showHighlight();
1293 }
1294
1295 public void mouseExited(MouseEvent e) {
1296 removeHighlight();
1297 }
1298 });
1299 popup.addPopupMenuListener(new PopupMenuListener(){
1300 public void popupMenuWillBecomeVisible(PopupMenuEvent e){
1301
1302 }
1303 public void popupMenuCanceled(PopupMenuEvent e){
1304 removeHighlight();
1305 }
1306 public void popupMenuWillBecomeInvisible(PopupMenuEvent e){
1307 removeHighlight();
1308 }
1309
1310
1311 });
1312 }
1313
1314 protected void showHighlight(){
1315 try {
1316 highlight = textPane.getHighlighter().addHighlight(start, end,
1317 DefaultHighlighter.DefaultPainter);
1318 }catch(BadLocationException ble){
1319 throw new GateRuntimeException(ble.toString());
1320 }
1321
1322 }
1323
1324 protected void removeHighlight(){
1325 if(highlight != null){
1326 textPane.getHighlighter().removeHighlight(highlight);
1327 highlight = null;
1328 }
1329
1330 }
1331
1332 int start;
1333 int end;
1334 Action action;
1335 Object highlight;
1336 }
1337
1338
1339
1340 protected class EditAnnotationAction extends AbstractAction{
1341 public EditAnnotationAction(AnnotationHandler aHandler){
1342 super(aHandler.ann.getType() + " [" +
1343 (aHandler.set.getName() == null ? " " :
1344 aHandler.set.getName()) +
1345 "]");
1346 putValue(SHORT_DESCRIPTION, aHandler.ann.getFeatures().toString());
1347 this.aHandler = aHandler;
1348 }
1349
1350 public void actionPerformed(ActionEvent evt){
1351 annotationEditor.setAnnotation(aHandler.ann, aHandler.set);
1352
1353 if(listView != null && listView.isActive() &&
1355 listView.getGUI().isVisible()){
1356 TypeHandler tHandler = getTypeHandler(aHandler.set.getName(),
1357 aHandler.ann.getType());
1358 if(tHandler != null){
1359 Object tag = tHandler.hghltTagsForAnn.get(aHandler.ann.getId());
1360 listView.selectAnnotationForTag(tag);
1361 }
1362 }
1363 annotationEditor.show(true);
1364 }
1365
1366 AnnotationHandler aHandler;
1367 }
1368
1369 protected class DeleteSelectedAnnotationGroupAction extends AbstractAction{
1370 public DeleteSelectedAnnotationGroupAction(){
1371 }
1372 public void actionPerformed(ActionEvent evt){
1373 int row = mainTable.getSelectedRow();
1374 if(row >= 0){
1375 Object handler = tableRows.get(row);
1376 if(handler instanceof TypeHandler){
1377 TypeHandler tHandler = (TypeHandler)handler;
1378 AnnotationSet set = tHandler.setHandler.set;
1379 AnnotationSet toDeleteAS = set.get(tHandler.name);
1380 if(toDeleteAS != null){
1381 List toDelete = new ArrayList(toDeleteAS);
1382 set.removeAll(toDelete);
1383 }
1384 }else if(handler instanceof SetHandler){
1385 SetHandler sHandler = (SetHandler)handler;
1386 if(sHandler.set == document.getAnnotations()){
1387 sHandler.set.clear();
1389 }else{
1390 document.removeAnnotationSet(sHandler.set.getName());
1391 }
1392 }
1393 }
1394 }
1395 }
1396
1397 List setHandlers;
1398 List tableRows;
1399 XJTable mainTable;
1400 SetsTableModel tableModel;
1401 JScrollPane scroller;
1402 JPanel mainPanel;
1403 JTextField newSetNameTextField;
1404
1405 TextualDocumentView textView;
1406 AnnotationListView listView;
1407 JEditorPane textPane;
1408 AnnotationEditor annotationEditor;
1409 NewAnnotationSetAction newSetAction;
1410
1411
1414 protected TextMouseListener textMouseListener;
1415
1416 protected javax.swing.Timer mouseMovementTimer;
1417 private static final int MOUSE_MOVEMENT_TIMER_DELAY = 500;
1418 protected AncestorListener textAncestorListener;
1419 protected MouseStoppedMovingAction mouseStoppedMovingAction;
1420
1421 protected String lastAnnotationType = "_New_";
1422
1423 protected List actions;
1424
1425 protected ColorGenerator colourGenerator;
1426 private static final int NAME_COL = 1;
1427 private static final int SELECTED_COL = 0;
1428
1429}
1430