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