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.LineRenderer;
024    import org.crsh.text.RenderAppendable;
025    import org.crsh.text.Style;
026    
027    import java.util.ArrayList;
028    import java.util.Arrays;
029    import java.util.List;
030    
031    class 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    }