001/* FrameSetView.java -- Implements HTML frameset
002   Copyright (C) 2006 Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package javax.swing.text.html;
040
041import java.util.StringTokenizer;
042
043import javax.swing.text.AttributeSet;
044import javax.swing.text.BoxView;
045import javax.swing.text.Element;
046import javax.swing.text.View;
047import javax.swing.text.ViewFactory;
048
049/**
050 * Implements HTML framesets. This is implemented as a vertical box that
051 * holds the rows of the frameset. Each row is again a horizontal box that
052 * holds the actual columns.
053 */
054public class FrameSetView
055  extends BoxView
056{
057
058  /**
059   * A row of a frameset.
060   */
061  private class FrameSetRow
062    extends BoxView
063  {
064    private int row;
065    FrameSetRow(Element el, int r)
066    {
067      super(el, X_AXIS);
068      row = r;
069    }
070
071    protected void loadChildren(ViewFactory f)
072    {
073      // Load the columns here.
074      Element el = getElement();
075      View[] columns = new View[numViews[X_AXIS]];
076      int offset = row * numViews[X_AXIS];
077      for (int c = 0; c < numViews[X_AXIS]; c++)
078        {
079          Element child = el.getElement(offset + c);
080          columns[c] = f.create(child);
081        }
082      replace(0, 0, columns);
083    }
084
085    protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
086                                   int[] spans)
087    {
088      int numRows = numViews[X_AXIS];
089      int[] abs = absolute[X_AXIS];
090      int[] rel = relative[X_AXIS];
091      int[] perc = percent[X_AXIS];
092      layoutViews(targetSpan, axis, offsets, spans, numRows, abs, rel, perc);
093    }
094  }
095
096  /**
097   * Holds the absolute layout information for the views along one axis. The
098   * indices are absolute[axis][index], where axis is either X_AXIS (columns)
099   * or Y_AXIS (rows). Rows or columns that don't have absolute layout have
100   * a -1 in this array.
101   */
102  int[][] absolute;
103
104  /**
105   * Holds the relative (*) layout information for the views along one axis.
106   * The indices are relative[axis][index], where axis is either X_AXIS
107   * (columns) or Y_AXIS (rows). Rows or columns that don't have relative
108   * layout have a Float.NaN in this array.
109   */
110  int[][] relative;
111
112  /**
113   * Holds the relative (%) layout information for the views along one axis.
114   * The indices are relative[axis][index], where axis is either X_AXIS
115   * (columns) or Y_AXIS (rows). Rows or columns that don't have relative
116   * layout have a Float.NaN in this array.
117   *
118   * The percentage is divided by 100 so that we hold the actual fraction here.
119   */
120  int[][] percent;
121
122  /**
123   * The number of children in each direction.
124   */
125  int[] numViews;
126
127  FrameSetView(Element el)
128  {
129    super(el, Y_AXIS);
130    numViews = new int[2];
131    absolute = new int[2][];
132    relative = new int[2][];
133    percent = new int[2][];
134  }
135
136  /**
137   * Loads the children and places them inside the grid.
138   */
139  protected void loadChildren(ViewFactory f)
140  {
141    parseRowsCols();
142    // Set up the rows.
143    View[] rows = new View[numViews[Y_AXIS]];
144    for (int r = 0; r < numViews[Y_AXIS]; r++)
145      {
146        rows[r] = new FrameSetRow(getElement(), r);
147      }
148    replace(0, 0, rows);
149  }
150
151  /**
152   * Parses the rows and cols attributes and sets up the layout info.
153   */
154  private void parseRowsCols()
155  {
156    Element el = getElement();
157    AttributeSet atts = el.getAttributes();
158    String cols = (String) atts.getAttribute(HTML.Attribute.COLS);
159    if (cols == null) // Defaults to '100%' when not specified.
160      cols = "100%";
161    parseLayout(cols, X_AXIS);
162    String rows = (String) atts.getAttribute(HTML.Attribute.ROWS);
163    if (rows == null) // Defaults to '100%' when not specified.
164      rows = "100%";
165    parseLayout(rows, Y_AXIS);
166  }
167
168  /**
169   * Parses the cols or rows attribute and places the layout info in the
170   * appropriate arrays.
171   *
172   * @param att the attributes to parse
173   * @param axis the axis
174   */
175  private void parseLayout(String att, int axis)
176  {
177    StringTokenizer tokens = new StringTokenizer(att, ",");
178    numViews[axis] = tokens.countTokens();
179    absolute[axis] = new int[numViews[axis]];
180    relative[axis] = new int[numViews[axis]];
181    percent[axis] = new int[numViews[axis]];
182    for (int index = 0; tokens.hasMoreTokens(); index++)
183      {
184        String token = tokens.nextToken();
185        int p = token.indexOf('%');
186        int s = token.indexOf('*');
187        if (p != -1)
188          {
189            // Percent value.
190            String number = token.substring(0, p);
191            try
192              {
193                percent[axis][index] = Integer.parseInt(number);
194              }
195            catch (NumberFormatException ex)
196              {
197                // Leave value as 0 then.
198              }
199          }
200        else if (s != -1)
201          {
202            // Star relative value.
203            String number = token.substring(0, s);
204            try
205              {
206                relative[axis][index] = Integer.parseInt(number);
207              }
208            catch (NumberFormatException ex)
209              {
210                // Leave value as 0 then.
211              }
212          }
213        else
214          {
215            // Absolute value.
216            try
217              {
218                absolute[axis][index] = Integer.parseInt(token);
219              }
220            catch (NumberFormatException ex)
221              {
222                // Leave value as 0 then.
223              }
224          }
225      }
226  }
227
228  protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
229                                 int[] spans)
230  {
231    int numRows = numViews[Y_AXIS];
232    int[] abs = absolute[Y_AXIS];
233    int[] rel = relative[Y_AXIS];
234    int[] perc = percent[Y_AXIS];
235    layoutViews(targetSpan, axis, offsets, spans, numRows, abs, rel, perc);
236  }
237
238  void layoutViews(int targetSpan, int axis, int[] offsets, int[] spans,
239                   int numViews, int[] abs, int[] rel, int[] perc)
240  {
241    // We need two passes. In the first pass we layout the absolute and
242    // percent values and accumulate the needed space. In the second pass
243    // the relative values are distributed and the offsets are set.
244    int total = 0;
245    int relTotal = 0;
246    for (int i = 0; i < numViews; i++)
247      {
248        if (abs[i] > 0)
249          {
250            spans[i] = abs[i];
251            total += spans[i];
252          }
253        else if (perc[i] > 0)
254          {
255            spans[i] = (targetSpan * perc[i]) / 100;
256            total += spans[i];
257          }
258        else if (rel[i] > 0)
259          {
260            relTotal += rel[i];
261          }
262      }
263    int offs = 0;
264    for (int i = 0; i < numViews; i++)
265      {
266        if (relTotal > 0 && rel[i] > 0)
267          {
268            spans[i] = targetSpan * (rel[i] / relTotal);
269          }
270        offsets[i] = offs;
271        offs += spans[i];
272      }
273  }
274}