| AnnotationDiff |

    1   /*
    2    *  AnnotationDiff.java
    3    *
    4    *  Copyright (c) 1998-2001, The University of Sheffield.
    5    *
    6    *  This file is part of GATE (see http://gate.ac.uk/), and is free
    7    *  software, licenced under the GNU Library General Public License,
    8    *  Version 2, June 1991 (in the distribution as file licence.html,
    9    *  and also available at http://gate.ac.uk/gate/licence.html).
    10   *
    11   *  Cristian URSU, 27/Oct/2000
    12   *
    13   *  $Id: AnnotationDiff.java,v 1.38 2001/12/03 15:02:05 cursu Exp $
    14   */
    15
    16  package gate.annotation;
    17
    18  import java.util.*;
    19  import java.awt.*;
    20  import java.text.NumberFormat;
    21  import java.awt.event.*;
    22  import javax.swing.*;
    23  import javax.swing.table.*;
    24
    25  import gate.util.*;
    26  import gate.annotation.*;
    27  import gate.*;
    28  import gate.gui.*;
    29  import gate.swing.*;
    30  import gate.creole.*;
    31  import java.beans.*;
    32
    33  /**
    34    * This class compare two annotation sets on annotation type given by the
    35    * AnnotationSchema object. It also deals with graphic representation of the
    36    * result.
    37    */
    38  public class AnnotationDiff extends AbstractVisualResource{
    39
    40    /** Debug flag */
    41    private static final boolean DEBUG = false;
    42
    43    /** This document contains the key annotation set which is taken as reference
    44     *  in comparison*/
    45    private Document keyDocument = null;
    46
    47    /** The name of the annotation set. If is null then the default annotation set
    48      * will be considered.
    49      */
    50    private String keyAnnotationSetName = null;
    51
    52    /** This document contains the response annotation set which is being
    53      * compared against the key annotation set.
    54      */
    55    private Document responseDocument = null;
    56
    57    /** The name of the annotation set. If is null then the default annotation set
    58      * will be considered.
    59      */
    60    private String responseAnnotationSetName = null;
    61
    62    /** The name of the annotation set considered in calculating FalsePozitive.
    63      * If is null then the default annotation set will be considered.
    64      */
    65    private String responseAnnotationSetNameFalsePoz = null;
    66
    67    /** The annotation schema object used to get the annotation name*/
    68    private AnnotationSchema annotationSchema = null;
    69
    70    /** A set of feature names bellonging to annotations from keyAnnotList
    71      * used in isCompatible() and isPartiallyCompatible() methods
    72      */
    73    private Set keyFeatureNamesSet = null;
    74
    75    /** The precision strict value (see NLP Information Extraction)*/
    76    private double precisionStrict = 0.0;
    77    /** The precision lenient value (see NLP Information Extraction)*/
    78    private double precisionLenient = 0.0;
    79    /** The precision average value (see NLP Information Extraction)*/
    80    private double precisionAverage = 0.0;
    81
    82    /** The Recall strict value (see NLP Information Extraction)*/
    83    private double recallStrict = 0.0;
    84    /** The Recall lenient value (see NLP Information Extraction)*/
    85    private double recallLenient = 0.0;
    86    /** The Recall average value (see NLP Information Extraction)*/
    87    private double recallAverage = 0.0;
    88
    89    /** The False positive strict (see NLP Information Extraction)*/
    90    private double falsePositiveStrict = 0.0;
    91    /** The False positive lenient (see NLP Information Extraction)*/
    92    private double falsePositiveLenient = 0.0;
    93    /** The False positive average (see NLP Information Extraction)*/
    94    private double falsePositiveAverage = 0.0;
    95
    96    /** The F-measure strict (see NLP Information Extraction)*/
    97    private double fMeasureStrict = 0.0;
    98    /** The F-measure lenient (see NLP Information Extraction)*/
    99    private double fMeasureLenient = 0.0;
    100   /** The F-measure average (see NLP Information Extraction)*/
    101   private double fMeasureAverage = 0.0;
    102   /** The weight used in F-measure (see NLP Information Extraction)*/
    103   public  static double weight = 0.5;
    104
    105   /**  This string represents the type of annotations used to play the roll of
    106     *  total number of words needed to calculate the False Positive.
    107     */
    108   private String annotationTypeForFalsePositive = null;
    109
    110   /** A number formater for displaying precision and recall*/
    111   protected static NumberFormat formatter = NumberFormat.getInstance();
    112
    113   /** The components that will stay into diffPanel*/
    114   private XJTable diffTable = null;
    115
    116   /** Used to represent the result of diff. See DiffSetElement class.*/
    117   private Set diffSet = null;
    118
    119   /** This field is used in doDiff() and detectKeyType() methods and holds all
    120    *  partially correct keys */
    121   private Set keyPartiallySet = null;
    122   /** This field is used in doDiff() and detectResponseType() methods*/
    123   private Set responsePartiallySet = null;
    124
    125   /** This list is created from keyAnnotationSet at init() time*/
    126   private java.util.List keyAnnotList = null;
    127   /** This list is created from responseAnnotationSet at init() time*/
    128   private java.util.List responseAnnotList = null;
    129
    130   /** This field indicates wheter or not the annot diff should run int the text
    131    *  mode*/
    132   private boolean textMode = false;
    133
    134   /**  Field designated to represent the max nr of annot types and coolors for
    135     *  each type
    136     **/
    137   public static final int MAX_TYPES = 5;
    138   /** A default type when all annotation are the same represented by White color*/
    139   public static final int DEFAULT_TYPE = 0;
    140   /** A correct type when all annotation are corect represented by Green color*/
    141   public static final int CORRECT_TYPE = 1;
    142   /** A partially correct type when all annotation are corect represented
    143    *  by Blue color*/
    144   public static final int PARTIALLY_CORRECT_TYPE = 2;
    145   /** A spurious type when annotations in response were not present in key.
    146    *  Represented by Red color*/
    147   public static final int SPURIOUS_TYPE = 3;
    148   /** A missing type when annotations in key were not present in response
    149    *  Represented by Yellow color*/
    150   public static final int MISSING_TYPE = 4;
    151
    152   /** Red used for SPURIOUS_TYPE*/
    153   private  final Color RED = new Color(255,173,181);
    154   /** Green used for CORRECT_TYPE*/
    155   private  final Color GREEN = new Color(173,255,214);
    156   /** White used for DEFAULT_TYPE*/
    157   private  final Color WHITE = new Color(255,255,255);
    158   /** Blue used for PARTIALLY_CORRECT_TYPE*/
    159   private  final Color BLUE = new Color(173,215,255);
    160   /** Yellow used for MISSING_TYPE*/
    161   private  final Color YELLOW = new Color(255,231,173);
    162
    163   /** Used in DiffSetElement to represent an empty raw in the table*/
    164   private final int NULL_TYPE = -1;
    165   /** Used in some setForeground() methods*/
    166   private  final Color BLACK = new Color(0,0,0);
    167   /** The array holding the colours according to the annotation types*/
    168   private Color colors[] = new Color[MAX_TYPES];
    169
    170   /** A scroll for the AnnotDiff's table*/
    171   private JScrollPane scrollPane = null;
    172
    173   /** Used to store the no. of annotations from response,identified as belonging
    174     * to one of the previous types.
    175     */
    176   private int typeCounter[] = new int[MAX_TYPES];
    177
    178   /** Constructs a AnnotationDif*/
    179   public AnnotationDiff(){
    180   } //AnnotationDiff
    181
    182   /** Sets the annotation type needed to calculate the falsePossitive measure
    183     * @param anAnnotType is the annotation type needed to calculate a special
    184     *  mesure called falsePossitive. Usualy the value is "token", but it can be
    185     *  any other string with the same semantic.
    186     */
    187   public void setAnnotationTypeForFalsePositive(String anAnnotType){
    188     annotationTypeForFalsePositive = anAnnotType;
    189   } // setAnnotationTypeForFalsePositive
    190
    191   /** Gets the annotation type needed to calculate the falsePossitive measure
    192     * @return annotation type needed to calculate a special
    193     * mesure called falsePossitive.
    194     */
    195   public String getAnnotationTypeForFalsePositive(){
    196     return annotationTypeForFalsePositive;
    197   } // getAnnotationTypeForFalsePositive
    198
    199   /** Sets the keyDocument in AnnotDiff
    200     * @param aKeyDocument The GATE document used as a key in annotation diff.
    201     */
    202   public void setKeyDocument(Document aKeyDocument) {
    203     keyDocument = aKeyDocument;
    204   } // setKeyDocument
    205
    206   /** @return the keyDocument used in AnnotDiff process */
    207   public Document getKeyDocument(){
    208     return keyDocument;
    209   } // getKeyDocument
    210
    211   /** Sets the keyAnnotationSetName in AnnotDiff
    212     * @param aKeyAnnotationSetName The name of the annotation set from the
    213     * keyDocument.If aKeyAnnotationSetName is null then the default annotation
    214     * set will be used.
    215     */
    216   public void setKeyAnnotationSetName(String aKeyAnnotationSetName){
    217     keyAnnotationSetName = aKeyAnnotationSetName;
    218   } // setKeyAnnotationSetName();
    219
    220   /** Gets the keyAnnotationSetName.
    221     * @return The name of the keyAnnotationSet used in AnnotationDiff. If
    222     * returns null then the the default annotation set will be used.
    223     */
    224   public String getKeyAnnotationSetName(){
    225     return keyAnnotationSetName;
    226   } // getKeyAnnotationSetName()
    227
    228   /** Sets the keyFeatureNamesSet in AnnotDiff.
    229     * @param aKeyFeatureNamesSet a set containing the feature names from key
    230     * that will be used in isPartiallyCompatible()
    231     */
    232   public void setKeyFeatureNamesSet(Set aKeyFeatureNamesSet){
    233     keyFeatureNamesSet = aKeyFeatureNamesSet;
    234   }//setKeyFeatureNamesSet();
    235
    236   /** Gets the keyFeatureNamesSet in AnnotDiff.
    237     * @return A set containing the feature names from key
    238     * that will be used in isPartiallyCompatible()
    239     */
    240   public Set getKeyFeatureNamesSet(){
    241     return keyFeatureNamesSet;
    242   }//getKeyFeatureNamesSet();
    243
    244   /** Sets the responseAnnotationSetName in AnnotDiff
    245     * @param aResponseAnnotationSetName The name of the annotation set from the
    246     * responseDocument.If aResponseAnnotationSetName is null then the default
    247     * annotation set will be used.
    248     */
    249   public void setResponseAnnotationSetName(String aResponseAnnotationSetName){
    250     responseAnnotationSetName = aResponseAnnotationSetName;
    251   } // setResponseAnnotationSetName();
    252
    253   /** gets the responseAnnotationSetName.
    254     * @return The name of the responseAnnotationSet used in AnnotationDiff. If
    255     * returns null then the the default annotation set will be used.
    256     */
    257   public String getResponseAnnotationSetName(){
    258     return responseAnnotationSetName;
    259   } // getResponseAnnotationSetName()
    260
    261   /** Sets the responseAnnotationSetNameFalsePoz in AnnotDiff
    262     * @param aResponseAnnotationSetNameFalsePoz The name of the annotation set
    263     * from the responseDocument.If aResponseAnnotationSetName is null
    264     * then the default annotation set will be used.
    265     */
    266   public void setResponseAnnotationSetNameFalsePoz(
    267                                     String aResponseAnnotationSetNameFalsePoz){
    268     responseAnnotationSetNameFalsePoz = aResponseAnnotationSetNameFalsePoz;
    269   } // setResponseAnnotationSetNameFalsePoz();
    270
    271   /** gets the responseAnnotationSetNameFalsePoz.
    272     * @return The name of the responseAnnotationSetFalsePoz used in
    273     * AnnotationDiff. If returns null then the the default annotation
    274     * set will be used.
    275     */
    276   public String getResponseAnnotationSetNameFalsePoz(){
    277     return responseAnnotationSetNameFalsePoz;
    278   } // getResponseAnnotationSetNamefalsePoz()
    279
    280   /**  Sets the annot diff to work in the text mode.This would not initiate the
    281     *  GUI part of annot diff but it would calculate precision etc
    282     */
    283   public void setTextMode(Boolean aTextMode){
    284     //it needs to be a Boolean and not boolean, because you cannot put
    285     //in the parameters hashmap a boolean, it needs an object
    286     textMode = aTextMode.booleanValue();
    287   }// End setTextMode();
    288
    289   /** Gets the annot diff textmode.True means that the text mode is activated.*/
    290   public boolean isTextMode(){
    291     return textMode;
    292   }// End setTextMode();
    293
    294   /** Returns a set with all annotations of a specific type*/
    295   public Set getAnnotationsOfType(int annotType){
    296     HashSet results = new HashSet();
    297     if (diffSet == null) return results;
    298     Iterator diffIter = diffSet.iterator();
    299     while(diffIter.hasNext()){
    300       DiffSetElement diffElem = (DiffSetElement)diffIter.next();
    301       switch(annotType){
    302         case CORRECT_TYPE:{
    303           if (diffElem.getRightType() == CORRECT_TYPE)
    304             results.add(diffElem.getRightAnnotation());
    305         }break;
    306         case PARTIALLY_CORRECT_TYPE:{
    307           if (diffElem.getRightType() == PARTIALLY_CORRECT_TYPE)
    308             results.add(diffElem.getRightAnnotation());
    309         }break;
    310         case SPURIOUS_TYPE:{
    311           if (diffElem.getRightType() == SPURIOUS_TYPE)
    312             results.add(diffElem.getRightAnnotation());
    313         }break;
    314         case MISSING_TYPE:{
    315           if (diffElem.getLeftType() == MISSING_TYPE)
    316             results.add(diffElem.getLeftAnnotation());
    317         }break;
    318         case DEFAULT_TYPE:{
    319           if (diffElem.getLeftType() == DEFAULT_TYPE)
    320             results.add(diffElem.getLeftAnnotation());
    321         }break;
    322       }// End switch
    323     }// End while
    324     return results;
    325   }//getAnnotationsOfType
    326
    327   //Prameters utility methods
    328   /**
    329    * Gets the value of a parameter of this resource.
    330    * @param paramaterName the name of the parameter
    331    * @return the current value of the parameter
    332    */
    333   public Object getParameterValue(String paramaterName)
    334                 throws ResourceInstantiationException{
    335     return AbstractResource.getParameterValue(this, paramaterName);
    336   }
    337
    338   /**
    339    * Sets the value for a specified parameter.
    340    *
    341    * @param paramaterName the name for the parameteer
    342    * @param parameterValue the value the parameter will receive
    343    */
    344   public void setParameterValue(String paramaterName, Object parameterValue)
    345               throws ResourceInstantiationException{
    346     // get the beaninfo for the resource bean, excluding data about Object
    347     BeanInfo resBeanInf = null;
    348     try {
    349       resBeanInf = Introspector.getBeanInfo(this.getClass(), Object.class);
    350     } catch(Exception e) {
    351       throw new ResourceInstantiationException(
    352         "Couldn't get bean info for resource " + this.getClass().getName()
    353         + Strings.getNl() + "Introspector exception was: " + e
    354       );
    355     }
    356     AbstractResource.setParameterValue(this, resBeanInf, paramaterName, parameterValue);
    357   }
    358
    359   /**
    360    * Sets the values for more parameters in one step.
    361    *
    362    * @param parameters a feature map that has paramete names as keys and
    363    * parameter values as values.
    364    */
    365   public void setParameterValues(FeatureMap parameters)
    366               throws ResourceInstantiationException{
    367     AbstractResource.setParameterValues(this, parameters);
    368   }
    369
    370
    371
    372   ///////////////////////////////////////////////////
    373   // PRECISION methods
    374   ///////////////////////////////////////////////////
    375
    376   /** @return the precisionStrict field*/
    377   public double getPrecisionStrict(){
    378     return precisionStrict;
    379   } // getPrecisionStrict
    380
    381   /** @return the precisionLenient field*/
    382   public double getPrecisionLenient(){
    383     return precisionLenient;
    384   } // getPrecisionLenient
    385
    386   /** @return the precisionAverage field*/
    387   public double getPrecisionAverage(){
    388     return precisionAverage;
    389   } // getPrecisionAverage
    390
    391   /** @return the fMeasureStrict field*/
    392   public double getFMeasureStrict(){
    393     return fMeasureStrict;
    394   } // getFMeasureStrict
    395
    396   /** @return the fMeasureLenient field*/
    397   public double getFMeasureLenient(){
    398     return fMeasureLenient;
    399   } // getFMeasureLenient
    400
    401   /** @return the fMeasureAverage field*/
    402   public double getFMeasureAverage(){
    403     return fMeasureAverage;
    404   } // getFMeasureAverage
    405
    406   ///////////////////////////////////////////////////
    407   // RECALL methods
    408   ///////////////////////////////////////////////////
    409
    410   /** @return the recallStrict field*/
    411   public double getRecallStrict(){
    412     return recallStrict;
    413   } // getRecallStrict
    414
    415   /** @return the recallLenient field*/
    416   public double getRecallLenient(){
    417     return recallLenient;
    418   } // getRecallLenient
    419
    420   /** @return the recallAverage field*/
    421   public double getRecallAverage(){
    422     return recallAverage;
    423   } // getRecallAverage
    424
    425   ///////////////////////////////////////////////////
    426   // FALSE POSITIVE methods
    427   ///////////////////////////////////////////////////
    428
    429   /** @return the falsePositiveStrict field*/
    430   public double getFalsePositiveStrict(){
    431     return falsePositiveStrict;
    432   } // getFalsePositiveStrict
    433
    434   /** @return the falsePositiveLenient field*/
    435   public double getFalsePositiveLenient(){
    436     return falsePositiveLenient;
    437   } // getFalsePositiveLenient
    438
    439   /** @return the falsePositiveAverage field*/
    440   public double getFalsePositiveAverage(){
    441     return falsePositiveAverage;
    442   } // getFalsePositive
    443
    444   /**
    445     * @param aResponseDocument the GATE response Document
    446     * containing the annotation Set being compared against the annotation from
    447     * the keyDocument.
    448     */
    449   public void setResponseDocument(Document aResponseDocument) {
    450     responseDocument = aResponseDocument;
    451   } //setResponseDocument
    452
    453   /**
    454     * @param anAnnotationSchema the annotation type being compared.
    455     * This type is found in annotationSchema object as field
    456     * {@link gate.creole.AnnotationSchema#getAnnotationName()}. If is <b>null<b>
    457     * then AnnotDiff will throw an exception when it comes to do the diff.
    458     */
    459   public void setAnnotationSchema(AnnotationSchema anAnnotationSchema) {
    460     annotationSchema = anAnnotationSchema;
    461   } // setAnnotationType
    462
    463   /** @return the annotation schema object used in annotation diff process */
    464   public AnnotationSchema getAnnotationSchema(){
    465     return annotationSchema;
    466   } // AnnotationSchema
    467
    468   /**
    469     * This method does the diff, Precision,Recall,FalsePositive
    470     * calculation and so on.
    471     */
    472   public Resource init() throws ResourceInstantiationException {
    473     colors[DEFAULT_TYPE] = WHITE;
    474     colors[CORRECT_TYPE] = GREEN;
    475     colors[SPURIOUS_TYPE] = RED;
    476     colors[PARTIALLY_CORRECT_TYPE] = BLUE;
    477     colors[MISSING_TYPE] = YELLOW;
    478
    479     // Initialize the partially sets...
    480     keyPartiallySet = new HashSet();
    481     responsePartiallySet = new HashSet();
    482
    483     // Do the diff, P&R calculation and so on
    484     AnnotationSet keyAnnotSet = null;
    485     AnnotationSet responseAnnotSet = null;
    486
    487     if(annotationSchema == null)
    488      throw new ResourceInstantiationException("No annotation schema defined !");
    489
    490     if(keyDocument == null)
    491       throw new ResourceInstantiationException("No key document defined !");
    492
    493     if(responseDocument == null)
    494       throw new ResourceInstantiationException("No response document defined !");
    495
    496     if (keyAnnotationSetName == null)
    497       // Get the default key AnnotationSet from the keyDocument
    498       keyAnnotSet = keyDocument.getAnnotations().get(
    499                               annotationSchema.getAnnotationName());
    500     else
    501       keyAnnotSet = keyDocument.getAnnotations(keyAnnotationSetName).
    502                                     get(annotationSchema.getAnnotationName());
    503
    504     if (keyAnnotSet == null)
    505       // The diff will run with an empty set.All annotations from response
    506       // would be spurious.
    507       keyAnnotList = new LinkedList();
    508     else
    509       // The alghoritm will modify this annotation set. It is better to make a
    510       // separate copy of them.
    511       keyAnnotList = new LinkedList(keyAnnotSet);
    512
    513     if (responseAnnotationSetName == null)
    514       // Get the response AnnotationSet from the default set
    515       responseAnnotSet = responseDocument.getAnnotations().get(
    516                                           annotationSchema.getAnnotationName());
    517     else
    518       responseAnnotSet = responseDocument.getAnnotations(responseAnnotationSetName).
    519                                     get(annotationSchema.getAnnotationName());
    520
    521     if (responseAnnotSet == null)
    522       // The diff will run with an empty set.All annotations from key
    523       // would be missing.
    524       responseAnnotList = new LinkedList();
    525     else
    526       // The alghoritm will modify this annotation set. It is better to make a
    527       // separate copy of them.
    528       responseAnnotList = new LinkedList(responseAnnotSet);
    529
    530     // Sort them ascending on Start offset (the comparator does that)
    531     AnnotationSetComparator asComparator = new AnnotationSetComparator();
    532     Collections.sort(keyAnnotList, asComparator);
    533     Collections.sort(responseAnnotList, asComparator);
    534
    535     for (int type=0; type < MAX_TYPES; type++)
    536       typeCounter[type] = 0;
    537
    538     // Calculate the diff Set. This set will be used later with graphic
    539     // visualisation.
    540     doDiff(keyAnnotList, responseAnnotList);
    541
    542     // If it runs under text mode just stop here.
    543     if (textMode) return this;
    544
    545     //Show it
    546     // Configuring the formatter object. It will be used later to format
    547     // precision and recall
    548     formatter.setMaximumIntegerDigits(1);
    549     formatter.setMinimumFractionDigits(4);
    550     formatter.setMinimumFractionDigits(4);
    551
    552     // Create an Annotation diff table model
    553     AnnotationDiffTableModel diffModel = new AnnotationDiffTableModel(diffSet);
    554     // Create a XJTable based on this model
    555     diffTable = new XJTable(diffModel);
    556     diffTable.setAlignmentX(Component.LEFT_ALIGNMENT);
    557     // Set the cell renderer for this table.
    558     AnnotationDiffCellRenderer cellRenderer = new AnnotationDiffCellRenderer();
    559     diffTable.setDefaultRenderer(java.lang.String.class,cellRenderer);
    560     diffTable.setDefaultRenderer(java.lang.Long.class,cellRenderer);
    561     // Put the table into a JScroll
    562
    563     // Arange all components on a this JPanel
    564     SwingUtilities.invokeLater(new Runnable(){
    565       public void run(){
    566         arangeAllComponents();
    567       }
    568     });
    569
    570     if (DEBUG)
    571       printStructure(diffSet);
    572
    573     return this;
    574   } //init()
    575
    576   /** This method creates the graphic components and aranges them on
    577     * <b>this</b> JPanel
    578     */
    579   protected void arangeAllComponents(){
    580     this.removeAll();
    581     // Setting the box layout for diffpanel
    582     BoxLayout boxLayout = new BoxLayout(this,BoxLayout.Y_AXIS);
    583     this.setLayout(boxLayout);
    584
    585     JTableHeader tableHeader = diffTable.getTableHeader();
    586     tableHeader.setAlignmentX(Component.LEFT_ALIGNMENT);
    587     this.add(tableHeader);
    588     diffTable.setAlignmentX(Component.LEFT_ALIGNMENT);
    589     // Add the tableScroll to the diffPanel
    590     this.add(diffTable);
    591
    592     // ADD the LEGEND
    593     //Lay out the JLabels from left to right.
    594     //Box infoBox = new Box(BoxLayout.X_AXIS);
    595     JPanel infoBox = new  JPanel();
    596     infoBox.setLayout(new BoxLayout(infoBox,BoxLayout.X_AXIS));
    597     infoBox.setAlignmentX(Component.LEFT_ALIGNMENT);
    598     // Keep the components together
    599     //box.add(Box.createHorizontalGlue());
    600
    601     Box box = new Box(BoxLayout.Y_AXIS);
    602     JLabel jLabel = new JLabel("LEGEND");
    603     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
    604     jLabel.setOpaque(true);
    605     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
    606     box.add(jLabel);
    607
    608     jLabel = new JLabel("Missing (present in Key but not in Response):  " +
    609                                                 typeCounter[MISSING_TYPE]);
    610     jLabel.setForeground(BLACK);
    611     jLabel.setBackground(colors[MISSING_TYPE]);
    612     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
    613     jLabel.setOpaque(true);
    614     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
    615     box.add(jLabel);
    616
    617     // Add a space
    618     box.add(Box.createRigidArea(new Dimension(0,5)));
    619
    620     jLabel = new JLabel("Correct (total match):  " + typeCounter[CORRECT_TYPE]);
    621     jLabel.setForeground(BLACK);
    622     jLabel.setBackground(colors[CORRECT_TYPE]);
    623     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
    624     jLabel.setOpaque(true);
    625     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
    626     box.add(jLabel);
    627
    628     // Add a space
    629     box.add(Box.createRigidArea(new Dimension(0,5)));
    630
    631     jLabel =new JLabel("Partially correct (overlap in Key and Response):  "+
    632                                         typeCounter[PARTIALLY_CORRECT_TYPE]);
    633     jLabel.setForeground(BLACK);
    634     jLabel.setBackground(colors[PARTIALLY_CORRECT_TYPE]);
    635     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
    636     jLabel.setOpaque(true);
    637     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
    638     box.add(jLabel);
    639
    640     // Add a space
    641     box.add(Box.createRigidArea(new Dimension(0,5)));
    642
    643     jLabel = new JLabel("Spurious (present in Response but not in Key):  " +
    644                                         typeCounter[SPURIOUS_TYPE]);
    645     jLabel.setForeground(BLACK);
    646     jLabel.setBackground(colors[SPURIOUS_TYPE]);
    647     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
    648     jLabel.setOpaque(true);
    649     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
    650     box.add(jLabel);
    651
    652     infoBox.add(box);
    653     // Add a space
    654     infoBox.add(Box.createRigidArea(new Dimension(40,0)));
    655
    656     // Precision measure
    657     //Lay out the JLabels from left to right.
    658     box = new Box(BoxLayout.Y_AXIS);
    659
    660     jLabel = new JLabel("Precision strict: " +
    661                                     formatter.format(precisionStrict));
    662     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
    663     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
    664     box.add(jLabel);
    665
    666     jLabel = new JLabel("Precision average: " +
    667                                     formatter.format(precisionAverage));
    668     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
    669     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
    670     box.add(jLabel);
    671
    672     jLabel = new JLabel("Precision lenient: " +
    673                                     formatter.format(precisionLenient));
    674     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
    675     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
    676     box.add(jLabel);
    677
    678     infoBox.add(box);
    679     // Add a space
    680     infoBox.add(Box.createRigidArea(new Dimension(40,0)));
    681
    682     // RECALL measure
    683     //Lay out the JLabels from left to right.
    684     box = new Box(BoxLayout.Y_AXIS);
    685
    686     jLabel = new JLabel("Recall strict: " + formatter.format(recallStrict));
    687     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
    688     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
    689     box.add(jLabel);
    690
    691     jLabel = new JLabel("Recall average: " + formatter.format(recallAverage));
    692     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
    693     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
    694     box.add(jLabel);
    695
    696     jLabel = new JLabel("Recall lenient: " + formatter.format(recallLenient));
    697     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
    698     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
    699     box.add(jLabel);
    700
    701     infoBox.add(box);
    702     // Add a space
    703     infoBox.add(Box.createRigidArea(new Dimension(40,0)));
    704
    705     // F-Measure
    706     //Lay out the JLabels from left to right.
    707     box = new Box(BoxLayout.Y_AXIS);
    708
    709     jLabel = new JLabel("F-Measure strict: " +
    710                                         formatter.format(fMeasureStrict));
    711     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
    712     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
    713     box.add(jLabel);
    714
    715     jLabel = new JLabel("F-Measure average: " +
    716                                         formatter.format(fMeasureAverage));
    717     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
    718     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
    719     box.add(jLabel);
    720
    721     jLabel = new JLabel("F-Measure lenient: " +
    722                                         formatter.format(fMeasureLenient));
    723     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
    724     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
    725     box.add(jLabel);
    726     infoBox.add(box);
    727
    728     // Add a space
    729     infoBox.add(Box.createRigidArea(new Dimension(40,0)));
    730
    731     // FALSE POZITIVE measure
    732     //Lay out the JLabels from left to right.
    733     box = new Box(BoxLayout.Y_AXIS);
    734
    735     jLabel = new JLabel("False positive strict: " +
    736                                         formatter.format(falsePositiveStrict));
    737     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
    738     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
    739     box.add(jLabel);
    740
    741     jLabel = new JLabel("False positive average: " +
    742                                         formatter.format(falsePositiveAverage));
    743     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
    744     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
    745     box.add(jLabel);
    746
    747     jLabel = new JLabel("False positive lenient: " +
    748                                         formatter.format(falsePositiveLenient));
    749     jLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
    750     jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD));
    751     box.add(jLabel);
    752     infoBox.add(box);
    753
    754     // Add a space
    755     infoBox.add(Box.createRigidArea(new Dimension(10,0)));
    756
    757     this.add(infoBox);
    758   } //arangeAllComponents
    759
    760   /** Used internally for debugging */
    761   protected void printStructure(Set aDiffSet){
    762     Iterator iterator = aDiffSet.iterator();
    763     String leftAnnot = null;
    764     String rightAnnot = null;
    765     while(iterator.hasNext()){
    766       DiffSetElement diffElem = (DiffSetElement) iterator.next();
    767       if (diffElem.getLeftAnnotation() == null)
    768         leftAnnot = "NULL ";
    769       else
    770         leftAnnot = diffElem.getLeftAnnotation().toString();
    771       if (diffElem.getRightAnnotation() == null)
    772         rightAnnot = " NULL";
    773       else
    774         rightAnnot = diffElem.getRightAnnotation().toString();
    775       Out.prln( leftAnnot + "|" + rightAnnot);
    776     } // end while
    777   } // printStructure
    778
    779   /** This method is the brain of the AnnotationSet diff and creates a set with
    780     * diffSetElement objects.
    781     * @param aKeyAnnotList a list containing the annotations from key. If this
    782     * param is <b>null</b> then the method will simply return and will not do a
    783     * thing.
    784     * @param aResponseAnnotList a list containing the annotation from response.
    785     * If this param is <b>null</b> the method will return.
    786     */
    787   protected void doDiff(java.util.List aKeyAnnotList,
    788                         java.util.List aResponseAnnotList){
    789
    790     // If one of the annotation sets is null then is no point in doing the diff.
    791     if (aKeyAnnotList == null || aResponseAnnotList == null)
    792       return;
    793
    794     int responseSize = aResponseAnnotList.size();
    795
    796     diffSet = new HashSet();
    797     // Iterate throught all elements from keyList and find those in the response
    798     // list which satisfies isCompatible() and isPartiallyCompatible() relations
    799     Iterator keyIterator = aKeyAnnotList.iterator();
    800     while(keyIterator.hasNext()){
    801       Annotation keyAnnot = (Annotation) keyIterator.next();
    802       Iterator responseIterator = aResponseAnnotList.iterator();
    803
    804       DiffSetElement diffElement = null;
    805       while(responseIterator.hasNext()){
    806         Annotation responseAnnot = (Annotation) responseIterator.next();
    807
    808         if(keyAnnot.isPartiallyCompatible(responseAnnot,keyFeatureNamesSet)){
    809           keyPartiallySet.add(keyAnnot);
    810           responsePartiallySet.add(responseAnnot);
    811           if (keyAnnot.coextensive(responseAnnot)){
    812             // Found two compatible annotations
    813             // Create a new DiffSetElement and add it to the diffSet
    814             diffElement = new DiffSetElement( keyAnnot,
    815                                               responseAnnot,
    816                                               DEFAULT_TYPE,
    817                                               CORRECT_TYPE);
    818
    819             // Add this element to the DiffSet
    820             addToDiffset(diffElement);
    821           } // End if (keyAnnot.coextensive(responseAnnot))
    822         }else if (keyAnnot.coextensive(responseAnnot)){
    823           // Found two aligned annotations. We have to find out if the response
    824           // is partialy compatible with another key annotation.
    825           // Create a new DiffSetElement and add it to the diffSet
    826           diffElement = new DiffSetElement( keyAnnot,
    827                                             responseAnnot,
    828                                             detectKeyType(keyAnnot),
    829                                             detectResponseType(responseAnnot));
    830           // Add this element to the DiffSet
    831           addToDiffset(diffElement);
    832         } // End if (keyAnnot.coextensive(responseAnnot)){
    833
    834         if (diffElement != null){
    835           // Eliminate the response annotation from the list.
    836           responseIterator.remove();
    837           break;
    838         } // End if
    839       } // end while responseIterator
    840
    841       // If diffElement != null it means that break was used
    842       if (diffElement == null){
    843         if (keyPartiallySet.contains(keyAnnot))
    844           diffElement = new DiffSetElement( keyAnnot,
    845                                             null,
    846                                             DEFAULT_TYPE,
    847                                             NULL_TYPE);
    848         else{
    849           // If keyAnnot is not in keyPartiallySet then it has to be checked
    850           // agains all annotations in DiffSet to see if there is
    851           // a previous annotation from response set which is partially
    852           // compatible with the keyAnnot
    853           Iterator respParIter = diffSet.iterator();
    854           while (respParIter.hasNext()){
    855             DiffSetElement diffElem = (DiffSetElement) respParIter.next();
    856             Annotation respAnnot = diffElem.getRightAnnotation();
    857             if (respAnnot != null && keyAnnot.isPartiallyCompatible(respAnnot,
    858                                                           keyFeatureNamesSet)){
    859                 diffElement = new DiffSetElement( keyAnnot,
    860                                                   null,
    861                                                   DEFAULT_TYPE,
    862                                                   NULL_TYPE);
    863                 break;
    864             } // End if
    865           } // End while
    866           // If is still nul then it means that the key annotation is missing
    867           if (diffElement == null)
    868             diffElement = new DiffSetElement( keyAnnot,
    869                                               null,
    870                                               MISSING_TYPE,
    871                                               NULL_TYPE);
    872         } // End if
    873         addToDiffset(diffElement);
    874       } // End if
    875
    876       keyIterator.remove();
    877     } // end while keyIterator
    878
    879     DiffSetElement diffElem = null;
    880     Iterator responseIter = aResponseAnnotList.iterator();
    881     while (responseIter.hasNext()){
    882       Annotation respAnnot = (Annotation) responseIter.next();
    883       if (responsePartiallySet.contains(respAnnot))
    884         diffElem = new DiffSetElement( null,
    885                                        respAnnot,
    886                                        NULL_TYPE,
    887                                        PARTIALLY_CORRECT_TYPE);
    888       else
    889         diffElem = new DiffSetElement( null,
    890                                        respAnnot,
    891                                        NULL_TYPE,
    892                                        SPURIOUS_TYPE);
    893       addToDiffset(diffElem);
    894       responseIter.remove();
    895     } // End while
    896
    897     // CALCULATE ALL (NLP) MEASURES like:
    898     // Precistion, Recall, FalsePositive and F-Measure
    899     int possible =  typeCounter[CORRECT_TYPE] +  // this comes from Key or Resp
    900                     typeCounter[PARTIALLY_CORRECT_TYPE] + // this comes from Resp
    901                     typeCounter[MISSING_TYPE]; // this comes from Key
    902
    903     int actual =  typeCounter[CORRECT_TYPE] +  // this comes from Key or Resp
    904                   typeCounter[PARTIALLY_CORRECT_TYPE] + // this comes from Resp
    905                   typeCounter[SPURIOUS_TYPE]; // this comes from Resp
    906
    907     if (actual != responseSize)
    908       Err.prln("AnnotDiff warning: The response size(" + responseSize +
    909       ") is not the same as the computed value of" +
    910     " actual(Correct[resp or key]+Partial[resp]+Spurious[resp]=" + actual +")");
    911
    912     if (actual != 0){
    913       precisionStrict =  ((double)typeCounter[CORRECT_TYPE])/((double)actual);
    914       precisionLenient = ((double)(typeCounter[CORRECT_TYPE] +
    915                          typeCounter[PARTIALLY_CORRECT_TYPE]))/((double)actual);
    916       precisionAverage = ((double)(precisionStrict + precisionLenient)) /
    917                                                                   ((double) 2);
    918     } // End if
    919     if (possible != 0){
    920       recallStrict = ((double)typeCounter[CORRECT_TYPE])/((double)possible);
    921       recallLenient = ((double)(typeCounter[CORRECT_TYPE] +
    922                        typeCounter[PARTIALLY_CORRECT_TYPE]))/((double)possible);
    923       recallAverage = ((double)(recallStrict + recallLenient)) / ((double)2);
    924     } // End if
    925
    926
    927     int no = 0;
    928     // If an annotation type for false poz was selected calculate the number of
    929     // Annotations
    930     if (annotationTypeForFalsePositive != null)
    931      // Was it the default set ?
    932      if (responseAnnotationSetNameFalsePoz == null)
    933           no = responseDocument.getAnnotations().get(
    934                                       annotationTypeForFalsePositive).size();
    935      else
    936       no = responseDocument.getAnnotations(responseAnnotationSetNameFalsePoz).get(
    937                                         annotationTypeForFalsePositive).size();
    938     if (no != 0){
    939       // No error here: the formula is the opposite to recall or precission
    940      falsePositiveStrict = ((double)(typeCounter[SPURIOUS_TYPE] +
    941                              typeCounter[PARTIALLY_CORRECT_TYPE])) /((double)no);
    942      falsePositiveLenient = ((double)typeCounter[SPURIOUS_TYPE]) /((double) no);
    943      falsePositiveAverage = ((double)(falsePositiveStrict +
    944                                            falsePositiveLenient))/((double)2) ;
    945     } // End if
    946
    947     // Calculate F-Measure Strict
    948     double denominator = weight * (precisionStrict + recallStrict);
    949     if (denominator != 0)
    950       fMeasureStrict = (precisionStrict * recallStrict) / denominator ;
    951     else fMeasureStrict = 0.0;
    952     // Calculate F-Measure Lenient
    953     denominator = weight * (precisionLenient + recallLenient);
    954     if (denominator != 0)
    955       fMeasureLenient = (precisionLenient * recallLenient) / denominator ;
    956     else fMeasureLenient = 0.0;
    957     // Calculate F-Measure Average
    958     fMeasureAverage = (fMeasureStrict + fMeasureLenient) / (double)2;
    959
    960   } // doDiff
    961
    962   /** Decide what type is the keyAnnotation (DEFAULT_TYPE, MISSING or NULL_TYPE)
    963    *  This method must be applied only on annotation from key set.
    964    *  @param anAnnot is an annotation from the key set.
    965    *  @return three possible value(DEFAULT_TYPE, MISSING or NULL_TYPE)
    966    */
    967   private int detectKeyType(Annotation anAnnot){
    968     if (anAnnot == null) return NULL_TYPE;
    969
    970     if (keyPartiallySet.contains(anAnnot)) return DEFAULT_TYPE;
    971     Iterator iter = responsePartiallySet.iterator();
    972     while(iter.hasNext()){
    973       Annotation a = (Annotation) iter.next();
    974       if (anAnnot.isPartiallyCompatible(a,keyFeatureNamesSet))
    975         return DEFAULT_TYPE;
    976     } // End while
    977
    978     iter = responseAnnotList.iterator();
    979     while(iter.hasNext()){
    980       Annotation a = (Annotation) iter.next();
    981       if (anAnnot.isPartiallyCompatible(a,keyFeatureNamesSet)){
    982          responsePartiallySet.add(a);
    983          keyPartiallySet.add(anAnnot);
    984          return DEFAULT_TYPE;
    985       } // End if
    986     } // End while
    987     return MISSING_TYPE;
    988   } //detectKeyType
    989
    990   /**  Decide what type is the responseAnnotation
    991     *  (PARTIALLY_CORRECT_TYPE, SPURIOUS or NULL_TYPE)
    992     *  This method must be applied only on annotation from response set.
    993     *  @param anAnnot is an annotation from the key set.
    994     *  @return three possible value(PARTIALLY_CORRECT_TYPE, SPURIOUS or NULL_TYPE)
    995     */
    996   private int detectResponseType(Annotation anAnnot){
    997     if (anAnnot == null) return NULL_TYPE;
    998
    999     if (responsePartiallySet.contains(anAnnot)) return PARTIALLY_CORRECT_TYPE;
    1000    Iterator iter = keyPartiallySet.iterator();
    1001    while(iter.hasNext()){
    1002      Annotation a = (Annotation) iter.next();
    1003      if (a.isPartiallyCompatible(anAnnot,keyFeatureNamesSet))
    1004        return PARTIALLY_CORRECT_TYPE;
    1005    } // End while
    1006
    1007    iter = keyAnnotList.iterator();
    1008    while(iter.hasNext()){
    1009      Annotation a = (Annotation) iter.next();
    1010      if (a.isPartiallyCompatible(anAnnot,keyFeatureNamesSet)){
    1011         responsePartiallySet.add(anAnnot);
    1012         keyPartiallySet.add(a);
    1013         return PARTIALLY_CORRECT_TYPE;
    1014      } // End if
    1015    } // End while
    1016    return SPURIOUS_TYPE;
    1017  } //detectResponseType
    1018
    1019  /** This method add an DiffsetElement to the DiffSet and also counts the
    1020    * number of compatible, partialCompatible, Incorect and Missing annotations.
    1021    */
    1022  private void addToDiffset(DiffSetElement aDiffSetElement){
    1023    if (aDiffSetElement == null) return;
    1024
    1025    diffSet.add(aDiffSetElement);
    1026    // For the Right side (response) the type can be one of the following:
    1027    // PC, I, C
    1028    if (NULL_TYPE != aDiffSetElement.getRightType())
    1029      typeCounter[aDiffSetElement.getRightType()]++;
    1030    // For the left side (key) the type can be : D or M
    1031    if (NULL_TYPE != aDiffSetElement.getLeftType() &&
    1032        CORRECT_TYPE != aDiffSetElement.getLeftType())
    1033      typeCounter[aDiffSetElement.getLeftType()]++;
    1034  } // addToDiffset
    1035
    1036  /* ********************************************************************
    1037   * INNER CLASS
    1038   * ********************************************************************/
    1039
    1040  /**
    1041    * A custom table model used to render a table containing the two annotation
    1042    * sets. The columns will be:
    1043    * (KEY) Type, Start, End, Features, empty column,(Response) Type,Start, End, Features
    1044    */
    1045  protected class AnnotationDiffTableModel extends AbstractTableModel{
    1046
    1047    /** Constructs an AnnotationDiffTableModel given a data Collection */
    1048    public AnnotationDiffTableModel(Collection data){
    1049      modelData = new ArrayList();
    1050      modelData.addAll(data);
    1051    } // AnnotationDiffTableModel
    1052
    1053    /** Constructs an AnnotationDiffTableModel */
    1054    public AnnotationDiffTableModel(){
    1055      modelData = new ArrayList();
    1056    } // AnnotationDiffTableModel
    1057
    1058    /** Return the size of data.*/
    1059    public int getRowCount(){
    1060      return modelData.size();
    1061    } //getRowCount
    1062
    1063    /** Return the number of columns.*/
    1064    public int getColumnCount(){
    1065      return 9;
    1066    } //getColumnCount
    1067
    1068    /** Returns the name of each column in the model*/
    1069    public String getColumnName(int column){
    1070      switch(column){
    1071        case 0: return "Type - Key";
    1072        case 1: return "Start - Key";
    1073        case 2: return "End - Key";
    1074        case 3: return "Features - Key";
    1075        case 4: return "   ";
    1076        case 5: return "Type - Response";
    1077        case 6: return "Start - Response";
    1078        case 7: return "End -Response";
    1079        case 8: return "Features - Response";
    1080        default:return "?";
    1081      }
    1082    } //getColumnName
    1083
    1084    /** Return the class type for each column. */
    1085    public Class getColumnClass(int column){
    1086      switch(column){
    1087        case 0: return String.class;
    1088        case 1: return Long.class;
    1089        case 2: return Long.class;
    1090        case 3: return String.class;
    1091        case 4: return String.class;
    1092        case 5: return String.class;
    1093        case 6: return Long.class;
    1094        case 7: return Long.class;
    1095        case 8: return String.class;
    1096        default:return Object.class;
    1097      }
    1098    } //getColumnClass
    1099
    1100    /**Returns a value from the table model */
    1101    public Object getValueAt(int row, int column){
    1102      DiffSetElement diffSetElement = (DiffSetElement) modelData.get(row);
    1103      if (diffSetElement == null) return null;
    1104      switch(column){
    1105        // Left Side (Key)
    1106        //Type - Key
    1107        case 0:{
    1108           if (diffSetElement.getLeftAnnotation() == null) return null;
    1109           return diffSetElement.getLeftAnnotation().getType();
    1110        }
    1111        // Start - Key
    1112        case 1:{
    1113           if (diffSetElement.getLeftAnnotation() == null) return null;
    1114           return diffSetElement.getLeftAnnotation().getStartNode().getOffset();
    1115        }
    1116        // End - Key
    1117        case 2:{
    1118           if (diffSetElement.getLeftAnnotation() == null) return null;
    1119           return diffSetElement.getLeftAnnotation().getEndNode().getOffset();
    1120        }
    1121        // Features - Key
    1122        case 3:{
    1123           if (diffSetElement.getLeftAnnotation() == null) return null;
    1124           if (diffSetElement.getLeftAnnotation().getFeatures() == null)
    1125             return null;
    1126           return diffSetElement.getLeftAnnotation().getFeatures().toString();
    1127        }
    1128        // Empty column
    1129        case 4:{
    1130          return "   ";
    1131        }
    1132        // Right Side (Response)
    1133        //Type - Response
    1134        case 5:{
    1135           if (diffSetElement.getRightAnnotation() == null) return null;
    1136           return diffSetElement.getRightAnnotation().getType();
    1137        }
    1138        // Start - Response
    1139        case 6:{
    1140           if (diffSetElement.getRightAnnotation() == null) return null;
    1141          return diffSetElement.getRightAnnotation().getStartNode().getOffset();
    1142        }
    1143        // End - Response
    1144        case 7:{
    1145           if (diffSetElement.getRightAnnotation() == null) return null;
    1146           return diffSetElement.getRightAnnotation().getEndNode().getOffset();
    1147        }
    1148        // Features - resonse
    1149        case 8:{
    1150           if (diffSetElement.getRightAnnotation() == null) return null;
    1151           return diffSetElement.getRightAnnotation().getFeatures().toString();
    1152        }
    1153        // The hidden column
    1154        case 9:{
    1155          return diffSetElement;
    1156        }
    1157        default:{return null;}
    1158      } // End switch
    1159    } //getValueAt
    1160
    1161    public Object getRawObject(int row){
    1162      return modelData.get(row);
    1163    } //getRawObject
    1164
    1165    /** Holds the data for TableDiff*/
    1166    private java.util.List modelData = null;
    1167
    1168  } //Inner class AnnotationDiffTableModel
    1169
    1170  /* ********************************************************************
    1171   * INNER CLASS
    1172   * ********************************************************************/
    1173  /**
    1174    * This class defines a Cell renderer for the AnnotationDiff table
    1175    */
    1176  public class AnnotationDiffCellRenderer extends DefaultTableCellRenderer{
    1177
    1178    /** Constructs a randerer with a table model*/
    1179    public AnnotationDiffCellRenderer() { }  //AnnotationDiffCellRenderer
    1180
    1181    private Color background = WHITE;
    1182
    1183    private Color foreground = BLACK;
    1184
    1185    /** This method is called by JTable*/
    1186
    1187    public Component getTableCellRendererComponent(
    1188      JTable table, Object value, boolean isSelected, boolean hasFocus,
    1189      int row, int column
    1190    ) {
    1191      JComponent defaultComp = null;
    1192      defaultComp = (JComponent) super.getTableCellRendererComponent(
    1193  table, value, isSelected, hasFocus, row, column
    1194      );
    1195
    1196      // The column number four will be randered using a blank component
    1197      if (column == 4 || value == null)
    1198        return new JPanel();
    1199
    1200      if (!(table.getModel().getValueAt(row,9) instanceof DiffSetElement))
    1201        return defaultComp;
    1202
    1203      DiffSetElement diffSetElement =
    1204                        (DiffSetElement) table.getModel().getValueAt(row,9);
    1205
    1206      if (diffSetElement == null)
    1207        return defaultComp;
    1208
    1209      if (column < 4){
    1210        if (NULL_TYPE != diffSetElement.getLeftType())
    1211          background = colors[diffSetElement.getLeftType()];
    1212        else return new JPanel();
    1213      }else{
    1214        if (NULL_TYPE != diffSetElement.getRightType())
    1215          background = colors[diffSetElement.getRightType()];
    1216        else return new JPanel();
    1217      }
    1218
    1219      defaultComp.setBackground(background);
    1220      defaultComp.setForeground(BLACK);
    1221
    1222      defaultComp.setOpaque(true);
    1223      return defaultComp;
    1224    } //getTableCellRendererComponent
    1225
    1226  } // class AnnotationDiffCellRenderer
    1227
    1228  /* ********************************************************************
    1229   * INNER CLASS
    1230   * ********************************************************************/
    1231   class AnnotationSetComparator implements java.util.Comparator {
    1232
    1233      public AnnotationSetComparator(){}
    1234
    1235      public int compare(Object o1, Object o2) {
    1236        if ( !(o1 instanceof gate.Annotation) ||
    1237             !(o2 instanceof gate.Annotation)) return 0;
    1238
    1239        gate.Annotation a1 = (gate.Annotation) o1;
    1240        gate.Annotation a2 = (gate.Annotation) o2;
    1241
    1242        Long l1 = a1.getStartNode().getOffset();
    1243        Long l2 = a2.getStartNode().getOffset();
    1244        if (l1 != null)
    1245          return l1.compareTo(l2);
    1246        else
    1247          return -1;
    1248      } //compare
    1249    } // class AnnotationSetComparator
    1250
    1251  /* ********************************************************************
    1252   * INNER CLASS
    1253   * ********************************************************************/
    1254
    1255  /**
    1256    * This class is used for internal purposes. It represents a row from the
    1257    * table.
    1258    */
    1259  protected class DiffSetElement {
    1260    /** This field represent a key annotation*/
    1261    private Annotation leftAnnotation = null;
    1262    /** This field represent a response annotation*/
    1263    private Annotation rightAnnotation = null;
    1264    /** Default initialization of the key type*/
    1265    private int leftType = DEFAULT_TYPE;
    1266    /** Default initialization of the response type*/
    1267    private int rightType = DEFAULT_TYPE;
    1268
    1269    /** Constructor for DiffSetlement*/
    1270    public DiffSetElement() {}
    1271
    1272    /** Constructor for DiffSetlement*/
    1273    public DiffSetElement( Annotation aLeftAnnotation,
    1274                           Annotation aRightAnnotation,
    1275                           int aLeftType,
    1276                           int aRightType){
    1277      leftAnnotation = aLeftAnnotation;
    1278      rightAnnotation = aRightAnnotation;
    1279      leftType = aLeftType;
    1280      rightType = aRightType;
    1281    } // DiffSetElement
    1282
    1283    /** Sets the left annotation*/
    1284    public void setLeftAnnotation(Annotation aLeftAnnotation){
    1285      leftAnnotation = aLeftAnnotation;
    1286    } // setLeftAnnot
    1287
    1288    /** Gets the left annotation*/
    1289    public Annotation getLeftAnnotation(){
    1290      return leftAnnotation;
    1291    } // getLeftAnnotation
    1292
    1293    /** Sets the right annotation*/
    1294    public void setRightAnnotation(Annotation aRightAnnotation){
    1295      rightAnnotation = aRightAnnotation;
    1296    } // setRightAnnot
    1297
    1298    /** Gets the right annotation*/
    1299    public Annotation getRightAnnotation(){
    1300      return rightAnnotation;
    1301    } // getRightAnnotation
    1302
    1303    /** Sets the left type*/
    1304    public void setLeftType(int aLeftType){
    1305      leftType = aLeftType;
    1306    } // setLeftType
    1307
    1308    /** Get the left type */
    1309    public int getLeftType() {
    1310      return leftType;
    1311    } // getLeftType
    1312
    1313    /** Sets the right type*/
    1314    public void setRightType(int aRightType) {
    1315      rightType = aRightType;
    1316    } // setRightType
    1317
    1318    /** Get the right type*/
    1319    public int getRightType() {
    1320      return rightType;
    1321    } // getRightType
    1322  } // classs DiffSetElement
    1323} // class AnnotationDiff
    1324

| AnnotationDiff |