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