STreeNode.java |
1 /* 2 * STreeNode.java 3 * 4 * Copyright (c) 1998-2005, 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 * Kalina Bontcheva, 07/08/2001 12 * 13 * $Id: STreeNode.java,v 1.14 2005/01/11 13:51:34 ian Exp $ 14 */ 15 16 package gate.gui; 17 18 import java.util.*; 19 20 import javax.swing.tree.DefaultMutableTreeNode; 21 22 import gate.*; 23 import gate.util.InvalidOffsetException; 24 import gate.util.Out; 25 26 27 public class STreeNode extends DefaultMutableTreeNode { 28 29 /** Debug flag */ 30 private static final boolean DEBUG = false; 31 private static final String ADDEDSET = "TreeViewerTempAdded"; 32 private static final String REMOVEDSET = "TreeViewerTempRemoved"; 33 34 static int nextID = 0; 35 36 int level; // level in the syntax tree 37 int nodeID; //ID of the node 38 39 long start, end; //the start and end nodes for this annotation 40 Annotation annot; //the annotation that's created during import/export 41 //not to be used otherwise. During import span is set to 42 //be the same as the annotation span. During export the 43 //annotation span is set to be the same as the span. 44 45 public STreeNode(Annotation annot) { 46 level = -1; 47 nodeID = nextID++; 48 //span = annot.getSpans().getElementAt(0); 49 //get the first span, there should be no others 50 this.annot = annot; 51 this.start = annot.getStartNode().getOffset().longValue(); 52 this.end = annot.getEndNode().getOffset().longValue(); 53 }// public STreeNode(Annotation annot) 54 55 public STreeNode(long start, long end) { 56 level = -1; 57 nodeID = nextID++; 58 this.start = start; 59 this.end = end; 60 }// public STreeNode(int start, int end) 61 62 public STreeNode() { 63 level = -1; 64 nodeID = nextID++; 65 start = 0; 66 end = 0; 67 }// public STreeNode() 68 69 public int getLevel() { 70 return level; 71 }// public int getLevel() 72 73 public void setLevel(long level) { 74 this.level = (int) level; 75 }// public void setLevel(int level) 76 77 public void setLevel(int level) { 78 this.level = level; 79 }// public void setLevel(int level) 80 81 public int getID() { 82 return nodeID; 83 }// public int getID() 84 85 public long getStart() { 86 return start; 87 }// public int getStart() 88 89 public void setStart(long start) { 90 this.start = start; 91 }// public void setStart(int start) 92 93 public long getEnd() { 94 return end; 95 }// public int getEnd() 96 97 public void setEnd(long end) { 98 this.end = end; 99 }// public void setEnd(int end) 100 101 /** 102 * This also sets the span to match the annotation span! 103 */ 104 public void setAnnotation(Annotation annot) { 105 this.annot = annot; 106 this.start = annot.getStartNode().getOffset().longValue(); 107 this.end = annot.getEndNode().getOffset().longValue(); 108 }// public void setAnnotation(Annotation annot) 109 110 public Annotation getAnnotation() { 111 return annot; 112 }// public Annotation getAnnotation() 113 114 public void disconnectChildren() { 115 for (Iterator i = this.children.iterator(); i.hasNext(); ) 116 ((STreeNode) i.next()).setParent(null); 117 this.children.clear(); 118 }// public void disconnectChildren() 119 120 /** 121 * Creates an annotation of the given type. If the children don't have their 122 * annotation objects created, it creates them and assigns the pointers. 123 * Expects the text string relative to which all offsets were created! 124 */ 125 public boolean createAnnotation(Document doc, String type, 126 String text, long utteranceOffset) { 127 boolean created = false; 128 129 if (annot != null ) 130 return false; 131 132 //no document, so cannot add annotations 133 if (doc == null) 134 return false; 135 136 // check if it has children. If it hasn't then it shouldn't have an 137 // annotation because all our leaf nodes are actually just words 138 // from the text (e.g. "this", "that"). Their categories are always 139 // encoded as non-terminal nodes. 140 if ( ! this.getAllowsChildren()) 141 return false; 142 143 FeatureMap attribs = Factory.newFeatureMap(); 144 // the text spanned by the annotation is stored as the userObject of the 145 // tree node 146 // comes from the default Swing tree node 147 List consists = new ArrayList(); 148 149 Long lStart = new Long(start), lEnd = new Long(end); 150 // try { 151 // attribs.put("text", 152 // doc.getContent().getContent(lStart, lEnd).toString()); 153 // } catch (InvalidOffsetException ex) { 154 // throw new RuntimeException(ex.getMessage()); 155 // } 156 attribs.put("text", 157 text.substring( (int) (start - utteranceOffset), 158 (int) (end - utteranceOffset) ) 159 ); 160 attribs.put("cat", (String) this.getUserObject()); 161 attribs.put("consists", consists); 162 163 // children comes from DefaultMutableTreeNode 164 for (Iterator i = children.iterator(); i.hasNext(); ) { 165 STreeNode child = (STreeNode) i.next(); 166 if (child.getAnnotation() == null) { 167 if (child.getAllowsChildren()) 168 if (createAnnotation(doc, type, text, utteranceOffset)) 169 consists.add(child.getAnnotation().getId()); 170 } else 171 consists.add(child.getAnnotation().getId()); 172 } 173 174 //!!! Need to account for the name of the Annot Set 175 AnnotationSet theSet = doc.getAnnotations(ADDEDSET); 176 try { 177 Integer Id = theSet.add(lStart, lEnd, type, attribs); 178 this.annot = theSet.get(Id); 179 created = true; 180 } catch (InvalidOffsetException ex) { 181 Out.println("Invalid annotation offsets: " 182 + start + " and/or " + end); 183 created = false; 184 } 185 186 return created; 187 }// public boolean createAnnotation 188 189 190 /** 191 * Transfers the annotations from added to the given annotation set 192 * Also, for each annotation in removed, removes it from the given annotation set 193 * Called by OkAction() in the treeViewer to finalise the changes. 194 */ 195 public static boolean transferAnnotations(Document doc, AnnotationSet targetAS) { 196 if (doc == null || targetAS == null) 197 return false; 198 199 HashMap tempId2permId = new HashMap(); 200 List newAnnots = new ArrayList(); 201 AnnotationSet addedSet = doc.getAnnotations(ADDEDSET); 202 if (addedSet != null && !addedSet.isEmpty()) { 203 Iterator addedIter = addedSet.iterator(); 204 while (addedIter.hasNext()) { 205 Annotation annot = (Annotation) addedIter.next(); 206 try { 207 Integer permId = 208 targetAS.add(annot.getStartNode().getOffset(), 209 annot.getEndNode().getOffset(), 210 annot.getType(), 211 annot.getFeatures()); 212 tempId2permId.put(annot.getId(), permId); 213 newAnnots.add(targetAS.get(permId)); 214 } catch (InvalidOffsetException ex) { 215 Out.println("Invalid annotation offsets: " 216 + annot.getStartNode().getOffset() 217 + " and/or " + annot.getEndNode().getOffset()); 218 } 219 }//while 220 221 //now update the consists Ids, because they have the old Ids in them 222 for (int i=0; i < newAnnots.size(); i++) { 223 Annotation newAnnot = (Annotation) newAnnots.get(i); 224 List children = (List) newAnnot.getFeatures().get( 225 SyntaxTreeViewer.NODE_CONSISTS_FEATURE_NAME); 226 if (children == null || children.size()== 0) { 227 continue; 228 } 229 else { 230 List newList = new ArrayList(); 231 for (int k=0; k< children.size(); k++) { 232 Integer oldId = (Integer) children.get(k); 233 if (tempId2permId.get(oldId) != null) 234 newList.add(tempId2permId.get(oldId)); 235 else 236 newList.add(oldId); 237 } 238 newAnnot.getFeatures().put(SyntaxTreeViewer.NODE_CONSISTS_FEATURE_NAME, 239 newList); 240 } 241 }//for 242 243 addedSet.clear(); 244 245 } 246 doc.removeAnnotationSet(ADDEDSET); 247 248 249 AnnotationSet removedSet = doc.getAnnotations(REMOVEDSET); 250 if (removedSet != null && ! removedSet.isEmpty()) { 251 targetAS.removeAll(removedSet); 252 removedSet.clear(); 253 } 254 doc.removeAnnotationSet(REMOVEDSET); 255 256 return true; 257 } 258 259 public static void undo(Document doc) { 260 AnnotationSet addedSet = doc.getAnnotations(ADDEDSET); 261 AnnotationSet removedSet = doc.getAnnotations(REMOVEDSET); 262 addedSet.clear(); 263 removedSet.clear(); 264 doc.removeAnnotationSet(ADDEDSET); 265 doc.removeAnnotationSet(REMOVEDSET); 266 } 267 268 /** Store the annotation in the deleted list so it can retrieved later */ 269 public void removeAnnotation(Document doc) { 270 if (this.annot == null || doc == null) 271 return; 272 273 doc.getAnnotations(REMOVEDSET).add(this.annot); 274 275 this.annot = null; 276 }// public void removeAnnotation(Document doc) 277 278 } // STreeNode 279 280 // $Log: STreeNode.java,v $ 281 // Revision 1.14 2005/01/11 13:51:34 ian 282 // Updating copyrights to 1998-2005 in preparation for v3.0 283 // 284 // Revision 1.13 2004/07/21 17:10:07 akshay 285 // Changed copyright from 1998-2001 to 1998-2005 286 // 287 // Revision 1.12 2004/03/25 13:01:03 valyt 288 // Imports optimisation throughout the Java sources 289 // (to get rid of annoying warnings in Eclipse) 290 // 291 // Revision 1.11 2003/01/28 10:01:16 marin 292 // [marin] bugfixes from Kali 293 // 294 // Revision 1.10 2001/12/03 14:04:04 kalina 295 // code cleanup in STreeNode.java 296 // 297 // Revision 1.9 2001/08/07 19:03:05 kalina 298 // Made the tree viewer use Token annotations to break the sentence for annotation 299 // 300 // Revision 1.8 2001/08/07 17:01:32 kalina 301 // Changed the AVR implementing classes in line with the updated AVR 302 // API (cancelAction() and setSpan new parameter). 303 // 304 // Also updated the TreeViewer, so now it can be used to edit and view 305 // Sentence annotations and the SyntaxTreeNodes associated with them. 306 // So if you have trees, it'll show them, if not, it'll help you build them. 307 // 308 // Revision 1.7 2001/04/09 10:36:36 oana 309 // a few changes in the code style 310 // 311 // Revision 1.6 2000/11/08 16:35:00 hamish 312 // formatting 313 // 314 // Revision 1.5 2000/10/26 10:45:25 oana 315 // Modified in the code style 316 // 317 // Revision 1.4 2000/10/18 13:26:47 hamish 318 // Factory.createResource now working, with a utility method that uses 319 // reflection (via java.beans.Introspector) to set properties on a resource 320 // from the 321 // parameter list fed to createResource. 322 // resources may now have both an interface and a class; they are indexed 323 // by interface type; the class is used to instantiate them 324 // moved createResource from CR to Factory 325 // removed Transients; use Factory instead 326 // 327 // Revision 1.3 2000/10/16 16:44:32 oana 328 // Changed the comment of DEBUG variable 329 // 330 // Revision 1.2 2000/10/10 15:36:34 oana 331 // Changed System.out in Out and System.err in Err; 332 // Added the DEBUG variable seted on false; 333 // Added in the header the licence; 334 // 335 // Revision 1.1 2000/09/20 17:03:37 kalina 336 // Added the tree viewer from the prototype. It works now with the new 337 // annotation API. 338 // 339 // Revision 1.6 1999/08/23 14:13:38 kalina 340 // Fixed resizing bugs in tree viewers 341 // 342 // Revision 1.5 1999/08/20 21:11:56 kalina 343 // Fixed most bugs and TreeViewer can now import and export annotations 344 // correctly 345 // There is still a delete bug somewhere. 346 // 347 // Revision 1.4 1999/08/18 17:55:24 kalina 348 // Added annotation export for the TreeViewer. Annotation import is the only 349 // thing that remains. 350 // 351 // Revision 1.3 1999/08/13 17:56:31 kalina 352 // Fixed the annotation of nodes in the TreeViewer to be done with click 353 // 354 // Revision 1.2 1999/08/12 16:10:12 kalina 355 // Added a new tree stereotype. Not in final version but would do for testing. 356 // 357 // Improved the tree viewer to allow dynamic creation of all nodes. 358 // Now I can build many trees or one tree; can delete non-terminal nodes; 359 // select/unselect nodes for annotation 360 // Overlapping trees are not a big problem too :-) Not wonderfully drawn but 361 // would do. 362 // 363 // Revision 1.1 1999/08/09 18:00:53 kalina 364 // Made the tree viewer to display an utterance/sentence annotation to start annotating them 365 // 366