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 }