DocumentEditor.java
0001 /*
0002  *  Copyright (c) 1995-2010, The University of Sheffield. See the file
0003  *  COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
0004  *
0005  *  This file is part of GATE (see http://gate.ac.uk/), and is free
0006  *  software, licenced under the GNU Library General Public License,
0007  *  Version 2, June 1991 (in the distribution as file licence.html,
0008  *  and also available at http://gate.ac.uk/gate/licence.html).
0009  *
0010  *  Valentin Tablan 13/11/2000
0011  *
0012  *  $Id: DocumentEditor.java 12950 2010-08-11 18:58:56Z bensonmargulies $
0013  *
0014  */
0015 package gate.gui;
0016 
0017 import java.awt.*;
0018 import java.awt.event.*;
0019 import java.awt.font.TextAttribute;
0020 import java.awt.print.*;
0021 import java.beans.*;
0022 import java.io.IOException;
0023 import java.io.Reader;
0024 import java.util.*;
0025 import java.util.regex.Matcher;
0026 import java.util.regex.Pattern;
0027 import javax.swing.*;
0028 import javax.swing.border.Border;
0029 import javax.swing.event.ListSelectionEvent;
0030 import javax.swing.event.ListSelectionListener;
0031 import javax.swing.table.AbstractTableModel;
0032 import javax.swing.text.*;
0033 import javax.swing.tree.*;
0034 import gate.*;
0035 import gate.corpora.DocumentContentImpl;
0036 import gate.creole.*;
0037 import gate.event.*;
0038 import gate.print.JComponentPrinter;
0039 import gate.swing.*;
0040 import gate.util.*;
0041 
0042 /**
0043  * This class implements a viewer/editor for the annotations on a document.
0044  * As a viewer, this visual resource will display all the annotations found on
0045  * the document. The editor needs to have some data about annotation types in
0046  * order to allow the editing of annotations. This data comes from the
0047  {@link gate.creole.AnnotationSchema} objects that are loaded in the Gate
0048  * system at a given moment. If there are no such objects the editing of
0049  * annotations will be restricted to a very crude method allowing the user to
0050  * add any type of annotations having any features with any String values.
0051  
0052  * This class has been deprecated! The document editing functionality is now
0053  * provided by the {@link gate.gui.docview.DocumentEditor} class.
0054  
0055  @deprecated
0056  */
0057 public class DocumentEditor extends AbstractVisualResource
0058                             implements ANNIEConstants{
0059   //properties
0060   private transient PropertyChangeSupport propertyChangeListeners =
0061                                           new PropertyChangeSupport(this);
0062   /**
0063    * The {@link gate.Document} currently displayed.
0064    */
0065   private gate.Document document;
0066 
0067   /**
0068    * A random colour generator used to generate initial default colours for
0069    * highlighting various types of annotations.
0070    */
0071   protected ColorGenerator colGenerator = new ColorGenerator();
0072 
0073   //GUI components
0074   /** The text display.*/
0075   protected JTextPane textPane;
0076 
0077   /** Scroller used for the text diaplay*/
0078   protected JScrollPane textScroll;
0079 
0080   /** The table placed below the text display used for showing annotations*/
0081   protected XJTable annotationsTable;
0082 
0083   /**Model for the annotations table*/
0084   protected AnnotationsTableModel annotationsTableModel;
0085 
0086   /** Scroller for the annotations table*/
0087   protected JScrollPane tableScroll;
0088 
0089   /*The split that contains the text(top) and the annotations table(bottom)*/
0090   protected JSplitPane leftSplit;
0091 
0092   /**
0093    * The split that contains the styles tree and the coreference viewer.
0094    */
0095   protected JSplitPane rightSplit;
0096 
0097   /**
0098    * The main horizontal split that contains all the contents of this viewer
0099    */
0100   protected JSplitPane mainSplit;
0101 
0102   /**
0103    * The right hand side tree with all  the annotation sets and types of
0104    * annotations
0105    */
0106   protected JTree stylesTree;
0107 
0108   /**
0109    * The toolbar displayed on the top part of the component
0110    */
0111   protected JToolBar toolbar;
0112 
0113   /**Scroller for the styles tree*/
0114   protected JScrollPane stylesTreeScroll;
0115 
0116   /**The root for the styles tree*/
0117   protected DefaultMutableTreeNode stylesTreeRoot;
0118 
0119   /**The model for the styles tree*/
0120   protected DefaultTreeModel stylesTreeModel;
0121 
0122   /**The dialog used for text search*/
0123   protected SearchDialog searchDialog;
0124 
0125   /**The dialog used for editing the styles used to highlight annotations*/
0126   protected TextAttributesChooser styleChooser;
0127 
0128 
0129   /**
0130    * The Jtree that displays the coreference data
0131    */
0132   protected JTree corefTree;
0133   /**
0134    * The root for the coref tree
0135    */
0136   protected DefaultMutableTreeNode corefTreeRoot;
0137 
0138   /**
0139    * The model for the coref tree
0140    */
0141   protected DefaultTreeModel corefTreeModel;
0142 
0143   /** The scroller for the coref list*/
0144   protected JScrollPane corefScroll;
0145 
0146   /**
0147    * A box containing a {@link javax.swing.JProgressBar} used to keep the user
0148    * entertained while the text display is being updated
0149    */
0150   protected Box progressBox;
0151 
0152   /**The progress bar used during updating the text*/
0153   protected JProgressBar progressBar;
0154 
0155   /**
0156    * The highlighter used to help the user select annotations that overlap
0157    * and for highligting in the text the annotations selected in the lower
0158    * table.
0159    */
0160   protected Highlighter highlighter;
0161 
0162   /**
0163    * This highlighter is actually used as a data structure. It is used to keep
0164    * the data for the selected annotations; the actual highlighting will be
0165    * done by the {@link #highlighter} as using two different
0166    * highlighters on the same text component is looking for trouble.
0167    */
0168   protected Highlighter selectionHighlighter;
0169 
0170   /**
0171    * The object responsible with blinking the selected annotations.
0172    */
0173   protected SelectionBlinker selectionBlinker;
0174 
0175 
0176   protected Handle myHandle;
0177 
0178   /**
0179    * holds the data for the  annotations table: a list of Annotation objects
0180    */
0181   protected java.util.List data;
0182 
0183   /**
0184    * a list containing {@link Range} objects. These are the
0185    * ranges in the {@link #data} structure. A range is a bunch
0186    * of annotations belonging to the same annotation set that are contiguous
0187    * in the {@link #data} structure.
0188    */
0189   protected java.util.List ranges;
0190 
0191   /**
0192    * A composed map used to get the metadata for an annotation type starting
0193    * from the annotation set name and the type name.
0194    * Annotation set name -> Annotation type -> {@link TypeData}
0195    * Maps from String to Map to {@link TypeData}.
0196    */
0197   protected Map typeDataMap;
0198 
0199   /**
0200    * The listener for the events coming from the document (annotations and
0201    * annotation sets added or removed).
0202    */
0203   protected EventsHandler eventHandler;
0204 
0205 
0206   /**
0207    * Object used to sychronise all the various threads involved in GUI
0208    * updating;
0209    */
0210   protected Object lock;
0211 
0212   /**Should the table be visible*/
0213 
0214   /**Should the text be visible*/
0215 
0216   /**
0217    * Should the right hand side tree be visible. That tree is used to select
0218    * what types of annotations are visible in the text display, hence the name
0219    * filters.
0220    */
0221 
0222   /**Should this component bahave as an editor as well as an viewer*/
0223   private boolean editable = true;
0224 
0225 
0226 
0227   private JToggleButton textVisibleBtn;
0228   private JToggleButton typesTreeVisibleBtn;
0229   private JToggleButton annotationsTableVisibleBtn;
0230   private JToggleButton coreferenceVisibleBtn;
0231   private boolean annotationsTableVisible = false;
0232   private boolean coreferenceVisible = false;
0233   private boolean textVisible = true;
0234   private boolean typesTreeVisible = false;
0235   private boolean corefOptionAvailable = false;
0236 
0237   /**
0238    * Default constructor. Creats all the components and initialises all the
0239    * internal data to default values where possible.
0240    */
0241   public DocumentEditor() {
0242   }
0243 
0244   public Resource init(){
0245     initLocalData();
0246     initGuiComponents();
0247     initListeners();
0248     return this;
0249   }
0250 
0251   /**
0252    * Initialises all the listeners that this component has to register with
0253    * other classes.
0254    */
0255   protected void initListeners() {
0256     //listen for our own properties change events
0257     this.addPropertyChangeListener(new PropertyChangeListener() {
0258       public void propertyChange(PropertyChangeEvent e) {
0259         if(e.getPropertyName().equals("annotationsTableVisible"||
0260            e.getPropertyName().equals("coreferenceVisible"||
0261            e.getPropertyName().equals("textVisible"||
0262            e.getPropertyName().equals("typesTreeVisible")){
0263           layoutComponents();
0264         }else if(e.getPropertyName().equals("corefOptionAvailable")){
0265           if(((Boolean)e.getNewValue()).booleanValue()){
0266             if(toolbar.getComponentIndex(coreferenceVisibleBtn== -1)
0267               toolbar.add(coreferenceVisibleBtn, 3);
0268           }else{
0269             toolbar.remove(coreferenceVisibleBtn);
0270           }
0271           layoutComponents();
0272         }
0273       }
0274     });
0275 
0276     textVisibleBtn.addActionListener(new ActionListener() {
0277       public void actionPerformed(ActionEvent e) {
0278         setTextVisible(textVisibleBtn.isSelected());
0279       }
0280     });
0281 
0282     annotationsTableVisibleBtn.addActionListener(new ActionListener() {
0283       public void actionPerformed(ActionEvent e) {
0284         setAnnotationsTableVisible(annotationsTableVisibleBtn.isSelected());
0285       }
0286     });
0287 
0288 
0289     typesTreeVisibleBtn.addActionListener(new ActionListener() {
0290       public void actionPerformed(ActionEvent e) {
0291         setTypesTreeVisible(typesTreeVisibleBtn.isSelected());
0292       }
0293     });
0294 
0295 
0296     coreferenceVisibleBtn.addActionListener(new ActionListener() {
0297       public void actionPerformed(ActionEvent e) {
0298         setCoreferenceVisible(coreferenceVisibleBtn.isSelected());
0299       }
0300     });
0301 
0302     stylesTree.addMouseListener(new MouseAdapter() {
0303       public void mouseClicked(MouseEvent e) {
0304         if(SwingUtilities.isLeftMouseButton(e)){
0305           //where inside the tree?
0306           int x = e.getX();
0307           int y = e.getY();
0308           TreePath path = stylesTree.getPathForLocation(x, y);
0309           if(path != null){
0310             DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.
0311                                          getLastPathComponent();
0312             TypeData nData = (TypeData)node.getUserObject();
0313             //where inside the cell?
0314             Rectangle cellRect = stylesTree.getPathBounds(path);
0315             x -= cellRect.x;
0316             y -= cellRect.y;
0317             Component cellComp = stylesTree.getCellRenderer().
0318                                  getTreeCellRendererComponent(stylesTree,
0319                                                               node, true,
0320                                                               false, false,
0321                                                               0true);
0322 //            cellComp.setSize(cellRect.width, cellRect.height);
0323             cellComp.setBounds(cellRect);
0324             Component clickedComp = cellComp.getComponentAt(x, y);
0325 
0326             if(clickedComp instanceof JCheckBox){
0327               nData.setVisible(! nData.getVisible());
0328 //              stylesTree.repaint(cellRect);
0329               stylesTreeModel.nodeChanged(node);
0330             // Check if the click indicates a shortcut to create an annotation
0331             }else ife.getClickCount() == &&
0332                       clickedComp instanceof JLabel &&
0333                       isTextSelected()){
0334               // Here creates an annotation with the selected text into the
0335               // target annotation set
0336 
0337               if(!editablereturn;
0338               Long startOffset = new Long(textPane.getSelectionStart());
0339               Long endOffset = new Long(textPane.getSelectionEnd());
0340               TreePath treePath = stylesTree.getSelectionPath();
0341               TypeData typeData = (TypeData)((DefaultMutableTreeNode)
0342                               treePath.getLastPathComponent()).getUserObject();
0343               String setName = typeData.getSet();
0344               if(typeData.getType() == null){
0345                 // The set is empty. It will not create an annotation.
0346                 // Loose the selection and return
0347                 textPane.setSelectionStart(startOffset.intValue());
0348                 textPane.setSelectionEnd(startOffset.intValue());
0349                 return;
0350               }// End if
0351               try{
0352                 if ("Default".equals(setName)){
0353                   document.getAnnotations().add(startOffset,
0354                                                 endOffset,
0355                                                 typeData.getType(),
0356                                                 Factory.newFeatureMap());
0357                 }else{
0358                   document.getAnnotations(setName).addstartOffset,
0359                                                         endOffset,
0360                                                         typeData.getType(),
0361                                                        Factory.newFeatureMap());
0362                 }// End if
0363               catch(gate.util.InvalidOffsetException ioe){
0364                 throw new GateRuntimeException(ioe.getMessage());
0365               }// End try
0366               // Loose the selection
0367               textPane.setSelectionStart(startOffset.intValue());
0368               textPane.setSelectionEnd(startOffset.intValue());
0369             }else if(clickedComp instanceof JLabel &&
0370                      e.getClickCount() == 2){
0371               if(styleChooser == null){
0372                 Window parent = SwingUtilities.getWindowAncestor(
0373                                   DocumentEditor.this);
0374                 styleChooser = parent instanceof Frame ?
0375                                new TextAttributesChooser((Frame)parent,
0376                                                          "Please select your options",
0377                                                          true:
0378                                new TextAttributesChooser((Dialog)parent,
0379                                                          "Please select your options",
0380                                                          true);
0381 
0382               }
0383 
0384               styleChooser.setLocationRelativeTo(stylesTree);
0385               nData.setAttributes(
0386                     styleChooser.show(nData.getAttributes().copyAttributes()));
0387               stylesTreeModel.nodeChanged(node);
0388 //              stylesTree.repaint(cellRect);
0389             }
0390           }
0391         }
0392       }
0393     });
0394 
0395     stylesTree.addComponentListener(new ComponentAdapter() {
0396       public void componentHidden(ComponentEvent e) {
0397 
0398       }
0399 
0400       public void componentMoved(ComponentEvent e) {
0401       }
0402 
0403       public void componentResized(ComponentEvent e) {
0404         SwingUtilities.invokeLater(new Runnable(){
0405           public void run(){
0406             Enumeration nodes = stylesTreeRoot.depthFirstEnumeration();
0407             while(nodes.hasMoreElements()){
0408               stylesTreeModel.nodeChanged((TreeNode)nodes.nextElement());
0409             }
0410           }
0411         });
0412       }
0413 
0414       public void componentShown(ComponentEvent e) {
0415       }
0416     });
0417 
0418     //clear selection in table on outside clicks
0419     tableScroll.addMouseListener(new MouseAdapter() {
0420       public void mouseClicked(MouseEvent e) {
0421         Point location = e.getPoint();
0422         if(!tableScroll.getViewport().getView().getBounds().contains(location)){
0423           //deselect everything in the table
0424           annotationsTable.clearSelection();
0425         }
0426       }
0427     });
0428 
0429     annotationsTable.addMouseListener(new MouseAdapter() {
0430       public void mouseClicked(MouseEvent e) {
0431         int row = annotationsTable.rowAtPoint(e.getPoint());
0432         Annotation ann = (Annotation)annotationsTable.getModel().
0433                                                       getValueAt(row, -1);
0434         //find the annotation set
0435         String setName = (String)annotationsTable.getModel().
0436                                                     getValueAt(row, 1);
0437         AnnotationSet set = setName.equals("Default")?
0438                             document.getAnnotations() :
0439                             document.getAnnotations(setName);
0440 
0441         EditAnnotationAction editAnnAct = new EditAnnotationAction(set, ann);
0442         if(SwingUtilities.isLeftMouseButton(e)){
0443           if(e.getClickCount() == 1){
0444           }else if(e.getClickCount() == 2){
0445             //double left click -> edit the annotation
0446             if(editableeditAnnAct.actionPerformed(null);
0447           }
0448         else if(SwingUtilities.isRightMouseButton(e)) {
0449           //right click
0450           //add select all option
0451           JPopupMenu popup = new XJPopupMenu();
0452           popup.add(new AbstractAction(){
0453             {
0454               putValue(NAME, "Select all");
0455             }
0456             public void actionPerformed(ActionEvent evt){
0457               annotationsTable.selectAll();
0458             }
0459           });
0460 
0461 //          popup.addSeparator();
0462           //add save preserving format
0463 //          popup.add(new DumpPreserveFormatAction());
0464           if(editable){
0465             //add delete option
0466             popup.addSeparator();
0467             popup.add(new DeleteSelectedAnnotationsAction(annotationsTable));
0468             popup.addSeparator();
0469             popup.add(new XJMenuItem(editAnnAct, myHandle));
0470           }
0471           popup.show(annotationsTable, e.getX(), e.getY());
0472         }
0473       }
0474     });//annotationsTable.addMouseListener(new MouseAdapter()
0475 
0476 
0477 
0478     annotationsTable.getInputMap().put(
0479                   KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_DELETE, 0),
0480                   "Delete");
0481     annotationsTable.getActionMap().put(
0482                         "Delete",
0483                         new DeleteSelectedAnnotationsAction(annotationsTable));
0484 
0485     stylesTree.getInputMap().put(
0486                   KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_DELETE, 0),
0487                   "Delete");
0488     stylesTree.getActionMap().put(
0489                         "Delete",
0490                         new DeleteSelectedAnnotationsAction(stylesTree));
0491 
0492     corefTree.getInputMap().put(
0493                   KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_DELETE, 0),
0494                   "Delete");
0495     corefTree.getActionMap().put(
0496                         "Delete",
0497                         new DeleteSelectedAnnotationsAction(corefTree));
0498 
0499 
0500     //takes care of highliting the selected annotations
0501     annotationsTable.getSelectionModel().addListSelectionListener(
0502       new ListSelectionListener(){
0503         public void valueChanged(ListSelectionEvent e){
0504           int[] rows = annotationsTable.getSelectedRows();
0505           synchronized(selectionHighlighter){
0506             selectionHighlighter.removeAllHighlights();
0507           }
0508           for(int i = 0; i < rows.length; i++){
0509             int start = ((Long)annotationsTable.getModel().
0510                          getValueAt(rows[i]2)
0511                         ).intValue();
0512             int end = ((Long)annotationsTable.getModel().
0513                        getValueAt(rows[i]3)
0514                       ).intValue();
0515 
0516             // compute correction for new line breaks in long lines
0517             start += longLinesCorrection(start);
0518             end += longLinesCorrection(end);
0519 
0520             //bring the annotation in view
0521             try{
0522               Rectangle startRect = textPane.modelToView(start);
0523               Rectangle endRect = textPane.modelToView(end);
0524               SwingUtilities.computeUnion(endRect.x, endRect.y,
0525                                           endRect.width, endRect.height,
0526                                           startRect);
0527               textPane.scrollRectToVisible(startRect);
0528               annotationsTable.requestFocus();
0529             }catch(BadLocationException ble){
0530               throw new GateRuntimeException(ble.toString());
0531             }
0532             //start blinking the annotation
0533             try{
0534               synchronized (selectionHighlighter){
0535                 selectionHighlighter.addHighlight(start, end,
0536                             DefaultHighlighter.DefaultPainter);
0537               }
0538             }catch(BadLocationException ble){
0539               throw new GateRuntimeException(ble.toString());
0540             }
0541           }//for(int i = 0; i < rows.length; i++)
0542           //start the blinker
0543           selectionBlinker.testAndStart();
0544         }
0545       });
0546 
0547 
0548     textPane.addMouseListener(new MouseAdapter() {
0549       public void mouseClicked(MouseEvent e) {
0550         if(SwingUtilities.isRightMouseButton(e)){
0551           int position = textPane.viewToModel(e.getPoint());
0552           if(textPane.getSelectionStart() ==  textPane.getSelectionEnd()){
0553             //no selection -> select an annotation
0554             JPopupMenu popup = new XJPopupMenu("Select:");
0555             //find annotations at this position
0556             Iterator<Annotation> annIter = document.getAnnotations().
0557                                         get(new Long(position),
0558                                             new Long(position)
0559                                         ).iterator();
0560             if(annIter.hasNext()){
0561               JMenu menu = new XJMenu("Default");
0562               popup.add(menu);
0563               while(annIter.hasNext()){
0564                 Annotation ann = annIter.next();
0565                 menu.add(new HighlightAnnotationMenu(ann,
0566                                                      document.getAnnotations()));
0567               }
0568             }
0569             Map namedASs = document.getNamedAnnotationSets();
0570             if(namedASs != null){
0571               Iterator namedASiter = namedASs.values().iterator();
0572               while(namedASiter.hasNext()){
0573                 //find annotations at this position
0574                 AnnotationSet set = (AnnotationSet)namedASiter.next();
0575                 annIter = set.get(new Long(position)new Long(position)).
0576                               iterator();
0577                 if(annIter.hasNext()){
0578                   JMenu menu = new XJMenu(set.getName());
0579                   popup.add(menu);
0580                   while(annIter.hasNext()){
0581                     Annotation ann = annIter.next();
0582                     menu.add(new HighlightAnnotationMenu(ann,set));
0583                   }
0584                 }
0585               }
0586             }
0587             popup.show(textPane, e.getPoint().x, e.getPoint().y);
0588           else {
0589             //there is selected text -> create a new annotation
0590             if(!editablereturn;
0591             Long startOffset = new Long(textPane.getSelectionStart());
0592             Long endOffset = new Long(textPane.getSelectionEnd());
0593             JPopupMenu popup = new XJPopupMenu();
0594             //add new annotation in the Default AS
0595             JMenu menu = new XJMenu("Add annotation to \"Default\"");
0596             menu.add(new XJMenuItem(
0597                          new NewAnnotationAction(document.getAnnotations(),
0598                                                  startOffset, endOffset),
0599                          myHandle));
0600             java.util.List customisedAnnTypes = Gate.getCreoleRegister().
0601                                                 getVREnabledAnnotationTypes();
0602             if(!customisedAnnTypes.isEmpty()){
0603               menu.addSeparator();
0604               Iterator typesIter = customisedAnnTypes.iterator();
0605               while(typesIter.hasNext()){
0606                 menu.add(new XJMenuItem(
0607                              new NewAnnotationAction(document.getAnnotations(),
0608                                                      (String)typesIter.next(),
0609                                                      startOffset, endOffset),
0610                              myHandle));
0611               }
0612             }//if(!customisedAnnTypes.isEmpty())
0613             popup.add(menu);
0614 
0615             //add a new annotation to a named AnnotationSet
0616             if(document.getNamedAnnotationSets() != null){
0617               Iterator annSetsIter = document.getNamedAnnotationSets().
0618                                               keySet().iterator();
0619               if(annSetsIter.hasNext()) popup.addSeparator();
0620               while(annSetsIter.hasNext()){
0621                 AnnotationSet set = document.getAnnotations(
0622                                              (String)annSetsIter.next());
0623 
0624 
0625                 menu = new XJMenu("Add annotation to \"" + set.getName() "\"");
0626                 menu.add(new XJMenuItem(
0627                              new NewAnnotationAction(set, startOffset, endOffset),
0628                              myHandle));
0629                 if(!customisedAnnTypes.isEmpty()){
0630                   menu.addSeparator();
0631                   Iterator typesIter = customisedAnnTypes.iterator();
0632                   while(typesIter.hasNext()){
0633                     menu.add(new XJMenuItem(
0634                                  new NewAnnotationAction(set,
0635                                                          (String)typesIter.next(),
0636                                                          startOffset, endOffset),
0637                                  myHandle));
0638                   }
0639                 }//if(!customisedAnnTypes.isEmpty())
0640                 popup.add(menu);
0641               }//while(annSetsIter.hasNext())
0642             }
0643 
0644             //add to a new annotation set
0645             menu = new XJMenu("Add annotation to a new set");
0646             menu.add(new XJMenuItem(
0647                          new NewAnnotationAction(null, startOffset, endOffset),
0648                          myHandle));
0649             if(!customisedAnnTypes.isEmpty()){
0650               menu.addSeparator();
0651               Iterator typesIter = customisedAnnTypes.iterator();
0652               while(typesIter.hasNext()){
0653                 menu.add(new XJMenuItem(
0654                              new NewAnnotationAction(null,
0655                                                      (String)typesIter.next(),
0656                                                      startOffset, endOffset),
0657                              myHandle));
0658               }
0659             }//if(!customisedAnnTypes.isEmpty())
0660             popup.add(menu);
0661             //show the popup
0662             popup.show(textPane, e.getPoint().x, e.getPoint().y);
0663           }//there is selected text
0664         }//if(SwingUtilities.isRightMouseButton(e))
0665       }//mouse clicked
0666 
0667       public void mousePressed(MouseEvent e) {
0668       }
0669 
0670       public void mouseReleased(MouseEvent e) {
0671       }
0672 
0673       public void mouseEntered(MouseEvent e) {
0674       }
0675 
0676       public void mouseExited(MouseEvent e) {
0677       }
0678     });
0679 
0680     //when the highlighter changes we need to get a hold of the new one
0681     textPane.addPropertyChangeListener(new PropertyChangeListener() {
0682       public void propertyChange(PropertyChangeEvent e) {
0683         if(e.getPropertyName().equals("highlighter")){
0684           highlighter = textPane.getHighlighter();
0685           selectionHighlighter.install(textPane);
0686         }
0687       }
0688     });
0689 
0690     corefTree.addMouseListener(new MouseAdapter() {
0691       public void mouseClicked(MouseEvent e) {
0692         if(SwingUtilities.isLeftMouseButton(e)){
0693           //where inside the tree?
0694           int x = e.getX();
0695           int y = e.getY();
0696           TreePath path = corefTree.getPathForLocation(x, y);
0697           if(path != null){
0698             DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.
0699                                          getLastPathComponent();
0700             //where inside the cell?
0701             Rectangle cellRect = corefTree.getPathBounds(path);
0702             x -= cellRect.x;
0703             y -= cellRect.y;
0704             Component cellComp = corefTree.getCellRenderer().
0705                                  getTreeCellRendererComponent(corefTree,
0706                                                               node, true,
0707                                                               false, false,
0708                                                               0true);
0709             cellComp.setBounds(cellRect);
0710             Component clickedComp = cellComp.getComponentAt(x, y);
0711             if(clickedComp instanceof LazyJPanel)
0712               clickedComp = clickedComp.getComponentAt(x, y);
0713             if(node.getUserObject() instanceof CorefData &&
0714                clickedComp instanceof JCheckBox){
0715               CorefData cData = (CorefData)node.getUserObject();
0716               cData.setVisible(!cData.getVisible());
0717               corefTreeModel.nodeChanged(node);
0718             }
0719           }
0720         }
0721       }
0722 
0723       public void mousePressed(MouseEvent e) {
0724       }
0725 
0726       public void mouseReleased(MouseEvent e) {
0727       }
0728 
0729       public void mouseEntered(MouseEvent e) {
0730       }
0731 
0732       public void mouseExited(MouseEvent e) {
0733       }
0734     });
0735 
0736 
0737 
0738     corefTree.addComponentListener(new ComponentAdapter() {
0739       public void componentHidden(ComponentEvent e) {
0740 
0741       }
0742 
0743       public void componentMoved(ComponentEvent e) {
0744       }
0745 
0746       public void componentResized(ComponentEvent e) {
0747         SwingUtilities.invokeLater(new Runnable(){
0748           public void run(){
0749             Enumeration nodes = corefTreeRoot.depthFirstEnumeration();
0750             while(nodes.hasMoreElements()){
0751               corefTreeModel.nodeChanged((TreeNode)nodes.nextElement());
0752             }
0753           }
0754         });
0755       }
0756 
0757       public void componentShown(ComponentEvent e) {
0758       }
0759     });
0760   }//protected void initListeners()
0761 
0762   /**
0763    * Initialises the local variables to their default values
0764    */
0765   protected void initLocalData(){
0766     //init local vars
0767     lock = new Object();
0768 
0769     data = Collections.synchronizedList(new ArrayList());
0770     //dataAsAS = new gate.annotation.AnnotationSetImpl(document);
0771     ranges = new ArrayList();
0772 
0773     typeDataMap = new HashMap();
0774 
0775     eventHandler = new EventsHandler();
0776 
0777   }//protected void initLocalData()
0778 
0779   /**Builds all the graphical components*/
0780   protected void initGuiComponents(){
0781     //initialise GUI components
0782 //    this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
0783     this.setLayout(new BorderLayout());
0784 
0785     //the toolbar
0786     toolbar = new JToolBar(JToolBar.HORIZONTAL);
0787     toolbar.setAlignmentX(Component.LEFT_ALIGNMENT);
0788     toolbar.setAlignmentY(Component.TOP_ALIGNMENT);
0789     toolbar.setFloatable(false);
0790     this.add(toolbar, BorderLayout.NORTH);
0791 
0792     textVisibleBtn = new JToggleButton("Text", textVisible);
0793     toolbar.add(textVisibleBtn);
0794 
0795     annotationsTableVisibleBtn = new JToggleButton("Annotations",
0796                                                    annotationsTableVisible);
0797     toolbar.add(annotationsTableVisibleBtn);
0798 
0799     typesTreeVisibleBtn = new JToggleButton("Annotation Sets", typesTreeVisible);
0800     toolbar.add(typesTreeVisibleBtn);
0801 
0802 
0803     coreferenceVisibleBtn = new JToggleButton("Coreference", coreferenceVisible);
0804     if(isCorefOptionAvailable()) toolbar.add(coreferenceVisibleBtn);
0805 
0806 
0807     //printing
0808     toolbar.add(Box.createHorizontalStrut(20));
0809     toolbar.add(new PrintAction());
0810     toolbar.add(new SearchAction());
0811 
0812 
0813 
0814     toolbar.add(Box.createHorizontalGlue());
0815 
0816     //The text
0817     textPane = new XJTextPane();
0818 //    textPane.setEditable(false);
0819     textPane.setEnabled(true);
0820     textPane.setEditorKit(new CustomStyledEditorKit());
0821     Style defaultStyle = textPane.getStyle("default");
0822     StyleConstants.setBackground(defaultStyle, Color.white);
0823     StyleConstants.setFontFamily(defaultStyle, "Arial Unicode MS");
0824     textScroll = new JScrollPane(textPane);
0825     textScroll.setAlignmentY(Component.TOP_ALIGNMENT);
0826     textScroll.setAlignmentX(Component.LEFT_ALIGNMENT);
0827 
0828 
0829     //The table
0830     annotationsTableModel = new AnnotationsTableModel();
0831     annotationsTable = new XJTable(annotationsTableModel);
0832 //    annotationsTable.setIntercellSpacing(new Dimension(10, 5));
0833 
0834     tableScroll = new JScrollPane(annotationsTable);
0835     tableScroll.setOpaque(true);
0836     tableScroll.setAlignmentY(Component.TOP_ALIGNMENT);
0837     tableScroll.setAlignmentX(Component.LEFT_ALIGNMENT);
0838 
0839 
0840     //RIGHT SIDE - the big tree
0841     stylesTreeRoot = new DefaultMutableTreeNode(null, true);
0842     stylesTreeModel = new DefaultTreeModel(stylesTreeRoot, true);
0843     stylesTree = new JTree(stylesTreeModel){
0844       public void updateUI(){
0845         super.updateUI();
0846         setRowHeight(0);
0847       }
0848     };
0849 
0850     stylesTree.setRootVisible(false);
0851     stylesTree.setCellRenderer(new NodeRenderer());
0852     //TIP: setting rowHeight to 0 tells the tree to query its renderer for each
0853     //row's size
0854     stylesTree.setRowHeight(0);
0855     stylesTree.setShowsRootHandles(true);
0856     stylesTree.setToggleClickCount(0);
0857     stylesTreeScroll = new JScrollPane(stylesTree);
0858     stylesTreeScroll.setAlignmentY(Component.TOP_ALIGNMENT);
0859     stylesTreeScroll.setAlignmentX(Component.LEFT_ALIGNMENT);
0860 
0861 
0862     //coreference
0863     corefTreeRoot = new DefaultMutableTreeNode("Co-reference data"true);
0864     corefTree = new JTree(corefTreeModel = new DefaultTreeModel(corefTreeRoot,
0865                                                                 true));
0866     corefTree.setCellRenderer(new CorefNodeRenderer());
0867     corefTree.setRowHeight(0);
0868     corefTree.setRootVisible(true);
0869     corefTree.setShowsRootHandles(false);
0870     corefScroll = new JScrollPane(corefTree);
0871     corefScroll.setAlignmentX(Component.LEFT_ALIGNMENT);
0872     corefScroll.setAlignmentY(Component.TOP_ALIGNMENT);
0873     updateCorefTree();
0874 
0875     //various containers
0876     leftSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, false);
0877     leftSplit.setOneTouchExpandable(true);
0878     leftSplit.setOpaque(true);
0879     leftSplit.setAlignmentY(Component.TOP_ALIGNMENT);
0880     leftSplit.setAlignmentX(Component.LEFT_ALIGNMENT);
0881     leftSplit.setResizeWeight((double)0.75);
0882 
0883     rightSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, false);
0884     rightSplit.setOneTouchExpandable(true);
0885     rightSplit.setOpaque(true);
0886     rightSplit.setAlignmentY(Component.TOP_ALIGNMENT);
0887     rightSplit.setAlignmentX(Component.LEFT_ALIGNMENT);
0888     rightSplit.setResizeWeight((double)0.75);
0889 
0890 
0891     mainSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, false);
0892     mainSplit.setOneTouchExpandable(true);
0893     mainSplit.setOpaque(true);
0894     mainSplit.setAlignmentY(Component.TOP_ALIGNMENT);
0895     mainSplit.setAlignmentX(Component.LEFT_ALIGNMENT);
0896     mainSplit.setResizeWeight((double)0.75);
0897 
0898     //put everything together
0899     layoutComponents();
0900 
0901     //Extra Stuff
0902 
0903     progressBox = new Box(BoxLayout.X_AXIS);
0904     progressBox.add(Box.createHorizontalStrut(5));
0905     progressBar = new JProgressBar(JProgressBar.HORIZONTAL, 0100);
0906     progressBox.add(progressBar);
0907     progressBox.add(Box.createHorizontalStrut(5));
0908 
0909     highlighter = textPane.getHighlighter();
0910     if(highlighter instanceof javax.swing.text.DefaultHighlighter){
0911       ((javax.swing.text.DefaultHighlighter)highlighter).
0912       setDrawsLayeredHighlights(true);
0913     }
0914 
0915     selectionHighlighter = new DefaultHighlighter();
0916     selectionHighlighter.install(textPane);
0917     selectionBlinker = new SelectionBlinker();
0918 
0919   }//protected void initGuiComponents()
0920 
0921 
0922   /** This method returns true if a text is selected in the textPane*/
0923   private boolean isTextSelected(){
0924     return !(textPane.getSelectionStart()==textPane.getSelectionEnd());
0925   }// isTextSelected()
0926   /**
0927    * Gets all the {@link gate.creole.AnnotationSchema} objects currently
0928    * loaded in the system.
0929    */
0930   protected Set getAnnotationSchemas(){
0931     Set result = new HashSet();
0932     ResourceData rData = (ResourceData)Gate.getCreoleRegister().
0933                                             get("gate.creole.AnnotationSchema");
0934     if(rData != null){
0935       result.addAll(rData.getInstantiations());
0936     }
0937     return result;
0938   }//protected Set getAnnotationSchemas()
0939 
0940   public synchronized void removePropertyChangeListener(
0941                                                     PropertyChangeListener l) {
0942     super.removePropertyChangeListener(l);
0943     propertyChangeListeners.removePropertyChangeListener(l);
0944   }
0945 
0946   public synchronized void addPropertyChangeListener(PropertyChangeListener l) {
0947     super.addPropertyChangeListener(l);
0948     propertyChangeListeners.addPropertyChangeListener(l);
0949   }
0950 
0951   public synchronized void addPropertyChangeListener(String propertyName,
0952                                                      PropertyChangeListener l) {
0953     super.addPropertyChangeListener(propertyName, l);
0954     propertyChangeListeners.addPropertyChangeListener(propertyName, l);
0955   }
0956 
0957 
0958   /** Return the current selected document */
0959   public gate.Document getDocument() {
0960     return document;
0961   // Document getDocument()
0962 
0963   /**
0964    * Sets the document to be displayed
0965    */
0966   public void setTarget(Object target){
0967     if(target == null){
0968       document = null;
0969       return;
0970     }
0971     if(!(target instanceof gate.Document)){
0972       throw new IllegalArgumentException(
0973         "The document editor can only display GATE documents!\n" +
0974         "The provided resource is not a document but a: " +
0975         target.getClass().toString() "!");
0976     }
0977     gate.Document  oldDocument = document;
0978     document = (gate.Document)target;
0979     //this needs to be executed even if the new document equals(oldDocument)
0980     //in order to update the pointers
0981     if(oldDocument != documentthis_documentChanged();
0982 
0983     propertyChangeListeners.firePropertyChange("document", oldDocument,
0984                                                target);
0985   }//public void setTarget(Object target)
0986 
0987   public void setHandle(Handle handle){
0988     myHandle = handle;
0989   }
0990 
0991   public void cleanup(){
0992     document = null;
0993     stylesTreeRoot.removeAllChildren();
0994     data.clear();
0995     ranges.clear();
0996     myHandle = null;
0997   }
0998 
0999   /**
1000    * This method returns a list of annotations which are currently shown in
1001    * the annotations table or null of the table is empty.
1002    */
1003   public java.util.Set getDisplayedAnnotations() {
1004     //if the annotations table is empty, then return null
1005     if (annotationsTableModel == null||annotationsTableModel.getRowCount() == 0)
1006       return null;
1007 
1008     // Read the displayed annotations and insert them into a list
1009     java.util.Set shownAnnots = new HashSet();
1010     for(int i = 0; i < annotationsTableModel.getRowCount(); i++){
1011       //Find an annotation and add it to the annotationsToDump set.
1012       Annotation ann = (Annotation)annotationsTableModel.getValueAt(i, -1);
1013       shownAnnots.add(ann);
1014     }// End for
1015 
1016     return shownAnnots;
1017   }
1018 
1019   /**
1020    * Get positions of cut points inside a very large text without new line
1021    */
1022   private Vector getBreakPositions(String content) {
1023     Vector breakPositions = new Vector();
1024 
1025     int lastNewLinePos = -1;
1026     int spacePos = -1;
1027     int unbreakedLineSize = 0;
1028     char ch;
1029     int contentSize = content.length();
1030 
1031     for(int i=0; i<contentSize; ++i) {
1032       ch = content.charAt(i);
1033 
1034       switch(ch) {
1035         case '\n' :
1036             unbreakedLineSize = 0;
1037             spacePos = -1;
1038           break;
1039         case '\r' :
1040             unbreakedLineSize = 0;
1041             spacePos = -1;
1042           break;
1043         case '\t' :
1044             spacePos = i;
1045             ++unbreakedLineSize;
1046           break;
1047         case ' ' :
1048             spacePos = i;
1049             ++unbreakedLineSize;
1050           break;
1051 
1052         default:
1053           if(unbreakedLineSize >= MAX_LINE_SIZE) {
1054             // insert break
1055             if(spacePos == -1) {
1056               // break without space
1057               spacePos = i;
1058             // if
1059 
1060             breakPositions.add(new Integer(spacePos+1));
1061             unbreakedLineSize = i - spacePos;
1062             spacePos = -1;
1063           }
1064           else {
1065             ++unbreakedLineSize;
1066           // if
1067       // switch
1068     // for
1069 
1070     return breakPositions;
1071   // getBreakPositions(String content)
1072 
1073   /** Max unbreaked line size */
1074   private final int MAX_LINE_SIZE = 2048;
1075 
1076   /**
1077    * Cut very long lines to pieces not grater than MAX_LINE_SIZE
1078    * This is a correction of SWING problem with very long lines of text
1079    <BR>
1080    * Return positions of new line insertion.
1081    */
1082   private Vector correctLongLines(StringBuffer buff) {
1083     // analyze for long unbreaked line of text
1084     Vector breaks = getBreakPositions(buff.toString());
1085 //if(breaks.size() > 0) System.out.println("Breaks: "+breaks);
1086 
1087     Integer currentBreak;
1088     int intValue;
1089     // put new line in break positions
1090     for(int i = breaks.size()-1; i>=0; --i) {
1091       currentBreak = (Integerbreaks.get(i);
1092       intValue = currentBreak.intValue();
1093       buff.insert(intValue, '\n');
1094     // for
1095 
1096     if(breaks.size() 0) {
1097       return breaks;
1098     }
1099     else {
1100       return null;
1101     }
1102   // correctLongLines(StringBuffer buff)
1103 
1104   /** Compute correction for additional new line in very long lines of text */
1105   private int longLinesCorrection(int position) {
1106     int result = 0;
1107 
1108     if(longLinesCorrectionPositions != null) {
1109       boolean underPosition = true;
1110       Integer current;
1111       Iterator it = longLinesCorrectionPositions.iterator();
1112 
1113       while(underPosition && it.hasNext()) {
1114         current = (Integerit.next();
1115         if(position > (current.intValue()+result)) {
1116           // cross this new line point
1117           ++result;
1118         }
1119         else {
1120           // all new lines computed
1121           underPosition = false;
1122         // if
1123       // while
1124     // if
1125 
1126     return result;
1127   // int longLinesCorrection(int position)
1128 
1129   /** Keep cut places in very long lines inside document */
1130   private Vector longLinesCorrectionPositions;
1131 
1132   /**
1133    * Updates this component when the underlying document is changed. This method
1134    * is only triggered when the document is changed to a new one and not when
1135    * the internal data from the document changes.
1136    */
1137   protected void this_documentChanged(){
1138     initLocalData();
1139 
1140     Enumeration enumeration = stylesTreeRoot.children();
1141     while(enumeration.hasMoreElements()){
1142       stylesTreeModel.removeNodeFromParent((DefaultMutableTreeNode)
1143                                            enumeration.nextElement());
1144     }
1145     if(document == nullreturn;
1146 
1147     // check for very long lines of text in order to correct SWING bug
1148     String documentContent = document.getContent().toString();
1149     StringBuffer buffContent = new StringBuffer(documentContent);
1150     // cut very long lines to pieces not grater than MAX_LINE_SIZE
1151     longLinesCorrectionPositions = correctLongLines(buffContent);
1152     if(longLinesCorrectionPositions != null) {
1153       documentContent = buffContent.toString();
1154     // if
1155 
1156     textPane.setText(documentContent);
1157     //listen for events from the document content editor
1158     textPane.getDocument().addDocumentListener(new SwingDocumentListener());
1159 
1160     //add the default annotation set
1161     eventHandler.annotationSetAdded(new gate.event.DocumentEvent(
1162                   document,
1163                   gate.event.DocumentEvent.ANNOTATION_SET_ADDED, null));
1164 
1165     //register the for this new document's events
1166     document.addDocumentListener(eventHandler);
1167 
1168     annotationsTableModel.fireTableDataChanged();
1169     document.getFeatures().addFeatureMapListener(new FeatureMapListener(){
1170       public void featureMapUpdated(){
1171         updateCorefTree();
1172       }
1173     });
1174     updateCorefTree();
1175 
1176 
1177     //add all the other annotation sets
1178     Map namedASs = document.getNamedAnnotationSets();
1179     if(namedASs != null){
1180       Iterator setsIter = namedASs.values().iterator();
1181       while(setsIter.hasNext()){
1182         AnnotationSet currentAS = (AnnotationSet)setsIter.next();
1183         if(currentAS != null){
1184           eventHandler.annotationSetAdded(new gate.event.DocumentEvent(
1185                         document,
1186                         gate.event.DocumentEvent.ANNOTATION_SET_ADDED,
1187                         currentAS.getName()));
1188         }
1189       }
1190     }
1191   }//protected void this_documentChanged()
1192 
1193   /**
1194    * Gets the data related to a given annotation type.
1195    * An annotation type is uniquely identified by the name of its AnnotationSet
1196    * and the name of the type.
1197    * For the default annotation set of a document (which has no name) the
1198    * &quot;&lt;Default&gt;&quot; value is used.
1199    *
1200    * Once a {@link TypeData} value has been obtained it can be used to change
1201    * the way the respective type of annotations are displayed.
1202    @param setName a {@link java.lang.String}, the name of the annotation set
1203    @param type a {@link java.lang.String}, the name of the type.
1204    @return {@link TypeData} value
1205    */
1206   protected TypeData getTypeData(String setName, String type){
1207     Map setMap = (Map)typeDataMap.get(setName);
1208     if(setMap != nullreturn (TypeData)setMap.get(type);
1209     else return null;
1210   }// protected TypeData getTypeData(String setName, String type)
1211 
1212 
1213   /**
1214    * Repaints the highlighting for annotation types in the text display.
1215    */
1216   protected void showHighlights(Set annotations, AttributeSet style) {
1217     //store the state of the text display
1218     int selStart = textPane.getSelectionStart();
1219     int selEnd = textPane.getSelectionEnd();
1220     final int position = textPane.viewToModel(
1221                             textScroll.getViewport().getViewPosition());
1222     //hide the text
1223     SwingUtilities.invokeLater(new Runnable() {
1224       public void run() {
1225         progressBar.setValue(0);
1226         //progressBar.setMaximumSize(new Dimension(textScroll.getWidth(),20));
1227         textScroll.getViewport().setView(progressBox);
1228         textScroll.paintImmediately(textScroll.getBounds());
1229       }
1230     });
1231 
1232     paintHighlights(annotations, style);
1233 
1234     //restore the state
1235     textPane.select(selStart, selEnd);
1236     SwingUtilities.invokeLater(new Runnable() {
1237       public void run() {
1238         //show the text
1239         textScroll.getViewport().setView(textPane);
1240         try {
1241           textScroll.getViewport().setViewPosition(
1242               textPane.modelToView(position).getLocation());
1243           textScroll.paintImmediately(textScroll.getBounds());
1244         }
1245         catch (BadLocationException ble) {
1246         }
1247       }
1248     });
1249   }//protected void showHighlights()
1250 
1251   protected void paintHighlights(Set annotations, AttributeSet style){
1252     //highlight the annotations
1253     int size = annotations.size();
1254     int i = 0;
1255     int lastValue = 0;
1256     int value;
1257 
1258     int start, end;
1259     Iterator annIter = annotations.iterator();
1260     while(annIter.hasNext()){
1261       Annotation ann = (Annotation)annIter.next();
1262       start = ann.getStartNode().getOffset().intValue();
1263       end = ann.getEndNode().getOffset().intValue();
1264       // compute correction for new line breaks in long lines
1265       start += longLinesCorrection(start);
1266       end += longLinesCorrection(end);
1267 
1268       textPane.select(start, end);
1269       textPane.setCharacterAttributes(style, true);
1270       if(progressBar.isVisible()){
1271         value = i * 100 / size;
1272         if (value - lastValue >= 5) {
1273           progressBar.setValue(value);
1274           progressBar.paintImmediately(progressBar.getBounds());
1275           lastValue = value;
1276         }
1277         i++;
1278       }
1279     }
1280   }
1281 
1282   /**
1283    * Called whenever a part of the textual display needs to be repainted
1284    * because, for instance, of an edit operation.
1285    @param start the start offset for the area to be repainted
1286    @param end the end offset for the area to be repainted.
1287    */
1288   protected void repairHighlights(int start, int end) {
1289     //we need to fix the character ranges for all types visible or not
1290     //clear everything
1291     int selStart = textPane.getSelectionStart();
1292     int selEnd = textPane.getSelectionEnd();
1293     //clear the styles in the affected area
1294     textPane.select(start, end);
1295     textPane.setCharacterAttributes(textPane.getStyle("default")true);
1296 
1297     //repaint the highlights for the annotations going through the affected area
1298     Iterator setsIter = typeDataMap.keySet().iterator();
1299     while(setsIter.hasNext()){
1300       Map typesMap = (Map)typeDataMap.get(setsIter.next());
1301       Iterator typesIter = typesMap.keySet().iterator();
1302       while(typesIter.hasNext()){
1303         TypeData tData = (TypeDatatypesMap.get(typesIter.next());
1304         if (tData.getVisible()) {
1305           String setName = tData.getSet();
1306           AnnotationSet annSet = setName.equals("Default"?
1307                                  document.getAnnotations() :
1308                                  document.getAnnotations(setName);
1309           annSet = annSet.get(tData.getType());
1310           if(annSet != null){
1311             AnnotationSet annotationsToRepaint = annSet.get(new Long(start),
1312                 new Long(end));
1313 //          Set annotationsToRepaint = new HashSet();
1314 //          Iterator annIter = tData.getAnnotations().iterator();
1315 //          while (annIter.hasNext()) {
1316 //            Annotation anAnnotation = (Annotation) annIter.next();
1317 //            long annStart = anAnnotation.getStartNode().getOffset().longValue();
1318 //            long annEnd = anAnnotation.getEndNode().getOffset().longValue();
1319 //            if ( (annStart < start && annEnd >= start) ||
1320 //                (start <= annStart && annStart <= end)
1321 //                )
1322 //              annotationsToRepaint.add(anAnnotation);
1323 //          }
1324             paintHighlights(annotationsToRepaint, tData.getActualStyle());
1325           }
1326         }
1327       }
1328     }
1329     //restore selection
1330     textPane.select(selStart, selEnd);
1331 //    textPane.requestFocus();
1332   }
1333 
1334   /**
1335    * Updates the GUI when the user has selected an annotation e.g. by using the
1336    * right click popup. That basically means make the appropiate type of
1337    * annotations visible in case it isn't already.
1338    */
1339   protected void selectAnnotation(String set, Annotation ann) {
1340     TypeData tData = getTypeData(set, ann.getType());
1341     if(!tData.getVisible()){
1342       tData.setVisible(true);
1343       //sleep a while so the gui updater thread has time to start
1344       try{
1345         Thread.sleep(100);
1346       }catch(InterruptedException ie){}
1347       //refresh the display for the type
1348       //(the checkbox has to be shown selected)
1349       DefaultMutableTreeNode node = (DefaultMutableTreeNode)
1350                                     ((DefaultMutableTreeNode)stylesTreeRoot).
1351                                     getFirstChild();
1352       while(node != null &&
1353             !((TypeData)node.getUserObject()).getSet().equals(set))
1354         node = node.getNextSibling();
1355       if(node != null){
1356         node = (DefaultMutableTreeNode)node.getFirstChild();
1357         String type = ann.getType();
1358         while(node != null &&
1359               !((TypeData)node.getUserObject()).getType().equals(type))
1360           node = node.getNextSibling();
1361         if(node != nullstylesTreeModel.nodeChanged(node);
1362       }
1363     }
1364     int position = -1;
1365     position = data.indexOf(ann);
1366     if(position != -1){
1367       position = annotationsTable.getTableRow(position);
1368       if(position != -1){
1369         annotationsTable.clearSelection();
1370         annotationsTable.addRowSelectionInterval(position, position);
1371         annotationsTable.scrollRectToVisible(
1372               annotationsTable.getCellRect(position, 0true));
1373       }
1374     }
1375   }//protected void selectAnnotation(String set, Annotation ann)
1376 
1377 
1378   /**
1379    * Creates the layout of this component acording to the set of subcomponents
1380    * (text display, annotations table, etc.) that need to be visible.
1381    */
1382   protected void layoutComponents(){
1383     SwingUtilities.invokeLater(new Runnable(){
1384       public void run(){
1385         Component leftComp = null, rightComp = null;
1386         if(isTextVisible() && isAnnotationsTableVisible()){
1387           leftSplit.setTopComponent(textScroll);
1388           leftSplit.setBottomComponent(tableScroll);
1389           leftComp = leftSplit;
1390         }else{
1391           if(isTextVisible()) leftComp = textScroll;
1392           else if(isAnnotationsTableVisible()) leftComp = tableScroll;
1393         }
1394 
1395         boolean corefDisplayed = isCoreferenceVisible() &&
1396                                  isCorefOptionAvailable();
1397         if(corefDisplayedupdateCorefTree();
1398         if(isTypesTreeVisible() && corefDisplayed){
1399           rightSplit.setTopComponent(stylesTreeScroll);
1400           rightSplit.setBottomComponent(corefScroll);
1401           rightComp = rightSplit;
1402         }else{
1403           if(isTypesTreeVisible()) rightComp = stylesTreeScroll;
1404           else if(corefDisplayedrightComp = corefScroll;
1405         }
1406 
1407         if(DocumentEditor.this.getComponentCount() 1)
1408           DocumentEditor.this.remove(1);
1409         if(leftComp != null && rightComp != null){
1410           //we need the main split
1411           mainSplit.setLeftComponent(leftComp);
1412           mainSplit.setRightComponent(rightComp);
1413           DocumentEditor.this.add(mainSplit, BorderLayout.CENTER);
1414         }else{
1415           if(leftComp != nullDocumentEditor.this.add(leftComp,
1416                                                        BorderLayout.CENTER);
1417           else if(rightComp != null)DocumentEditor.this.add(rightComp,
1418                                                             BorderLayout.CENTER);
1419         }
1420 
1421         DocumentEditor.this.validate();
1422         DocumentEditor.this.repaint();
1423       }
1424     });
1425   }
1426 
1427 
1428   /**
1429    * Updates the coref tree from the coref data on the document's features
1430    */
1431   protected void updateCorefTree(){
1432     if(document == null || document.getFeatures() == null){
1433       //no coref data; clear the tree
1434       corefTreeRoot.removeAllChildren();
1435       corefTreeModel.nodeStructureChanged(corefTreeRoot);
1436       setCorefOptionAvailable(false);
1437       return;
1438     }
1439 
1440     Map matchesMap = null;
1441     try{
1442       matchesMap = (Map)document.getFeatures().get(DOCUMENT_COREF_FEATURE_NAME);
1443     }catch(Exception e){
1444     }
1445     if(matchesMap == null){
1446       //no coref data; clear the tree
1447       Enumeration nodes = corefTreeRoot.breadthFirstEnumeration();
1448       while(nodes.hasMoreElements()){
1449         DefaultMutableTreeNode node = (DefaultMutableTreeNode)
1450                                       nodes.nextElement();
1451         if(node.getUserObject() instanceof CorefData){
1452           ((CorefData)node.getUserObject()).setVisible(false);
1453         }
1454       }
1455       corefTreeRoot.removeAllChildren();
1456       corefTreeModel.nodeStructureChanged(corefTreeRoot);
1457       setCorefOptionAvailable(false);
1458       return;
1459     }
1460 
1461     //matches map is not null; check whether it's valid
1462     Iterator setsIter = matchesMap.keySet().iterator();
1463     setsLoop: while(setsIter.hasNext()){
1464       String setName = (String)setsIter.next();
1465       AnnotationSet annSet = setName == null ? document.getAnnotations() :
1466                                                document.getAnnotations(setName);
1467       Iterator entitiesIter = ((java.util.List)matchesMap.get(setName)).
1468                               iterator();
1469       //each entity is a list of annotation IDs
1470       while(entitiesIter.hasNext()){
1471         Iterator idsIter = ((java.util.List)entitiesIter.next()).iterator();
1472         while(idsIter.hasNext()){
1473           if(annSet.get((Integer)idsIter.next()) == null){
1474             //remove the data for this set
1475             setsIter.remove();
1476             Err.prln("Coreference data for the \"" +
1477                      (setName == null "Default" : setName+
1478                       "\" annotation set of document \"" + document.getName() +
1479                      "\" was invalid and has been removed");
1480             continue setsLoop;
1481           }
1482         }
1483       }
1484     }
1485 
1486     if(matchesMap.isEmpty()){
1487       //no more coref data
1488       corefTreeRoot.removeAllChildren();
1489       corefTreeModel.nodeStructureChanged(corefTreeRoot);
1490       setCorefOptionAvailable(false);
1491       return;
1492     }
1493 
1494     String[] newSetNames = (String[])
1495                            matchesMap.keySet().toArray(new String[]{});
1496     Arrays.sort(newSetNames);
1497 
1498     ArrayList oldSetNames = new ArrayList(corefTreeRoot.getChildCount());
1499     Enumeration setNodes = corefTreeRoot.children();
1500     while(setNodes.hasMoreElements()){
1501       String oldSetName = (String)
1502                            ((DefaultMutableTreeNode)setNodes.nextElement()).
1503                            getUserObject();
1504       oldSetNames.add(oldSetName.equals("Default"null : oldSetName);
1505     }
1506 
1507 
1508     // stores the new set nodes; they will be added to root after the
1509     // processing is done
1510     ArrayList newSetNodes = new ArrayList();
1511     //for each new set update the children
1512     for(int i =0; i < newSetNames.length; i++){
1513       String setName = newSetNames[i];
1514       int oldNodeIndex = oldSetNames.indexOf(setName);
1515       DefaultMutableTreeNode setNode =
1516           (oldNodeIndex != -1?
1517           (DefaultMutableTreeNode)
1518           corefTreeRoot.getChildAt(oldNodeIndex:
1519           new DefaultMutableTreeNode((setName == null "Default" : setName),
1520                                      true);
1521       //if found it will be reused so delete it from the list
1522       if(oldNodeIndex != -1oldSetNames.remove(oldNodeIndex);
1523 
1524       // temporarily stores the new nodes
1525       ArrayList newEntityNodes = new ArrayList();
1526       //for each set the coref data is a list of lists
1527       Iterator corefDataIter = ((java.util.List)matchesMap.get(setName)).
1528                                iterator();
1529       while(corefDataIter.hasNext()){
1530         java.util.List newAnnotIDs = (java.util.List)corefDataIter.next();
1531         CorefData cData = null;
1532         DefaultMutableTreeNode entityNode = null;
1533         //try to find the old coref data
1534         Enumeration entityNodes = setNode.children();
1535         while(cData == null && entityNodes.hasMoreElements()){
1536           entityNode = (DefaultMutableTreeNode)entityNodes.nextElement();
1537           java.util.List oldAnnotIDs = ((CorefData)entityNode.getUserObject()).
1538                                      getAnnoationIDs();
1539           java.util.List intersection = new ArrayList(oldAnnotIDs);
1540           intersection.retainAll(newAnnotIDs);
1541           if(!intersection.isEmpty()){
1542             //we have some common values; assume we found it
1543             cData = (CorefData)entityNode.getUserObject();
1544             if(intersection.size() == newAnnotIDs.size()){
1545               //identical values, we just got lucky: noting to do
1546             }else{
1547               cData.setAnnotationIDs(newAnnotIDs);
1548             }
1549           }
1550         }
1551         if(cData == null){
1552           //we couldn't find a suitable node, create a new one
1553           cData = new CorefData(newAnnotIDs, false, setName == null ?
1554                                                     "Default" : setName);
1555           entityNode = new DefaultMutableTreeNode(cData, false);
1556         }
1557         newEntityNodes.add(entityNode);
1558       }//while(corefDataIter.hasNext())
1559       //we're done with this set: add all the nodes to the set node
1560       //set visible to false for all nodes that will not be kept
1561 //      for(Enumeration entityNodes = setNode.children();
1562 //          entityNodes.hasMoreElements();){
1563 //        Object anOldNode = entityNodes.nextElement();
1564 //        if(!newEntityNodes.contains(anOldNode)){
1565 //          ((CorefData)((DefaultMutableTreeNode)anOldNode).
1566 //          getUserObject()).setVisible(false);
1567 //        }
1568 //      }
1569 
1570       setNode.removeAllChildren();
1571       for(Iterator nodesIter = newEntityNodes.iterator();
1572           nodesIter.hasNext();
1573           setNode.add((DefaultMutableTreeNode)nodesIter.next())){
1574       }
1575       newSetNodes.add(setNode);
1576     }//for(int i =0; i < newSetNames.length; i++)
1577     //we're done with all the sets: add the nodes to the tree root
1578     corefTreeRoot.removeAllChildren();
1579     for(Iterator nodesIter = newSetNodes.iterator();
1580         nodesIter.hasNext();){
1581       DefaultMutableTreeNode setNode = (DefaultMutableTreeNode)nodesIter.next();
1582       corefTreeRoot.add(setNode);
1583     }
1584     SwingUtilities.invokeLater(new Runnable(){
1585       public void run(){
1586         highlighter.removeAllHighlights();
1587         corefTreeModel.nodeStructureChanged(corefTreeRoot);
1588         //expand the root
1589         corefTree.expandPath(new TreePath(new Object[]{corefTreeRoot}));
1590         //expand all of root's children
1591         Enumeration children = corefTreeRoot.children();
1592         while(children.hasMoreElements()){
1593           DefaultMutableTreeNode aNode =
1594             (DefaultMutableTreeNode)children.nextElement();
1595           corefTree.expandPath(
1596             new TreePath(corefTreeModel.getPathToRoot(aNode)));
1597           if(aNode.getUserObject() instanceof CorefData){
1598             CorefData cData = (CorefData)aNode.getUserObject();
1599             //trigger highlights repaint
1600             cData.setVisible(cData.getVisible());
1601           }
1602         }
1603       }
1604     });
1605     setCorefOptionAvailable(true);
1606   }//protected void updateCorefTree()
1607 
1608 
1609   /**Should the editor functionality of this component be enabled*/
1610   public void setEditable(boolean newEditable) {
1611     editable = newEditable;
1612   }
1613 
1614   /**Is the editor functionality enabled*/
1615   public boolean isEditable() {
1616     return editable;
1617   }
1618   public void setAnnotationsTableVisible(boolean annotationsTableVisible) {
1619     boolean  oldAnnotationsTableVisible = this.annotationsTableVisible;
1620     this.annotationsTableVisible = annotationsTableVisible;
1621     propertyChangeListeners.firePropertyChange(
1622         "annotationsTableVisible",
1623         new Boolean(oldAnnotationsTableVisible),
1624         new Boolean(annotationsTableVisible));
1625   }
1626   public boolean isAnnotationsTableVisible() {
1627     return annotationsTableVisible;
1628   }
1629   public void setCoreferenceVisible(boolean coreferenceVisible) {
1630     boolean  oldCoreferenceVisible = this.coreferenceVisible;
1631     this.coreferenceVisible = coreferenceVisible;
1632     propertyChangeListeners.firePropertyChange(
1633       "coreferenceVisible",
1634       new Boolean(oldCoreferenceVisible),
1635       new Boolean(coreferenceVisible));
1636   }
1637 
1638   public boolean isCoreferenceVisible() {
1639     return coreferenceVisible;
1640   }
1641   public void setTextVisible(boolean textVisible) {
1642     boolean  oldTextVisible = this.textVisible;
1643     this.textVisible = textVisible;
1644     propertyChangeListeners.firePropertyChange("textVisible",
1645                                                new Boolean(oldTextVisible),
1646                                                new Boolean(textVisible));
1647   }
1648   public boolean isTextVisible() {
1649     return textVisible;
1650   }
1651   public void setTypesTreeVisible(boolean typesTreeVisible) {
1652     boolean  oldTypesTreeVisible = this.typesTreeVisible;
1653     this.typesTreeVisible = typesTreeVisible;
1654     propertyChangeListeners.firePropertyChange("typesTreeVisible",
1655                                                new Boolean(oldTypesTreeVisible),
1656                                                new Boolean(typesTreeVisible));
1657   }
1658   public boolean isTypesTreeVisible() {
1659     return typesTreeVisible;
1660   }
1661   public void setCorefOptionAvailable(boolean corefOptionAvailable) {
1662     boolean  oldCorefOptionAvailable = this.corefOptionAvailable;
1663     this.corefOptionAvailable = corefOptionAvailable;
1664     propertyChangeListeners.firePropertyChange(
1665       "corefOptionAvailable"new Boolean(oldCorefOptionAvailable),
1666       new Boolean(corefOptionAvailable));
1667   }
1668 
1669   public boolean isCorefOptionAvailable() {
1670     return corefOptionAvailable;
1671   }
1672 
1673   //inner classes
1674   /**
1675    * A custom table model used to render a table containing the annotations
1676    * from a set of annotation sets.
1677    * The columns will be: Type, Set, Start, End, Features
1678    */
1679   protected class AnnotationsTableModel extends AbstractTableModel{
1680     public AnnotationsTableModel(){
1681     }
1682 
1683     public int getRowCount(){
1684       return data.size();
1685     }
1686 
1687     public int getColumnCount(){
1688       return 5;
1689     }
1690 
1691     public String getColumnName(int column){
1692       switch(column){
1693         case 0return "Type";
1694         case 1return "Set";
1695         case 2return "Start";
1696         case 3return "End";
1697         case 4return "Features";
1698         default:return "?";
1699       }
1700     }
1701 
1702     public Class getColumnClass(int column){
1703       switch(column){
1704         case 0return String.class;
1705         case 1return String.class;
1706         case 2return Long.class;
1707         case 3return Long.class;
1708         case 4return String.class;
1709         default:return Object.class;
1710       }
1711     }
1712 
1713     public Object getValueAt(int row, int column){
1714       Annotation ann;
1715       ann = (Annotation)data.get(row);
1716       switch(column){
1717         case -1:{//The actual annotation
1718           return ann;
1719         }
1720         case 0:{//Type
1721           return ann.getType();
1722         }
1723         case 1:{//Set
1724           Iterator rangesIter = ranges.iterator();
1725           while(rangesIter.hasNext()){
1726             Range range = (Range)rangesIter.next();
1727             if(range.start <= row && row < range.endreturn range.setName;
1728           }
1729           return "?";
1730         }
1731         case 2:{//Start
1732           return ann.getStartNode().getOffset();
1733         }
1734         case 3:{//End
1735           return ann.getEndNode().getOffset();
1736         }
1737         case 4:{//Features
1738           if(ann.getFeatures() == nullreturn null;
1739           else return ann.getFeatures().toString();
1740         }
1741         default:{
1742         }
1743       }
1744       return null;
1745     }
1746   }//class AnnotationsTableModel extends AbstractTableModel
1747 
1748 
1749   protected class CorefData{
1750     CorefData(java.util.List annotationIDs, boolean visible, String setName){
1751       this.visible = visible;
1752       this.setName = setName;
1753       this.colour = colGenerator.getNextColor();
1754       highlights = new ArrayList();
1755       this.annotationIDs = annotationIDs;
1756       this.title = getNameForCorefList(annotationIDs);
1757     }
1758 
1759     /**
1760      * Finds the name for a set of co refering entities (uses the string of the
1761      * first one).
1762      @param list a list of annotation IDs
1763      */
1764     String getNameForCorefList(java.util.List list){
1765       if(list == null || list.isEmpty()) return null;
1766       Integer id = (Integer)list.get(0);
1767       AnnotationSet set = setName.equals("Default"?
1768                           document.getAnnotations() :
1769                           document.getAnnotations(setName);
1770       Annotation ann = set.get(id);
1771 
1772       String name = null;
1773       try{
1774         name = document.getContent().
1775                         getContent(ann.getStartNode().getOffset(),
1776                                    ann.getEndNode().getOffset()).toString();
1777       }catch(InvalidOffsetException ioe){
1778       }
1779       return name;
1780     }
1781 
1782     public boolean getVisible(){
1783       return visible;
1784     }
1785 
1786     public void removeAnnotations(){
1787       AnnotationSet set = setName.equals("Default"?
1788                           document.getAnnotations() :
1789                           document.getAnnotations(setName);
1790 
1791       Iterator idIter = annotationIDs.iterator();
1792       while(idIter.hasNext()){
1793         set.remove(set.get((Integer)idIter.next()));
1794       }
1795       ((java.util.List)((Map)document.getFeatures().
1796         get(ANNIEConstants.DOCUMENT_COREF_FEATURE_NAME)).
1797         get(setName.equals("Default"null : setName)).remove(annotationIDs);
1798       annotationIDs.clear();
1799       updateCorefTree();
1800     }
1801 
1802     public void setVisible(boolean isVisible){
1803       if(this.visible == isVisiblereturn;
1804       this.visible = isVisible;
1805       if(visible){
1806         //add new highlights and store them
1807         AnnotationSet set = setName.equals("Default"?
1808                             document.getAnnotations() :
1809                             document.getAnnotations(setName);
1810         Iterator idIter = annotationIDs.iterator();
1811         ArrayList invalidIDs = new ArrayList();
1812         while(idIter.hasNext()){
1813           Integer id = (Integer)idIter.next();
1814           Annotation ann = set.get(id);
1815           if(ann == null){
1816             invalidIDs.add(id);
1817           }else try{
1818             highlights.add(highlighter.addHighlight(
1819               ann.getStartNode().getOffset().intValue(),
1820               ann.getEndNode().getOffset().intValue(),
1821               new DefaultHighlighter.DefaultHighlightPainter(colour)));
1822           }catch(BadLocationException ble){
1823             ble.printStackTrace();
1824           }
1825         }
1826         if(!invalidIDs.isEmpty()){
1827           annotationIDs.removeAll(invalidIDs);
1828         }
1829       }else{
1830         //remove the highlights
1831         if(!highlights.isEmpty()){
1832           Iterator hlIter = highlights.iterator();
1833           while(hlIter.hasNext()){
1834             Object tag = hlIter.next();
1835             highlighter.removeHighlight(tag);
1836             hlIter.remove();
1837           }
1838         }
1839       }
1840     }
1841 
1842     public String getTitle(){
1843       return title;
1844     }
1845 
1846     public Color getColour(){
1847       return colour;
1848     }
1849 
1850     public void setColour(Color newColour){
1851       this.colour = newColour;
1852       if(visible){
1853         //update the highlights
1854         setVisible(false);
1855         setVisible(true);
1856       }
1857     }
1858 
1859     public java.util.List getAnnoationIDs(){
1860       return annotationIDs;
1861     }
1862 
1863     public String getSetName(){
1864       return setName;
1865     }
1866     public String toString(){
1867       return title;
1868     }
1869 
1870     public void setAnnotationIDs(java.util.List newAnnIDs){
1871       this.annotationIDs =newAnnIDs;
1872       this.title = getNameForCorefList(annotationIDs);
1873       if(visible){
1874         //restore the highlights
1875         setVisible(false);
1876         setVisible(true);
1877       }
1878     }
1879 
1880     private boolean visible;
1881     private String title;
1882     private String setName;
1883     private Color colour;
1884     private java.util.List highlights;
1885     private java.util.List annotationIDs;
1886   }
1887 
1888 /*
1889   protected class CorefComboModel extends AbstractListModel
1890                                   implements ComboBoxModel{
1891 
1892     CorefComboModel(){
1893       lastReturnedSize = 0;
1894     }
1895 
1896     public int getSize(){
1897       if(document == null || document.getFeatures() == null) return 0;
1898       Map matchesMap = null;
1899       try{
1900         matchesMap = (Map)document.getFeatures().get(DOCUMENT_COREF_FEATURE_NAME);
1901       }catch(Exception e){
1902         e.printStackTrace();
1903       }
1904       int size = (matchesMap == null) ? 0 : matchesMap.size();
1905       if(lastReturnedSize != size){
1906         lastReturnedSize = size;
1907         fireDataChanged();
1908       }
1909       return lastReturnedSize;
1910     }
1911 
1912 
1913     public Object getElementAt(int index){
1914       if(document == null || document.getFeatures() == null) return null;
1915       Map matchesMap = null;
1916       try{
1917         matchesMap = (Map)document.getFeatures().get(DOCUMENT_COREF_FEATURE_NAME);
1918       }catch(Exception e){
1919         e.printStackTrace();
1920       }
1921       if(matchesMap == null) return null;
1922       java.util.List setsList = new ArrayList(matchesMap.keySet());
1923       boolean nullPresent = setsList.remove(null);
1924       Collections.sort(setsList);
1925       if(nullPresent) setsList.add(0, null);
1926       String res = (String)setsList.get(index);
1927       return (res == null) ? "Default" : res;
1928     }
1929 
1930     public void setSelectedItem(Object anItem){
1931       if(anItem == null) selectedItem = null;
1932       else selectedItem = ((String)anItem).equals("Default") ? null : anItem;
1933     }
1934 
1935     public Object getSelectedItem(){
1936       return selectedItem == null ? "Default" : selectedItem;
1937     }
1938 
1939     void fireDataChanged(){
1940       fireContentsChanged(this, 0, getSize());
1941     }
1942 
1943     Object selectedItem = null;
1944     int lastReturnedSize;
1945   }
1946 */
1947 
1948   /**
1949    * Panels used in cell/node renderers
1950    */
1951   class LazyJPanel extends JPanel{
1952     /**
1953      * Overridden for performance reasons.
1954      */
1955     public void revalidate() {}
1956 
1957     /**
1958      * Overridden for performance reasons.
1959      */
1960     public void repaint(long tm, int x, int y, int width, int height) {}
1961 
1962     /**
1963      * Overridden for performance reasons.
1964      */
1965     public void repaint(Rectangle r) {}
1966 
1967     /**
1968      * Overridden for performance reasons.
1969      */
1970     protected void firePropertyChange(String propertyName, Object oldValue,
1971                                                             Object newValue) {}
1972 
1973     /**
1974      * Overridden for performance reasons.
1975      */
1976     public void firePropertyChange(String propertyName, byte oldValue,
1977                                                               byte newValue) {}
1978 
1979     /**
1980      * Overridden for performance reasons.
1981      */
1982     public void firePropertyChange(String propertyName, char oldValue,
1983                                                               char newValue) {}
1984 
1985     /**
1986      * Overridden for performance reasons.
1987      */
1988     public void firePropertyChange(String propertyName, short oldValue,
1989                                                             short newValue) {}
1990 
1991     /**
1992      * Overridden for performance reasons.
1993      */
1994     public void firePropertyChange(String propertyName, int oldValue,
1995                                                               int newValue) {}
1996 
1997     /**
1998      * Overridden for performance reasons.
1999      */
2000     public void firePropertyChange(String propertyName, long oldValue,
2001                                                               long newValue) {}
2002 
2003     /**
2004      * Overridden for performance reasons.
2005      */
2006     public void firePropertyChange(String propertyName, float oldValue,
2007                                                               float newValue) {}
2008 
2009     /**
2010      * Overridden for performance reasons.
2011      */
2012     public void firePropertyChange(String propertyName, double oldValue,
2013                                                             double newValue) {}
2014 
2015     /**
2016      * Overridden for performance reasons.
2017      */
2018     public void firePropertyChange(String propertyName, boolean oldValue,
2019                                                             boolean newValue) {}
2020   }
2021 
2022   /**
2023    * A tree node renderer used by the coref tree
2024    */
2025   class CorefNodeRenderer implements TreeCellRenderer{
2026 
2027     CorefNodeRenderer(){
2028       label = new JLabel();
2029       label.setOpaque(true);
2030 
2031       checkBox = new JCheckBox();
2032       checkBox.setBorderPaintedFlat(true);
2033 
2034       panel = new LazyJPanel();
2035       panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
2036       panel.setOpaque(false);
2037 
2038       hBox = new LazyJPanel();
2039       hBox.setLayout(new BoxLayout(hBox, BoxLayout.X_AXIS));
2040       hBox.setOpaque(false);
2041 
2042       panel.add(Box.createVerticalStrut(2));
2043       panel.add(hBox);
2044       panel.add(Box.createVerticalStrut(2));
2045 
2046       leftSpacer = Box.createHorizontalStrut(3);
2047       rightSpacer = Box.createHorizontalStrut(3);
2048 
2049       selectedBorder = BorderFactory.createLineBorder(Color.blue, 1);
2050       normalBorder = BorderFactory.createEmptyBorder(1111);
2051     }
2052 
2053     public Component getTreeCellRendererComponent(JTree tree,
2054                                               Object value,
2055                                               boolean selected,
2056                                               boolean expanded,
2057                                               boolean leaf,
2058                                               int row,
2059                                               boolean hasFocus){
2060 
2061       hBox.removeAll();
2062       hBox.add(leftSpacer);
2063 
2064       if(value instanceof DefaultMutableTreeNode){
2065         value = ((DefaultMutableTreeNode)value).getUserObject();
2066       }
2067       if(value instanceof CorefData){
2068         CorefData cData = (CorefData)value;
2069         checkBox.setSelected(cData.getVisible());
2070         checkBox.setBackground(tree.getBackground());
2071 
2072         label.setBackground(cData.getColour());
2073         label.setForeground(tree.getForeground());
2074         label.setText(cData.getTitle());
2075         label.setFont(tree.getFont());
2076         hBox.add(checkBox);
2077         hBox.add(label);
2078         hBox.add(rightSpacer);
2079       }else{
2080         label.setText(value == null "" : value.toString());
2081         label.setForeground(tree.getForeground());
2082         label.setBackground(tree.getBackground());
2083         label.setFont(tree.getFont());
2084         hBox.add(label);
2085       }
2086       if(selectedpanel.setBorder(selectedBorder);
2087       else panel.setBorder(normalBorder);
2088       return panel;
2089     }
2090 
2091     JLabel label;
2092     JCheckBox checkBox;
2093     JPanel panel;
2094     JPanel hBox;
2095     Border selectedBorder;
2096     Border normalBorder;
2097     Component leftSpacer, rightSpacer;
2098   }
2099 
2100   /**
2101    * A tree node renderer used byt the coref tree
2102    */
2103   class CorefNodeRenderer1 implements TreeCellRenderer{
2104 
2105     CorefNodeRenderer1(){
2106       label = new JLabel();
2107       label.setOpaque(true);
2108 
2109       toggleButton = new JToggleButton();
2110       toggleButton.setMargin(new Insets(0,3,0,3));
2111 
2112       panel = new LazyJPanel();
2113       panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
2114       panel.setOpaque(false);
2115       topSpacer = Box.createVerticalStrut(2);
2116       bottomSpacer = Box.createVerticalStrut(2);
2117 
2118       selectedBorder = BorderFactory.createLineBorder(Color.blue, 1);
2119       normalBorder = BorderFactory.createEmptyBorder(1111);
2120 
2121     }
2122 
2123     public Component getTreeCellRendererComponent(JTree tree,
2124                                               Object value,
2125                                               boolean selected,
2126                                               boolean expanded,
2127                                               boolean leaf,
2128                                               int row,
2129                                               boolean hasFocus){
2130 
2131       panel.removeAll();
2132       panel.add(topSpacer);
2133 
2134       if(value instanceof DefaultMutableTreeNode){
2135         value = ((DefaultMutableTreeNode)value).getUserObject();
2136       }
2137       if(value instanceof CorefData){
2138         CorefData cData = (CorefData)value;
2139         toggleButton.setSelected(cData.getVisible());
2140         toggleButton.setBackground(cData.getColour());
2141         toggleButton.setForeground(tree.getForeground());
2142         toggleButton.setText(cData.getTitle());
2143         toggleButton.setFont(tree.getFont());
2144         panel.add(toggleButton);
2145       }else{
2146         label.setText(value.toString());
2147         label.setForeground(tree.getForeground());
2148         label.setBackground(tree.getBackground());
2149         label.setFont(tree.getFont());
2150         panel.add(label);
2151       }
2152       panel.add(bottomSpacer);
2153       if(selectedpanel.setBorder(selectedBorder);
2154       else panel.setBorder(normalBorder);
2155       return panel;
2156     }
2157 
2158     JLabel label;
2159     JToggleButton toggleButton;
2160     JPanel panel;
2161     Border selectedBorder;
2162     Border normalBorder;
2163     Component topSpacer, bottomSpacer;
2164   }
2165 
2166 
2167   /**
2168    * Displays an entry in the right hand side tree.
2169    <strong>Implementation Note:</strong>
2170    * This class overrides
2171    <code>revalidate</code>,
2172    <code>repaint</code>,
2173    * and
2174    <code>firePropertyChange</code>
2175    * solely to improve performance.
2176    * If not overridden, these frequently called methods would execute code paths
2177    * that are unnecessary for a tree cell renderer.
2178    */
2179   class NodeRenderer extends LazyJPanel implements TreeCellRenderer{
2180 
2181     public NodeRenderer(){
2182       visibleChk = new JCheckBox("",false);
2183       visibleChk.setOpaque(false);
2184       visibleChk.setBorderPaintedFlat(true);
2185 
2186       label = new JLabel();
2187       label.setOpaque(true);
2188       fontAttrs = new HashMap();
2189       selectedBorder = BorderFactory.createLineBorder(Color.blue, 1);
2190       normalBorder = BorderFactory.createEmptyBorder(1111);
2191       setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
2192       setOpaque(false);
2193       spacer = Box.createHorizontalStrut(3);
2194     }
2195 
2196     public Component getTreeCellRendererComponent(JTree tree,
2197                                               Object value,
2198                                               boolean selected,
2199                                               boolean expanded,
2200                                               boolean leaf,
2201                                               int row,
2202                                               boolean hasFocus){
2203       removeAll();
2204       add(spacer);
2205 
2206       int width = spacer.getWidth();
2207 
2208 
2209       TypeData nData = (TypeData)
2210                             ((DefaultMutableTreeNode)value).getUserObject();
2211 
2212       if(nData != null){
2213         label.setText(nData.getTitle());
2214         setLabelAttributes(nData.getAttributes());
2215 
2216         if(nData.getType() != null) {
2217           visibleChk.setSelected(nData.getVisible());
2218           add(visibleChk);
2219           width += visibleChk.getMinimumSize().width;
2220         }
2221       }else{
2222         label.setText(((value == null || value.toString() == null?
2223                               "" : value.toString()));
2224       }
2225       add(label);
2226 
2227       if(selectedsetBorder(selectedBorder);
2228       else setBorder(normalBorder);
2229       return this;
2230     }//public Component getTreeCellRendererComponent
2231 
2232     protected void setLabelAttributes(AttributeSet style){
2233       label.setForeground(StyleConstants.getForeground(style));
2234       label.setBackground(StyleConstants.getBackground(style));
2235       fontAttrs.clear();
2236       fontAttrs.put(TextAttribute.FAMILY, StyleConstants.getFontFamily(style));
2237       fontAttrs.put(TextAttribute.SIZE, new Float(StyleConstants.getFontSize(style)));
2238       if(StyleConstants.isBold(style))
2239         fontAttrs.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
2240       else fontAttrs.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_REGULAR);
2241       if(StyleConstants.isItalic(style))
2242         fontAttrs.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE);
2243       else fontAttrs.put(TextAttribute.POSTURE, TextAttribute.POSTURE_REGULAR);
2244       if(StyleConstants.isUnderline(style))
2245         fontAttrs.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
2246       else fontAttrs.remove(TextAttribute.UNDERLINE);
2247       if(StyleConstants.isStrikeThrough(style))
2248         fontAttrs.put(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON);
2249       else fontAttrs.remove(TextAttribute.STRIKETHROUGH);
2250       if(StyleConstants.isSuperscript(style))
2251         fontAttrs.put(TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUPER);
2252       else if(StyleConstants.isSubscript(style))
2253         fontAttrs.put(TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUB);
2254       else fontAttrs.remove(TextAttribute.SUPERSCRIPT);
2255 
2256       label.setFont(new Font(fontAttrs));
2257     }
2258 
2259     Border selectedBorder;
2260     Border normalBorder;
2261     JCheckBox visibleChk;
2262     JLabel label;
2263     Map fontAttrs;
2264     Component spacer;
2265   }//class NodeRenderer extends JPanel implements TreeCellRenderer
2266   /**
2267    * Displays an entry in the right hand side tree.
2268    <strong>Implementation Note:</strong>
2269    * This class overrides
2270    <code>revalidate</code>,
2271    <code>repaint</code>,
2272    * and
2273    <code>firePropertyChange</code>
2274    * solely to improve performance.
2275    * If not overridden, these frequently called methods would execute code paths
2276    * that are unnecessary for a tree cell renderer.
2277    */
2278   class NodeRenderer1 extends LazyJPanel implements TreeCellRenderer{
2279 
2280     public NodeRenderer1(){
2281       visibleChk = new JCheckBox("",false);
2282       visibleChk.setOpaque(false);
2283       visibleChk.setBorderPaintedFlat(true);
2284       textComponent = new JTextPane();
2285       selectedBorder = BorderFactory.createLineBorder(Color.blue, 1);
2286       normalBorder = BorderFactory.createEmptyBorder(1111);
2287       setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
2288       setOpaque(false);
2289       spacer = Box.createHorizontalStrut(3);
2290     }
2291 
2292     public Component getTreeCellRendererComponent(JTree tree,
2293                                               Object value,
2294                                               boolean selected,
2295                                               boolean expanded,
2296                                               boolean leaf,
2297                                               int row,
2298                                               boolean hasFocus){
2299       removeAll();
2300       add(spacer);
2301 
2302       int width = spacer.getWidth();
2303 
2304       //the text pane needs to be sized for modelToView() to work
2305       textComponent.setSize(10001000);
2306 
2307       TypeData nData = (TypeData)
2308                             ((DefaultMutableTreeNode)value).getUserObject();
2309 //      javax.swing.text.Document doc = textComponent.getDocument();
2310 
2311       if(nData != null){
2312         textComponent.setText(nData.getTitle());
2313         textComponent.selectAll();
2314         textComponent.setCharacterAttributes(nData.getAttributes()false);
2315         textComponent.select(00);
2316 //        try{
2317 //          doc.remove(0, doc.getLength());
2318 //          doc.insertString(0, nData.getTitle(),
2319 //                           nData.getAttributes());
2320 //        }catch(BadLocationException ble){
2321 //          ble.printStackTrace();
2322 //        }
2323 
2324         if(nData.getType() != null) {
2325           visibleChk.setSelected(nData.getVisible());
2326           add(visibleChk);
2327           width += visibleChk.getMinimumSize().width;
2328         }
2329       }else{
2330         textComponent.setText(((value == null || value.toString() == null?
2331                               "" : value.toString()));
2332 //        try{
2333 //          doc.remove(0, doc.getLength());
2334 //          doc.insertString(0, value.toString(),
2335 //                           textComponent.getStyle("default"));
2336 //        }catch(BadLocationException ble){
2337 //          ble.printStackTrace();
2338 //        }
2339       }
2340       setTextComponentSize(textComponent);
2341       add(textComponent);
2342       width += textComponent.getPreferredSize().width;
2343       if(selectedsetBorder(selectedBorder);
2344       else setBorder(normalBorder);
2345       width += getInsets().left + getInsets().right;
2346       setPreferredSize(null);
2347       setPreferredSize(new Dimension(width, super.getPreferredSize().height));
2348       return this;
2349     }//public Component getTreeCellRendererComponent
2350 
2351    protected void setTextComponentSize(JTextComponent comp){
2352       try{
2353         if(comp.getDocument() == null || comp.getDocument().getLength() <= 0){
2354           return;
2355         }
2356         int width = 0;
2357         Rectangle rect = comp.modelToView(0);
2358         int height = rect.height;
2359         int length = comp.getDocument().getLength();
2360         if(length > 0){
2361           Rectangle rect2 = comp.modelToView(length );
2362           if(rect2 != null){
2363             if(rect.x < rect2.x){
2364               //left to right
2365               width = rect2.x + rect2.width - rect.x;
2366             }else{
2367               //RtL
2368               width = rect.x +rect.width - rect2.x;
2369             }
2370             height = Math.max(height, rect2.height);
2371           }
2372         }
2373         Insets insets = comp.getInsets();
2374         Dimension dim = new Dimension(width + insets.left + insets.right + 5,
2375                                       height + insets.top + insets.bottom);
2376         comp.setPreferredSize(dim);
2377       }catch(BadLocationException ble){
2378         //this will work the next time around so it's safe to ignore it now
2379       }
2380     }
2381     Border selectedBorder;
2382     Border normalBorder;
2383     JCheckBox visibleChk;
2384     JTextPane textComponent;
2385     Component spacer;
2386   }//class NodeRenderer extends JPanel implements TreeCellRenderer
2387 
2388   /**
2389    * Displays an entry in the right hand side tree.
2390    <strong><a name="override">Implementation Note:</a></strong>
2391    * This class overrides
2392    <code>revalidate</code>,
2393    <code>repaint</code>,
2394    * and
2395    <code>firePropertyChange</code>
2396    * solely to improve performance.
2397    * If not overridden, these frequently called methods would execute code paths
2398    * that are unnecessary for a tree cell renderer.
2399    */
2400 /*
2401   class NodeRenderer1 extends JPanel implements TreeCellRenderer{
2402 
2403     public NodeRenderer1(){
2404       visibleChk = new JCheckBox("",false);
2405       visibleChk.setOpaque(false);
2406       typeComponent = new JTextPane();
2407       setComponent = new JTextPane();
2408       selectedBorder = BorderFactory.createLineBorder(Color.blue);
2409       normalBorder = BorderFactory.createEmptyBorder(1,1,1,1);
2410 
2411       setPanel = new LazyJPanel();
2412       setPanel.setOpaque(false);
2413       setPanel.setLayout(new BoxLayout(setPanel, BoxLayout.X_AXIS));
2414       setPanel.add(setComponent);
2415       typePanel = new LazyJPanel();
2416       typePanel.setOpaque(false);
2417       typePanel.setLayout(new BoxLayout(typePanel, BoxLayout.X_AXIS));
2418       typePanel.add(visibleChk);
2419       typePanel.add(typeComponent);
2420     }
2421 
2422     public Component getTreeCellRendererComponent(JTree tree,
2423                                               Object value,
2424                                               boolean selected,
2425                                               boolean expanded,
2426                                               boolean leaf,
2427                                               int row,
2428                                               boolean hasFocus){
2429       JComponent renderer = null;
2430       TypeData nData = (TypeData)
2431                             ((DefaultMutableTreeNode)value).getUserObject();
2432       if(nData != null){
2433         if(nData.getType() != null) {
2434           visibleChk.setSelected(nData.getVisible());
2435           typeComponent.setSize(1000, 1000);
2436           javax.swing.text.Document doc = typeComponent.getDocument();
2437           try{
2438             doc.remove(0, doc.getLength());
2439             doc.insertString(0, nData.getTitle(), nData.getAttributes());
2440           }catch(BadLocationException ble){
2441             ble.printStackTrace();
2442           }
2443           setTextComponentSize(typeComponent);
2444 //          typePanel.removeAll();
2445 //          typePanel.add(visibleChk);
2446 //          typePanel.add(typeComponent);
2447           renderer = typePanel;
2448         }else{
2449           setComponent.setSize(1000, 1000);
2450           javax.swing.text.Document doc = setComponent.getDocument();
2451           try{
2452             doc.remove(0, doc.getLength());
2453             doc.insertString(0, nData.getTitle(), nData.getAttributes());
2454           }catch(BadLocationException ble){
2455             ble.printStackTrace();
2456           }
2457           setTextComponentSize(setComponent);
2458 //          setPanel.removeAll();
2459 //          setPanel.add(setComponent);
2460           renderer = setPanel;
2461         }
2462       }else{
2463         setComponent.setSize(1000, 1000);
2464         javax.swing.text.Document doc = setComponent.getDocument();
2465         try{
2466           doc.remove(0, doc.getLength());
2467           doc.insertString(0, value.toString(), setComponent.getStyle("default"));
2468         }catch(BadLocationException ble){
2469           ble.printStackTrace();
2470         }
2471         setTextComponentSize(setComponent);
2472 //        setPanel.removeAll();
2473 //        setPanel.add(setComponent);
2474         renderer = setPanel;
2475       }
2476       if(selected) renderer.setBorder(selectedBorder);
2477       else renderer.setBorder(normalBorder);
2478       return renderer;
2479     }//public Component getTreeCellRendererComponent
2480 
2481     protected void setTextComponentSize(JTextComponent comp){
2482       try{
2483         Rectangle rect = comp.modelToView(0);
2484         int length = comp.getDocument().getLength();
2485         if(length > 0){
2486           Rectangle rect2 = comp.modelToView(length - 1);
2487           if(rect2 != null){
2488 Out.pr("Rect2.x " + rect2.x);
2489             //this mutates rect
2490             rect = SwingUtilities.computeUnion(rect2.x, rect2.y, rect2.width,
2491                                         rect2.height, rect);
2492 Out.prln("Rect.width " + rect.width);
2493           }else{
2494 Out.prln("NULL size");
2495           }
2496         }
2497         Insets insets = comp.getInsets();
2498         Dimension dim = new Dimension(rect.width + insets.left + insets.right,
2499                                       rect.height + insets.top + insets.bottom);
2500         comp.setPreferredSize(dim);
2501       }catch(BadLocationException ble){
2502         ble.printStackTrace();
2503       }
2504     }
2505 
2506     Border selectedBorder;
2507     Border normalBorder;
2508     JCheckBox visibleChk;
2509     JTextPane setComponent;
2510     JTextPane typeComponent;
2511     JPanel setPanel;
2512     JPanel typePanel;
2513   }//class NodeRenderer extends JPanel implements TreeCellRenderer
2514 */
2515   /**
2516    * Holds the GUI metadata for a given annotation type. An annotation type is
2517    * uniquely identified by the name of its AnnotationSet and the name of the
2518    * type.
2519    * For the default annotation set of a document (which has no name) the
2520    * &quot;&lt;Default&gt;&quot; value is used.
2521    * The GUI metadata contains, amongst other things, the style used for
2522    * highlighting the annotations of this type.
2523    * These styles are cascading styles (there is a relation of inheritance
2524    * between them) so the annotation type style inherits the characteristics
2525    * from the style associated with the annotation set it belongs to.
2526    *
2527    * For eficiency reasons there are some intermediary styles between a parent
2528    * and a child style that used for changing the display in one operation.
2529    */
2530   public class TypeData {
2531 
2532     public TypeData(String set, String type, boolean visible){
2533       this.set = set;
2534       this.type = type;
2535       this.visible = visible;
2536       Map setMap = (Map)typeDataMap.get(set);
2537       if(setMap == null){
2538         setMap = new HashMap();
2539         typeDataMap.put(set, setMap);
2540       }
2541       if(type == null) {
2542         //this node represents a Set
2543         style = textPane.addStyle(set, textPane.getStyle("default"));
2544       else {
2545         style = textPane.addStyle(set + "." + type, textPane.getStyle(set));
2546         StyleConstants.setBackground(style,
2547                                      colGenerator.getNextColor().brighter());
2548         //add an intermediary style that will be used attribute inheritance tricks
2549         middleStyle = visible ?
2550                       textPane.addStyle("_" + set + "." + type, style:
2551                       textPane.addStyle("_" + set + "." + type,
2552                                         textPane.getStyle("default"));
2553         //add the style that will be used for the actual display
2554         actualStyle = textPane.addStyle("_" + set + "." + type + "_",
2555                           textPane.getStyle("_" + set + "." + type));
2556         setMap.put(type, this);
2557       }
2558     }
2559 
2560     public String getSet() { return set;}
2561 
2562     public void setSet(String set) {this.set = set;}
2563 
2564     public String getType() {return type;}
2565 
2566     public String getTitle() {return (type == null? set + " annotations" :
2567                                                       type;}
2568     public boolean getVisible() {return visible;}
2569 
2570     public void setVisible(boolean isVisible) {
2571       if(this.visible == isVisiblereturn;
2572       this.visible = isVisible;
2573       //this is most likely called from the SWING thread so we want to get
2574       //out of here as quickly as possible. We'll start a new thread that will
2575       //do all that needs doing
2576       Runnable runnable = new Runnable() {
2577         public void run() {
2578           if(visible) {
2579             //make the corresponding range visible
2580             //update the annotations table
2581             synchronized(data) {
2582               range = new Range(set, type, data.size(),
2583                                 data.size() + annotations.size());
2584               ranges.add(range);
2585               data.addAll(annotations);
2586               SwingUtilities.invokeLater(new Runnable() {
2587                 public void run() {
2588                   annotationsTableModel.fireTableDataChanged();
2589                 }
2590               });
2591             }
2592 
2593             //update the text display
2594 //            Style tempStyle = textPane.getStyle("_" + set + "." + type);
2595             middleStyle.setResolveParent(style);
2596             showHighlights(annotations, actualStyle);
2597           else {
2598             //hide the corresponding range
2599             //update the annotations table
2600             Collections.sort(ranges);
2601             Iterator rangesIter = ranges.iterator();
2602             while(rangesIter.hasNext()) {
2603               //find my range
2604               Range aRange = (Range)rangesIter.next();
2605               if(aRange == range){
2606                 rangesIter.remove();
2607                 int size = range.end - range.start;
2608                 //remove the elements from Data
2609                 data.subList(range.start, range.end).clear();
2610                 //shift back all the remaining ranges
2611                 while(rangesIter.hasNext()) {
2612                   aRange = (Range)rangesIter.next();
2613                   aRange.start -= size;
2614                   aRange.end -= size;
2615                 }
2616               }
2617             }
2618             range = null;
2619             SwingUtilities.invokeLater(new Runnable() {
2620               public void run() {
2621                 annotationsTableModel.fireTableDataChanged();
2622               }
2623             });
2624             //update the text display
2625 //            Style middleStyle = textPane.getStyle("_" + set + "." + type);
2626             middleStyle.setResolveParent(textPane.getStyle("default"));
2627           }//if(visible)
2628         }//public void run()
2629       };//Runnable runnable = new Runnable()
2630       Thread thread = new Thread(Thread.currentThread().getThreadGroup(),
2631                                    runnable,
2632                                    "AnnotationEditor4");
2633       thread.setPriority(Thread.MIN_PRIORITY);
2634       thread.start();
2635     }//public void setVisible(boolean isVisible)
2636 
2637     public AttributeSet getAttributes() { return style;}
2638 
2639     private AttributeSet getActualStyle() { return actualStyle;}
2640 
2641     public void setAttributes(AttributeSet newAttributes) {
2642       style.removeAttributes(style.copyAttributes());
2643       style.addAttributes(newAttributes);
2644     }
2645 
2646 
2647     public void setAnnotations(Set as) {
2648       this.annotations = as;
2649     }
2650 
2651     public Set getAnnotations() {
2652       return annotations;
2653     }
2654 
2655     public void setNode(DefaultMutableTreeNode node){
2656       this.node = node;
2657     }
2658 
2659     public DefaultMutableTreeNode getNode(){
2660       return node;
2661     }
2662 
2663     public String toString() {return getTitle();}
2664 
2665     private String set;
2666     private String type;
2667     private boolean visible;
2668     /**
2669      * The style used for annotations of this type
2670      */
2671     private Style style;
2672 
2673     /**
2674      * Used internally for attribute inheritance tricks.
2675      */
2676     private Style middleStyle;
2677 
2678     /**
2679      * The style actually used to affect the text.
2680      */
2681     private Style actualStyle;
2682     private Set annotations = null;
2683     private Range range = null;
2684 
2685     /** The node that represents this set/type in the types tree*/
2686     private DefaultMutableTreeNode node = null;
2687   }//class TypeData
2688 
2689 
2690   /**
2691    * Describes a range in the {@link #data} structure. A range is a bunch of
2692    * annotations of the same type belonging to the same annotation set that
2693    * are contiguous in the {@link #data} structure.
2694    */
2695   class Range implements Comparable {
2696     public Range(String setName, String type, int start, int end) {
2697       this.setName = setName;
2698       this.type = type;
2699       this.start = start;
2700       this.end = end;
2701     }
2702 
2703     public String toString() {
2704       return setName +  ", " + type + " (" + start + ", " + end + ")";
2705     }
2706 
2707     public int compareTo(Object other) {
2708       if(other instanceof Rangereturn start - ((Range)other).start;
2709       else throw new ClassCastException("Can't compare a " +
2710                                          other.getClass() " to a " +
2711                                          getClass() "!");
2712     }
2713 
2714     String setName;
2715     String type;
2716     int start;
2717     int end;
2718   }//class Range
2719 
2720 
2721   /**
2722    * All the events from the document or its annotation sets are handled by
2723    * this inner class.
2724    */
2725   class EventsHandler implements gate.event.DocumentListener,
2726                                  AnnotationSetListener{
2727 
2728     public void annotationSetAdded(gate.event.DocumentEvent e) {
2729       String setName = e.getAnnotationSetName();
2730       AnnotationSet as = (setName == null ? document.getAnnotations() :
2731                              document.getAnnotations(setName));
2732 
2733       as.addAnnotationSetListener(this);
2734       if(setName == nullsetName = "Default";
2735       TypeData setData = new TypeData(setName, null, false);
2736       setData.setAnnotations(as);
2737 
2738       SwingUtilities.invokeLater(new NodeAdder(setData));
2739 
2740       ArrayList typesLst = new ArrayList(as.getAllTypes());
2741       Collections.sort(typesLst);
2742 
2743       Iterator typesIter = typesLst.iterator();
2744       while(typesIter.hasNext()){
2745         String type = (String)typesIter.next();
2746         TypeData typeData = new TypeData(setName, type, false);
2747         AnnotationSet sameType = as.get(type);
2748         typeData.setAnnotations(sameType);
2749 
2750         SwingUtilities.invokeLater(new NodeAdder(typeData));
2751       }
2752     }
2753 
2754     public void annotationSetRemoved(gate.event.DocumentEvent e) {
2755       //we access the GUI a lot here so we'll do everything from the
2756       //Swing thread
2757       SwingUtilities.invokeLater(
2758                      new SetRemovedOperation(e.getAnnotationSetName()));
2759     }//public void annotationSetRemoved(gate.event.DocumentEvent e)
2760 
2761     /**Called when the content of the document has changed through an edit
2762      * operation.
2763      */
2764     public void contentEdited(DocumentEvent e){
2765       //ignore
2766     }
2767 
2768     public void annotationAdded(AnnotationSetEvent e) {
2769       AnnotationSet set = (AnnotationSet)e.getSource();
2770       String setName = set.getName();
2771       if(setName == nullsetName = "Default";
2772       Annotation ann = e.getAnnotation();
2773       String type = ann.getType();
2774       TypeData tData = getTypeData(setName, type);
2775 
2776       boolean tableChanged = false;
2777       if(tData != null){
2778 //                tData.annotations.add(ann);
2779         if(tData.getVisible()){
2780           //1) update the table
2781           data.add(tData.range.end, ann);
2782           tData.range.end++;
2783           Iterator rangesIter = ranges.
2784                                 subList(
2785                                     ranges.indexOf(tData.range1,
2786                                         ranges.size()).
2787                                 iterator();
2788           while(rangesIter.hasNext()){
2789             Range aRange = (RangerangesIter.next();
2790             aRange.start++;
2791             aRange.end++;
2792           }//while(rangesIter.hasNext())
2793           tableChanged = true;
2794 
2795           //2) update the text
2796           SwingUtilities.invokeLater(
2797                          new HihglightsShower(ann,
2798                                               textPane.getStyle(
2799                                                 "_" + setName + "." +
2800                                                 type + "_")));
2801         }//if(tData.getVisible())
2802       else {
2803         //new type
2804         Map setMap = (Map)typeDataMap.get(setName);
2805         if(setMap == null){
2806           setMap = new HashMap();
2807           typeDataMap.put(setName, setMap);
2808         }
2809         tData = new TypeData(setName, type, false);
2810         tData.setAnnotations(set.get(type));
2811         setMap.put(type, tData);
2812         SwingUtilities.invokeLater(new NodeAdder(tData));
2813 
2814       }//new type
2815 
2816       if(tableChanged){
2817         SwingUtilities.invokeLater(new Runnable() {
2818           public void run(){
2819             if(annotationsTableModel != null){
2820               annotationsTableModel.fireTableDataChanged();
2821             }
2822           }
2823         });
2824       }//if(tableChanged)
2825     }//public void annotationAdded(AnnotationSetEvent e)
2826 
2827     public void annotationRemoved(AnnotationSetEvent e){
2828       AnnotationSet set = (AnnotationSet)e.getSource();
2829       String setName = set.getName();
2830       if(setName == nullsetName = "Default";
2831       Annotation ann = e.getAnnotation();
2832       String type = ann.getType();
2833       TypeData tData = getTypeData(setName, type);
2834       boolean tableChanged = false;
2835 
2836       if(tData != null){
2837 //                tData.annotations.remove(ann);
2838         if(tData.getVisible()){
2839           //1) update the annotations table
2840           data.remove(ann);
2841           //shorten the range conatining the annotation
2842           tData.range.end--;
2843           //shift all the remaining ranges
2844           Iterator rangesIter = ranges.
2845                               subList(ranges.indexOf(tData.range1,
2846                               ranges.size()).
2847                                 iterator();
2848           while(rangesIter.hasNext()){
2849             Range aRange = (RangerangesIter.next();
2850             aRange.start--;
2851             aRange.end--;
2852           }//while(rangesIter.hasNext())
2853           tableChanged = true;
2854         }//if(tData.getVisible())
2855         //update the text -> hide the highlight
2856         //required even if not visible
2857         SwingUtilities.invokeLater(new HighlightsRemover(ann));
2858 
2859         //if this was the last annotation of this type remove the type node
2860         if((tData.annotations.size() == &&
2861            tData.annotations.iterator().next() == ann||
2862            tData.annotations.size() == 0){
2863           //no more annotations of this type -> delete the node
2864           SwingUtilities.invokeLater(new NodeRemover(tData));
2865           //remove the data for this type
2866           Map setMap = (Map)typeDataMap.get(setName);
2867           setMap.remove(tData.getType());
2868         }//if(tData.getAnnotations().isEmpty())
2869       }//if(tData != null)
2870 
2871       if(tableChanged){
2872         SwingUtilities.invokeLater(new Runnable() {
2873           public void run(){
2874             if(annotationsTableModel != null){
2875               annotationsTableModel.fireTableDataChanged();
2876             }
2877           }
2878         });
2879       }//if(tableChanged)
2880     }//public void annotationRemoved(AnnotationSetEvent e)
2881 
2882     /**
2883      * Helper class that removes one highlight corresponding to an annotation.
2884      */
2885     class HighlightsRemover implements Runnable{
2886       HighlightsRemover(Annotation ann){
2887         this.ann = ann;
2888       }
2889       public void run(){
2890         int selStart = textPane.getSelectionStart();
2891         int selEnd = textPane.getSelectionEnd();
2892         textPane.select(ann.getStartNode().getOffset().intValue(),
2893                         ann.getEndNode().getOffset().intValue());
2894         textPane.setCharacterAttributes(
2895                   textPane.getStyle("default")true);
2896         textPane.select(selStart, selEnd);
2897       }
2898       Annotation ann;
2899     }//class HihglightsRemover implements Runnable
2900 
2901     /**
2902      * Helper class that highlights a given annotation with the specified style.
2903      */
2904     class HihglightsShower implements Runnable{
2905       HihglightsShower(Annotation ann, Style style){
2906         this.ann = ann;
2907         this.style = style;
2908       }
2909       public void run(){
2910         textPane.select(ann.getStartNode().getOffset().intValue(),
2911                         ann.getEndNode().getOffset().intValue());
2912         textPane.setCharacterAttributes(style, true);
2913       }
2914       Annotation ann;
2915       Style style;
2916     }//class HihglightsRemover implements Runnable
2917 
2918     /**
2919      * Helper class that removes one node from the types tree.
2920      */
2921     class NodeRemover implements Runnable{
2922       NodeRemover(TypeData tData){
2923         this.tData = tData;
2924       }
2925       public void run(){
2926         DefaultMutableTreeNode node = tData.getNode();
2927         if(node != null){
2928           stylesTreeModel.removeNodeFromParent(tData.getNode());
2929         }else{
2930           Err.prln("Could not find node for " + tData.set + "->" + tData.type);
2931         }
2932       }
2933       TypeData tData;
2934     }//class NodeRemover implements Runnable
2935 
2936     /**
2937      * Helper class that adds a specified tree node
2938      */
2939     class NodeAdder implements Runnable{
2940       NodeAdder(TypeData tData){
2941         this.tData = tData;
2942       }
2943       public void run(){
2944         //create the new node
2945         DefaultMutableTreeNode newNode =
2946                   new DefaultMutableTreeNode(tData, tData.getType() == null);
2947         tData.setNode(newNode);
2948         //find its parent
2949         DefaultMutableTreeNode node = null;
2950         if(tData.getType() == null){
2951           //set node
2952           node = (DefaultMutableTreeNode)stylesTreeRoot;
2953 //System.out.println("Set node " + tData.getSet());
2954         }else{
2955 //System.out.println("Type node " + tData.getSet() + ":" + tData.getType());
2956 
2957           //the document should at least have the default annotation set
2958           //if it doesn't, then something's fishy -> return;
2959           if(((DefaultMutableTreeNode)stylesTreeRoot).getChildCount() == 0)
2960             return;
2961           node = (DefaultMutableTreeNode)
2962             ((DefaultMutableTreeNode)stylesTreeRoot).getFirstChild();
2963           while(node != null &&
2964             !((TypeData)node.getUserObject()).getSet().equals(tData.getSet()))
2965             node = node.getNextSibling();
2966         }
2967 
2968         //we have to add typeNode to node
2969         //find the right place
2970         int i = 0;
2971         if(tData.getType() == null){
2972           while (i < node.getChildCount() &&
2973                 ((TypeData)
2974                   ((DefaultMutableTreeNode)node.getChildAt(i)).
2975                   getUserObject()
2976                 ).getSet().compareTo(tData.getSet())<0i++;
2977         }else{
2978           while (i < node.getChildCount() &&
2979                 ((TypeData)
2980                   ((DefaultMutableTreeNode)node.getChildAt(i)).
2981                   getUserObject()
2982                 ).getType().compareTo(tData.getType())<0i++;
2983         }
2984 
2985         //insert it!
2986         stylesTreeModel.insertNodeInto(newNode, node, i);
2987 
2988         if(tData.getType() == null){
2989           //set node, expand it!
2990           stylesTree.expandPath(new TreePath(new Object[]{stylesTreeRoot,
2991                                                           newNode}));
2992         }
2993       }
2994 
2995       TypeData tData;
2996     }//class NodeAdder implements Runnable
2997 
2998     /**
2999      * Helper class that handles the removal of a named annotation set.
3000      * This runnable should only be called from the Swing thread
3001      */
3002     class SetRemovedOperation implements Runnable{
3003       SetRemovedOperation(String setName){
3004         this.setName = setName;
3005       }
3006 
3007       public void run(){
3008         //find the set node
3009         Enumeration setNodesEnum = stylesTreeRoot.children();
3010         DefaultMutableTreeNode setNode = null;
3011         boolean done = false;
3012         while(!done && setNodesEnum.hasMoreElements()){
3013           setNode = (DefaultMutableTreeNode)setNodesEnum.nextElement();
3014           done = ((TypeData)setNode.getUserObject()).getSet().equals(setName);
3015         }
3016 
3017         if(!((TypeData)setNode.getUserObject()).getSet().equals(setName)){
3018           throw new GateRuntimeException(
3019                 "Could not find the tree node for the " + setName +
3020                 " annotation set!");
3021         }
3022 
3023         boolean tableChanged = false;
3024         Enumeration typeNodesEnum = setNode.children();
3025         while(typeNodesEnum.hasMoreElements()){
3026           DefaultMutableTreeNode typeNode =
3027             (DefaultMutableTreeNode)typeNodesEnum.nextElement();
3028           TypeData tData = (TypeData)typeNode.getUserObject();
3029           if(tData.getVisible()){
3030             //1) update the annotations table
3031             data.subList(tData.range.start, tData.range.end).clear();
3032             //remove the range
3033             int delta = tData.range.end - tData.range.start;
3034             //1a)first shift all following ranges
3035             Iterator rangesIter = ranges.
3036                                 subList(ranges.indexOf(tData.range1,
3037                                 ranges.size()).
3038                                   iterator();
3039             while(rangesIter.hasNext()){
3040               Range aRange = (RangerangesIter.next();
3041               aRange.start -= delta;
3042               aRange.end -= delta;
3043             }//while(rangesIter.hasNext())
3044             //1b)now remove the range
3045             ranges.remove(tData.range);
3046             tableChanged = true;
3047 
3048             //2)update the text
3049             //hide the highlights
3050 
3051             Iterator annIter = tData.getAnnotations().iterator();
3052             while(annIter.hasNext()){
3053               Annotation ann = (Annotation)annIter.next();
3054               new HighlightsRemover(ann).run();
3055             }//while(annIter.hasNext())
3056           }//if(tData.getVisible())
3057         }//while(typeNodesEnum.hasMoreElements())
3058 
3059         if(tableChanged){
3060           if(annotationsTableModel != null){
3061             annotationsTableModel.fireTableDataChanged();
3062           }
3063         }//if(tableChanged)
3064 
3065         //remove the node for the set
3066         typeDataMap.remove(setName);
3067         stylesTreeModel.removeNodeFromParent(setNode);
3068       }//public void run()
3069 
3070       String setName;
3071     }
3072 
3073   }//class EventsHandler
3074 
3075   /**
3076    *  Listens for updates from the text editor and updates the GATE document
3077    *  accordingly
3078    */
3079   class SwingDocumentListener implements javax.swing.event.DocumentListener{
3080     public void insertUpdate(final javax.swing.event.DocumentEvent e) {
3081       try{
3082         document.edit(new Long(e.getOffset())new Long(e.getOffset()),
3083                       new DocumentContentImpl(
3084                         e.getDocument().getText(e.getOffset(), e.getLength())));
3085         SwingUtilities.invokeLater(new Runnable(){
3086           public void run(){
3087             annotationsTable.repaint();
3088             repairHighlights(e.getOffset(), e.getOffset() + e.getLength());
3089           }
3090         });
3091         updateBlinks();
3092       }catch(BadLocationException ble){
3093         ble.printStackTrace(Err.getPrintWriter());
3094       }catch(InvalidOffsetException ioe){
3095         ioe.printStackTrace(Err.getPrintWriter());
3096       }
3097     }
3098 
3099     public void removeUpdate(javax.swing.event.DocumentEvent e) {
3100       try{
3101         document.edit(new Long(e.getOffset()),
3102                       new Long(e.getOffset() + e.getLength()),
3103                       new DocumentContentImpl(""));
3104         SwingUtilities.invokeLater(new Runnable(){
3105           public void run(){
3106             annotationsTable.repaint();
3107           }
3108         });
3109         updateBlinks();
3110       }catch(InvalidOffsetException ioe){
3111         ioe.printStackTrace(Err.getPrintWriter());
3112       }
3113     }
3114 
3115     public void changedUpdate(javax.swing.event.DocumentEvent e) {
3116       //some attributes changed: we don't care about that
3117     }
3118     /**
3119      * Restores the blinking selection if any
3120      */
3121     protected void updateBlinks(){
3122       int[] rows = annotationsTable.getSelectedRows();
3123       if(rows != null && rows.length > 0){
3124         selectionHighlighter.removeAllHighlights();
3125         for(int i = 0; i < rows.length; i++){
3126           int start = ((Long)annotationsTable.getModel().
3127                        getValueAt(rows[i]2)
3128                       ).intValue();
3129           int end = ((Long)annotationsTable.getModel().
3130                      getValueAt(rows[i]3)
3131                     ).intValue();
3132 
3133           // compute correction for new line breaks in long lines
3134           start += longLinesCorrection(start);
3135           end += longLinesCorrection(end);
3136 
3137           //start blinking the annotation
3138           try{
3139             synchronized (selectionHighlighter){
3140               selectionHighlighter.addHighlight(start, end,
3141                           DefaultHighlighter.DefaultPainter);
3142             }
3143           }catch(BadLocationException ble){
3144             throw new GateRuntimeException(ble.toString());
3145           }
3146         }//for(int i = 0; i < rows.length; i++)
3147 
3148 //        annotationsTable.clearSelection();
3149 //        for (int i = 0; i < rows.length; i++) {
3150 //          annotationsTable.addRowSelectionInterval(rows[i], rows[i]);
3151 //        }
3152       }
3153 
3154     }
3155   }//class SwingDocumentListener implements javax.swing.event.DocumentListener
3156 
3157   /**
3158    * This class handles the blinking for the selected annotations in the
3159    * text display.
3160    */
3161   class SelectionBlinker implements Runnable{
3162     public void run(){
3163       synchronized(selectionHighlighter){
3164         highlights = selectionHighlighter.getHighlights();
3165       }
3166 
3167 
3168       while(highlights != null && highlights.length > 0){
3169         SwingUtilities.invokeLater(new Runnable(){
3170           public void run(){
3171             showHighlights();
3172           }
3173         });
3174         try{
3175           Thread.sleep(400);
3176         }catch(InterruptedException ie){
3177           ie.printStackTrace(Err.getPrintWriter());
3178         }
3179         SwingUtilities.invokeLater(new Runnable(){
3180           public void run(){
3181             hideHighlights();
3182           }
3183         });
3184 
3185         try{
3186           Thread.sleep(600);
3187         }catch(InterruptedException ie){
3188           ie.printStackTrace(Err.getPrintWriter());
3189         }
3190         synchronized(selectionHighlighter){
3191           highlights = selectionHighlighter.getHighlights();
3192         }
3193       }//while we have highlights
3194       //no more highlights; stop the thread by exiting run();
3195       synchronized(selectionHighlighter){
3196         thread = null;
3197       }
3198     }//run()
3199 
3200     /**
3201      * If there is no running thread then starts one and stores it in
3202      * the <tt>thread</tt> member.
3203      */
3204     public synchronized void testAndStart(){
3205       synchronized(selectionHighlighter){
3206         if(thread == null){
3207           thread  = new Thread(Thread.currentThread().getThreadGroup(),
3208                                this, "AnnotationEditor2");
3209           thread.setPriority(Thread.MIN_PRIORITY);
3210           thread.start();
3211         }
3212       }
3213     }
3214 
3215     protected void showHighlights(){
3216       actualHighlights.clear();
3217       try{
3218         for(int i = 0; i < highlights.length; i++){
3219           actualHighlights.add(highlighter.addHighlight(
3220                                    highlights[i].getStartOffset(),
3221                                    highlights[i].getEndOffset(),
3222                                    highlights[i].getPainter()));
3223         }
3224       }catch(BadLocationException ble){
3225         ble.printStackTrace(Err.getPrintWriter());
3226       }
3227     }
3228 
3229     protected void hideHighlights(){
3230       Iterator hIter = actualHighlights.iterator();
3231       while(hIter.hasNext()) highlighter.removeHighlight(hIter.next());
3232     }
3233 
3234     ArrayList actualHighlights = new ArrayList();
3235     Thread thread;
3236     Highlighter.Highlight[] highlights;
3237   }//class SelectionBlinker implements Runnable
3238 
3239   /**
3240    * Fixes the <a
3241    * href="http://developer.java.sun.com/developer/bugParade/bugs/4406598.html">
3242    * 4406598 bug</a> in swing text components.
3243    * The bug consists in the fact that the Background attribute is ignored by
3244    * the text component whent it is defined in a style from which the current
3245    * style inherits.
3246    */
3247   public class CustomLabelView extends javax.swing.text.LabelView {
3248     public CustomLabelView(Element elem) {
3249       super(elem);
3250     }
3251 
3252     public Color getBackground() {
3253       AttributeSet attr = getAttributes();
3254       if (attr != null) {
3255         javax.swing.text.Document d = super.getDocument();
3256         if (instanceof StyledDocument){
3257           StyledDocument doc = (StyledDocumentd;
3258           return doc.getBackground(attr);
3259         }else{
3260           return null;
3261         }
3262       }
3263       return null;
3264     }
3265   }
3266 
3267   /**
3268    * The popup menu items used to select annotations at right click.
3269    * Apart from the normal {@link javax.swing.JMenuItem} behaviour, this menu
3270    * item also highlits the annotation which it would select if pressed.
3271    */
3272   protected class HighlightAnnotationMenu extends JMenu {
3273     public HighlightAnnotationMenu(Annotation ann, AnnotationSet aSet) {
3274       super(ann.getType());
3275       setToolTipText("<html><b>Features:</b><br>" +
3276                      (ann.getFeatures() == null "" :
3277                      ann.getFeatures().toString()) "</html>");
3278       this.annotation = ann;
3279       this.set = aSet;
3280       this.setName = (set.getName() == null"Default" : set.getName();
3281       start = ann.getStartNode().getOffset().intValue();
3282       end = ann.getEndNode().getOffset().intValue();
3283       this.addMouseListener(new MouseAdapter() {
3284         public void mouseEntered(MouseEvent e) {
3285           try {
3286             highlight = highlighter.addHighlight(start, end,
3287                                             DefaultHighlighter.DefaultPainter);
3288           }catch(BadLocationException ble){
3289             throw new GateRuntimeException(ble.toString());
3290           }
3291         }
3292 
3293         public void mouseExited(MouseEvent e) {
3294           if(highlight != null){
3295             highlighter.removeHighlight(highlight);
3296             highlight = null;
3297           }
3298         }
3299       });
3300 
3301       this.add(new AbstractAction(){
3302         {
3303           putValue(NAME, "Select");
3304         }
3305         public void actionPerformed(ActionEvent e) {
3306           Runnable runnable = new Runnable(){
3307             public void run(){
3308               if(highlight != null){
3309                 highlighter.removeHighlight(highlight);
3310                 highlight = null;
3311               }
3312               selectAnnotation(setName, annotation);
3313             }
3314           };
3315           Thread thread = new Thread(Thread.currentThread().getThreadGroup(),
3316                                      runnable,
3317                                      "AnnotationEditor5");
3318           thread.start();
3319         }
3320       });
3321 
3322       this.add(new AbstractAction(){
3323         {
3324           putValue(NAME, "Delete");
3325         }
3326         public void actionPerformed(ActionEvent e) {
3327           Runnable runnable = new Runnable(){
3328             public void run(){
3329               if(highlight != null){
3330                 highlighter.removeHighlight(highlight);
3331                 highlight = null;
3332               }
3333               set.remove(annotation);
3334             }
3335           };
3336           Thread thread = new Thread(Thread.currentThread().getThreadGroup(),
3337                                      runnable,
3338                                      "AnnotationEditor5");
3339           thread.start();
3340         }
3341       });
3342 
3343     }
3344 
3345     int start;
3346     int end;
3347     AnnotationSet set;
3348     String setName;
3349     Annotation annotation;
3350     Object highlight;
3351   }
3352 
3353 
3354   protected class DeleteSelectedAnnotationsAction extends AbstractAction {
3355     public DeleteSelectedAnnotationsAction(JComponent source){
3356       super("Delete selected annotations");
3357       this.source = source;
3358     }
3359 
3360     public void actionPerformed(ActionEvent evt){
3361       if(source == annotationsTable){
3362         //collect the list of annotations to be removed
3363         //maps from set name to list of annotations to be removed
3364         Map annotationsBySet = new HashMap();
3365         int[] rows = annotationsTable.getSelectedRows();
3366         String setName;
3367         for(int i = 0; i < rows.length; i++){
3368           int row = rows[i];
3369           //find the annotation
3370           Annotation ann = (Annotation)annotationsTable.
3371                               getModel().getValueAt(row, -1);
3372           //find the annotation set
3373           setName = (String)annotationsTable.getModel().
3374                                                       getValueAt(row, 1);
3375           java.util.List existingList = (java.util.List)
3376                                         annotationsBySet.get(setName);
3377           if(existingList == null){
3378             existingList = new ArrayList();
3379             annotationsBySet.put(setName, existingList);
3380           }
3381           existingList.add(ann);
3382         }//for(int i = 0; i < rows.length; i++)
3383         //remove the collected annotations
3384         Iterator setsIter = annotationsBySet.keySet().iterator();
3385         while(setsIter.hasNext()){
3386           setName = (String)setsIter.next();
3387           AnnotationSet set = setName.equals("Default")?
3388                               document.getAnnotations() :
3389                               document.getAnnotations(setName);
3390           set.removeAll((java.util.List)annotationsBySet.get(setName));
3391         }//while(setsIter.hasNext())
3392       }else if(source == stylesTree){
3393         TreePath[] paths = stylesTree.getSelectionPaths();
3394         for(int i = 0; i < paths.length; i++){
3395           TypeData tData = (TypeData)((DefaultMutableTreeNode)
3396                             paths[i].getLastPathComponent()).getUserObject();
3397           String setName = tData.getSet();
3398           if(tData.getType() == null){
3399             //set node
3400             if(setName.equals("Default")){
3401               JOptionPane.showMessageDialog(
3402                 DocumentEditor.this,
3403                 "The default annotation set cannot be deleted!\n" +
3404                 "It will only be cleared...",
3405                 "GATE", JOptionPane.ERROR_MESSAGE);
3406               document.getAnnotations().clear();
3407             }else{
3408               document.removeAnnotationSet(setName);
3409             }
3410           }else{
3411             //type node
3412             if(!setName.equals("Default"&&
3413                !document.getNamedAnnotationSets().containsKey(setName)){
3414               //the set for this type has already been removed completely
3415               //nothing more do (that's nice :) )
3416               return;
3417             }
3418             AnnotationSet set = setName.equals("Default"?
3419                                 document.getAnnotations() :
3420                                 document.getAnnotations(setName);
3421             if(set != null){
3422               AnnotationSet subset = set.get(tData.getType());
3423               if(subset != nullset.removeAll(new ArrayList(subset));
3424             }//if(set != null)
3425           }//type node
3426         }//for(int i = 0; i < paths.length; i++)
3427       }else if(source == corefTree){
3428         TreePath[] paths = corefTree.getSelectionPaths();
3429         for(int i = 0; i < paths.length; i++){
3430           CorefData cData = (CorefData)((DefaultMutableTreeNode)
3431                             paths[i].getLastPathComponent()).getUserObject();
3432           class CorefClearer implements Runnable{
3433             CorefClearer(CorefData cData){
3434               this.cData = cData;
3435             }
3436             public void run(){
3437               cData.removeAnnotations();
3438             }
3439             CorefData cData;
3440           }
3441           Thread thread = new Thread(new CorefClearer(cData));
3442           thread.setPriority(Thread.MIN_PRIORITY);
3443           thread.start();
3444         }
3445       }
3446     }//public void actionPerformed(ActionEvent evt)
3447     JComponent source;
3448   }//protected class DeleteSelectedAnnotationsAction
3449 
3450   protected class SearchAction extends AbstractAction {
3451     public SearchAction(){
3452       super("Search");
3453       putValue(SHORT_DESCRIPTION, "Search within the text");
3454       putValue(SMALL_ICON, MainFrame.getIcon("search"));
3455     }
3456 
3457     public void actionPerformed(ActionEvent evt){
3458       if(searchDialog == null){
3459         Window parent = SwingUtilities.getWindowAncestor(DocumentEditor.this);
3460         searchDialog = (parent instanceof Dialog?
3461                        new SearchDialog((Dialog)parent:
3462                        new SearchDialog((Frame)parent);
3463         searchDialog.pack();
3464         searchDialog.setLocationRelativeTo(DocumentEditor.this);
3465         searchDialog.setResizable(false);
3466         MainFrame.getGuiRoots().add(searchDialog);
3467       }
3468 
3469       if(searchDialog.isVisible()){
3470         searchDialog.toFront();
3471       }else{
3472         searchDialog.setVisible(true);
3473       }
3474     }
3475   }
3476 
3477   protected class SearchDialog extends JDialog{
3478     SearchDialog(Frame owner){
3479       super(owner, false);
3480       setTitle"Find in \"" + document.getName() "\"");
3481       initLocalData();
3482       initGuiComponents();
3483       initListeners();
3484     }
3485 
3486     SearchDialog(Dialog owner){
3487       super(owner, false);
3488       setTitle("Find in \"" + document.getName() "\"");
3489       initLocalData();
3490       initGuiComponents();
3491       initListeners();
3492     }
3493     protected void initLocalData(){
3494       pattern = null;
3495       nextMatchStartsFrom = 0;
3496       content = document.getContent().toString();
3497 
3498       findFirstAction = new AbstractAction("Find first"){
3499         {
3500           putValue(SHORT_DESCRIPTION, "Finds first match");
3501         }
3502 
3503         public void actionPerformed(ActionEvent evt){
3504           //needed to create the right RE
3505           refresh();
3506           //remove selection
3507           textPane.setCaretPosition(textPane.getCaretPosition());
3508           boolean found = false;
3509           int start = nextMatchStartsFrom - 1;
3510           int end = -1;
3511           
3512           Matcher matcher = pattern.matcher(content);
3513           while (matcher.find() && (found == false))
3514               {
3515                   start = matcher.start();
3516                   end = matcher.end();
3517                   if (wholeWordsChk.isSelected())
3518                       {
3519                           //validate the result
3520                           found = (start == || !Character.isLetterOrDigit(content.charAt(start - 1)))
3521                                   && (end == content.length() || !Character.isLetterOrDigit(content.charAt(end)));
3522                       }
3523                   else
3524                       found = true;
3525               }
3526                              
3527           if (found)
3528               {
3529                   nextMatchStartsFrom = start + 1;
3530                   //display the result
3531                   SwingUtilities.getWindowAncestor(textPane).requestFocus();
3532                   textPane.requestFocus();
3533                   textPane.setCaretPosition(start);
3534                   textPane.moveCaretPosition(end);
3535               }
3536           else
3537               {
3538                   JOptionPane.showMessageDialog(searchDialog, "String not found!""GATE", JOptionPane.INFORMATION_MESSAGE);
3539               }
3540          }
3541       };
3542 
3543 
3544       findNextAction = new AbstractAction("Find next"){
3545         {
3546           putValue(SHORT_DESCRIPTION, "Finds next match");
3547         }
3548         public void actionPerformed(ActionEvent evt){
3549           //needed to create the right RE
3550           refresh();
3551           //remove selection
3552           textPane.setCaretPosition(textPane.getCaretPosition());
3553           boolean found = false;
3554           int start = nextMatchStartsFrom - 1;
3555           int end = -1;
3556           
3557           Matcher matcher = pattern.matcher(content);
3558           while (matcher.find() && (found == false))
3559               {
3560                   start = matcher.start();
3561                   end = matcher.end();
3562                   if (wholeWordsChk.isSelected())
3563                       {
3564                           //validate the result
3565                           found = (start == || !Character.isLetterOrDigit(content.charAt(start - 1)))
3566                                   && (end == content.length() || !Character.isLetterOrDigit(content.charAt(end)));
3567                       }
3568                   else
3569                       found = true;
3570               }
3571                              
3572           if (found)
3573               {
3574                   nextMatchStartsFrom = start + 1;
3575                   //display the result
3576                   SwingUtilities.getWindowAncestor(textPane).requestFocus();
3577                   textPane.requestFocus();
3578                   textPane.setCaretPosition(start);
3579                   textPane.moveCaretPosition(end);
3580               }
3581           else
3582               {
3583                   JOptionPane.showMessageDialog(searchDialog, "String not found!""GATE", JOptionPane.INFORMATION_MESSAGE);
3584               }
3585             }
3586            };
3587 
3588       cancelAction = new AbstractAction("Cancel"){
3589         {
3590           putValue(SHORT_DESCRIPTION, "Cancel");
3591         }
3592         public void actionPerformed(ActionEvent evt){
3593           searchDialog.setVisible(false);
3594         }
3595       };
3596 
3597     }
3598 
3599 
3600     protected void initGuiComponents(){
3601       getContentPane().setLayout(new BoxLayout(getContentPane(),
3602                                                BoxLayout.Y_AXIS));
3603 
3604       getContentPane().add(Box.createVerticalStrut(5));
3605       Box hBox = Box.createHorizontalBox();
3606       hBox.add(Box.createHorizontalStrut(5));
3607       hBox.add(new JLabel("Find what:"));
3608       hBox.add(Box.createHorizontalStrut(5));
3609       hBox.add(patternTextField = new JTextField(20));
3610       hBox.add(Box.createHorizontalStrut(5));
3611       hBox.add(Box.createHorizontalGlue());
3612       getContentPane().add(hBox);
3613 
3614       getContentPane().add(Box.createVerticalStrut(5));
3615       hBox = Box.createHorizontalBox();
3616       hBox.add(Box.createHorizontalStrut(5));
3617       hBox.add(ignoreCaseChk = new JCheckBox("Ignore case"false));
3618       hBox.add(Box.createHorizontalStrut(5));
3619       hBox.add(wholeWordsChk = new JCheckBox("Whole words only"false));
3620       hBox.add(Box.createHorizontalStrut(5));
3621       hBox.add(Box.createHorizontalGlue());
3622       getContentPane().add(hBox);
3623 
3624       getContentPane().add(Box.createVerticalStrut(5));
3625       hBox = Box.createHorizontalBox();
3626       hBox.add(Box.createHorizontalGlue());
3627       hBox.add(new JButton(findFirstAction));
3628       hBox.add(Box.createHorizontalStrut(5));
3629       hBox.add(new JButton(findNextAction));
3630       hBox.add(Box.createHorizontalStrut(5));
3631       hBox.add(new JButton(cancelAction));
3632       hBox.add(Box.createHorizontalGlue());
3633       getContentPane().add(hBox);
3634       getContentPane().add(Box.createVerticalStrut(5));
3635     }
3636 
3637     protected void initListeners(){
3638       addComponentListener(new ComponentAdapter() {
3639         public void componentHidden(ComponentEvent e) {
3640         }
3641 
3642         public void componentMoved(ComponentEvent e) {
3643         }
3644 
3645         public void componentResized(ComponentEvent e) {
3646         }
3647 
3648         public void componentShown(ComponentEvent e) {
3649           refresh();
3650         }
3651       });
3652 
3653       patternTextField.getDocument().addDocumentListener(
3654         new javax.swing.event.DocumentListener() {
3655         public void insertUpdate(javax.swing.event.DocumentEvent e) {
3656           refresh();
3657         }
3658 
3659         public void removeUpdate(javax.swing.event.DocumentEvent e) {
3660           refresh();
3661         }
3662 
3663         public void changedUpdate(javax.swing.event.DocumentEvent e) {
3664           refresh();
3665         }
3666       });
3667 
3668     }
3669 
3670     protected void refresh(){
3671       String patternText = patternTextField.getText();
3672       if(patternText != null && patternText.length() 0){
3673         //update actions state
3674         findFirstAction.setEnabled(true);
3675         findNextAction.setEnabled(true);
3676 
3677         //update patternRE
3678         try
3679         {
3680             pattern = ignoreCaseChk.isSelected() ? Pattern.compile(patternText, Pattern.CASE_INSENSITIVE: Pattern
3681                     .compile(patternText);
3682         }
3683     catch (Exception ree)
3684         {
3685             JOptionPane.showMessageDialog(searchDialog, "Invalid pattern!\n" + ree.toString()"GATE", JOptionPane.ERROR_MESSAGE);
3686         }
3687       }else{
3688         findFirstAction.setEnabled(false);
3689         findNextAction.setEnabled(false);
3690       }
3691 
3692       if(pattern == null){
3693       }
3694     }
3695     JTextField patternTextField;
3696     JCheckBox ignoreCaseChk;
3697     JCheckBox wholeWordsChk;
3698     Pattern pattern;
3699     int nextMatchStartsFrom;
3700     String content;
3701 
3702     Action findFirstAction;
3703     Action findNextAction;
3704     Action cancelAction;
3705   }
3706 
3707   protected class PrintAction extends AbstractAction{
3708     public PrintAction(){
3709       super("Print");
3710     }
3711 
3712     public void actionPerformed(ActionEvent e){
3713       Runnable runnable = new Runnable(){
3714         public void run(){
3715           PrinterJob printerJob = PrinterJob.getPrinterJob();
3716 
3717           if (printerJob.printDialog()) {
3718             try{
3719 
3720 //              PageFormat pageFormat = printerJob.pageDialog(printerJob.defaultPage());
3721               PageFormat pageFormat = printerJob.defaultPage();
3722               Pageable pageable = new JComponentPrinter(textPane, pageFormat);
3723               printerJob.setPageable(pageable);
3724 
3725               printerJob.print();
3726               //fire the events
3727               StatusListener sListener = (StatusListener)Gate.
3728                                          getListeners().
3729                                          get("gate.event.StatusListener");
3730               if(sListener != null){
3731                 sListener.statusChanged("Document printed!");
3732               }
3733 
3734             }catch(Exception ex) {
3735               ex.printStackTrace();
3736             }
3737           }
3738         }
3739       };
3740 
3741       Thread thread = new Thread(Thread.currentThread().getThreadGroup(),
3742                                  runnable, "Print thread");
3743       thread.setPriority(Thread.MIN_PRIORITY);
3744       thread.start();
3745     }
3746   }
3747 
3748 
3749   /**
3750    * The action that is fired when the user wants to edit an annotation.
3751    * It will build a dialog containing all the valid annotation editors.
3752    */
3753   protected class EditAnnotationAction extends AbstractAction {
3754     public EditAnnotationAction(AnnotationSet set, Annotation annotation){
3755       super("Edit");
3756       this.set = set;
3757       this.annotation = annotation;
3758       putValue(SHORT_DESCRIPTION, "Edits the annotation");
3759     }
3760 
3761     public void actionPerformed(ActionEvent e){
3762       //get the list of editors
3763       java.util.List specificEditors = Gate.getCreoleRegister().
3764                                        getAnnotationVRs(annotation.getType());
3765       java.util.List genericEditors = Gate.getCreoleRegister().
3766                                       getAnnotationVRs();
3767       //create the GUI
3768       JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.BOTTOM);
3769       //add all the specific editors
3770       Iterator editorIter = specificEditors.iterator();
3771       while(editorIter.hasNext()){
3772         String editorType = (String)editorIter.next();
3773         //create the editor
3774         AnnotationVisualResource editor;
3775         try{
3776           editor = (AnnotationVisualResource)
3777                    Factory.createResource(editorType);
3778           if(editor instanceof ResizableVisualResource){
3779             tabbedPane.add((Component)editor,
3780                            ((ResourceData)Gate.getCreoleRegister().
3781                            get(editorType)).getName());
3782           }else{
3783             JScrollPane scroller = new JScrollPane((Component)editor);
3784 //            scroller.setPreferredSize(((Component) editor).getPreferredSize());
3785             tabbedPane.add(scroller,
3786                            ((ResourceData)Gate.getCreoleRegister().
3787                             get(editorType)).getName());
3788           }
3789 
3790 //          editor.setTarget(set);
3791 //          editor.setAnnotation(annotation);
3792           editor.editAnnotation(annotation, set);
3793         }catch(ResourceInstantiationException rie){
3794           rie.printStackTrace(Err.getPrintWriter());
3795         }
3796       }
3797 
3798       //add all the generic editors
3799       editorIter = genericEditors.iterator();
3800       while(editorIter.hasNext()){
3801         String editorType = (String)editorIter.next();
3802         //create the editor
3803         AnnotationVisualResource editor;
3804         try{
3805           editor  = (AnnotationVisualResource)
3806                                           Factory.createResource(editorType);
3807           if(editor.canDisplayAnnotationType(annotation.getType())){
3808 //            editor.setTarget(set);
3809 //            editor.setAnnotation(annotation);
3810             editor.editAnnotation(annotation, set);
3811             if(editor instanceof ResizableVisualResource){
3812               tabbedPane.add((Component)editor,
3813                              ((ResourceData)Gate.getCreoleRegister().
3814                                                 get(editorType)).getName());
3815             }else{
3816               tabbedPane.add(new JScrollPane((Component)editor),
3817                              ((ResourceData)Gate.getCreoleRegister().
3818                                                 get(editorType)).getName());
3819             }
3820           }
3821         }catch(ResourceInstantiationException rie){
3822           rie.printStackTrace(Err.getPrintWriter());
3823         }
3824 
3825       }
3826 
3827       //show the modal dialog until the data is OK or the user cancels
3828       boolean allOK = false;
3829       while(!allOK){
3830         if(OkCancelDialog.showDialog(DocumentEditor.this,
3831                                      tabbedPane,
3832                                      "Edit Annotation")){
3833           try{
3834             Component comp = tabbedPane.getSelectedComponent();
3835             if(comp instanceof AnnotationVisualResource){
3836               ((AnnotationVisualResource)comp).okAction();
3837             }else if(comp instanceof JScrollPane){
3838               ((AnnotationVisualResource)((JScrollPane)comp).
3839                                           getViewport().getView()).okAction();
3840             }else{
3841               throw new LuckyException("DocumentEditor.EditAnnotationAction1");
3842             }
3843 
3844             allOK = true;
3845           }catch(GateException ge){
3846             JOptionPane.showMessageDialog(
3847               DocumentEditor.this,
3848               "There was an error:\n" +
3849               ge.toString(),
3850               "GATE", JOptionPane.ERROR_MESSAGE);
3851             ge.printStackTrace(Err.getPrintWriter());
3852             allOK = false;
3853           }
3854         }else{
3855           if (OkCancelDialog.userHasPressedCancel)
3856             try{
3857               Component comp = tabbedPane.getSelectedComponent();
3858               if(comp instanceof AnnotationVisualResource){
3859                 ((AnnotationVisualResource)comp).cancelAction();
3860               }else if(comp instanceof JScrollPane){
3861                 ((AnnotationVisualResource)
3862                     ((JScrollPane)comp).getViewport().getView()).cancelAction();
3863               }else{
3864                 throw new LuckyException("DocumentEditor.EditAnnotationAction");
3865               }
3866               allOK = true;
3867             catch(GateException ge){
3868               JOptionPane.showMessageDialog(
3869                 DocumentEditor.this,
3870                 "There was an error:\n" +
3871                 ge.toString(),
3872                 "GATE", JOptionPane.ERROR_MESSAGE);
3873               allOK = false;
3874             }
3875           allOK = true;
3876         }
3877       }//while(!allOK)
3878     }//public void actionPerformed(ActionEvent e)
3879 
3880     protected AnnotationSet set;
3881     protected Annotation annotation;
3882   }//class EditAnnotationAction
3883 
3884   /**
3885    * The action that is fired when the user wants to create a new annotation.
3886    * It will build a dialog containing all the valid annotation editors.
3887    */
3888   class NewAnnotationAction extends AbstractAction{
3889     public NewAnnotationAction(AnnotationSet set,
3890                                Long startOffset,
3891                                Long endOffset){
3892       super("New annotation");
3893       putValue(SHORT_DESCRIPTION, "Creates a new annotation");
3894       this.set = set;
3895       this.startOffset = startOffset;
3896       this.endOffset = endOffset;
3897       this.type = null;
3898     }
3899 
3900     public NewAnnotationAction(AnnotationSet set, String type,
3901                                Long startOffset, Long endOffset){
3902       super("New \"" + type + "\" annotation");
3903       putValue(SHORT_DESCRIPTION, "Creates a new annotation of type \"" +
3904                                   type + "\"");
3905       this.set = set;
3906       this.startOffset = startOffset;
3907       this.endOffset = endOffset;
3908       this.type = type;
3909     }
3910 
3911     public void actionPerformed(ActionEvent e){
3912       if(set == null){
3913         //get the name from the user
3914         String setName = JOptionPane.showInputDialog(
3915               DocumentEditor.this,
3916               "Please provide a name for the new annotation set",
3917               "GATE", JOptionPane.QUESTION_MESSAGE);
3918         if(setName == nullreturn;
3919         this.set = document.getAnnotations(setName);
3920       }
3921       try{
3922         //create the new annotation
3923         Integer annId = set.add(startOffset, endOffset,
3924                 (type == null "_New_" : type),
3925                 Factory.newFeatureMap());
3926         Annotation ann = set.get(annId);
3927         new EditAnnotationAction(set, ann).actionPerformed(e);
3928       }catch (GateException ge) {
3929         JOptionPane.showMessageDialog(
3930                 DocumentEditor.this,
3931                 "There was an error:\n" +
3932                 ge.toString(),
3933                 "GATE", JOptionPane.ERROR_MESSAGE);
3934       }
3935 //      
3936 //      //get the lists of editors
3937 //      java.util.List specificEditors;
3938 //      if(type != null) specificEditors = Gate.getCreoleRegister().
3939 //                                         getAnnotationVRs(type);
3940 //      else specificEditors = new ArrayList();
3941 //
3942 //      java.util.List genericEditors = Gate.getCreoleRegister().
3943 //                                      getAnnotationVRs();
3944 //      //create the GUI
3945 //      JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.BOTTOM);
3946 //      //add all the specific editors
3947 //      Iterator editorIter = specificEditors.iterator();
3948 //      while(editorIter.hasNext()){
3949 //        String editorType = (String)editorIter.next();
3950 //        //create the editor
3951 //        AnnotationVisualResource editor;
3952 //        try{
3953 //          editor = (AnnotationVisualResource)
3954 //                                          Factory.createResource(editorType);
3955 //          tabbedPane.add(new JScrollPane((Component)editor),
3956 //                        ((ResourceData)Gate.getCreoleRegister().get(editorType)).
3957 //                                                                getName());
3958 //          editor.setTarget(set);
3959 //          editor.setSpan(startOffset, endOffset, type);
3960 //
3961 //        }catch(ResourceInstantiationException rie){
3962 //          rie.printStackTrace(Err.getPrintWriter());
3963 //        }
3964 //      }
3965 //
3966 //      //add all the generic editors
3967 //      editorIter = genericEditors.iterator();
3968 //      while(editorIter.hasNext()){
3969 //        String editorType = (String)editorIter.next();
3970 //        //create the editor
3971 //        AnnotationVisualResource editor;
3972 //        try{
3973 //          editor  = (AnnotationVisualResource)
3974 //                                          Factory.createResource(editorType);
3975 //
3976 //          if(type == null ||
3977 //             (type != null && editor.canDisplayAnnotationType(type))){
3978 //            editor.setTarget(set);
3979 //            editor.setSpan(startOffset, endOffset, type);
3980 //            tabbedPane.add(new JScrollPane((Component)editor),
3981 //                           ((ResourceData)Gate.getCreoleRegister().
3982 //                                              get(editorType)).getName());
3983 //          }
3984 //        }catch(ResourceInstantiationException rie){
3985 //          rie.printStackTrace(Err.getPrintWriter());
3986 //        }
3987 //
3988 //      }
3989 //
3990 //      //show the modal dialog until the data is OK or the user cancels
3991 //      boolean allOK = false;
3992 //      while(!allOK){
3993 //        if(OkCancelDialog.showDialog(DocumentEditor.this,
3994 //                                     tabbedPane, "Edit Annotation")){
3995 //          try{
3996 //            ((AnnotationVisualResource)((JScrollPane)tabbedPane.
3997 //                                        getSelectedComponent()).getViewport().
3998 //                                                                getView()
3999 //             ).okAction();
4000 //             allOK = true;
4001 //          }catch(GateException ge){
4002 //            JOptionPane.showMessageDialog(
4003 //              DocumentEditor.this,
4004 //              "There was an error:\n" +
4005 //              ge.toString(),
4006 //              "GATE", JOptionPane.ERROR_MESSAGE);
4007 ////            ge.printStackTrace(Err.getPrintWriter());
4008 //            allOK = false;
4009 //          }
4010 //        }else{
4011 //          allOK = true;
4012 //        }
4013 //      }//while(!allOK)
4014 //
4015 //
4016     }//public void actionPerformed(ActionEvent e)
4017 
4018     AnnotationSet set;
4019     Long startOffset;
4020     Long endOffset;
4021     String type;
4022   }//class NewAnnotationAction extends AbstractAction
4023 
4024   /**
4025    * Fixes the <a
4026    * href="http://developer.java.sun.com/developer/bugParade/bugs/4406598.html">
4027    * 4406598 bug</a> in swing text components.
4028    * The bug consists in the fact that the Background attribute is ignored by
4029    * the text component whent it is defined in a style from which the current
4030    * style inherits.
4031    */
4032   public class CustomStyledEditorKit extends StyledEditorKit{
4033     private final ViewFactory defaultFactory = new CustomStyledViewFactory();
4034     public ViewFactory getViewFactory() {
4035       return defaultFactory;
4036     }
4037 
4038     /**
4039       * Inserts content from the given stream, which will be
4040       * treated as plain text.
4041       * This insertion is done without checking \r or \r \n sequence.
4042       * It takes the text from the Reader and place it into Document at position
4043       * pos
4044       */
4045     public void read(Reader in, javax.swing.text.Document doc, int pos)
4046                 throws IOException, BadLocationException {
4047 
4048       char[] buff = new char[65536];
4049       int charsRead = 0;
4050       while ((charsRead = in.read(buff, 0, buff.length)) != -1) {
4051             doc.insertString(pos, new String(buff, 0, charsRead)null);
4052             pos += charsRead;
4053       }// while
4054     }// read
4055   }
4056 
4057   /**
4058    * Fixes the <a
4059    * href="http://developer.java.sun.com/developer/bugParade/bugs/4406598.html">
4060    * 4406598 bug</a> in swing text components.
4061    * The bug consists in the fact that the Background attribute is ignored by
4062    * the text component whent it is defined in a style from which the current
4063    * style inherits.
4064    */
4065   public class CustomStyledViewFactory implements ViewFactory{
4066     public View create(Element elem) {
4067       String kind = elem.getName();
4068       if (kind != null) {
4069         if (kind.equals(AbstractDocument.ContentElementName)) {
4070           return new CustomLabelView(elem);
4071         }else if (kind.equals(AbstractDocument.ParagraphElementName)) {
4072           return new ParagraphView(elem);
4073         }else if (kind.equals(AbstractDocument.SectionElementName)) {
4074           return new BoxView(elem, View.Y_AXIS);
4075         }else if (kind.equals(StyleConstants.ComponentElementName)) {
4076           return new ComponentView(elem);
4077         }else if (kind.equals(StyleConstants.IconElementName)) {
4078           return new IconView(elem);
4079         }
4080       }
4081       // default to text display
4082       return new CustomLabelView(elem);
4083     }
4084   }
4085   }//class AnnotationEditor