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
020package org.crsh.text.ui;
021
022import org.crsh.text.LineReader;
023import org.crsh.text.LineRenderer;
024import org.crsh.text.RenderAppendable;
025import org.crsh.text.Style;
026
027import java.util.ArrayList;
028import java.util.Arrays;
029import java.util.List;
030
031class RowLineRenderer extends LineRenderer {
032
033  /** . */
034  private final List<LineRenderer> cols;
035
036  /** . */
037  private final Style.Composite style;
038
039  /** . */
040  final int leftCellPadding;
041
042  /** . */
043  final int rightCellPadding;
044
045  /** . */
046  private final BorderStyle separator;
047
048  RowLineRenderer(RowElement row, BorderStyle separator, int leftCellPadding, int rightCellPadding) {
049
050    List<LineRenderer> cols = new ArrayList<LineRenderer>(row.cols.size());
051    for (Element col : row.cols) {
052      cols.add(col.renderer());
053    }
054
055    //
056    this.cols = cols;
057    this.style = row.getStyle();
058    this.separator = separator;
059    this.leftCellPadding = leftCellPadding;
060    this.rightCellPadding = rightCellPadding;
061  }
062
063  int getSize() {
064    return cols.size();
065  }
066
067  public List<LineRenderer> getCols() {
068    return cols;
069  }
070
071  @Override
072  public int getActualWidth() {
073    int actualWidth = 0;
074    for (int i = 0;i < cols.size();i++) {
075      LineRenderer col = cols.get(i);
076      actualWidth += col.getActualWidth();
077      actualWidth += leftCellPadding;
078      actualWidth += rightCellPadding;
079      if (separator != null && i > 0) {
080        actualWidth++;
081      }
082    }
083    return actualWidth;
084  }
085
086  @Override
087  public int getMinWidth() {
088    int minWidth = 0;
089    for (int i = 0;i < cols.size();i++) {
090      LineRenderer col = cols.get(i);
091      minWidth += col.getMinWidth();
092      minWidth += leftCellPadding;
093      minWidth += rightCellPadding;
094      if (separator != null && i > 0) {
095        minWidth++;
096      }
097    }
098    return minWidth;
099  }
100
101  @Override
102  public int getActualHeight(int width) {
103    int actualHeight = 0;
104    for (LineRenderer col : cols) {
105      actualHeight = Math.max(actualHeight, col.getActualHeight(width));
106    }
107    return actualHeight;
108  }
109
110  @Override
111  public int getMinHeight(int width) {
112    int minHeight = 0;
113    for (LineRenderer col : cols) {
114      minHeight = Math.max(minHeight, col.getMinHeight(width));
115    }
116    return minHeight;
117  }
118
119  // todo look at :
120  // if (i > 0) {
121  // to.append(b.horizontal);
122  // }
123  // in relation to widths array that can contain (should?) 0 value
124  LineReader renderer(final int[] widths, int height) {
125    final LineReader[] readers = new LineReader[widths.length];
126    for (int i = 0;i < readers.length;i++) {
127      LineRenderer renderer = cols.get(i);
128      LineReader reader = renderer.reader(widths[i] - leftCellPadding - rightCellPadding, height);
129      readers[i] = reader;
130    }
131
132    //
133    return new LineReader() {
134
135      /** . */
136      private boolean done = false;
137
138      public boolean hasLine() {
139        return !done;
140      }
141
142      public void renderLine(RenderAppendable to) {
143        if (!hasLine()) {
144          throw new IllegalStateException();
145        }
146
147        //
148        if (style != null) {
149          to.enterStyle(style);
150        }
151
152        //
153        for (int i = 0;i < readers.length;i++) {
154          LineReader reader = readers[i];
155
156          //
157          if (i > 0) {
158            if (separator != null) {
159              to.styleOff();
160              to.append(separator.vertical);
161              to.styleOn();
162            }
163          }
164          if (reader != null && reader.hasLine()) {
165            // Left padding
166            if (leftCellPadding > 0) {
167              for (int j = 0;j < leftCellPadding;j++) {
168                to.append(' ');
169              }
170            }
171            reader.renderLine(to);
172            // Right padding
173            if (rightCellPadding > 0) {
174              for (int j = 0;j < rightCellPadding;j++) {
175                to.append(' ');
176              }
177            }
178          } else {
179            readers[i] = null;
180            for (int j = widths[i];j > 0;j--) {
181              to.append(' ');
182            }
183          }
184        }
185
186        //
187        if (style != null) {
188          to.leaveStyle();
189        }
190
191
192        // Update status
193        done = true;
194        for (LineReader reader : readers) {
195          if (reader != null) {
196            if (reader.hasLine()) {
197              done = false;
198              break;
199            }
200          }
201        }
202      }
203    };
204  }
205
206  @Override
207  public LineReader reader(int width) {
208    int[] widths = new int[cols.size()];
209    int[] minWidths = new int[cols.size()];
210    for (int i = 0;i < cols.size();i++) {
211      LineRenderer renderable = cols.get(i);
212      widths[i] = Math.max(widths[i], renderable.getActualWidth());
213      minWidths[i] = Math.max(minWidths[i], renderable.getMinWidth());
214    }
215    widths = Layout.flow().compute(false, width, widths, minWidths);
216    if (widths == null) {
217      return null;
218    } else {
219      // Size could be smaller and lead to ArrayIndexOutOfBounds later
220      widths = Arrays.copyOf(widths, minWidths.length);
221      return renderer(widths, -1);
222    }
223  }
224}