| SyntaxTreeViewer.java |
1 /*
2 * SyntaxTreeViewer.java
3 *
4 * Copyright (c) 1998-2004, 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, 20/09/2000
12 *
13 * $Id: SyntaxTreeViewer.java,v 1.26 2004/07/26 14:59:32 valyt Exp $
14 */
15
16 package gate.gui;
17
18 //java imports
19 import java.awt.*;
20 import java.awt.event.*;
21 import java.beans.PropertyChangeEvent;
22 import java.util.*;
23
24 import javax.swing.*;
25
26 import gate.*;
27 import gate.creole.*;
28 import gate.util.*;
29
30
31 /**
32 * The SyntaxTreeViewer is capable of showing and editing utterances (fancy
33 * name for sentences) and the
34 * attached syntax trees. It works by taking an utterance and all Token
35 * annotations and constructs the text. Then it also gets all SyntaxTreeNode
36 * annotations and builds and shows the syntac tree for that utterance. The
37 * leaves of the tree are the tokens, which constitute the utterance.<P>
38 *
39 * It is possible to configure the annotation types that are used by the
40 * viewer. The textAnnotationType property specifies the type
41 * of annotation which is used to denote the utterance (sentence).
42 * In GATE, the value of this property is not set directly, but is derived
43 * from the VR configuration information from creole.xml (explained below).
44 *
45 * The treeNodeAnnotationType is the name of the
46 * annotations which encode the SyntaxTreeNodes; default - SyntaxTreeNode.
47 * To change when part of GATE, modify the <PARAMETER> setting of the
48 * TreeViewer entry in creole.xml. Similarly, one can change which annotation
49 * is used for chunking the utterance. By default, it is Token, which is also
50 * specified in creole.xml as a parameter in the treeviewer entry.
51 *
52 * The component assumes that the annotations of type treeNodeAnnotationType have
53 * features called: cat with a value String; consists which is a List either
54 * empty or with annotation ids of the node's children; and optionally
55 * text which contains
56 * the text covered by this annotation. The component will work fine even
57 * without the last feature. Still when it creates annotations,
58 * these will have this feature added. <P>
59 *
60 *
61 * Newly added tree nodes to the tree are added to the document
62 * as annotations and deleted nodes are automatically deleted from the document
63 * only after OK is chosen in the dialog. Cancel does not make any changes
64 * permanent. <P>
65 *
66 * Configuring the viewer in GATE<P>
67 * The viewer is configured in creole.xml. The default entry is:
68 * <PRE>
69 * <RESOURCE>
70 * <NAME>Syntax tree viewer</NAME>
71 * <CLASS>gate.gui.SyntaxTreeViewer</CLASS>
72 * <!-- type values can be "large" or "small"-->
73 * <GUI>
74 * <MAIN_VIEWER/>
75 * <ANNOTATION_TYPE_DISPLAYED>Sentence</ANNOTATION_TYPE_DISPLAYED>
76 * <PARAMETER NAME="treeNodeAnnotationType" DEFAULT="SyntaxTreeNode"
77 * RUNTIME="false" OPTIONAL="true">java.lang.String
78 * </PARAMETER>
79 * <PARAMETER NAME="tokenType" DEFAULT="Token" RUNTIME="false"
80 * OPTIONAL="true">java.lang.String
81 * </PARAMETER>
82 * </GUI>
83 * </RESOURCE>
84 * </PRE>
85 *
86 * The categories that appear in the menu for manual annotation are determined
87 * from SyntaxTreeViewerSchema.xml. If you want to change the default set,
88 * you must edit this file and update your Gate jar accordingly (e.g., by
89 * recompilation. This does not affect the categories of SyntaxTreeNode
90 * annotations, which have been created automatically by some other process,
91 * e.g., a parser PR.
92 *
93 * <P>
94 * If used outside GATE,
95 * in order to have appropriate behaviour always put this component inside a
96 * scroll pane or something similar that provides scrollers.
97 * Example code: <BREAK>
98 * <PRE>
99 * JScrollPane scroller = new JScrollPane(syntaxTreeViewer1);
100 * scroller.setPreferredSize(syntaxTreeViewer1.getPreferredSize());
101 * frame.getContentPane().add(scroller, BorderLayout.CENTER);
102 * </PRE>
103 *
104 *
105 * The default way is to pass just one annotation of type textAnnotationType
106 * which corresponds to the entire sentence or utterance to be annotated with
107 * syntax tree information. Then the viewer automatically tokenises it
108 * (by obtaining the relevant token annotations) and creates the leaves.<P>
109 *
110 * To create a new annotation, use setSpan, instead of setAnnotation.
111 *
112 * <P> In either
113 * case, you must call setTarget first, because that'll provide the viewer
114 * with the document's annotation set, from where it can obtain the token
115 * annotations.
116 * <P> If you intend to use the viewer outside GATE and do not understand
117 * the API, e-mail gate@dcs.shef.ac.uk.
118 */
119
120 public class SyntaxTreeViewer extends AbstractVisualResource
121 implements Scrollable, ActionListener, MouseListener,
122 AnnotationVisualResource {
123
124 /** The annotation type used to encode each tree node*/
125 public static final String TREE_NODE_ANNOTATION_TYPE = "SyntaxTreeNode";
126 /** The name of the feature that encodes the tree node's category information */
127 public static final String NODE_CAT_FEATURE_NAME = "cat";
128 /** The name of the feature that encodes the subtree annotations */
129 public static final String NODE_CONSISTS_FEATURE_NAME = "consists";
130
131 // class members
132 // whether to use any layout or not
133 protected boolean laidOut = false;
134
135 // display all buttons x pixels apart horizontally
136 protected int horizButtonGap = 5;
137
138 // display buttons at diff layers x pixels apart vertically
139 protected int vertButtonGap = 50;
140
141 // extra width in pixels to be added to each button
142 protected int extraButtonWidth = 10;
143
144 // number of pixels to be used as increment by scroller
145 protected int maxUnitIncrement = 10;
146
147 // GUI members
148 BorderLayout borderLayout1 = new BorderLayout();
149 JPopupMenu popup = new JPopupMenu(); //the right-click popup
150 Color buttonBackground;
151 Color selectedNodeColor = Color.red.darker();
152
153 // the HashSet with the coordinates of the lines to draw
154 HashSet lines = new HashSet();
155
156 // The utterance to be annotated as a sentence. It's not used if the tree
157 // is passed
158 // as annotations.
159 protected Annotation utterance;
160 protected Long utteranceStartOffset = new Long(0);
161 protected Long utteranceEndOffset = new Long(0);
162 protected AnnotationSet currentSet = null;
163
164 protected String tokenType = ANNIEConstants.TOKEN_ANNOTATION_TYPE;
165
166 // for internal use only. Set when the utterance is set.
167 protected String displayedString = "";
168
169 // The name of the annotation type which is used to locate the
170 // stereotype with the allowed categories
171 // also when reading and creating annotations
172 protected String treeNodeAnnotationType = TREE_NODE_ANNOTATION_TYPE;
173
174 // The annotation name of the annotations used to extract the
175 // text that appears at the leaves of the tree. For now the viewer
176 // supports only one such annotation but might be an idea to extend it
177 // so that it gets its text off many token annotations, which do not
178 // need to be tokenised or off the syntax tree annotations themselves.
179 protected String textAnnotationType = ANNIEConstants.SENTENCE_ANNOTATION_TYPE;
180
181 // all leaf nodes
182 protected HashMap leaves = new HashMap();
183
184 // all non-terminal nodes
185 protected HashMap nonTerminals = new HashMap();
186
187 // all buttons corresponding to any node
188 protected HashMap buttons = new HashMap();
189
190 // all selected buttons
191 protected Vector selection = new Vector();
192
193 // all annotations to be displayed
194 protected AnnotationSet treeAnnotations;
195
196 protected Document document = null;
197 // the document to which the annotations belong
198
199 //true when a new utterance annotation has been added
200 //then if the user presses cancel, I need to delete it
201 protected boolean utteranceAdded = false;
202
203
204 public SyntaxTreeViewer() {
205 try {
206 jbInit();
207 }
208 catch(Exception ex) {
209 ex.printStackTrace(Err.getPrintWriter());
210 }
211
212 }
213
214 //CONSTRUCTORS
215 private SyntaxTreeViewer(String annotType) {
216
217 treeNodeAnnotationType = annotType;
218 try {
219 jbInit();
220 }
221 catch(Exception ex) {
222 ex.printStackTrace(Err.getPrintWriter());
223 }
224 }
225
226 //METHODS
227 private void jbInit() throws Exception {
228
229 //check if we're using a layout; preferrably not
230 if (laidOut)
231 this.setLayout(borderLayout1);
232 else
233 this.setLayout(null);
234
235 this.setPreferredSize(new Dimension (600, 400));
236 this.setSize(600, 400);
237 this.setBounds(0, 0, 600, 400);
238 this.addComponentListener(new java.awt.event.ComponentAdapter() {
239 public void componentShown(ComponentEvent e) {
240 this_componentShown(e);
241 }
242 public void componentHidden(ComponentEvent e) {
243 this_componentHidden(e);
244 }
245 });
246 this.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
247
248 public void propertyChange(PropertyChangeEvent e) {
249 this_propertyChange(e);
250 }
251 });
252
253 buttonBackground = Color.red; //this.getBackground();
254
255 //get all categories from stereotype
256 fillCategoriesMenu();
257
258 //initialise the popup menu
259
260 //add popup to container
261 this.add(popup);
262 }// private void jbInit()
263
264 // Methods required by AnnotationVisualResource
265
266 /**
267 * Called by the GUI when this viewer/editor has to initialise itself for a
268 * specific annotation or text span.
269 * @param target the object which will always be a {@link gate.AnnotationSet}
270 */
271
272 public void setTarget(Object target) {
273 if (target == null) return;
274 currentSet = (AnnotationSet) target;
275 document = currentSet.getDocument();
276 }
277
278 /**
279 * Used when the viewer/editor has to display/edit an existing annotation
280 * @param ann the annotation to be displayed or edited. If ann is null then
281 * the method simply returns
282 */
283 public void setAnnotation(Annotation ann){
284 if (ann == null) return;
285
286 utterance = ann;
287 utteranceStartOffset = utterance.getStartNode().getOffset();
288 utteranceEndOffset = utterance.getEndNode().getOffset();
289 textAnnotationType = ann.getType();
290
291 clearAll();
292 utterances2Trees();
293 annotations2Trees();
294 this.setVisible(true);
295 repaint();
296 }
297
298 /**
299 * Used when the viewer has to create new annotations.
300 * @param startOffset the start offset of the span covered by the new
301 * annotation(s). If is <b>null</b> the method will simply return.
302 * @param endOffset the end offset of the span covered by the new
303 * annotation(s). If is <b>null</b> the method will simply return.
304 */
305 public void setSpan(Long startOffset, Long endOffset, String annotType){
306 // If one of them is null, then simply return.
307 if (startOffset == null || endOffset == null) return;
308 if (document == null) return;
309
310 try {
311 Integer newId = currentSet.add( startOffset, endOffset, annotType,
312 Factory.newFeatureMap());
313 utterance = currentSet.get(newId);
314 utteranceAdded = true;
315 textAnnotationType = annotType;
316 setAnnotation(utterance);
317
318 } catch (InvalidOffsetException ioe) {
319 ioe.printStackTrace(Err.getPrintWriter());
320 }
321
322 }
323
324 /**
325 * Called by the GUI when the user has pressed the "OK" button. This should
326 * trigger the saving of the newly created annotation(s)
327 */
328 public void okAction() throws GateException{
329 //Out.println("Visible coords" + this.getVisibleRect().toString());
330 //Out.println("Size" + this.getBounds().toString());
331 STreeNode.transferAnnotations(document, currentSet);
332
333 } //okAction()
334
335 /**
336 * Called by the GUI when the user has pressed the "Cancel" button. This should
337 * trigger the cleanup operation
338 */
339 public void cancelAction() throws GateException{
340 //if we added a new utterance but user does not want it any more...
341 if (utteranceAdded) {
342 currentSet.remove(utterance); //delete it
343 utteranceAdded = false;
344 }
345 //also cleanup the temporary annotation sets used by the viewer
346 //to cache the added and deleted tree annotations
347 STreeNode.undo(document);
348
349 } //okAction()
350
351
352 /**
353 * Checks whether this viewer/editor can handle a specific annotation type.
354 * @param annotationType represents the annotation type being questioned.If
355 * it is <b>null</b> then the method will return false.
356 * @return true if the SchemaAnnotationEditor can handle the annotationType
357 * or false otherwise.
358 */
359 public boolean canDisplayAnnotationType(String annotationType){
360 // Returns true only if the there is an AnnotationSchema with the same type
361 // as annotationType.
362 if (annotationType == null) return false;
363 boolean found = false;
364
365 java.util.List specificEditors = Gate.getCreoleRegister().
366 getAnnotationVRs(annotationType);
367 Iterator editorIter = specificEditors.iterator();
368 while(editorIter.hasNext() && !found){
369 String editorClass = (String)editorIter.next();
370
371 Out.println(editorClass);
372 if (editorClass.indexOf(this.getClass().getName()) > -1) {
373 textAnnotationType = annotationType;
374 found = true;
375 }
376 }
377
378 return found;
379 }// canDisplayAnnotationType();
380
381
382 /* public static void main(String[] args) throws Exception {
383 Gate.init();
384 // final String text = "This is a sentence. That is another one.";
385 final String text = "कल्इनكطب Калина Kalina";
386 final Document doc = Factory.newDocument(text);
387
388 // that works too but only use if you have the test file there.
389 // final Document doc = Factory.newDocument(
390 // new URL("file:///z:/temp/weird.txt"), "UTF-8");
391
392
393 final SyntaxTreeViewer syntaxTreeViewer1 =
394 new SyntaxTreeViewer("SyntaxTreeNode");
395 //syntaxTreeViewer1.setUnicodeSupportEnabled(true);
396 //need to set the document here!!!!
397
398
399 JFrame frame = new JFrame();
400
401 //INITIALISE THE FRAME, ETC.
402 frame.setEnabled(true);
403 frame.setTitle("SyntaxTree Viewer");
404 frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
405
406 // frame.getContentPane().add(syntaxTreeViewer1, BorderLayout.CENTER);
407 // intercept the closing event to shut the application
408 frame.addWindowListener(new WindowAdapter() {
409 public void windowClosing(WindowEvent e) {
410 AnnotationSet hs = doc.getAnnotations().get("SyntaxTreeNode");
411 if (hs != null && hs.size() > 0) {
412 int k = 0;
413 for (Iterator i = hs.iterator(); i.hasNext(); k++) {
414 Out.println("Tree Annot " + k + ": ");
415 Out.println(i.next().toString());
416 }
417 } //if
418 Out.println("Exiting...");
419 //System.exit(0);
420 }
421 });
422
423 //Put the bean in a scroll pane.
424 JScrollPane scroller = new JScrollPane(syntaxTreeViewer1);
425 scroller.setPreferredSize(syntaxTreeViewer1.getPreferredSize());
426 frame.getContentPane().add(scroller, BorderLayout.CENTER);
427
428 //DISPLAY FRAME
429 frame.pack();
430 frame.show();
431
432 FeatureMap attrs = Factory.newFeatureMap();
433 attrs.put("time", new Long(0));
434 attrs.put("text", doc.getContent().toString());
435 */
436 /*
437 FeatureMap attrs1 = Factory.newFeatureMap();
438 attrs1.put("cat", "N");
439 attrs1.put("text", "This");
440 attrs1.put("consists", new Vector());
441
442 FeatureMap attrs2 = Factory.newFeatureMap();
443 attrs2.put("cat", "V");
444 attrs2.put("text", "is");
445 attrs2.put("consists", new Vector());
446 */
447
448 /*
449 doc.getAnnotations().add( new Long(0), new Long(
450 doc.getContent().toString().length()),"utterance", attrs);
451 */
452 /* Integer id1 = doc.getAnnotations().add(new Long(0), new Long(4),
453 "SyntaxTreeNode", attrs1);
454 Integer id2 = doc.getAnnotations().add(new Long(5), new Long(7),
455 "SyntaxTreeNode", attrs2);
456
457 FeatureMap attrs3 = Factory.newFeatureMap();
458 attrs3.put("cat", "VP");
459 attrs3.put("text", "This is");
460 Vector consists = new Vector();
461 consists.add(id1);
462 consists.add(id2);
463 attrs3.put("consists", consists);
464 doc.getAnnotations().add(new Long(0), new Long(7),
465 "SyntaxTreeNode", attrs3);
466 */
467
468 /*
469 HashSet set = new HashSet();
470 set.add("utterance");
471 set.add("SyntaxTreeNode");
472 AnnotationSet annots = doc.getAnnotations().get(set);
473 syntaxTreeViewer1.setTreeAnnotations(annots);
474
475 }// public static void main
476 */
477
478 protected void paintComponent(Graphics g) {
479 super.paintComponent( g);
480 drawLines(g);
481 }// protected void paintComponent(Graphics g)
482
483
484 private void drawLines(Graphics g) {
485
486 for (Iterator i = lines.iterator(); i.hasNext(); ) {
487 Coordinates coords = (Coordinates) i.next();
488
489 g.drawLine( coords.getX1(),
490 coords.getY1(),
491 coords.getX2(),
492 coords.getY2());
493 }// for
494 }// private void drawLines(Graphics g)
495
496 public Dimension getPreferredScrollableViewportSize() {
497 return getPreferredSize();
498 }// public Dimension getPreferredScrollableViewportSize()
499
500 public int getScrollableUnitIncrement(Rectangle visibleRect,
501 int orientation, int direction) {
502 return maxUnitIncrement;
503 }// public int getScrollableUnitIncrement
504
505 public int getScrollableBlockIncrement(Rectangle visibleRect,
506 int orientation, int direction) {
507 if (orientation == SwingConstants.HORIZONTAL)
508 return visibleRect.width - maxUnitIncrement;
509 else
510 return visibleRect.height - maxUnitIncrement;
511 }// public int getScrollableBlockIncrement
512
513 public boolean getScrollableTracksViewportWidth() {
514 return false;
515 }// public boolean getScrollableTracksViewportWidth()
516
517 public boolean getScrollableTracksViewportHeight() {
518 return false;
519 }
520
521 void this_propertyChange(PropertyChangeEvent e) {
522
523 //we have a new utterance to display and annotate
524 if (e.getPropertyName().equals("utterance")) {
525 clearAll();
526 utterances2Trees();
527 }
528
529 } //this_propertyChange
530
531 /**
532 * Clear all buttons and tree nodes created because component is being
533 * re-initialised. Not sure it works perfectly.
534 */
535 private void clearAll() {
536 lines.clear();
537 this.removeAll();
538 buttons.clear();
539 leaves.clear();
540 nonTerminals.clear();
541 }
542
543 /**
544 * Converts the annotations into treeNodes
545 */
546 private void annotations2Trees() {
547 if (document == null) return;
548
549 HashMap processed = new HashMap(); //for all processed annotations
550
551 //first get all tree nodes in this set, then restrict them by offset
552 AnnotationSet tempSet = currentSet.get(treeNodeAnnotationType);
553 if (tempSet == null || tempSet.isEmpty())
554 return;
555 treeAnnotations = tempSet.get(utterance.getStartNode().getOffset(),
556 utterance.getEndNode().getOffset());
557 if (treeAnnotations == null || treeAnnotations.isEmpty())
558 return;
559
560 // sort them from left to right first
561 // Should work as
562 // annotation implements Comparable
563 java.util.List nodeAnnots = new ArrayList(treeAnnotations);
564 Collections.sort(nodeAnnots, new gate.util.OffsetComparator());
565
566 Vector childrenButtons = new Vector();
567 String oldParent = "";
568
569 //find all annotations with no children
570 Iterator i = nodeAnnots.iterator();
571 while (i.hasNext()) {
572 Annotation annot = (Annotation) i.next();
573
574 java.util.List children =
575 (java.util.List) annot.getFeatures().get(NODE_CONSISTS_FEATURE_NAME);
576 //check if it's a leaf
577 if (children == null ||
578 children.isEmpty())
579 {
580
581 STreeNode leaf = findLeaf(annot.getStartNode(), annot.getEndNode());
582 if (leaf == null) {//not found
583 Out.println("Can't find my leaf node for annotation: " + annot);
584 }
585
586 JButton button = (JButton) buttons.get(new Integer(leaf.getID()));
587 selection.clear();
588 selection.add(button);
589
590 //then create the non-terminal with the category
591 STreeNode node = new STreeNode(annot);
592 node.add(leaf);
593 node.setLevel(1);
594 node.setUserObject(annot.getFeatures().get(NODE_CAT_FEATURE_NAME));
595 nonTerminals.put(new Integer(node.getID()), node);
596 JButton parentButton = createCentralButton(node);
597 addLines(node);
598
599 //finally add to the processed annotations
600 processed.put(annot.getId(), parentButton);
601
602 } //if
603
604 } //loop through children
605
606 //loop through the rest of the nodes
607 Iterator i1 = nodeAnnots.iterator();
608 while (i1.hasNext()) {
609 Annotation annotNode = (Annotation) i1.next();
610 if (processed.containsKey(annotNode.getId()))
611 continue;
612 processChildrenAnnots(annotNode, processed);
613 } //process all higher nodes
614
615 selection.clear();
616
617 this.scrollRectToVisible(new
618 Rectangle(0, (int) getHeight()- (int) getVisibleRect().getHeight(),
619 (int) getVisibleRect().getWidth(), (int) getVisibleRect().getHeight()));
620 } //annotations2Trees
621
622 private JButton processChildrenAnnots(Annotation annot, HashMap processed) {
623 selection.clear();
624 Vector childrenButtons = new Vector();
625 java.util.List children =
626 (java.util.List) annot.getFeatures().get(NODE_CONSISTS_FEATURE_NAME);
627
628 for (Iterator i = children.iterator(); i.hasNext(); ) {
629 Integer childId = (Integer) i.next();
630 Annotation child = treeAnnotations.get(childId);
631 JButton childButton;
632
633 if (processed.containsKey(child.getId()))
634 childButton = (JButton) processed.get(child.getId());
635 else
636 childButton = processChildrenAnnots(child, processed);
637
638 childrenButtons.add(childButton);
639 }
640
641 selection = (Vector) childrenButtons.clone();
642 STreeNode parent = createParentNode(
643 (String) annot.getFeatures().get(NODE_CAT_FEATURE_NAME),
644 annot);
645 nonTerminals.put(new Integer(parent.getID()), parent);
646 JButton parentButton = createCentralButton(parent);
647 addLines(parent);
648
649 processed.put(annot.getId(), parentButton);
650 selection.clear();
651 return parentButton;
652 }// private JButton processChildrenAnnots
653
654 private STreeNode findLeaf(Node start, Node end) {
655 for (Iterator i = leaves.values().iterator(); i.hasNext(); ) {
656 STreeNode node = (STreeNode) i.next();
657 if (node.getStart() == start.getOffset().intValue() &&
658 node.getEnd() == end.getOffset().intValue()
659 )
660 return node;
661 }
662
663 return null;
664 }//private STreeNode findLeaf(Node start, Node end)
665
666
667 /**
668 * Converts the given utterances into a set of leaf nodes for annotation
669 */
670 private void utterances2Trees() {
671
672 if (! utterance.getType().equals(textAnnotationType)) {
673 Out.println("Can't display annotations other than the specified type:" +
674 textAnnotationType);
675 return;
676 }
677
678 // set the utterance offset correctly.
679 // All substring calculations depend on that.
680 utteranceStartOffset = utterance.getStartNode().getOffset();
681 utteranceEndOffset = utterance.getEndNode().getOffset();
682
683 try {
684 displayedString = currentSet.getDocument().getContent().getContent(
685 utteranceStartOffset, utteranceEndOffset).toString();
686 } catch (InvalidOffsetException ioe) {
687 ioe.printStackTrace(Err.getPrintWriter());
688 }
689
690 AnnotationSet tokensAS = currentSet.get(tokenType, utteranceStartOffset,
691 utteranceEndOffset);
692 if (tokensAS == null || tokensAS.isEmpty()) {
693 Out.println("TreeViewer warning: No annotations of type " + tokenType +
694 "so cannot show or edit the text and the tree annotations.");
695 return;
696 }
697
698 Insets insets = this.getInsets();
699 // the starting X position for the buttons
700 int buttonX = insets.left;
701
702 // the starting Y position
703 int buttonY = this.getHeight() - 20 - insets.bottom;
704
705 java.util.List tokens = new ArrayList(tokensAS);
706 //if no tokens to match, do nothing
707 if (tokens.isEmpty())
708 return;
709 Collections.sort(tokens, new gate.util.OffsetComparator());
710
711 //loop through the tokens
712 for (int i= 0; i< tokens.size(); i++) {
713 Annotation tokenAnnot = (Annotation) tokens.get(i);
714 Long tokenBegin = tokenAnnot.getStartNode().getOffset();
715 Long tokenEnd = tokenAnnot.getEndNode().getOffset();
716
717 String tokenText = "";
718 try {
719 tokenText = document.getContent().getContent(
720 tokenBegin, tokenEnd).toString();
721 } catch (InvalidOffsetException ioe) {
722 ioe.printStackTrace(Err.getPrintWriter());
723 }
724
725 // create the leaf node
726 STreeNode node =
727 new STreeNode(tokenBegin.longValue(), tokenEnd.longValue());
728
729 // make it a leaf
730 node.setAllowsChildren(false);
731
732 // set the text
733 node.setUserObject(tokenText);
734 node.setLevel(0);
735
736 // add to hash table of leaves
737 leaves.put(new Integer(node.getID()), node);
738
739 // create the corresponding button
740 buttonX = createButton4Node(node, buttonX, buttonY);
741
742 } //while
743
744
745 /*
746 //This old piece of code was used to tokenise, instead of relying on
747 // annotations. Can re-instate if someone shows me the need for it.
748
749 long currentOffset = utteranceStartOffset.longValue();
750
751 StrTokeniser strTok =
752 new StrTokeniser(displayedString,
753 " \r\n\t");
754
755 Insets insets = this.getInsets();
756 // the starting X position for the buttons
757 int buttonX = insets.left;
758
759 // the starting Y position
760 int buttonY = this.getHeight() - 20 - insets.bottom;
761
762 while (strTok.hasMoreTokens()) {
763 String word = strTok.nextToken();
764 // Out.println("To display:" + word);
765
766 // create the leaf node
767 STreeNode node =
768 new STreeNode(currentOffset, currentOffset + word.length());
769
770 // make it a leaf
771 node.setAllowsChildren(false);
772
773 // set the text
774 node.setUserObject(word);
775 node.setLevel(0);
776
777 // add to hash table of leaves
778 leaves.put(new Integer(node.getID()), node);
779
780 // create the corresponding button
781 buttonX = createButton4Node(node, buttonX, buttonY);
782
783 currentOffset += word.length()+1; //// +1 to include the delimiter too
784 }
785 */
786
787 this.setSize(buttonX, buttonY + 20 + insets.bottom);
788 // this.resize(buttonX, buttonY + 20 + insets.bottom);
789 this.setPreferredSize(this.getSize());
790
791 } // utterance2Trees
792
793 /**
794 * Returns the X position where another button can start if necessary.
795 * To be used to layout only the leaf buttons. All others must be created
796 * central to their children using createCentralButton.
797 */
798 private int createButton4Node(STreeNode node, int buttonX, int buttonY) {
799
800 JButton button = new JButton((String) node.getUserObject());
801 button.setBorderPainted(false);
802
803 FontMetrics fm = button.getFontMetrics(button.getFont());
804
805 int buttonWidth,
806 buttonHeight;
807
808 // Out.print
809 // ("Button width " + b1.getWidth() + "Button height " + b1.getHeight());
810
811 buttonWidth = fm.stringWidth(button.getText())
812 + button.getMargin().left + button.getMargin().right
813 + extraButtonWidth;
814 buttonHeight = fm.getHeight() + button.getMargin().top +
815 button.getMargin().bottom;
816 buttonY = buttonY - buttonHeight;
817
818 // Out.print("New Button X " + buttonX +
819 // "New Button Y" + buttonY);
820
821 button.setBounds(buttonX, buttonY, buttonWidth, buttonHeight);
822 button.addActionListener(this);
823 button.addMouseListener(this);
824 button.setActionCommand("" + node.getID());
825 button.setVisible(true);
826 button.setEnabled(true);
827
828 this.add(button);
829 buttons.put(new Integer(node.getID()), button);
830
831 buttonX += buttonWidth + horizButtonGap;
832 return buttonX;
833
834 }// private int createButton4Node(STreeNode node, int buttonX, int buttonY)
835
836 private JButton createCentralButton(STreeNode newNode) {
837
838 FocusButton button = new FocusButton((String) newNode.getUserObject());
839 button.setBorderPainted(false);
840
841 FontMetrics fm = button.getFontMetrics(button.getFont());
842
843 int buttonWidth,
844 buttonHeight,
845 buttonX = 0,
846 buttonY =0;
847
848 // Out.print("Button width " + b1.getWidth() + ";
849 // Button height " + b1.getHeight());
850
851 buttonWidth = fm.stringWidth(button.getText())
852 + button.getMargin().left + button.getMargin().right
853 + extraButtonWidth;
854 buttonHeight = fm.getHeight() + button.getMargin().top +
855 button.getMargin().bottom;
856
857 int left = this.getWidth(), right =0 , top = this.getHeight();
858
859 // determine the left, right, top
860 for (Iterator i = selection.iterator(); i.hasNext(); ) {
861 JButton childButton = (JButton) i.next();
862
863 if (left > childButton.getX())
864 left = childButton.getX();
865 if (childButton.getX() + childButton.getWidth() > right)
866 right = childButton.getX() + childButton.getWidth();
867 if (childButton.getY() < top)
868 top = childButton.getY();
869 }
870
871 buttonX = (left + right) /2 - buttonWidth/2;
872 buttonY = top - vertButtonGap;
873 // Out.println("Button's Y is" + buttonY);
874
875 // Out.print("New Button width " + buttonWidth + ";
876 // New Button height " + buttonHeight);
877 button.setBounds(buttonX, buttonY, buttonWidth, buttonHeight);
878 button.addActionListener(this);
879 button.addMouseListener(this);
880 // button.registerKeyboardAction(this,
881 // "delete",
882 // KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0),
883 // WHEN_FOCUSED);
884
885 button.setActionCommand("" + newNode.getID());
886
887 this.add(button);
888 // add to hashmap of buttons
889 buttons.put(new Integer(newNode.getID()), button);
890
891 // check if we need to resize the panel
892 if (buttonY < 0) {
893 this.setSize(this.getWidth(), this.getHeight() + 5* (- buttonY));
894 this.setPreferredSize(this.getSize());
895 shiftButtonsDown(5* (-buttonY));
896 }
897
898 return button;
899 }// private JButton createCentralButton(STreeNode newNode)
900
901 private void shiftButtonsDown(int offset) {
902 for (Iterator i = buttons.values().iterator(); i.hasNext(); ) {
903 JButton button = (JButton) i.next();
904 button.setBounds( button.getX(),
905 button.getY() + offset,
906 button.getWidth(),
907 button.getHeight());
908 } // for loop through buttons
909
910 for (Iterator k = lines.iterator(); k.hasNext(); ) {
911 Coordinates coords = (Coordinates) k.next();
912 coords.setY1(coords.getY1() + offset);
913 coords.setY2(coords.getY2() + offset);
914 }
915 }// private void shiftButtonsDown(int offset)
916
917 public void actionPerformed(ActionEvent e) {
918
919 //check for the popup menu items
920 if (e.getSource() instanceof JMenuItem) {
921 JMenuItem menuItem = (JMenuItem) e.getSource();
922
923 // check if we're annotating a leaf
924 // the popup label is set to leaves when the popup has been
925 // constructed in showRightClickPopup
926 if (popup.getLabel().equals("leaves")) {
927 Integer id = new Integer(e.getActionCommand());
928
929 // clearSelection();
930 JButton button = (JButton) buttons.get(id);
931 selection.add(button);
932
933 STreeNode leaf = (STreeNode) leaves.get(id);
934
935 // create parent with the same span as leaf
936 // using createParentNode here is not a good idea coz it works only
937 // for creating parents of non-terminal nodes, not leaves
938 STreeNode parent = new STreeNode(leaf.getStart(), leaf.getEnd());
939 parent.setLevel(leaf.getLevel()+1); //levels increase from bottom to top
940 parent.add(leaf);
941
942 // set the text
943 parent.setUserObject(menuItem.getText());
944
945 // last create the annotation; should always come last!
946 parent.createAnnotation( document,
947 treeNodeAnnotationType,
948 displayedString,
949 utteranceStartOffset.longValue());
950 nonTerminals.put(new Integer(parent.getID()), parent);
951
952 // create new button positioned centrally above the leaf
953 createCentralButton(parent);
954
955 // add the necessary lines for drawing
956 addLines(parent);
957
958 clearSelection();
959
960 // repaint the picture!
961 this.repaint();
962 } // finished processing leaves
963 else if (popup.getLabel().equals("non-terminal")) {
964 // the action command is set to the id under which
965 // the button can be found
966 Integer id = new Integer(e.getActionCommand());
967
968 //locate button from buttons hashMap and add to selection
969 JButton button = (JButton) buttons.get(id);
970 selection.add(button);
971
972 //create the new parent
973 STreeNode parent = createParentNode(menuItem.getText());
974
975 //add to nonTerminals HashMap
976 nonTerminals.put(new Integer(parent.getID()), parent);
977
978 //create new button positioned centrally above the leaf
979 createCentralButton(parent);
980
981 //add the necessary lines for drawing
982 addLines(parent);
983
984 clearSelection();
985
986 //repaint the picture!
987 this.repaint();
988
989 } //check for non-terminals
990
991 } //if statement for MenuItems
992
993
994 }// public void actionPerformed(ActionEvent e)
995
996 public void mouseClicked(MouseEvent e) {
997
998 if (! (e.getSource() instanceof JButton))
999 return;
1000
1001 JButton source = (JButton) e.getSource();
1002
1003 //check if CTRL or Shift is pressed and if not, clear the selection
1004 if ((! (e.isControlDown() || e.isShiftDown()))
1005 && SwingUtilities.isLeftMouseButton(e))
1006 clearSelection();
1007
1008 //and select the current node
1009 if (SwingUtilities.isLeftMouseButton(e))
1010 //if (e.getModifiers() == e.BUTTON1_MASK)
1011 selectNode(e);
1012
1013
1014 //only repspond to right-clicks here by displaying the popup
1015 if (SwingUtilities.isRightMouseButton(e)) {
1016 //if button not in focus, grad the focus and select it!
1017 if ( source.getBackground() != selectedNodeColor ) {
1018 source.grabFocus();
1019 source.doClick();
1020 selectNode(e);
1021 }
1022 //Out.println(e.getComponent().getClass() + " right-clicked!");
1023 showRightClickPopup(e);
1024 } //end of right-click processing
1025
1026 }// public void mouseClicked(MouseEvent e)
1027
1028 public void mousePressed(MouseEvent e) {
1029 }
1030
1031 public void mouseReleased(MouseEvent e) {
1032 }
1033
1034 public void mouseEntered(MouseEvent e) {
1035 }
1036
1037 public void mouseExited(MouseEvent e) {
1038 } // createButton4Node
1039
1040
1041 private void showRightClickPopup(MouseEvent e) {
1042
1043 //that'll always work coz we checked it in MouseClicked.
1044 JButton source = (JButton) e.getSource();
1045 Integer id = new Integer(source.getActionCommand());
1046
1047 //check if it's a leaf and if so, offer the leaf annotation dialog
1048 Object obj = leaves.get(id);
1049 if (obj != null) {
1050 STreeNode leaf = (STreeNode) obj;
1051 //do nothing if it already has a parent
1052 if (leaf.getParent() != null) {
1053 clearSelection();
1054 JOptionPane.showMessageDialog(
1055 this,
1056 "Node already annotated. To delete the existing annotation, " +
1057 "select it and press <DEL>.",
1058 "Syntax Tree Viewer message",
1059 JOptionPane.INFORMATION_MESSAGE);
1060 return;
1061 }
1062
1063 //reset the popup and set it's heading accordingly
1064 popup.setLabel("leaves");
1065 setMenuCommands(popup, ""+id);
1066
1067 popup.pack();
1068 popup.show(source, e.getX(), e.getY());
1069 } else { //we have a non-terminal node
1070
1071 //check if it has been annotated already
1072 if ( ((STreeNode) nonTerminals.get(id)).getParent() != null) {
1073 clearSelection();
1074 JOptionPane.showMessageDialog(this, "Node already annotated. To delete"+
1075 " the existing annotation, select it and press <DEL>.",
1076 "Syntax Tree Viewer message",
1077 JOptionPane.INFORMATION_MESSAGE);
1078 return; //and do nothing if so!
1079 }
1080
1081 popup.setLabel("non-terminal");
1082 setMenuCommands(popup, ""+id);
1083
1084 popup.pack();
1085 popup.show(source, e.getX(), e.getY());
1086
1087 }
1088
1089 } //showRightClickPopup
1090
1091 private void addLines(STreeNode newNode) {
1092
1093 JButton newButton = (JButton) buttons.get(new Integer(newNode.getID()));
1094 int nbX = newButton.getX() + newButton.getWidth()/2;
1095 int nbY = newButton.getY() + newButton.getHeight();
1096
1097 for (Iterator i = selection.iterator(); i.hasNext(); ) {
1098 JButton selButton = (JButton) i.next();
1099
1100 //I create it a rect but it will in fact be used as x1, y1, x2, y2 for the
1101 //draw line. see drawLines.
1102 Coordinates coords = new Coordinates(
1103 nbX,
1104 nbY,
1105 selButton.getX() + selButton.getWidth()/2,
1106 selButton.getY());
1107
1108 lines.add(coords);
1109 }
1110
1111 } // addLines
1112
1113 private void clearSelection() {
1114 for (Enumeration enumeration = selection.elements(); enumeration.hasMoreElements(); ) {
1115 JButton selButton = (JButton) enumeration.nextElement();
1116 selButton.setBackground(buttonBackground);
1117 }
1118
1119 selection.clear();
1120
1121 } //clearSlection
1122
1123
1124 private void fillCategoriesMenu() {
1125 boolean found = false;
1126
1127 //fetch the valid categories from the stereotype
1128 CreoleRegister creoleReg = Gate.getCreoleRegister();
1129 java.util.List currentAnnotationSchemaList =
1130 creoleReg.getLrInstances("gate.creole.AnnotationSchema");
1131 if (currentAnnotationSchemaList.isEmpty()) return;
1132
1133 Iterator iter = currentAnnotationSchemaList.iterator();
1134 while (iter.hasNext()){
1135 AnnotationSchema annotSchema = (AnnotationSchema) iter.next();
1136 //we have found the right schema
1137 if (treeNodeAnnotationType.equals(annotSchema.getAnnotationName())) {
1138 found = true;
1139 FeatureSchema categories = annotSchema.getFeatureSchema(NODE_CAT_FEATURE_NAME);
1140 //iterate through all categories
1141 for (Iterator i =
1142 categories.getPermissibleValues().iterator(); i.hasNext(); ) {
1143
1144 JMenuItem menuItem = new JMenuItem( (String) i.next() );
1145 menuItem.addActionListener(this);
1146 popup.add(menuItem);
1147 } //for
1148
1149 } //if
1150 }// while
1151
1152 //if we don't have a schema, issue a warning
1153 if (! found)
1154 Out.println("Warning: You need to define an annotation schema for " +
1155 treeNodeAnnotationType +
1156 " in order to be able to add such annotations.");
1157
1158 } // fillCategoriesMenu
1159
1160 /**
1161 * Sets the action commands of all menu items to the specified command
1162 */
1163 private void setMenuCommands(JPopupMenu menu, String command) {
1164 for (int i = 0; i < menu.getComponentCount() ; i++) {
1165 JMenuItem item = (JMenuItem) menu.getComponent(i);
1166 item.setActionCommand(command);
1167 }
1168
1169 } // setMenuCommands
1170
1171 /**
1172 * Create a parent node for all selected non-terminal nodes
1173 */
1174 protected STreeNode createParentNode(String text) {
1175 STreeNode parentNode = new STreeNode();
1176
1177 long begin = 2147483647, end = 0, level= -1;
1178 for (Iterator i = selection.iterator(); i.hasNext(); ) {
1179 JButton button = (JButton) i.next();
1180 Integer id = new Integer(button.getActionCommand());
1181
1182 STreeNode child = (STreeNode) nonTerminals.get(id);
1183
1184 if (begin > child.getStart())
1185 begin = child.getStart();
1186 if (end < child.getEnd())
1187 end = child.getEnd();
1188 if (level < child.getLevel())
1189 level = child.getLevel();
1190
1191 parentNode.add(child);
1192
1193 } //for
1194
1195 parentNode.setLevel(level+1);
1196 parentNode.setStart(begin);
1197 parentNode.setEnd(end);
1198 parentNode.setUserObject(text);
1199 parentNode.createAnnotation(document,
1200 treeNodeAnnotationType,
1201 displayedString,
1202 utteranceStartOffset.longValue());
1203
1204
1205 return parentNode;
1206 }
1207
1208 /**
1209 * Create a parent node for all selected non-terminal nodes
1210 */
1211 protected STreeNode createParentNode(String text, Annotation annot) {
1212 STreeNode parentNode = new STreeNode(annot);
1213
1214 long level = -1;
1215 for (Iterator i = selection.iterator(); i.hasNext(); ) {
1216 JButton button = (JButton) i.next();
1217 Integer id = new Integer(button.getActionCommand());
1218
1219 STreeNode child = (STreeNode) nonTerminals.get(id);
1220
1221 if (level < child.getLevel())
1222 level = child.getLevel();
1223
1224 parentNode.add(child);
1225 } //for
1226
1227 parentNode.setLevel(level+1);
1228 parentNode.setUserObject(text);
1229
1230 return parentNode;
1231 }
1232
1233
1234 void selectNode(MouseEvent e) {
1235 // try finding the node that's annotated, i.e., the selected button
1236 if (e.getSource() instanceof JButton) {
1237 JButton source = (JButton) e.getSource();
1238
1239 selection.add(source);
1240 buttonBackground = source.getBackground();
1241 source.setBackground(selectedNodeColor);
1242 }
1243 }
1244
1245 // remove that node from the syntax tree
1246 void removeNode(JButton button) {
1247
1248 Integer id = new Integer(button.getActionCommand());
1249 STreeNode node = (STreeNode) nonTerminals.get(id);
1250 nonTerminals.remove(node);
1251 node.removeAnnotation(document);
1252
1253 //fix the STreeNodes involved
1254 resetChildren(node);
1255 removeNodesAbove(node);
1256
1257 //remove button from everywhere
1258 buttons.remove(button);
1259 button.setVisible(false);
1260 this.remove(button);
1261
1262 //recalculate all lines
1263 recalculateLines();
1264
1265 //make sure we clear the selection
1266 selection.clear();
1267 repaint();
1268 }
1269
1270 //set parent node to null for all children of the given node
1271 private void resetChildren(STreeNode node) {
1272 for (Enumeration e = node.children(); e.hasMoreElements(); )
1273 ((STreeNode) e.nextElement()).setParent(null);
1274
1275 node.disconnectChildren();
1276 }
1277
1278 private void removeNodesAbove(STreeNode node) {
1279 STreeNode parent = (STreeNode) node.getParent();
1280
1281 while (parent != null) {
1282 Integer id = new Integer(parent.getID());
1283 parent.removeAnnotation(document);
1284 if (parent.isNodeChild(node))
1285 parent.remove(node);
1286 parent.disconnectChildren();
1287
1288 nonTerminals.remove(id);
1289
1290 JButton button = (JButton) buttons.get(id);
1291 this.remove(button);
1292 buttons.remove(id);
1293
1294 parent = (STreeNode) parent.getParent();
1295 }
1296 }
1297
1298 private void recalculateLines() {
1299 lines.clear();
1300 //go through all non-terminals and recalculate their lines to their children
1301 for (Iterator i = nonTerminals.values().iterator(); i.hasNext(); )
1302 recalculateLines((STreeNode) i.next());
1303
1304 }
1305
1306 /**
1307 * recalculates all lines from that node to all its children
1308 */
1309 private void recalculateLines(STreeNode node) {
1310 Integer id = new Integer(node.getID());
1311 JButton button = (JButton) buttons.get(id);
1312
1313 int bX = button.getX() + button.getWidth()/2;
1314 int bY = button.getY() + button.getHeight();
1315
1316 for (Enumeration e = node.children(); e.hasMoreElements(); ) {
1317 STreeNode subNode = (STreeNode) e.nextElement();
1318 Integer sid = new Integer(subNode.getID());
1319 JButton subButton = (JButton) buttons.get(sid);
1320
1321 Coordinates coords = new Coordinates(
1322 bX,
1323 bY,
1324 subButton.getX() + subButton.getWidth()/2,
1325 subButton.getY());
1326
1327 lines.add(coords);
1328 }
1329
1330 }
1331
1332/*
1333 // discontinued from use,done automatically instead, when the utterance is set
1334
1335 public void setTreeAnnotations(AnnotationSet newTreeAnnotations) {
1336 AnnotationSet oldTreeAnnotations = treeAnnotations;
1337 treeAnnotations = newTreeAnnotations;
1338 firePropertyChange("treeAnnotations", oldTreeAnnotations,
1339 newTreeAnnotations);
1340 }
1341*/
1342
1343 public void setTreeNodeAnnotationType(String newTreeNodeAnnotationType) {
1344 treeNodeAnnotationType = newTreeNodeAnnotationType;
1345 }
1346
1347 public String getTreeNodeAnnotationType() {
1348 return treeNodeAnnotationType;
1349 }
1350
1351 public void setTokenType(String newTokenType) {
1352 if (newTokenType != null && ! newTokenType.equals(""))
1353 tokenType = newTokenType;
1354 }
1355
1356 public String getTokenType() {
1357 return tokenType;
1358 }
1359
1360 void this_componentShown(ComponentEvent e) {
1361 Out.println("Tree Viewer shown");
1362 }
1363
1364 void this_componentHidden(ComponentEvent e) {
1365 Out.println("Tree Viewer closes");
1366 }
1367
1368/*
1369 //None of this works, damn!!!
1370
1371 public void setVisible(boolean b) {
1372 if (!b && this.isVisible())
1373 Out.println("Tree Viewer closes");
1374
1375 super.setVisible( b);
1376 }
1377 public void hide() {
1378 Out.println("Tree Viewer closes");
1379 super.hide();
1380 }
1381*/
1382
1383
1384}// class SyntaxTreeViewer
1385
1386
1387class FocusButton extends JButton {
1388
1389 public FocusButton(String text) {
1390 super(text);
1391 }
1392
1393 public FocusButton() {
1394 super();
1395 }
1396
1397 public FocusButton(Icon icon) {
1398 super(icon);
1399 }
1400
1401 public FocusButton(String text, Icon icon) {
1402 super(text, icon);
1403 }// public FocusButton
1404
1405// public boolean isManagingFocus() {
1406// return true;
1407// }// public boolean isManagingFocus()
1408
1409 public void processComponentKeyEvent(KeyEvent e) {
1410 super.processComponentKeyEvent(e);
1411
1412 //I need that cause I get all events here, so I only want to process
1413 //when it's a release event. The reason is that for keys like <DEL>
1414 //key_typed never happens
1415 if (e.getID() != KeyEvent.KEY_RELEASED)
1416 return;
1417
1418 if (e.getKeyCode() == KeyEvent.VK_DELETE) {
1419 SyntaxTreeViewer viewer = (SyntaxTreeViewer) ((JButton) e.getSource()).getParent();
1420 viewer.removeNode((JButton) e.getSource());
1421 }
1422 }// public void processComponentKeyEvent(KeyEvent e)
1423
1424} // class SyntaxTreeViewer
1425
1426// $Log: SyntaxTreeViewer.java,v $
1427// Revision 1.26 2004/07/26 14:59:32 valyt
1428// "Made in Sheffield" sources are now JDK 1.5 safe (by renaming enum to enumeration).
1429// There are still problems with Java sources generated by JavaCC
1430//
1431// Revision 1.25 2004/07/21 17:10:07 akshay
1432// Changed copyright from 1998-2001 to 1998-2004
1433//
1434// Revision 1.24 2004/03/25 13:01:05 valyt
1435// Imports optimisation throughout the Java sources
1436// (to get rid of annoying warnings in Eclipse)
1437//
1438// Revision 1.23 2003/08/27 15:53:03 valyt
1439//
1440// removed deprecation warning
1441//
1442// Revision 1.22 2003/01/28 10:01:16 marin
1443// [marin] bugfixes from Kali
1444//
1445// Revision 1.21 2002/03/06 17:15:46 kalina
1446// Reorganised the source code, so that it now uses constants from
1447// ANNIEConstants, GateConstants and parameter constants defined on each PR.
1448// Read e-mail to the gate list for an explanation.
1449//
1450// Revision 1.20 2001/08/08 16:14:26 kalina
1451// A minor change to the tree viewer.
1452//
1453// Revision 1.19 2001/08/08 14:39:00 kalina
1454// Made the dialog to size itself maximum as much as the screen, coz was
1455// getting too big without that.
1456//
1457// Some documentation on Tree Viewer and some small changes to utterance2trees()
1458// to make it order the tokens correctly by offset
1459//
1460// Revision 1.18 2001/08/07 19:03:05 kalina
1461// Made the tree viewer use Token annotations to break the sentence for annotation
1462//
1463// Revision 1.17 2001/08/07 17:01:32 kalina
1464// Changed the AVR implementing classes in line with the updated AVR
1465// API (cancelAction() and setSpan new parameter).
1466//
1467// Also updated the TreeViewer, so now it can be used to edit and view
1468// Sentence annotations and the SyntaxTreeNodes associated with them.
1469// So if you have trees, it'll show them, if not, it'll help you build them.
1470//
1471// Revision 1.16 2001/04/09 10:36:36 oana
1472// a few changes in the code style
1473//
1474// Revision 1.14 2000/12/04 12:29:29 valyt
1475// Done some work on the visual resources
1476// Added the smart XJTable
1477//
1478// Revision 1.13 2000/11/08 16:35:00 hamish
1479// formatting
1480//
1481// Revision 1.12 2000/10/26 10:45:26 oana
1482// Modified in the code style
1483//
1484// Revision 1.11 2000/10/24 10:10:18 valyt
1485// Fixed the deprecation warning in gate/gui/SyntaxTreeViewer.java
1486//
1487// Revision 1.10 2000/10/18 13:26:47 hamish
1488// Factory.createResource now working, with a utility method that uses reflection (via java.beans.Introspector) to set properties on a resource from the
1489// parameter list fed to createResource.
1490// resources may now have both an interface and a class; they are indexed by interface type; the class is used to instantiate them
1491// moved createResource from CR to Factory
1492// removed Transients; use Factory instead
1493//
1494// Revision 1.9 2000/10/16 16:44:32 oana
1495// Changed the comment of DEBUG variable
1496//
1497// Revision 1.8 2000/10/10 15:36:35 oana
1498// Changed System.out in Out and System.err in Err;
1499// Added the DEBUG variable seted on false;
1500// Added in the header the licence;
1501//
1502// Revision 1.7 2000/10/10 09:49:57 valyt
1503// Fixed the Annotation test
1504//
1505// Revision 1.6 2000/10/02 12:34:06 valyt
1506// Added the UnicodeEnabled switch on gate.util.Tools
1507//
1508// Revision 1.5 2000/09/28 14:26:09 kalina
1509// Added even more documentation (is this me?!) and allowed several tokens to be
1510// passed instead of a whole utterance/sentence for annotation. Needs good testing this
1511// but will do it when somebody tries using this functionality.
1512//
1513// Revision 1.4 2000/09/28 13:16:12 kalina
1514// Added some documentation
1515//
1516// Revision 1.3 2000/09/21 14:23:45 kalina
1517// Fixed some small bug in main(). To test just run the component itself.
1518//
1519// Revision 1.2 2000/09/21 14:17:27 kalina
1520// Added Unicode support
1521//
1522// Revision 1.1 2000/09/20 17:03:37 kalina
1523// Added the tree viewer from the prototype. It works now with the new annotation API.
1524