CorefEditor.java
0001 /*
0002  *  Copyright (c) 1995-2012, 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  *  CorefEditor.java
0011  *
0012  *  Niraj Aswani, 24-Jun-2004
0013  *
0014  *  $Id: CorefEditor.java 19152 2016-03-17 18:39:49Z markagreenwood $
0015  */
0016 
0017 package gate.gui.docview;
0018 
0019 import gate.Annotation;
0020 import gate.AnnotationSet;
0021 import gate.creole.ANNIEConstants;
0022 import gate.event.AnnotationSetEvent;
0023 import gate.event.AnnotationSetListener;
0024 import gate.gui.MainFrame;
0025 import gate.swing.ColorGenerator;
0026 
0027 import java.awt.BorderLayout;
0028 import java.awt.Color;
0029 import java.awt.Component;
0030 import java.awt.FlowLayout;
0031 import java.awt.Point;
0032 import java.awt.event.ActionEvent;
0033 import java.awt.event.ActionListener;
0034 import java.awt.event.KeyAdapter;
0035 import java.awt.event.KeyEvent;
0036 import java.awt.event.MouseAdapter;
0037 import java.awt.event.MouseEvent;
0038 import java.util.ArrayList;
0039 import java.util.Collections;
0040 import java.util.HashMap;
0041 import java.util.Iterator;
0042 import java.util.List;
0043 import java.util.Map;
0044 import java.util.Set;
0045 import java.util.Vector;
0046 
0047 import javax.swing.AbstractAction;
0048 import javax.swing.BorderFactory;
0049 import javax.swing.ComboBoxEditor;
0050 import javax.swing.ComboBoxModel;
0051 import javax.swing.DefaultComboBoxModel;
0052 import javax.swing.JButton;
0053 import javax.swing.JCheckBox;
0054 import javax.swing.JColorChooser;
0055 import javax.swing.JComboBox;
0056 import javax.swing.JLabel;
0057 import javax.swing.JOptionPane;
0058 import javax.swing.JPanel;
0059 import javax.swing.JPopupMenu;
0060 import javax.swing.JScrollPane;
0061 import javax.swing.JTextArea;
0062 import javax.swing.JTextField;
0063 import javax.swing.JToggleButton;
0064 import javax.swing.JTree;
0065 import javax.swing.JWindow;
0066 import javax.swing.SwingUtilities;
0067 import javax.swing.ToolTipManager;
0068 import javax.swing.UIManager;
0069 import javax.swing.event.MouseInputAdapter;
0070 import javax.swing.text.DefaultHighlighter;
0071 import javax.swing.text.Highlighter;
0072 import javax.swing.tree.DefaultMutableTreeNode;
0073 import javax.swing.tree.TreeCellRenderer;
0074 import javax.swing.tree.TreePath;
0075 
0076 /**
0077  * Display a tree that contains the co-references type of the document,
0078  * highlight co-references in the document, allow creating
0079  * co-references from existing annotations, editing and deleting co-references.
0080  */
0081 @SuppressWarnings("serial")
0082 public class CorefEditor
0083     extends AbstractDocumentView
0084     implements ActionListener, gate.event.FeatureMapListener,
0085     gate.event.DocumentListener, AnnotationSetListener {
0086 
0087   // default AnnotationSet Name
0088   private final static String DEFAULT_ANNOTSET_NAME = "Default";
0089 
0090   private JPanel mainPanel, topPanel, subPanel;
0091   private JToggleButton showAnnotations;
0092   private JComboBox<String> annotSets, annotTypes;
0093   private DefaultComboBoxModel<String> annotSetsModel, annotTypesModel;
0094 
0095   // Co-reference Tree
0096   private JTree corefTree;
0097 
0098   // Root node
0099   private CorefTreeNode rootNode;
0100 
0101   // top level hashMap (corefChains)
0102   // AnnotationSet(CorefTreeNode) --> (CorefTreeNode type ChainNode --> ArrayList AnnotationIds)
0103   private Map<CorefTreeNode, Map<CorefTreeNode, List<Integer>>> corefChains;
0104 
0105   // This is used to store the annotationSet name and its respective corefTreeNode
0106   // annotationSetName --> CorefTreeNode of type (AnnotationSet)
0107   private Map<String,CorefTreeNode> corefAnnotationSetNodesMap;
0108 
0109   // annotationSetName --> (chainNodeString --> Boolean)
0110   private Map<String,Map<String,Boolean>> selectionChainsMap;
0111 
0112   // chainString --> Boolean
0113   private Map<String,Boolean> currentSelections;
0114 
0115   // annotationSetName --> (chainNodeString --> Color)
0116   private Map<String,Map<String,Color>> colorChainsMap;
0117 
0118   // chainNodeString --> Color
0119   private Map<String,Color> currentColors;
0120 
0121   private ColorGenerator colorGenerator;
0122   private TextualDocumentView textView;
0123   private JTextArea textPane;
0124 
0125   /* ChainNode --> (HighlightedTags) */
0126   private Map<CorefTreeNode, List<Object>> highlightedTags;
0127 
0128   /* This arraylist stores the highlighted tags for the specific selected annotation type */
0129   private List<Object> typeSpecificHighlightedTags;
0130   private TextPaneMouseListener textPaneMouseListener;
0131 
0132   /* This stores Ids of the highlighted Chain Annotations*/
0133   private List<Annotation> highlightedChainAnnots = new ArrayList<Annotation>();
0134   /* This stores start and end offsets of the highlightedChainAnnotations */
0135   private int[] highlightedChainAnnotsOffsets;
0136 
0137   /* This stores Ids of the highlighted Annotations of particular type */
0138   private List<Annotation> highlightedTypeAnnots = new ArrayList<Annotation>();
0139   /* This stores start and end offsets of highlightedTypeAnnots */
0140   private int[] highlightedTypeAnnotsOffsets;
0141 
0142   /* Timer for the Chain Tool tip action */
0143   private ChainToolTipAction chainToolTipAction;
0144   private javax.swing.Timer chainToolTipTimer;
0145 
0146   private NewCorefAction newCorefAction;
0147   private javax.swing.Timer newCorefActionTimer;
0148 
0149   private Annotation annotToConsiderForChain = null;
0150   private JWindow popupWindow;
0151   private boolean explicitCall = false;
0152   private Highlighter highlighter;
0153 
0154   /**
0155    * This method intiates the GUI for co-reference editor
0156    */
0157   @Override
0158   protected void initGUI() {
0159 
0160     //get a pointer to the textual view used for highlights
0161     Iterator<DocumentView> centralViewsIter = owner.getCentralViews().iterator();
0162     while (textView == null && centralViewsIter.hasNext()) {
0163       DocumentView aView = centralViewsIter.next();
0164       if (aView instanceof TextualDocumentView)
0165         textView = (TextualDocumentViewaView;
0166     }
0167     textPane = (JTextArea) ( (JScrollPanetextView.getGUI()).getViewport().
0168                getView();
0169     highlighter = textPane.getHighlighter();
0170     chainToolTipAction = new ChainToolTipAction();
0171     chainToolTipTimer = new javax.swing.Timer(500, chainToolTipAction);
0172     chainToolTipTimer.setRepeats(false);
0173     newCorefAction = new NewCorefAction();
0174     newCorefActionTimer = new javax.swing.Timer(500, newCorefAction);
0175     newCorefActionTimer.setRepeats(false);
0176 
0177     colorGenerator = new ColorGenerator();
0178 
0179     // main Panel
0180     mainPanel = new JPanel();
0181     mainPanel.setLayout(new BorderLayout());
0182 
0183     // topPanel
0184     topPanel = new JPanel();
0185     topPanel.setLayout(new BorderLayout());
0186 
0187     // subPanel
0188     subPanel = new JPanel();
0189     subPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
0190 
0191     // showAnnotations Button
0192     showAnnotations = new JToggleButton("Show");
0193     showAnnotations.addActionListener(this);
0194 
0195     // annotSets
0196     annotSets = new JComboBox<String>();
0197     annotSets.addActionListener(this);
0198 
0199     // get all the annotationSets
0200     Map<String,AnnotationSet> annotSetsMap = document.getNamedAnnotationSets();
0201     annotSetsModel = new DefaultComboBoxModel<String>();
0202     if (annotSetsMap != null) {
0203       String [] array = annotSetsMap.keySet().toArray(new String[annotSetsMap.keySet().size()]);
0204       for(int i=0;i<array.length;i++) {
0205         annotSetsMap.get(array[i]).addAnnotationSetListener(this);
0206       }
0207       annotSetsModel = new DefaultComboBoxModel<String>(array);
0208     }
0209     document.getAnnotations().addAnnotationSetListener(this);
0210     annotSetsModel.insertElementAt(DEFAULT_ANNOTSET_NAME, 0);
0211     annotSets.setModel(annotSetsModel);
0212 
0213     // annotTypes
0214     annotTypesModel = new DefaultComboBoxModel<String>();
0215     annotTypes = new JComboBox<String>(annotTypesModel);
0216     annotTypes.addActionListener(this);
0217     subPanel.add(new JLabel("Sets : "));
0218     subPanel.add(annotSets);
0219     JPanel tempPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
0220     tempPanel.add(new JLabel("Types : "));
0221     tempPanel.add(annotTypes);
0222     tempPanel.add(showAnnotations);
0223     // intialises the Data
0224     initData();
0225 
0226     // and creating the tree
0227     corefTree = new JTree(rootNode);
0228     corefTree.putClientProperty("JTree.lineStyle""None");
0229     corefTree.setRowHeight(corefTree.getRowHeight() 2);
0230     corefTree.setLargeModel(true);
0231     corefTree.setAutoscrolls(true);
0232 
0233     //corefTree.setRootVisible(false);
0234     //corefTree.setShowsRootHandles(false);
0235     corefTree.addMouseListener(new CorefTreeMouseListener());
0236     corefTree.setCellRenderer(new CorefTreeCellRenderer());
0237 
0238     mainPanel.add(topPanel, BorderLayout.NORTH);
0239     mainPanel.add(new JScrollPane(corefTree), BorderLayout.CENTER);
0240     topPanel.add(subPanel, BorderLayout.CENTER);
0241     topPanel.add(tempPanel, BorderLayout.SOUTH);
0242 
0243     // get the highlighter
0244     textPaneMouseListener = new TextPaneMouseListener();
0245     annotSets.setSelectedIndex(0);
0246 
0247     // finally show the tree
0248     //annotSetSelectionChanged();
0249 
0250     document.addDocumentListener(this);
0251     document.getFeatures().addFeatureMapListener(this);
0252   }
0253 
0254   public void reinitAllVariables() {
0255 
0256     if (highlightedChainAnnots != null)
0257       highlightedChainAnnots.clear();
0258     if (highlightedTypeAnnots != null)
0259       highlightedTypeAnnots.clear();
0260     if (typeSpecificHighlightedTags != null)
0261       typeSpecificHighlightedTags.clear();
0262     highlightedChainAnnotsOffsets = null;
0263     highlightedTypeAnnotsOffsets = null;
0264     if (highlightedTags != null && highlightedTags.values() != null) {
0265       Iterator<List<Object>> highlightsIter = highlightedTags.values().iterator();
0266       while (highlightsIter.hasNext()) {
0267         List<Object> tags = highlightsIter.next();
0268         for (int i = 0; i < tags.size(); i++) {
0269           highlighter.removeHighlight(tags.get(i));
0270         }
0271       }
0272       highlightedTags.clear();
0273     }
0274 
0275     // we need to find out all the annotSetNodes and remove all the chainNodes
0276     // under it
0277     Iterator<String> annotSetsIter = corefAnnotationSetNodesMap.keySet().iterator();
0278     while (annotSetsIter.hasNext()) {
0279       CorefTreeNode annotSetNode = corefAnnotationSetNodesMap.get(annotSetsIter.next());
0280       annotSetNode.removeAllChildren();
0281       colorChainsMap.put(annotSetNode.toString()new HashMap<String,Color>());
0282       selectionChainsMap.put(annotSetNode.toString()new HashMap<String,Boolean>());
0283       corefChains.put(annotSetNode, new HashMap<CorefTreeNode, List<Integer>>());
0284     }
0285   }
0286 
0287       /** This methods cleans up the memory by removing all listener registrations */
0288   @Override
0289   public void cleanup() {
0290     document.removeDocumentListener(this);
0291     document.getFeatures().removeFeatureMapListener(this);
0292   }
0293 
0294   /** Given arrayList containing Ids of the annotations, and an annotationSet, this method
0295    * returns the annotations that has longest string among the matches
0296    */
0297   public Annotation findOutTheLongestAnnotation(List<Integer> matches,
0298                                                 AnnotationSet set) {
0299     if (matches == null || matches.size() == 0) {
0300       return null;
0301     }
0302     int length = 0;
0303     int index = 0;
0304     for (int i = 0; i < matches.size(); i++) {
0305       Annotation currAnn = set.get(matches.get(i));
0306       int start = currAnn.getStartNode().getOffset().intValue();
0307       int end = currAnn.getEndNode().getOffset().intValue();
0308       if ( (end - start> length) {
0309         length = end - start;
0310         index = i;
0311       }
0312     }
0313     // so now we now have the longest String annotations at index
0314     return set.get(matches.get(index));
0315   }
0316 
0317   /**
0318    * This method is called when any annotationSet is removed outside the
0319    * co-reference editor..
0320    @param de
0321    */
0322   @Override
0323   public void annotationSetRemoved(gate.event.DocumentEvent de) {
0324     // this method removes the annotationSet from the annotSets
0325     // and all chainNodes under it
0326 
0327     String annotSet = de.getAnnotationSetName();
0328     annotSet = (annotSet == null? DEFAULT_ANNOTSET_NAME : annotSet;
0329     // find out the currently Selected annotationSetName
0330     String annotSetName = (StringannotSets.getSelectedItem();
0331     // remove it from the main data store
0332     corefChains.remove(corefAnnotationSetNodesMap.get(annotSet));
0333     // remove it from the main data store
0334     corefAnnotationSetNodesMap.remove(annotSet);
0335     // remove it from the annotationSetModel (combobox)
0336     annotSetsModel.removeElement(annotSet);
0337     annotSets.setModel(annotSetsModel);
0338     // remove it from the colorChainMap
0339     colorChainsMap.remove(annotSet);
0340     // remove it from the selectionChainMap
0341     selectionChainsMap.remove(annotSet);
0342     if (annotSetsModel.getSize() == 0) {
0343       // no annotationSet to display
0344       // so set visible false
0345       if (popupWindow != null && popupWindow.isVisible()) {
0346         popupWindow.setVisible(false);
0347       }
0348       corefTree.setVisible(false);
0349     }
0350     else {
0351       if (annotSetName.equals(annotSet)) {
0352         if (popupWindow != null && popupWindow.isVisible()) {
0353           popupWindow.setVisible(false);
0354         }
0355         if (!corefTree.isVisible())
0356           corefTree.setVisible(true);
0357 
0358         annotSets.setSelectedIndex(0);
0359         //annotSetSelectionChanged();
0360       }
0361     }
0362   }
0363 
0364   /**
0365    * This method is called when any new annotationSet is added
0366    @param de
0367    */
0368   @Override
0369   public void annotationSetAdded(gate.event.DocumentEvent de) {
0370 
0371     String annotSet = de.getAnnotationSetName();
0372     if(annotSet == null)
0373       document.getAnnotations().addAnnotationSetListener(this);
0374     else
0375       document.getAnnotations(annotSet).addAnnotationSetListener(this);
0376 
0377     annotSet = (annotSet == null? DEFAULT_ANNOTSET_NAME : annotSet;
0378     // find out the currently Selected annotationSetName
0379     String annotSetName = (StringannotSets.getSelectedItem();
0380 
0381     // check if newly added annotationSet is the default AnnotationSet
0382     CorefTreeNode annotSetNode = null;
0383 
0384     if (annotSet.equals(DEFAULT_ANNOTSET_NAME))
0385       annotSetNode = createAnnotSetNode(document.getAnnotations()true);
0386     else
0387       annotSetNode = createAnnotSetNode(document.getAnnotations(annotSet)false);
0388 
0389     corefAnnotationSetNodesMap.put(annotSet, annotSetNode);
0390     /*annotSetsModel.addElement(annotSet);
0391     annotSets.setModel(annotSetsModel);*/
0392 
0393     if (annotSetName != null)
0394       annotSets.setSelectedItem(annotSetName);
0395     else
0396       annotSets.setSelectedIndex(0);
0397 
0398       //annotSetSelectionChanged();
0399   }
0400 
0401   /**Called when the content of the document has changed through an edit
0402    * operation.
0403    */
0404   @Override
0405   public void contentEdited(gate.event.DocumentEvent e) {
0406     //ignore
0407   }
0408 
0409   @Override
0410   public void annotationAdded(AnnotationSetEvent ase) {
0411     // ignore
0412   }
0413 
0414   @Override
0415   public void annotationRemoved(AnnotationSetEvent ase) {
0416     Annotation delAnnot = ase.getAnnotation();
0417     Integer id = delAnnot.getId();
0418     Object matchesMapObject = document.getFeatures().get(ANNIEConstants.DOCUMENT_COREF_FEATURE_NAME);
0419     
0420     if(matchesMapObject == null)
0421       return;
0422     
0423     if(!(matchesMapObject instanceof Map)) {
0424       // no need to do anything
0425       // and return
0426       return;
0427     }
0428 
0429     @SuppressWarnings("unchecked")
0430     Map<String, List<List<Integer>>> matchesMap = (Map<String, List<List<Integer>>>matchesMapObject;
0431 
0432     Set<String> keySet = matchesMap.keySet();
0433     if(keySet == null)
0434       return;
0435 
0436     Iterator<String> iter = keySet.iterator();
0437     boolean found = false;
0438     while(iter.hasNext()) {
0439       String currSet = iter.next();
0440       List<List<Integer>> matches = matchesMap.get(currSet);
0441       if(matches == null || matches.size() == 0)
0442         continue;
0443       else {
0444         for(int i=0;i<matches.size();i++) {
0445           List<Integer> ids = matches.get(i);
0446           if(ids.contains(id)) {
0447             // found
0448             // so remove this
0449             found = true;
0450             ids.remove(id);
0451             matches.set(i, ids);
0452             break;
0453           }
0454         }
0455         if(found) {
0456           matchesMap.put(currSet, matches);
0457           explicitCall = true;
0458           document.getFeatures().put(ANNIEConstants.DOCUMENT_COREF_FEATURE_NAME,
0459                                      matchesMap);
0460           explicitCall = false;
0461           break;
0462         }
0463       }
0464     }
0465     if(found)
0466       featureMapUpdated();
0467   }
0468 
0469   /**
0470    * Called when features are changed outside the co-refEditor
0471    */
0472   @Override
0473   public void featureMapUpdated() {
0474 
0475     if (explicitCall)
0476       return;
0477 
0478     // we would first save the current settings
0479     // 1. Current AnnotSet
0480     // 2. Current AnnotType
0481     // 3. ShowAnnotation Status
0482     String currentAnnotSet = (StringannotSets.getSelectedItem();
0483     String currentAnnotType = (StringannotTypes.getSelectedItem();
0484     boolean currentShowAnnotationStatus = showAnnotations.isSelected();
0485 
0486     // there is some change in the featureMap
0487     Object matchesMapObject = document.getFeatures().get(ANNIEConstants.DOCUMENT_COREF_FEATURE_NAME);
0488     if(matchesMapObject == null || !(matchesMapObject instanceof Map)) {
0489       // no need to do anything
0490       // and return
0491       reinitAllVariables();
0492       explicitCall = false;
0493       
0494       SwingUtilities.invokeLater(new Runnable(){
0495         @Override
0496         public void run() {
0497           // not sure why this is necessary but if we are going to do
0498           // it then at least do it on the EDT to avoid a violation
0499           annotSets.setSelectedIndex(0);          
0500         }
0501       });
0502       
0503       return;
0504     }
0505 
0506     @SuppressWarnings("unchecked")
0507     Map<String, List<List<Integer>>> matchesMap = (Map<String, List<List<Integer>>>matchesMapObject;
0508 
0509     //AnnotationSetName --> List of ArrayLists
0510     //each ArrayList contains Ids of related annotations
0511     Iterator<String> setIter = matchesMap.keySet().iterator();
0512     HashMap<Object, Boolean> annotSetsNamesMap = new HashMap<Object, Boolean>();
0513     for (int i = 0; i < annotSets.getItemCount(); i++) {
0514       annotSetsNamesMap.putannotSets.getItemAt(i)new Boolean(false));
0515     }
0516     outer:while (setIter.hasNext()) {
0517       String currentSet = setIter.next();
0518       List<List<Integer>> matches = matchesMap.get(currentSet);
0519       currentSet = (currentSet == null? DEFAULT_ANNOTSET_NAME : currentSet;
0520 
0521       if (matches == null)
0522         continue;
0523 
0524       AnnotationSet currAnnotSet = getAnnotationSet(currentSet);
0525       annotSetsNamesMap.put(currentSet, new Boolean(true));
0526 
0527       Iterator<List<Integer>> entitiesIter = matches.iterator();
0528       //each entity is a list of annotation IDs
0529 
0530       if (corefAnnotationSetNodesMap.get(currentSet== null) {
0531         // we need to create the node for this
0532         if (currentSet.equals(DEFAULT_ANNOTSET_NAME)) {
0533           corefAnnotationSetNodesMap.put(DEFAULT_ANNOTSET_NAME,
0534                                          createChain(document.getAnnotations()true));
0535         }
0536         else {
0537           corefAnnotationSetNodesMap.put(currentSet,
0538                                          createChain(document.getAnnotations(
0539               currentSet)false));
0540         }
0541         continue outer;
0542       }
0543 
0544       Map<CorefTreeNode, List<Integer>> chains = corefChains.get(corefAnnotationSetNodesMap.get(currentSet));
0545       Map<CorefTreeNode, Boolean> visitedList = new HashMap<CorefTreeNode, Boolean>();
0546 
0547       if (chains != null) {
0548         Iterator<CorefTreeNode> chainsList = chains.keySet().iterator();
0549 
0550         // intially no chainHead is visited
0551         while (chainsList.hasNext()) {
0552           visitedList.putchainsList.next()new Boolean(false));
0553         }
0554 
0555         // now we need to search for the chainHead of each group
0556         List<List<Integer>> idsToRemove = new ArrayList<List<Integer>>();
0557         while (entitiesIter.hasNext()) {
0558           List<Integer> ids = entitiesIter.next();
0559           if (ids == null || ids.size() == 0) {
0560             idsToRemove.add(ids);
0561             continue;
0562           }
0563 
0564           CorefTreeNode chainHead = null;
0565           for (int i = 0; i < ids.size(); i++) {
0566             Integer id = ids.get(i);
0567             // now lets find out the headnode for this, if it is available
0568             chainHead = findOutTheChainHead(currAnnotSet.get(id), currentSet);
0569             if (chainHead != null) {
0570               visitedList.put(chainHead, new Boolean(true));
0571               break;
0572             }
0573           }
0574 
0575           if (chainHead != null) {
0576             // we found the chainHead for this
0577             // so we would replace the ids
0578             // but before that we would check if chainHead should be replaced
0579             Annotation longestAnn = findOutTheLongestAnnotation(ids, getAnnotationSet(currentSet));
0580             if (getString(longestAnn).equals(chainHead.toString())) {
0581               chains.put(chainHead, ids);
0582               corefChains.put(corefAnnotationSetNodesMap.get(currentSet),
0583                               chains);
0584             }
0585             else {
0586               // we first check if new longestAnnotation String is already available as some other chain Node head
0587               if (currentColors.containsKey(getString(longestAnn))) {
0588                 // yes one chainHead with this string already exists
0589                 // so we need to merge them together
0590                 String longestString = getString(longestAnn);
0591                 CorefTreeNode tempChainHead = findOutChainNode(longestString, currentSet);
0592                 // now all the ids under current chainHead should be placed under the tempChainHead
0593                 List<Integer> tempIds = chains.get(tempChainHead);
0594                 List<Integer> currentChainHeadIds = chains.get(chainHead);
0595                 // so lets merge them
0596                 tempIds.addAll(currentChainHeadIds);
0597 
0598                 // and update the chains
0599                 chains.remove(chainHead);
0600                 chains.put(tempChainHead, tempIds);
0601                 corefChains.put(corefAnnotationSetNodesMap.get(currentSet),
0602                                 chains);
0603                 visitedList.put(chainHead, new Boolean(false));
0604                 visitedList.put(tempChainHead, new Boolean(true));
0605 
0606               }
0607               else {
0608                 String previousString = chainHead.toString();
0609                 String newString = getString(longestAnn);
0610                 chainHead.setUserObject(newString);
0611 
0612                 // we need to change the colors
0613                 Color color = currentColors.get(previousString);
0614                 currentColors.remove(previousString);
0615                 currentColors.put(newString, color);
0616                 colorChainsMap.put(newString, currentColors);
0617 
0618                 // we need to change the selections
0619                 Boolean val = currentSelections.get(previousString);
0620                 currentSelections.remove(previousString);
0621                 currentSelections.put(newString, val);
0622                 selectionChainsMap.put(newString, currentSelections);
0623 
0624                 chains.put(chainHead, ids);
0625                 corefChains.put(corefAnnotationSetNodesMap.get(currentSet),
0626                                 chains);
0627               }
0628             }
0629           }
0630           else {
0631             // this is something new addition
0632             // so we need to create a new chainNode
0633             // this is the new chain
0634             // get the current annotSetNode
0635             CorefTreeNode annotSetNode = corefAnnotationSetNodesMap.get(currentSet);
0636 
0637             // we need to find out the longest string annotation
0638             @SuppressWarnings("unused")
0639             AnnotationSet actSet = getAnnotationSet(currentSet);
0640 
0641             Annotation ann = findOutTheLongestAnnotation(ids, getAnnotationSet(currentSet));
0642             // so before creating a new chainNode we need to find out if
0643             // any of the chainNodes has the same string that of this chainNode
0644             HashMap<String, Boolean> tempSelection = (HashMap<String, Boolean>selectionChainsMap.get(
0645                 currentSet);
0646             CorefTreeNode chainNode = null;
0647             if (tempSelection.containsKey(getString(ann))) {
0648               chainNode = findOutChainNode(getString(ann), currentSet);
0649 
0650               // ArrayList matches
0651               Map<CorefTreeNode,List<Integer>> newHashMap = corefChains.get(annotSetNode);
0652               newHashMap.put(chainNode, ids);
0653               corefChains.put(annotSetNode, newHashMap);
0654 
0655               visitedList.put(chainNode, new Boolean(true));
0656             }
0657             else {
0658               // create the new chainNode
0659               chainNode = new CorefTreeNode(getString(ann), false,
0660                                             CorefTreeNode.CHAIN_NODE);
0661 
0662               // add this to tree
0663               annotSetNode.add(chainNode);
0664               corefAnnotationSetNodesMap.put(currentSet, annotSetNode);
0665 
0666               // ArrayList matches
0667               Map<CorefTreeNode, List<Integer>> newHashMap = corefChains.get(annotSetNode);
0668               newHashMap.put(chainNode, ids);
0669               corefChains.put(annotSetNode, newHashMap);
0670 
0671               boolean selectionValue = false;
0672               if(currentAnnotSet.equals(currentSet))
0673                 selectionValue = true;
0674 
0675               // entry into the selection
0676               tempSelection.put(chainNode.toString()new Boolean(selectionValue));
0677               selectionChainsMap.put(currentSet, tempSelection);
0678 
0679               // entry into the colors
0680               float components[] = colorGenerator.getNextColor().getComponents(null);
0681               Color color = new Color(components[0],
0682                                       components[1],
0683                                       components[2],
0684                                       0.5f);
0685               Map<String,Color> tempColors = colorChainsMap.get(currentSet);
0686               tempColors.put(chainNode.toString(), color);
0687               colorChainsMap.put(annotSets.getSelectedItem().toString(), tempColors);
0688             }
0689           }
0690         }
0691 
0692         // ok we need to remove Idsnow
0693         Iterator<List<Integer>> removeIter = idsToRemove.iterator();
0694         while (removeIter.hasNext()) {
0695           explicitCall = true;
0696           List<Integer> ids = removeIter.next();
0697           matches.remove(ids);
0698           String set = currentSet.equals(DEFAULT_ANNOTSET_NAMEnull :
0699                        currentSet;
0700           matchesMap.put(set, matches);
0701           explicitCall = false;
0702         }
0703         explicitCall = true;
0704         document.getFeatures().put(ANNIEConstants.DOCUMENT_COREF_FEATURE_NAME,
0705                                    matchesMap);
0706         explicitCall = false;
0707 
0708         // here we need to find out the chainNodes those are no longer needed
0709         Iterator<CorefTreeNode> visitedListIter = visitedList.keySet().iterator();
0710         while (visitedListIter.hasNext()) {
0711           CorefTreeNode chainNode = visitedListIter.next();
0712           if (! visitedList.get(chainNode).booleanValue()) {
0713             // yes this should be deleted
0714             CorefTreeNode annotSetNode = corefAnnotationSetNodesMap.get(currentSet);
0715 
0716             // remove from the tree
0717             annotSetNode.remove(chainNode);
0718             corefAnnotationSetNodesMap.put(currentSet, annotSetNode);
0719 
0720             // ArrayList matches
0721             Map<CorefTreeNode, List<Integer>> newHashMap = corefChains.get(annotSetNode);
0722             newHashMap.remove(chainNode);
0723             corefChains.put(annotSetNode, newHashMap);
0724 
0725             // remove from the selections
0726             Map<String,Boolean> tempSelection = selectionChainsMap.get(
0727                 currentSet);
0728             tempSelection.remove(chainNode.toString());
0729             selectionChainsMap.put(currentSet, tempSelection);
0730 
0731             // remove from the colors
0732             Map<String,Color> tempColors = colorChainsMap.get(currentSet);
0733             tempColors.remove(chainNode.toString());
0734             colorChainsMap.put(currentSet, currentColors);
0735           }
0736         }
0737       }
0738     }
0739 
0740     Iterator<Object> tempIter = annotSetsNamesMap.keySet().iterator();
0741     while (tempIter.hasNext()) {
0742       String currentSet = (StringtempIter.next();
0743       if (! annotSetsNamesMap.get(currentSet).booleanValue()) {
0744         String annotSet = currentSet;
0745 
0746         // find out the currently Selected annotationSetName
0747         @SuppressWarnings("unused")
0748         String annotSetName = (StringannotSets.getSelectedItem();
0749         
0750         // remove it from the main data store
0751         corefChains.remove(corefAnnotationSetNodesMap.get(annotSet));
0752         // remove it from the main data store
0753         corefAnnotationSetNodesMap.remove(annotSet);
0754         // remove it from the annotationSetModel (combobox)
0755         annotSetsModel.removeElement(annotSet);
0756         annotSets.setModel(annotSetsModel);
0757         annotSets.updateUI();
0758         // remove it from the colorChainMap
0759         colorChainsMap.remove(annotSet);
0760         // remove it from the selectionChainMap
0761         selectionChainsMap.remove(annotSet);
0762       }
0763     }
0764 
0765     if (annotSetsModel.getSize() == 0) {
0766       // no annotationSet to display
0767       // so set visible false
0768       if (popupWindow != null && popupWindow.isVisible()) {
0769         popupWindow.setVisible(false);
0770       }
0771       corefTree.setVisible(false);
0772 
0773       // remove all highlights
0774       List<Object> allHighlights = new ArrayList<Object>();
0775       if(typeSpecificHighlightedTags != null)
0776         allHighlights.addAll(typeSpecificHighlightedTags);
0777       if(highlightedTags != null) {
0778         Iterator<List<Object>> iter = highlightedTags.values().iterator();
0779         while(iter.hasNext()) {
0780           List<Object> highlights = iter.next();
0781           allHighlights.addAll(highlights);
0782         }
0783       }
0784       for(int i=0;i<allHighlights.size();i++) {
0785         highlighter.removeHighlight(allHighlights.get(i));
0786       }
0787 
0788       //highlighter.removeAllHighlights();
0789       highlightedTags = null;
0790       typeSpecificHighlightedTags = null;
0791       return;
0792     }
0793     else {
0794 
0795       if (popupWindow != null && popupWindow.isVisible()) {
0796         popupWindow.setVisible(false);
0797       }
0798 
0799       // remove all highlights
0800       List<Object> allHighlights = new ArrayList<Object>();
0801       if(typeSpecificHighlightedTags != null)
0802         allHighlights.addAll(typeSpecificHighlightedTags);
0803       if(highlightedTags != null) {
0804         Iterator<List<Object>> iter = highlightedTags.values().iterator();
0805         while(iter.hasNext()) {
0806           List<Object> highlights = iter.next();
0807           allHighlights.addAll(highlights);
0808         }
0809       }
0810       for (int i = 0; i < allHighlights.size(); i++) {
0811         highlighter.removeHighlight(allHighlights.get(i));
0812       }
0813 
0814       //highlighter.removeAllHighlights();
0815       highlightedTags = null;
0816       typeSpecificHighlightedTags = null;
0817       if (currentAnnotSet != null) {
0818         annotSets.setSelectedItem(currentAnnotSet);
0819         currentSelections = selectionChainsMap.get(currentAnnotSet);
0820         currentColors = colorChainsMap.get(currentAnnotSet);
0821         highlightAnnotations();
0822 
0823         showAnnotations.setSelected(currentShowAnnotationStatus);
0824         if (currentAnnotType != null)
0825           annotTypes.setSelectedItem(currentAnnotType);
0826         else
0827         if (annotTypes.getModel().getSize() 0) {
0828           annotTypes.setSelectedIndex(0);
0829         }
0830       }
0831       else {
0832         explicitCall = false;
0833         annotSets.setSelectedIndex(0);
0834       }
0835     }
0836   }
0837 
0838   /**
0839    * ActionPerformed Activity
0840    @param ae
0841    */
0842   @Override
0843   public void actionPerformed(ActionEvent ae) {
0844     // when annotationSet value changes
0845     if (ae.getSource() == annotSets) {
0846       if (!explicitCall) {
0847         annotSetSelectionChanged();
0848       }
0849     }
0850     else if (ae.getSource() == showAnnotations) {
0851       if (!explicitCall) {
0852         showTypeWiseAnnotations();
0853       }
0854     }
0855     else if (ae.getSource() == annotTypes) {
0856       if (!explicitCall) {
0857         if (typeSpecificHighlightedTags != null) {
0858           for (int i = 0; i < typeSpecificHighlightedTags.size(); i++) {
0859             highlighter.removeHighlight(typeSpecificHighlightedTags.get(i));
0860           }
0861         }
0862         typeSpecificHighlightedTags = null;
0863         showTypeWiseAnnotations();
0864       }
0865     }
0866   }
0867 
0868   /**
0869    * When user preses the show Toggle button, this will show up annotations
0870    * of selected Type from selected AnnotationSet
0871    */
0872   private void showTypeWiseAnnotations() {
0873     if (typeSpecificHighlightedTags == null) {
0874       highlightedTypeAnnots = new ArrayList<Annotation>();
0875       typeSpecificHighlightedTags = new ArrayList<Object>();
0876     }
0877 
0878     if (showAnnotations.isSelected()) {
0879       // get the annotationsSet and its type
0880       AnnotationSet set = getAnnotationSet( (StringannotSets.getSelectedItem());
0881       String type = (StringannotTypes.getSelectedItem();
0882       if (type == null) {
0883         try {
0884           JOptionPane.showMessageDialog(MainFrame.getInstance(),
0885                                         "No annotation type found to display");
0886         }
0887         catch (Exception e) {
0888           e.printStackTrace();
0889         }
0890         showAnnotations.setSelected(false);
0891         return;
0892       }
0893 
0894       Color color = AnnotationSetsView.getColor(getAnnotationSet((String)annotSets.getSelectedItem()).getName(),type);
0895       if (type != null) {
0896         AnnotationSet typeSet = set.get(type);
0897         Iterator<Annotation> iter = typeSet.iterator();
0898         while (iter.hasNext()) {
0899           Annotation ann = iter.next();
0900           highlightedTypeAnnots.add(ann);
0901           try {
0902             typeSpecificHighlightedTags.add(highlighter.addHighlight(ann.
0903                 getStartNode().
0904                 getOffset().intValue(),
0905                 ann.getEndNode().getOffset().intValue(),
0906                 new DefaultHighlighter.
0907                 DefaultHighlightPainter(color)));
0908           }
0909           catch (Exception e) {
0910             e.printStackTrace();
0911           }
0912           //typeSpecificHighlightedTags.add(textView.addHighlight(ann, getAnnotationSet((String)annotSets.getSelectedItem()),color));
0913         }
0914       }
0915     }
0916     else {
0917       for (int i = 0; i < typeSpecificHighlightedTags.size(); i++) {
0918         //textView.removeHighlight(typeSpecificHighlightedTags.get(i));
0919         highlighter.removeHighlight(typeSpecificHighlightedTags.get(i));
0920       }
0921       typeSpecificHighlightedTags = new ArrayList<Object>();
0922       highlightedTypeAnnots = new ArrayList<Annotation>();
0923       highlightedTypeAnnotsOffsets = null;
0924     }
0925 
0926     // This is to make process faster.. instead of accessing each annotation and
0927     // its offset, we create an array with its annotation offsets to search faster
0928     Collections.sort(highlightedTypeAnnots, new gate.util.OffsetComparator());
0929     highlightedTypeAnnotsOffsets = new int[highlightedTypeAnnots.size() 2];
0930     for (int i = 0, j = 0; j < highlightedTypeAnnots.size(); i += 2, j++) {
0931       Annotation ann1 = highlightedTypeAnnots.get(j);
0932       highlightedTypeAnnotsOffsets[i= ann1.getStartNode().getOffset().
0933                                         intValue();
0934       highlightedTypeAnnotsOffsets[i +
0935           1= ann1.getEndNode().getOffset().intValue();
0936     }
0937 
0938   }
0939 
0940   /**
0941    * Returns annotation Set
0942    */
0943   private AnnotationSet getAnnotationSet(String annotSet) {
0944     return (annotSet.equals(DEFAULT_ANNOTSET_NAME)) ? document.getAnnotations() :
0945         document.getAnnotations(annotSet);
0946   }
0947 
0948   /**
0949    * When annotationSet selection changes
0950    */
0951   private void annotSetSelectionChanged() {
0952     if (annotSets.getModel().getSize() == 0) {
0953       if (popupWindow != null && popupWindow.isVisible()) {
0954         popupWindow.setVisible(false);
0955       }
0956       corefTree.setVisible(false);
0957       return;
0958     }
0959 
0960     System.out.println("calling from here");
0961     
0962     final String currentAnnotSet =
0963             annotSets.getSelectedItem() != null (String)annotSets
0964                     .getSelectedItem() : annotSets.getItemAt(0);
0965                     
0966     // get all the types of the currently Selected AnnotationSet
0967     AnnotationSet temp = getAnnotationSet(currentAnnotSet);
0968     Set<String> types = temp.getAllTypes();
0969     annotTypesModel = new DefaultComboBoxModel<String>();
0970     if (types != null) {
0971       annotTypesModel = new DefaultComboBoxModel<String>(types.toArray(new String[types.size()]));
0972     }
0973     
0974     SwingUtilities.invokeLater(new Runnable() {
0975       
0976       @Override
0977       public void run() {
0978         annotTypes.setModel(annotTypesModel);
0979         annotTypes.updateUI();
0980 
0981         // and redraw the CorefTree
0982         if (rootNode.getChildCount() 0)
0983           rootNode.removeAllChildren();
0984 
0985         CorefTreeNode annotSetNode = corefAnnotationSetNodesMap.get(currentAnnotSet);
0986 
0987         if (annotSetNode != null) {
0988           rootNode.add(annotSetNode);
0989           currentSelections = selectionChainsMap.get(currentAnnotSet);
0990           currentColors = colorChainsMap.get(currentAnnotSet);
0991           if (!corefTree.isVisible()) {
0992             if (popupWindow != null && popupWindow.isVisible()) {
0993               popupWindow.setVisible(false);
0994             }
0995             corefTree.setVisible(true);
0996           }
0997           corefTree.repaint();
0998           corefTree.updateUI();
0999 
1000         }
1001         else {
1002           corefTree.setVisible(false);
1003         }
1004     
1005       }
1006     });
1007   }
1008 
1009   /**
1010    * This will initialise the data
1011    */
1012   private void initData() {
1013 
1014     rootNode = new CorefTreeNode("Co-reference Data", true,
1015                                  CorefTreeNode.ROOT_NODE);
1016     corefChains = new HashMap<CorefTreeNode, Map<CorefTreeNode, List<Integer>>>();
1017     selectionChainsMap = new HashMap<String, Map<String,Boolean>>();
1018     currentSelections = new HashMap<String, Boolean>();
1019     colorChainsMap = new HashMap<String, Map<String,Color>>();
1020     currentColors = new HashMap<String, Color>();
1021     corefAnnotationSetNodesMap = new HashMap<String, CorefTreeNode>();
1022 
1023     // now we need to findout the chains
1024     // for the defaultAnnotationSet
1025     CorefTreeNode annotSetNode = createChain(document.getAnnotations()true);
1026     if (annotSetNode != null) {
1027       corefAnnotationSetNodesMap.put(DEFAULT_ANNOTSET_NAME, annotSetNode);
1028     }
1029 
1030     // and for the rest AnnotationSets
1031     Map<String,AnnotationSet> annotSets = document.getNamedAnnotationSets();
1032     if (annotSets != null) {
1033       Iterator<String> annotSetsIter = annotSets.keySet().iterator();
1034       while (annotSetsIter.hasNext()) {
1035         String annotSetName = annotSetsIter.next();
1036         annotSetNode = createChain(document.getAnnotations(annotSetName)false);
1037         if (annotSetNode != null) {
1038           corefAnnotationSetNodesMap.put(annotSetName, annotSetNode);
1039         }
1040       }
1041     }
1042   }
1043 
1044   private CorefTreeNode createAnnotSetNode(AnnotationSet set, boolean isDefaultSet) {
1045     // create the node for setName
1046     String setName = isDefaultSet ? DEFAULT_ANNOTSET_NAME : set.getName();
1047     CorefTreeNode annotSetNode = new CorefTreeNode(setName, true,
1048         CorefTreeNode.ANNOTSET_NODE);
1049 
1050     // see if this setName available in the annotSets
1051     boolean found = false;
1052     for (int i = 0; i < annotSets.getModel().getSize(); i++) {
1053       if annotSets.getModel().getElementAt(i).equals(setName)) {
1054         found = true;
1055         break;
1056       }
1057     }
1058     if (!found) {
1059       explicitCall = true;
1060       annotSets.addItem(setName);
1061       explicitCall = false;
1062     }
1063 
1064     // the internal datastructure
1065     Map<CorefTreeNode,List<Integer>> chainLinks = new HashMap<CorefTreeNode, List<Integer>>();
1066     Map<String,Boolean> selectionMap = new HashMap<String,Boolean>();
1067     Map<String,Color> colorMap = new HashMap<String,Color>();
1068 
1069     corefChains.put(annotSetNode, chainLinks);
1070     selectionChainsMap.put(setName, selectionMap);
1071     colorChainsMap.put(setName, colorMap);
1072     return annotSetNode;
1073 
1074   }
1075 
1076   /**
1077    * Creates the internal data structure
1078    @param set
1079    */
1080   @SuppressWarnings("unchecked")
1081   private CorefTreeNode createChain(AnnotationSet set, boolean isDefaultSet) {
1082 
1083     // create the node for setName
1084     String setName = isDefaultSet ? DEFAULT_ANNOTSET_NAME : set.getName();
1085     CorefTreeNode annotSetNode = new CorefTreeNode(setName, true,
1086         CorefTreeNode.ANNOTSET_NODE);
1087 
1088     // see if this setName available in the annotSets
1089     boolean found = false;
1090     for (int i = 0; i < annotSets.getModel().getSize(); i++) {
1091       if annotSets.getModel().getElementAt(i).equals(setName)) {
1092         found = true;
1093         break;
1094       }
1095     }
1096     if (!found) {
1097       explicitCall = true;
1098       annotSets.addItem(setName);
1099       explicitCall = false;
1100     }
1101 
1102     // the internal datastructure
1103     Map<CorefTreeNode, List<Integer>> chainLinks = new HashMap<CorefTreeNode, List<Integer>>();
1104     Map<String, Boolean> selectionMap = new HashMap<String, Boolean>();
1105     Map<String, Color> colorMap = new HashMap<String, Color>();
1106 
1107     // map for all the annotations with matches feature in it
1108     Map<String,List<List<Integer>>> matchesMap = null;
1109     Object matchesMapObject = document.getFeatures().get(ANNIEConstants.DOCUMENT_COREF_FEATURE_NAME);
1110     if(matchesMapObject instanceof Map) {
1111       matchesMap = (Map<String,List<List<Integer>>>matchesMapObject;
1112     }
1113 
1114 
1115     // what if this map is null
1116     if (matchesMap == null) {
1117       corefChains.put(annotSetNode, chainLinks);
1118       selectionChainsMap.put(setName, selectionMap);
1119       colorChainsMap.put(setName, colorMap);
1120       return annotSetNode;
1121     }
1122 
1123     //AnnotationSetName --> List of ArrayLists
1124     //each ArrayList contains Ids of related annotations
1125     List<List<Integer>> matches1 = matchesMap.get(isDefaultSet ? null :
1126         setName);
1127     if (matches1 == null) {
1128       corefChains.put(annotSetNode, chainLinks);
1129       selectionChainsMap.put(setName, selectionMap);
1130       colorChainsMap.put(setName, colorMap);
1131       return annotSetNode;
1132     }
1133 
1134     Iterator<List<Integer>> tempIter = matches1.iterator();
1135 
1136     while (tempIter.hasNext()) {
1137       List<Integer> matches = tempIter.next();
1138       if (matches == null)
1139         matches = new ArrayList<Integer>();
1140 
1141       if (matches.size() && set.size() 0) {
1142 
1143         String longestString = getString(findOutTheLongestAnnotation(matches,
1144             set));
1145         // so this should become one of the tree node
1146         CorefTreeNode chainNode = new CorefTreeNode(longestString, false,
1147             CorefTreeNode.CHAIN_NODE);
1148         // and add it under the topNode
1149         annotSetNode.add(chainNode);
1150 
1151         // chainNode --> All related annotIds
1152         chainLinks.put(chainNode, matches);
1153         selectionMap.put(chainNode.toString()new Boolean(false));
1154         // and generate the color for this chainNode
1155         float components[] = colorGenerator.getNextColor().getComponents(null);
1156         Color color = new Color(components[0],
1157                                 components[1],
1158                                 components[2],
1159                                 0.5f);
1160         colorMap.put(chainNode.toString(), color);
1161       }
1162     }
1163 
1164     corefChains.put(annotSetNode, chainLinks);
1165     selectionChainsMap.put(setName, selectionMap);
1166     colorChainsMap.put(setName, colorMap);
1167     return annotSetNode;
1168   }
1169 
1170   /**
1171    * Given an annotation, this method returns the string of that annotation
1172    */
1173   public String getString(Annotation ann) {
1174     return document.getContent().toString().substring(ann.
1175           getStartNode().getOffset().intValue(),
1176           ann.getEndNode().getOffset().intValue()
1177           ).replaceAll("\\r\\n|\\r|\\n"" ");
1178   }
1179 
1180   /**
1181    * Removes the reference of this annotation from the current chain.
1182    @param annot annotation to remove
1183    @param chainHead co-reference chain to modify
1184    */
1185   @SuppressWarnings("unchecked")
1186   public void removeChainReference(Annotation annot, CorefTreeNode chainHead) {
1187 
1188     // so we would find out the matches
1189     List<Integer> ids = corefChains.get(corefAnnotationSetNodesMap.get(
1190     annotSets.getSelectedItem())).get(chainHead);
1191 
1192    String currentSet = (StringannotSets.getSelectedItem();
1193    currentSet = (currentSet.equals(DEFAULT_ANNOTSET_NAME)) null : currentSet;
1194 
1195     // we need to update the Co-reference document feature
1196     Map<String, List<List<Integer>>> matchesMap = null;
1197     List<List<Integer>> matches = null;
1198     Object matchesMapObject = document.getFeatures().get(ANNIEConstants.DOCUMENT_COREF_FEATURE_NAME);
1199     if(matchesMapObject instanceof Map) {
1200       matchesMap = (Map<String, List<List<Integer>>>matchesMapObject;
1201       matches = matchesMap.get(currentSet);
1202     else {
1203       matchesMap = new HashMap<String, List<List<Integer>>>();
1204     }
1205 
1206     if (matches == null)
1207       matches = new ArrayList<List<Integer>>();
1208 
1209     int index = matches.indexOf(ids);
1210     if (index != -1) {
1211       // yes found
1212       ids.remove(annot.getId());
1213       
1214       //Annotation ann = findOutTheLongestAnnotation(ids,getAnnotationSet( (String) annotSets.getSelectedItem()));
1215 
1216       matches.set(index, ids);
1217       matchesMap.put(currentSet, matches);
1218       document.getFeatures().put(ANNIEConstants.DOCUMENT_COREF_FEATURE_NAME,
1219                                  matchesMap);
1220     }
1221   }
1222 
1223   /**
1224    * Given an annotation, this will find out the chainHead
1225    */
1226   private CorefTreeNode findOutTheChainHead(Annotation ann, String set) {
1227     Map<CorefTreeNode, List<Integer>> chains = corefChains.get(corefAnnotationSetNodesMap.get(
1228         set));
1229     if (chains == null)
1230       return null;
1231     Iterator<CorefTreeNode> iter = chains.keySet().iterator();
1232     while (iter.hasNext()) {
1233       CorefTreeNode head = iter.next();
1234       if (chains.get(head).contains(ann.getId())) {
1235         return head;
1236       }
1237     }
1238     return null;
1239   }
1240 
1241   /**
1242    * This methods highlights the annotations
1243    */
1244   public void highlightAnnotations() {
1245 
1246     if (highlightedTags == null) {
1247       highlightedTags = new HashMap<CorefTreeNode, List<Object>>();
1248       highlightedChainAnnots = new ArrayList<Annotation>();
1249     }
1250 
1251     AnnotationSet annotSet = getAnnotationSet( (StringannotSets.
1252                                               getSelectedItem());
1253     CorefTreeNode annotSetNode = corefAnnotationSetNodesMap.get(annotSets.getSelectedItem());
1254     if (annotSetNode == null) {
1255       return;
1256     }
1257     Map<CorefTreeNode,List<Integer>> chainMap = corefChains.get(annotSetNode);
1258     Iterator<CorefTreeNode> iter = chainMap.keySet().iterator();
1259 
1260     while (iter.hasNext()) {
1261       CorefTreeNode currentNode = iter.next();
1262       if (currentSelections.get(currentNode.toString()).
1263           booleanValue()) {
1264         if (!highlightedTags.containsKey(currentNode)) {
1265           // find out the arrayList
1266           List<Integer> ids = chainMap.get(currentNode);
1267           ArrayList<Object> highlighTag = new ArrayList<Object>();
1268           if (ids != null) {
1269             for (int i = 0; i < ids.size(); i++) {
1270               Annotation ann = annotSet.get(ids.get(i));
1271               highlightedChainAnnots.add(ann);
1272               Color color = currentColors.get(currentNode.toString());
1273               try {
1274                 highlighTag.add(highlighter.addHighlight(ann.getStartNode().
1275                     getOffset().intValue(),
1276                     ann.getEndNode().getOffset().intValue(),
1277                     new DefaultHighlighter.
1278                     DefaultHighlightPainter(color)));
1279               }
1280               catch (Exception e) {
1281                 e.printStackTrace();
1282               }
1283               //highlighTag.add(textView.addHighlight(ann, getAnnotationSet((String) annotSets.getSelectedItem()), color));
1284             }
1285             highlightedTags.put(currentNode, highlighTag);
1286           }
1287         }
1288       }
1289       else {
1290         if (highlightedTags.containsKey(currentNode)) {
1291           List<Object> highlights = highlightedTags.get(currentNode);
1292           for (int i = 0; i < highlights.size(); i++) {
1293             //textView.removeHighlight(highlights.get(i));
1294             highlighter.removeHighlight(highlights.get(i));
1295           }
1296           highlightedTags.remove(currentNode);
1297           List<Integer> ids = chainMap.get(currentNode);
1298           if (ids != null) {
1299             for (int i = 0; i < ids.size(); i++) {
1300               Annotation ann = annotSet.get(ids.get(i));
1301               highlightedChainAnnots.remove(ann);
1302             }
1303           }
1304         }
1305       }
1306     }
1307 
1308     // This is to make process faster.. instead of accessing each annotation and
1309     // its offset, we create an array with its annotation offsets to search faster
1310     Collections.sort(highlightedChainAnnots, new gate.util.OffsetComparator());
1311     highlightedChainAnnotsOffsets = new int[highlightedChainAnnots.size() 2];
1312     for (int i = 0, j = 0; j < highlightedChainAnnots.size(); i += 2, j++) {
1313       Annotation ann1 = highlightedChainAnnots.get(j);
1314       highlightedChainAnnotsOffsets[i= ann1.getStartNode().getOffset().
1315                                          intValue();
1316       highlightedChainAnnotsOffsets[i +
1317           1= ann1.getEndNode().getOffset().intValue();
1318     }
1319   }
1320 
1321   @Override
1322   protected void registerHooks() {
1323     textPane.addMouseListener(textPaneMouseListener);
1324     textPane.addMouseMotionListener(textPaneMouseListener);
1325 
1326   }
1327 
1328   @Override
1329   protected void unregisterHooks() {
1330     textPane.removeMouseListener(textPaneMouseListener);
1331     textPane.removeMouseMotionListener(textPaneMouseListener);
1332   }
1333 
1334   @Override
1335   public Component getGUI() {
1336     return mainPanel;
1337   }
1338 
1339   @Override
1340   public int getType() {
1341     return VERTICAL;
1342   }
1343 
1344   //**********************************************
1345    // MouseListener and MouseMotionListener Methods
1346    //***********************************************
1347 
1348     protected class TextPaneMouseListener
1349         extends MouseInputAdapter {
1350 
1351       public TextPaneMouseListener() {
1352         chainToolTipTimer.setRepeats(false);
1353         newCorefActionTimer.setRepeats(false);
1354       }
1355 
1356       @Override
1357       public void mouseMoved(MouseEvent me) {
1358         int textLocation = textPane.viewToModel(me.getPoint());
1359         chainToolTipAction.setTextLocation(textLocation);
1360         chainToolTipAction.setMousePointer(me.getPoint());
1361         chainToolTipTimer.restart();
1362 
1363         newCorefAction.setTextLocation(textLocation);
1364         newCorefAction.setMousePointer(me.getPoint());
1365         newCorefActionTimer.restart();
1366       }
1367     }
1368 
1369   public void mouseClicked(MouseEvent me) {
1370     if (popupWindow != null && popupWindow.isVisible()) {
1371       popupWindow.setVisible(false);
1372     }
1373   }
1374 
1375   public CorefTreeNode findOutChainNode(String chainNodeString, String set) {
1376     if (corefChains == null || corefAnnotationSetNodesMap == null) {
1377       return null;
1378     }
1379     Map<CorefTreeNode, List<Integer>> chains = corefChains.get(corefAnnotationSetNodesMap.get(set));
1380     if (chains == null) {
1381       return null;
1382     }
1383     Iterator<CorefTreeNode> iter = chains.keySet().iterator();
1384     while (iter.hasNext()) {
1385       CorefTreeNode currentNode = iter.next();
1386       if (currentNode.toString().equals(chainNodeString))
1387         return currentNode;
1388     }
1389     return null;
1390   }
1391 
1392   /**
1393    * When user hovers over the annotations which have been highlighted by
1394    * show button
1395    */
1396   protected class NewCorefAction
1397       implements ActionListener {
1398 
1399     int textLocation;
1400     Point mousePoint;
1401     JLabel label = new JLabel();
1402     JPanel panel = new JPanel();
1403     JPanel subPanel = new JPanel();
1404     String field = "";
1405     JButton add = new JButton("OK");
1406     JButton cancel = new JButton("Cancel");
1407     JComboBox<String> list = new JComboBox<String>();
1408     JPanel mainPanel = new JPanel();
1409     JPopupMenu popup1 = new JPopupMenu();
1410     ListEditor listEditor = null;
1411     ComboBoxModel<String> model = new DefaultComboBoxModel<String>();
1412     boolean firstTime = true;
1413 
1414     public NewCorefAction() {
1415       popupWindow = new JWindow(SwingUtilities.getWindowAncestor(textView.
1416           getGUI()));
1417       popupWindow.setBackground(UIManager.getLookAndFeelDefaults().
1418                                 getColor("ToolTip.background"));
1419       mainPanel.setLayout(new BorderLayout());
1420       mainPanel.setOpaque(true);
1421       mainPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
1422       mainPanel.setBackground(UIManager.getLookAndFeelDefaults().
1423                               getColor("ToolTip.background"));
1424       popupWindow.setContentPane(mainPanel);
1425 
1426       panel.setLayout(new BorderLayout());
1427       panel.setOpaque(false);
1428       panel.add(new JScrollPane(list), BorderLayout.CENTER);
1429 
1430       subPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
1431       subPanel.add(add);
1432       subPanel.add(cancel);
1433       subPanel.setOpaque(false);
1434       panel.add(subPanel, BorderLayout.SOUTH);
1435       mainPanel.add(label, BorderLayout.NORTH);
1436       mainPanel.add(panel, BorderLayout.CENTER);
1437 
1438       // and finally load the data for the list
1439       AddAction action = new AddAction();
1440       add.addActionListener(action);
1441       cancel.addActionListener(action);
1442       listEditor = new ListEditor(action);
1443       list.setMaximumRowCount(5);
1444       list.setEditable(true);
1445       list.setEditor(listEditor);
1446       list.setModel(model);
1447     }
1448 
1449     @Override
1450     public void actionPerformed(ActionEvent ae) {
1451       int index = -1;
1452       if (highlightedChainAnnotsOffsets != null) {
1453         for (int i = 0; i < highlightedChainAnnotsOffsets.length; i += 2) {
1454           if (textLocation >= highlightedChainAnnotsOffsets[i&&
1455               textLocation <= highlightedChainAnnotsOffsets[i + 1]) {
1456             index = (i == 0? i : i / 2;
1457             break;
1458           }
1459         }
1460       }
1461 
1462       // yes it is put on highlighted so show the annotationType
1463       if (highlightedChainAnnotsOffsets != null &&
1464           index < highlightedChainAnnotsOffsets.length && index >= 0) {
1465         return;
1466       }
1467 
1468       if (highlightedTypeAnnotsOffsets != null) {
1469         for (int i = 0; i < highlightedTypeAnnotsOffsets.length; i += 2) {
1470           if (textLocation >= highlightedTypeAnnotsOffsets[i&&
1471               textLocation <= highlightedTypeAnnotsOffsets[i + 1]) {
1472             index = (i == 0? i : i / 2;
1473             break;
1474           }
1475         }
1476       }
1477 
1478       // yes it is put on highlighted so show the annotationType
1479       if (highlightedTypeAnnotsOffsets != null &&
1480           index < highlightedTypeAnnotsOffsets.length && index >= 0) {
1481         textPane.removeAll();
1482         annotToConsiderForChain = highlightedTypeAnnots.get(index);
1483         // now check if this annotation is already linked with something
1484         CorefTreeNode headNode = findOutTheChainHead(annotToConsiderForChain, (StringannotSets.getSelectedItem());
1485         if (headNode != null) {
1486           popup1 = new JPopupMenu();
1487           popup1.setBackground(UIManager.getLookAndFeelDefaults().
1488                                getColor("ToolTip.background"));
1489           JLabel label1 = new JLabel("Annotation co-referenced to : \"" +
1490                                      headNode.toString() "\"");
1491           popup1.setLayout(new FlowLayout());
1492           popup1.add(label1);
1493           if (popupWindow != null && popupWindow.isVisible()) {
1494             popupWindow.setVisible(false);
1495           }
1496           popup1.setVisible(true);
1497           popup1.show(textPane, (intmousePoint.getX()(intmousePoint.getY());
1498         }
1499         else {
1500           popupWindow.setVisible(false);
1501           List<String> set = new ArrayList<String>(currentSelections.keySet());
1502           Collections.sort(set);
1503           set.add(0"[New Chain]");
1504           model = new DefaultComboBoxModel<String>(set.toArray(new String[set.size()]));
1505           list.setModel(model);
1506           listEditor.setItem("");
1507           label.setText("Add \"" + getString(annotToConsiderForChain+
1508                         "\" to ");
1509           Point topLeft = textPane.getLocationOnScreen();
1510           int x = topLeft.x + (intmousePoint.getX();
1511           int y = topLeft.y + (intmousePoint.getY();
1512           popupWindow.setLocation(x, y);
1513           if (popup1.isVisible()) {
1514             popup1.setVisible(false);
1515           }
1516           popupWindow.pack();
1517           popupWindow.setVisible(true);
1518           listEditor.requestFocus();
1519 
1520           if (firstTime) {
1521             firstTime = false;
1522             popupWindow.pack();
1523             popupWindow.repaint();
1524             listEditor.requestFocus();
1525           }
1526         }
1527       }
1528     }
1529 
1530     public void setTextLocation(int textLocation) {
1531       this.textLocation = textLocation;
1532     }
1533 
1534     public void setMousePointer(Point point) {
1535       this.mousePoint = point;
1536     }
1537 
1538     /** Custom Editor for the ComboBox to enable key events */
1539     private class ListEditor
1540         extends KeyAdapter
1541         implements ComboBoxEditor {
1542       JTextField myField = new JTextField(20);
1543       AddAction action = null;
1544       Vector<String> myList = new Vector<String>();
1545 
1546       public ListEditor(AddAction action) {
1547         this.action = action;
1548         myField.addKeyListener(this);
1549       }
1550 
1551       @Override
1552       public void addActionListener(ActionListener al) {
1553         myField.addActionListener(al);
1554       }
1555 
1556       @Override
1557       public void removeActionListener(ActionListener al) {
1558         myField.removeActionListener(al);
1559       }
1560 
1561       @Override
1562       public Component getEditorComponent() {
1563         return myField;
1564       }
1565 
1566       @Override
1567       public Object getItem() {
1568         return myField.getText();
1569       }
1570 
1571       @Override
1572       public void selectAll() {
1573         if (myField.getText() != null && myField.getText().length() 0) {
1574           myField.setSelectionStart(0);
1575           myField.setSelectionEnd(myField.getText().length());
1576         }
1577       }
1578 
1579       @Override
1580       public void setItem(Object item) {
1581         myField.setText( (Stringitem);
1582         field = myField.getText();
1583       }
1584 
1585       public void requestFocus() {
1586         myField.requestFocus();
1587       }
1588 
1589       @Override
1590       public void keyReleased(KeyEvent ke) {
1591         if (myField.getText() == null) {
1592           myField.setText("");
1593           field = myField.getText();
1594         }
1595 
1596         if (ke.getKeyCode() == KeyEvent.VK_DOWN) {
1597           if (myList.size() == 1) {
1598             myField.setTextmyList.get(0));
1599           }
1600           else if (list.getSelectedIndex() < list.getModel().getSize() 1) {
1601             list.setSelectedIndex(list.getSelectedIndex());
1602             myField.setText( (Stringlist.getSelectedItem());
1603           }
1604           field = myField.getText();
1605           myField.requestFocus();
1606           return;
1607         }
1608         else if (ke.getKeyCode() == KeyEvent.VK_UP) {
1609           if (list.getSelectedIndex() 0) {
1610             list.setSelectedIndex(list.getSelectedIndex());
1611           }
1612           myField.setText( (Stringlist.getSelectedItem());
1613           field = myField.getText();
1614           return;
1615         }
1616         else if (ke.getKeyCode() == KeyEvent.VK_ENTER) {
1617           field = myField.getText();
1618           action.actionPerformed(new ActionEvent(add,
1619                                                  ActionEvent.ACTION_PERFORMED,
1620                                                  "add"));
1621           return;
1622         }
1623         else if (ke.getKeyCode() == KeyEvent.VK_BACK_SPACE) {
1624         }
1625         else if (Character.isJavaIdentifierPart(ke.getKeyChar()) ||
1626                  Character.isSpaceChar(ke.getKeyChar()) ||
1627                  Character.isDefined(ke.getKeyChar())) {
1628         }
1629         else {
1630           return;
1631         }
1632 
1633         String startWith = myField.getText();
1634         myList = new Vector<String>();
1635         ArrayList<String> set = new ArrayList<String>(currentSelections.keySet());
1636         Collections.sort(set);
1637         set.add(0"[New Chain]");
1638         boolean first = true;
1639         for (int i = 0; i < set.size(); i++) {
1640           String currString = set.get(i);
1641           if (currString.toLowerCase().startsWith(startWith.toLowerCase())) {
1642             if (first) {
1643               myField.setText(currString.substring(0, startWith.length()));
1644               first = false;
1645             }
1646             myList.add(currString);
1647           }
1648         }
1649         ComboBoxModel<String> model = new DefaultComboBoxModel<String>(myList);
1650         list.setModel(model);
1651         myField.setText(startWith);
1652         field = myField.getText();
1653         list.showPopup();
1654       }
1655     }
1656 
1657     private class AddAction
1658         extends AbstractAction {
1659       @SuppressWarnings("unchecked")
1660       @Override
1661       public void actionPerformed(ActionEvent ae) {
1662         if (ae.getSource() == cancel) {
1663           popupWindow.setVisible(false);
1664           return;
1665         }
1666         else if (ae.getSource() == add) {
1667           if (field.length() == 0) {
1668             try {
1669               JOptionPane.showMessageDialog(MainFrame.getInstance(),
1670                                             "No Chain Selected",
1671                                             "New Chain - Error",
1672                                             JOptionPane.ERROR_MESSAGE);
1673             }
1674             catch (Exception e) {
1675               e.printStackTrace();
1676             }
1677             return;
1678           }
1679           else {
1680             // we want to add this
1681             // now first find out the annotation
1682             Annotation ann = annotToConsiderForChain;
1683             if (ann == null)
1684               return;
1685             // yes it is available
1686             // find out the CorefTreeNode for the chain under which it is to be inserted
1687             if (field.equals("[New Chain]")) {
1688               // we want to add this
1689               // now first find out the annotation
1690               
1691               CorefTreeNode chainNode = findOutChainNode(getString(ann)(StringannotSets.getSelectedItem());
1692               if (chainNode != null) {
1693                 try {
1694                   JOptionPane.showMessageDialog(MainFrame.getInstance(),
1695                                                 "Chain with " + getString(ann+
1696                                                 " title already exists",
1697                                                 "New Chain - Error",
1698                                                 JOptionPane.ERROR_MESSAGE);
1699                 }
1700                 catch (Exception e) {
1701                   e.printStackTrace();
1702                 }
1703                 return;
1704               }
1705 
1706               popupWindow.setVisible(false);
1707 
1708               String currentSet = (StringannotSets.getSelectedItem();
1709               currentSet = (currentSet.equals(DEFAULT_ANNOTSET_NAME)) null :
1710                            currentSet;
1711 
1712               Map<String, List<List<Integer>>> matchesMap = null;
1713               Object matchesMapObject = document.getFeatures().get(ANNIEConstants.DOCUMENT_COREF_FEATURE_NAME);
1714               if(matchesMapObject instanceof Map) {
1715                 matchesMap = (Map<String, List<List<Integer>>>matchesMapObject;
1716               }
1717 
1718               if (matchesMap == null) {
1719                 matchesMap = new HashMap<String, List<List<Integer>>>();
1720               }
1721 
1722               List<List<Integer>> matches = matchesMap.get(currentSet);
1723               ArrayList<Integer> tempList = new ArrayList<Integer>();
1724               tempList.add(ann.getId());
1725               if (matches == null)
1726                 matches = new ArrayList<List<Integer>>();
1727               matches.add(tempList);
1728               matchesMap.put(currentSet, matches);
1729               document.getFeatures().put(ANNIEConstants.
1730                                          DOCUMENT_COREF_FEATURE_NAME,
1731                                          matchesMap);
1732               return;
1733             }
1734 
1735             CorefTreeNode chainNode = findOutChainNode(field, (StringannotSets.getSelectedItem());
1736             Map<CorefTreeNode, List<Integer>> chains = corefChains.get(corefAnnotationSetNodesMap.get(
1737         annotSets.getSelectedItem()));
1738             if (chainNode == null) {
1739               try {
1740                 JOptionPane.showMessageDialog(MainFrame.getInstance(),
1741                                               "Incorrect Chain Title",
1742                                               "New Chain - Error",
1743                                               JOptionPane.ERROR_MESSAGE);
1744               }
1745               catch (Exception e) {
1746                 e.printStackTrace();
1747               }
1748               return;
1749             }
1750             popupWindow.setVisible(false);
1751             List<Integer> ids = chains.get(chainNode);
1752 
1753             Map<String, List<List<Integer>>> matchesMap = null;
1754             Object matchesMapObject = document.getFeatures().get(ANNIEConstants.DOCUMENT_COREF_FEATURE_NAME);
1755             if(matchesMapObject instanceof Map) {
1756               matchesMap = (Map<String, List<List<Integer>>>matchesMapObject;
1757             }
1758 
1759             if (matchesMap == null) {
1760               matchesMap = new HashMap<String, List<List<Integer>>>();
1761             }
1762             String currentSet = (StringannotSets.getSelectedItem();
1763             currentSet = (currentSet.equals(DEFAULT_ANNOTSET_NAME)) null :
1764                          currentSet;
1765             List<List<Integer>> matches = matchesMap.get(currentSet);
1766             if (matches == null)
1767               matches = new ArrayList<List<Integer>>();
1768             int index = matches.indexOf(ids);
1769             if (index != -1) {
1770               List<Integer> tempIds = matches.get(index);
1771               tempIds.add(ann.getId());
1772               matches.set(index, tempIds);
1773               matchesMap.put(currentSet, matches);
1774               document.getFeatures().put(ANNIEConstants.
1775                                          DOCUMENT_COREF_FEATURE_NAME,
1776                                          matchesMap);
1777             }
1778             return;
1779           }
1780         }
1781       }
1782     }
1783   }
1784 
1785   /** When user hovers over the chainnodes */
1786   protected class ChainToolTipAction
1787       extends AbstractAction {
1788 
1789     int textLocation;
1790     Point mousePoint;
1791     JPopupMenu popup = new JPopupMenu();
1792 
1793     public ChainToolTipAction() {
1794       popup.setBackground(UIManager.getLookAndFeelDefaults().
1795                           getColor("ToolTip.background"));
1796     }
1797 
1798     @Override
1799     public void actionPerformed(ActionEvent ae) {
1800 
1801       int index = -1;
1802       if (highlightedChainAnnotsOffsets != null) {
1803         for (int i = 0; i < highlightedChainAnnotsOffsets.length; i += 2) {
1804           if (textLocation >= highlightedChainAnnotsOffsets[i&&
1805               textLocation <= highlightedChainAnnotsOffsets[i + 1]) {
1806             index = (i == 0? i : i / 2;
1807             break;
1808           }
1809         }
1810       }
1811 
1812       // yes it is put on highlighted so show the annotationType
1813       if (highlightedChainAnnotsOffsets != null &&
1814           index < highlightedChainAnnotsOffsets.length && index >= 0) {
1815 
1816         if (popupWindow != null && popupWindow.isVisible()) {
1817           popupWindow.setVisible(false);
1818         }
1819 
1820         popup.setVisible(false);
1821         popup.removeAll();
1822         final int tempIndex = index;
1823         CorefTreeNode chainHead = findOutTheChainHeadhighlightedChainAnnots.get(index)(StringannotSets.getSelectedItem());
1824         final HashMap<String, CorefTreeNode> tempMap = new HashMap<String, CorefTreeNode>();
1825         popup.setLayout(new FlowLayout(FlowLayout.LEFT));
1826         if (chainHead != null) {
1827           JPanel tempPanel = new JPanel();
1828           tempPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
1829           tempPanel.add(new JLabel(chainHead.toString()));
1830           tempPanel.setBackground(UIManager.getLookAndFeelDefaults().
1831                                   getColor("ToolTip.background"));
1832           final JButton deleteButton = new JButton("Delete");
1833           tempPanel.add(deleteButton);
1834           popup.add(tempPanel);
1835           deleteButton.setActionCommand(chainHead.toString());
1836           tempMap.put(chainHead.toString(), chainHead);
1837           deleteButton.addActionListener(new ActionListener() {
1838             @Override
1839             public void actionPerformed(ActionEvent ae) {
1840               try {
1841                 int confirm = JOptionPane.showConfirmDialog(MainFrame.getInstance(),
1842                     "Are you sure?""Removing reference...",
1843                     JOptionPane.YES_NO_OPTION);
1844                 if (confirm == JOptionPane.YES_OPTION) {
1845                   popup.setVisible(false);
1846                   // remove it
1847                   removeChainReferencehighlightedChainAnnots.get(
1848                       tempIndex),
1849                       tempMap.get(deleteButton.getActionCommand()));
1850                 }
1851               }
1852               catch (Exception e1) {
1853                 e1.printStackTrace();
1854               }
1855             }
1856           });
1857         }
1858         //label.setText("Remove \""+getString((Annotation) highlightedChainAnnots.get(index)) + "\" from \""+ findOutTheChainHead((Annotation) highlightedChainAnnots.get(index)).toString()+"\"");
1859         popup.revalidate();
1860         if (popupWindow != null && popupWindow.isVisible()) {
1861           popupWindow.setVisible(false);
1862         }
1863         popup.setVisible(true);
1864         popup.show(textPane, (intmousePoint.getX()(intmousePoint.getY());
1865       }
1866     }
1867 
1868     public void setTextLocation(int textLocation) {
1869       this.textLocation = textLocation;
1870     }
1871 
1872     public void setMousePointer(Point point) {
1873       this.mousePoint = point;
1874     }
1875 
1876   }
1877 
1878   // Class that represents each individual tree node in the corefTree
1879   protected class CorefTreeNode
1880       extends DefaultMutableTreeNode {
1881     public final static int ROOT_NODE = 0;
1882     public final static int ANNOTSET_NODE = 1;
1883     public final static int CHAIN_NODE = 2;
1884 
1885     private int type;
1886 
1887     public CorefTreeNode(Object value, boolean allowsChildren, int type) {
1888       super(value, allowsChildren);
1889       this.type = type;
1890     }
1891 
1892     public int getType() {
1893       return this.type;
1894     }
1895 
1896   }
1897 
1898   /**
1899    * Action for mouseClick on the Tree
1900    */
1901   protected class CorefTreeMouseListener
1902       extends MouseAdapter {
1903 
1904     @Override
1905     public void mouseClicked(MouseEvent me) { }
1906     @Override
1907     public void mouseReleased(MouseEvent me) { }
1908 
1909     @Override
1910     public void mousePressed(MouseEvent me) {
1911       if (popupWindow != null && popupWindow.isVisible()) {
1912         popupWindow.setVisible(false);
1913       }
1914       textPane.removeAll();
1915       // ok now find out the currently selected node
1916       int x = me.getX();
1917       int y = me.getY();
1918       int row = corefTree.getRowForLocation(x, y);
1919       TreePath path = corefTree.getPathForRow(row);
1920 
1921       if (path != null) {
1922         final CorefTreeNode node = (CorefTreeNodepath.
1923                                    getLastPathComponent();
1924 
1925         // if it only chainNode
1926         if (node.getType() != CorefTreeNode.CHAIN_NODE) {
1927           return;
1928         }
1929 
1930         // see if user clicked the right click
1931         if (SwingUtilities.isRightMouseButton(me)) {
1932           // it is right click
1933           // we need to show the popup window
1934           final JPopupMenu popup = new JPopupMenu();
1935           JButton delete = new JButton("Delete");
1936           delete.setToolTipText("Delete Chain");
1937           ToolTipManager.sharedInstance().registerComponent(delete);
1938           JButton cancel = new JButton("Close");
1939           cancel.setToolTipText("Closes this popup");
1940           JButton changeColor = new JButton("Change Color");
1941           changeColor.setToolTipText("Changes Color");
1942           ToolTipManager.sharedInstance().registerComponent(cancel);
1943           ToolTipManager.sharedInstance().registerComponent(changeColor);
1944           JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT));
1945           panel.setOpaque(false);
1946           panel.add(changeColor);
1947           panel.add(delete);
1948           panel.add(cancel);
1949           popup.setLayout(new BorderLayout());
1950           popup.setOpaque(true);
1951           popup.setBackground(UIManager.getLookAndFeelDefaults().
1952                               getColor("ToolTip.background"));
1953           popup.add(new JLabel("Chain \"" + node.toString() "\""),
1954                     BorderLayout.NORTH);
1955           popup.add(panel, BorderLayout.SOUTH);
1956 
1957           changeColor.addActionListener(new ActionListener() {
1958             @Override
1959             public void actionPerformed(ActionEvent ae) {
1960               String currentAnnotSet = (StringannotSets.getSelectedItem();
1961               currentColors = colorChainsMap.get(currentAnnotSet);
1962               Color colour = currentColors.get(node.toString());
1963               Color col = JColorChooser.showDialog(getGUI(),
1964                   "Select colour for \"" + node.toString() "\"",
1965                   colour);
1966               if (col != null) {
1967                 Color colAlpha = new Color(col.getRed(), col.getGreen(),
1968                                            col.getBlue()128);
1969 
1970                 // make change in the datastructures
1971                 currentColors.put(node.toString(),colAlpha);
1972                 colorChainsMap.put(currentAnnotSet, currentColors);
1973                 // and redraw the tree
1974                 corefTree.repaint();
1975 
1976                 // remove all highlights
1977                 List<Object> allHighlights = new ArrayList<Object>();
1978                 if(typeSpecificHighlightedTags != null)
1979                   allHighlights.addAll(typeSpecificHighlightedTags);
1980                 if(highlightedTags != null) {
1981                   Iterator<List<Object>> iter = highlightedTags.values().iterator();
1982                   while(iter.hasNext()) {
1983                     List<Object> highlights = iter.next();
1984                     allHighlights.addAll(highlights);
1985                   }
1986                 }
1987                 for (int i = 0; i < allHighlights.size(); i++) {
1988                   highlighter.removeHighlight(allHighlights.get(i));
1989                 }
1990 
1991                 //highlighter.removeAllHighlights();
1992                 highlightedTags = null;
1993                 highlightAnnotations();
1994                 typeSpecificHighlightedTags = null;
1995                 showTypeWiseAnnotations();
1996               }
1997               popup.setVisible(false);
1998             }
1999           });
2000 
2001           delete.addActionListener(new ActionListener() {
2002             @SuppressWarnings("unchecked")
2003             @Override
2004             public void actionPerformed(ActionEvent ae) {
2005               // get the ids of current chainNode
2006               Map<CorefTreeNode, List<Integer>> chains = corefChains.get(corefAnnotationSetNodesMap.get(
2007          annotSets.getSelectedItem()));
2008               List<Integer> ids = chains.get(node);
2009 
2010               String currentSet = (StringannotSets.getSelectedItem();
2011               currentSet = (currentSet.equals(DEFAULT_ANNOTSET_NAME)) null : currentSet;
2012 
2013               // now search this in the document feature map
2014               Map<String, List<List<Integer>>> matchesMap = null;
2015               List<List<Integer>> matches = null;
2016 
2017               Object matchesMapObject = document.getFeatures().get(ANNIEConstants.DOCUMENT_COREF_FEATURE_NAME);
2018               if(matchesMapObject instanceof Map) {
2019                 matchesMap = (Map<String, List<List<Integer>>>matchesMapObject;
2020                 matches = matchesMap.get(currentSet);
2021               }
2022 
2023               if(matchesMap == null) {
2024                 matchesMap = new HashMap<String, List<List<Integer>>>();
2025               }
2026 
2027               if (matches == null)
2028                 matches = new ArrayList<List<Integer>>();
2029 
2030               int index = matches.indexOf(ids);
2031               if (index != -1) {
2032                 // yes found
2033                 matches.remove(index);
2034                 matchesMap.put(currentSet, matches);
2035                 document.getFeatures().put(ANNIEConstants.
2036                                            DOCUMENT_COREF_FEATURE_NAME,
2037                                            matchesMap);
2038               }
2039               popup.setVisible(false);
2040             }
2041           });
2042 
2043           cancel.addActionListener(new ActionListener() {
2044             @Override
2045             public void actionPerformed(ActionEvent ae) {
2046               popup.setVisible(false);
2047             }
2048           });
2049           popup.setVisible(true);
2050           popup.show(corefTree, x, y);
2051           return;
2052         }
2053 
2054         boolean isSelected = ! currentSelections.get(node.toString()).
2055                              booleanValue();
2056         currentSelections.put(node.toString()new Boolean(isSelected));
2057 
2058         // so now we need to highlight all the stuff
2059         highlightAnnotations();
2060         corefTree.repaint();
2061         corefTree.updateUI();
2062         corefTree.repaint();
2063         corefTree.updateUI();
2064 
2065       }
2066     }
2067   }
2068 
2069   /**
2070    * Cell renderer to add the checkbox in the tree
2071    */
2072   protected class CorefTreeCellRenderer
2073       extends JPanel
2074       implements TreeCellRenderer {
2075 
2076     private JCheckBox check;
2077     private JLabel label;
2078 
2079     /**
2080      * Constructor.
2081      */
2082     public CorefTreeCellRenderer() {
2083       setOpaque(true);
2084       check = new JCheckBox();
2085       check.setBackground(Color.white);
2086       label = new JLabel();
2087       setLayout(new BorderLayout(510));
2088       add(check, BorderLayout.WEST);
2089       add(label, BorderLayout.CENTER);
2090     }
2091 
2092     /**
2093      * Renderer class
2094      */
2095     @Override
2096     public Component getTreeCellRendererComponent(JTree tree, Object value,
2097                                                   boolean isSelected,
2098                                                   boolean expanded,
2099                                                   boolean leaf, int row,
2100                                                   boolean hasFocus) {
2101 
2102       CorefTreeNode userObject = (CorefTreeNodevalue;
2103       label.setText(userObject.toString());
2104       this.setSize(label.getWidth(),
2105                    label.getFontMetrics(label.getFont()).getHeight() 2);
2106       tree.expandRow(row);
2107       if (userObject.getType() == CorefTreeNode.ROOT_NODE || userObject.getType() ==
2108           CorefTreeNode.ANNOTSET_NODE) {
2109         this.setBackground(Color.white);
2110         this.check.setVisible(false);
2111         return this;
2112       }
2113       else {
2114         this.setBackground(currentColors.get(userObject.toString()));
2115         check.setVisible(true);
2116         check.setBackground(Color.white);
2117       }
2118 
2119       // if node should be selected
2120       boolean selected = currentSelections.get(userObject.toString()).
2121                          booleanValue();
2122       check.setSelected(selected);
2123       return this;
2124     }
2125   }
2126 }