001    /* FrameSetView.java -- Implements HTML frameset
002       Copyright (C) 2006 Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package javax.swing.text.html;
040    
041    import java.util.StringTokenizer;
042    
043    import javax.swing.text.AttributeSet;
044    import javax.swing.text.BoxView;
045    import javax.swing.text.Element;
046    import javax.swing.text.View;
047    import 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     */
054    public 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    }