CorpusAnnotationDiff.java
0001 /*
0002  *  CorpusAnnotationDiff.java
0003  *
0004  *  Copyright (c) 1995-2010, The University of Sheffield. See the file
0005  *  COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
0006  *
0007  *  This file is part of GATE (see http://gate.ac.uk/), and is free
0008  *  software, licenced under the GNU Library General Public License,
0009  *  Version 2, June 1991 (in the distribution as file licence.html,
0010  *  and also available at http://gate.ac.uk/gate/licence.html).
0011  *
0012  *  Angel Kirilov (mod. AnnotationDiff), 22/Aug/2002
0013  *
0014  *  $Id: CorpusAnnotationDiff.java 12006 2009-12-01 17:24:28Z thomas_heitz $
0015  */
0016 
0017 package gate.annotation;
0018 
0019 import java.awt.*;
0020 import java.beans.BeanInfo;
0021 import java.beans.Introspector;
0022 import java.text.NumberFormat;
0023 import java.util.*;
0024 
0025 import javax.swing.*;
0026 import javax.swing.table.*;
0027 
0028 import gate.*;
0029 import gate.creole.*;
0030 import gate.swing.XJTable;
0031 import gate.util.*;
0032 
0033 /**
0034   * This class compare two annotation sets on annotation type given by the
0035   * AnnotationSchema object. It also deals with graphic representation of the
0036   * result.
0037   */
0038 public class CorpusAnnotationDiff extends AbstractVisualResource
0039   implements  Scrollable{
0040 
0041   // number of pixels to be used as increment by scroller
0042   protected int maxUnitIncrement = 10;
0043 
0044   /** Debug flag */
0045   private static final boolean DEBUG = false;
0046 
0047   /** This document contains the key annotation set which is taken as reference
0048    *  in comparison*/
0049   private Document keyDocument = null;
0050 
0051   /** This corpus contains the key annotation set which is taken as reference
0052    *  in comparison*/
0053   private Corpus keyCorpus = null;
0054   
0055   /** The name of the annotation set. If is null then the default annotation set
0056     * will be considered.
0057     */
0058   private String keyAnnotationSetName = null;
0059 
0060   /** This document contains the response annotation set which is being
0061     * compared against the key annotation set.
0062     */
0063   private Document responseDocument = null;
0064 
0065   /** This corpus contains the response annotation set which is being
0066     * compared against the key annotation set.
0067     */
0068   private Corpus responseCorpus = null;
0069 
0070   /** The name of the annotation set. If is null then the default annotation set
0071     * will be considered.
0072     */
0073   private String responseAnnotationSetName = null;
0074 
0075   /** The name of the annotation set considered in calculating FalsePozitive.
0076     * If is null then the default annotation set will be considered.
0077     */
0078   private String responseAnnotationSetNameFalsePoz = null;
0079 
0080   /** The annotation schema object used to get the annotation name*/
0081   private AnnotationSchema annotationSchema = null;
0082 
0083   /** A set of feature names bellonging to annotations from keyAnnotList
0084     * used in isCompatible() and isPartiallyCompatible() methods
0085     */
0086   private Set keyFeatureNamesSet = null;
0087 
0088   /** The precision strict value (see NLP Information Extraction)*/
0089   private double precisionStrict = 0.0;
0090   /** The precision lenient value (see NLP Information Extraction)*/
0091   private double precisionLenient = 0.0;
0092   /** The precision average value (see NLP Information Extraction)*/
0093   private double precisionAverage = 0.0;
0094 
0095   /** The Recall strict value (see NLP Information Extraction)*/
0096   private double recallStrict = 0.0;
0097   /** The Recall lenient value (see NLP Information Extraction)*/
0098   private double recallLenient = 0.0;
0099   /** The Recall average value (see NLP Information Extraction)*/
0100   private double recallAverage = 0.0;
0101 
0102   /** The False positive strict (see NLP Information Extraction)*/
0103   private double falsePositiveStrict = 0.0;
0104   /** The False positive lenient (see NLP Information Extraction)*/
0105   private double falsePositiveLenient = 0.0;
0106   /** The False positive average (see NLP Information Extraction)*/
0107   private double falsePositiveAverage = 0.0;
0108 
0109   /** The F-measure strict (see NLP Information Extraction)*/
0110   private double fMeasureStrict = 0.0;
0111   /** The F-measure lenient (see NLP Information Extraction)*/
0112   private double fMeasureLenient = 0.0;
0113   /** The F-measure average (see NLP Information Extraction)*/
0114   private double fMeasureAverage = 0.0;
0115   /** The weight used in F-measure (see NLP Information Extraction)*/
0116   public  static double weight = 0.5;
0117 
0118   /**  This string represents the type of annotations used to play the roll of
0119     *  total number of words needed to calculate the False Positive.
0120     */
0121   private String annotationTypeForFalsePositive = null;
0122 
0123   /** A number formater for displaying precision and recall*/
0124   protected static NumberFormat formatter = NumberFormat.getInstance();
0125 
0126   /** The components that will stay into diffPanel*/
0127   private XJTable diffTable = null;
0128 
0129   /** Used to represent the result of diff. See DiffSetElement class.*/
0130   private Set diffSet = null;
0131 
0132   /** This field is used in doDiff() and detectKeyType() methods and holds all
0133    *  partially correct keys */
0134   private Set keyPartiallySet = null;
0135   /** This field is used in doDiff() and detectResponseType() methods*/
0136   private Set responsePartiallySet = null;
0137 
0138   /** This list is created from keyAnnotationSet at init() time*/
0139   private java.util.List keyAnnotList = null;
0140   /** This list is created from responseAnnotationSet at init() time*/
0141   private java.util.List responseAnnotList = null;
0142 
0143   /** This field indicates wheter or not the annot diff should run int the text
0144    *  mode*/
0145   private boolean textMode = false;
0146 
0147   /**  Field designated to represent the max nr of annot types and coolors for
0148     *  each type
0149     **/
0150   public static final int MAX_TYPES = 5;
0151   /** A default type when all annotation are the same represented by White color*/
0152   public static final int DEFAULT_TYPE = 0;
0153   /** A correct type when all annotation are corect represented by Green color*/
0154   public static final int CORRECT_TYPE = 1;
0155   /** A partially correct type when all annotation are corect represented
0156    *  by Blue color*/
0157   public static final int PARTIALLY_CORRECT_TYPE = 2;
0158   /** A spurious type when annotations in response were not present in key.
0159    *  Represented by Red color*/
0160   public static final int SPURIOUS_TYPE = 3;
0161   /** A missing type when annotations in key were not present in response
0162    *  Represented by Yellow color*/
0163   public static final int MISSING_TYPE = 4;
0164 
0165   /** Red used for SPURIOUS_TYPE*/
0166   private  final Color RED = new Color(255,173,181);
0167   /** Green used for CORRECT_TYPE*/
0168   private  final Color GREEN = new Color(173,255,214);
0169   /** White used for DEFAULT_TYPE*/
0170   private  final Color WHITE = new Color(255,255,255);
0171   /** Blue used for PARTIALLY_CORRECT_TYPE*/
0172   private  final Color BLUE = new Color(173,215,255);
0173   /** Yellow used for MISSING_TYPE*/
0174   private  final Color YELLOW = new Color(255,231,173);
0175 
0176   /** Used in DiffSetElement to represent an empty raw in the table*/
0177   private final int NULL_TYPE = -1;
0178   /** Used in some setForeground() methods*/
0179   private  final Color BLACK = new Color(0,0,0);
0180   /** The array holding the colours according to the annotation types*/
0181   private Color colors[] new Color[MAX_TYPES];
0182 
0183   /** A scroll for the AnnotDiff's table*/
0184   private JScrollPane scrollPane = null;
0185 
0186   /** Used to store the no. of annotations from response,identified as belonging
0187     * to one of the previous types.
0188     */
0189   private int typeCounter[] new int[MAX_TYPES];
0190 
0191   /** Constructs a CorpusAnnotationDiff*/
0192   public CorpusAnnotationDiff(){
0193   //CorpusAnnotationDiff
0194 
0195   /** Sets the annotation type needed to calculate the falsePossitive measure
0196     @param anAnnotType is the annotation type needed to calculate a special
0197     *  mesure called falsePossitive. Usualy the value is "token", but it can be
0198     *  any other string with the same semantic.
0199     */
0200   public void setAnnotationTypeForFalsePositive(String anAnnotType){
0201     annotationTypeForFalsePositive = anAnnotType;
0202   // setAnnotationTypeForFalsePositive
0203 
0204   /** Gets the annotation type needed to calculate the falsePossitive measure
0205     @return annotation type needed to calculate a special
0206     * mesure called falsePossitive.
0207     */
0208   public String getAnnotationTypeForFalsePositive(){
0209     return annotationTypeForFalsePositive;
0210   // getAnnotationTypeForFalsePositive
0211 
0212   /** Sets the keyCorpus in AnnotDiff
0213     @param aKeyCorpus The GATE corpus used as a key in annotation diff.
0214     */
0215   public void setKeyCorpus(Corpus aKeyCorpus) {
0216     keyCorpus = aKeyCorpus;
0217   // setKeyCorpus
0218 
0219   /** @return the keyCorpus used in AnnotDiff process */
0220   public Corpus getKeyCorpus(){
0221     return keyCorpus;
0222   // getKeyCorpus
0223 
0224   /** Sets the keyAnnotationSetName in AnnotDiff
0225     @param aKeyAnnotationSetName The name of the annotation set from the
0226     * keyDocument.If aKeyAnnotationSetName is null then the default annotation
0227     * set will be used.
0228     */
0229   public void setKeyAnnotationSetName(String aKeyAnnotationSetName){
0230     keyAnnotationSetName = aKeyAnnotationSetName;
0231   // setKeyAnnotationSetName();
0232 
0233   /** Gets the keyAnnotationSetName.
0234     @return The name of the keyAnnotationSet used in AnnotationDiff. If
0235     * returns null then the the default annotation set will be used.
0236     */
0237   public String getKeyAnnotationSetName(){
0238     return keyAnnotationSetName;
0239   // getKeyAnnotationSetName()
0240 
0241   /** Sets the keyFeatureNamesSet in AnnotDiff.
0242     @param aKeyFeatureNamesSet a set containing the feature names from key
0243     * that will be used in isPartiallyCompatible()
0244     */
0245   public void setKeyFeatureNamesSet(Set aKeyFeatureNamesSet){
0246     keyFeatureNamesSet = aKeyFeatureNamesSet;
0247   }//setKeyFeatureNamesSet();
0248 
0249   /** Gets the keyFeatureNamesSet in AnnotDiff.
0250     @return A set containing the feature names from key
0251     * that will be used in isPartiallyCompatible()
0252     */
0253   public Set getKeyFeatureNamesSet(){
0254     return keyFeatureNamesSet;
0255   }//getKeyFeatureNamesSet();
0256 
0257   /** Sets the responseAnnotationSetName in AnnotDiff
0258     @param aResponseAnnotationSetName The name of the annotation set from the
0259     * responseDocument.If aResponseAnnotationSetName is null then the default
0260     * annotation set will be used.
0261     */
0262   public void setResponseAnnotationSetName(String aResponseAnnotationSetName){
0263     responseAnnotationSetName = aResponseAnnotationSetName;
0264   // setResponseAnnotationSetName();
0265 
0266   /** gets the responseAnnotationSetName.
0267     @return The name of the responseAnnotationSet used in AnnotationDiff. If
0268     * returns null then the the default annotation set will be used.
0269     */
0270   public String getResponseAnnotationSetName(){
0271     return responseAnnotationSetName;
0272   // getResponseAnnotationSetName()
0273 
0274   /** Sets the responseAnnotationSetNameFalsePoz in AnnotDiff
0275     @param aResponseAnnotationSetNameFalsePoz The name of the annotation set
0276     * from the responseDocument.If aResponseAnnotationSetName is null
0277     * then the default annotation set will be used.
0278     */
0279   public void setResponseAnnotationSetNameFalsePoz(
0280                                     String aResponseAnnotationSetNameFalsePoz){
0281     responseAnnotationSetNameFalsePoz = aResponseAnnotationSetNameFalsePoz;
0282   // setResponseAnnotationSetNameFalsePoz();
0283 
0284   /** gets the responseAnnotationSetNameFalsePoz.
0285     @return The name of the responseAnnotationSetFalsePoz used in
0286     * AnnotationDiff. If returns null then the the default annotation
0287     * set will be used.
0288     */
0289   public String getResponseAnnotationSetNameFalsePoz(){
0290     return responseAnnotationSetNameFalsePoz;
0291   // getResponseAnnotationSetNamefalsePoz()
0292 
0293   /**  Sets the annot diff to work in the text mode.This would not initiate the
0294     *  GUI part of annot diff but it would calculate precision etc
0295     */
0296   public void setTextMode(Boolean aTextMode){
0297     //it needs to be a Boolean and not boolean, because you cannot put
0298     //in the parameters hashmap a boolean, it needs an object
0299     textMode = aTextMode.booleanValue();
0300   }// End setTextMode();
0301 
0302   /** Gets the annot diff textmode.True means that the text mode is activated.*/
0303   public boolean isTextMode(){
0304     return textMode;
0305   }// End setTextMode();
0306 
0307   /** Returns a set with all annotations of a specific type*/
0308   public Set getAnnotationsOfType(int annotType){
0309     HashSet results = new HashSet();
0310     if (diffSet == nullreturn results;
0311     Iterator diffIter = diffSet.iterator();
0312     while(diffIter.hasNext()){
0313       DiffSetElement diffElem = (DiffSetElement)diffIter.next();
0314       switch(annotType){
0315         case CORRECT_TYPE:{
0316           if (diffElem.getRightType() == CORRECT_TYPE)
0317             results.add(diffElem.getRightAnnotation());
0318         }break;
0319         case PARTIALLY_CORRECT_TYPE:{
0320           if (diffElem.getRightType() == PARTIALLY_CORRECT_TYPE)
0321             results.add(diffElem.getRightAnnotation());
0322         }break;
0323         case SPURIOUS_TYPE:{
0324           if (diffElem.getRightType() == SPURIOUS_TYPE)
0325             results.add(diffElem.getRightAnnotation());
0326         }break;
0327         case MISSING_TYPE:{
0328           if (diffElem.getLeftType() == MISSING_TYPE)
0329             results.add(diffElem.getLeftAnnotation());
0330         }break;
0331         case DEFAULT_TYPE:{
0332           if (diffElem.getLeftType() == DEFAULT_TYPE)
0333             results.add(diffElem.getLeftAnnotation());
0334         }break;
0335       }// End switch
0336     }// End while
0337     return results;
0338   }//getAnnotationsOfType
0339 
0340   //Prameters utility methods
0341   /**
0342    * Gets the value of a parameter of this resource.
0343    @param paramaterName the name of the parameter
0344    @return the current value of the parameter
0345    */
0346   public Object getParameterValue(String paramaterName)
0347                 throws ResourceInstantiationException{
0348     return AbstractResource.getParameterValue(this, paramaterName);
0349   }
0350 
0351   /**
0352    * Sets the value for a specified parameter.
0353    *
0354    @param paramaterName the name for the parameteer
0355    @param parameterValue the value the parameter will receive
0356    */
0357   public void setParameterValue(String paramaterName, Object parameterValue)
0358               throws ResourceInstantiationException{
0359     // get the beaninfo for the resource bean, excluding data about Object
0360     BeanInfo resBeanInf = null;
0361     try {
0362       resBeanInf = Introspector.getBeanInfo(this.getClass(), Object.class);
0363     catch(Exception e) {
0364       throw new ResourceInstantiationException(
0365         "Couldn't get bean info for resource " this.getClass().getName()
0366         + Strings.getNl() "Introspector exception was: " + e
0367       );
0368     }
0369     AbstractResource.setParameterValue(this, resBeanInf, paramaterName, parameterValue);
0370   }
0371 
0372   /**
0373    * Sets the values for more parameters in one step.
0374    *
0375    @param parameters a feature map that has paramete names as keys and
0376    * parameter values as values.
0377    */
0378   public void setParameterValues(FeatureMap parameters)
0379               throws ResourceInstantiationException{
0380     AbstractResource.setParameterValues(this, parameters);
0381   }
0382 
0383 
0384 
0385   ///////////////////////////////////////////////////
0386   // PRECISION methods
0387   ///////////////////////////////////////////////////
0388 
0389   /** @return the precisionStrict field*/
0390   public double getPrecisionStrict(){
0391     return precisionStrict;
0392   // getPrecisionStrict
0393 
0394   /** @return the precisionLenient field*/
0395   public double getPrecisionLenient(){
0396     return precisionLenient;
0397   // getPrecisionLenient
0398 
0399   /** @return the precisionAverage field*/
0400   public double getPrecisionAverage(){
0401     return precisionAverage;
0402   // getPrecisionAverage
0403 
0404   /** @return the fMeasureStrict field*/
0405   public double getFMeasureStrict(){
0406     return fMeasureStrict;
0407   // getFMeasureStrict
0408 
0409   /** @return the fMeasureLenient field*/
0410   public double getFMeasureLenient(){
0411     return fMeasureLenient;
0412   // getFMeasureLenient
0413 
0414   /** @return the fMeasureAverage field*/
0415   public double getFMeasureAverage(){
0416     return fMeasureAverage;
0417   // getFMeasureAverage
0418 
0419   ///////////////////////////////////////////////////
0420   // RECALL methods
0421   ///////////////////////////////////////////////////
0422 
0423   /** @return the recallStrict field*/
0424   public double getRecallStrict(){
0425     return recallStrict;
0426   // getRecallStrict
0427 
0428   /** @return the recallLenient field*/
0429   public double getRecallLenient(){
0430     return recallLenient;
0431   // getRecallLenient
0432 
0433   /** @return the recallAverage field*/
0434   public double getRecallAverage(){
0435     return recallAverage;
0436   // getRecallAverage
0437 
0438   ///////////////////////////////////////////////////
0439   // FALSE POSITIVE methods
0440   ///////////////////////////////////////////////////
0441 
0442   /** @return the falsePositiveStrict field*/
0443   public double getFalsePositiveStrict(){
0444     return falsePositiveStrict;
0445   // getFalsePositiveStrict
0446 
0447   /** @return the falsePositiveLenient field*/
0448   public double getFalsePositiveLenient(){
0449     return falsePositiveLenient;
0450   // getFalsePositiveLenient
0451 
0452   /** @return the falsePositiveAverage field*/
0453   public double getFalsePositiveAverage(){
0454     return falsePositiveAverage;
0455   // getFalsePositive
0456 
0457   /**
0458     @param aResponseCorpus the GATE response corpus
0459     * containing the annotation Set being compared against the annotation from
0460     * the keyCorpus.
0461     */
0462   public void setResponseCorpus(Corpus aResponseCorpus) {
0463     responseCorpus = aResponseCorpus;
0464   //setResponseCorpus
0465 
0466   /**
0467     @param anAnnotationSchema the annotation type being compared.
0468     * This type is found in annotationSchema object as field
0469     {@link gate.creole.AnnotationSchema#getAnnotationName()}. If is <b>null<b>
0470     * then AnnotDiff will throw an exception when it comes to do the diff.
0471     */
0472   public void setAnnotationSchema(AnnotationSchema anAnnotationSchema) {
0473     annotationSchema = anAnnotationSchema;
0474   // setAnnotationType
0475 
0476   /** @return the annotation schema object used in annotation diff process */
0477   public AnnotationSchema getAnnotationSchema(){
0478     return annotationSchema;
0479   // AnnotationSchema
0480 
0481   public Dimension getPreferredScrollableViewportSize() {
0482         return getPreferredSize();
0483   }// public Dimension getPreferredScrollableViewportSize()
0484 
0485   public int getScrollableUnitIncrement(Rectangle visibleRect,
0486                                               int orientation, int direction) {
0487     return maxUnitIncrement;
0488   }// public int getScrollableUnitIncrement
0489 
0490   public int getScrollableBlockIncrement(Rectangle visibleRect,
0491                                               int orientation, int direction) {
0492     if (orientation == SwingConstants.HORIZONTAL)
0493         return visibleRect.width - maxUnitIncrement;
0494     else
0495         return visibleRect.height - maxUnitIncrement;
0496   }// public int getScrollableBlockIncrement
0497 
0498   public boolean getScrollableTracksViewportWidth() {
0499     return false;
0500   }// public boolean getScrollableTracksViewportWidth()
0501 
0502   public boolean getScrollableTracksViewportHeight() {
0503     return false;
0504   }
0505 
0506   /**
0507     * This method does the diff, Precision,Recall,FalsePositive
0508     * calculation and so on.
0509     */
0510   public Resource init() throws ResourceInstantiationException {
0511     colors[DEFAULT_TYPE= WHITE;
0512     colors[CORRECT_TYPE= GREEN;
0513     colors[SPURIOUS_TYPE= RED;
0514     colors[PARTIALLY_CORRECT_TYPE= BLUE;
0515     colors[MISSING_TYPE= YELLOW;
0516 
0517     // Initialize the partially sets...
0518     keyPartiallySet = new HashSet();
0519     responsePartiallySet = new HashSet();
0520 
0521     // Do the diff, P&R calculation and so on
0522     AnnotationSet keyAnnotSet = null;
0523     AnnotationSet responseAnnotSet = null;
0524 
0525     if(annotationSchema == null)
0526      throw new ResourceInstantiationException("No annotation schema defined !");
0527 
0528     if(keyCorpus == null || == keyCorpus.size())
0529       throw new ResourceInstantiationException("No key corpus or empty defined !");
0530 
0531     if(responseCorpus == null || == responseCorpus.size())
0532       throw new ResourceInstantiationException("No response corpus or empty defined !");
0533 
0534     // init counters and do difference for documents by pairs
0535     for (int type=0; type < MAX_TYPES; type++)
0536       typeCounter[type0;
0537     diffSet = new HashSet();
0538 
0539     for(int i=0; i<keyCorpus.size(); ++i) {
0540       keyDocument = (DocumentkeyCorpus.get(i);
0541       // find corresponding responce document if any
0542 
0543       Document doc;
0544       responseDocument = null;
0545       for(int j=0; j<responseCorpus.size(); ++j) {
0546         doc = (DocumentresponseCorpus.get(j);
0547         if(== doc.getName().compareTo(keyDocument.getName())
0548             || == doc.getSourceUrl().getFile().compareTo(
0549                       keyDocument.getSourceUrl().getFile())) {
0550           responseDocument = doc;
0551           break// response corpus loop
0552         // if
0553       // for
0554       
0555       if(null == responseDocument) {
0556         Out.prln("There is no mach in responce corpus for document '"
0557                   +keyDocument.getName()+"' from key corpus");
0558         continue// key corpus loop
0559       // if
0560       
0561       if (keyAnnotationSetName == null) {
0562         // Get the default key AnnotationSet from the keyDocument
0563         keyAnnotSet =  keyDocument.getAnnotations().get(
0564                                 annotationSchema.getAnnotationName());
0565       }
0566       else {
0567         keyAnnotSet =  keyDocument.getAnnotations(keyAnnotationSetName).get(
0568                                 annotationSchema.getAnnotationName());
0569       // if
0570   
0571       if (keyAnnotSet == null)
0572         // The diff will run with an empty set.All annotations from response
0573         // would be spurious.
0574         keyAnnotList = new LinkedList();
0575       else
0576         // The alghoritm will modify this annotation set. It is better to make a
0577         // separate copy of them.
0578         keyAnnotList = new LinkedList(keyAnnotSet);
0579   
0580       if (responseAnnotationSetName == null)
0581         // Get the response AnnotationSet from the default set
0582         responseAnnotSet = responseDocument.getAnnotations().get(
0583                                             annotationSchema.getAnnotationName());
0584       else
0585         responseAnnotSet = responseDocument.getAnnotations(responseAnnotationSetName).
0586                                       get(annotationSchema.getAnnotationName());
0587   
0588       if (responseAnnotSet == null)
0589         // The diff will run with an empty set.All annotations from key
0590         // would be missing.
0591         responseAnnotList = new LinkedList();
0592       else
0593         // The alghoritm will modify this annotation set. It is better to make a
0594         // separate copy of them.
0595         responseAnnotList = new LinkedList(responseAnnotSet);
0596   
0597       // Sort them ascending on Start offset (the comparator does that)
0598       AnnotationSetComparator asComparator = new AnnotationSetComparator();
0599       Collections.sort(keyAnnotList, asComparator);
0600       Collections.sort(responseAnnotList, asComparator);
0601   
0602       // Calculate the diff Set. This set will be used later with graphic
0603       // visualisation.
0604       doDiff(keyAnnotList, responseAnnotList);
0605     // for
0606     
0607     // If it runs under text mode just stop here.
0608     if (textModereturn this;
0609 
0610     //Show it
0611     // Configuring the formatter object. It will be used later to format
0612     // precision and recall
0613     formatter.setMaximumIntegerDigits(1);
0614     formatter.setMinimumFractionDigits(4);
0615     formatter.setMinimumFractionDigits(4);
0616 
0617     // Create an Annotation diff table model
0618     AnnotationDiffTableModel diffModel = new AnnotationDiffTableModel(diffSet);
0619     // Create a XJTable based on this model
0620     diffTable = new XJTable(diffModel);
0621     diffTable.setAlignmentX(Component.LEFT_ALIGNMENT);
0622     // Set the cell renderer for this table.
0623     AnnotationDiffCellRenderer cellRenderer = new AnnotationDiffCellRenderer();
0624     diffTable.setDefaultRenderer(java.lang.String.class,cellRenderer);
0625     diffTable.setDefaultRenderer(java.lang.Long.class,cellRenderer);
0626     // Put the table into a JScroll
0627 
0628     // Arange all components on a this JPanel
0629     SwingUtilities.invokeLater(new Runnable(){
0630       public void run(){
0631         arangeAllComponents();
0632       }
0633     });
0634 
0635     if (DEBUG)
0636       printStructure(diffSet);
0637 
0638     return this;
0639   //init()
0640 
0641   /** This method creates the graphic components and aranges them on
0642     <b>this</b> JPanel
0643     */
0644   protected void arangeAllComponents(){
0645     this.removeAll();
0646     // Setting the box layout for diffpanel
0647     BoxLayout boxLayout = new BoxLayout(this,BoxLayout.Y_AXIS);
0648     this.setLayout(boxLayout);
0649 
0650     JTableHeader tableHeader = diffTable.getTableHeader();
0651     tableHeader.setAlignmentX(Component.LEFT_ALIGNMENT);
0652     this.add(tableHeader);
0653     diffTable.setAlignmentX(Component.LEFT_ALIGNMENT);
0654     // Add the tableScroll to the diffPanel
0655     this.add(diffTable);
0656 
0657 
0658     // ADD the LEGEND
0659     //Lay out the JLabels from left to right.
0660     //Box infoBox = new Box(BoxLayout.X_AXIS);
0661     JPanel infoBox = new  JPanel();
0662     infoBox.setLayout(new BoxLayout(infoBox,BoxLayout.X_AXIS));
0663     infoBox.setAlignmentX(Component.LEFT_ALIGNMENT);
0664     // Keep the components together
0665     //box.add(Box.createHorizontalGlue());
0666 
0667     Box box = new Box(BoxLayout.Y_AXIS);
0668     JLabel jLabel = new JLabel("LEGEND");
0669     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0670     jLabel.setOpaque(true);
0671     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0672     box.add(jLabel);
0673 
0674     jLabel = new JLabel("Missing (present in Key but not in Response):  " +
0675                                                 typeCounter[MISSING_TYPE]);
0676     jLabel.setForeground(BLACK);
0677     jLabel.setBackground(colors[MISSING_TYPE]);
0678     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0679     jLabel.setOpaque(true);
0680     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0681     box.add(jLabel);
0682 
0683     // Add a space
0684     box.add(Box.createRigidArea(new Dimension(0,5)));
0685 
0686     jLabel = new JLabel("Correct (total match):  " + typeCounter[CORRECT_TYPE]);
0687     jLabel.setForeground(BLACK);
0688     jLabel.setBackground(colors[CORRECT_TYPE]);
0689     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0690     jLabel.setOpaque(true);
0691     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0692     box.add(jLabel);
0693 
0694     // Add a space
0695     box.add(Box.createRigidArea(new Dimension(0,5)));
0696 
0697     jLabel =new JLabel("Partially correct (overlap in Key and Response):  "+
0698                                         typeCounter[PARTIALLY_CORRECT_TYPE]);
0699     jLabel.setForeground(BLACK);
0700     jLabel.setBackground(colors[PARTIALLY_CORRECT_TYPE]);
0701     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0702     jLabel.setOpaque(true);
0703     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0704     box.add(jLabel);
0705 
0706     // Add a space
0707     box.add(Box.createRigidArea(new Dimension(0,5)));
0708 
0709     jLabel = new JLabel("Spurious (present in Response but not in Key):  " +
0710                                         typeCounter[SPURIOUS_TYPE]);
0711     jLabel.setForeground(BLACK);
0712     jLabel.setBackground(colors[SPURIOUS_TYPE]);
0713     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0714     jLabel.setOpaque(true);
0715     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0716     box.add(jLabel);
0717 
0718     infoBox.add(box);
0719     // Add a space
0720     infoBox.add(Box.createRigidArea(new Dimension(40,0)));
0721 
0722     // Precision measure
0723     //Lay out the JLabels from left to right.
0724     box = new Box(BoxLayout.Y_AXIS);
0725 
0726     jLabel = new JLabel("Precision strict: " +
0727                                     formatter.format(precisionStrict));
0728     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0729     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0730     box.add(jLabel);
0731 
0732     jLabel = new JLabel("Precision average: " +
0733                                     formatter.format(precisionAverage));
0734     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0735     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0736     box.add(jLabel);
0737 
0738     jLabel = new JLabel("Precision lenient: " +
0739                                     formatter.format(precisionLenient));
0740     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0741     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0742     box.add(jLabel);
0743 
0744     infoBox.add(box);
0745     // Add a space
0746     infoBox.add(Box.createRigidArea(new Dimension(40,0)));
0747 
0748     // RECALL measure
0749     //Lay out the JLabels from left to right.
0750     box = new Box(BoxLayout.Y_AXIS);
0751 
0752     jLabel = new JLabel("Recall strict: " + formatter.format(recallStrict));
0753     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0754     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0755     box.add(jLabel);
0756 
0757     jLabel = new JLabel("Recall average: " + formatter.format(recallAverage));
0758     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0759     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0760     box.add(jLabel);
0761 
0762     jLabel = new JLabel("Recall lenient: " + formatter.format(recallLenient));
0763     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0764     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0765     box.add(jLabel);
0766 
0767     infoBox.add(box);
0768     // Add a space
0769     infoBox.add(Box.createRigidArea(new Dimension(40,0)));
0770 
0771     // F-Measure
0772     //Lay out the JLabels from left to right.
0773     box = new Box(BoxLayout.Y_AXIS);
0774 
0775     jLabel = new JLabel("F-Measure strict: " +
0776                                         formatter.format(fMeasureStrict));
0777     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0778     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0779     box.add(jLabel);
0780 
0781     jLabel = new JLabel("F-Measure average: " +
0782                                         formatter.format(fMeasureAverage));
0783     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0784     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0785     box.add(jLabel);
0786 
0787     jLabel = new JLabel("F-Measure lenient: " +
0788                                         formatter.format(fMeasureLenient));
0789     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0790     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0791     box.add(jLabel);
0792     infoBox.add(box);
0793 
0794     // Add a space
0795     infoBox.add(Box.createRigidArea(new Dimension(40,0)));
0796 
0797     // FALSE POZITIVE measure
0798     //Lay out the JLabels from left to right.
0799     box = new Box(BoxLayout.Y_AXIS);
0800 
0801     jLabel = new JLabel("False positive strict: " +
0802                                         formatter.format(falsePositiveStrict));
0803     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0804     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0805     box.add(jLabel);
0806 
0807     jLabel = new JLabel("False positive average: " +
0808                                         formatter.format(falsePositiveAverage));
0809     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0810     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0811     box.add(jLabel);
0812 
0813     jLabel = new JLabel("False positive lenient: " +
0814                                         formatter.format(falsePositiveLenient));
0815     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
0816     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
0817     box.add(jLabel);
0818     infoBox.add(box);
0819 
0820     // Add a space
0821     infoBox.add(Box.createRigidArea(new Dimension(10,0)));
0822 
0823     this.add(infoBox);
0824   //arangeAllComponents
0825 
0826   /** Used internally for debugging */
0827   protected void printStructure(Set aDiffSet){
0828     Iterator iterator = aDiffSet.iterator();
0829     String leftAnnot = null;
0830     String rightAnnot = null;
0831     while(iterator.hasNext()){
0832       DiffSetElement diffElem = (DiffSetElementiterator.next();
0833       if (diffElem.getLeftAnnotation() == null)
0834         leftAnnot = "NULL ";
0835       else
0836         leftAnnot = diffElem.getLeftAnnotation().toString();
0837       if (diffElem.getRightAnnotation() == null)
0838         rightAnnot = " NULL";
0839       else
0840         rightAnnot = diffElem.getRightAnnotation().toString();
0841       Out.prlnleftAnnot + "|" + rightAnnot);
0842     // end while
0843   // printStructure
0844 
0845   /** This method is the brain of the AnnotationSet diff and creates a set with
0846     * diffSetElement objects.
0847     @param aKeyAnnotList a list containing the annotations from key. If this
0848     * param is <b>null</b> then the method will simply return and will not do a
0849     * thing.
0850     @param aResponseAnnotList a list containing the annotation from response.
0851     * If this param is <b>null</b> the method will return.
0852     */
0853   protected void doDiff(java.util.List aKeyAnnotList,
0854                         java.util.List aResponseAnnotList){
0855 
0856     // If one of the annotation sets is null then is no point in doing the diff.
0857     if (aKeyAnnotList == null || aResponseAnnotList == null)
0858       return;
0859 
0860     int responseSize = aResponseAnnotList.size();
0861 
0862     // Iterate throught all elements from keyList and find those in the response
0863     // list which satisfies isCompatible() and isPartiallyCompatible() relations
0864     Iterator keyIterator = aKeyAnnotList.iterator();
0865     while(keyIterator.hasNext()){
0866       Annotation keyAnnot = (AnnotationkeyIterator.next();
0867       Iterator responseIterator = aResponseAnnotList.iterator();
0868 
0869       DiffSetElement diffElement = null;
0870       while(responseIterator.hasNext()){
0871         Annotation responseAnnot = (AnnotationresponseIterator.next();
0872 
0873         if(keyAnnot.isPartiallyCompatible(responseAnnot,keyFeatureNamesSet)){
0874           keyPartiallySet.add(keyAnnot);
0875           responsePartiallySet.add(responseAnnot);
0876           if (keyAnnot.coextensive(responseAnnot)){
0877             // Found two compatible annotations
0878             // Create a new DiffSetElement and add it to the diffSet
0879             diffElement = new DiffSetElementkeyAnnot,
0880                                               responseAnnot,
0881                                               DEFAULT_TYPE,
0882                                               CORRECT_TYPE,
0883                                               keyDocument,
0884                                               responseDocument);
0885 
0886             // Add this element to the DiffSet
0887             addToDiffset(diffElement);
0888           // End if (keyAnnot.coextensive(responseAnnot))
0889         }else if (keyAnnot.coextensive(responseAnnot)){
0890           // Found two aligned annotations. We have to find out if the response
0891           // is partialy compatible with another key annotation.
0892           // Create a new DiffSetElement and add it to the diffSet
0893           diffElement = new DiffSetElementkeyAnnot,
0894                                             responseAnnot,
0895                                             detectKeyType(keyAnnot),
0896                                             detectResponseType(responseAnnot),
0897                                             keyDocument,
0898                                             responseDocument);
0899           // Add this element to the DiffSet
0900           addToDiffset(diffElement);
0901         // End if (keyAnnot.coextensive(responseAnnot)){
0902 
0903         if (diffElement != null){
0904           // Eliminate the response annotation from the list.
0905           responseIterator.remove();
0906           break;
0907         // End if
0908       // end while responseIterator
0909 
0910       // If diffElement != null it means that break was used
0911       if (diffElement == null){
0912         if (keyPartiallySet.contains(keyAnnot))
0913           diffElement = new DiffSetElementkeyAnnot,
0914                                             null,
0915                                             DEFAULT_TYPE,
0916                                             NULL_TYPE,
0917                                             keyDocument,
0918                                             responseDocument);
0919         else{
0920           // If keyAnnot is not in keyPartiallySet then it has to be checked
0921           // agains all annotations in DiffSet to see if there is
0922           // a previous annotation from response set which is partially
0923           // compatible with the keyAnnot
0924           Iterator respParIter = diffSet.iterator();
0925           while (respParIter.hasNext()){
0926             DiffSetElement diffElem = (DiffSetElementrespParIter.next();
0927             Annotation respAnnot = diffElem.getRightAnnotation();
0928             if (respAnnot != null && keyAnnot.isPartiallyCompatible(respAnnot,
0929                                                           keyFeatureNamesSet)){
0930                 diffElement = new DiffSetElementkeyAnnot,
0931                                                   null,
0932                                                   DEFAULT_TYPE,
0933                                                   NULL_TYPE,
0934                                                   keyDocument,
0935                                                   responseDocument);
0936                 break;
0937             // End if
0938           // End while
0939           // If is still nul then it means that the key annotation is missing
0940           if (diffElement == null)
0941             diffElement = new DiffSetElementkeyAnnot,
0942                                               null,
0943                                               MISSING_TYPE,
0944                                               NULL_TYPE,
0945                                               keyDocument,
0946                                               responseDocument);
0947         // End if
0948         addToDiffset(diffElement);
0949       // End if
0950 
0951       keyIterator.remove();
0952     // end while keyIterator
0953 
0954     DiffSetElement diffElem = null;
0955     Iterator responseIter = aResponseAnnotList.iterator();
0956     while (responseIter.hasNext()){
0957       Annotation respAnnot = (AnnotationresponseIter.next();
0958       if (responsePartiallySet.contains(respAnnot))
0959         diffElem = new DiffSetElementnull,
0960                                        respAnnot,
0961                                        NULL_TYPE,
0962                                        PARTIALLY_CORRECT_TYPE,
0963                                        keyDocument,
0964                                        responseDocument);
0965       else
0966         diffElem = new DiffSetElementnull,
0967                                        respAnnot,
0968                                        NULL_TYPE,
0969                                        SPURIOUS_TYPE,
0970                                        keyDocument,
0971                                        responseDocument);
0972       addToDiffset(diffElem);
0973       responseIter.remove();
0974     // End while
0975 
0976     // CALCULATE ALL (NLP) MEASURES like:
0977     // Precistion, Recall, FalsePositive and F-Measure
0978     int possible =  typeCounter[CORRECT_TYPE+  // this comes from Key or Resp
0979                     typeCounter[PARTIALLY_CORRECT_TYPE// this comes from Resp
0980                     typeCounter[MISSING_TYPE]// this comes from Key
0981 
0982     int actual =  typeCounter[CORRECT_TYPE+  // this comes from Key or Resp
0983                   typeCounter[PARTIALLY_CORRECT_TYPE// this comes from Resp
0984                   typeCounter[SPURIOUS_TYPE]// this comes from Resp
0985 /*
0986     if (actual != responseSize)
0987       Err.prln("AnnotDiff warning: The response size(" + responseSize +
0988       ") is not the same as the computed value of" +
0989     " actual(Correct[resp or key]+Partial[resp]+Spurious[resp]=" + actual +")");
0990 */
0991     if (actual != 0){
0992       precisionStrict =  ((double)typeCounter[CORRECT_TYPE])/((double)actual);
0993       precisionLenient = ((double)(typeCounter[CORRECT_TYPE+
0994                          typeCounter[PARTIALLY_CORRECT_TYPE]))/((double)actual);
0995       precisionAverage = ((double)(precisionStrict + precisionLenient)) /
0996                                                                   ((double2);
0997     // End if
0998     if (possible != 0){
0999       recallStrict = ((double)typeCounter[CORRECT_TYPE])/((double)possible);
1000       recallLenient = ((double)(typeCounter[CORRECT_TYPE+
1001                        typeCounter[PARTIALLY_CORRECT_TYPE]))/((double)possible);
1002       recallAverage = ((double)(recallStrict + recallLenient)) ((double)2);
1003     // End if
1004 
1005 
1006     int no = 0;
1007     // If an annotation type for false poz was selected calculate the number of
1008     // Annotations
1009     if (annotationTypeForFalsePositive != null)
1010      // Was it the default set ?
1011      if (responseAnnotationSetNameFalsePoz == null){
1012       AnnotationSet aSet = responseDocument.getAnnotations().get(
1013                                       annotationTypeForFalsePositive);
1014           no = aSet == null : aSet.size();
1015      }else{
1016       AnnotationSet aSet = responseDocument.getAnnotations(responseAnnotationSetNameFalsePoz).get(
1017                                         annotationTypeForFalsePositive);
1018       no = aSet == null: aSet.size();
1019      }
1020     if (no != 0){
1021       // No error here: the formula is the opposite to recall or precission
1022      falsePositiveStrict = ((double)(typeCounter[SPURIOUS_TYPE+
1023                              typeCounter[PARTIALLY_CORRECT_TYPE])) /((double)no);
1024      falsePositiveLenient = ((double)typeCounter[SPURIOUS_TYPE]) /((doubleno);
1025      falsePositiveAverage = ((double)(falsePositiveStrict +
1026                                            falsePositiveLenient))/((double)2;
1027     // End if
1028 
1029     // Calculate F-Measure Strict
1030     double denominator = weight * (precisionStrict + recallStrict);
1031     if (denominator != 0)
1032       fMeasureStrict = (precisionStrict * recallStrict/ denominator ;
1033     else fMeasureStrict = 0.0;
1034     // Calculate F-Measure Lenient
1035     denominator = weight * (precisionLenient + recallLenient);
1036     if (denominator != 0)
1037       fMeasureLenient = (precisionLenient * recallLenient/ denominator ;
1038     else fMeasureLenient = 0.0;
1039     // Calculate F-Measure Average
1040     fMeasureAverage = (fMeasureStrict + fMeasureLenient(double)2;
1041 
1042   // doDiff
1043 
1044   /** Decide what type is the keyAnnotation (DEFAULT_TYPE, MISSING or NULL_TYPE)
1045    *  This method must be applied only on annotation from key set.
1046    *  @param anAnnot is an annotation from the key set.
1047    *  @return three possible value(DEFAULT_TYPE, MISSING or NULL_TYPE)
1048    */
1049   private int detectKeyType(Annotation anAnnot){
1050     if (anAnnot == nullreturn NULL_TYPE;
1051 
1052     if (keyPartiallySet.contains(anAnnot)) return DEFAULT_TYPE;
1053     Iterator iter = responsePartiallySet.iterator();
1054     while(iter.hasNext()){
1055       Annotation a = (Annotationiter.next();
1056       if (anAnnot.isPartiallyCompatible(a,keyFeatureNamesSet))
1057         return DEFAULT_TYPE;
1058     // End while
1059 
1060     iter = responseAnnotList.iterator();
1061     while(iter.hasNext()){
1062       Annotation a = (Annotationiter.next();
1063       if (anAnnot.isPartiallyCompatible(a,keyFeatureNamesSet)){
1064          responsePartiallySet.add(a);
1065          keyPartiallySet.add(anAnnot);
1066          return DEFAULT_TYPE;
1067       // End if
1068     // End while
1069     return MISSING_TYPE;
1070   //detectKeyType
1071 
1072   /**  Decide what type is the responseAnnotation
1073     *  (PARTIALLY_CORRECT_TYPE, SPURIOUS or NULL_TYPE)
1074     *  This method must be applied only on annotation from response set.
1075     *  @param anAnnot is an annotation from the key set.
1076     *  @return three possible value(PARTIALLY_CORRECT_TYPE, SPURIOUS or NULL_TYPE)
1077     */
1078   private int detectResponseType(Annotation anAnnot){
1079     if (anAnnot == nullreturn NULL_TYPE;
1080 
1081     if (responsePartiallySet.contains(anAnnot)) return PARTIALLY_CORRECT_TYPE;
1082     Iterator iter = keyPartiallySet.iterator();
1083     while(iter.hasNext()){
1084       Annotation a = (Annotationiter.next();
1085       if (a.isPartiallyCompatible(anAnnot,keyFeatureNamesSet))
1086         return PARTIALLY_CORRECT_TYPE;
1087     // End while
1088 
1089     iter = keyAnnotList.iterator();
1090     while(iter.hasNext()){
1091       Annotation a = (Annotationiter.next();
1092       if (a.isPartiallyCompatible(anAnnot,keyFeatureNamesSet)){
1093          responsePartiallySet.add(anAnnot);
1094          keyPartiallySet.add(a);
1095          return PARTIALLY_CORRECT_TYPE;
1096       // End if
1097     // End while
1098     return SPURIOUS_TYPE;
1099   //detectResponseType
1100 
1101   /** This method add an DiffsetElement to the DiffSet and also counts the
1102     * number of compatible, partialCompatible, Incorect and Missing annotations.
1103     */
1104   private void addToDiffset(DiffSetElement aDiffSetElement){
1105     if (aDiffSetElement == nullreturn;
1106 
1107     diffSet.add(aDiffSetElement);
1108     // For the Right side (response) the type can be one of the following:
1109     // PC, I, C
1110     if (NULL_TYPE != aDiffSetElement.getRightType())
1111       typeCounter[aDiffSetElement.getRightType()]++;
1112     // For the left side (key) the type can be : D or M
1113     if (NULL_TYPE != aDiffSetElement.getLeftType() &&
1114         CORRECT_TYPE != aDiffSetElement.getLeftType())
1115       typeCounter[aDiffSetElement.getLeftType()]++;
1116   // addToDiffset
1117 
1118   /* ********************************************************************
1119    * INNER CLASS
1120    * ********************************************************************/
1121 
1122   /**
1123     * A custom table model used to render a table containing the two annotation
1124     * sets. The columns will be:
1125     * (KEY) Type, Start, End, Features, empty column,(Response) Type,Start, End, Features
1126     */
1127   protected class AnnotationDiffTableModel extends AbstractTableModel{
1128 
1129     /** Constructs an AnnotationDiffTableModel given a data Collection */
1130     public AnnotationDiffTableModel(Collection data){
1131       modelData = new ArrayList();
1132       modelData.addAll(data);
1133     // AnnotationDiffTableModel
1134 
1135     /** Constructs an AnnotationDiffTableModel */
1136     public AnnotationDiffTableModel(){
1137       modelData = new ArrayList();
1138     // AnnotationDiffTableModel
1139 
1140     /** Return the size of data.*/
1141     public int getRowCount(){
1142       return modelData.size();
1143     //getRowCount
1144 
1145     /** Return the number of columns.*/
1146     public int getColumnCount(){
1147       return 10;
1148     //getColumnCount
1149 
1150     /** Returns the name of each column in the model*/
1151     public String getColumnName(int column){
1152       switch(column){
1153         case 0return "String - Key";
1154         case 1return "Start - Key";
1155         case 2return "End - Key";
1156         case 3return "Features - Key";
1157         case 4return "   ";
1158         case 5return "String - Response";
1159         case 6return "Start - Response";
1160         case 7return "End -Response";
1161         case 8return "Features - Response";
1162         case 9return "Document";
1163         default:return "?";
1164       }
1165     //getColumnName
1166 
1167     /** Return the class type for each column. */
1168     public Class getColumnClass(int column){
1169       switch(column){
1170         case 0return String.class;
1171         case 1return Long.class;
1172         case 2return Long.class;
1173         case 3return String.class;
1174         case 4return String.class;
1175         case 5return String.class;
1176         case 6return Long.class;
1177         case 7return Long.class;
1178         case 8return String.class;
1179         case 9return String.class;
1180         default:return Object.class;
1181       }
1182     //getColumnClass
1183 
1184     /**Returns a value from the table model */
1185     public Object getValueAt(int row, int column){
1186       DiffSetElement diffSetElement = (DiffSetElementmodelData.get(row);
1187       if (diffSetElement == nullreturn null;
1188       switch(column){
1189         // Left Side (Key)
1190         //Type - Key
1191         case 0:{
1192            if (diffSetElement.getLeftAnnotation() == nullreturn null;
1193 //           return diffSetElement.getLeftAnnotation().getType();
1194            Annotation annot = diffSetElement.getLeftAnnotation();
1195            String theString = "";
1196            try {
1197              theString = diffSetElement.getKeyDocument().getContent().getContent(
1198                     annot.getStartNode().getOffset(),
1199                     annot.getEndNode().getOffset()).toString();
1200            catch (gate.util.InvalidOffsetException ex) {
1201              Err.prln(ex.getMessage());
1202            }
1203            return theString;
1204         }
1205         // Start - Key
1206         case 1:{
1207            if (diffSetElement.getLeftAnnotation() == nullreturn null;
1208            return diffSetElement.getLeftAnnotation().getStartNode().getOffset();
1209         }
1210         // End - Key
1211         case 2:{
1212            if (diffSetElement.getLeftAnnotation() == nullreturn null;
1213            return diffSetElement.getLeftAnnotation().getEndNode().getOffset();
1214         }
1215         // Features - Key
1216         case 3:{
1217            if (diffSetElement.getLeftAnnotation() == nullreturn null;
1218            if (diffSetElement.getLeftAnnotation().getFeatures() == null)
1219              return null;
1220            return diffSetElement.getLeftAnnotation().getFeatures().toString();
1221         }
1222         // Empty column
1223         case 4:{
1224           return "   ";
1225         }
1226         // Right Side (Response)
1227         //Type - Response
1228         case 5:{
1229            if (diffSetElement.getRightAnnotation() == nullreturn null;
1230 //           return diffSetElement.getRightAnnotation().getType();
1231            Annotation annot = diffSetElement.getRightAnnotation();
1232            String theString = "";
1233            try {
1234              theString = diffSetElement.getResponseDocument().getContent().getContent(
1235                     annot.getStartNode().getOffset(),
1236                     annot.getEndNode().getOffset()).toString();
1237            catch (gate.util.InvalidOffsetException ex) {
1238              Err.prln(ex.getMessage());
1239            }
1240            return theString;
1241         }
1242         // Start - Response
1243         case 6:{
1244            if (diffSetElement.getRightAnnotation() == nullreturn null;
1245           return diffSetElement.getRightAnnotation().getStartNode().getOffset();
1246         }
1247         // End - Response
1248         case 7:{
1249            if (diffSetElement.getRightAnnotation() == nullreturn null;
1250            return diffSetElement.getRightAnnotation().getEndNode().getOffset();
1251         }
1252         // Features - resonse
1253         case 8:{
1254            if (diffSetElement.getRightAnnotation() == nullreturn null;
1255            return diffSetElement.getRightAnnotation().getFeatures().toString();
1256         }
1257         // Document name
1258         case 9:{
1259           return diffSetElement.getKeyDocument().getName();
1260         }
1261         // The hidden column
1262         case 10:{
1263           return diffSetElement;
1264         }
1265         default:{return null;}
1266       // End switch
1267     //getValueAt
1268 
1269     public Object getRawObject(int row){
1270       return modelData.get(row);
1271     //getRawObject
1272 
1273     /** Holds the data for TableDiff*/
1274     private java.util.List modelData = null;
1275 
1276   //Inner class AnnotationDiffTableModel
1277 
1278   /* ********************************************************************
1279    * INNER CLASS
1280    * ********************************************************************/
1281   /**
1282     * This class defines a Cell renderer for the AnnotationDiff table
1283     */
1284   public class AnnotationDiffCellRenderer extends DefaultTableCellRenderer{
1285 
1286     /** Constructs a randerer with a table model*/
1287     public AnnotationDiffCellRenderer() { }  //AnnotationDiffCellRenderer
1288 
1289     private Color background = WHITE;
1290 
1291     private Color foreground = BLACK;
1292 
1293     /** This method is called by JTable*/
1294 
1295     public Component getTableCellRendererComponent(
1296       JTable table, Object value, boolean isSelected, boolean hasFocus,
1297       int row, int column
1298     ) {
1299       JComponent defaultComp = null;
1300       defaultComp = (JComponentsuper.getTableCellRendererComponent(
1301   table, value, isSelected, hasFocus, row, column
1302       );
1303 
1304       // The column number four will be randered using a blank component
1305       if (column == || value == null)
1306         return new JPanel();
1307 
1308       if (!(table.getModel().getValueAt(row,10instanceof DiffSetElement))
1309         return defaultComp;
1310 
1311       DiffSetElement diffSetElement =
1312                         (DiffSetElementtable.getModel().getValueAt(row,10);
1313 
1314       if (diffSetElement == null)
1315         return defaultComp;
1316 
1317       if (column < 4){
1318         if (NULL_TYPE != diffSetElement.getLeftType())
1319           background = colors[diffSetElement.getLeftType()];
1320         else return new JPanel();
1321       }else if (column < 10){
1322         if (NULL_TYPE != diffSetElement.getRightType())
1323           background = colors[diffSetElement.getRightType()];
1324         else return new JPanel();
1325       }
1326 
1327       defaultComp.setBackground(background);
1328       defaultComp.setForeground(BLACK);
1329 
1330       defaultComp.setOpaque(true);
1331       return defaultComp;
1332     //getTableCellRendererComponent
1333 
1334   // class AnnotationDiffCellRenderer
1335 
1336   /* ********************************************************************
1337    * INNER CLASS
1338    * ********************************************************************/
1339    class AnnotationSetComparator implements java.util.Comparator {
1340 
1341       public AnnotationSetComparator(){}
1342 
1343       public int compare(Object o1, Object o2) {
1344         if !(o1 instanceof gate.Annotation||
1345              !(o2 instanceof gate.Annotation)) return 0;
1346 
1347         gate.Annotation a1 = (gate.Annotationo1;
1348         gate.Annotation a2 = (gate.Annotationo2;
1349 
1350         Long l1 = a1.getStartNode().getOffset();
1351         Long l2 = a2.getStartNode().getOffset();
1352         if (l1 != null)
1353           return l1.compareTo(l2);
1354         else
1355           return -1;
1356       //compare
1357     // class AnnotationSetComparator
1358 
1359   /* ********************************************************************
1360    * INNER CLASS
1361    * ********************************************************************/
1362 
1363   /**
1364     * This class is used for internal purposes. It represents a row from the
1365     * table.
1366     */
1367   protected class DiffSetElement {
1368     /** This field represent a key annotation*/
1369     private Annotation leftAnnotation = null;
1370     /** This field represent a response annotation*/
1371     private Annotation rightAnnotation = null;
1372     /** Default initialization of the key type*/
1373     private int leftType = DEFAULT_TYPE;
1374     /** Default initialization of the response type*/
1375     private int rightType = DEFAULT_TYPE;
1376     /** Key document */
1377     private Document keyDocument;
1378     /** Response document */
1379     private Document respDocument;
1380 
1381     /** Constructor for DiffSetlement*/
1382     public DiffSetElement() {}
1383 
1384     /** Constructor for DiffSetlement*/
1385     public DiffSetElementAnnotation aLeftAnnotation,
1386                            Annotation aRightAnnotation,
1387                            int aLeftType,
1388                            int aRightType){
1389       leftAnnotation = aLeftAnnotation;
1390       rightAnnotation = aRightAnnotation;
1391       leftType = aLeftType;
1392       rightType = aRightType;
1393       keyDocument = null;
1394       respDocument = null;
1395     // DiffSetElement
1396 
1397     /** Constructor for DiffSetlement with document name */
1398     public DiffSetElementAnnotation aLeftAnnotation,
1399                            Annotation aRightAnnotation,
1400                            int aLeftType,
1401                            int aRightType,
1402                            Document kDocument,
1403                            Document rDocument){
1404       leftAnnotation = aLeftAnnotation;
1405       rightAnnotation = aRightAnnotation;
1406       leftType = aLeftType;
1407       rightType = aRightType;
1408       keyDocument = kDocument;
1409       respDocument = rDocument;
1410     // DiffSetElement
1411     
1412     /** Sets the left annotation*/
1413     public void setLeftAnnotation(Annotation aLeftAnnotation){
1414       leftAnnotation = aLeftAnnotation;
1415     // setLeftAnnot
1416 
1417     /** Gets the left annotation*/
1418     public Annotation getLeftAnnotation(){
1419       return leftAnnotation;
1420     // getLeftAnnotation
1421 
1422     /** Sets the right annotation*/
1423     public void setRightAnnotation(Annotation aRightAnnotation){
1424       rightAnnotation = aRightAnnotation;
1425     // setRightAnnot
1426 
1427     /** Gets the right annotation*/
1428     public Annotation getRightAnnotation(){
1429       return rightAnnotation;
1430     // getRightAnnotation
1431 
1432     /** Sets the left type*/
1433     public void setLeftType(int aLeftType){
1434       leftType = aLeftType;
1435     // setLeftType
1436 
1437     /** Get the left type */
1438     public int getLeftType() {
1439       return leftType;
1440     // getLeftType
1441 
1442     /** Sets the right type*/
1443     public void setRightType(int aRightType) {
1444       rightType = aRightType;
1445     // setRightType
1446 
1447     /** Get the right type*/
1448     public int getRightType() {
1449       return rightType;
1450     // getRightType
1451 
1452     /** Get Key document */
1453     public Document getKeyDocument() {
1454       return keyDocument;
1455     // getKeyDocument
1456 
1457     /** Set Key document */
1458     public void setKeyDocument(Document aDoc) {
1459       keyDocument = aDoc;
1460     // setKeyDocument
1461 
1462     /** Get Response document */
1463     public Document getResponseDocument() {
1464       return respDocument;
1465     // getResponseDocument
1466 
1467     /** Set Response document */
1468     public void setResponseDocument(Document aDoc) {
1469       respDocument = aDoc;
1470     // setResponseDocument
1471   // classs DiffSetElement
1472 // class CorpusAnnotationDiff