|
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 |
|