STreeNode.java
001 /*
002  *  STreeNode.java
003  *
004  *  Copyright (c) 1995-2010, The University of Sheffield. See the file
005  *  COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
006  *
007  *  This file is part of GATE (see http://gate.ac.uk/), and is free
008  *  software, licenced under the GNU Library General Public License,
009  *  Version 2, June 1991 (in the distribution as file licence.html,
010  *  and also available at http://gate.ac.uk/gate/licence.html).
011  *
012  *  Kalina Bontcheva, 07/08/2001
013  *
014  *  $Id: STreeNode.java 12006 2009-12-01 17:24:28Z thomas_heitz $
015  */
016 
017 package gate.gui;
018 
019 import java.util.*;
020 
021 import javax.swing.tree.DefaultMutableTreeNode;
022 
023 import gate.*;
024 import gate.util.InvalidOffsetException;
025 import gate.util.Out;
026 
027 
028 public class STreeNode extends DefaultMutableTreeNode {
029 
030   /** Debug flag */
031   private static final boolean DEBUG = false;
032   private static final String ADDEDSET = "TreeViewerTempAdded";
033   private static final String REMOVEDSET = "TreeViewerTempRemoved";
034 
035   static int nextID = 0;
036 
037   int level;            // level in the syntax tree
038   int nodeID;           //ID of the node
039 
040   long start, end;       //the start and end nodes for this annotation
041   Annotation annot;     //the annotation that's created during import/export
042                         //not to be used otherwise. During import span is set to
043                         //be the same as the annotation span. During export the
044                         //annotation span is set to be the same as the span.
045 
046   public STreeNode(Annotation annot) {
047     level = -1;
048     nodeID = nextID++;
049     //span = annot.getSpans().getElementAt(0);
050     //get the first span, there should be no others
051     this.annot = annot;
052     this.start = annot.getStartNode().getOffset().longValue();
053     this.end = annot.getEndNode().getOffset().longValue();
054   }// public STreeNode(Annotation annot)
055 
056   public STreeNode(long start, long end) {
057     level = -1;
058     nodeID = nextID++;
059     this.start = start;
060     this.end = end;
061   }// public STreeNode(int start, int end)
062 
063   public STreeNode() {
064     level = -1;
065     nodeID = nextID++;
066     start = 0;
067     end = 0;
068   }// public STreeNode()
069 
070   public int getLevel() {
071     return level;
072   }// public int getLevel()
073 
074   public void setLevel(long level) {
075     this.level = (intlevel;
076   }// public void setLevel(int level)
077 
078   public void setLevel(int level) {
079     this.level = level;
080   }// public void setLevel(int level)
081 
082   public int getID() {
083     return nodeID;
084   }// public int getID()
085 
086   public long getStart() {
087     return start;
088   }// public int getStart()
089 
090   public void setStart(long start) {
091     this.start = start;
092   }// public void setStart(int start)
093 
094   public long getEnd() {
095     return end;
096   }// public int getEnd()
097 
098   public void setEnd(long end) {
099     this.end = end;
100   }// public void setEnd(int end)
101 
102   /**
103     * This also sets the span to match the annotation span!
104     */
105   public void setAnnotation(Annotation annot) {
106     this.annot = annot;
107     this.start = annot.getStartNode().getOffset().longValue();
108     this.end = annot.getEndNode().getOffset().longValue();
109   }// public void setAnnotation(Annotation annot)
110 
111   public Annotation getAnnotation() {
112     return annot;
113   }// public Annotation getAnnotation()
114 
115   public void disconnectChildren() {
116     for (Iterator i = this.children.iterator(); i.hasNext())
117       ((STreeNodei.next()).setParent(null);
118     this.children.clear();
119   }// public void disconnectChildren()
120 
121   /**
122     * Creates an annotation of the given type. If the children don't have their
123     * annotation objects created, it creates them and assigns the pointers.
124     * Expects the text string relative to which all offsets were created!
125     */
126   public boolean createAnnotation(Document doc, String type,
127                                     String text, long utteranceOffset) {
128     boolean created = false;
129 
130     if (annot != null )
131       return false;
132 
133     //no document, so cannot add annotations
134     if (doc == null)
135       return false;
136 
137     // check if it has children. If it hasn't then it shouldn't have an
138     // annotation because all our leaf nodes are actually just words
139     // from the text (e.g. "this", "that"). Their categories are always
140     // encoded as non-terminal nodes.
141     if this.getAllowsChildren())
142       return false;
143 
144     FeatureMap attribs = Factory.newFeatureMap();
145     // the text spanned by the annotation is stored as the userObject of the
146     // tree node
147     // comes from the default Swing tree node
148     List consists = new ArrayList();
149 
150     Long lStart = new Long(start), lEnd = new Long(end);
151 //    try {
152 //      attribs.put("text",
153 //                  doc.getContent().getContent(lStart, lEnd).toString());
154 //    } catch (InvalidOffsetException ex) {
155 //      throw new RuntimeException(ex.getMessage());
156 //    }
157     attribs.put("text",
158                   text.substring( (int) (start - utteranceOffset),
159                                  (int) (end - utteranceOffset) )
160     );
161     attribs.put("cat"(Stringthis.getUserObject());
162     attribs.put("consists", consists);
163 
164     // children comes from DefaultMutableTreeNode
165     for (Iterator i = children.iterator(); i.hasNext()) {
166       STreeNode child = (STreeNodei.next();
167       if (child.getAnnotation() == null) {
168         if (child.getAllowsChildren())
169           if (createAnnotation(doc, type, text, utteranceOffset))
170             consists.add(child.getAnnotation().getId());
171       else
172         consists.add(child.getAnnotation().getId());
173     }
174 
175     //!!! Need to account for the name of the Annot Set
176     AnnotationSet theSet = doc.getAnnotations(ADDEDSET);
177     try {
178       Integer Id = theSet.add(lStart, lEnd, type, attribs);
179       this.annot = theSet.get(Id);
180       created = true;
181     catch (InvalidOffsetException ex) {
182       Out.println("Invalid annotation offsets: "
183                             + start + " and/or " + end);
184       created = false;
185     }
186 
187     return created;
188   }// public boolean createAnnotation
189 
190 
191   /**
192     * Transfers the annotations from added to the given annotation set
193     * Also, for each annotation in removed, removes it from the given annotation set
194     * Called by OkAction() in the treeViewer to finalise the changes.
195     */
196   public static boolean transferAnnotations(Document doc, AnnotationSet targetAS) {
197     if (doc == null || targetAS == null)
198       return false;
199 
200     HashMap tempId2permId = new HashMap();
201     List newAnnots = new ArrayList();
202     AnnotationSet addedSet = doc.getAnnotations(ADDEDSET);
203     if (addedSet != null && !addedSet.isEmpty()) {
204       Iterator addedIter = addedSet.iterator();
205       while (addedIter.hasNext()) {
206         Annotation annot = (AnnotationaddedIter.next();
207         try {
208           Integer permId =
209               targetAS.add(annot.getStartNode().getOffset(),
210                        annot.getEndNode().getOffset(),
211                        annot.getType(),
212                        annot.getFeatures());
213           tempId2permId.put(annot.getId(), permId);
214           newAnnots.add(targetAS.get(permId));
215         catch (InvalidOffsetException ex) {
216           Out.println("Invalid annotation offsets: "
217                         + annot.getStartNode().getOffset()
218                         " and/or " + annot.getEndNode().getOffset());
219         }
220       }//while
221 
222       //now update the consists Ids, because they have the old Ids in them
223       for (int i=0; i < newAnnots.size(); i++) {
224         Annotation newAnnot = (AnnotationnewAnnots.get(i);
225         List children = (ListnewAnnot.getFeatures().get(
226             SyntaxTreeViewer.NODE_CONSISTS_FEATURE_NAME);
227         if (children == null || children.size()== 0) {
228           continue;
229         }
230         else {
231           List newList = new ArrayList();
232           for (int k=0; k< children.size(); k++) {
233             Integer oldId = (Integerchildren.get(k);
234             if (tempId2permId.get(oldId!= null)
235               newList.add(tempId2permId.get(oldId));
236             else
237               newList.add(oldId);
238           }
239           newAnnot.getFeatures().put(SyntaxTreeViewer.NODE_CONSISTS_FEATURE_NAME,
240                                      newList);
241         }
242       }//for
243 
244       addedSet.clear();
245 
246     }
247     doc.removeAnnotationSet(ADDEDSET);
248 
249 
250     AnnotationSet removedSet = doc.getAnnotations(REMOVEDSET);
251     if (removedSet != null &&  ! removedSet.isEmpty()) {
252       targetAS.removeAll(removedSet);
253       removedSet.clear();
254     }
255     doc.removeAnnotationSet(REMOVEDSET);
256 
257     return true;
258   }
259 
260   public static void undo(Document doc) {
261     AnnotationSet addedSet = doc.getAnnotations(ADDEDSET);
262     AnnotationSet removedSet = doc.getAnnotations(REMOVEDSET);
263     addedSet.clear();
264     removedSet.clear();
265     doc.removeAnnotationSet(ADDEDSET);
266     doc.removeAnnotationSet(REMOVEDSET);
267   }
268 
269   /** Store the annotation in the deleted list so it can retrieved later */
270   public void removeAnnotation(Document doc) {
271     if (this.annot == null || doc == null)
272       return;
273 
274     doc.getAnnotations(REMOVEDSET).add(this.annot);
275 
276     this.annot = null;
277   }//  public void removeAnnotation(Document doc)
278 
279 // STreeNode
280 
281 // $Log$
282 // Revision 1.14  2005/01/11 13:51:34  ian
283 // Updating copyrights to 1998-2005 in preparation for v3.0
284 //
285 // Revision 1.13  2004/07/21 17:10:07  akshay
286 // Changed copyright from 1998-2001 to 1998-2005
287 //
288 // Revision 1.12  2004/03/25 13:01:03  valyt
289 // Imports optimisation throughout the Java sources
290 // (to get rid of annoying warnings in Eclipse)
291 //
292 // Revision 1.11  2003/01/28 10:01:16  marin
293 // [marin] bugfixes from Kali
294 //
295 // Revision 1.10  2001/12/03 14:04:04  kalina
296 // code cleanup in STreeNode.java
297 //
298 // Revision 1.9  2001/08/07 19:03:05  kalina
299 // Made the tree viewer use Token annotations to break the sentence for annotation
300 //
301 // Revision 1.8  2001/08/07 17:01:32  kalina
302 // Changed the AVR implementing classes in line with the updated AVR
303 // API (cancelAction() and setSpan new parameter).
304 //
305 // Also updated the TreeViewer, so now it can be used to edit and view
306 // Sentence annotations and the SyntaxTreeNodes associated with them.
307 // So if you have trees, it'll show them, if not, it'll help you build them.
308 //
309 // Revision 1.7  2001/04/09 10:36:36  oana
310 // a few changes in the code style
311 //
312 // Revision 1.6  2000/11/08 16:35:00  hamish
313 // formatting
314 //
315 // Revision 1.5  2000/10/26 10:45:25  oana
316 // Modified in the code style
317 //
318 // Revision 1.4  2000/10/18 13:26:47  hamish
319 // Factory.createResource now working, with a utility method that uses
320 // reflection (via java.beans.Introspector) to set properties on a resource
321 // from the
322 //     parameter list fed to createResource.
323 //     resources may now have both an interface and a class; they are indexed
324 //        by interface type; the class is used to instantiate them
325 //     moved createResource from CR to Factory
326 //     removed Transients; use Factory instead
327 //
328 // Revision 1.3  2000/10/16 16:44:32  oana
329 // Changed the comment of DEBUG variable
330 //
331 // Revision 1.2  2000/10/10 15:36:34  oana
332 // Changed System.out in Out and System.err in Err;
333 // Added the DEBUG variable seted on false;
334 // Added in the header the licence;
335 //
336 // Revision 1.1  2000/09/20 17:03:37  kalina
337 // Added the tree viewer from the prototype. It works now with the new
338 // annotation API.
339 //
340 // Revision 1.6  1999/08/23 14:13:38  kalina
341 // Fixed resizing bugs in tree viewers
342 //
343 // Revision 1.5  1999/08/20 21:11:56  kalina
344 // Fixed most bugs and TreeViewer can now import and export annotations
345 // correctly
346 // There is still a delete bug somewhere.
347 //
348 // Revision 1.4  1999/08/18 17:55:24  kalina
349 // Added annotation export for the TreeViewer. Annotation import is the only
350 // thing that remains.
351 //
352 // Revision 1.3  1999/08/13 17:56:31  kalina
353 // Fixed the annotation of nodes in the TreeViewer to be done with click
354 //
355 // Revision 1.2  1999/08/12 16:10:12  kalina
356 // Added a new tree stereotype. Not in final version but would do for testing.
357 //
358 // Improved the tree viewer to allow dynamic creation of all nodes.
359 // Now I can build many trees or one tree; can delete non-terminal nodes;
360 // select/unselect nodes for annotation
361 // Overlapping trees are not a big problem too :-) Not wonderfully drawn but
362 // would do.
363 //
364 // Revision 1.1  1999/08/09 18:00:53  kalina
365 // Made the tree viewer to display an utterance/sentence annotation to start annotating them
366 //