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