001    /*
002     * Copyright (C) 2012 eXo Platform SAS.
003     *
004     * This is free software; you can redistribute it and/or modify it
005     * under the terms of the GNU Lesser General Public License as
006     * published by the Free Software Foundation; either version 2.1 of
007     * the License, or (at your option) any later version.
008     *
009     * This software is distributed in the hope that it will be useful,
010     * but WITHOUT ANY WARRANTY; without even the implied warranty of
011     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012     * Lesser General Public License for more details.
013     *
014     * You should have received a copy of the GNU Lesser General Public
015     * License along with this software; if not, write to the Free
016     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
017     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
018     */
019    
020    package org.crsh.text.ui;
021    
022    import org.crsh.text.LineReader;
023    import org.crsh.text.RenderAppendable;
024    
025    class TableRowReader implements LineReader {
026    
027      /** . */
028      private final TableRowLineRenderer renderer;
029    
030      /** . */
031      private final int[] widths;
032    
033      /** . */
034      private final RowLineRenderer row;
035    
036      /** . */
037      private LineReader reader;
038    
039      /** . */
040      private TableRowReader previous;
041    
042      /** . */
043      private TableRowReader next;
044    
045      /** . */
046      private BorderStyle top;
047    
048      /** . */
049      private BorderStyle bottom;
050    
051      /** . */
052      private final int height;
053    
054      /**
055       * 0 -> render top
056       * 1 -> render cells
057       * 2 -> render bottom
058       * 3 -> done
059       */
060      private int status;
061    
062      TableRowReader(TableRowLineRenderer renderer, RowLineRenderer row, int[] widths, int height) {
063    
064        //
065        this.renderer = renderer;
066        this.row = row;
067        this.widths = widths;
068        this.reader = null;
069        this.top = null;
070        this.bottom = null;
071        this.height = height;
072        this.status = 1;
073      }
074    
075      TableRowReader add(TableRowReader next) {
076        next.previous = this;
077        this.next = next;
078        bottom = renderer.header ? (renderer.table.separator != null ? renderer.table.separator : BorderStyle.DASHED) : null;
079        next.top = next.renderer.header && !renderer.header ? (next.renderer.table.separator != null ? next.renderer.table.separator : BorderStyle.DASHED) : null;
080        next.status = next.top != null ? 0 : 1;
081        return next;
082      }
083    
084      TableRowReader previous() {
085        return previous;
086      }
087    
088      TableRowReader next() {
089        return next;
090      }
091    
092      boolean hasTop() {
093        return renderer.header && previous != null;
094      }
095    
096      boolean hasBottom() {
097        return renderer.header && next != null && !next.renderer.header;
098      }
099    
100      boolean isSeparator() {
101        return status == 0 || status == 2;
102      }
103    
104      public boolean hasLine() {
105        return 0 <= status && status <= 2;
106      }
107    
108      public void renderLine(RenderAppendable to) throws IllegalStateException {
109        if (!hasLine()) {
110          throw new IllegalStateException();
111        }
112        switch (status) {
113          case 0:
114          case 2: {
115            BorderStyle b = status == 0 ? top : bottom;
116            to.styleOff();
117            for (int i = 0;i < widths.length;i++) {
118              if (i > 0 && renderer.table.separator != null) {
119                to.append(b.horizontal);
120              }
121              for (int j = 0;j < widths[i];j++) {
122                to.append(b.horizontal);
123              }
124            }
125            to.styleOn();
126            status++;
127            break;
128          }
129          case 1: {
130    
131            //
132            if (reader == null) {
133              if (height > 0 && renderer.table.overflow == Overflow.WRAP) {
134                int h = height;
135                if (hasTop()) {
136                  h--;
137                }
138                if (hasBottom()) {
139                  h--;
140                }
141                reader = row.renderer(widths, h);
142              } else {
143                reader = row.renderer(widths, -1);
144              }
145            }
146    
147            //
148            reader.renderLine(to);
149    
150            //
151            if (renderer.table.overflow == Overflow.HIDDEN) {
152              status = bottom != null ? 2 : 3;
153            } else {
154              if (!reader.hasLine()) {
155                status = bottom != null ? 2 : 3;
156              }
157            }
158    
159            //
160            break;
161          }
162          default:
163            throw new AssertionError();
164        }
165      }
166    }