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