1   /*
2    *  Copyright (c) 1998-2004, The University of Sheffield.
3    *
4    *  This file is part of GATE (see http://gate.ac.uk/), and is free
5    *  software, licenced under the GNU Library General Public License,
6    *  Version 2, June 1991 (in the distribution as file licence.html,
7    *  and also available at http://gate.ac.uk/gate/licence.html).
8    *
9    *  CorefEditor.java
10   *
11   *  Niraj Aswani, 24-Jun-2004
12   *
13   *  $Id: CorefEditor.java,v 1.13 2004/08/04 14:32:56 niraj Exp $
14   */
15  
16  package gate.gui.docview;
17  
18  import java.awt.*;
19  import javax.swing.*;
20  import javax.swing.tree.*;
21  import javax.swing.event.*;
22  import java.util.*;
23  import gate.*;
24  import gate.creole.*;
25  import java.io.*;
26  import java.awt.event.*;
27  import gate.swing.*;
28  import gate.event.*;
29  import javax.swing.text.Highlighter;
30  import javax.swing.text.DefaultHighlighter;
31  
32  public class CorefEditor
33      extends AbstractDocumentView
34      implements ActionListener, gate.event.FeatureMapListener,
35      gate.event.DocumentListener, AnnotationSetListener {
36  
37    // default AnnotationSet Name
38    private final static String DEFAULT_ANNOTSET_NAME = "Default";
39  
40    private JPanel mainPanel, topPanel, subPanel;
41    private JToggleButton showAnnotations;
42    private JComboBox annotSets, annotTypes;
43    private DefaultComboBoxModel annotSetsModel, annotTypesModel;
44  
45    // Co-reference Tree
46    private JTree corefTree;
47  
48    // Root node
49    private CorefTreeNode rootNode;
50  
51    // top level hashMap (corefChains)
52    // AnnotationSet(CorefTreeNode) --> (CorefTreeNode type ChainNode --> ArrayList AnnotationIds)
53    private HashMap corefChains;
54  
55    // This is used to store the annotationSet name and its respective corefTreeNode
56    // annotationSetName --> CorefTreeNode of type (AnnotationSet)
57    private HashMap corefAnnotationSetNodesMap;
58  
59    // annotationSetName --> (chainNodeString --> Boolean)
60    private HashMap selectionChainsMap;
61  
62    // chainString --> Boolean
63    private HashMap currentSelections;
64  
65    // annotationSetName --> (chainNodeString --> Color)
66    private HashMap colorChainsMap;
67  
68    // chainNodeString --> Color
69    private HashMap currentColors;
70  
71    private ColorGenerator colorGenerator;
72    private TextualDocumentView textView;
73    private JEditorPane textPane;
74  
75    /* ChainNode --> (HighlightedTags) */
76    private HashMap highlightedTags;
77  
78    /* This arraylist stores the highlighted tags for the specific selected annotation type */
79    private ArrayList typeSpecificHighlightedTags;
80    private TextPaneMouseListener textPaneMouseListener;
81  
82    /* This stores Ids of the highlighted Chain Annotations*/
83    private ArrayList highlightedChainAnnots = new ArrayList();
84    /* This stores start and end offsets of the highlightedChainAnnotations */
85    private int[] highlightedChainAnnotsOffsets;
86  
87    /* This stores Ids of the highlighted Annotations of particular type */
88    private ArrayList highlightedTypeAnnots = new ArrayList();
89    /* This stores start and end offsets of highlightedTypeAnnots */
90    private int[] highlightedTypeAnnotsOffsets;
91  
92    /* Timer for the Chain Tool tip action */
93    private ChainToolTipAction chainToolTipAction;
94    private javax.swing.Timer chainToolTipTimer;
95  
96    private NewCorefAction newCorefAction;
97    private javax.swing.Timer newCorefActionTimer;
98  
99    private Annotation annotToConsiderForChain = null;
100   private JWindow popupWindow;
101   private boolean explicitCall = false;
102   private Highlighter highlighter;
103 
104   /**
105    * This method intiates the GUI for co-reference editor
106    */
107   protected void initGUI() {
108 
109     //get a pointer to the textual view used for highlights
110     Iterator centralViewsIter = owner.getCentralViews().iterator();
111     while (textView == null && centralViewsIter.hasNext()) {
112       DocumentView aView = (DocumentView) centralViewsIter.next();
113       if (aView instanceof TextualDocumentView)
114         textView = (TextualDocumentView) aView;
115     }
116     textPane = (JEditorPane) ( (JScrollPane) textView.getGUI()).getViewport().
117                getView();
118     highlighter = textPane.getHighlighter();
119     chainToolTipAction = new ChainToolTipAction();
120     chainToolTipTimer = new javax.swing.Timer(500, chainToolTipAction);
121 
122     newCorefAction = new NewCorefAction();
123     newCorefActionTimer = new javax.swing.Timer(500, newCorefAction);
124 
125     colorGenerator = new ColorGenerator();
126 
127     // main Panel
128     mainPanel = new JPanel();
129     mainPanel.setLayout(new BorderLayout());
130 
131     // topPanel
132     topPanel = new JPanel();
133     topPanel.setLayout(new BorderLayout());
134 
135     // subPanel
136     subPanel = new JPanel();
137     subPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
138 
139     // showAnnotations Button
140     showAnnotations = new JToggleButton("Show");
141     showAnnotations.addActionListener(this);
142 
143     // annotSets
144     annotSets = new JComboBox();
145     annotSets.addActionListener(this);
146 
147     // get all the annotationSets
148     Map annotSetsMap = document.getNamedAnnotationSets();
149     annotSetsModel = new DefaultComboBoxModel();
150     if (annotSetsMap != null) {
151       Object [] array = annotSetsMap.keySet().toArray();
152       for(int i=0;i<array.length;i++) {
153         ((AnnotationSet) annotSetsMap.get((String) array[i])).addAnnotationSetListener(this);
154       }
155       annotSetsModel = new DefaultComboBoxModel(array);
156     }
157     document.getAnnotations().addAnnotationSetListener(this);
158     annotSetsModel.insertElementAt(DEFAULT_ANNOTSET_NAME, 0);
159     annotSets.setModel(annotSetsModel);
160 
161     // annotTypes
162     annotTypesModel = new DefaultComboBoxModel();
163     annotTypes = new JComboBox(annotTypesModel);
164     annotTypes.addActionListener(this);
165     subPanel.add(new JLabel("Sets : "));
166     subPanel.add(annotSets);
167     JPanel tempPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
168     tempPanel.add(new JLabel("Types : "));
169     tempPanel.add(annotTypes);
170     tempPanel.add(showAnnotations);
171     // intialises the Data
172     initData();
173 
174     // and creating the tree
175     corefTree = new JTree(rootNode);
176     corefTree.putClientProperty("JTree.lineStyle", "None");
177     corefTree.setRowHeight(corefTree.getRowHeight() * 2);
178     corefTree.setLargeModel(true);
179     corefTree.setAutoscrolls(true);
180 
181     //corefTree.setRootVisible(false);
182     //corefTree.setShowsRootHandles(false);
183     corefTree.addMouseListener(new CorefTreeMouseListener());
184     corefTree.setCellRenderer(new CorefTreeCellRenderer());
185 
186     mainPanel.add(topPanel, BorderLayout.NORTH);
187     mainPanel.add(new JScrollPane(corefTree), BorderLayout.CENTER);
188     topPanel.add(subPanel, BorderLayout.CENTER);
189     topPanel.add(tempPanel, BorderLayout.SOUTH);
190 
191     // get the highlighter
192     textPaneMouseListener = new TextPaneMouseListener();
193     annotSets.setSelectedIndex(0);
194 
195     // finally show the tree
196     //annotSetSelectionChanged();
197 
198     document.addDocumentListener(this);
199     document.getFeatures().addFeatureMapListener(this);
200   }
201 
202   public void reinitAllVariables() {
203 
204     if (highlightedChainAnnots != null)
205       highlightedChainAnnots.clear();
206     if (highlightedTypeAnnots != null)
207       highlightedTypeAnnots.clear();
208     if (typeSpecificHighlightedTags != null)
209       typeSpecificHighlightedTags.clear();
210     highlightedChainAnnotsOffsets = null;
211     highlightedTypeAnnotsOffsets = null;
212     if (highlightedTags != null && highlightedTags.values() != null) {
213       Iterator highlightsIter = highlightedTags.values().iterator();
214       while (highlightsIter.hasNext()) {
215         ArrayList tags = (ArrayList) highlightsIter.next();
216         for (int i = 0; i < tags.size(); i++) {
217           highlighter.removeHighlight(tags.get(i));
218         }
219       }
220       highlightedTags.clear();
221     }
222 
223     // we need to find out all the annotSetNodes and remove all the chainNodes
224     // under it
225     Iterator annotSetsIter = corefAnnotationSetNodesMap.keySet().iterator();
226     while (annotSetsIter.hasNext()) {
227       CorefTreeNode annotSetNode = (CorefTreeNode) corefAnnotationSetNodesMap.
228                                    get(annotSetsIter.next());
229       annotSetNode.removeAllChildren();
230       colorChainsMap.put(annotSetNode.toString(), new HashMap());
231       selectionChainsMap.put(annotSetNode.toString(), new HashMap());
232       corefChains.put(annotSetNode, new HashMap());
233     }
234   }
235 
236       /** This methods cleans up the memory by removing all listener registrations */
237   public void cleanup() {
238     document.removeDocumentListener(this);
239     document.getFeatures().removeFeatureMapListener(this);
240   }
241 
242   /** Given arrayList containing Ids of the annotations, and an annotationSet, this method
243    * returns the annotations that has longest string among the matches
244    */
245   public Annotation findOutTheLongestAnnotation(ArrayList matches,
246                                                 AnnotationSet set) {
247     if (matches == null || matches.size() == 0) {
248       return null;
249     }
250     int length = 0;
251     int index = 0;
252     for (int i = 0; i < matches.size(); i++) {
253       Annotation currAnn = (Annotation) set.get( (Integer) matches.get(i));
254       int start = currAnn.getStartNode().getOffset().intValue();
255       int end = currAnn.getEndNode().getOffset().intValue();
256       if ( (end - start) > length) {
257         length = end - start;
258         index = i;
259       }
260     }
261     // so now we now have the longest String annotations at index
262     return (Annotation) set.get( (Integer) matches.get(index));
263   }
264 
265   /**
266    * This method is called when any annotationSet is removed outside the
267    * co-reference editor..
268    * @param de
269    */
270   public void annotationSetRemoved(gate.event.DocumentEvent de) {
271     // this method removes the annotationSet from the annotSets
272     // and all chainNodes under it
273 
274     String annotSet = de.getAnnotationSetName();
275     annotSet = (annotSet == null) ? DEFAULT_ANNOTSET_NAME : annotSet;
276     // find out the currently Selected annotationSetName
277     String annotSetName = (String) annotSets.getSelectedItem();
278     // remove it from the main data store
279     corefChains.remove(corefAnnotationSetNodesMap.get(annotSet));
280     // remove it from the main data store
281     corefAnnotationSetNodesMap.remove(annotSet);
282     // remove it from the annotationSetModel (combobox)
283     annotSetsModel.removeElement(annotSet);
284     annotSets.setModel(annotSetsModel);
285     // remove it from the colorChainMap
286     colorChainsMap.remove(annotSet);
287     // remove it from the selectionChainMap
288     selectionChainsMap.remove(annotSet);
289     if (annotSetsModel.getSize() == 0) {
290       // no annotationSet to display
291       // so set visible false
292       if (popupWindow != null && popupWindow.isVisible()) {
293         popupWindow.setVisible(false);
294       }
295       corefTree.setVisible(false);
296     }
297     else {
298       if (annotSetName.equals(annotSet)) {
299         if (popupWindow != null && popupWindow.isVisible()) {
300           popupWindow.setVisible(false);
301         }
302         if (!corefTree.isVisible())
303           corefTree.setVisible(true);
304 
305         annotSets.setSelectedIndex(0);
306         //annotSetSelectionChanged();
307       }
308     }
309   }
310 
311   /**
312    * This method is called when any new annotationSet is added
313    * @param de
314    */
315   public void annotationSetAdded(gate.event.DocumentEvent de) {
316 
317     String annotSet = de.getAnnotationSetName();
318     if(annotSet == null)
319       document.getAnnotations().addAnnotationSetListener(this);
320     else
321       document.getAnnotations(annotSet).addAnnotationSetListener(this);
322 
323     annotSet = (annotSet == null) ? DEFAULT_ANNOTSET_NAME : annotSet;
324     // find out the currently Selected annotationSetName
325     String annotSetName = (String) annotSets.getSelectedItem();
326 
327     // check if newly added annotationSet is the default AnnotationSet
328     CorefTreeNode annotSetNode = null;
329 
330     if (annotSet.equals(DEFAULT_ANNOTSET_NAME))
331       annotSetNode = createChain(document.getAnnotations(), true);
332     else
333       annotSetNode = createChain(document.getAnnotations(annotSet), false);
334 
335     corefAnnotationSetNodesMap.put(annotSet, annotSetNode);
336     annotSetsModel.addElement(annotSet);
337     annotSets.setModel(annotSetsModel);
338 
339     if (annotSetName != null)
340       annotSets.setSelectedItem(annotSetName);
341     else
342       annotSets.setSelectedIndex(0);
343 
344       //annotSetSelectionChanged();
345   }
346 
347   /**Called when the content of the document has changed through an edit
348    * operation.
349    */
350   public void contentEdited(gate.event.DocumentEvent e) {
351     //ignore
352   }
353 
354   public void annotationAdded(AnnotationSetEvent ase) {
355     // ignore
356   }
357 
358   public void annotationRemoved(AnnotationSetEvent ase) {
359     Annotation delAnnot = ase.getAnnotation();
360     Integer id = delAnnot.getId();
361     Map matchesMap = null;
362     matchesMap = (Map) document.getFeatures().get(ANNIEConstants.
363                                                   DOCUMENT_COREF_FEATURE_NAME);
364     if(matchesMap == null)
365       return;
366 
367     Set keySet = matchesMap.keySet();
368     if(keySet == null)
369       return;
370 
371     Iterator iter = keySet.iterator();
372     boolean found = false;
373     while(iter.hasNext()) {
374       String currSet = (String) iter.next();
375       java.util.List matches = (java.util.List) matchesMap.get(currSet);
376       if(matches == null || matches.size() == 0)
377         continue;
378       else {
379         for(int i=0;i<matches.size();i++) {
380           ArrayList ids = (ArrayList) matches.get(i);
381           if(ids.contains(id)) {
382             // found
383             // so remove this
384             found = true;
385             ids.remove(id);
386             matches.set(i, ids);
387             break;
388           }
389         }
390         if(found) {
391           matchesMap.put(currSet, matches);
392           explicitCall = true;
393           document.getFeatures().put(ANNIEConstants.DOCUMENT_COREF_FEATURE_NAME,
394                                      matchesMap);
395           explicitCall = false;
396           break;
397         }
398       }
399     }
400     if(found)
401       featureMapUpdated();
402   }
403 
404   /**
405    * Called when features are changed outside the co-refEditor
406    */
407   public void featureMapUpdated() {
408 
409     if (explicitCall)
410       return;
411 
412     // we would first save the current settings
413     // 1. Current AnnotSet
414     // 2. Current AnnotType
415     // 3. ShowAnnotation Status
416     String currentAnnotSet = (String) annotSets.getSelectedItem();
417     String currentAnnotType = (String) annotTypes.getSelectedItem();
418     boolean currentShowAnnotationStatus = showAnnotations.isSelected();
419 
420     // there is some change in the featureMap
421     Map matchesMap = null;
422     matchesMap = (Map) document.getFeatures().get(ANNIEConstants.
423                                                   DOCUMENT_COREF_FEATURE_NAME);
424     if (matchesMap == null) {
425       reinitAllVariables();
426       explicitCall = false;
427       annotSets.setSelectedIndex(0);
428       return;
429     }
430 
431     //AnnotationSetName --> List of ArrayLists
432     //each ArrayList contains Ids of related annotations
433     Iterator setIter = matchesMap.keySet().iterator();
434     HashMap annotSetsNamesMap = new HashMap();
435     for (int i = 0; i < annotSets.getItemCount(); i++) {
436       annotSetsNamesMap.put( (String) annotSets.getItemAt(i), new Boolean(false));
437     }
438     outer:while (setIter.hasNext()) {
439       String currentSet = (String) setIter.next();
440       java.util.List matches = (java.util.List) matchesMap.get(currentSet);
441       currentSet = (currentSet == null) ? DEFAULT_ANNOTSET_NAME : currentSet;
442       AnnotationSet currAnnotSet = getAnnotationSet(currentSet);
443       annotSetsNamesMap.put(currentSet, new Boolean(true));
444 
445       if (matches == null)
446         continue;
447 
448       Iterator entitiesIter = matches.iterator();
449       //each entity is a list of annotation IDs
450 
451       if (corefAnnotationSetNodesMap.get(currentSet) == null) {
452         // we need to create the node for this
453         if (currentSet.equals(DEFAULT_ANNOTSET_NAME)) {
454           corefAnnotationSetNodesMap.put(DEFAULT_ANNOTSET_NAME,
455                                          createChain(document.getAnnotations(), true));
456         }
457         else {
458           corefAnnotationSetNodesMap.put(currentSet,
459                                          createChain(document.getAnnotations(
460               currentSet), false));
461         }
462         continue outer;
463       }
464 
465       HashMap chains = (HashMap) corefChains.get(corefAnnotationSetNodesMap.
466                                                  get(
467           currentSet));
468       HashMap visitedList = new HashMap();
469 
470       if (chains != null) {
471         Iterator chainsList = chains.keySet().iterator();
472 
473         // intially no chainHead is visited
474         while (chainsList.hasNext()) {
475           visitedList.put( (CorefTreeNode) chainsList.next(), new Boolean(false));
476         }
477 
478         // now we need to search for the chainHead of each group
479         ArrayList idsToRemove = new ArrayList();
480         while (entitiesIter.hasNext()) {
481           ArrayList ids = (ArrayList) entitiesIter.next();
482           if (ids == null || ids.size() == 0) {
483             idsToRemove.add(ids);
484             continue;
485           }
486 
487           CorefTreeNode chainHead = null;
488           for (int i = 0; i < ids.size(); i++) {
489             Integer id = (Integer) ids.get(i);
490             // now lets find out the headnode for this, if it is available
491             chainHead = findOutTheChainHead(currAnnotSet.get(id));
492             if (chainHead != null) {
493               visitedList.put(chainHead, new Boolean(true));
494               break;
495             }
496           }
497 
498           if (chainHead != null) {
499             // we found the chainHead for this
500             // so we would replace the ids
501             // but before that we would check if chainHead should be replaced
502             Annotation longestAnn = findOutTheLongestAnnotation(ids,
503                 getAnnotationSet(currentSet));
504             if (getString(longestAnn).equals(chainHead.toString())) {
505               // no action needed
506             }
507             else {
508               // we first check if new longestAnnotation String is already available as some other chain Node head
509               if (currentColors.containsKey(getString(longestAnn))) {
510                 // yes one chainHead with this string already exists
511                 // so we need to merge them together
512                 String longestString = getString(longestAnn);
513                 CorefTreeNode tempChainHead = findOutChainNode(longestString);
514                 // now all the ids under current chainHead should be placed under the tempChainHead
515                 ArrayList tempIds = (ArrayList) chains.get(tempChainHead);
516                 ArrayList currentChainHeadIds = (ArrayList) chains.get(
517                     chainHead);
518                 // so lets merge them
519                 tempIds.addAll(currentChainHeadIds);
520 
521                 // and update the chains
522                 chains.remove(chainHead);
523                 chains.put(tempChainHead, tempIds);
524                 corefChains.put(corefAnnotationSetNodesMap.get(currentSet),
525                                 chains);
526                 visitedList.put(chainHead, new Boolean(false));
527                 visitedList.put(tempChainHead, new Boolean(true));
528 
529               }
530               else {
531                 String previousString = chainHead.toString();
532                 String newString = getString(longestAnn);
533                 chainHead.setUserObject(newString);
534 
535                 // we need to change the colors
536                 Color color = (Color) currentColors.get(previousString);
537                 currentColors.remove(previousString);
538                 currentColors.put(newString, color);
539                 colorChainsMap.put(newString, currentColors);
540 
541                 // we need to change the selections
542                 Boolean val = (Boolean) currentSelections.get(previousString);
543                 currentSelections.remove(previousString);
544                 currentSelections.put(newString, val);
545                 selectionChainsMap.put(newString, currentSelections);
546 
547                 chains.put(chainHead, ids);
548                 corefChains.put(corefAnnotationSetNodesMap.get(currentSet),
549                                 chains);
550               }
551             }
552           }
553           else {
554             // this is something new addition
555             // so we need to create a new chainNode
556             // this is the new chain
557             // get the current annotSetNode
558             CorefTreeNode annotSetNode = (CorefTreeNode)
559                                          corefAnnotationSetNodesMap.get(
560                 currentSet);
561 
562             // we need to find out the longest string annotation
563             Annotation ann = findOutTheLongestAnnotation(ids, currAnnotSet);
564             // so before creating a new chainNode we need to find out if
565             // any of the chainNodes has the same string that of this chainNode
566             HashMap tempSelection = (HashMap) selectionChainsMap.get(
567                 currentSet);
568             CorefTreeNode chainNode = null;
569             if (tempSelection.containsKey(getString(ann))) {
570               chainNode = findOutChainNode(getString(ann));
571 
572               // ArrayList matches
573               HashMap newHashMap = (HashMap) corefChains.get(annotSetNode);
574               newHashMap.put(chainNode, ids);
575               corefChains.put(annotSetNode, newHashMap);
576 
577               visitedList.put(chainNode, new Boolean(true));
578             }
579             else {
580               // create the new chainNode
581               chainNode = new CorefTreeNode(getString(ann), false,
582                                             CorefTreeNode.CHAIN_NODE);
583 
584               // add this to tree
585               annotSetNode.add(chainNode);
586               corefAnnotationSetNodesMap.put(currentSet, annotSetNode);
587 
588               // ArrayList matches
589               HashMap newHashMap = (HashMap) corefChains.get(annotSetNode);
590               newHashMap.put(chainNode, ids);
591               corefChains.put(annotSetNode, newHashMap);
592 
593               // entry into the selection
594               tempSelection.put(chainNode.toString(), new Boolean(true));
595               selectionChainsMap.put(currentSet, tempSelection);
596 
597               // entry into the colors
598               float components[] = colorGenerator.getNextColor().getComponents(null);
599               Color color = new Color(components[0],
600                                       components[1],
601                                       components[2],
602                                       0.5f);
603               HashMap tempColors = (HashMap) colorChainsMap.get(currentSet);
604               tempColors.put(chainNode.toString(), color);
605               colorChainsMap.put(annotSets.getSelectedItem(), tempColors);
606             }
607           }
608         }
609 
610         // ok we need to remove Idsnow
611         Iterator removeIter = idsToRemove.iterator();
612         while (removeIter.hasNext()) {
613           explicitCall = true;
614           ArrayList ids = (ArrayList) removeIter.next();
615           matches.remove(ids);
616           String set = currentSet.equals(DEFAULT_ANNOTSET_NAME) ? null :
617                        currentSet;
618           matchesMap.put(set, matches);
619           explicitCall = false;
620         }
621         explicitCall = true;
622         document.getFeatures().put(ANNIEConstants.DOCUMENT_COREF_FEATURE_NAME,
623                                    matchesMap);
624         explicitCall = false;
625 
626         // here we need to find out the chainNodes those are no longer needed
627         Iterator visitedListIter = visitedList.keySet().iterator();
628         while (visitedListIter.hasNext()) {
629           CorefTreeNode chainNode = (CorefTreeNode) visitedListIter.next();
630           if (! ( (Boolean) visitedList.get(chainNode)).booleanValue()) {
631             // yes this should be deleted
632             CorefTreeNode annotSetNode = (CorefTreeNode)
633                                          corefAnnotationSetNodesMap.get(
634                 currentSet);
635 
636             // remove from the tree
637             annotSetNode.remove(chainNode);
638             corefAnnotationSetNodesMap.put(currentSet, annotSetNode);
639 
640             // ArrayList matches
641             HashMap newHashMap = (HashMap) corefChains.get(annotSetNode);
642             newHashMap.remove(chainNode);
643             corefChains.put(annotSetNode, newHashMap);
644 
645             // remove from the selections
646             HashMap tempSelection = (HashMap) selectionChainsMap.get(
647                 currentSet);
648             tempSelection.remove(chainNode.toString());
649             selectionChainsMap.put(currentSet, tempSelection);
650 
651             // remove from the colors
652             HashMap tempColors = (HashMap) colorChainsMap.get(currentSet);
653             tempColors.remove(chainNode.toString());
654             colorChainsMap.put(currentSet, currentColors);
655           }
656         }
657       }
658     }
659 
660     Iterator tempIter = annotSetsNamesMap.keySet().iterator();
661     while (tempIter.hasNext()) {
662       String currentSet = (String) tempIter.next();
663       if (! ( (Boolean) annotSetsNamesMap.get(currentSet)).booleanValue()) {
664         String annotSet = currentSet;
665         // find out the currently Selected annotationSetName
666         String annotSetName = (String) annotSets.getSelectedItem();
667         // remove it from the main data store
668         corefChains.remove(corefAnnotationSetNodesMap.get(annotSet));
669         // remove it from the main data store
670         corefAnnotationSetNodesMap.remove(annotSet);
671         // remove it from the annotationSetModel (combobox)
672         annotSetsModel.removeElement(annotSet);
673         annotSets.setModel(annotSetsModel);
674         annotSets.updateUI();
675         // remove it from the colorChainMap
676         colorChainsMap.remove(annotSet);
677         // remove it from the selectionChainMap
678         selectionChainsMap.remove(annotSet);
679       }
680     }
681 
682     if (annotSetsModel.getSize() == 0) {
683       // no annotationSet to display
684       // so set visible false
685       if (popupWindow != null && popupWindow.isVisible()) {
686         popupWindow.setVisible(false);
687       }
688       corefTree.setVisible(false);
689 
690       // remove all highlights
691       ArrayList allHighlights = new ArrayList();
692       if(typeSpecificHighlightedTags != null)
693         allHighlights.addAll(typeSpecificHighlightedTags);
694       if(highlightedTags != null) {
695         Iterator iter = highlightedTags.values().iterator();
696         while(iter.hasNext()) {
697           ArrayList highlights = (ArrayList) iter.next();
698           allHighlights.addAll(highlights);
699         }
700       }
701       for(int i=0;i<allHighlights.size();i++) {
702         highlighter.removeHighlight(allHighlights.get(i));
703       }
704 
705       //highlighter.removeAllHighlights();
706       highlightedTags = null;
707       typeSpecificHighlightedTags = null;
708       return;
709     }
710     else {
711 
712       if (popupWindow != null && popupWindow.isVisible()) {
713         popupWindow.setVisible(false);
714       }
715 
716       // remove all highlights
717       ArrayList allHighlights = new ArrayList();
718       if(typeSpecificHighlightedTags != null)
719         allHighlights.addAll(typeSpecificHighlightedTags);
720       if(highlightedTags != null) {
721         Iterator iter = highlightedTags.values().iterator();
722         while(iter.hasNext()) {
723           ArrayList highlights = (ArrayList) iter.next();
724           allHighlights.addAll(highlights);
725         }
726       }
727       for (int i = 0; i < allHighlights.size(); i++) {
728         highlighter.removeHighlight(allHighlights.get(i));
729       }
730 
731       //highlighter.removeAllHighlights();
732       highlightedTags = null;
733       typeSpecificHighlightedTags = null;
734       if (currentAnnotSet != null) {
735         annotSets.setSelectedItem(currentAnnotSet);
736         currentSelections = (HashMap) selectionChainsMap.get(currentAnnotSet);
737         currentColors = (HashMap) colorChainsMap.get(currentAnnotSet);
738         highlightAnnotations();
739 
740         showAnnotations.setSelected(currentShowAnnotationStatus);
741         if (currentAnnotType != null)
742           annotTypes.setSelectedItem(currentAnnotType);
743         else
744         if (annotTypes.getModel().getSize() > 0) {
745           annotTypes.setSelectedIndex(0);
746         }
747       }
748       else {
749         explicitCall = false;
750         annotSets.setSelectedIndex(0);
751       }
752     }
753   }
754 
755   /**
756    * ActionPerformed Activity
757    * @param ae
758    */
759   public void actionPerformed(ActionEvent ae) {
760     // when annotationSet value changes
761     if (ae.getSource() == annotSets) {
762       if (!explicitCall) {
763         annotSetSelectionChanged();
764       }
765     }
766     else if (ae.getSource() == showAnnotations) {
767       if (!explicitCall) {
768         showTypeWiseAnnotations();
769       }
770     }
771     else if (ae.getSource() == annotTypes) {
772       if (!explicitCall) {
773         if (typeSpecificHighlightedTags != null) {
774           for (int i = 0; i < typeSpecificHighlightedTags.size(); i++) {
775             highlighter.removeHighlight(typeSpecificHighlightedTags.get(i));
776           }
777         }
778         typeSpecificHighlightedTags = null;
779         showTypeWiseAnnotations();
780       }
781     }
782   }
783 
784   /**
785    * When user preses the show Toggle button, this will show up annotations
786    * of selected Type from selected AnnotationSet
787    */
788   private void showTypeWiseAnnotations() {
789     if (typeSpecificHighlightedTags == null) {
790       highlightedTypeAnnots = new ArrayList();
791       typeSpecificHighlightedTags = new ArrayList();
792     }
793 
794     if (showAnnotations.isSelected()) {
795       // get the annotationsSet and its type
796       AnnotationSet set = getAnnotationSet( (String) annotSets.getSelectedItem());
797       String type = (String) annotTypes.getSelectedItem();
798       if (type == null) {
799         try {
800           JOptionPane.showMessageDialog(Main.getMainFrame(),
801                                         "No annotation type found to display");
802         }
803         catch (Exception e) {
804           e.printStackTrace();
805         }
806         showAnnotations.setSelected(false);
807         return;
808       }
809 
810       Color color = getColor(type);
811       if (type != null) {
812         AnnotationSet typeSet = set.get(type);
813         Iterator iter = typeSet.iterator();
814         while (iter.hasNext()) {
815           Annotation ann = (Annotation) iter.next();
816           highlightedTypeAnnots.add(ann);
817           try {
818             typeSpecificHighlightedTags.add(highlighter.addHighlight(ann.
819                 getStartNode().
820                 getOffset().intValue(),
821                 ann.getEndNode().getOffset().intValue(),
822                 new DefaultHighlighter.
823                 DefaultHighlightPainter(color)));
824           }
825           catch (Exception e) {
826             e.printStackTrace();
827           }
828           //typeSpecificHighlightedTags.add(textView.addHighlight(ann, getAnnotationSet((String)annotSets.getSelectedItem()),color));
829         }
830       }
831     }
832     else {
833       for (int i = 0; i < typeSpecificHighlightedTags.size(); i++) {
834         //textView.removeHighlight(typeSpecificHighlightedTags.get(i));
835         highlighter.removeHighlight(typeSpecificHighlightedTags.get(i));
836       }
837       typeSpecificHighlightedTags = new ArrayList();
838       highlightedTypeAnnots = new ArrayList();
839       highlightedTypeAnnotsOffsets = null;
840     }
841 
842     // This is to make process faster.. instead of accessing each annotation and
843     // its offset, we create an array with its annotation offsets to search faster
844     Collections.sort(highlightedTypeAnnots, new gate.util.OffsetComparator());
845     highlightedTypeAnnotsOffsets = new int[highlightedTypeAnnots.size() * 2];
846     for (int i = 0, j = 0; j < highlightedTypeAnnots.size(); i += 2, j++) {
847       Annotation ann1 = (Annotation) highlightedTypeAnnots.get(j);
848       highlightedTypeAnnotsOffsets[i] = ann1.getStartNode().getOffset().
849                                         intValue();
850       highlightedTypeAnnotsOffsets[i +
851           1] = ann1.getEndNode().getOffset().intValue();
852     }
853 
854   }
855 
856   /**
857    * Returns annotation Set
858    * @param annotSet
859    * @return
860    */
861   private AnnotationSet getAnnotationSet(String annotSet) {
862     return (annotSet.equals(DEFAULT_ANNOTSET_NAME)) ? document.getAnnotations() :
863         document.getAnnotations(annotSet);
864   }
865 
866   /**
867    * When annotationSet selection changes
868    */
869   private void annotSetSelectionChanged() {
870     if (annotSets.getModel().getSize() == 0) {
871       if (popupWindow != null && popupWindow.isVisible()) {
872         popupWindow.setVisible(false);
873       }
874       corefTree.setVisible(false);
875       return;
876     }
877 
878     String currentAnnotSet = (String) annotSets.getSelectedItem();
879     // get all the types of the currently Selected AnnotationSet
880     if (currentAnnotSet == null)
881       currentAnnotSet = (String) annotSets.getItemAt(0);
882     AnnotationSet temp = getAnnotationSet(currentAnnotSet);
883     Set types = temp.getAllTypes();
884     annotTypesModel = new DefaultComboBoxModel();
885     if (types != null) {
886       annotTypesModel = new DefaultComboBoxModel(types.toArray());
887     }
888     annotTypes.setModel(annotTypesModel);
889     annotTypes.updateUI();
890 
891     // and redraw the CorefTree
892     if (rootNode.getChildCount() > 0)
893       rootNode.removeAllChildren();
894 
895     CorefTreeNode annotSetNode = (CorefTreeNode) corefAnnotationSetNodesMap.get(
896         currentAnnotSet);
897 
898     if (annotSetNode != null) {
899       rootNode.add(annotSetNode);
900       currentSelections = (HashMap) selectionChainsMap.get(currentAnnotSet);
901       currentColors = (HashMap) colorChainsMap.get(currentAnnotSet);
902       if (!corefTree.isVisible()) {
903         if (popupWindow != null && popupWindow.isVisible()) {
904           popupWindow.setVisible(false);
905         }
906         corefTree.setVisible(true);
907       }
908       corefTree.repaint();
909       corefTree.updateUI();
910 
911     }
912     else {
913       corefTree.setVisible(false);
914     }
915   }
916 
917   /**
918    * This will initialise the data
919    */
920   private void initData() {
921 
922     rootNode = new CorefTreeNode("Co-reference Data", true,
923                                  CorefTreeNode.ROOT_NODE);
924     corefChains = new HashMap();
925     selectionChainsMap = new HashMap();
926     currentSelections = new HashMap();
927     colorChainsMap = new HashMap();
928     currentColors = new HashMap();
929     corefAnnotationSetNodesMap = new HashMap();
930 
931     // now we need to findout the chains
932     // for the defaultAnnotationSet
933     CorefTreeNode annotSetNode = createChain(document.getAnnotations(), true);
934     if (annotSetNode != null) {
935       corefAnnotationSetNodesMap.put(DEFAULT_ANNOTSET_NAME, annotSetNode);
936     }
937 
938     // and for the rest AnnotationSets
939     Map annotSets = document.getNamedAnnotationSets();
940     if (annotSets != null) {
941       Iterator annotSetsIter = annotSets.keySet().iterator();
942       while (annotSetsIter.hasNext()) {
943         String annotSetName = (String) annotSetsIter.next();
944         annotSetNode = createChain(document.getAnnotations(annotSetName), false);
945         if (annotSetNode != null) {
946           corefAnnotationSetNodesMap.put(annotSetName, annotSetNode);
947         }
948       }
949     }
950   }
951 
952   /**
953    * Creates the internal data structure
954    * @param set
955    */
956   private CorefTreeNode createChain(AnnotationSet set, boolean isDefaultSet) {
957 
958     // create the node for setName
959     String setName = isDefaultSet ? DEFAULT_ANNOTSET_NAME : set.getName();
960     CorefTreeNode annotSetNode = new CorefTreeNode(setName, true,
961         CorefTreeNode.ANNOTSET_NODE);
962 
963     // see if this setName available in the annotSets
964     boolean found = false;
965     for (int i = 0; i < annotSets.getModel().getSize(); i++) {
966       if ( ( (String) annotSets.getModel().getElementAt(i)).equals(setName)) {
967         found = true;
968         break;
969       }
970     }
971     if (!found) {
972       explicitCall = true;
973       annotSets.addItem(setName);
974       explicitCall = false;
975     }
976 
977     // the internal datastructure
978     HashMap chainLinks = new HashMap();
979     HashMap selectionMap = new HashMap();
980     HashMap colorMap = new HashMap();
981 
982     // map for all the annotations with matches feature in it
983     Map matchesMap = null;
984     matchesMap = (Map) document.getFeatures().get(ANNIEConstants.
985                                                   DOCUMENT_COREF_FEATURE_NAME);
986 
987     // what if this map is null
988     if (matchesMap == null) {
989       corefChains.put(annotSetNode, chainLinks);
990       selectionChainsMap.put(setName, selectionMap);
991       colorChainsMap.put(setName, colorMap);
992       return annotSetNode;
993     }
994 
995     //AnnotationSetName --> List of ArrayLists
996     //each ArrayList contains Ids of related annotations
997     Iterator setIter = matchesMap.keySet().iterator();
998     java.util.List matches1 = (java.util.List) matchesMap.get(isDefaultSet ? null :
999         setName);
1000    if (matches1 == null) {
1001      corefChains.put(annotSetNode, chainLinks);
1002      selectionChainsMap.put(setName, selectionMap);
1003      colorChainsMap.put(setName, colorMap);
1004      return annotSetNode;
1005    }
1006
1007    Iterator tempIter = matches1.iterator();
1008
1009    while (tempIter.hasNext()) {
1010      ArrayList matches = (ArrayList) tempIter.next();
1011      int length = 0;
1012      int index = 0;
1013      if (matches == null)
1014        matches = new ArrayList();
1015      if (matches.size() > 0) {
1016
1017        String longestString = getString( (Annotation)
1018                                         findOutTheLongestAnnotation(matches,
1019            set));
1020        // so this should become one of the tree node
1021        CorefTreeNode chainNode = new CorefTreeNode(longestString, false,
1022            CorefTreeNode.CHAIN_NODE);
1023        // and add it under the topNode
1024        annotSetNode.add(chainNode);
1025
1026        // chainNode --> All related annotIds
1027        chainLinks.put(chainNode, matches);
1028        selectionMap.put(chainNode.toString(), new Boolean(false));
1029        // and generate the color for this chainNode
1030        float components[] = colorGenerator.getNextColor().getComponents(null);
1031        Color color = new Color(components[0],
1032                                components[1],
1033                                components[2],
1034                                0.5f);
1035        colorMap.put(chainNode.toString(), color);
1036      }
1037    }
1038
1039    corefChains.put(annotSetNode, chainLinks);
1040    selectionChainsMap.put(setName, selectionMap);
1041    colorChainsMap.put(setName, colorMap);
1042    return annotSetNode;
1043  }
1044
1045  /**
1046   * Given an annotation, this method returns the string of that annotation
1047   * @param ann
1048   * @return
1049   */
1050  public String getString(Annotation ann) {
1051    return document.getContent().toString().substring(ann.
1052        getStartNode().getOffset().intValue(),
1053        ann.getEndNode().getOffset().intValue());
1054  }
1055
1056  /**
1057       * This method removes the reference of this annotatation from the current chain
1058   * @param ann
1059   */
1060  public void removeChainReference(Annotation annot, CorefTreeNode chainHead) {
1061
1062    // so we would find out the matches
1063    CorefTreeNode currentNode = chainHead;
1064    ArrayList ids = (ArrayList) ( (HashMap)
1065                                 corefChains.get(corefAnnotationSetNodesMap.get(
1066        annotSets.getSelectedItem()))).get(chainHead);
1067    // we need to update the Co-reference document feature
1068    Map matchesMap = null;
1069    matchesMap = (Map) document.getFeatures().get(ANNIEConstants.
1070                                                  DOCUMENT_COREF_FEATURE_NAME);
1071    String currentSet = (String) annotSets.getSelectedItem();
1072    currentSet = (currentSet.equals(DEFAULT_ANNOTSET_NAME)) ? null : currentSet;
1073    java.util.List matches = (java.util.List) matchesMap.get(currentSet);
1074    if (matches == null)
1075      matches = new ArrayList();
1076    int index = matches.indexOf(ids);
1077    if (index != -1) {
1078      // yes found
1079      ids.remove(annot.getId());
1080      Annotation ann = findOutTheLongestAnnotation(ids,
1081          getAnnotationSet( (String) annotSets.getSelectedItem()));
1082
1083      matches.set(index, ids);
1084      matchesMap.put(currentSet, matches);
1085      document.getFeatures().put(ANNIEConstants.DOCUMENT_COREF_FEATURE_NAME,
1086                                 matchesMap);
1087    }
1088  }
1089
1090  /**
1091   * Given an annotation, this will find out the chainHead
1092   * @param ann
1093   * @return
1094   */
1095  private CorefTreeNode findOutTheChainHead(Annotation ann) {
1096    HashMap chains = (HashMap) corefChains.get(corefAnnotationSetNodesMap.get(
1097        annotSets.getSelectedItem()));
1098    if (chains == null)
1099      return null;
1100    Iterator iter = chains.keySet().iterator();
1101    while (iter.hasNext()) {
1102      CorefTreeNode head = (CorefTreeNode) iter.next();
1103      if ( ( (ArrayList) chains.get(head)).contains(ann.getId())) {
1104        return head;
1105      }
1106    }
1107    return null;
1108  }
1109
1110  /**
1111   * This methods highlights the annotations
1112   */
1113  public void highlightAnnotations() {
1114
1115    if (highlightedTags == null) {
1116      highlightedTags = new HashMap();
1117      highlightedChainAnnots = new ArrayList();
1118    }
1119
1120    AnnotationSet annotSet = getAnnotationSet( (String) annotSets.
1121                                              getSelectedItem());
1122    CorefTreeNode annotSetNode = (CorefTreeNode) corefAnnotationSetNodesMap.get(
1123        annotSets.getSelectedItem());
1124    if (annotSetNode == null) {
1125      return;
1126    }
1127    HashMap chainMap = (HashMap) corefChains.get(annotSetNode);
1128    Iterator iter = chainMap.keySet().iterator();
1129
1130    while (iter.hasNext()) {
1131      CorefTreeNode currentNode = (CorefTreeNode) iter.next();
1132      if ( ( (Boolean) currentSelections.get(currentNode.toString())).
1133          booleanValue()) {
1134        if (!highlightedTags.containsKey(currentNode)) {
1135          // find out the arrayList
1136          ArrayList ids = (ArrayList) chainMap.get(currentNode);
1137          ArrayList highlighTag = new ArrayList();
1138          if (ids != null) {
1139            for (int i = 0; i < ids.size(); i++) {
1140              Annotation ann = annotSet.get( (Integer) ids.get(i));
1141              highlightedChainAnnots.add(ann);
1142              Color color = (Color) currentColors.get(currentNode.toString());
1143              try {
1144                highlighTag.add(highlighter.addHighlight(ann.getStartNode().
1145                    getOffset().intValue(),
1146                    ann.getEndNode().getOffset().intValue(),
1147                    new DefaultHighlighter.
1148                    DefaultHighlightPainter(color)));
1149              }
1150              catch (Exception e) {
1151                e.printStackTrace();
1152              }
1153              //highlighTag.add(textView.addHighlight(ann, getAnnotationSet((String) annotSets.getSelectedItem()), color));
1154            }
1155            highlightedTags.put(currentNode, highlighTag);
1156          }
1157        }
1158      }
1159      else {
1160        if (highlightedTags.containsKey(currentNode)) {
1161          ArrayList highlights = (ArrayList) highlightedTags.get(currentNode);
1162          for (int i = 0; i < highlights.size(); i++) {
1163            //textView.removeHighlight(highlights.get(i));
1164            highlighter.removeHighlight(highlights.get(i));
1165          }
1166          highlightedTags.remove(currentNode);
1167          ArrayList ids = (ArrayList) chainMap.get(currentNode);
1168          if (ids != null) {
1169            for (int i = 0; i < ids.size(); i++) {
1170              Annotation ann = annotSet.get( (Integer) ids.get(i));
1171              highlightedChainAnnots.remove(ann);
1172            }
1173          }
1174        }
1175      }
1176    }
1177
1178    // This is to make process faster.. instead of accessing each annotation and
1179    // its offset, we create an array with its annotation offsets to search faster
1180    Collections.sort(highlightedChainAnnots, new gate.util.OffsetComparator());
1181    highlightedChainAnnotsOffsets = new int[highlightedChainAnnots.size() * 2];
1182    for (int i = 0, j = 0; j < highlightedChainAnnots.size(); i += 2, j++) {
1183      Annotation ann1 = (Annotation) highlightedChainAnnots.get(j);
1184      highlightedChainAnnotsOffsets[i] = ann1.getStartNode().getOffset().
1185                                         intValue();
1186      highlightedChainAnnotsOffsets[i +
1187          1] = ann1.getEndNode().getOffset().intValue();
1188    }
1189  }
1190
1191  protected void registerHooks() {
1192    textPane.addMouseListener(textPaneMouseListener);
1193    textPane.addMouseMotionListener(textPaneMouseListener);
1194
1195  }
1196
1197  protected void unregisterHooks() {
1198    textPane.removeMouseListener(textPaneMouseListener);
1199    textPane.removeMouseMotionListener(textPaneMouseListener);
1200  }
1201
1202  public Component getGUI() {
1203    return mainPanel;
1204  }
1205
1206  public int getType() {
1207    return VERTICAL;
1208  }
1209
1210  //**********************************************
1211   // MouseListener and MouseMotionListener Methods
1212   //***********************************************
1213
1214    protected class TextPaneMouseListener
1215        extends MouseInputAdapter {
1216
1217      public TextPaneMouseListener() {
1218        chainToolTipTimer.setRepeats(false);
1219        newCorefActionTimer.setRepeats(false);
1220      }
1221
1222      public void mouseMoved(MouseEvent me) {
1223        int textLocation = textPane.viewToModel(me.getPoint());
1224        chainToolTipAction.setTextLocation(textLocation);
1225        chainToolTipAction.setMousePointer(me.getPoint());
1226        chainToolTipTimer.restart();
1227
1228        newCorefAction.setTextLocation(textLocation);
1229        newCorefAction.setMousePointer(me.getPoint());
1230        newCorefActionTimer.restart();
1231      }
1232    }
1233
1234  public void mouseClicked(MouseEvent me) {
1235    if (popupWindow != null && popupWindow.isVisible()) {
1236      popupWindow.setVisible(false);
1237    }
1238  }
1239
1240  public CorefTreeNode findOutChainNode(String chainNodeString) {
1241    if (corefChains == null || corefAnnotationSetNodesMap == null) {
1242      return null;
1243    }
1244    HashMap chains = (HashMap) corefChains.get(corefAnnotationSetNodesMap.get(
1245        annotSets.getSelectedItem()));
1246    if (chains == null) {
1247      return null;
1248    }
1249    Iterator iter = chains.keySet().iterator();
1250    while (iter.hasNext()) {
1251      CorefTreeNode currentNode = (CorefTreeNode) iter.next();
1252      if (currentNode.toString().equals(chainNodeString))
1253        return currentNode;
1254    }
1255    return null;
1256  }
1257
1258  /**
1259   * When user hovers over the annotations which have been highlighted by
1260   * show button
1261   */
1262  protected class NewCorefAction
1263      implements ActionListener {
1264
1265    int textLocation;
1266    Point mousePoint;
1267    JLabel label = new JLabel();
1268    JPanel panel = new JPanel();
1269    JPanel subPanel = new JPanel();
1270    String field = "";
1271    JButton add = new JButton("OK");
1272    JButton cancel = new JButton("Cancel");
1273    JComboBox list = new JComboBox();
1274    JPanel mainPanel = new JPanel();
1275    JPopupMenu popup1 = new JPopupMenu();
1276    ListEditor listEditor = null;
1277    ComboBoxModel model = new DefaultComboBoxModel();
1278    boolean firstTime = true;
1279
1280    public NewCorefAction() {
1281      popupWindow = new JWindow(SwingUtilities.getWindowAncestor(textView.
1282          getGUI()));
1283      popupWindow.setBackground(UIManager.getLookAndFeelDefaults().
1284                                getColor("ToolTip.background"));
1285      mainPanel.setLayout(new BorderLayout());
1286      mainPanel.setOpaque(true);
1287      mainPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
1288      mainPanel.setBackground(UIManager.getLookAndFeelDefaults().
1289                              getColor("ToolTip.background"));
1290      popupWindow.setContentPane(mainPanel);
1291
1292      panel.setLayout(new BorderLayout());
1293      panel.setOpaque(false);
1294      panel.add(new JScrollPane(list), BorderLayout.CENTER);
1295
1296      subPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
1297      subPanel.add(add);
1298      subPanel.add(cancel);
1299      subPanel.setOpaque(false);
1300      panel.add(subPanel, BorderLayout.SOUTH);
1301      mainPanel.add(label, BorderLayout.NORTH);
1302      mainPanel.add(panel, BorderLayout.CENTER);
1303
1304      // and finally load the data for the list
1305      AddAction action = new AddAction();
1306      add.addActionListener(action);
1307      cancel.addActionListener(action);
1308      listEditor = new ListEditor(action);
1309      list.setMaximumRowCount(5);
1310      list.setEditable(true);
1311      list.setEditor(listEditor);
1312      list.setModel(model);
1313    }
1314
1315    public void actionPerformed(ActionEvent ae) {
1316      int index = -1;
1317      if (highlightedChainAnnotsOffsets != null) {
1318        for (int i = 0; i < highlightedChainAnnotsOffsets.length; i += 2) {
1319          if (textLocation >= highlightedChainAnnotsOffsets[i] &&
1320              textLocation <= highlightedChainAnnotsOffsets[i + 1]) {
1321            index = (i == 0) ? i : i / 2;
1322            break;
1323          }
1324        }
1325      }
1326
1327      // yes it is put on highlighted so show the annotationType
1328      if (highlightedChainAnnotsOffsets != null &&
1329          index < highlightedChainAnnotsOffsets.length && index >= 0) {
1330        return;
1331      }
1332
1333      if (highlightedTypeAnnotsOffsets != null) {
1334        for (int i = 0; i < highlightedTypeAnnotsOffsets.length; i += 2) {
1335          if (textLocation >= highlightedTypeAnnotsOffsets[i] &&
1336              textLocation <= highlightedTypeAnnotsOffsets[i + 1]) {
1337            index = (i == 0) ? i : i / 2;
1338            break;
1339          }
1340        }
1341      }
1342
1343      // yes it is put on highlighted so show the annotationType
1344      if (highlightedTypeAnnotsOffsets != null &&
1345          index < highlightedTypeAnnotsOffsets.length && index >= 0) {
1346        textPane.removeAll();
1347        annotToConsiderForChain = (Annotation) highlightedTypeAnnots.get(index);
1348        // now check if this annotation is already linked with something
1349        CorefTreeNode headNode = findOutTheChainHead(annotToConsiderForChain);
1350        if (headNode != null) {
1351          popup1 = new JPopupMenu();
1352          popup1.setBackground(UIManager.getLookAndFeelDefaults().
1353                               getColor("ToolTip.background"));
1354          JLabel label1 = new JLabel("Annotation co-referenced to : \"" +
1355                                     headNode.toString() + "\"");
1356          popup1.setLayout(new FlowLayout());
1357          popup1.add(label1);
1358          if (popupWindow != null && popupWindow.isVisible()) {
1359            popupWindow.setVisible(false);
1360          }
1361          popup1.setVisible(true);
1362          popup1.show(textPane, (int) mousePoint.getX(), (int) mousePoint.getY());
1363        }
1364        else {
1365          popupWindow.setVisible(false);
1366          ArrayList set = new ArrayList(currentSelections.keySet());
1367          Collections.sort(set);
1368          set.add(0, "[New Chain]");
1369          model = new DefaultComboBoxModel(set.toArray());
1370          list.setModel(model);
1371          listEditor.setItem("");
1372          label.setText("Add \"" + getString(annotToConsiderForChain) +
1373                        "\" to ");
1374          Point topLeft = textPane.getLocationOnScreen();
1375          int x = topLeft.x + (int) mousePoint.getX();
1376          int y = topLeft.y + (int) mousePoint.getY();
1377          popupWindow.setLocation(x, y);
1378          if (popup1.isVisible()) {
1379            popup1.setVisible(false);
1380          }
1381          popupWindow.pack();
1382          popupWindow.setVisible(true);
1383          listEditor.requestFocus();
1384
1385          if (firstTime) {
1386            firstTime = false;
1387            popupWindow.pack();
1388            popupWindow.repaint();
1389            listEditor.requestFocus();
1390          }
1391        }
1392      }
1393    }
1394
1395    public void setTextLocation(int textLocation) {
1396      this.textLocation = textLocation;
1397    }
1398
1399    public void setMousePointer(Point point) {
1400      this.mousePoint = point;
1401    }
1402
1403    /** Custom Editor for the ComboBox to enable key events */
1404    private class ListEditor
1405        extends KeyAdapter
1406        implements ComboBoxEditor {
1407      JTextField myField = new JTextField(20);
1408      AddAction action = null;
1409      Vector myList = new Vector();
1410
1411      public ListEditor(AddAction action) {
1412        this.action = action;
1413        myField.addKeyListener(this);
1414      }
1415
1416      public void addActionListener(ActionListener al) {
1417        myField.addActionListener(al);
1418      }
1419
1420      public void removeActionListener(ActionListener al) {
1421        myField.removeActionListener(al);
1422      }
1423
1424      public Component getEditorComponent() {
1425        return myField;
1426      }
1427
1428      public Object getItem() {
1429        return myField.getText();
1430      }
1431
1432      public void selectAll() {
1433        if (myField.getText() != null && myField.getText().length() > 0) {
1434          myField.setSelectionStart(0);
1435          myField.setSelectionEnd(myField.getText().length());
1436        }
1437      }
1438
1439      public void setItem(Object item) {
1440        myField.setText( (String) item);
1441        field = myField.getText();
1442      }
1443
1444      public void requestFocus() {
1445        myField.requestFocus();
1446      }
1447
1448      public void keyReleased(KeyEvent ke) {
1449        if (myField.getText() == null) {
1450          myField.setText("");
1451          field = myField.getText();
1452        }
1453
1454        if (ke.getKeyCode() == KeyEvent.VK_DOWN) {
1455          if (myList.size() == 1) {
1456            myField.setText( (String) myList.get(0));
1457          }
1458          else if (list.getSelectedIndex() < list.getModel().getSize() - 1) {
1459            list.setSelectedIndex(list.getSelectedIndex());
1460            myField.setText( (String) list.getSelectedItem());
1461          }
1462          field = myField.getText();
1463          myField.requestFocus();
1464          return;
1465        }
1466        else if (ke.getKeyCode() == KeyEvent.VK_UP) {
1467          if (list.getSelectedIndex() > 0) {
1468            list.setSelectedIndex(list.getSelectedIndex());
1469          }
1470          myField.setText( (String) list.getSelectedItem());
1471          field = myField.getText();
1472          return;
1473        }
1474        else if (ke.getKeyCode() == KeyEvent.VK_ENTER) {
1475          field = myField.getText();
1476          action.actionPerformed(new ActionEvent(add,
1477                                                 ActionEvent.ACTION_PERFORMED,
1478                                                 "add"));
1479          return;
1480        }
1481        else if (ke.getKeyCode() == KeyEvent.VK_BACK_SPACE) {
1482        }
1483        else if (Character.isJavaLetterOrDigit(ke.getKeyChar()) ||
1484                 Character.isSpaceChar(ke.getKeyChar()) ||
1485                 Character.isDefined(ke.getKeyChar())) {
1486        }
1487        else {
1488          return;
1489        }
1490
1491        String startWith = myField.getText();
1492        myList = new Vector();
1493        ArrayList set = new ArrayList(currentSelections.keySet());
1494        Collections.sort(set);
1495        set.add(0, "[New Chain]");
1496        boolean first = true;
1497        for (int i = 0; i < set.size(); i++) {
1498          String currString = (String) set.get(i);
1499          if (currString.toLowerCase().startsWith(startWith.toLowerCase())) {
1500            if (first) {
1501              myField.setText(currString.substring(0, startWith.length()));
1502              first = false;
1503            }
1504            myList.add(currString);
1505          }
1506        }
1507        ComboBoxModel model = new DefaultComboBoxModel(myList);
1508        list.setModel(model);
1509        myField.setText(startWith);
1510        field = myField.getText();
1511        list.showPopup();
1512      }
1513    }
1514
1515    private class AddAction
1516        extends AbstractAction {
1517      public void actionPerformed(ActionEvent ae) {
1518        if (ae.getSource() == cancel) {
1519          popupWindow.setVisible(false);
1520          return;
1521        }
1522        else if (ae.getSource() == add) {
1523          if (field.length() == 0) {
1524            try {
1525              JOptionPane.showMessageDialog(Main.getMainFrame(),
1526                                            "No Chain Selected",
1527                                            "New Chain - Error",
1528                                            JOptionPane.ERROR_MESSAGE);
1529            }
1530            catch (Exception e) {
1531              e.printStackTrace();
1532            }
1533            return;
1534          }
1535          else {
1536            // we want to add this
1537            // now first find out the annotation
1538            Annotation ann = annotToConsiderForChain;
1539            if (ann == null)
1540              return;
1541            // yes it is available
1542            // find out the CorefTreeNode for the chain under which it is to be inserted
1543            if (field.equals("[New Chain]")) {
1544              // we want to add this
1545              // now first find out the annotation
1546              if (ann == null)
1547                return;
1548              CorefTreeNode chainNode = findOutChainNode(getString(ann));
1549              if (chainNode != null) {
1550                try {
1551                  JOptionPane.showMessageDialog(Main.getMainFrame(),
1552                                                "Chain with " + getString(ann) +
1553                                                " title already exists",
1554                                                "New Chain - Error",
1555                                                JOptionPane.ERROR_MESSAGE);
1556                }
1557                catch (Exception e) {
1558                  e.printStackTrace();
1559                }
1560                return;
1561              }
1562
1563              popupWindow.setVisible(false);
1564
1565              Map matchesMap = null;
1566              matchesMap = (Map) document.getFeatures().get(ANNIEConstants.
1567                  DOCUMENT_COREF_FEATURE_NAME);
1568              String currentSet = (String) annotSets.getSelectedItem();
1569              currentSet = (currentSet.equals(DEFAULT_ANNOTSET_NAME)) ? null :
1570                           currentSet;
1571              if (matchesMap == null) {
1572                matchesMap = new HashMap();
1573              }
1574              java.util.List matches = (java.util.List) matchesMap.get(
1575                  currentSet);
1576              ArrayList tempList = new ArrayList();
1577              tempList.add(ann.getId());
1578              if (matches == null)
1579                matches = new ArrayList();
1580              matches.add(tempList);
1581              matchesMap.put(currentSet, matches);
1582              document.getFeatures().put(ANNIEConstants.
1583                                         DOCUMENT_COREF_FEATURE_NAME,
1584                                         matchesMap);
1585              return;
1586            }
1587
1588            CorefTreeNode chainNode = findOutChainNode(field);
1589            HashMap chains = (HashMap)
1590                             corefChains.get(corefAnnotationSetNodesMap.get(
1591                annotSets.getSelectedItem()));
1592            if (chainNode == null) {
1593              try {
1594                JOptionPane.showMessageDialog(Main.getMainFrame(),
1595                                              "Incorrect Chain Title",
1596                                              "New Chain - Error",
1597                                              JOptionPane.ERROR_MESSAGE);
1598              }
1599              catch (Exception e) {
1600                e.printStackTrace();
1601              }
1602              return;
1603            }
1604            popupWindow.setVisible(false);
1605            ArrayList ids = (ArrayList) chains.get(chainNode);
1606
1607            Map matchesMap = null;
1608            matchesMap = (Map) document.getFeatures().get(ANNIEConstants.
1609                DOCUMENT_COREF_FEATURE_NAME);
1610            if (matchesMap == null) {
1611              matchesMap = new HashMap();
1612            }
1613            String currentSet = (String) annotSets.getSelectedItem();
1614            currentSet = (currentSet.equals(DEFAULT_ANNOTSET_NAME)) ? null :
1615                         currentSet;
1616            java.util.List matches = (java.util.List) matchesMap.get(currentSet);
1617            if (matches == null)
1618              matches = new ArrayList();
1619            int index = matches.indexOf(ids);
1620            if (index != -1) {
1621              ArrayList tempIds = (ArrayList) matches.get(index);
1622              tempIds.add(ann.getId());
1623              matches.set(index, tempIds);
1624              matchesMap.put(currentSet, matches);
1625              document.getFeatures().put(ANNIEConstants.
1626                                         DOCUMENT_COREF_FEATURE_NAME,
1627                                         matchesMap);
1628            }
1629            return;
1630          }
1631        }
1632      }
1633    }
1634  }
1635
1636  /** When user hovers over the chainnodes */
1637  protected class ChainToolTipAction
1638      extends AbstractAction {
1639
1640    int textLocation;
1641    Point mousePoint;
1642    JPopupMenu popup = new JPopupMenu();
1643
1644    public ChainToolTipAction() {
1645      popup.setBackground(UIManager.getLookAndFeelDefaults().
1646                          getColor("ToolTip.background"));
1647    }
1648
1649    public void actionPerformed(ActionEvent ae) {
1650
1651      int index = -1;
1652      if (highlightedChainAnnotsOffsets != null) {
1653        for (int i = 0; i < highlightedChainAnnotsOffsets.length; i += 2) {
1654          if (textLocation >= highlightedChainAnnotsOffsets[i] &&
1655              textLocation <= highlightedChainAnnotsOffsets[i + 1]) {
1656            index = (i == 0) ? i : i / 2;
1657            break;
1658          }
1659        }
1660      }
1661
1662      // yes it is put on highlighted so show the annotationType
1663      if (highlightedChainAnnotsOffsets != null &&
1664          index < highlightedChainAnnotsOffsets.length && index >= 0) {
1665
1666        if (popupWindow != null && popupWindow.isVisible()) {
1667          popupWindow.setVisible(false);
1668        }
1669
1670        popup.setVisible(false);
1671        popup.removeAll();
1672        final int tempIndex = index;
1673        CorefTreeNode chainHead = findOutTheChainHead( (Annotation)
1674            highlightedChainAnnots.get(index));
1675        final HashMap tempMap = new HashMap();
1676        popup.setLayout(new FlowLayout(FlowLayout.LEFT));
1677        if (chainHead != null) {
1678          JPanel tempPanel = new JPanel();
1679          tempPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
1680          tempPanel.add(new JLabel(chainHead.toString()));
1681          tempPanel.setBackground(UIManager.getLookAndFeelDefaults().
1682                                  getColor("ToolTip.background"));
1683          final JButton deleteButton = new JButton("Delete");
1684          tempPanel.add(deleteButton);
1685          popup.add(tempPanel);
1686          deleteButton.setActionCommand(chainHead.toString());
1687          tempMap.put(chainHead.toString(), chainHead);
1688          deleteButton.addActionListener(new ActionListener() {
1689            public void actionPerformed(ActionEvent ae) {
1690              try {
1691                int confirm = JOptionPane.showConfirmDialog(Main.getMainFrame(),
1692                    "Are you sure?", "Removing reference...",
1693                    JOptionPane.YES_NO_OPTION);
1694                if (confirm == JOptionPane.YES_OPTION) {
1695                  popup.setVisible(false);
1696                  // remove it
1697                  removeChainReference( (Annotation) highlightedChainAnnots.get(
1698                      tempIndex),
1699                      (CorefTreeNode) tempMap.get(deleteButton.getActionCommand()));
1700                }
1701              }
1702              catch (Exception e1) {
1703                e1.printStackTrace();
1704              }
1705            }
1706          });
1707        }
1708        //label.setText("Remove \""+getString((Annotation) highlightedChainAnnots.get(index)) + "\" from \""+ findOutTheChainHead((Annotation) highlightedChainAnnots.get(index)).toString()+"\"");
1709        popup.revalidate();
1710        if (popupWindow != null && popupWindow.isVisible()) {
1711          popupWindow.setVisible(false);
1712        }
1713        popup.setVisible(true);
1714        popup.show(textPane, (int) mousePoint.getX(), (int) mousePoint.getY());
1715      }
1716    }
1717
1718    public void setTextLocation(int textLocation) {
1719      this.textLocation = textLocation;
1720    }
1721
1722    public void setMousePointer(Point point) {
1723      this.mousePoint = point;
1724    }
1725
1726  }
1727
1728  // Class that represents each individual tree node in the corefTree
1729  protected class CorefTreeNode
1730      extends DefaultMutableTreeNode {
1731    public final static int ROOT_NODE = 0;
1732    public final static int ANNOTSET_NODE = 1;
1733    public final static int CHAIN_NODE = 2;
1734
1735    private int type;
1736
1737    public CorefTreeNode(Object value, boolean allowsChildren, int type) {
1738      super(value, allowsChildren);
1739      this.type = type;
1740    }
1741
1742    public int getType() {
1743      return this.type;
1744    }
1745
1746  }
1747
1748  /**
1749   * Action for mouseClick on the Tree
1750   */
1751  protected class CorefTreeMouseListener
1752      extends MouseAdapter {
1753
1754    public void mouseClicked(MouseEvent me) {
1755      if (popupWindow != null && popupWindow.isVisible()) {
1756        popupWindow.setVisible(false);
1757      }
1758      textPane.removeAll();
1759      // ok now find out the currently selected node
1760      int x = me.getX();
1761      int y = me.getY();
1762      int row = corefTree.getRowForLocation(x, y);
1763      TreePath path = corefTree.getPathForRow(row);
1764
1765      // let us expand it if the sibling feature is on
1766      if (path != null) {
1767        final CorefTreeNode node = (CorefTreeNode) path.
1768                                   getLastPathComponent();
1769
1770        // if it only chainNode
1771        if (node.getType() != CorefTreeNode.CHAIN_NODE)
1772          return;
1773
1774        // see if user clicked the right click
1775        if (me.getModifiers() == 4) {
1776          // it is right click
1777          // we need to show the popup window
1778          final JPopupMenu popup = new JPopupMenu();
1779          JButton delete = new JButton("Delete");
1780          delete.setToolTipText("Delete Chain");
1781          ToolTipManager.sharedInstance().registerComponent(delete);
1782          JButton cancel = new JButton("Close");
1783          cancel.setToolTipText("Closes this popup");
1784          JButton changeColor = new JButton("Change Color");
1785          changeColor.setToolTipText("Changes Color");
1786          ToolTipManager.sharedInstance().registerComponent(cancel);
1787          ToolTipManager.sharedInstance().registerComponent(changeColor);
1788          JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT));
1789          panel.setOpaque(false);
1790          panel.add(changeColor);
1791          panel.add(delete);
1792          panel.add(cancel);
1793          popup.setLayout(new BorderLayout());
1794          popup.setOpaque(true);
1795          popup.setBackground(UIManager.getLookAndFeelDefaults().
1796                              getColor("ToolTip.background"));
1797          popup.add(new JLabel("Chain \"" + node.toString() + "\""),
1798                    BorderLayout.NORTH);
1799          popup.add(panel, BorderLayout.SOUTH);
1800
1801          changeColor.addActionListener(new ActionListener() {
1802            public void actionPerformed(ActionEvent ae) {
1803              String currentAnnotSet = (String) annotSets.getSelectedItem();
1804              currentColors = (HashMap) colorChainsMap.get(currentAnnotSet);
1805              Color colour = (Color) currentColors.get(node.toString());
1806              Color col = JColorChooser.showDialog(getGUI(),
1807                  "Select colour for \"" + node.toString() + "\"",
1808                  colour);
1809              if (col != null) {
1810                Color colAlpha = new Color(col.getRed(), col.getGreen(),
1811                                           col.getBlue(), 128);
1812
1813                // make change in the datastructures
1814                currentColors.put(node.toString(),colAlpha);
1815                colorChainsMap.put(currentAnnotSet, currentColors);
1816                // and redraw the tree
1817                corefTree.repaint();
1818
1819                // remove all highlights
1820                ArrayList allHighlights = new ArrayList();
1821                if(typeSpecificHighlightedTags != null)
1822                  allHighlights.addAll(typeSpecificHighlightedTags);
1823                if(highlightedTags != null) {
1824                  Iterator iter = highlightedTags.values().iterator();
1825                  while(iter.hasNext()) {
1826                    ArrayList highlights = (ArrayList) iter.next();
1827                    allHighlights.addAll(highlights);
1828                  }
1829                }
1830                for (int i = 0; i < allHighlights.size(); i++) {
1831                  highlighter.removeHighlight(allHighlights.get(i));
1832                }
1833
1834                //highlighter.removeAllHighlights();
1835                highlightedTags = null;
1836                highlightAnnotations();
1837                typeSpecificHighlightedTags = null;
1838                showTypeWiseAnnotations();
1839              }
1840              popup.setVisible(false);
1841            }
1842          });
1843
1844          delete.addActionListener(new ActionListener() {
1845            public void actionPerformed(ActionEvent ae) {
1846              // get the ids of current chainNode
1847              HashMap chains = (HashMap)
1848                               corefChains.get(corefAnnotationSetNodesMap.get(
1849                  annotSets.getSelectedItem()));
1850              ArrayList ids = (ArrayList) chains.get(node);
1851              // now search this in the document feature map
1852              Map matchesMap = null;
1853              matchesMap = (Map) document.getFeatures().get(ANNIEConstants.
1854                  DOCUMENT_COREF_FEATURE_NAME);
1855              String currentSet = (String) annotSets.getSelectedItem();
1856              currentSet = (currentSet.equals(DEFAULT_ANNOTSET_NAME)) ? null :
1857                           currentSet;
1858              java.util.List matches = (java.util.List) matchesMap.get(
1859                  currentSet);
1860              if (matches == null)
1861                matches = new ArrayList();
1862              int index = matches.indexOf(ids);
1863              if (index != -1) {
1864                // yes found
1865                matches.remove(index);
1866                matchesMap.put(currentSet, matches);
1867                document.getFeatures().put(ANNIEConstants.
1868                                           DOCUMENT_COREF_FEATURE_NAME,
1869                                           matchesMap);
1870              }
1871              popup.setVisible(false);
1872            }
1873          });
1874
1875          cancel.addActionListener(new ActionListener() {
1876            public void actionPerformed(ActionEvent ae) {
1877              popup.setVisible(false);
1878            }
1879          });
1880          popup.setVisible(true);
1881          popup.show(corefTree, x, y);
1882          return;
1883        }
1884
1885        boolean isSelected = ! ( (Boolean) currentSelections.get(node.toString())).
1886                             booleanValue();
1887        currentSelections.put(node.toString(), new Boolean(isSelected));
1888
1889        // so now we need to highlight all the stuff
1890        highlightAnnotations();
1891        corefTree.repaint();
1892        corefTree.updateUI();
1893        corefTree.repaint();
1894        corefTree.updateUI();
1895
1896      }
1897    }
1898  }
1899
1900  /**
1901   * This method uses the java.util.prefs.Preferences and get the color
1902   * for particular annotationType.. This color could have been saved
1903   * by the AnnotationSetsView
1904   * @param annotationType
1905   * @return
1906   */
1907  private Color getColor(String annotationType) {
1908    java.util.prefs.Preferences prefRoot = null;
1909    try {
1910      prefRoot = java.util.prefs.Preferences.userNodeForPackage(Class.forName(
1911          "gate.gui.docview.AnnotationSetsView"));
1912    }
1913    catch (Exception e) {
1914      e.printStackTrace();
1915    }
1916    int rgba = prefRoot.getInt(annotationType, -1);
1917    Color colour;
1918    if (rgba == -1) {
1919      //initialise and save
1920      float components[] = colorGenerator.getNextColor().getComponents(null);
1921      colour = new Color(components[0],
1922                         components[1],
1923                         components[2],
1924                         0.5f);
1925      int rgb = colour.getRGB();
1926      int alpha = colour.getAlpha();
1927      rgba = rgb | (alpha << 24);
1928      prefRoot.putInt(annotationType, rgba);
1929
1930    }
1931    else {
1932      colour = new Color(rgba, true);
1933    }
1934    return colour;
1935  }
1936
1937  /**
1938   * Cell renderer to add the checkbox in the tree
1939   */
1940  protected class CorefTreeCellRenderer
1941      extends JPanel
1942      implements TreeCellRenderer {
1943
1944    private JCheckBox check;
1945    private JLabel label;
1946
1947    /**
1948     * Constructor
1949     * @param owner
1950     */
1951    public CorefTreeCellRenderer() {
1952      setOpaque(true);
1953      check = new JCheckBox();
1954      check.setBackground(Color.white);
1955      label = new JLabel();
1956      setLayout(new BorderLayout(5, 10));
1957      add(check, BorderLayout.WEST);
1958      add(label, BorderLayout.CENTER);
1959    }
1960
1961    /**
1962     * Renderer class
1963     */
1964    public Component getTreeCellRendererComponent(JTree tree, Object value,
1965                                                  boolean isSelected,
1966                                                  boolean expanded,
1967                                                  boolean leaf, int row,
1968                                                  boolean hasFocus) {
1969
1970      CorefTreeNode userObject = (CorefTreeNode) value;
1971      label.setText(userObject.toString());
1972      this.setSize(label.getWidth(),
1973                   label.getFontMetrics(label.getFont()).getHeight() * 2);
1974      tree.expandRow(row);
1975      if (userObject.getType() == CorefTreeNode.ROOT_NODE || userObject.getType() ==
1976          CorefTreeNode.ANNOTSET_NODE) {
1977        this.setBackground(Color.white);
1978        this.check.setVisible(false);
1979        return this;
1980      }
1981      else {
1982        this.setBackground( (Color) currentColors.get(userObject.toString()));
1983        check.setVisible(true);
1984        check.setBackground(Color.white);
1985      }
1986
1987      // if node should be selected
1988      boolean selected = ( (Boolean) currentSelections.get(userObject.toString())).
1989                         booleanValue();
1990      check.setSelected(selected);
1991      return this;
1992    }
1993  }
1994}