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