001 /* 002 // $Id: Node.java 3 2009-05-11 08:11:57Z jhyde $ 003 // Clapham generates railroad diagrams to represent computer language grammars. 004 // Copyright (C) 2008-2009 Julian Hyde 005 // Copyright (c) 2005 Stefan Schoergenhumer, Markus Dopler 006 // 007 // This program is free software; you can redistribute it and/or modify it 008 // under the terms of the GNU General Public License as published by the Free 009 // Software Foundation; either version 2 of the License, or (at your option) 010 // any later version approved by The Eigenbase Project. 011 // 012 // This program is distributed in the hope that it will be useful, 013 // but WITHOUT ANY WARRANTY; without even the implied warranty of 014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 015 // GNU General Public License for more details. 016 // 017 // You should have received a copy of the GNU General Public License 018 // along with this program; if not, write to the Free Software 019 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 020 */ 021 package net.hydromatic.clapham.graph; 022 023 import java.awt.*; 024 import java.awt.geom.Point2D.Float; 025 import java.util.List; 026 import java.util.ArrayList; 027 028 /** 029 * TODO: 030 * 031 * @author jhyde 032 * @version $Id: Node.java 3 2009-05-11 08:11:57Z jhyde $ 033 * @since Jul 30, 2008 034 */ 035 public class Node { 036 037 public final int n; // node number 038 public NodeType typ; // t, nt, eps, alt, iter, opt, rerun 039 public Node next; // to successor node 040 public Node down; // alt: to next alternative 041 public Node sub; // alt, iter, opt: to first node of substructure 042 public boolean up; // true: "next" leads to successor in enclosing structure 043 public Symbol sym; // nt, t: symbol represented by this node 044 public Node itergraph; // rerun: points to the b in "a {b a}", null if "a {a}" 045 private boolean firstLevel; // true if the Node is in the first Level 046 private TextBox textBox; 047 048 public Node(Grammar grammar, Symbol sym) { 049 this.typ = sym.typ; 050 this.sym = sym; 051 n = grammar.nodes.size(); 052 grammar.nodes.add(this); 053 } 054 055 public Node(Grammar grammar, NodeType typ, Node sub) { 056 this.typ = typ; 057 n = grammar.nodes.size(); 058 grammar.nodes.add(this); 059 this.sub = sub; 060 } 061 062 //----------------- for printing ---------------------- 063 064 //----------------- for drawing ---------------------- 065 066 /*****************other variables needed for the drawing********/ 067 Size size = new Size(0,0); // the required size to draw the node 068 private Size altSize = new Size(0,0); // the required size to draw a construct of alts or the size of the firstcomponent in the special rerun-node (itergraph!=null) 069 private Size iterSize = new Size(0,0); // the size of the second component in the special rerun Node (itergraph!=null) 070 final Float posBegin = new Float(0,0); // the point in the left above corner of the component 071 public final Float posLine = new Float(0,0); // the point of the line of the component 072 final Float posEnd = new Float(0,0); // the point in the left down corner of the component 073 074 public void unparse(StringBuffer buf) { 075 switch (typ) { 076 case TERM: 077 buf.append('\'').append(sym.name).append('\''); 078 break; 079 case NONTERM: 080 buf.append('<').append(sym.name).append('>'); 081 break; 082 case ALT: 083 final List<Node> alts = new ArrayList<Node>(); 084 for (Node n = this; n != null; n = n.down) { 085 alts.add(n.sub); 086 } 087 int count = 0; 088 buf.append("("); 089 for (Node alt : alts) { 090 if (count++ > 0) { 091 buf.append(" | "); 092 } 093 unparseList(buf, nextChildren(alt), "", " ", ""); 094 } 095 buf.append(")"); 096 break; 097 case ITER: 098 unparseList(buf, nextChildren(sub), "iter(", " ", ")"); 099 break; 100 default: 101 buf.append("unknown <").append(typ).append(">"); 102 } 103 } 104 105 private static List<Node> nextChildren(Node next) { 106 final List<Node> list = new ArrayList<Node>(); 107 for (Node n = next; n != null; n = n.up ? null : n.next) { 108 list.add(n); 109 } 110 return list; 111 } 112 113 private void unparseList( 114 StringBuffer buf, 115 List<Node> list, 116 String before, 117 String mid, 118 String after) 119 { 120 int count = 0; 121 buf.append(before); 122 for (Node n : list) { 123 if (count++ > 0) { 124 buf.append(mid); 125 } 126 n.unparse(buf); 127 } 128 buf.append(after); 129 } 130 131 // calculates the size if there are wraps in the rule 132 public void setWrapSize(Chart chart) { 133 Node n = this; 134 float maxH = 0; 135 while (n != null) { 136 n.firstLevel = true; 137 switch (n.typ) { 138 case WRAP: 139 n.size.setHeight(maxH); 140 maxH = 0; 141 break; 142 case ITER: 143 if (maxH 144 < n.size.getHeight() 145 + (chart.getFontHeight() + chart.componentGapHeight) 146 / 2) { 147 maxH = 148 n.size.getHeight() 149 + (chart.getFontHeight() 150 + chart.componentGapHeight) / 2; 151 } 152 break; 153 default: 154 if (maxH < n.size.getHeight() 155 || maxH < n.altSize.getHeight()) { 156 if (n.altSize.getHeight() != 0) { 157 maxH = n.altSize.getHeight(); 158 } else { 159 maxH = n.size.getHeight(); 160 } 161 } 162 break; 163 } 164 n = n.next; 165 } 166 } 167 168 /** 169 * Calculates the size of each symbol. 170 */ 171 public Size calcSize(Chart chart) { 172 Node n = this; //current node in the level 173 Size s = new Size(); // alt,iter,opt: size of current construct 174 int iterCompensation = 0; 175 boolean samelevel = true; //next node in same level? 176 int realHeight = n.calcHeight(chart); 177 Size maxTotalSize = new Size(0, 0); 178 while (n != null && samelevel) { 179 switch (n.typ) { 180 case TERM: 181 case NONTERM: 182 n.textBox = 183 new TextBox( 184 chart, n.sym.name, chart.charFont, chart.charColor); 185 n.size.setHeight( 186 n.textBox.height 187 + chart.symbolGapHeight * 2 188 + chart.componentGapHeight); 189 n.size.setWidth( 190 n.textBox.width 191 + chart.symbolGapWidth * 2); 192 if (n.typ == NodeType.TERM) { 193 n.size.maxWidth( 194 chart.componentArcSize); 195 } 196 if (!n.up 197 && n.next != null 198 && n.next.typ == NodeType.WRAP 199 && n.next.size.getHeight() == 0) { 200 if (!n.next.up 201 && n.next.next != null 202 && (n.next.next.typ == NodeType.TERM 203 || n.next.next.typ == NodeType.NONTERM)) { 204 s.incWidth(chart.componentGapWidth / 2); 205 } 206 } 207 if (!n.up && n.next != null 208 && (n.next.typ == NodeType.TERM 209 || n.next.typ == NodeType.NONTERM)) { 210 s.incWidth(chart.componentGapWidth / 2); 211 } 212 break; 213 case EPS: 214 n.size.setHeight( 215 chart.getFontHeight() + chart.componentGapHeight); 216 n.size.setWidth(chart.componentGapWidth); 217 break; 218 case OPT: 219 n.size = n.sub.calcSize(chart); 220 n.size.incWidth(chart.componentGapWidth * 2); 221 n.size.incHeight(chart.componentGapHeight / 2); 222 break; 223 case ITER: 224 n.size = n.sub.calcSize(chart); 225 n.size.incWidth(chart.componentGapWidth * 2); 226 break; 227 case WRAP: 228 maxTotalSize.incHeight( 229 s.getHeight() 230 - chart.componentGapHeight / 2); 231 maxTotalSize.maxWidth(s.getWidth()); 232 s.setHeight(0); 233 s.setWidth(0); 234 break; 235 case RERUN: 236 n.size = n.sub.calcSize(chart); 237 if (n.itergraph != null) { 238 n.altSize = n.size; 239 n.size.maxWidth(n.itergraph.calcSize(chart).getWidth()); 240 n.size.incHeight(n.itergraph.calcSize(chart).getHeight()); 241 n.iterSize = n.itergraph.calcSize(chart); 242 } else { 243 n.size.incHeight(chart.componentGapHeight / 2); 244 } 245 n.size.incWidth(chart.componentGapWidth * 2); 246 break; 247 case ALT: { 248 Node a = n; 249 int maxH = -chart.componentGapHeight; 250 float maxW = 0; 251 while (a != null) { 252 a.size = a.sub.calcSize(chart); 253 maxH += a.size.getHeight(); 254 if (a.size.getWidth() > maxW) { 255 maxW = a.size.getWidth(); 256 } 257 a = a.down; 258 } 259 if (n.sub.typ == NodeType.ITER && realHeight != 0) { 260 maxH += 261 (chart.getFontHeight() + chart.componentGapHeight) / 2; 262 } 263 maxW += 2 * chart.componentGapWidth; 264 maxH += chart.componentGapHeight; 265 266 n.altSize.setHeight(maxH); 267 n.altSize.setWidth(maxW); 268 } 269 break; 270 } 271 if (n.typ == NodeType.ITER && realHeight != 0) { 272 iterCompensation = 273 (chart.getFontHeight() + chart.componentGapHeight) / 2; 274 } 275 if (n.typ == NodeType.ALT) { 276 s.maxHeight(n.altSize.getHeight()); 277 s.incWidth(n.altSize.getWidth()); 278 } else { 279 s.maxHeight(n.size.getHeight()); 280 s.incWidth(n.size.getWidth()); 281 } 282 if (n.typ == NodeType.ITER) { 283 s.maxHeight(n.size.getHeight() + iterCompensation); 284 } 285 if (n.up) { 286 samelevel = false; 287 } 288 n = n.next; 289 } 290 if (maxTotalSize.getWidth() != 0) { 291 maxTotalSize.incHeight( 292 s.getHeight() 293 - chart.componentGapHeight / 2); 294 maxTotalSize.maxWidth(s.getWidth()); 295 return maxTotalSize; 296 } else { 297 return s; 298 } 299 } 300 301 /** 302 * Calculates the total height of all symbols wich are in the same 303 * horizontal level. 304 */ 305 int calcHeight(Chart chart) { 306 Node n = this; //current node in the level 307 float realHeight = 0; 308 boolean samelevel = true; //next node in same level? 309 while (n != null && samelevel) { 310 if (n.typ == NodeType.NONTERM || n.typ == NodeType.TERM) { 311 if (realHeight < n.size.getHeight()) { 312 realHeight = n.size.getHeight(); 313 } 314 } else if (n.typ == NodeType.ITER) { 315 int tmpHeight = 0; 316 if (realHeight < tmpHeight) { 317 realHeight = tmpHeight; 318 } 319 } else if (n.typ == NodeType.OPT 320 || n.typ == NodeType.RERUN) { 321 int tmpHeight = n.sub.calcHeight(chart); 322 if (realHeight < tmpHeight) { 323 // REVIEW: 324 } 325 realHeight = tmpHeight; 326 } else if (n.typ == NodeType.ALT) { 327 int tmpHeight = n.sub.calcHeight(chart); 328 if (realHeight < tmpHeight) { 329 // REVIEW: 330 } 331 realHeight = tmpHeight; 332 } else if (n.typ == NodeType.EPS) { 333 if (realHeight < chart.getFontHeight() * 3 / 2) { 334 realHeight = 335 chart.getFontHeight() + chart.componentGapHeight; 336 } 337 } 338 if (n.up) { 339 samelevel = false; 340 } 341 n = n.next; 342 } 343 return (int) realHeight; 344 } 345 346 /** 347 * Calculates the horizontal position of the symbols. 348 */ 349 public void calcPos(Chart chart, float posBegin) { 350 Node n = this; //current node in the level 351 int realHeight = calcHeight(chart); 352 boolean samelevel = true; //next node in same level? 353 while (n != null && samelevel) { 354 if (n.typ == NodeType.NONTERM || n.typ == NodeType.TERM) { 355 n.posLine.y = posBegin + realHeight / 2; 356 n.posBegin.y = 357 n.posLine.y 358 - (n.size.getHeight() - chart.componentGapHeight) / 2; 359 n.posEnd.y = 360 n.posLine.y 361 + (n.size.getHeight() - chart.componentGapHeight) / 2; 362 } else if (n.typ == NodeType.EPS) { 363 n.posLine.y = posBegin + n.size.getHeight() / 2; 364 n.posBegin.y = posBegin; 365 n.posEnd.y = posBegin + n.size.getHeight(); 366 } else if (n.typ == NodeType.OPT) { 367 n.posLine.y = posBegin + realHeight / 2; 368 n.posBegin.y = posBegin; 369 n.posEnd.y = posBegin + n.size.getHeight(); 370 n.sub.calcPos(chart, n.posBegin.y); 371 } else if (n.typ == NodeType.RERUN) { 372 n.posLine.y = posBegin + realHeight / 2; 373 n.posBegin.y = posBegin; 374 n.posEnd.y = posBegin + n.size.getHeight(); 375 if (n.itergraph != null) { 376 n.itergraph.calcPos( 377 chart, 378 posBegin + n.altSize.getHeight()); 379 } 380 n.sub.calcPos(chart, n.posBegin.y); 381 } else if (n.typ == NodeType.ITER) { 382 if (realHeight == 0) { 383 n.posLine.y = posBegin + realHeight / 2; 384 n.posBegin.y = posBegin; 385 n.posEnd.y = posBegin + n.size.getHeight(); 386 } else { 387 n.posLine.y = posBegin + realHeight / 2; 388 n.posBegin.y = 389 posBegin 390 + (chart.getFontHeight() + chart.componentGapHeight) 391 / 2; 392 n.posEnd.y = n.posBegin.y + n.size.getHeight(); 393 } 394 n.sub.calcPos(chart, n.posLine.y); 395 } else if (n.typ == NodeType.WRAP && firstLevel) { 396 n.posLine.y = posBegin + realHeight / 2; 397 n.posEnd.y = posBegin + n.size.getHeight(); 398 posBegin = posBegin + n.size.getHeight(); 399 } else if (n.typ == NodeType.ALT) { 400 n.posLine.y = posBegin + realHeight / 2; 401 n.posBegin.y = posBegin; 402 n.posEnd.y = posBegin + n.altSize.getHeight(); 403 if (n.sub.typ == NodeType.ITER 404 && n.calcHeight(chart) != 0 405 && n.altSize.getHeight() != 0) { 406 posBegin += 407 (chart.getFontHeight() + chart.componentGapHeight) / 2; 408 } 409 n.sub.calcPos(chart, posBegin); 410 if (n.down != null) { 411 n.down.calcPos(chart, posBegin + n.size.getHeight()); 412 } 413 if (n.sub.typ == NodeType.ITER 414 && n.calcHeight(chart) != 0 415 && n.altSize.getHeight() != 0) { 416 posBegin -= 417 (chart.getFontHeight() + chart.componentGapHeight) / 2; 418 } 419 } 420 if (n.up) { 421 samelevel = false; 422 } 423 n = n.next; 424 } 425 } 426 427 /** 428 * Draws the components from left to right. 429 * 430 * <p>Each component paints itself and then give its coordinates to its 431 * sub-components for a recursive call, or if applicable, a call to 432 * the {@link #drawComponentsInverse} method. 433 */ 434 public void drawComponents(Chart chart, Float p, Size s) { 435 Node n = this; // current node in the level 436 boolean samelevel = true; // next node in same level? 437 438 while (n != null && samelevel) { 439 switch (n.typ) { 440 case TERM: 441 case NONTERM: 442 if (chart.showBorders) { 443 chart.drawRectangle( 444 Chart.RERUN_COLOR, 445 Chart.STROKE1, 446 p.x, 447 n.posBegin.y - chart.componentGapHeight / 2, 448 n.size.getWidth(), 449 n.size.getHeight()); 450 } 451 if (n.typ == NodeType.TERM) { 452 // the quarter Arcs 453 final float foo = 454 (n.size.getHeight() - chart.componentGapHeight) / 2; 455 chart.drawArcCorner( 456 p.x, 457 n.posBegin.y, 458 foo, 459 180); 460 chart.drawArcCorner( 461 p.x, 462 n.posLine.y, 463 foo, 464 90); 465 chart.drawArcCorner( 466 p.x + n.size.getWidth() - foo, 467 n.posBegin.y, 468 foo, 469 270); 470 chart.drawArcCorner( 471 p.x + n.size.getWidth() - foo, 472 n.posLine.y, 473 foo, 474 0); 475 476 n.textBox.drawAtCenter( 477 p.x, 478 n.posBegin.y, 479 n.size.getWidth() - foo, 480 n.posLine.y - n.posBegin.y); 481 482 // the short vertical and horizontal lines between the quarter Arcs 483 final float quarterHeight = 484 (n.size.getHeight() - chart.componentGapHeight) 485 / 4; 486 chart.drawLine( 487 p.x + quarterHeight - 1, 488 n.posBegin.y, 489 p.x + n.size.getWidth() - quarterHeight + 1, 490 n.posBegin.y); 491 chart.drawLine( 492 p.x + quarterHeight - 1, 493 n.posEnd.y, 494 p.x + n.size.getWidth() - quarterHeight + 1, 495 n.posEnd.y); 496 chart.drawLine( 497 p.x, 498 n.posLine.y + quarterHeight + 1, 499 p.x, 500 n.posLine.y - quarterHeight - 1); 501 chart.drawLine( 502 p.x + n.size.getWidth(), 503 n.posLine.y + quarterHeight + 1, 504 p.x + n.size.getWidth(), 505 n.posLine.y - quarterHeight - 1); 506 } else { 507 n.posBegin.x = p.x; 508 n.posEnd.x = p.x + n.size.getWidth(); 509 chart.drawRectangle( 510 chart.lineColor, 511 chart.lineStroke, 512 n.posBegin.x, 513 n.posBegin.y, 514 n.size.getWidth(), 515 n.size.getHeight() - chart.componentGapHeight); 516 517 n.textBox.drawAtCenter( 518 n.posBegin.x, 519 n.posBegin.y, 520 n.size.getWidth(), 521 n.size.getHeight() - chart.componentGapHeight); 522 } 523 if (Grammar.TRACE) { 524 System.out.println("text=" + n.sym.name); 525 System.out.println("n.posBegin.y=" + n.posBegin.y); 526 System.out.println( 527 "chart.getFontHeight()=" + chart.getFontHeight()); 528 System.out.println("n.size=" + n.size.getHeight()); 529 System.out.println( 530 "2=" + +(n.size.getHeight() 531 - chart.componentGapHeight)); 532 System.out.println( 533 "3=" 534 + (n.size.getHeight() - chart.componentGapHeight - chart 535 .getFontHeight()) / 2); 536 } 537 if (false) 538 chart.drawString( 539 n.sym.name, 540 chart.charFont, 541 chart.charColor, 542 p.x 543 + chart.symbolGapWidth, 544 n.posBegin.y 545 + (n.size.getHeight() - chart.componentGapHeight) 546 - chart.symbolGapHeight); 547 chart.drawArrow( 548 p.x, 549 n.posLine.y, 550 p.x, 551 n.posLine.y, 552 Grammar.Direction.RIGHT); 553 p.x += n.size.getWidth(); 554 // draw lines between t and nt nodes 555 if (!n.up && n.next != null 556 && (n.next.typ == NodeType.TERM 557 || n.next.typ == NodeType.NONTERM)) { 558 chart.drawArrow( 559 p.x, 560 n.posLine.y, 561 p.x 562 + chart.componentGapWidth / 2, 563 n.posLine.y, 564 Grammar.Direction.RIGHT); 565 p.x += chart.componentGapWidth / 2; 566 } 567 if (!n.up 568 && n.next != null 569 && n.next.typ == NodeType.WRAP 570 && n.next.size.getHeight() == 0) { 571 chart.drawArrow( 572 p.x, 573 n.posLine.y, 574 p.x 575 + chart.componentGapWidth / 2, 576 n.posLine.y, 577 Grammar.Direction.RIGHT); 578 p.x += chart.componentGapWidth / 2; 579 } 580 break; 581 case EPS: 582 if (chart.showBorders) { 583 chart.drawRectangle( 584 Chart.EPS_COLOR, 585 chart.lineStroke, 586 p.x, 587 n.posBegin.y, 588 n.size.getWidth(), 589 n.size.getHeight()); 590 } 591 592 chart.drawLine( 593 p.x, 594 n.posLine.y, 595 p.x + n.size.getWidth(), 596 n.posLine.y); 597 break; 598 case OPT: 599 if (chart.showBorders) { 600 chart.drawRectangle( 601 Chart.EPS_COLOR, 602 Chart.STROKE1, 603 p.x, 604 n.posBegin.y, 605 n.size.getWidth(), 606 n.size.getHeight()); 607 } 608 609 // the two short lines at the beginning and the end 610 chart.drawLine( 611 p.x, 612 n.posLine.y, 613 p.x + chart.componentGapWidth, 614 n.posLine.y); 615 chart.drawLine( 616 p.x + n.size.getWidth(), 617 n.posLine.y, 618 p.x 619 + n.size.getWidth() 620 - chart.componentGapWidth, 621 n.posLine.y); 622 // the quarter Arcs 623 chart.drawArcCorner( 624 p.x 625 + chart.componentGapWidth / 4 626 - chart.componentArcSize / 2, 627 n.posLine.y, 628 270); 629 chart.drawArcCorner( 630 p.x + chart.componentGapWidth / 4 631 + chart.componentArcSize / 2, 632 n.posEnd.y 633 - chart.componentArcSize 634 - chart.componentGapHeight / 2, 635 90); 636 chart.drawArcCorner( 637 p.x 638 - chart.componentGapWidth / 4 639 - chart.componentArcSize / 2 640 + n.size.getWidth(), 641 n.posLine.y, 642 180); 643 chart.drawArcCorner( 644 p.x 645 - chart.componentGapWidth / 4 646 - chart.componentArcSize * 3 / 2 647 + n.size.getWidth(), 648 n.posEnd.y 649 - chart.componentArcSize 650 - chart.componentGapHeight / 2, 651 0); 652 // the short vertical lines between the quarter Arcs 653 chart.drawLine( 654 p.x 655 + chart.componentGapWidth / 4 656 + chart.componentArcSize / 2, 657 n.posLine.y 658 + chart.componentArcSize / 2, 659 p.x 660 + chart.componentGapWidth / 4 661 + chart.componentArcSize / 2, 662 n.posEnd.y 663 - chart.componentArcSize / 2 664 - chart.componentGapHeight / 2 + 1); 665 chart.drawLine( 666 p.x - chart.componentGapWidth / 4 667 - chart.componentArcSize / 2 668 + n.size.getWidth(), 669 n.posLine.y 670 + chart.componentArcSize / 2, 671 p.x 672 - chart.componentGapWidth / 4 673 - chart.componentArcSize / 2 674 + n.size.getWidth(), 675 n.posEnd.y 676 - chart.componentArcSize / 2 677 - chart.componentGapHeight / 2 + 1); 678 // the the long horizontal line between the quarter Arcs 679 chart.drawLine( 680 p.x + chart.componentGapWidth / 4 681 + chart.componentArcSize, 682 n.posEnd.y 683 - chart.componentGapHeight / 2, 684 p.x 685 - chart.componentGapWidth / 4 686 - chart.componentArcSize 687 + n.size.getWidth() + 1, 688 n.posEnd.y 689 - chart.componentGapHeight / 2); 690 691 n.sub.drawComponents( 692 chart, 693 new Float( 694 p.x + chart.componentGapWidth, 695 0), 696 n.size); 697 p.x += n.size.getWidth(); 698 break; 699 case RERUN: 700 if (n.itergraph == null) { 701 if (chart.showBorders) { 702 chart.drawRectangle( 703 Chart.RERUN_COLOR, 704 Chart.STROKE1, 705 p.x, 706 n.posBegin.y, 707 n.size.getWidth(), 708 n.size.getHeight()); 709 } 710 711 // the two short lines at the beginning and the end 712 chart.drawLine( 713 p.x, 714 n.posLine.y, 715 p.x + chart.componentGapWidth, 716 n.posLine.y); 717 chart.drawLine( 718 p.x + n.size.getWidth(), 719 n.posLine.y, 720 p.x 721 + n.size.getWidth() 722 - chart.componentGapWidth, 723 n.posLine.y); 724 // the quarter Arcs 725 chart.drawArcCorner( 726 p.x 727 + chart.componentGapWidth / 4 728 + chart.componentArcSize / 2, 729 n.posEnd.y 730 - chart.componentGapHeight / 2 731 - chart.componentArcSize, 732 90); 733 chart.drawArcCorner( 734 p.x 735 + chart.componentGapWidth / 4 736 + chart.componentArcSize / 2, 737 n.posLine.y, 738 180); 739 chart.drawArcCorner( 740 p.x 741 - chart.componentGapWidth / 4 742 - chart.componentArcSize * 3 / 2 743 + n.size.getWidth(), 744 n.posEnd.y 745 - chart.componentGapHeight / 2 746 - chart.componentArcSize, 747 0); 748 chart.drawArcCorner( 749 p.x 750 - chart.componentGapWidth / 4 751 - chart.componentArcSize * 3 / 2 752 + n.size.getWidth(), 753 n.posLine.y, 754 270); 755 // the short vertical lines between the quarter Arcs 756 chart.drawLine( 757 p.x 758 + chart.componentGapWidth / 4 759 + chart.componentArcSize / 2, 760 n.posLine.y 761 + chart.componentArcSize / 2, 762 p.x 763 + chart.componentGapWidth / 4 764 + chart.componentArcSize / 2, 765 n.posEnd.y 766 - chart.componentGapHeight / 2 767 - chart.componentArcSize / 2 + 1); 768 chart.drawLine( 769 p.x 770 - chart.componentGapWidth / 4 771 - chart.componentArcSize / 2 772 + n.size.getWidth(), 773 n.posLine.y 774 + chart.componentArcSize / 2, 775 p.x 776 - chart.componentGapWidth / 4 777 - chart.componentArcSize / 2 778 + n.size.getWidth(), 779 n.posEnd.y 780 - chart.componentGapHeight / 2 781 - chart.componentArcSize / 2 + 1); 782 // the the long horizontal line between the quarter Arcs 783 chart.drawLine( 784 p.x 785 + chart.componentGapWidth / 4 786 + chart.componentArcSize - 1, 787 n.posEnd.y 788 - chart.componentGapHeight / 2, 789 p.x 790 - chart.componentGapWidth / 4 791 - chart.componentArcSize 792 + n.size.getWidth() + 1, 793 n.posEnd.y 794 - chart.componentGapHeight / 2); 795 796 n.sub.drawComponents( 797 chart, 798 new Float( 799 p.x + chart.componentGapWidth, 800 0), 801 n.size); 802 p.x += n.size.getWidth(); 803 } else { 804 if (chart.showBorders) { 805 chart.drawRectangle( 806 Chart.RERUN1_COLOR, 807 Chart.STROKE1, 808 p.x, 809 n.posBegin.y, 810 n.size.getWidth(), 811 n.size.getHeight()); 812 } 813 814 // the two short lines at the beginning and the end of the first component 815 chart.drawLine( 816 p.x, 817 n.posLine.y, 818 p.x 819 + n.size.getWidth() / 2 820 - n.altSize.getWidth() / 2 821 - 1, 822 n.posLine.y); 823 chart.drawLine( 824 p.x 825 + n.size.getWidth() / 2 826 + n.altSize.getWidth() / 2 827 + 1, 828 n.posLine.y, 829 p.x 830 + n.size.getWidth(), 831 n.posLine.y); 832 // the quarter Arcs 833 chart.drawArcCorner( 834 p.x 835 + chart.componentGapWidth / 4 836 + chart.componentArcSize / 2, 837 n.itergraph.posLine.y 838 - chart.componentArcSize, 839 90); 840 chart.drawArcCorner( 841 p.x 842 + chart.componentGapWidth / 4 843 + chart.componentArcSize / 2, 844 n.posLine.y, 845 180); 846 chart.drawArcCorner( 847 p.x 848 - chart.componentGapWidth / 4 849 - chart.componentArcSize * 3 / 2 850 + n.size.getWidth(), 851 n.itergraph.posLine.y 852 - chart.componentArcSize, 853 0); 854 chart.drawArcCorner( 855 p.x 856 - chart.componentGapWidth / 4 857 - chart.componentArcSize * 3 / 2 858 + n.size.getWidth(), 859 n.posLine.y, 860 270); 861 // the short vertical lines between the quarter Arcs 862 chart.drawLine( 863 p.x 864 + chart.componentGapWidth / 4 865 + chart.componentArcSize / 2, 866 n.posLine.y 867 + chart.componentArcSize / 2, 868 p.x 869 + chart.componentGapWidth / 4 870 + chart.componentArcSize / 2, 871 n.itergraph.posLine.y 872 - chart.componentArcSize / 2 + 1); 873 chart.drawLine( 874 p.x 875 - chart.componentGapWidth / 4 876 - chart.componentArcSize / 2 877 + n.size.getWidth(), 878 n.posLine.y 879 + chart.componentArcSize / 2, 880 p.x 881 - chart.componentGapWidth / 4 882 - chart.componentArcSize / 2 883 + n.size.getWidth(), 884 n.itergraph.posLine.y 885 - chart.componentArcSize / 2 + 1); 886 // the two short lines at the beginning and the end of the second component 887 chart.drawLine( 888 p.x 889 + chart.componentGapWidth / 4 890 + chart.componentArcSize, 891 n.itergraph.posLine.y, 892 p.x 893 + n.size.getWidth() / 2 894 - n.iterSize.getWidth() / 2 895 - 1, 896 n.itergraph.posLine.y); 897 chart.drawLine( 898 p.x 899 + n.size.getWidth() / 2 900 + n.iterSize.getWidth() / 2 901 + 1, 902 n.itergraph.posLine.y, 903 p.x 904 - chart.componentGapWidth / 4 905 - chart.componentArcSize 906 + n.size.getWidth() 907 + 1, 908 n.itergraph.posLine.y); 909 910 n.itergraph.drawComponentsInverse( 911 chart, 912 new Float( 913 p.x 914 + n.size.getWidth() / 2 915 + n.iterSize.getWidth() / 2, 916 n.posEnd.y), 917 n.size); 918 n.sub.drawComponents( 919 chart, 920 new Float( 921 p.x 922 + n.size.getWidth() / 2 923 - n.altSize.getWidth() / 2, 924 n.posEnd.y), n.size); 925 p.x += n.size.getWidth(); 926 } 927 break; 928 case ITER: 929 if (chart.showBorders) { 930 chart.drawRectangle( 931 Chart.ITER_COLOR, 932 Chart.STROKE1, 933 p.x, 934 n.posBegin.y, 935 n.size.getWidth(), 936 n.size.getHeight()); 937 } 938 939 // the quarter Arcs 940 chart.drawArcCorner( 941 p.x 942 + chart.componentGapWidth / 4 943 + chart.componentArcSize / 2, 944 n.sub.posLine.y 945 - chart.componentArcSize, 946 90); 947 chart.drawArcCorner( 948 p.x 949 + chart.componentGapWidth / 4 950 + chart.componentArcSize / 2, 951 n.posLine.y, 952 180); 953 chart.drawArcCorner( 954 p.x 955 - chart.componentGapWidth / 4 956 - chart.componentArcSize * 3 / 2 957 + n.size.getWidth(), 958 n.sub.posLine.y 959 - chart.componentArcSize, 960 0); 961 chart.drawArcCorner( 962 p.x 963 - chart.componentGapWidth / 4 964 - chart.componentArcSize * 3 / 2 965 + n.size.getWidth(), 966 n.posLine.y, 967 270); 968 // the short vertical lines between the quarter Arcs 969 chart.drawLine( 970 p.x 971 + chart.componentGapWidth / 4 972 + chart.componentArcSize / 2, 973 n.posLine.y 974 + chart.componentArcSize / 2, 975 p.x 976 + chart.componentGapWidth / 4 977 + chart.componentArcSize / 2, 978 n.sub.posLine.y 979 - chart.componentArcSize / 2 + 1); 980 chart.drawLine( 981 p.x 982 - chart.componentGapWidth / 4 983 - chart.componentArcSize / 2 984 + n.size.getWidth(), 985 n.posLine.y 986 + chart.componentArcSize / 2, 987 p.x 988 - chart.componentGapWidth / 4 989 - chart.componentArcSize / 2 990 + n.size.getWidth(), 991 n.sub.posLine.y 992 - chart.componentArcSize / 2 + 1); 993 // the two short horizontal lines between the quater Arcs and the components 994 chart.drawLine( 995 p.x 996 + chart.componentGapWidth / 4 997 + chart.componentArcSize - 1, 998 n.sub.posLine.y, 999 p.x 1000 + chart.componentGapWidth, 1001 n.sub.posLine.y); 1002 chart.drawLine( 1003 p.x 1004 - chart.componentGapWidth 1005 + n.size.getWidth(), 1006 n.sub.posLine.y, 1007 p.x 1008 + n.size.getWidth() 1009 - chart.componentGapWidth / 4 1010 - chart.componentArcSize + 1, 1011 n.sub.posLine.y); 1012 // the long horizontal line in the middle 1013 chart.drawLine( 1014 p.x, 1015 n.posLine.y, 1016 p.x + n.size.getWidth(), 1017 n.posLine.y); 1018 1019 n.sub.drawComponentsInverse( 1020 chart, 1021 new Float( 1022 p.x - chart.componentGapWidth + n.size.getWidth(), 1023 0), 1024 n.size); 1025 p.x += n.size.getWidth(); 1026 break; 1027 case WRAP: 1028 if (n.size.getHeight() != 0 1029 && n.next != null) { 1030 1031 // the short horizontal line after the first component 1032 chart.drawLine( 1033 p.x, n.posLine.y, p.x 1034 + chart.componentGapWidth / 4 + 1, n.posLine.y); 1035 // the short horizontal line at the beginning of the second component 1036 chart.drawLine( 1037 chart.beginningXCoordinate, 1038 n.next.posLine.y, 1039 chart.beginningXCoordinate 1040 - chart.componentGapWidth / 4, 1041 n.next.posLine.y); 1042 // the quarter Arcs 1043 chart.drawArcCorner( 1044 p.x + chart.componentGapWidth / 4 - 1045 chart.componentArcSize / 2, 1046 n.posLine.y, 1047 270); 1048 chart.drawArcCorner( 1049 p.x + chart.componentGapWidth / 4 1050 - chart.componentArcSize / 2, 1051 n.posEnd.y 1052 - chart.componentArcSize, 1053 0); 1054 chart.drawArcCorner( 1055 (float) (chart.beginningXCoordinate 1056 - chart.componentGapWidth / 4 1057 - chart.componentArcSize / 2), 1058 n.posEnd.y, 1059 180); 1060 chart.drawArcCorner( 1061 (float) (chart.beginningXCoordinate 1062 - chart.componentGapWidth / 4 1063 - chart.componentArcSize / 2), 1064 n.next.posLine.y 1065 - chart.componentArcSize, 1066 90); 1067 // the short vertical lines between the quarter Arcs 1068 chart.drawLine( 1069 p.x 1070 + chart.componentGapWidth / 4 1071 + chart.componentArcSize / 2, 1072 n.posLine.y 1073 + chart.componentArcSize / 2, 1074 p.x 1075 + chart.componentGapWidth / 4 1076 + chart.componentArcSize / 2, 1077 n.posEnd.y 1078 - chart.componentArcSize / 2 + 1); 1079 chart.drawLine( 1080 chart.beginningXCoordinate 1081 - chart.componentGapWidth / 4 1082 - chart.componentArcSize / 2, 1083 n.posEnd.y + chart.componentArcSize / 2, 1084 chart.beginningXCoordinate 1085 - chart.componentGapWidth / 4 1086 - chart.componentArcSize / 2, 1087 n.next.posLine.y 1088 - chart.componentArcSize / 2 + 1); 1089 // the long horizontal line in the middle oft the two components 1090 chart.drawLine( 1091 p.x + chart.componentGapWidth / 4 + 1, 1092 n.posEnd.y, 1093 chart.beginningXCoordinate 1094 - chart.componentGapWidth / 4, 1095 n.posEnd.y); 1096 1097 p.x = chart.beginningXCoordinate; 1098 } 1099 break; 1100 case ALT: { 1101 if (chart.showBorders) { 1102 chart.drawRectangle( 1103 Color.RED, 1104 Chart.STROKE1, 1105 p.x, 1106 n.posBegin.y, 1107 n.altSize.getWidth(), 1108 n.altSize.getHeight()); 1109 } 1110 1111 // the two short lines at the beginning and the end of the alt 1112 // component 1113 chart.drawLine( 1114 p.x, 1115 n.posLine.y, 1116 p.x 1117 + chart.componentArcSize * 3 / 2, 1118 n.posLine.y); 1119 chart.drawLine( 1120 p.x + n.altSize.getWidth(), 1121 n.posLine.y, 1122 p.x 1123 + n.altSize.getWidth() 1124 - chart.componentArcSize * 3 / 2, 1125 n.posLine.y); 1126 Node a = n; 1127 boolean first = true; 1128 while (a != null) { 1129 // the horizontal lines at the beginning and the end 1130 chart.drawLine( 1131 p.x 1132 + chart.componentArcSize * 3 / 2, 1133 a.sub.posLine.y, 1134 p.x 1135 + (n.altSize.getWidth() - a.size.getWidth()) / 2, 1136 a.sub.posLine.y); 1137 chart.drawLine( 1138 p.x 1139 - chart.componentArcSize * 3 / 2 1140 + n.altSize.getWidth() 1141 + 1, 1142 a.sub.posLine.y, 1143 p.x 1144 + (n.altSize.getWidth() - a.size.getWidth()) / 2 1145 + a.size.getWidth(), 1146 a.sub.posLine.y); 1147 // the first alternative draws different arcs 1148 if (first) { 1149 chart.drawArcCorner( 1150 p.x, 1151 n.posLine.y, 1152 270); 1153 chart.drawArcCorner( 1154 p.x 1155 + n.altSize.getWidth() 1156 - chart.componentArcSize, 1157 n.posLine.y, 1158 180); 1159 first = false; 1160 } else { 1161 // else draw other arcs and vertical lines 1162 chart.drawArcCorner( 1163 p.x + chart.componentArcSize, 1164 a.sub.posLine.y 1165 - chart.componentArcSize, 1166 90); 1167 chart.drawLine( 1168 p.x + chart.componentArcSize, 1169 n.posLine.y 1170 + chart.componentArcSize / 2, 1171 p.x 1172 + chart.componentArcSize, 1173 a.posLine.y 1174 - chart.componentArcSize / 2 + 1); 1175 chart.drawArcCorner( 1176 p.x 1177 - chart.componentArcSize * 2 1178 + n.altSize.getWidth(), 1179 a.sub.posLine.y 1180 - chart.componentArcSize, 1181 0); 1182 chart.drawLine( 1183 p.x 1184 - chart.componentArcSize 1185 + n.altSize.getWidth(), 1186 n.posLine.y 1187 + chart.componentArcSize / 2, 1188 p.x 1189 - chart.componentArcSize 1190 + n.altSize.getWidth(), 1191 a.posLine.y 1192 - chart.componentArcSize / 2 + 1); 1193 } 1194 a.sub.drawComponents( 1195 chart, 1196 new Float( 1197 p.x 1198 + (n.altSize.getWidth() - a.size.getWidth()) 1199 / 2, a.posEnd.y), a.size); 1200 a = a.down; 1201 } 1202 p.x += n.altSize.getWidth(); 1203 } 1204 break; 1205 } 1206 1207 if (n.up) { 1208 samelevel = false; 1209 } 1210 if (n.next == null && firstLevel) { 1211 chart.drawLine( 1212 p.x, 1213 n.posLine.y, 1214 p.x 1215 + chart.componentGapWidth / 4, 1216 n.posLine.y); 1217 chart.drawArrow( 1218 p.x 1219 + chart.componentGapWidth / 4 1220 + chart.arrowSize, 1221 n.posLine.y, 1222 p.x 1223 + chart.componentGapWidth / 4 1224 + chart.arrowSize, 1225 n.posLine.y, 1226 Grammar.Direction.RIGHT); 1227 } 1228 n = n.next; 1229 } 1230 } 1231 1232 /* 1233 * Draw the components from right to left. 1234 * Needed if for example in an iter-node. 1235 */ 1236 void drawComponentsInverse( 1237 Chart chart, Float p, Size s) 1238 { 1239 Node n = this; //current node in the level 1240 boolean samelevel = true; //next node in same level? 1241 Float p1 = new Float(0, 0); 1242 1243 while (n != null && samelevel) { 1244 p.x -= n.size.getWidth(); 1245 if (n.typ == NodeType.TERM || n.typ == NodeType.NONTERM) { 1246 if (chart.showBorders) { 1247 chart.drawRectangle( 1248 Chart.N_NT_COLOR, 1249 Chart.STROKE1, 1250 p.x, 1251 n.posBegin.y - chart.componentGapHeight / 2, 1252 n.size.getWidth(), 1253 n.size.getHeight()); 1254 } 1255 if (n.typ == NodeType.TERM) { 1256 // the quarter Arcs 1257 final float foo = 1258 (n.size.getHeight() - chart.componentGapHeight) / 2; 1259 chart.drawArc( 1260 chart.lineStroke, 1261 chart.lineColor, 1262 p.x, 1263 n.posBegin.y, 1264 foo, 1265 foo, 1266 180, 1267 90); 1268 chart.drawArc( 1269 chart.lineStroke, 1270 chart.lineColor, 1271 p.x, 1272 n.posLine.y, 1273 foo, 1274 foo, 1275 90, 1276 90); 1277 chart.drawArc( 1278 chart.lineStroke, 1279 chart.lineColor, 1280 p.x + n.size.getWidth() - foo, 1281 n.posBegin.y, 1282 foo, 1283 foo, 1284 270, 1285 90); 1286 chart.drawArc( 1287 chart.lineStroke, 1288 chart.lineColor, 1289 p.x + n.size.getWidth() - foo, 1290 n.posLine.y, 1291 foo, 1292 foo, 1293 0, 1294 90); 1295 // the short vertical and horizontal lines between the quarter Arcs 1296 chart.drawLine( 1297 p.x 1298 + (n.size.getHeight() - chart.componentGapHeight) / 4 1299 - 1, n.posBegin.y, p.x 1300 + n.size.getWidth() 1301 - (n.size.getHeight() - chart.componentGapHeight) / 4 1302 + 1, n.posBegin.y); 1303 chart.drawLine( 1304 p.x 1305 + (n.size.getHeight() - chart.componentGapHeight) / 4 1306 - 1, n.posEnd.y, p.x 1307 + n.size.getWidth() 1308 - (n.size.getHeight() - chart.componentGapHeight) / 4 1309 + 1, n.posEnd.y); 1310 chart.drawLine( 1311 p.x, 1312 n.posLine.y 1313 + (n.size.getHeight() - chart.componentGapHeight) / 4 1314 + 1, p.x, 1315 n.posLine.y 1316 - (n.size.getHeight() - chart.componentGapHeight) / 4 1317 - 1); 1318 chart.drawLine( 1319 p.x + n.size.getWidth(), 1320 n.posLine.y 1321 + (n.size.getHeight() - chart.componentGapHeight) 1322 / 4 + 1, 1323 p.x + n.size.getWidth(), 1324 n.posLine.y 1325 - (n.size.getHeight() - chart.componentGapHeight) 1326 / 4 - 1); 1327 } else { 1328 n.posBegin.x = p.x; 1329 n.posEnd.x = p.x + n.size.getWidth(); 1330 chart.drawRectangle( 1331 chart.lineColor, 1332 chart.lineStroke, 1333 n.posBegin.x, 1334 n.posBegin.y, 1335 n.size.getWidth(), 1336 (n.size.getHeight() - chart.componentGapHeight)); 1337 } 1338 // StringFormat drawFormat = new StringFormat(); 1339 // drawFormat.setAlignment(StringAlignment.Center); 1340 // drawFormat.setLineAlignment(StringAlignment.Center); 1341 // DrawString(n.sym.name , charFont , charColor , new Rectangle((int)p.x,(int)n.posBegin.y,n.size.getWidth(),n.size.getHeight()-componentGapHeight-2),drawFormat); 1342 chart.drawString( 1343 n.sym.name, 1344 chart.charFont, 1345 chart.charColor, 1346 p.x 1347 + chart.symbolGapWidth, 1348 n.posBegin.y 1349 + (n.size.getHeight() - chart.componentGapHeight) 1350 - chart.symbolGapHeight); 1351 chart.drawArrow( 1352 p.x + n.size.getWidth(), 1353 n.posLine.y, 1354 p.x + n.size.getWidth(), 1355 n.posLine.y, 1356 Grammar.Direction.LEFT); 1357 1358 if (!n.up 1359 && n.next != null 1360 && (n.next.typ == NodeType.TERM 1361 || n.next.typ == NodeType.NONTERM)) 1362 { 1363 chart.drawArrow( 1364 p.x, 1365 n.posLine.y, 1366 p.x - chart.componentGapWidth / 2, 1367 n.posLine.y, 1368 Grammar.Direction.LEFT); 1369 p.x -= chart.componentGapWidth / 2; 1370 } 1371 if (!n.up 1372 && n.next != null 1373 && n.next.typ == NodeType.WRAP 1374 && n.next.size.getHeight() == 0) 1375 { 1376 if (!n.next.up 1377 && n.next.next != null 1378 && (n.next.next.typ == NodeType.TERM 1379 || n.next.next.typ == NodeType.NONTERM)) 1380 { 1381 chart.drawArrow( 1382 p.x, 1383 n.posLine.y, 1384 p.x 1385 - chart.componentGapWidth / 2, 1386 n.posLine.y, 1387 Grammar.Direction.LEFT); 1388 p.x -= chart.componentGapWidth / 2; 1389 } 1390 } 1391 } else if (n.typ == NodeType.EPS) { 1392 if (chart.showBorders) { 1393 chart.drawRectangle( 1394 Chart.EPS_COLOR, 1395 Chart.STROKE1, 1396 p.x, 1397 n.posBegin.y, 1398 n.size.getWidth(), 1399 n.size.getHeight()); 1400 } 1401 1402 chart.drawLine( 1403 p.x, 1404 n.posLine.y, 1405 p.x + n.size.getWidth(), 1406 n.posLine.y); 1407 } else if (n.typ == NodeType.OPT) { 1408 if (chart.showBorders) { 1409 chart.drawRectangle( 1410 Chart.OPT_COLOR, 1411 Chart.STROKE1, 1412 p.x, 1413 n.posBegin.y, 1414 n.size.getWidth(), 1415 n.size.getHeight()); 1416 } 1417 1418 // the two short lines at the beginning and the end 1419 chart.drawLine( 1420 p.x, 1421 n.posLine.y, 1422 p.x + chart.componentGapWidth, 1423 n.posLine.y); 1424 chart.drawLine( 1425 p.x + n.size.getWidth(), 1426 n.posLine.y, 1427 p.x 1428 + n.size.getWidth() - chart.componentGapWidth, 1429 n.posLine.y); 1430 // the quarter Arcs 1431 chart.drawArcCorner( 1432 p.x 1433 + chart.componentGapWidth / 4 1434 - chart.componentArcSize / 2, 1435 n.posLine.y, 1436 270); 1437 chart.drawArcCorner( 1438 p.x 1439 + chart.componentGapWidth / 4 1440 + chart.componentArcSize / 2, 1441 n.posEnd.y 1442 - chart.componentArcSize 1443 - chart.componentGapHeight / 2, 1444 90); 1445 chart.drawArcCorner( 1446 p.x 1447 - chart.componentGapWidth / 4 1448 - chart.componentArcSize / 2 1449 + n.size.getWidth(), 1450 n.posLine.y, 1451 180); 1452 chart.drawArcCorner( 1453 p.x 1454 - chart.componentGapWidth / 4 1455 - chart.componentArcSize * 3 / 2 1456 + n.size.getWidth(), 1457 n.posEnd.y 1458 - chart.componentArcSize 1459 - chart.componentGapHeight / 2, 1460 0); 1461 // the short vertical lines between the quarter Arcs 1462 chart.drawLine( 1463 p.x 1464 + chart.componentGapWidth / 4 1465 + chart.componentArcSize / 2, 1466 n.posLine.y 1467 + chart.componentArcSize / 2, 1468 p.x 1469 + chart.componentGapWidth / 4 1470 + chart.componentArcSize / 2, 1471 n.posEnd.y 1472 - chart.componentArcSize / 2 1473 - chart.componentGapHeight / 2 + 1); 1474 chart.drawLine( 1475 p.x 1476 - chart.componentGapWidth / 4 1477 - chart.componentArcSize / 2 1478 + n.size.getWidth(), 1479 n.posLine.y 1480 + chart.componentArcSize / 2, 1481 p.x 1482 - chart.componentGapWidth / 4 1483 - chart.componentArcSize / 2 1484 + n.size.getWidth(), 1485 n.posEnd.y 1486 - chart.componentArcSize / 2 1487 - chart.componentGapHeight / 2 + 1); 1488 // the the long horizontal line between the quarter Arcs 1489 chart.drawLine( 1490 p.x 1491 + chart.componentGapWidth / 4 1492 + chart.componentArcSize, 1493 n.posEnd.y 1494 - chart.componentGapHeight / 2, 1495 p.x 1496 - chart.componentGapWidth / 4 1497 - chart.componentArcSize 1498 + n.size.getWidth() + 1, 1499 n.posEnd.y 1500 - chart.componentGapHeight / 2); 1501 1502 p1.x = p.x + n.size.getWidth() - chart.componentGapWidth; 1503 n.sub.drawComponentsInverse(chart, p1, n.size); 1504 } else if (n.typ == NodeType.RERUN && n.itergraph == null) { 1505 if (chart.showBorders) { 1506 chart.drawRectangle( 1507 Chart.RERUN_COLOR, 1508 Chart.STROKE1, 1509 p.x, 1510 n.posBegin.y, 1511 n.size.getWidth(), 1512 n.size.getHeight()); 1513 } 1514 1515 // the two short lines at the beginning and the end 1516 chart.drawLine( 1517 p.x, 1518 n.posLine.y, 1519 p.x + chart.componentGapWidth, 1520 n.posLine.y); 1521 chart.drawLine( 1522 p.x + n.size.getWidth(), 1523 n.posLine.y, 1524 p.x 1525 + n.size.getWidth() - chart.componentGapWidth, 1526 n.posLine.y); 1527 // the quarter Arcs 1528 chart.drawArcCorner( 1529 p.x 1530 + chart.componentGapWidth / 4 1531 + chart.componentArcSize / 2, 1532 n.posEnd.y 1533 - chart.componentGapHeight / 2 1534 - chart.componentArcSize, 1535 90); 1536 chart.drawArcCorner( 1537 p.x 1538 + chart.componentGapWidth / 4 1539 + chart.componentArcSize / 2, 1540 n.posLine.y, 1541 180); 1542 chart.drawArcCorner( 1543 p.x 1544 - chart.componentGapWidth / 4 1545 - chart.componentArcSize * 3 / 2 1546 + n.size.getWidth(), 1547 n.posEnd.y 1548 - chart.componentGapHeight / 2 1549 - chart.componentArcSize, 1550 0); 1551 chart.drawArcCorner( 1552 p.x 1553 - chart.componentGapWidth / 4 1554 - chart.componentArcSize * 3 / 2 1555 + n.size.getWidth(), 1556 n.posLine.y, 1557 270); 1558 // the short vertical lines between the quarter Arcs 1559 chart.drawLine( 1560 p.x 1561 + chart.componentGapWidth / 4 1562 + chart.componentArcSize / 2, 1563 n.posLine.y 1564 + chart.componentArcSize / 2, 1565 p.x 1566 + chart.componentGapWidth / 4 1567 + chart.componentArcSize / 2, 1568 n.posEnd.y 1569 - chart.componentGapHeight / 2 1570 - chart.componentArcSize / 2 + 1); 1571 chart.drawLine( 1572 p.x 1573 - chart.componentGapWidth / 4 1574 - chart.componentArcSize / 2 1575 + n.size.getWidth(), 1576 n.posLine.y 1577 + chart.componentArcSize / 2, 1578 p.x 1579 - chart.componentGapWidth / 4 1580 - chart.componentArcSize / 2 1581 + n.size.getWidth(), 1582 n.posEnd.y 1583 - chart.componentGapHeight / 2 1584 - chart.componentArcSize / 2 + 1); 1585 // the the long horizontal line between the quarter Arcs 1586 chart.drawLine( 1587 p.x 1588 + chart.componentGapWidth / 4 1589 + chart.componentArcSize - 1, 1590 n.posEnd.y 1591 - chart.componentGapHeight / 2, 1592 p.x 1593 - chart.componentGapWidth / 4 1594 - chart.componentArcSize 1595 + n.size.getWidth() + 1, 1596 n.posEnd.y 1597 - chart.componentGapHeight / 2); 1598 1599 p1.x = p.x + n.size.getWidth() - chart.componentGapWidth; 1600 n.sub.drawComponentsInverse(chart, p1, n.size); 1601 } else if (n.typ == NodeType.RERUN && n.itergraph != null) { 1602 if (chart.showBorders) { 1603 chart.drawRectangle( 1604 Chart.RERUN1_COLOR, 1605 Chart.STROKE1, 1606 p.x, 1607 n.posBegin.y, 1608 n.size.getWidth(), 1609 n.size.getHeight()); 1610 } 1611 1612 // the two short lines at the beginning and the end of the first component 1613 chart.drawLine( 1614 p.x, 1615 n.posLine.y, 1616 p.x 1617 + n.size.getWidth() / 2 1618 - n.altSize.getWidth() / 2 - 1, 1619 n.posLine.y); 1620 chart.drawLine( 1621 p.x 1622 + n.size.getWidth() / 2 1623 + n.altSize.getWidth() / 2 + 1, 1624 n.posLine.y, 1625 p.x 1626 + n.size.getWidth(), 1627 n.posLine.y); 1628 // the quarter Arcs 1629 chart.drawArcCorner( 1630 p.x 1631 + chart.componentGapWidth / 4 1632 + chart.componentArcSize / 2, 1633 n.itergraph.posLine.y 1634 - chart.componentArcSize, 1635 90); 1636 chart.drawArcCorner( 1637 p.x 1638 + chart.componentGapWidth / 4 1639 + chart.componentArcSize / 2, 1640 n.posLine.y, 1641 180); 1642 chart.drawArcCorner( 1643 p.x 1644 - chart.componentGapWidth / 4 1645 - chart.componentArcSize * 3 / 2 1646 + n.size.getWidth(), 1647 n.itergraph.posLine.y 1648 - chart.componentArcSize, 1649 0); 1650 chart.drawArcCorner( 1651 p.x 1652 - chart.componentGapWidth / 4 1653 - chart.componentArcSize * 3 / 2 1654 + n.size.getWidth(), 1655 n.posLine.y, 1656 270); 1657 // the short vertical lines between the quarter Arcs 1658 chart.drawLine( 1659 p.x 1660 + chart.componentGapWidth / 4 1661 + chart.componentArcSize / 2, 1662 n.posLine.y 1663 + chart.componentArcSize / 2, 1664 p.x 1665 + chart.componentGapWidth / 4 1666 + chart.componentArcSize / 2, 1667 n.itergraph.posLine.y 1668 - chart.componentArcSize / 2 + 1); 1669 chart.drawLine( 1670 p.x 1671 - chart.componentGapWidth / 4 1672 - chart.componentArcSize / 2 1673 + n.size.getWidth(), 1674 n.posLine.y 1675 + chart.componentArcSize / 2, 1676 p.x 1677 - chart.componentGapWidth / 4 1678 - chart.componentArcSize / 2 1679 + n.size.getWidth(), 1680 n.itergraph.posLine.y 1681 - chart.componentArcSize / 2 + 1); 1682 // the two short lines at the beginning and the end of the second component 1683 chart.drawLine( 1684 p.x 1685 + chart.componentGapWidth / 4 1686 + chart.componentArcSize, 1687 n.itergraph.posLine.y, 1688 p.x 1689 + n.size.getWidth() / 2 1690 - n.iterSize.getWidth() / 2 1691 - 1, 1692 n.itergraph.posLine.y); 1693 chart.drawLine( 1694 p.x 1695 + n.size.getWidth() / 2 1696 + n.iterSize.getWidth() / 2 1697 + 1, 1698 n.itergraph.posLine.y, 1699 p.x 1700 - chart.componentGapWidth / 4 1701 - chart.componentArcSize 1702 + n.size.getWidth() + 1, 1703 n.itergraph.posLine.y); 1704 1705 n.sub.drawComponentsInverse( 1706 chart, 1707 new Float( 1708 p.x 1709 + n.size.getWidth() / 2 + n.altSize.getWidth() / 2, 1710 n.posEnd.y), 1711 n.size); 1712 n.itergraph.drawComponents( 1713 chart, 1714 new Float( 1715 p.x + n.size.getWidth() / 2 1716 - n.iterSize.getWidth() / 2, 1717 n.posEnd.y), 1718 n.size); 1719 } else if (n.typ == NodeType.ITER) { 1720 if (chart.showBorders) { 1721 chart.drawRectangle( 1722 Chart.ITER_COLOR, 1723 Chart.STROKE1, 1724 p.x, 1725 n.posBegin.y, 1726 n.size.getWidth(), 1727 n.size.getHeight()); 1728 } 1729 1730 // the quarter Arcs 1731 chart.drawArcCorner( 1732 p.x 1733 + chart.componentGapWidth / 4 1734 + chart.componentArcSize / 2, 1735 n.sub.posLine.y 1736 - chart.componentArcSize, 1737 90); 1738 chart.drawArcCorner( 1739 p.x 1740 + chart.componentGapWidth / 4 1741 + chart.componentArcSize / 2, 1742 n.posLine.y, 1743 180); 1744 chart.drawArcCorner( 1745 p.x 1746 - chart.componentGapWidth / 4 1747 - chart.componentArcSize * 3 / 2 1748 + n.size.getWidth(), 1749 n.sub.posLine.y 1750 - chart.componentArcSize, 1751 0); 1752 chart.drawArcCorner( 1753 p.x 1754 - chart.componentGapWidth / 4 1755 - chart.componentArcSize * 3 / 2 1756 + n.size.getWidth(), 1757 n.posLine.y, 1758 270); 1759 // the short vertical lines between the quarter Arcs 1760 chart.drawLine( 1761 p.x 1762 + chart.componentGapWidth / 4 1763 + chart.componentArcSize / 2, 1764 n.posLine.y 1765 + chart.componentArcSize / 2, 1766 p.x 1767 + chart.componentGapWidth / 4 1768 + chart.componentArcSize / 2, 1769 n.sub.posLine.y 1770 - chart.componentArcSize / 2 + 1); 1771 chart.drawLine( 1772 p.x 1773 - chart.componentGapWidth / 4 1774 - chart.componentArcSize / 2 1775 + n.size.getWidth(), 1776 n.posLine.y 1777 + chart.componentArcSize / 2, 1778 p.x 1779 - chart.componentGapWidth / 4 1780 - chart.componentArcSize / 2 1781 + n.size.getWidth(), 1782 n.sub.posLine.y 1783 - chart.componentArcSize / 2 + 1); 1784 // the two short horizontal lines between the quater Arcs and the components 1785 chart.drawLine( 1786 p.x 1787 + chart.componentGapWidth / 4 1788 + chart.componentArcSize - 1, 1789 n.sub.posLine.y, 1790 p.x 1791 + chart.componentGapWidth, 1792 n.sub.posLine.y); 1793 chart.drawLine( 1794 p.x 1795 - chart.componentGapWidth 1796 + n.size.getWidth(), 1797 n.sub.posLine.y, 1798 p.x 1799 + n.size.getWidth() 1800 - chart.componentGapWidth / 4 1801 - chart.componentArcSize + 1, 1802 n.sub.posLine.y); 1803 // the long horizontal line in the middle 1804 chart.drawLine( 1805 p.x, 1806 n.posLine.y, 1807 p.x + n.size.getWidth(), 1808 n.posLine.y); 1809 1810 p1.x = p.x + chart.componentGapWidth; 1811 n.sub.drawComponents(chart, p1, n.size); 1812 } else if (n.typ == NodeType.ALT) { 1813 p.x -= n.altSize.getWidth() - n.size.getWidth(); 1814 if (chart.showBorders) { 1815 chart.drawRectangle( 1816 Color.RED, 1817 Chart.STROKE1, 1818 p.x, 1819 n.posBegin.y, 1820 n.altSize.getWidth(), 1821 n.altSize.getHeight()); 1822 } 1823 1824 // the two short lines at the beginning and the end of the altcomponent 1825 chart.drawLine( 1826 p.x, 1827 n.posLine.y, 1828 p.x 1829 + chart.componentArcSize * 3 / 2, 1830 n.posLine.y); 1831 chart.drawLine( 1832 p.x 1833 + n.altSize.getWidth(), 1834 n.posLine.y, 1835 p.x 1836 + n.altSize.getWidth() 1837 - chart.componentArcSize * 3 / 2, 1838 n.posLine.y); 1839 p1.x = p.x + 2 * chart.componentGapWidth; 1840 p1.y = p1.y + chart.componentGapHeight; 1841 Node a = n; 1842 boolean first = true; 1843 while (a != null) { 1844 1845 // the horizontal lines at the beginning and the end 1846 chart.drawLine( 1847 p.x + chart.componentArcSize * 3 / 2, 1848 a.sub.posLine.y, 1849 p.x 1850 + (n.altSize.getWidth() - a.size.getWidth()) / 2, 1851 a.sub.posLine.y); 1852 chart.drawLine( 1853 p.x 1854 - chart.componentArcSize * 3 / 2 1855 + n.altSize.getWidth() 1856 + 1, 1857 a.sub.posLine.y, 1858 p.x 1859 + (n.altSize.getWidth() - a.size.getWidth()) / 2 1860 + a.size.getWidth(), 1861 a.sub.posLine.y); 1862 // if the first Alternative draw differnt Arcs 1863 if (first) { 1864 chart.drawArcCorner( 1865 p.x, 1866 n.posLine.y, 1867 270); 1868 chart.drawArcCorner( 1869 p.x 1870 + n.altSize.getWidth() 1871 - chart.componentArcSize, 1872 n.posLine.y, 1873 180); 1874 first = false; 1875 } else { 1876 // else draw other Arcs and vertical lines 1877 chart.drawArcCorner( 1878 p.x + chart.componentArcSize, 1879 a.sub.posLine.y 1880 - chart.componentArcSize, 1881 90); 1882 chart.drawLine( 1883 p.x + chart.componentArcSize, 1884 n.posLine.y 1885 + chart.componentArcSize / 2, 1886 p.x 1887 + chart.componentArcSize, 1888 a.posLine.y 1889 - chart.componentArcSize / 2 + 1); 1890 chart.drawArcCorner( 1891 p.x 1892 - chart.componentArcSize * 2 1893 + n.altSize.getWidth(), 1894 a.sub.posLine.y 1895 - chart.componentArcSize, 1896 0); 1897 chart.drawLine( 1898 p.x 1899 - chart.componentArcSize 1900 + n.altSize.getWidth(), 1901 n.posLine.y 1902 + chart.componentArcSize / 2, 1903 p.x 1904 - chart.componentArcSize 1905 + n.altSize.getWidth(), 1906 a.posLine.y 1907 - chart.componentArcSize / 2 + 1); 1908 } 1909 Float pf = new Float( 1910 p.x 1911 + (n.altSize.getWidth() + a.size.getWidth()) / 2, 1912 p1.y); 1913 a.sub.drawComponentsInverse(chart, pf, a.size); 1914 a = a.down; 1915 } 1916 } 1917 if (n.up) { 1918 samelevel = false; 1919 } 1920 n = n.next; 1921 } 1922 } 1923 1924 public void accept(Chart.NodeVisitor nodeVisitor) { 1925 nodeVisitor.visit(this); 1926 } 1927 1928 public void visitChildren(Chart.NodeVisitor visitor) { 1929 switch (typ) { 1930 case TERM: 1931 case NONTERM: 1932 break; 1933 case ALT: 1934 final List<Node> alts = new ArrayList<Node>(); 1935 for (Node n = this; n != null; n = n.down) { 1936 n.sub.accept(visitor); 1937 } 1938 break; 1939 case ITER: 1940 for (Node node : nextChildren(sub)) { 1941 node.accept(visitor); 1942 } 1943 break; 1944 default: 1945 throw new RuntimeException("unknown <" + typ + ">"); 1946 } 1947 } 1948 } 1949 1950 // End Node.java