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 == null) return 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 || 0 == keyCorpus.size())
0529 throw new ResourceInstantiationException("No key corpus or empty defined !");
0530
0531 if(responseCorpus == null || 0 == 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[type] = 0;
0537 diffSet = new HashSet();
0538
0539 for(int i=0; i<keyCorpus.size(); ++i) {
0540 keyDocument = (Document) keyCorpus.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 = (Document) responseCorpus.get(j);
0547 if(0 == doc.getName().compareTo(keyDocument.getName())
0548 || 0 == 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 (textMode) return 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 = (DiffSetElement) iterator.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.prln( leftAnnot + "|" + 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 = (Annotation) keyIterator.next();
0867 Iterator responseIterator = aResponseAnnotList.iterator();
0868
0869 DiffSetElement diffElement = null;
0870 while(responseIterator.hasNext()){
0871 Annotation responseAnnot = (Annotation) responseIterator.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 DiffSetElement( keyAnnot,
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 DiffSetElement( keyAnnot,
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 DiffSetElement( keyAnnot,
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 = (DiffSetElement) respParIter.next();
0927 Annotation respAnnot = diffElem.getRightAnnotation();
0928 if (respAnnot != null && keyAnnot.isPartiallyCompatible(respAnnot,
0929 keyFeatureNamesSet)){
0930 diffElement = new DiffSetElement( keyAnnot,
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 DiffSetElement( keyAnnot,
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 = (Annotation) responseIter.next();
0958 if (responsePartiallySet.contains(respAnnot))
0959 diffElem = new DiffSetElement( null,
0960 respAnnot,
0961 NULL_TYPE,
0962 PARTIALLY_CORRECT_TYPE,
0963 keyDocument,
0964 responseDocument);
0965 else
0966 diffElem = new DiffSetElement( null,
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 ((double) 2);
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 ? 0 : aSet.size();
1015 }else{
1016 AnnotationSet aSet = responseDocument.getAnnotations(responseAnnotationSetNameFalsePoz).get(
1017 annotationTypeForFalsePositive);
1018 no = aSet == null? 0 : 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]) /((double) no);
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 == null) return NULL_TYPE;
1051
1052 if (keyPartiallySet.contains(anAnnot)) return DEFAULT_TYPE;
1053 Iterator iter = responsePartiallySet.iterator();
1054 while(iter.hasNext()){
1055 Annotation a = (Annotation) iter.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 = (Annotation) iter.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 == null) return NULL_TYPE;
1080
1081 if (responsePartiallySet.contains(anAnnot)) return PARTIALLY_CORRECT_TYPE;
1082 Iterator iter = keyPartiallySet.iterator();
1083 while(iter.hasNext()){
1084 Annotation a = (Annotation) iter.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 = (Annotation) iter.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 == null) return;
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 0: return "String - Key";
1154 case 1: return "Start - Key";
1155 case 2: return "End - Key";
1156 case 3: return "Features - Key";
1157 case 4: return " ";
1158 case 5: return "String - Response";
1159 case 6: return "Start - Response";
1160 case 7: return "End -Response";
1161 case 8: return "Features - Response";
1162 case 9: return "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 0: return String.class;
1171 case 1: return Long.class;
1172 case 2: return Long.class;
1173 case 3: return String.class;
1174 case 4: return String.class;
1175 case 5: return String.class;
1176 case 6: return Long.class;
1177 case 7: return Long.class;
1178 case 8: return String.class;
1179 case 9: return 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 = (DiffSetElement) modelData.get(row);
1187 if (diffSetElement == null) return null;
1188 switch(column){
1189 // Left Side (Key)
1190 //Type - Key
1191 case 0:{
1192 if (diffSetElement.getLeftAnnotation() == null) return 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() == null) return null;
1208 return diffSetElement.getLeftAnnotation().getStartNode().getOffset();
1209 }
1210 // End - Key
1211 case 2:{
1212 if (diffSetElement.getLeftAnnotation() == null) return null;
1213 return diffSetElement.getLeftAnnotation().getEndNode().getOffset();
1214 }
1215 // Features - Key
1216 case 3:{
1217 if (diffSetElement.getLeftAnnotation() == null) return 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() == null) return 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() == null) return null;
1245 return diffSetElement.getRightAnnotation().getStartNode().getOffset();
1246 }
1247 // End - Response
1248 case 7:{
1249 if (diffSetElement.getRightAnnotation() == null) return null;
1250 return diffSetElement.getRightAnnotation().getEndNode().getOffset();
1251 }
1252 // Features - resonse
1253 case 8:{
1254 if (diffSetElement.getRightAnnotation() == null) return 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 = (JComponent) super.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 == 4 || value == null)
1306 return new JPanel();
1307
1308 if (!(table.getModel().getValueAt(row,10) instanceof DiffSetElement))
1309 return defaultComp;
1310
1311 DiffSetElement diffSetElement =
1312 (DiffSetElement) table.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.Annotation) o1;
1348 gate.Annotation a2 = (gate.Annotation) o2;
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 DiffSetElement( Annotation 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 DiffSetElement( Annotation 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
|