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;
025
026import java.util.ArrayList;
027import java.util.Iterator;
028import java.util.LinkedList;
029import java.util.List;
030
031class TreeLineRenderer extends LineRenderer {
032
033  /** . */
034  private final LineRenderer value;
035
036  /** . */
037  private final List<LineRenderer> children;
038
039  TreeLineRenderer(TreeElement tree) {
040
041    ArrayList<LineRenderer> children = new ArrayList<LineRenderer>(tree.children.size());
042    for (Element child : tree.children) {
043      children.add(child.renderer());
044    }
045
046    //
047    this.children = children;
048    this.value = tree.value != null ? tree.value.renderer() : null;
049  }
050
051  @Override
052  public int getActualWidth() {
053    int width = value != null ? value.getActualWidth() : 0;
054    for (LineRenderer child : children) {
055      width = Math.max(width, 2 + child.getActualWidth());
056    }
057    return width;
058  }
059
060  @Override
061  public int getMinWidth() {
062    int width = value != null ? value.getMinWidth() : 0;
063    for (LineRenderer child : children) {
064      width = Math.max(width, 2 + child.getMinWidth());
065    }
066    return width;
067  }
068
069  @Override
070  public int getActualHeight(int width) {
071    throw new UnsupportedOperationException("Implement me");
072  }
073
074  @Override
075  public int getMinHeight(int width) {
076    throw new UnsupportedOperationException("Implement me");
077  }
078
079  @Override
080  public LineReader reader(final int width) {
081
082
083    final LinkedList<LineReader> readers  = new LinkedList<LineReader>();
084    for (LineRenderer child : children) {
085      readers.addLast(child.reader(width - 2));
086    }
087
088    //
089    return new LineReader() {
090
091      /** . */
092      LineReader value = TreeLineRenderer.this.value != null ? TreeLineRenderer.this.value.reader(width) : null;
093
094      /** . */
095      boolean node = true;
096
097      public boolean hasLine() {
098        if (value != null) {
099          if (value.hasLine()) {
100            return true;
101          } else {
102            value = null;
103          }
104        }
105        while (readers.size() > 0) {
106          if (readers.peekFirst().hasLine()) {
107            return true;
108          } else {
109            readers.removeFirst();
110            node = true;
111          }
112        }
113        return false;
114      }
115
116      public void renderLine(RenderAppendable to) {
117        if (value != null) {
118          if (value.hasLine()) {
119            value.renderLine(to);
120          } else {
121            value = null;
122          }
123        }
124        if (value == null) {
125          while (readers.size() > 0) {
126            LineReader first = readers.peekFirst();
127            if (first.hasLine()) {
128              if (node) {
129                to.append("+-");
130                node = false;
131              } else {
132                Iterator<LineReader> i = readers.descendingIterator();
133                boolean rest = false;
134                while (i.hasNext()) {
135                  LineReader renderer = i.next();
136                  if (i.hasNext()) {
137                    if (renderer.hasLine()) {
138                      rest = true;
139                      break;
140                    }
141                  }
142                }
143                if (rest) {
144                  to.append("| ");
145                } else {
146                  to.append("  ");
147                }
148              }
149              first.renderLine(to);
150              break;
151            }
152          }
153        }
154      }
155    };
156  }
157}