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