| SyntaxTreeViewer |

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

| SyntaxTreeViewer |